I’m having trouble with my PHP Telegram bot. I built a system where I store user chat IDs in a database so I can broadcast messages to everyone. The bot works with a command like /broadcast announce:hello world and most of the time everything works perfectly.
The weird issue is that sometimes the bot gets stuck in a loop and keeps sending the same message over and over to all users. It won’t stop until I clear the database completely. What could be causing this infinite loop behavior?
Had the same issue with my newsletter bot. It’s webhook retries, but there’s more to it. Your file_get_contents() calls don’t handle failures. When Telegram’s API is slow or errors out (rate limits, outages), file_get_contents() fails silently and keeps looping. Telegram thinks your webhook died and retries. Switch to cURL - check response codes and handle timeouts properly. Set timeouts to 5-10 seconds max and catch failures. Also, chunk your broadcasts. I do 50 users at a time with a cron job for the next batch. Keeps webhook responses under Telegram’s timeout while still being efficient. Ditch the exit() - your webhook should always return a clean response whether the broadcast works or not.
The problem is webhook timeout plus missing update deduplication, but there’s a smarter fix than patching this mess.
Your PHP script makes synchronous API calls, sending messages one by one. With hundreds or thousands of subscribers, this drags on forever and Telegram’s webhook times out. Then it retries the same request.
Don’t bother fixing timeouts and adding update tracking. Move the heavy work outside the webhook completely. Your webhook should queue the broadcast job and respond to Telegram immediately.
I hit this exact issue last year with a notification system. Tried the usual fixes but kept running into edge cases. Ended up switching to Latenode for the broadcast logic.
With Latenode, your webhook just triggers a workflow that handles the entire broadcast async. It retries failed messages, handles rate limits properly, and won’t timeout your webhook. Plus you get built-in logging to see exactly what went wrong.
The workflow grabs your subscriber list, sends messages in batches with proper delays, and handles errors gracefully. No more infinite loops or duplicate messages.
Your Telegram bot is experiencing an infinite loop where it repeatedly sends the same message to all users in your subscriber database. This is likely due to a combination of webhook retry mechanisms in Telegram’s API and the improper handling of webhook requests and responses within your PHP code. The bot continues the loop until you manually clear the database.
Understanding the “Why” (The Root Cause):
Telegram’s webhook system is designed to handle temporary network interruptions or processing delays on your server. If a webhook request doesn’t receive a successful HTTP 200 response within a certain timeout period, Telegram will retry the same request. In your case, the exit() call within the broadcastToAll function is causing this issue. When the script reaches this exit() statement, it abruptly terminates before sending a successful response code back to Telegram. This is interpreted as a failure, triggering Telegram’s retry mechanism. The retry then causes your bot to re-execute the broadcastToAll function and the cycle repeats. Additionally, a lack of update ID tracking means your bot processes the same update multiple times, exacerbating the problem.
Step-by-Step Guide:
Implement Update ID Tracking: Before processing any commands, your bot needs to track the update_id. This ensures that you do not process the same update multiple times. Modify your webhook handler to store and compare the update_id (assuming you receive this in the webhook request). Here’s how to modify your existing structure (assuming $update contains webhook data):
// ... within your webhook handler ...
$updateId = $update['update_id']; //Assuming 'update_id' is available in the webhook data
$lastProcessedUpdateId = getLastProcessedUpdateId(); //Fetch from database or file
if ($updateId > $lastProcessedUpdateId) {
// Process the command as before
// ... your existing case '/broadcast' code ...
updateLastProcessedUpdateId($updateId); //Store the update ID after processing
}
You’ll need to create functions getLastProcessedUpdateId() and updateLastProcessedUpdateId() to store and retrieve the last processed update_id persistently (e.g., in a database or a file).
Remove the exit() Call and Implement Proper Response Handling: The exit() call within your broadcastToAll function needs to be removed. Instead, ensure your webhook always returns a proper HTTP 200 response, even if the broadcast has errors. This signals to Telegram that the request was successfully received and processed, preventing retries. Wrap your broadcast logic in a try...catch block:
Your webhook handler should now send a JSON response (e.g., using json_encode) containing the status of the broadcast attempt.
Batch Your Broadcasts: Sending messages one by one to thousands of users can cause significant delays, exceeding Telegram’s timeout. Break your broadcast into smaller batches (e.g., 50 users at a time). Use a loop and introduce small delays between batches to prevent exceeding rate limits.
Common Pitfalls & What to Check Next:
Database Errors: Ensure your database queries are efficient and that there are no errors during the SELECT statement. Log database queries for debugging.
Telegram API Rate Limits: Monitor your API calls to avoid exceeding Telegram’s rate limits, which can lead to temporary bans. Implement exponential backoff strategies to handle rate limit errors.
Network Issues: If you continue facing timeouts, check your server’s network connection and ensure it can reliably communicate with Telegram’s servers.
Error Logging: Implement comprehensive error logging throughout your code to track any issues during the broadcasting process.
Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!
this is a webhook timeout problem. your broadcastToAll function is taking too long, so telegram thinks the request failed and keeps resending the same update. ditch the exit() and handle responses properly. also check your hosting’s execution time limits - broadcasting to tons of users can cause timeouts that make telegram retry forever.