Halo Sobat, pernahkah Sobat melewatkan agenda penting atau lupa jadwal bayar tagihan hanya karena lupa mencatatnya? Atau mungkin Sobat bosan dengan aplikasi reminder biasa yang notifikasinya sering tenggelam?
Tenang, Sobat! Kali ini kita akan berbagi cara cerdas membuat aplikasi Catatan sekaligus Reminder Otomatis berbasis web menggunakan PHP, yang canggihnya, notifikasi pengingatnya akan dikirim langsung ke HP Android Sobat lewat Bot Telegram secara real-time dan gratis.
Dengan sistem ini, tanggal masa lalu akan otomatis disimpan sebagai Catatan Histori, sedangkan tanggal masa depan akan otomatis diantrekan menjadi Reminder aktif. Yuk, simak langkah demi langkah-nya!
1. Persiapan Bot Telegram (Token & Chat ID)
Sebelum masuk ke urusan coding, kita perlu menyiapkan “jalur pipa” pengiriman notifikasinya dulu lewat Telegram. Tenang Sobat, caranya gampang banget dan cuma butuh waktu 3 menit dari HP:
- Mendapatkan Token Bot: Buka Telegram, cari akun resmi @BotFather (yang ada centang birunya). Ketik perintah
/newbot, lalu ikuti instruksinya untuk memberi nama bot Sobat. Di akhir, Sobat akan diberikan rentetan kode panjang bernama HTTP API Token. Salin token ini! - Mendapatkan Chat ID: Cari bot bernama @MyIdBot di Telegram, lalu ketik
/getid. Bot akan memberikan deretan angka unik. Angka ini adalah ID akun Telegram pribadi Sobat agar bot tahu ke mana harus mengirim pesan. - Langkah Wajib: Cari bot yang baru saja Sobat buat tadi di Telegram, lalu tekan tombol Start agar bot tersebut diizinkan mengirim pesan ke Sobat.
2. Menyiapkan Database dan Halaman CRUD (catatan.php)
File pertama ini berfungsi sebagai tempat Sobat menginput, melihat, mengedit, dan menghapus catatan (CRUD). Jika kolom tanggal dikosongkan, sistem akan otomatis mengisinya dengan tanggal hari ini.
Buat file bernama catatan.php dan masukkan kode berikut:
PHP
<?php
# file catatan.php
require_once "config.php";
date_default_timezone_set("Asia/Jakarta");
mysqli_set_charset($conn, 'utf8mb4');
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
session_start();
function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
function flash_set($msg) { $_SESSION['flash_msg'] = $msg; }
function flash_get() {
if (!empty($_SESSION['flash_msg'])) {
$msg = $_SESSION['flash_msg'];
unset($_SESSION['flash_msg']);
return $msg;
}
return '';
}
// Auto create table
mysqli_query($conn, "
CREATE TABLE IF NOT EXISTS catatan_reminder(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tanggal DATE NOT NULL,
judul VARCHAR(200) NOT NULL,
keterangan TEXT,
is_notified TINYINT(1) NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_tanggal (tanggal)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
");
$today = date('Y-m-d');
$q = trim($_GET['q'] ?? '');
$page = max(1, (int)($_GET['page'] ?? 1));
$perPage = 20;
$offset = ($page - 1) * $perPage;
// Handle Simpan / Update
if (isset($_POST['simpan'])) {
$id = (int)($_POST['edit_id'] ?? 0);
$tgl = trim($_POST['tanggal'] ?? '') ?: $today;
$judul = trim($_POST['judul'] ?? '');
$ket = trim($_POST['keterangan'] ?? '');
if ($judul === '') { flash_set('Judul wajib diisi.'); header("Location: catatan.php"); exit; }
if ($id > 0) {
$stmt = $conn->prepare("UPDATE catatan_reminder SET tanggal=?, judul=?, keterangan=?, is_notified=0 WHERE id=?");
$stmt->bind_param("sssi", $tgl, $judul, $ket, $id);
$stmt->execute();
} else {
$stmt = $conn->prepare("INSERT INTO catatan_reminder (tanggal, judul, keterangan) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $tgl, $judul, $ket);
$stmt->execute();
}
header("Location: catatan.php"); exit;
}
// Handle Hapus
if (isset($_POST['hapus_id'])) {
$hapusId = (int)$_POST['hapus_id'];
$stmt = $conn->prepare("DELETE FROM catatan_reminder WHERE id = ?");
$stmt->bind_param("i", $hapusId);
$stmt->execute();
header("Location: catatan.php"); exit;
}
// Load Data Edit
$editData = ['id' => 0, 'tanggal' => date('Y-m-d'), 'judul' => '', 'keterangan' => ''];
if (isset($_GET['edit']) && (int)$_GET['edit'] > 0) {
$stmt = $conn->prepare("SELECT * FROM catatan_reminder WHERE id = ?");
$stmt->bind_param("i", $_GET['edit']);
$stmt->execute();
if ($row = $stmt->get_result()->fetch_assoc()) $editData = $row;
}
// Search & Pagination
$where = " WHERE 1=1 "; $params = []; $types = "";
if ($q !== '') { $where .= " AND (judul LIKE ? OR keterangan LIKE ?) "; $like = "%$q%"; $params[] = $like; $params[] = $like; $types .= "ss"; }
$stmtCount = $conn->prepare("SELECT COUNT(*) AS jml FROM catatan_reminder $where");
if ($q !== '') $stmtCount->bind_param($types, ...$params);
$stmtCount->execute();
$totalRows = $stmtCount->get_result()->fetch_assoc()['jml'];
$totalPages = max(1, (int)ceil($totalRows / $perPage));
$params[] = $perPage; $params[] = $offset; $types .= "ii";
$stmtList = $conn->prepare("SELECT * FROM catatan_reminder $where ORDER BY tanggal DESC, id DESC LIMIT ? OFFSET ?");
$stmtList->bind_param($types, ...$params);
$stmtList->execute();
$listData = $stmtList->get_result();
$flash = flash_get();
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Catatan & Pengingat</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
.container { max-width: 1000px; margin: 0 auto; }
.box { background: #fff; border: 1px solid #ddd; border-radius: 10px; padding: 16px; margin-bottom: 16px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 10px; font-size: 13px; text-align: left; }
th { background: #0f172a; color: #fff; }
input, textarea { width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 8px; }
.btn { padding: 6px 12px; border: 0; border-radius: 6px; cursor: pointer; text-decoration: none; font-size: 12px; font-weight: bold; display: inline-block; }
.btn-primary { background: #2563eb; color: #fff; }
.btn-success { background: #16a34a; color: #fff; }
.btn-danger { background: #dc2626; color: #fff; }
.badge { padding: 3px 7px; font-size: 11px; border-radius: 12px; font-weight: bold; display: inline-block; }
.badge-history { background: #e2e8f0; color: #334155; }
.badge-reminder { background: #dbeafe; color: #1e40af; }
</style>
</head>
<body>
<div class="container">
<?php if ($flash): ?><div style="padding:10px; background:#ecfdf5; color:#065f46; margin-bottom:16px; border-radius:8px;"><?=h($flash)?></div><?php endif; ?>
<div class="box">
<h2><?= $editData['id'] > 0 ? 'Edit Catatan' : 'Buat Catatan / Reminder' ?></h2>
<form method="post">
<input type="hidden" name="edit_id" value="<?=h($editData['id'])?>">
<table>
<tr><td width="150">Tanggal</td><td><input type="date" name="tanggal" value="<?=h($editData['tanggal'])?>"></td></tr>
<tr><td>Judul</td><td><input type="text" name="judul" value="<?=h($editData['judul'])?>" required></td></tr>
<tr><td>Keterangan</td><td><textarea name="keterangan"><?=h($editData['keterangan'])?></textarea></td></tr>
<tr><td colspan="2"><button class="btn btn-primary" type="submit" name="simpan">Simpan</button></td></tr>
</table>
</form>
</div>
<div class="box">
<h2>Daftar Kegiatan</h2>
<table>
<thead><tr><th>Tanggal</th><th>Tipe</th><th>Judul & Keterangan</th><th>Aksi</th></tr></thead>
<tbody>
<?php while ($row = $listData->fetch_assoc()): $isPast = ($row['tanggal'] < $today); ?>
<tr>
<td><b><?=h($row['tanggal'])?></b></td>
<td><span class="badge <?=$isPast ? 'badge-history':'badge-reminder'?>"><?=$isPast ? ' Histori':'⏰ Reminder '?></span></td>
<td><b><?=h($row['judul'])?></b><br><small><?=nl2br(h($row['keterangan']))?></small></td>
<td>
<a class="btn btn-success" href="catatan.php?edit=<?=h($row['id'])?>">Edit</a>
<form method="post" style="display:inline;" onsubmit="return confirm('Hapus?');">
<input type="hidden" name="hapus_id" value="<?=h($row['id'])?>">
<button class="btn btn-danger" type="submit">Hapus</button>
</form>
</td>
</tr>
<?php endwhile; ?>
</tbody>
</table>
</div>
</div>
</body>
</html>
3. Menulis Script Pengirim Notifikasi Otomatis (cron_reminder.php)
File kedua ini bertugas sebagai background job. Taruh konfigurasi token dan chat ID Sobat di bagian paling atas script ini.
Script ini akan mencari data yang tanggalnya hari ini, lalu menembakkannya ke API Telegram.
PHP
<?php
# file cron_reminder.php
require_once "config.php";
date_default_timezone_set("Asia/Jakarta");
// =========================================================================
// KONFIGURASI BOT TELEGRAM SOBAT
// =========================================================================
define('TELEGRAM_TOKEN', 'MASUKKAN_TOKEN_BOT_TELEGRAM_SOBAT');
define('TELEGRAM_CHAT_ID', 'MASUKKAN_CHAT_ID_SOBAT');
$today = date('Y-m-d');
// Ambil reminder yang jatuh tempo HARI INI dan belum diberi notifikasi
$stmt = $conn->prepare("SELECT * FROM catatan_reminder WHERE tanggal = ? AND is_notified = 0");
$stmt->bind_param("s", $today);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
// Menyusun pesan berformat Markdown
$pesan = "⏰ *PENGINGAT JADWAL HARI INI* ⏰\n\n";
$pesan .= " *Judul:* " . $row['judul'] . "\n";
$pesan .= " *Tanggal:* " . $row['tanggal'] . "\n";
if (!empty($row['keterangan'])) {
$pesan .= " *Keterangan:*\n" . $row['keterangan'] . "\n";
}
// Kirim ke Telegram menggunakan cURL
$url = "https://api.telegram.org/bot" . TELEGRAM_TOKEN . "/sendMessage";
$data = ['chat_id' => TELEGRAM_CHAT_ID, 'text' => $pesan, 'parse_mode' => 'Markdown'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
$resArray = json_decode($response, true);
if (isset($resArray['ok']) && $resArray['ok'] === true) {
// Tandai sudah terkirim agar tidak spamming ganda
$update = $conn->prepare("UPDATE catatan_reminder SET is_notified = 1 WHERE id = ?");
$update->bind_param("i", $row['id']);
$update->execute();
echo "Notifikasi sukses dikirim untuk ID: " . $row['id'] . "\n";
}
}
} else {
echo "Tidak ada reminder untuk hari ini.\n";
}
4. Penjelasan Langkah Kerja Program
- Pembedaan Tipe Otomatis: Ketika Sobat menginput data di halaman
catatan.php, script akan membandingkan tanggal inputan dengan tanggal hari ini. Status badge pelabelan visual langsung berubah menjadi Histori atau Reminder. - Pemicu Cron Job Terjadwal: File
cron_reminder.phpdidesain untuk dijalankan oleh sistem cPanel Cron Job server Sobat (misal diatur berjalan otomatis tiap jam 7 pagi). - Seleksi Baris Fleksibel: Saat dijalankan, script hanya mencari baris data yang
tanggal = hari inidan kolomis_notified = 0. Ini memastikan data masa depan tetap aman mengantre, dan data masa lalu tidak dikirim berulang-ulang. - Flag Keamanan Antrean: Setelah cURL berhasil mengirim pesan ke Telegram Anda, kolom
is_notifiedlangsung di-update menjadi1agar pada tarikan waktu cron berikutnya, data yang sama tidak terkirim lagi.
Dengan menerapkan panduan ini, Sobat sekarang punya asisten digital pribadi yang super responsif langsung di genggaman tangan lewat aplikasi Telegram.
Semoga panduan ini bermanfaat dan bisa membantu manajemen waktu maupun aktivitas bisnis online Sobat semua. Jangan lupa untuk share pengalaman Sobat dan bertanya di kolom komentar ya!
Selamat mencoba dan semoga sukses, Sobat.