the cure for spam bots is more bots. specifically of the cron-activated, PHP-scripted, one-kick variety
remember when our greatest hassle was cleaning spam and deploying captcha challenges? oh yes, those were the days. now it looks like we've got more than enough on our plates with AI running rampant. and that includes keeping our groups happy, productive, and spam-free across multiple apps, which means having to deal with bots that can reliably answer captchas and slip us the ads we never asked for stuff we don't plan on buying.
(hair loss medication, anyone?)
yep, it looks like the future is not what is used to be.
but do not fret, dear reader. if you're dealing with the onslaught of spambots in your Telegram group, I have just the thing to defeat them (and no, it's not a huge laser beam (but that would be very cool)).
here is a detailed guide to create a Telegram bot in PHP that kicks users from a group if they have been active for over a year and have only ever sent a single message since their first participation was recorded. the bot will use the Telegram Bot API, SQLite for data storage, and a webhook to process updates.
and the best thing is that you can host it today in your favorite web server and start kicking bot ass.
Step 1: Create a Telegram Bot Using BotFather
first off, create a bot on Telegram to obtain an API token. open the app, search for @BotFather, and send /start.
send /newbot, then follow the prompts to name your bot (eg. OneMessageKicker) and set a username ending in Bot (eg. @OneMessageKickerBot).
BotFather will provide an API token, for instance 123456:ABC-DEF1234ghikL-mno56P7q8r890st10. save this token securely. the API token authenticates your bot with Telegram's servers, allowing your PHP script to control it. if anyone gets ahold of it, they can control your bot in your behalf, and now the world's got another spambot in the making. so be careful, ok?
Step 2: Set Up Your Server Environment
ensure your server has PHP and SQLite support:
- verify PHP is installed: you'll want to future-proof your setup, so version 8.2 or higher is recommended as it has a generous support deadline (december 31, 2026).
- ensure the curl and sqlite3 PHP extensions are enabled: most hosting providers include these by default; check phpinfo() or ask your host.
- create a directory on your server such as /var/www/html/one_message_kicker.
- make it writable for SQLite database creation with chmod 775 on Linux servers.
PHP will handle HTTP requests for the aforementioned webhook, curl will communicate with Telegram's API, and SQLite will store user data; hence a writable directory is needed for the database file.
Step 3: Set Up an SQLite Database
the provided code will create a SQLite database to track users' IDs, chat IDs, first message timestamp, and message count in a database file (bot_data.db) with a users table containing:
- chat_id: group identifier (integer);
- user_id: user identifier (integer);
- first_message_timestamp: unix timestamp of the first message (real); and
- message_count: total messages sent (integer).
SQLite is lightweight and stores data in a single file, which is ideal for this bot. we track the first message timestamp as a proxy for user activity duration, because bots can't reliably access join times for existing group members.
don't worry, the provided script will take care of that.
Step 4: Set Up a Webhook
next, the script will configure Telegram to send updates (messages or users leaving groups) to your server via a webhook. you'll need to host your PHP script (bot.php) on a server with HTTPS as Telegram requires a secure URL.
use a setup script (provided below) to register the webhook URL with Telegram, eg. https://sky.net/one_message_kicker/setup_webhook.php. run it once to configure the webhook by visiting that address in your browser.
webhooks allow Telegram to send real-time updates to your server whenever a message is sent or a user leaves. HTTPS is mandatory for security, so ensure your server has an SSL certificate like Let's Encrypt.
setup_webhook.php
<?php
$token = 'YOUR_API_TOKEN_HERE'; // Replace with your BotFather token
$webhook_url = 'https://yourdomain.com/telegram_bot/bot.php'; // Replace with your server's URL
// Set webhook
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.telegram.org/bot$token/setWebhook?url=" . urlencode($webhook_url));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;Step 5: Handle New Messages
the OneMessageKicker bot will need to process incoming messages to update the SQLite database in 3 steps:
- parse incoming webhook updates to extract chat_id, user_id, and message details.
- if the user is new, add them to the database with the current timestamp and message_count = 1.
- if the user exists, increment their message_count.
the bot counts all messages (text, photos, etc.) as activity: this ensures accurate tracking of message counts per user, which will determine when to kick them.
Step 6: Handle Users Leaving the Group
the script also needs to remove users from the database when they leave the group. in order to do so, it will:
- detect left_chat_member updates in the webhook data.
- delete the user's database entry using their chat_id and user_id.
this keeps the database clean, ensuring it only tracks active group members. and below you'll find the finished code:
bot.php
<?php
$token = 'YOUR_API_TOKEN_HERE'; // Replace with your BotFather token
// Read incoming webhook data
$update = json_decode(file_get_contents('php://input'), true);
// Open SQLite database
$db = new SQLite3('bot_data.db');
$db->exec('CREATE TABLE IF NOT EXISTS users (chat_id INTEGER, user_id INTEGER, first_message_timestamp REAL, message_count INTEGER)');
// Handle updates
if (isset($update['message'])) {
$chat_id = $update['message']['chat']['id'];
$user_id = $update['message']['from']['id'];
// Check if user exists in database
$stmt = $db->prepare('SELECT * FROM users WHERE chat_id = :chat_id AND user_id = :user_id');
$stmt->bindValue(':chat_id', $chat_id, SQLITE3_INTEGER);
$stmt->bindValue(':user_id', $user_id, SQLITE3_INTEGER);
$result = $stmt->execute()->fetchArray(SQLITE3_ASSOC);
if (!$result) {
// New user: insert with timestamp and message_count = 1
$stmt = $db->prepare('INSERT INTO users (chat_id, user_id, first_message_timestamp, message_count) VALUES (:chat_id, :user_id, :timestamp, 1)');
$stmt->bindValue(':chat_id', $chat_id, SQLITE3_INTEGER);
$stmt->bindValue(':user_id', $user_id, SQLITE3_INTEGER);
$stmt->bindValue(':timestamp', time(), SQLITE3_FLOAT);
$stmt->execute();
} else {
// Existing user: increment message_count
$stmt = $db->prepare('UPDATE users SET message_count = message_count + 1 WHERE chat_id = :chat_id AND user_id = :user_id');
$stmt->bindValue(':chat_id', $chat_id, SQLITE3_INTEGER);
$stmt->bindValue(':user_id', $user_id, SQLITE3_INTEGER);
$stmt->execute();
}
} elseif (isset($update['message']['left_chat_member'])) {
// User left the group: remove from database
$chat_id = $update['message']['chat']['id'];
$user_id = $update['message']['left_chat_member']['id'];
$stmt = $db->prepare('DELETE FROM users WHERE chat_id = :chat_id AND user_id = :user_id');
$stmt->bindValue(':chat_id', $chat_id, SQLITE3_INTEGER);
$stmt->bindValue(':user_id', $user_id, SQLITE3_INTEGER);
$stmt->execute();
}
$db->close();Step 7: Periodically Check and Kick Users
so far, so good. now the bot needs a job.
a cron job.
which will check users daily who have a single message older than one year. besides that, the bot needs to be able to kick -- specifically, a script with the kick command.
the plot thickens.
write a separate PHP script (kick.php) to query the database for users whose current_time - first_message_timestamp > 1 year and message_count = 1. then use Telegram's banChatMember API to kick them and remove their database entry.
when you piece both together, you'll set up a cron job on your server to run kick.php daily.
kick.php
<?php
$token = 'YOUR_API_TOKEN_HERE'; // Replace with your BotFather token
// Open SQLite database
$db = new SQLite3('bot_data.db');
// Calculate one year ago
$one_year_ago = time() - (365 * 24 * 60 * 60);
// Get all chat IDs
$result = $db->query('SELECT DISTINCT chat_id FROM users');
$chat_ids = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$chat_ids[] = $row['chat_id'];
}
// Process each chat
foreach ($chat_ids as $chat_id) {
$stmt = $db->prepare('SELECT user_id FROM users WHERE chat_id = :chat_id AND first_message_timestamp < :timestamp AND message_count = 1');
$stmt->bindValue(':chat_id', $chat_id, SQLITE3_INTEGER);
$stmt->bindValue(':timestamp', $one_year_ago, SQLITE3_FLOAT);
$result = $stmt->execute();
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$user_id = $row['user_id'];
// Kick user
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.telegram.org/bot$token/banChatMember?chat_id=$chat_id&user_id=$user_id");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
// Delete user from database
$delete_stmt = $db->prepare('DELETE FROM users WHERE chat_id = :chat_id AND user_id = :user_id');
$delete_stmt->bindValue(':chat_id', $chat_id, SQLITE3_INTEGER);
$delete_stmt->bindValue(':user_id', $user_id, SQLITE3_INTEGER);
$delete_stmt->execute();
echo "Kicked user $user_id from chat $chat_id\n";
}
}
$db->close();Step 8: Ensure Bot Permissions
everything's going smoothly. we have a bot that kicks ass and takes names — not exactly in that order.
now he just needs a license.
make the bot an administrator in the group with the Ban Users permission. without this permission, the bot cannot kick users, API calls will fail, and the mission will be over before it begins.
- add the bot to your Telegram group using its username.
- go to group settings > Manage Group > Administrators.
- add the bot and enable "Ban Users" permission.
Step 9: Deploy and Test
it's now or never.
- upload the scripts;
- set up the webhook by running it in your browser;
- configure the cron job; and
- test the bot.
cron job
0 1 * * * php /var/www/html/one_message_kicker/kick.phptesting ensures the webhook receives updates and the database updates correctly. Use a SQLite browser like DBeaver to inspect bot_data.db if needed.
that's it! your robot is ready to be unleashed. action!
¹ hey, that's still less than 10 steps.
Originally published at https://linkedin.com on June 24, 2025.