Rabu, 18 September 2013

Aplikasi Database MySQL dengan Heroku dan CloudBees


Pada artikel sebelumnya tentang hosting PHP gratisan menggunakan layanan heroku.com saya telah mencoba membahas tentang apa itu heroku dan bagaimana melakukan administrasi sederhana seperti cara mendeploy app dan menggunakan git untuk melakukan manajemen file. Karena memang hanya untuk perkenalan maka disitu tidak dibahas bagaimana cara membuat aplikasi yang menggunakan database. Sebenarnya di heroku terdapat addon untuk bermacam hal, termasuk untuk mendapatkan database MySQL secara gratis, hanya saja sebelum bisa benar-benar menggunakannya kita harus terlebih dahulu memvalidasi pembayaran (biasanya dengan kartu kredit). Karena itu, masih dengan semangat "cari yang gratis", kita cari cloud database lain yang bisa kita gunakan untuk menyimpan data dari aplikasi PHP yang kita buat di heroku.

Kandidat


Pencarian awal di google saya menemukan beberapa kandidat yang akan kita bahas satu persatu. Kita tidak akan terlalu teknis membahas fasilitas, kemampuan dan fitur dari masing-masing cloud database yang saya sebutkan karena satu hal yang paling mendasar sebenarnya adalah: GRATIS.


  1. Xeround.com. Saya dulu sempat menggunakan layanan disini, pendaftaran mudah, gratis dan disediakan halaman phpMyAdmin, sempurna. Tapi ternyata entah kenapa layanan nya ditutup pada bulan Mei 2013. Karena tidak dapat digunakan lagi maka kita coret kandidat ini.
  2. AWS Amazon. Cukup menjanjikan sebenarnya sebelum saya menyadari bahwa saat pendaftaran terdapat step untuk melakukan validasi pembayaran menggunakan kartu kredit. Kandidat ini juga kita coret.
  3. ClearDB. Lebih menjanjikan dibandingkan dengan AWS Amazon namun dia hanya bisa digunakan untuk aplikasi yang berjalan di appfog dan heroku. Pas sebenarnya, tapi di heroku dia menjadi addon yang kalau ingin menggunakan harus validasi pembayaran juga. Kita coret juga kandidat ini.
  4. Google Cloud. Dilengkapi dengan database MySQL dan berasal dari Google harusnya kandidat ini meyakinkan, tapi sayang, harus validasi pembayaran juga meskipun kita ingin mencoba yang gratis. Jadi terpaksa kandidat ini kita coret.
  5. CloudBees. Tidak begitu terkenal dibanding kandidat sebelumnya tapi ternyata lumayan menjanjikan. Pendaftaran mudah tanpa menggunakan kartu kredit, dan dapat menggunakan akun Google kita untuk mendaftar. Dengan kapasitas 5 MB cloud database ini layak digunakan untuk coba-coba. Hanya saja saya belum menemukan halaman phpMyAdmin disitu :), karena untuk administrasi databasenya oleh cloudbees kita dianjurkan menggunakan SQLyog.


Membuat dan Mengatur Database di CloudBees


Setelah terdaftar, Anda akan diberi pilihan untuk melanggan layanan yang ada tergantung kebutuhan Anda. Klik layanan database di bagian atas dan subscribe. Setelah itu buat Database baru, beri nama database nya, username, password dan klik Finish. Setelah dibuat klik database tersebut dan akan muncul halaman untuk manajemen database seperti gambar berikut:





Beberapa parameter akan kita gunakan untuk melakukan koneksi ke database di cloudbees seperti Server, Port, Username dan Password.
Dengan parameter ini kita sudah bisa bernafas lega karena mendapatkan database gratis yang bisa kita gunakan untuk menyimpan data aplikasi yang kita buat. Namun mungkin muncul masalah baru, bagaimana mengatur database yang sudah ada, bagaimana membuat tabel, melihat data pada tabel, drop tabel dan sebagainya. Jika Anda mengikuti anjuran dari cloudbees, Anda dapat menggunakan SQLyog, tapi saya lebih nyaman dengan tampilan berbasis web jadi saya gunakan DBNinja seperti ini.



Mengkoneksikan App di Heroku ke Database di CloudBees


Anggap kita sudah mempunyai app di heroku. Untuk menguji apakah applikasi di heroku dapat terkoneksi ke cloudbees kita buat script sederhana seperti ini:


<?php

/**
 * DATABASE CONNECTION
 */

$host = 'ec2-23-21-211-172.compute-1.amazonaws.com:3306';
$user = 'username';
$pass = 'password';
$dbnm = 'database';

$link = mysql_connect($host, $user, $pass);
if ( ! $link) {
    die('Could not connect: ' . mysql_error());
}

$db_selected = mysql_select_db($dbnm, $link);
if ( ! $db_selected) {
    die ('Can\'t use ' . $dbnm . ' : ' . mysql_error());
}

Simpan dengan nama file dbconfig.php misalnya. Lakukan upload file ini ke heroku dengan git push dan coba akses halaman: namaapp.heroku.com/dbconfig.php. Jika tidak muncul error apapun maka Anda telah berhasil mengkoneksikan aplikasi di heroku Anda dengan cloud database di cloudbees. Terima kasih dan Happy coding :D

Sumber:

  1. http://www.comtechies.com/2013/03/how-to-create-and-connect-cloudbees.html 
  2. http://www.sitepoint.com/database-as-a-service-mysql-in-the-cloud/


Jumat, 24 Mei 2013

Format Angka Input Ribuan Dengan Jquery



Sebenarnya yang dibahas disini adalah hal yang sangat sederhana dimana saat kita memasukkan input angka, maka input langsung otomatis membuat pemisah angka ribuan dengan tanda titik. Misalkan kita mengetik angka 9000 tapi yang muncul di input menjadi 9.000. Aku punya contoh kasus seperti ini:
  1. Anggap saja kita buat aplikasi kasir sederhana dimana terdapat 3 input (total, bayar dan kembalian)
  2. Input total dan kembalian dijadikan readonly agar tidak bisa diedit
  3. Saat kita mengisikan input bayar, maka format angka di input tersebut akan berubah dengan adanya pemisah angka ribuan
  4. Saat input bayar diisi, input kembalian akan berubah otomatis berdasarkan jumlah angka yang dimasukkan di input bayar
Kita buat kerangka HTML + CSS nya dulu
<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Input Formatter</title>
 <style>
* { margin: 0; padding: 0; }
body {
 font-family: Arial, sans-serif;
 font-size: 14px;
}
.container { margin: 50px auto; width: 80%; }
input[type="text"] {
 font-family: Arial, sans-serif;
 font-size: 14px;
 padding: 5px 1px;
}
table td { margin: 10px 0px; }
input[readonly] { cursor: not-allowed; }
 </style>
</head>
<body>
 <div class="container">
  <form action="post" novalidate>
   <table>
    <tr>
     <td style="width: 150px;"><h4>TOTAL</h4></td>
     <td>Rp. <input type="text" name="input_total" id="input-total" value="" readonly></td>
    </tr>
    <tr>
     <td><h4>BAYAR</h4></td>
     <td>Rp. <input type="text" name="input_bayar" id="input-bayar" value=""></td>
    </tr>
    <tr>
     <td><h4>KEMBALI</h4></td>
     <td>Rp. <input type="text" name="input_kembali" id="input-kembali" value="" readonly></td>
    </tr>
   </table>
  </form>
 </div>
 <script src="jquery-1.9.0.min.js"></script>
</body>
</html>
Tidak ada yang istimewa di kode HTML diatas, pastikan file jquery sudah dimasukkan menggunakan tag script. Di kode diatas terdapat tiga input yang saya letakkan di dalam tabel untuk mengurangi styling yaitu input-total, input-bayar, dan input-kembali. Sekarang kita masukkan kode javascript yang akan memproses input yang kita masukkan dan masukkan kode javascript ini setelah script dari jquery.
<script>

// memformat angka ribuan
function formatAngka(angka) {
 if (typeof(angka) != 'string') angka = angka.toString();
 var reg = new RegExp('([0-9]+)([0-9]{3})');
 while(reg.test(angka)) angka = angka.replace(reg, '$1.$2');
 return angka;
}
 
// nilai total ditulis langsung, bisa dari hasil perhitungan lain
var total = 4500,
 bayar = 0,
 kembali = 0;

// masukkan angka total dari variabel
$('#input-total').val(formatAngka(total));

// tambah event keypress untuk input bayar
$('#input-bayar').on('keypress', function(e) {
 var c = e.keyCode || e.charCode;
 switch (c) {
  case 8: case 9: case 27: case 13: return;
  case 65:
   if (e.ctrlKey === true) return;
 }
 if (c < 48 || c > 57) e.preventDefault();
}).on('keyup', function() {
 var inp = $(this).val().replace(/\./g, '');
 
 // set nilai ke variabel bayar
 bayar = new Number(inp);
 $(this).val(formatAngka(inp));
 
 // set kembalian, validasi
 if (bayar > total) kembali = bayar - total;
 if (total > bayar) kembali = 0;
 $('#input-kembali').val(formatAngka(kembali));
});
</script>
Kode diatas sudah saya beri beberapa komentar sehingga setidaknya sudah memberikan gambaran apa yang dilakukan pada beberapa hal yang saya anggap penting. Beberapa hal yang perlu diperhatikan adalah penambahan event onkeypress dan onkeyup pada input-bayar yang akan mengubah isi input-bayar sendiri sekaligus mengubah isi di input-kembali. Semoga posting ini bermanfaat dan terima kasih :D. Happy Coding!

Rabu, 01 Mei 2013

Membuat Request Ajax dari local filesystem (file:///) dengan Google Chrome



Untuk alasan keamanan, semua request Ajax haruslah mengakses file yang memiliki origin yang sama, sehingga request Ajax dengan local filesystem secara default tidak dapat dilakukan meskipun file target hanya file xml atau html biasa. Karena itulah file yang menggunakan Ajax tersebut haruslah diletakkan pada web server. Mozilla dan Safari tidak konsisten menerapkan hal ini karena pada beberapa kondisi browser masih mengijinkan request Ajax yang berasal dari file local dan menghasilkan output yang tidak terduga. File local adalah file HTML yang dibuka dengan menggunakan double click atau dengan context menu Open sehingga alamat yang muncul di address bar adalah mirip seperti ini: "file:///C://my/path/index.html"




Google Chrome tidak mengijinkan sama sekali request Ajax yang berasal dari file local, dan akan memunculkan error seperti ini bila dilihat di Console:




Namun kita bisa "memaksa" Chrome untuk memperbolehkan request Ajax dari file local dengan "memulai" Chrome disertai opsi "--allow-file-access-from-files". Ikuti cara berikut:

1. Buka CMD (Command Prompt) dan arahkan ke folder dimana Google Chrome berada, di Windows 7 biasanya ada di C:\Users\ADMINUSER\AppData\Local\Google\Chrome\Application (*bagian ADMINUSER bisa berbeda tergantung User di komputermu)

2. Setelah berada di folder Application, ketik perintah berikut:
chrome --allow-file-access-from-files




3. Google Chrome akan terbuka. Jangan ditutup browsermu, terus cari file HTMLmu yang berisi request Ajax dengan Windows Explorer, lalu klik Open With -> Google Chrome, atau jika Chrome sudah menjadi browser default maka tinggal di double click icon file HTML tersebut.

4. Sekarang Chrome bisa menjalankan file HTML yang berisi request Ajaxmu dengan baik :)

PERHATIAN: "memaksa" Chrome seperti ini tidak baik untuk kedepannya, cara terbaik adalah meletakkan file HTML mu di webserver. Gunakan Node.js untuk membuat webserver sederhana, dengan Node.js kamu tidak perlu menginstal apapun dan servernya bisa portable dan bisa langsung dijalankan dari removable media seperti flashdisk atau CD. Jika ingin menginstal webserver Apache + PHP dan MySQL bisa menggunakan XAMPP installer.

Selasa, 12 Februari 2013

Modifikasi Typeahead Bootstrap dan Ajax

Jika kamu belum tahu apa itu Bootstrap bisa dilihat disini. Jika kamu sudah tahu Bootstrap tapi belum tahu tentang Typeahead bisa dilihat disini. Secara singkat Typeahead adalah input yang memunculkan pilihan saat kita mengetikkan sesuatu yang mirip dengan input yang kita masukkan. Contoh: waktu kamu mengetikkan nama di Facebook pasti muncul pilihan pada input tersebut daftar teman-temanmu yang memiliki nama yang mirip dengan input yang kamu masukkan.
Bootstrap memiliki Typeahead yang sebenarnya sudah cukup keren, tapi kita akan memodifikasi Typeahead ini agar bisa menampilkan foto dan menerima sumber data dari Ajax sehingga mirip dengan input di Facebook. Jika kamu penasaran bentuk asli dari Typeahead kita akan buat kerangka dasarnya dulu.

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Typeahead</title>
  <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" media="all">
  <link rel="stylesheet" href="bootstrap/css/bootstrap-responsive.min.css" media="all">
  <script src="jquery/jquery-1.9.0.min.js"></script>
  <script src="bootstrap/bootstrap.min.js"></script>
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="span8 offset2">
        <h3>Bootstrap Typeahead</h3>
        <hr>
        <form class="form-horizontal">
          <div class="control-group">
            <label for="artis" class="control-label">Pilih Artis</label>
            <div class="controls">
              <input type="text" name="artis" id="artis" class="input-xlarge" data-provide="typeahead" data-source='["Maria Selena", "Gita Gutawa", "Sandra Dewi", "Citra Kirana"]'>
            </div>
          </div>
          <div class="form-actions">
            <button class="btn btn-primary">SIMPAN</button> &nbsp;
            <button class="btn">BATAL</button>
          </div>
        </form>
      </div>
    </div>
  </div>
</body>
</html>

Untuk path css dan javascriptnya ubah sesuai dengan letak file Bootstrap dan jQuery yang kamu punyai. Untuk mengaplikasi typeahead pada sebuah input sangatlah mudah, bahkan cuma menambahkan atribut data-provide="typeahead" dan data-source yang beruba array string maka typeahead sudah bisa berjalan seperti pada gambar ini:



Lumayan keren kan?, tapi sekarang kita akan memodifikasinya sehingga bisa menampilkan foto bersama dengan namanya. Bootstrap Typeahead memiliki API yang bisa kita ubah agar kita dapat mengubah tampilan defaultnya yaitu menggunakan highlighter dan updater. Berikut ini kode Javascriptnya yang bisa kamu masukkan dimanapun (sebaiknya sebelum tutup tag BODY).
/* 
 * load data dengan ajax dimana data yang diperoleh memiliki format:
 * [{ nama: 'nama artist', foto: 'url foto' }]
 *
 * jika tidak menggunakan ajax langsung masukkan di source
 */
$.ajax({
  url: 'respond.php?artis',
  dataType: 'json',
  success: function(d) {
    var data = d;
    
    /*
     * ini deklarasi typeaheadnya yang sudah dimodifikasi
     */
    $('#artis').typeahead({
      source: function(query, process) {
        objects = [];
        // iterasi data
        $.each(data, function(i, object) {
          objects.push(object.foto + '#' + object.nama);
        });
        process(objects);
      },
      items: 4, // jumlah list maksimal yang muncul
      highlighter: function(item) {
        var s = item.split('#'),
          regex = new RegExp('(' + this.query + ')', 'i'),
          nama = s[1].replace(regex, "<strong>$1</strong>");
        html = '<div class="typeahead">';
        html += '<div class="typeahead-media"><img src="img/' + s[0] + '" class="pull-left">';
        html += '<div class="media-body">';
        html += '<p class="media-heading">' + nama + '</p>';
        html += '</div>';
        html += '</div>';
        return html;
      },
      updater: function(item) {
        var s = item.split('#');
        return s[1];
      },
      matcher: function(item) {
        var s = item.split('#');
        return s[1].toLowerCase().indexOf(this.query.toLowerCase()) != -1
      }
    });
  }
});

Dan hasil yang kita peroleh seperti gambar ini:



Sebaiknya ukuran file gambarnya sama dan berbentuk bujursangkar. Karena tampilannya masih acak-acakan kita butuh sedikit CSS untuk merapikannya. Tambahkan kode CSS ini di dalam tag HEAD:
ul.typeahead.dropdown-menu {
  min-width: 370px; }
ul.typeahead li a {
  padding: 4px; }
.typeahead-media img {
    width: 28px;
  margin-right: 5px; }

Dan inilah hasil akhirnya:



Gak jelek2 amat kan :D. Semoga bermanfaat.

Jika kamu penasaran dan ingin tahu seperti apa file php yang memproses request sehingga menghasilkan bentuk yang diinginkan maka ini contoh kerangka kodenya:

<?php
if (isset($_GET['artis'])) {
  $query = mysql_query("SELECT `nama`, `foto` FROM `artis`");
  $hasil = array();
  while ($d = mysql_fetch_array($query, MYSQL_ASSOC)) {
    $hasil[] = array(
      'nama' => $d['nama'],
      'foto' => $d['foto']
    );
  }
  echo json_encode($hasil, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
}

Senin, 11 Februari 2013

Pagination dengan CodeIgniter, jQuery dan Bootstrap

Karena ada beberapa teman yang kesulitan mengaplikasikan pagination di CodeIgniter dengan jQuery, maka aku coba membuat sesuatu yang menurutku simple dan mudah dipahami (*semoga :). Kali ini aku akan menggunakan Twitter Bootstrap untuk CSS-nya dan jQuery untuk meload data. Kerangka dasar dokumennya adalah seperti ini:
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Pagination</title>
  <link rel="stylesheet" href="/third_party/bootstrap/css/bootstrap.min.css" />
  <link rel="stylesheet" href="/third_party/bootstrap/css/bootstrap-responsive.min.css" />
  <script src="/third_party/jquery/jquery-1.8.2.js"></script>
  <script>
    // masukkan kode javascript berikutnya disini
  </script>
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="span12">
        <h1>Pagination Dokumen</h1>
        <hr>
        <form class="form-inline">
          <input type="text" name="query" id="query" class="input-large"> &nbsp; 
          <button class="btn" onclick="return Document.search()"><i class="icon-search"></i> Cari</button>
        </form>
        <hr>
        <table class="table table-bordered table-condensed table-striped">
          <thead>
            <tr>
              <th>Judul</th>
              <th>Pengarang</th>
              <th>Tahun</th>
            </tr>
          </thead>
          <tbody id="document-data">
            <tr>
              <td></td>
              <td></td>
              <td></td>
            </tr>
          </tbody>
        </table>
        <hr>
        <div class="pagination pagination-centered pagination-medium" id="pagination">
          <ul>
            <li><a href="">&laquo;</a></li>
            <li><a href="">1</a></li>
            <li><a href="">&raquo;</a></li>
          </ul>
        </div>
      </div>
    </div>
  </div>
</body>
</html>



Pada dokumen diatas kita memiliki sebuah tabel yang akan menampilkan data dokumen dengan kolom Judul, Pengarang, dan Tahun. Diatas tabel terdapat form untuk memasukkan kata kunci pencarian. Dibawah tabel terdapat template pagination yang nanti akan diubah setelah data diload oleh Ajax. Perhatikan ada beberapa id dari elemen yang berperan yaitu:
  • query. id untuk input kata kunci pencarian
  • document-data. id di tbody tabel data
  • pagination. id untuk bagian pagination dibawah tabel
Jika diperhatikan, di tombol Cari ada atribut onclick="return Document.search()". Nah sekarang kita tambahkan fungsi Javascriptnya untuk menangani tampilan data dan pagination di dokumen ini. Kode Javascript ini bisa kamu letakkan di dalam tag HEAD setelah jquery (di bagian yang aku tandai sebelumnya).
var Document = {
  param: {
    dataperpage: 3, // jumlah data per halaman
    query: '',
    curpage: 0,
    numpage: 0
  },
  url: '/test/document',
  search: function() {
    this.param.query = $('#query').val();
    this.param.curpage = 0;
    this.loadData();
    return false;
  },
  setPage: function(n) {
    this.param.curpage = n;
    this.loadData();
    return false;
  },
  prevPage: function() {
    if (this.param.curpage > 0) {
      this.param.curpage--;
      this.loadData();
    }
    return false;
  },
  nextPage: function() {
    if (this.param.curpage < this.param.numpage) {
      this.param.curpage++;
      this.loadData();
    }
    return false;
  },
  loadData: function() {
    $.ajax({
      url: Document.url,
      type: 'POST',
      dataType: 'json',
      data: jQuery.param(Document.param),
      success: function(d) {
        $('#pagination').html(d.pagination);
        Document.param.numpage = d.numpage;
        var t = '', dt = {};
        for (var i = 0; i < d.data.length; i++) {
          dt = d.data[i];
          t += '<tr><td>' + dt.judul +'</td>' + 
             '<td>' + dt.pengarang + '</td>' + 
             '<td>' + dt.tahun + '</td></tr>';
        }
        $('#document-data').html(t); // id dari tbody tabel data
      }
    });
  }
}

$(document).ready(function() {
  Document.search();
});
Ada bagian penting di property param dalam object Document diatas yaitu dataperpage yang berisi jumlah data perhalaman yang akan ditampilkan di tabel. Kamu bisa mengubah-ubah sesuai keinginanmu. Lalu bagian url juga harus disesuaikan dengan route yang akan kita buat di CodeIgniternya. Agar javascript meload data untuk pertamakalinya maka kita panggil Document.search() ketika dokumen siap melakui event $(document).ready(). Jangan simpan dulu file dokumen tadi karena setelah kita buat Controller baru kita bisa tahu mau disimpan dimana dokumen ini.
Sekarang kita buka file application/config/routes.php di CodeIgniter dan masukkan baris berikut:
$route['test'] = "test";
$route['test/document'] = "test/pagination";
Kita mesti punya Test controller sekarang. buat Controller baru dan beri nama Test yang isinya seperti ini:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Test extends CI_Controller {
  public function index() {
    $this->load->view('test/pagination.php');
  }
  
  public function pagination() {
    $this->load->database();
    $this->load->model('test_model');
    $this->test_model->search_document();
  }
}
Perhatikan di method index kita meload View test/pagination.php. Nah, file view ini adalah file dokumen yang berisi HTML dan Javascript yang telah kita buat sebelumnya. Berarti file dokumen tadi simpan di dalam folder application/views/test dan diberi nama pagination.php. Kalau kamu punya struktur view dan controller sendiri maka bagian controller bisa diubah sesuai dengan struktur yang kamu punya yang penting dokumennya ketemu.
Selanjutnya di controller tadi kita lihat bahwa controller meload model test_model, berarti sekarang kita buat modelnya:
<?php
class Test_model extends CI_Model {
  public function search_document() {
    $input = array('dataperpage', 'query', 'curpage');
    foreach ($input as $val)
      $$val = $this->input->post($val);
    
    $query = $this->db->escape_like_str($query);
    $where = "`JUDUL_DOKUMEN` LIKE '%{$query}%' OR `PENGARANG_DOKUMEN` LIKE '%{$query}%'";
    
    $query = $this->db->query("SELECT COUNT(`ID_DOKUMEN`) AS `HASIL` FROM `tb_dokumen` WHERE $where");
    $total = $query->row()->HASIL;
    $npage = ceil($total / $dataperpage);
    
    $start = $curpage * $dataperpage;
    $end = $start + $dataperpage;
    $query = $this->db->query("SELECT `JUDUL_DOKUMEN`, `PENGARANG_DOKUMEN`, `TAHUN_PENERBITAN_DOKUMEN` FROM `tb_dokumen` WHERE $where LIMIT $start, $dataperpage");
    $hasil = array(
      'data' => array(),
      'pagination' => '',
      'numpage' => $npage - 1,
    );
    if ($query->num_rows() > 0) {
      foreach ($query->result() as $row) {
        $hasil['data'][] = array(
          'judul' => $row->JUDUL_DOKUMEN,
          'pengarang' => $row->PENGARANG_DOKUMEN,
          'tahun' => $row->TAHUN_PENERBITAN_DOKUMEN
        );
      }
    }
    
    $hasil['pagination'] .= '<ul>
      <li class="'. ($curpage == 0 ? 'disabled' : '') .'" onclick="return Document.prevPage()"><a href>&laquo;</li>';
    for ($i = 1; $i <= $npage; $i++) {
      $hasil['pagination'] .= '<li class="' . ($curpage == ($i - 1) ? 'active' : '') . '" onclick="return Document.setPage(' . ($i - 1) .')"><a href>' . $i . '</a></li>';
    }
    $hasil['pagination'] .= '<li class="' . ($curpage == $npage - 1 ? 'disabled' : '') . '" onclick="return Document.nextPage()"><a href>&raquo;</a></li>
      </ul>';
    
    echo json_encode($hasil, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
  }
}
Kita akan mereturn hasil berupa JSON yang akan diterima oleh Javascript. Jika kamu memiliki database yang berbeda maka ubah saja bagian model diatas dan edit sesuai keinginanmu. Dan berikut ini hasil akhirnya:



Semoga bermanfaat dan mudah dipahami :D