Saya sudah menulis postingan blog tentang membuat sistem login dan pendaftaran pengguna yang lengkap menggunakan PHP dan MySQL, tetapi saya tidak menyertakan verifikasi email.
Tutorial ini sedikit mirip dengan update pada tutorial sebelumnya. Selain dapat mendaftar, masuk, dan keluar dari akunnya, pengguna juga akan dikirimi email verifikasi ke alamat email mereka dengan tautan yang dapat mereka klik dan alamat emailnya diverifikasi.
Pada sebagian besar aplikasi yang akan Anda buat, penting untuk menambahkan fitur verifikasi email karena berbagai alasan:Anda mungkin ingin mengirim email nanti kepada pengguna dan ingin memastikan mereka akan melihatnya; atau pengguna mungkin lupa kata sandi mereka dan perlu mengatur ulang, dan untuk melakukan ini, kami perlu mengirim email kepada mereka tautan pengaturan ulang kata sandi; ada banyak alasan lain tetapi Anda mengerti maksudnya.
Dalam sistem yang kami bangun hari ini, pengguna yang belum memverifikasi email mereka tidak akan dapat melakukan tindakan tertentu (saya hanya akan menggunakan demonstrasi sederhana seperti melihat tombol. Hanya pengguna terverifikasi yang dapat melihat tombol itu).
Untuk memulai, buat proyek PHP baru bernama verifikasi-pengguna dan di folder ini, buat dua file:signup.php dan login.php.
pendaftaran.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
<link rel="stylesheet" href="main.css">
<title>User verification system PHP</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 offset-md-4 form-wrapper auth">
<h3 class="text-center form-title">Register</h3>
<form action="signup.php" method="post">
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control form-control-lg" value="<?php echo $username; ?>">
</div>
<div class="form-group">
<label>Email</label>
<input type="text" name="email" class="form-control form-control-lg" value="<?php echo $email; ?>">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control form-control-lg">
</div>
<div class="form-group">
<label>Password Confirm</label>
<input type="password" name="passwordConf" class="form-control form-control-lg">
</div>
<div class="form-group">
<button type="submit" name="signup-btn" class="btn btn-lg btn-block">Sign Up</button>
</div>
</form>
<p>Already have an account? <a href="login.php">Login</a></p>
</div>
</div>
</div>
</body>
</html>
Ini hanya file HTML/CSS sederhana. Satu-satunya hal yang perlu diperhatikan adalah bahwa kita menggunakan kerangka kerja CSS Bootstrap 4 untuk menata halaman kita. Anda dapat menggunakan kerangka gaya lain pilihan Anda atau menulis CSS Anda sendiri jika Anda mau.
Segera setelah Bootstrap CSS, kami menyertakan file main.css untuk gaya kustom. Mari kita buat file itu sekarang. Di folder root aplikasi, buat file bernama main.css.
main.css:
@import url('https://fonts.googleapis.com/css?family=Lora');
li { list-style-type: none; }
.form-wrapper {
margin: 50px auto 50px;
font-family: 'Lora', serif;
font-size: 1.09em;
}
.form-wrapper.login { margin-top: 120px; }
.form-wrapper p { font-size: .8em; text-align: center; }
.form-control:focus { box-shadow: none; }
.form-wrapper {
border: 1px solid #80CED7;
border-radius: 5px;
padding: 25px 15px 0px 15px;
}
.form-wrapper.auth .form-title { color: #007EA7; }
.home-wrapper button,
.form-wrapper.auth button {
background: #007EA7;
color: white;
}
.home-wrapper {
margin-top: 150px;
border-radius: 5px;
padding: 10px;
border: 1px solid #80CED7;
}
Pada baris pertama file ini kita mengimpor dan menggunakan beberapa Google Font untuk membuat font kita terlihat lebih indah.
Sekarang buka file login.php dan lakukan hal serupa.
login.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
<link rel="stylesheet" href="main.css">
<title>User verification system PHP - Login</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 offset-md-4 form-wrapper auth login">
<h3 class="text-center form-title">Login</h3>
<form action="login.php" method="post">
<div class="form-group">
<label>Username or Email</label>
<input type="text" name="username" class="form-control form-control-lg" value="<?php echo $username; ?>">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control form-control-lg">
</div>
<div class="form-group">
<button type="submit" name="login-btn" class="btn btn-lg btn-block">Login</button>
</div>
</form>
<p>Don't yet have an account? <a href="signup.php">Sign up</a></p>
</div>
</div>
</div>
</body>
</html>
Di browser Anda, buka http://localhost/cwa/verify-user/signup.php Anda akan melihat formulir pendaftaran yang indah (sama untuk login). Abaikan kesalahan di kolom input, kami akan segera memperbaikinya.
Untuk saat ini, mari kita siapkan databasenya. Buat database bernama verifikasi-pengguna dan dalam database ini, buat tabel pengguna dengan atribut sebagai berikut:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL,
`verified` tinyint(1) NOT NULL DEFAULT '0',
`token` varchar(255) DEFAULT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
Tidak ada yang aneh kecuali, mungkin, token dan bidang terverifikasi, yang akan saya jelaskan sebentar lagi.
Sekarang kita mulai dengan logika pendaftaran yang sebenarnya. Saya biasanya suka merujuk ke bagian logis dari aplikasi saya sebagai pengontrol dan itulah yang akan saya lakukan di sini. Di folder root proyek, buat folder bernama controllers dan di dalam controllers, buat file bernama authController.php.
controllers/authController.php:
<?php
session_start();
$username = "";
$email = "";
$errors = [];
$conn = new mysqli('localhost', 'root', '', 'verify-user');
// SIGN UP USER
if (isset($_POST['signup-btn'])) {
if (empty($_POST['username'])) {
$errors['username'] = 'Username required';
}
if (empty($_POST['email'])) {
$errors['email'] = 'Email required';
}
if (empty($_POST['password'])) {
$errors['password'] = 'Password required';
}
if (isset($_POST['password']) && $_POST['password'] !== $_POST['passwordConf']) {
$errors['passwordConf'] = 'The two passwords do not match';
}
$username = $_POST['username'];
$email = $_POST['email'];
$token = bin2hex(random_bytes(50)); // generate unique token
$password = password_hash($_POST['password'], PASSWORD_DEFAULT); //encrypt password
// Check if email already exists
$sql = "SELECT * FROM users WHERE email='$email' LIMIT 1";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
$errors['email'] = "Email already exists";
}
if (count($errors) === 0) {
$query = "INSERT INTO users SET username=?, email=?, token=?, password=?";
$stmt = $conn->prepare($query);
$stmt->bind_param('ssss', $username, $email, $token, $password);
$result = $stmt->execute();
if ($result) {
$user_id = $stmt->insert_id;
$stmt->close();
// TO DO: send verification email to user
// sendVerificationEmail($email, $token);
$_SESSION['id'] = $user_id;
$_SESSION['username'] = $username;
$_SESSION['email'] = $email;
$_SESSION['verified'] = false;
$_SESSION['message'] = 'You are logged in!';
$_SESSION['type'] = 'alert-success';
header('location: index.php');
} else {
$_SESSION['error_msg'] = "Database error: Could not register user";
}
}
}
// LOGIN
if (isset($_POST['login-btn'])) {
if (empty($_POST['username'])) {
$errors['username'] = 'Username or email required';
}
if (empty($_POST['password'])) {
$errors['password'] = 'Password required';
}
$username = $_POST['username'];
$password = $_POST['password'];
if (count($errors) === 0) {
$query = "SELECT * FROM users WHERE username=? OR email=? LIMIT 1";
$stmt = $conn->prepare($query);
$stmt->bind_param('ss', $username, $password);
if ($stmt->execute()) {
$result = $stmt->get_result();
$user = $result->fetch_assoc();
if (password_verify($password, $user['password'])) { // if password matches
$stmt->close();
$_SESSION['id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['email'] = $user['email'];
$_SESSION['verified'] = $user['verified'];
$_SESSION['message'] = 'You are logged in!';
$_SESSION['type'] = 'alert-success';
header('location: index.php');
exit(0);
} else { // if password does not match
$errors['login_fail'] = "Wrong username / password";
}
} else {
$_SESSION['message'] = "Database error. Login failed!";
$_SESSION['type'] = "alert-danger";
}
}
}
Jika Anda telah mengikuti tutorial saya sebelumnya, maka tidak ada yang baru bagi Anda dalam file ini. Tapi demi pemula, saya akan menjelaskannya.
Hal pertama adalah kita memulai sesi menggunakan session_start() karena kita perlu menyimpan informasi pengguna yang masuk dalam sesi. Setelah memulai sesi, kami menginisialisasi variabel $username dan $email yang kami gunakan dalam formulir kami, dan juga array $errors yang akan menampung kesalahan validasi formulir kami.
Selanjutnya, kita terhubung ke database. Dua pernyataan if berikutnya yang mengikuti masing-masing adalah kode yang dieksekusi ketika pengguna mengklik tombol signup atau login. Dalam hal pendaftaran, kami memeriksa untuk memastikan bahwa semua bidang yang diperlukan telah diisi dengan benar dan baru kemudian kami melanjutkan untuk menyimpan pengguna dalam database. Kami juga membuat token (string unik dan acak) dan menyimpannya dengan pengguna sebagai atribut. Ini akan digunakan untuk memverifikasi email pengguna. Lebih lanjut nanti.
Karena file authController.php kita bertanggung jawab untuk signup dan login, kita harus menyertakannya di bagian paling atas halaman signup.php dan login.php karena ke sanalah data formulir dikirimkan. Seperti ini:
signup.php dan login.php (di bagian paling atas):
<?php include 'controllers/authController.php' ?>
Jika ada pesan kesalahan dalam array $errors, kita perlu menampilkannya di formulir. Untuk melakukannya, tambahkan pernyataan if ini di dalam formulir Anda tepat di bawah judul formulir untuk halaman pendaftaran dan login.
<!-- form title -->
<h3 class="text-center form-title">Register</h3> <!-- or Login -->
<?php if (count($errors) > 0): ?>
<div class="alert alert-danger">
<?php foreach ($errors as $error): ?>
<li>
<?php echo $error; ?>
</li>
<?php endforeach;?>
</div>
<?php endif;?>
Jika tidak ada kesalahan, skrip kami akan melanjutkan untuk menyimpan pengguna di database. Setelah menyimpan pengguna di database, kami langsung login. Dalam kasus kami, memasukkan pengguna berarti menyimpan data mereka dalam sesi dan itulah yang baru saja kami lakukan.
Pada titik ini, Anda sudah dapat mendaftar dan bahkan login pengguna. Namun setelah login, Anda akan diarahkan ke halaman index.php yang tidak ada. Kami akan segera membuatnya.
Di authController.php, kita menyimpan variabel pesan dan tipe di sesi yang akan ditampilkan segera setelah pengguna login. pesan adalah teks pesan yang sebenarnya sedangkan tipenya adalah kelas penataan Bootstrap yang akan memformat pesan dengan sesuai warna tergantung pada nilai jenisnya.
Pesan ini ditampilkan setelah pengguna login dan ditampilkan pada file index.php. Mari buat file itu sekarang di folder root proyek kita.
index.php:
<?php include 'controllers/authController.php'?>
<?php
// redirect user to login page if they're not logged in
if (empty($_SESSION['id'])) {
header('location: login.php');
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
<link rel="stylesheet" href="main.css">
<title>User verification system PHP</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 offset-md-4 home-wrapper">
<!-- Display messages -->
<?php if (isset($_SESSION['message'])): ?>
<div class="alert <?php echo $_SESSION['type'] ?>">
<?php
echo $_SESSION['message'];
unset($_SESSION['message']);
unset($_SESSION['type']);
?>
</div>
<?php endif;?>
<h4>Welcome, <?php echo $_SESSION['username']; ?></h4>
<a href="logout.php" style="color: red">Logout</a>
<?php if (!$_SESSION['verified']): ?>
<div class="alert alert-warning alert-dismissible fade show" role="alert">
You need to verify your email address!
Sign into your email account and click
on the verification link we just emailed you
at
<strong><?php echo $_SESSION['email']; ?></strong>
</div>
<?php else: ?>
<button class="btn btn-lg btn-primary btn-block">I'm verified!!!</button>
<?php endif;?>
</div>
</div>
</div>
</body>
</html>
Halaman ini dimaksudkan hanya dapat diakses oleh pengguna yang masuk. Itulah sebabnya di bagian atas file, kami mengarahkan pengguna ke halaman login jika mereka tidak login. Di suatu tempat di tengah halaman, kami menampilkan pesan. Setelah menampilkan pesan, kami membatalkan pengaturan pesan dan mengetik variabel karena kami tidak ingin pesan itu tetap ada di halaman bahkan setelah pengguna me-refresh halaman.
Terakhir, di bagian tengah halaman, kami melakukan pemeriksaan untuk melihat apakah pengguna yang login telah memverifikasi alamat email mereka atau belum. Ingat kami menambahkan variabel terverifikasi di sesi saat kami memasukkan pengguna. Jika pengguna telah diverifikasi, maka kami menampilkan "Saya Terverifikasi!!!" tombol untuk mereka lihat. Jika mereka tidak diverifikasi, kami memberi tahu mereka tentang tautan verifikasi yang kami kirimkan ke alamat email mereka dan kami meminta mereka untuk mengeklik tautan itu untuk memverifikasi email mereka.
Verifikasi Email
Dalam file authController.php, kami menggunakan komentar untuk menunjukkan ke mana kami akan mengirim email verifikasi kepada pengguna dengan memanggil sendVerificationEmail(). Buka file authController.php dan batalkan komentar pada panggilan fungsi sebagai berikut:
// TO DO: send verification email to user
sendVerificationEmail($email, $token);
Kami akan mendefinisikan fungsi ini di file lain dan memasukkan file itu ke dalam authController.php. Di dalam folder controllers, buat file bernama sendEmails.php.
Sebelum kita menambahkan kode apa pun dalam file ini, izinkan saya menjelaskan sedikit tentang PHP SwiftMailer, perpustakaan populer untuk mengirim email dalam PHP yang akan kita gunakan dalam proyek ini untuk mengirim email dari localhost.
SwiftMailer adalah pustaka kaya fitur yang populer untuk mengirim email dalam aplikasi PHP.
Untuk menggunakan Swiftmailer, Anda harus menginstal Komposer terlebih dahulu. Setelah Anda menginstal komposer, buka terminal atau baris perintah Anda dan arahkan ke folder root proyek dan jalankan perintah berikut untuk menambahkan perpustakaan Swift Mailer dengan semua filenya ke proyek kami:
composer require "swiftmailer/swiftmailer:^6.0"
Ini membuat folder vendor di root aplikasi kita yang berisi semua kode (kelas) yang diperlukan untuk mengirim email dan juga membuat file composer.json di root aplikasi yang terlihat seperti ini:
{
"require": {
"swiftmailer/swiftmailer": "^6.0"
}
}
Sekarang buka file sendEmails.php yang kita buat tadi dan mari kita tulis fungsi sendVerificationEmail():
<?php
require_once './vendor/autoload.php';
// Create the Transport
$transport = (new Swift_SmtpTransport('smtp.gmail.com', 465, 'ssl'))
->setUsername(SENDER_EMAIL)
->setPassword(SENDER_PASSWORD);
// Create the Mailer using your created Transport
$mailer = new Swift_Mailer($transport);
function sendVerificationEmail($userEmail, $token)
{
global $mailer;
$body = '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test mail</title>
<style>
.wrapper {
padding: 20px;
color: #444;
font-size: 1.3em;
}
a {
background: #592f80;
text-decoration: none;
padding: 8px 15px;
border-radius: 5px;
color: #fff;
}
</style>
</head>
<body>
<div class="wrapper">
<p>Thank you for signing up on our site. Please click on the link below to verify your account:.</p>
<a href="http://localhost/cwa/verify-user/verify_email.php?token=' . $token . '">Verify Email!</a>
</div>
</body>
</html>';
// Create a message
$message = (new Swift_Message('Verify your email'))
->setFrom(SENDER_EMAIL)
->setTo($userEmail)
->setBody($body, 'text/html');
// Send the message
$result = $mailer->send($message);
if ($result > 0) {
return true;
} else {
return false;
}
}
Pernyataan pertama membutuhkan file autoload.php ke dalam file ini. File autoload.php ini secara otomatis akan memasukkan semua class dari library Swift Mailer di folder vendor yang kita gunakan di file ini.
Kami menggunakan Gmail dalam contoh ini. Jadi, Anda dapat mengganti SENDER_EMAIL dan SENDER_PASSWORD dengan alamat Gmail dan sandi yang ingin digunakan sebagai alamat email pengirim. (Alamat email penerima adalah yang dikirimkan melalui formulir).
Biasanya, untuk mengirim email ke seseorang, Anda harus masuk ke akun Gmail Anda sebelum menulis dan mengirim email. Ini adalah hal yang sama seperti yang dilakukan oleh pustaka Swift Mailer. Jadi ketika penerima ($userEmail) menerima email, alamat Gmail Anda (SENDER_EMAIL) akan mereka lihat sebagai email pengirim.
Sekarang kita memanggil fungsi sendVerificationEmail() dalam file authController.php kita tetapi kita mendefinisikan fungsi di dalam file sendEmails.php. Mari kita sertakan file sendEmails.php di dalam authController.php kita untuk membuat fungsi ini tersedia dalam file. Di bagian atas authController.php, tepat sebelum session_start(), tambahkan baris berikut:
require_once 'sendEmails.php';
Itu saja yang kami butuhkan, Tuan-tuan (dan ibu-ibu) untuk mengirim email ke pengguna kami dengan tautan verifikasi email. Tetapi kami sedang mengerjakan localhost dan Gmail akan memblokir semua upaya masuk dari Swift Mailer yang berjalan di localhost.
Mengirim email dari localhost
Jika Anda ingin ini berjalan di localhost, Anda perlu mengonfigurasi akun Gmail Anda untuk menerima masuk dari aplikasi yang kurang aman. Tentu saja, ini dapat menimbulkan beberapa kerentanan pada akun Gmail Anda, tetapi Anda dapat melakukannya hanya untuk waktu yang singkat sehingga Anda perlu menguji aplikasi ini di localhost. Setelah pengujian, Anda dapat membatalkan pengaturan pada akun Gmail Anda. Setelah aplikasi Anda di-host di internet, Anda akan bekerja. Kami melakukan ini hanya karena kami menggunakan localhost.
Anda dapat lebih berhati-hati dan membuat akun Gmail lain hanya untuk tujuan seperti ini.
Jadi, masuk ke Gmail di browser Anda, buka https://myaccount.google.com/security#connectedapps dan ubah nilai 'Izinkan aplikasi yang kurang aman' menjadi AKTIF.
Anda dapat menonaktifkannya setelah selesai menguji proyek di localhost.
Dengan ini, Anda akan dapat mengirim email dari localhost dengan tautan verifikasi setelah pengguna mendaftar. Sekarang lihat metode sendVerificationEmail() lagi dan Anda akan melihat bahwa di badan email yang kami kirim ke pengguna, token yang kami buat untuk pengguna tertentu (token unik) telah ditetapkan sebagai parameter pada tautan sehingga ketika pengguna mengklik link di email, mereka akan diarahkan ke aplikasi kita di halaman yang disebut verifikasi_email.php dengan token tersebut di URL. Seperti ini:
<a href="http://localhost/cwa/verify-user/verify_email.php?token=0a150966418fa3a694bcb3ab8fcacd2063a096accc0ee33c3e8c863538ee825c0b52f2e1535d0e1377558c378ba5fc3106eb">Verify Email!</a>
Jadi kita bisa mendapatkan token ini di verifikasi_email.php kita seperti ini (tenang saja, kita akan segera membuat verifikasi_email.php ini):
$token = $_GET['token'];
Kami sekarang dapat menggunakan token ini untuk mengambil pengguna yang memiliki token khusus ini (ingat token itu unik) dan jika kami mendapatkan pengguna itu, kami memperbarui catatan mereka dengan mengubah atribut terverifikasi menjadi true di database. Kemudian, dengan bangga kami katakan bahwa kami telah memverifikasi alamat email pengguna tersebut.
Mari buat file verifikasi_email.php ini di folder root proyek kita:
verifikasi_email.php:
<?php
session_start();
$conn = new mysqli('localhost', 'root', '', 'verify-user');
if (isset($_GET['token'])) {
$token = $_GET['token'];
$sql = "SELECT * FROM users WHERE token='$token' LIMIT 1";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
$user = mysqli_fetch_assoc($result);
$query = "UPDATE users SET verified=1 WHERE token='$token'";
if (mysqli_query($conn, $query)) {
$_SESSION['id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['email'] = $user['email'];
$_SESSION['verified'] = true;
$_SESSION['message'] = "Your email address has been verified successfully";
$_SESSION['type'] = 'alert-success';
header('location: index.php');
exit(0);
}
} else {
echo "User not found!";
}
} else {
echo "No token provided!";
}
Perhatikan bahwa menyetel nilai nilai terverifikasi ke 1 sama dengan menyetelnya ke true karena di database MySQL, jenis Boolean ditafsirkan sebagai tinyint.
Sekarang ketika pengguna mengklik tautan di email mereka dan membawa mereka ke halaman ini, itu memperbarui status terverifikasi pengguna menjadi true, memasukkan mereka dan mengarahkan mereka ke halaman index.php. Di halaman indeks, setelah memverifikasi pengguna, Anda akan melihat bahwa pesan peringatan yang menyarankan pengguna untuk memverifikasi alamat email mereka sekarang hilang dan sebagai gantinya kami memiliki "Saya telah diverifikasi!!!" tombol yang hanya dapat dilihat oleh pengguna terverifikasi.
Satu hal terakhir, pada halaman index.php setelah pengguna login, ada link logout yang menunjuk ke file logout.php yang seharusnya membuat pengguna logout. Mari kita buat file itu di root aplikasi kita:
logout.php:
<?php
session_destroy();
unset($_SESSION['id']);
unset($_SESSION['username']);
unset($_SESSION['email']);
unset($_SESSION['verify']);
header("location: login.php");
Jadi selain bisa sign up, verifikasi email, sign in, user sekarang juga bisa logout.
Kesimpulan
Jadi itu saja dengan pendaftaran pengguna dan verifikasi email. Jika Anda memiliki komentar, pertanyaan, atau kata-kata penyemangat, silakan tinggalkan di komentar di bawah. Dan tolong, jangan lupa untuk membagikan posting ini atau merekomendasikan situs ini ke teman Anda jika Anda merasa terbantu. Ini sangat mendorong saya!
Semoga harimu menyenangkan!