Skip to content

How to deal with 500 errors (webHook installation)

Saber edited this page Sep 23, 2021 · 2 revisions

Sometimes we write code that breaks our bot. Yes we do.

Sometimes you miss some exception that should be handled. Sometimes you'll notice that your bot don't send any response to some particular command only when this command will fill up your pending updates queue.

Since Telegram will try to resend any update over and over again in case it got 500 error in response, this error will spawn on every retry until code 200 response received (even if message is not handled).

So?

Some code added to your hook.php right after require __DIR__ . '/vendor/autoload.php'; could save you a lot of time finding what's wrong with your bot. Your bot will send you any fatal error, it's description and message that caused that error right after that error occurred and gracefully answer with code 200 to Telegram request.

Please note that some setup required inside log_exception() function. Feel free to improve code as well as this page.

// Error handling
   
  /**
   * Error handler, passes flow over the exception logger with new ErrorException.
   *
   * @param $num
   * @param $str
   * @param $file
   * @param $line
   * @param null $context
   */
  function log_error( $num, $str, $file, $line, $context = null )  {
    log_exception( new ErrorException( $str, 0, $num, $file, $line ) );
  }
  
  /**
   * Uncaught exception handler.
   * @param \Exception $e
   */
  function log_exception( $e )  {

    // setup notifier
    $API_KEY  = 'XXXXXXXXXX'; // Replace 'XXXXXXXXXX' with your bot's API token
    $DEV_ID   = 'XXXXXXXXXX'; // Replace 'XXXXXXXXXX' with your Telegram user ID (use /whoami command)
    
    // get incomming message
    $incoming = file_get_contents('php://input');
    
    // if message exist convert it into array
    $incoming = !empty($incoming) ? json_decode(file_get_contents('php://input'), true) : false ;
    
    // developer notification message text
    $message  = get_class( $e ) . " - <b>{$e->getMessage()}</b>;".PHP_EOL."File: <b>{$e->getFile()}</b>; Line: <b>{$e->getLine()}</b>; Time: <b>".date("H:i:s / d.m.Y")."</b>;".PHP_EOL."<b>Incoming message:</b><pre>".(!empty($incoming)?var_export($incoming, true).'</pre>':'</pre>'.PHP_EOL.'<b>Trace:</b><pre>'.$e->getTraceAsString().'</pre>');
    
    // developer notification message settings
    $fields_string = '';
    $url = 'https://api.telegram.org/bot'.$API_KEY.'/sendMessage';
    
    $fields = [
        'chat_id' => urlencode($DEV_ID),
        'parse_mode' => urlencode('HTML'),
        'text' => urlencode(''.$message)
    ];
    
    //url-ify the data for the POST
    foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
    rtrim($fields_string, '&');
    
    //open connection
    $ch = curl_init();
    
    //set the url, number of POST vars, POST data
    curl_setopt($ch,CURLOPT_URL, $url);
    curl_setopt($ch,CURLOPT_POST, count($fields));
    curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
    
    //execute post
    $result = curl_exec($ch);
        
    //close connection
    curl_close($ch);
    
    // Uncomment following line and change path to store errors log in custom file
    // file_put_contents( __DIR__ .'/custom_errors.log', ($result?'Notified: '.var_export($result, true).PHP_EOL:'Not notified: '.var_export($result, true).PHP_EOL).$message . PHP_EOL, FILE_APPEND );
  
    // Sending 200 response code
    header('X-PHP-Response-Code: 200', true, 200);
    
    exit();
  }
  
  /**
   * Checks for a fatal error, work around for set_error_handler not working on fatal errors.
   */
  function check_for_fatal()
  {
    $error = error_get_last();
    if (isset($error))
      if ( $error["type"] == E_ERROR )
        log_error( $error["type"], $error["message"], $error["file"], $error["line"] );
  }
  
  register_shutdown_function( "check_for_fatal" );
  set_error_handler( "log_error" );
  set_exception_handler( "log_exception" );
  ini_set( "display_errors", "off" );
  error_reporting( E_ALL );

some code from http://php.net/manual/en/function.set-error-handler.php#112291