Membuat login remember me dengan PHP

Posted: 16 May 2016, Last updated: 17 May 2016

Sistem login yang Saya bahas di sini disadur dari sistem login pada framework Laravel. Sistem ini menggunakan session dan cookie untuk memproses login. Pertama-tama, mari kita buat form login:

Membuat Form login dengan HTML

File login.php

<html>
  <head><title>Halaman login</title></head>
  <body>
    <form method="post" action="">
      <table>
        <tr><td>Username:</td><td><input type="text" name="username" /></td></tr>
        <tr><td>Password:</td><td><input type="password" name="password" /></td></tr>
        <tr><td></td><td><input type="checkbox" name="remember" checked /> Remember me</td></tr>
        <tr><td colspan="2"><button type="submit">Masuk!</button></td></tr>
      </table>
    </form>
  </body>
</html>

Dengan menggunakan form, table dan input HTML, kita telah membuat sebuah antarmuka untuk login.

Membaca POST dari HTML dengan PHP

Berikutnya, kita coba mengambil kiriman data dari HTML tersebut dengan POST pada PHP, masih pada file login.php:

<?php
if (isset($_POST['login'])) {
  echo "<pre>".print_r($_POST, true)."</pre>";
  die();
}
?><html>
...
</html>

Pastikan jika Anda menginput form tersebut, tampil sesuatu seperti berikut:

Array
(
    [username] => fandi
    [password] => 123123
    [remember] => 1
    [login] => 
)

Membuat database login

Untuk uji coba ini, kita perlu membuat database untuk menampung data pengguna. Syntax database ini sengaja tidak menggunakan AUTO_INCREMENT pada MySQL ataupun SERIAL pada PostgreSQL agar script ini bisa dicoba oleh semua. Jalankan perintah berikut pada database:

CREATE DATABASE coba;

Pindah ke database coba: USE coba; pada MySQL atau \c coba pada PostgreSQL. Dan tentunya Anda juga boleh menggunakan GUI pada phpMyAdmin atau phpPgAdmin.

CREATE TABLE login (
  id INT,
  username VARCHAR(100) NOT NULL,
  password VARCHAR(100) NOT NULL,
  remember_token VARCHAR(100),
  remember_expiry INT,
  CONSTRAINT pk_login PRIMARY KEY (id),
  CONSTRAINT uq_username_login UNIQUE (username)
);
CREATE INDEX idx_remember_login ON login (remember_token);

Koneksi ke database dengan PHP

Untuk berinteraksi dengan database melalui PHP, kita akan menggunakan class PDO. Buat script nyambung.php:

<?php
list($host, $db, $user, $pass, $port) = ["localhost","coba","fandi", "123", 5432];
$pdo = new \PDO(
  "pgsql:host=$host;port=$port;dbname=$db;", $user, $pass, array(
    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
    \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_OBJ
  ));

Untuk koneksi ke MySQL, Anda dapat menyesuaikan kode di atas seperti pada tutorial koneksi PDO.

Mengisi data ke dalam tabel login

Kita tidak membahas register pengguna di sini, jadi kita langsung saja insert beberapa data ke dalam tabel login. Kita menggunakan script PHP isidata.php:

<?php
include "nyambung.php";
$stmt = $pdo->query("SELECT COUNT(*) FROM login");
$baris = $stmt->fetch();
if ($baris->count > 0) { //kolom count dari query
  echo "Data login telah ada";
  die();
}
//class Login
class Login {
  public $id, $username, $password;
  public function __construct($arr) {
    foreach ($arr as $k=>$v) $this->$k = $v;
  }
}
//data-data login
$logins = [
  new Login(["id"=>1, "username"=>"user1", "password"=>hash('haval256,4','123')]),
  new Login(["id"=>2, "username"=>"user2", "password"=>hash('haval256,4','456')]),
  new Login(["id"=>3, "username"=>"user3", "password"=>hash('haval256,4','789')]),
];
//insert ke database
try {
  $stmt = $pdo->prepare("INSERT INTO login VALUES (:id,:username,:password, null, 0)");
  foreach ($logins as $objLogin) $stmt->execute((array)$objLogin);
} catch (Exception $ex) {
  echo $ex->getMessage();
  throw $ex;
}
echo "Insert berhasil";

Tentunya Anda perlu mengunjungi localhost/folder/coba/anda/isidata.php lewat browser agar data tersebut terisi.

Melakukan login

Sekarang mari kita membuat script untuk menerima login. Kita buat juga class.Login.php agar script kita lebih rapi.

<?php
class Login {
  public $id, $username, $password, $remember_token, $remember_expiry;
  public function __construct($arr) {
    foreach ($arr as $k=>$v) $this->$k = $v;
  }
  static function findByUsername($username) {
    include "nyambung.php";
    $stmt = $pdo->prepare("SELECT * FROM login WHERE username=:user");
    $stmt->execute(["user"=>$username]);
    $baris = $stmt->fetch();
    if ($baris != null) return new Login($baris);
    return null;
  }
}

Kemudian kita gunakan dalam script login.php yang tadi:

<?php
session_start();
if (isset($_POST['login'])) {
  include "class.Login.php";
  $objLogin = Login::findByUsername($_POST['username']);
  if (!$objLogin) {
    echo "User tidak dikenal"; die();
  }
  elseif ($objLogin->password != hash("haval256,4",$_POST['password'])) {
    echo "Password salah"; die();
  }
  die("Login berhasil");
}
?><html>
...
</html>

Tentunya bagian dalam <html> tidak berubah. Jika sudah berhasil, kita tambahkan lebih lanjut proses loginnya: menyimpan ke dalam session dan pindah ke halaman home. Ubah baris die("Login berhasil"); menjadi:

  $objLogin->login();
  header("location:/home.php");

Lalu tambahkan method login di dalam class.Login.php:

  public function login() {
    $_SESSION['login'] = $this;
  }

Sampai di sana, Anda sudah dapat melakukan login. Bila user dan pass benar, maka script akan diarahkan ke home.php.

Menambahkan fitur remember me pada login

Kita perlu menambahkan pengecekan input pada checkbox remember. Tambahkan di bagian atas $objLogin->login(); pada login.php:

  if (isset($_POST['remember']) && $_POST['remember'] == 'on') {
    $objLogin->login(time() + 3600 * 24 * 14);
  }
  else $objLogin->login();
  header("location:/home.php");

Dan update method login pada class.Login.php:

  public function login($expiry=0) {
    if ($expiry>0) {
      $token = hash('ripemd256',time());
      setcookie("login",$token,$expiry);
      $this->remember_token = $token;
      $this->remember_expiry = $expiry;
    } else {
      $this->remember_token = '';
      $this->remember_expiry = 0;
    }
    //update ke database
    include "nyambung.php";
    try {
      $sql = "UPDATE login SET remember_token=:token, remember_expiry=:expiry WHERE id=:id";
      $stmt = $pdo->prepare($sql);
      $stmt->bindParam("token",$this->remember_token);
      $stmt->bindParam("expiry",$this->remember_expiry);
      $stmt->bindParam("id",$this->id);
      $stmt->execute();
    } catch (Exception $ex) {
      echo $ex->getMessage();
      die();
    }
    $_SESSION['login'] = $this;
  }

Method tersebut akan membuat dan menyimpan token remember me ke dalam database. Tetapi bila user melakukan login tanpa mencentang "remember", token akan dihapus. Sedangkan tampak luar program, masih sama seperti sebelumnya. Login seperti biasa.

Login dengan cookie tanpa session

Sebelum melanjutkan, Anda mungkin tertarik untuk membaca tentang cookie pada PHP. Dan ada baiknya kita buat dulu script home.php:

<?php
include "class.Login.php";
session_start();
if (isset($_SESSION['login'])) {
  echo "Selamat datang ".$_SESSION['login']->username;
} else {
  echo "Anda belum login";
}

Untuk mencoba login dengan cookie saja, kita perlu mencoba menghapus session untuk mengemulasi session yang telah expired. Kita coba membuat logout.php:

<?php
include "class.Login.php";
session_start();
if ($_GET['tipe'] == "session") {
  //hapus session saja
  unset ($_SESSION['login']);
} else {
  //hapus session dan cookie
  unset ($_SESSION['login']);
  setcookie("login",'',time()-1);
}
header("location:/home.php");

Kita coba hapus session dengan mengunjungi localhost/logout.php?tipe=session. Kita akan diarahkan kembali ke halaman home dengan pesan "Anda belum login". Sekarang kita coba login menggunakan cookie. Tambahkan method findByToken di class.Login.php:

  static function findByToken($rememberToken) {
    include "nyambung.php";
    $stmt = $pdo->prepare("SELECT * FROM login WHERE remember_token=:token");
    $stmt->execute(["token"=>$rememberToken]);
    $baris = $stmt->fetch();
    if ($baris != null) return new Login($baris);
    return null;
  }

Lalu pada bagian echo "Anda belum login"; di home.php, ubah menjadi:

  echo "Anda belum login";
  if (isset($_COOKIE['login'])) {
    $objLogin = Login::findByToken($_COOKIE['login']);
    if ($objLogin == null) echo "Cookie login tidak valid";
    else {
      echo "<br />Berhasil login dengan cookie: <b>$objLogin->username</b>";
      $objLogin->login(time()+3600*24*14);
    }
  }

Jika setelah logout muncul tulisan seperti:

Anda belum login
Berhasil login dengan cookie: user2

Berarti Anda telah berhasil melakukannya. Source code lengkap tutorial ini dapat didownload di SINI.