BAFU Calendar Bot — Bản PHP + MySQL + Cron
Tự tìm bài lịch tuần mới trên bafu.edu.vn, theo dõi thêm/sửa/hoãn, gửi tóm tắt tuần, bản tin ngày và nhắc trước 24 giờ, 1 giờ qua Telegram. Dùng chat riêng, chỉ người quản trị cấp quyền mới xem lịch qua bot.
1. Yêu cầu hosting
- PHP 8.1 trở lên, MySQL 5.7+/MariaDB 10.4+, InnoDB, utf8mb4.
- Extension: PDO MySQL, cURL, DOM/XML, mbstring; session và OpenSSL. Không cần Composer.
- Cron Jobs chạy mỗi phút; bản PHP CLI nên cùng phiên bản PHP website.
- Hosting kết nối HTTPS ra
bafu.edu.vnvàapi.telegram.org; chứng chỉ CA hợp lệ. Website quản trị dùng HTTPS. - Chỉ dùng một bản cài và một Cron cho một token bot; không chạy getUpdates ở công cụ khác đồng thời.
2. Tạo bot Telegram
- Trong Telegram, mở tài khoản chính thức @BotFather.
- Gửi
/newbot; đặt tên, ví dụ Trợ lý lịch tuần BAFU. - Đặt username còn trống, kết thúc bằng
bot, ví dụlich_bafu_canhan_bot. - Sao chép token được cấp vào config.php. Giữ kín token.
- Mở bot vừa tạo và bấm Start. Bot sẽ trả lời sau khi Cron đã chạy.
3. Tạo database và upload mã nguồn
- Trong cPanel/DirectAdmin: tạo database, tạo user MySQL và cấp user quyền trên database đó (ALL PRIVILEGES). Lưu đủ tên có tiền tố tài khoản hosting.
- Giải nén thư mục
bafu-telegram. Ví dụ upload vào/home/USER/public_html/lich-bafu/. - Thấy đủ
app,bin,public,schema.sql,.htaccess. Bật “Show Hidden Files” để thấy .htaccess. - Sao chép
config.example.phpthànhconfig.php, nằm ngang hàng thư mục app. Chỉnh:
<?php return [ 'db' => [ 'host' => 'localhost', 'port' => 3306, 'name' => 'USER_bafubot', 'user' => 'USER_bafuuser', 'pass' => 'MAT_KHAU_MYSQL_CUA_BAN', ], 'setup_key' => 'CHUOI_NGAU_NHIEN_TU_32_KY_TU_DO_BAN_TU_TAO', 'telegram_token' => 'TOKEN_BOTFATHER_CUA_BAN', 'timezone' => 'Asia/Ho_Chi_Minh', ];
setup_key là khóa cài đặt riêng, khác mật khẩu MySQL và token Telegram. Dùng chuỗi ngẫu nhiên từ 32 ký tự, không để nguyên ví dụ. Nếu mật khẩu có dấu nháy đơn, phải escape đúng trong chuỗi PHP; tốt nhất dùng mật khẩu ngẫu nhiên không chứa nháy cho cấu hình ban đầu.
Apache/LiteSpeed: có thể truy cập https://tenmiencuaban.vn/lich-bafu/public/ với .htaccess đi kèm. Không để config.php hoặc các thư mục nội bộ truy cập từ web. Quyền thông thường: thư mục 755, file 644; config.php dùng 600/640 nếu hosting hỗ trợ, không đặt 777.
Nginx hoặc cấu hình subdomain riêng: đặt Document Root trỏ vào /home/USER/.../bafu-telegram/public, các thư mục app/bin/config ở ngoài Document Root. Nginx không đọc .htaccess; bắt buộc bố trí như trên. Khi đó mở https://lich.tenmiencuaban.vn/. Đọc hướng dẫn này từ file tải về.
4. Cài đặt và đăng nhập
- Mở
https://tenmiencuaban.vn/lich-bafu/public/install.php. - Trang cài đặt kiểm tra phiên bản PHP và extension.
- Nhập setup_key đã đặt trong config.php và tạo mật khẩu quản trị ít nhất 12 ký tự.
- Bấm Cài đặt: hệ thống tự tạo bảng, không cần import SQL thủ công.
schema.sqlchỉ để tham khảo/khôi phục. - Đăng nhập trang quản trị. Sau khi cài, install.php tự khóa, không thể cài lại ghi đè mật khẩu.
5. Cấu hình Cron Jobs — bước bắt buộc
Trong cPanel → Advanced → Cron Jobs → chọn Once Per Minute. Điền năm ô thời gian là * * * * *. Ô Command điền:
/usr/local/bin/php -q /home/USER/public_html/lich-bafu/bin/cron.php >> /home/USER/public_html/lich-bafu/var/cron.log 2>&1
Thay USER, đường dẫn thực và đường dẫn PHP theo hosting của bạn. Không dán năm dấu * vào ô Command nếu đã chọn thời gian ở năm ô phía trên. Nếu sửa crontab qua SSH, dòng đầy đủ là:
* * * * * /usr/local/bin/php -q /home/USER/public_html/lich-bafu/bin/cron.php >> /home/USER/public_html/lich-bafu/var/cron.log 2>&1
Một số hosting dùng /usr/local/bin/ea-php83 hoặc /opt/alt/php83/usr/bin/php. Hỏi nhà cung cấp hoặc kiểm tra Select PHP Version. Khi Cron không ghi được log, kiểm tra chủ sở hữu thư mục var, không mở quyền 777. Có thể bỏ phần chuyển hướng log để nhận lỗi qua email Cron trong lúc chẩn đoán. Chủ động xoay/xóa cron.log định kỳ; nhật ký database được dọn tự động.
Một Cron thực hiện toàn bộ: nhận lệnh Telegram → kiểm tra website nếu đã qua 5 phút → tạo các nhắc đến hạn → gửi hàng đợi. Nếu tác vụ cũ còn chạy, khóa MySQL ngăn tác vụ mới chạy chồng. Thời gian phản hồi lệnh thường trong chu kỳ Cron kế tiếp. Đừng thêm Cron web bằng curl/wget: bin/cron.php chỉ cho phép CLI.
6. Cấp quyền người nhận
- Chờ Cron chạy lần đầu. Trong quản trị, nếu bot từng dùng webhook, bấm Chuyển bot sang Cron.
- Trên Telegram, mở bot → Start → gửi
/id. - Bot trả Chat ID dạng số. Nếu chưa có phản hồi, kiểm tra Cron, token và kết nối Telegram.
- Quản trị → Người nhận thông báo → Thêm/cập nhật: nhập tên, Chat ID, bộ lọc, nhắc
1440,60, bản tin06:30. - Bấm Gửi thử để xác nhận kết nối; gửi
/startlần nữa để hiện các nút. - Bấm Kiểm tra website để tải lịch. Tin tuần mới chờ Cron gửi trong lượt tiếp theo. Nếu thêm người sau khi đã tải lịch, dùng
/weekđể xem; bot không gửi lại bản tin tuần cũ tự động.
Muốn sửa người nhận: điền lại đúng Chat ID vào form, nhập các cấu hình mới rồi lưu. Bản đầu hỗ trợ Telegram cá nhân; chưa có nhóm/kênh, Google Calendar, nhắc 19h hôm trước, lịch xe hoặc giao diện nhập lịch thủ công.
7. Lệnh Telegram
| Lệnh | Chức năng |
|---|---|
| /today | Lịch hôm nay |
| /tomorrow | Lịch ngày mai |
| /week | Tuần hiện tại (thứ Hai–Chủ nhật theo ngày thực tế) |
| /filter all | Theo dõi toàn trường |
| /filter Tên bạn;Tên đơn vị;toàn thể | Có một từ khóa xuất hiện trong thành phần/chủ trì là được chọn |
| /remind 1440,60 | Nhắc trước 24 giờ và 1 giờ |
| /remind 60 | Chỉ trước 1 giờ |
| /remind off | Tắt nhắc từng lịch |
| /morning 06:30 | Bản tin hằng ngày, giờ Việt Nam |
| /morning off | Tắt bản tin ngày |
| /off và /on | Tắt/bật toàn bộ thông báo tự động, vẫn có thể xem lịch bằng lệnh |
| /start hoặc nút Cài đặt | Xem hướng dẫn và cấu hình đang dùng |
| /id | Xem Chat ID, không cấp quyền tự động |
Bộ lọc giữ nguyên dấu tiếng Việt và tìm theo chuỗi, không phân biệt hoa/thường; không tự suy ra tên viết tắt hoặc nhóm của bạn. Hãy thêm các cách gọi phù hợp, ví dụ tên thường gọi, tên đơn vị, “toàn thể”, “viên chức”. Để trống là theo dõi toàn trường. Bộ lọc không tìm trong tiêu đề cuộc họp để hạn chế gửi lịch không thuộc thành phần của bạn.
8. Cách phát hiện bài mới và thay đổi
- Theo dõi chuyên mục Lịch công tác tuần; lấy các link bài gần đây; tiếp tục kiểm tra các nguồn đang trong tuần hiện tại hoặc sắp tới. Không phải nhập URL mỗi tuần.
- Ngày được lấy từ dòng ngày và khoảng ngày trong tiêu đề; năm dựa trên ngày đăng, có xử lý qua năm mới. Không dựa vào số tuần để tính ngày vì website có thể đặt số tuần khác lịch ISO.
- Chỉ đọc bảng lịch công tác có đúng năm cột. Gộp hàng được hỗ trợ; lịch không có giờ chỉ xuất hiện trong bản tin, không tự tạo giờ nhắc.
- Lưu dữ liệu và so sánh trường: ngày, giờ, nội dung, thành phần, chủ trì, địa điểm, trạng thái. Thay banner/footer không tạo thông báo.
- Đổi giờ với cùng nội dung hoặc sửa nội dung theo mốc duy nhất được cập nhật; lời nhắc cũ chưa gửi bị hủy. Đổi nhiều trường không chắc chắn hoặc xóa dòng sẽ chờ quản trị duyệt.
- Khi cần duyệt: bot gửi cảnh báo; quản trị mở nguồn lịch, so sánh hai bản rồi bấm duyệt. Không gọi một dòng biến mất là “hủy” khi chưa được xác nhận. Các lời nhắc của cả bài đó tạm dừng trong lúc chờ.
- Website lỗi hoặc bảng đổi cấu trúc: giữ dữ liệu cũ, hiển thị lỗi. Nếu không đọc thành công bài trong hơn 20 phút, ngừng tạo nhắc từ bài đó cho tới khi đồng bộ lại. Bản tin ngày vẫn ghi lịch đã lưu; cần đối chiếu nguồn khi có lỗi.
- Hệ thống chỉ phát hiện các phiên bản tồn tại tại lúc kiểm tra. Thay đổi rồi khôi phục giữa hai lượt 5 phút có thể không được ghi nhận.
9. Chống gửi trùng và xử lý trễ
- Mỗi người nhận/cuộc họp/phiên bản/mốc nhắc có mã duy nhất; nhiều lượt Cron không tạo lại cùng nhắc hẹn.
- Chỉ nhắc trong vòng 5 phút sau mốc đến hạn, và trước giờ họp. Lịch vừa thêm sau mốc 24 giờ không bị gửi dồn nhắc 24 giờ cũ; vẫn nhận báo bổ sung và các mốc tương lai.
- Nếu Cron dừng lâu, các nhắc đã qua cửa sổ không gửi bù. Bản tin sáng gửi bù tối đa 2 giờ. Không dùng bot như hệ thống báo thức được bảo đảm tuyệt đối.
- Telegram báo chờ do giới hạn tốc độ: lên lịch thử lại. Kết nối bị ngắt trong lúc gửi có thể đã gửi thành công: đánh dấu
uncertain, không tự gửi lại. Quản trị kiểm tra Telegram trước rồi mới bấm thử lại để giảm tin trùng. - Mỗi lượt gửi tối đa 25 phần tin; văn bản dài được chia nhỏ. Bản đầu phù hợp sử dụng cá nhân/nhóm người nhận nhỏ; chưa tối ưu cho hàng nghìn người.
10. Kiểm tra sau cài đặt
- Trang quản trị hiển thị Cron gần nhất trong vòng 1–2 phút, không còn cảnh báo.
- Gửi thử tới Telegram thành công; các lệnh /id, /today, /week hoạt động.
- Nguồn tuần 42 có 10 lịch tại thời điểm kiểm tra 18/10/2026; số lượng thực tế có thể đổi sau đó. Không có lịch xe trong bảng công tác.
- Chọn bộ lọc cụ thể, kiểm tra lịch hiện ra khớp thành phần/chủ trì.
- Kiểm tra hàng đợi có trạng thái sent khi đã gửi. Không cần chỉnh website thật để thử thay đổi.
11. Xử lý lỗi thường gặp
| Hiện tượng | Cách kiểm tra |
|---|---|
| HTTP 500 | PHP ≥8.1, bật extension, kiểm tra Error Log hosting, config.php thiếu dấu phẩy/nháy. Nếu “Options not allowed here”, xóa riêng dòng Options -Indexes trong .htaccess; giữ quy tắc chặn nội bộ. |
| MySQL không kết nối | Tên DB và user có tiền tố cPanel, gán quyền, mật khẩu đúng, host/port đúng nhà cung cấp. |
| Cron không chạy | Kiểm tra đường dẫn file PHP và cron.php tuyệt đối, PHP CLI extension, log var/cron.log, phút = mỗi phút. |
| Telegram không trả lời | Đã Start bot, token đúng, Cron chạy, kết nối ra Telegram, bấm Chuyển bot sang Cron; dừng các chương trình khác dùng cùng bot. |
| getUpdates lỗi 409 | Còn webhook hoặc bot đang polling nơi khác. Chỉ chạy một bản cài. |
| Gửi lỗi 403 | Người nhận đã chặn bot/chưa bắt đầu chat; mở bot và Start lại. |
| Website chặn/timeout | Kiểm tra hosting tải bafu.edu.vn được không. Không tắt SSL verification; nhờ hosting kiểm tra DNS, firewall, CA. |
| Không thấy lịch cá nhân | Thử /filter all. Bộ lọc không tự hiểu tên gọi khác hoặc chữ viết tắt. |
| Tuần này trống nhưng đã có tuần sau | /week luôn dùng tuần hiện tại. Dùng /tomorrow hoặc xem trang quản trị; bản tin tuần mới vẫn thông báo khi bài được phát hiện. |
| Lịch đang chờ duyệt | Vào Nguồn lịch, so sánh bản đã lưu với bản website và duyệt đúng phiên bản đang hiển thị. |
12. Sao lưu, bảo trì và kiểm thử
Sao lưu MySQL và config.php an toàn; không công khai token/backup. Bộ mã không cần quyền ghi vào thư mục app/public; chỉ var/cron.log cần ghi nếu bật log. Dọn log định kỳ. Dữ liệu lịch và phiên bản lưu trong DB; các log DB cũ hơn 30 ngày và tin đã xử lý cũ hơn 60 ngày được dọn tự động.
php tests/run.php
Kiểm thử độc lập gồm đọc bảng, rowspan, không đoán giờ, hoãn, qua năm mới, đối chiếu giờ/tiêu đề, bộ lọc, loại nhắc trùng và kiểm tra nguồn hợp lệ. tests/integration.php chỉ chạy trên database thử nghiệm trống có tên kết thúc _test; không chạy trên dữ liệu thật.
Mã nguồn gồm app (nghiệp vụ), public (quản trị), bin/cron.php (tác vụ định kỳ), schema.sql và config.example.php. Không có mã/mật khẩu mặc định hoặc token thật trong gói.