Tampilkan postingan dengan label php. Tampilkan semua postingan
Tampilkan postingan dengan label php. Tampilkan semua postingan

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/


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

Kamis, 06 September 2012

Combobox Dinamis dengan PHP dan Javascript


Kasus: ada input combobox pilih provinsi, setelah dipilih, tiba-tiba combobox kabupaten berubah isinya. Oke, langsung saja kita buat hal semacam itu dengan gabungan PHP serta Javascript.

Tugas PHP


Kemungkinan besar kamu menyimpan data provinsi dan kabupaten di database atau di file. Nah, PHP berguna untuk mengambil data tersebut dan mempersiapkannya untuk digunakan Javascript mengubah isian combobox secara dinamis. Jika kamu memiliki data yang sudah ada di dalam Javascript tentu saja kamu tidak butuh PHP lagi.

Tugas Javascript


Dia akan mendeteksi perubahan combobox provinsi lalu secara otomatis mengubah isi di combobox kabupaten. Ada beberapa metode yang dilakukan oleh Javascript dalam melakukan hal ini antara lain:


  1. Saat combobox provinsi berubah, Javascript melakukan request Ajax ke file PHP untuk mendapatkan data yang akan diisikan di combobox kabupaten (mungkin ada jeda sebelum input kabupaten berubah karena request Ajax)
  2. Data dari PHP diubah ke JSON pada halaman tersebut dan Javascript langsung membacanya (ini lebih cepat tapi untuk data yang besar browsermu akan menyita cukup banyak memory)


Contoh yang aku berikan nanti akan menggunakan cara kedua karena datanya hanya sedikit.

HTML


Berikut ini kode HTML sebagai kerangka dasarnya, masalah tampilan dicuekin saja :)

<?php
// tulis php disini
?><!DOCTYPE html>
<html>
<head>
<title>Combobox Dinamis</title>
</head>
<body>
<form method="post" action="">
Provinsi: <select name="provinsi" id="provinsi"></select><br /><br />
Kabupaten: <select name="kabupaten" id="kabupaten"></select><br /><br />
<button type="submit">SIMPAN</button>
</form>

<script type="text/javascript">
// tulis javascript disini
</script>
</body>
</html>

PHP


Tulis kode ini di bagian PHP (paling atas sebelum DOCTYPE)

<?php
// data provinsi bisa saja dari database, misalkan dengan query
// SELECT * FROM provinsi
// dengan kolom: id_provinsi, nama_provinsi
$provinsi = array(
0 => array('1', 'Banten'),
1 => array('2', 'Yogyakarta'),
2 => array('3', 'Bali'),
);

// data kabupaten, kalau dari database
// SELECT * FROM kabupaten
// dengan kolom: id_kabupaten, id_provinsi, nama_kabupaten
$kabupaten = array(
0 => array('1', '1', 'Tangerang'),
1 => array('2', '1', 'Serang'),
2 => array('3', '1', 'Lebak'),
3 => array('4', '1', 'Pandeglang'),
4 => array('5', '1', 'Cilegon'),
5 => array('6', '2', 'Bantul'),
6 => array('7', '2', 'Sleman'),
7 => array('8', '2', 'Kulonprogo'),
8 => array('9', '2', 'Gunungkidul'),
8 => array('10', '2', 'Yogyakarta'),
9 => array('11', '3', 'Badung'),
10 => array('12', '3', 'Bangli'),
11 => array('13', '3', 'Buleleng'),
12 => array('14', '3', 'Gianyar'),
13 => array('15', '3', 'Jembrana'),
14 => array('16', '3', 'Karangasem'),
15 => array('17', '3', 'Klungkung'),
16 => array('18', '3', 'Tabanan'),
17 => array('19', '3', 'Denpasar'),
);

?>

Di kode diatas data provinsi dan kabupaten dituliskan langsung tapi bisa saja data itu berasal dari database. Asalkan kamu tahu asal-usul dan bentuk data yang ada tentunya tidak akan sulit untuk menggunakannya dan disesuaikan dengan data yang kamu punya.

Javascript


Berikut ini kode javascript yang digunakan, tuliskan sebelum tag body (paling bawah)

<script type="text/javascript">

// mendapatkan object dalam document
function getObject(id) {
return document.getElementById(id);
}

// ubah data array PHP ke JSON
var provinsi = <?php echo json_encode($provinsi) ?>;
var kabupaten = <?php echo json_encode($kabupaten) ?>;

var option = '<option value="0" selected>-- pilih provinsi --</option>',
// opsi default dengan nilai 0
comboprovinsi = getObject('provinsi'),
combokabupaten = getObject('kabupaten');

// inject provinsi
for (var i = 0; i < provinsi.length; i++) {
option += '<option value="' + provinsi[i][0] + '">' + provinsi[i][1] + '</option>';
}
comboprovinsi.innerHTML = option;

// inject kabupaten
combokabupaten.innerHTML = '<option value="0">-- pilih kabupaten --</option>';

// add event listener ke combobox, atau lebih gampang buat fungsi dan
// tambahkan property onchange di html combobox provinsi
comboprovinsi.addEventListener('change', function(e) {
var option = '',
selected = this.value;

// jika belum memilih
if (selected == '0') {
combokabupaten.innerHTML = '<option value="0">-- pilih kabupaten --</option>';
return;
}

// cacah array kabupaten
for (var i = 0; i < kabupaten.length; i++) {
if (kabupaten[i][1] == selected) {
option += '<option value="' + kabupaten[i][0] + '">' + kabupaten[i][2] + '</option>';
}
}
combokabupaten.innerHTML = option;
}, false);

</script>

Lihat variabel provinsi dan kabupaten, keduanya berasal dari array data yang dihasilkan oleh PHP dan diubah menjadi JSON menggunakan fungsi json_encode() di PHP. Untuk mengubah isi dari option dalam combobox kita menggunakan perintah innerHTML pada object element HTML yang kita dapatkan menggunakan fungsi getObject(). Fungsi getObject() berusaha mencari elemen dengan ID "provinsi" dan "kabupaten", jadi jika kamu mengubah kode diatas pastikan nama ID yang kamu gunakan benar. Kita menggunakan eventListener pada object combobox provinsi sehingga saat input ini nilainya diubah ("change") maka javascript akan mengubah isi dari combobox kabupaten.

Ada cara lain untuk menambahkan event pada combobox provinsi yaitu dengan menambahkan properti "onchange" pada tag selectnya. Contohnya seperti ini:

<select name="provinsi" id="provinsi" onchange="ubahKabupaten(this)"></select>

otomatis Javascriptnya juga berubah, kita tidak menggunakan addEventListener lagi tapi langsung saja buat fungsi ubahKabupaten() seperti ini:

function ubahKabupaten(obj) {
...
}

Dengan jQuery?


Jika kamu belum tau jQuery, coba googling dulu. Pastikan kamu sudah menginclude jQuery ke halamanmu dengan tag <script src="path/ke/jquery"></script>. Perubahannya hanya pada bagian untuk mendapatkan object DOM. berikut ini kodenya (kalau pakai jQuery berarti kode Javascript sebelumnya diganti dengan yang ini):

<script type="text/javascript">

// ubah data array PHP ke JSON
var provinsi = <?php echo json_encode($provinsi) ?>;
var kabupaten = <?php echo json_encode($kabupaten) ?>;

var option = '<option value="0" selected>-- pilih provinsi --</option>',
$comboprovinsi = $('#provinsi');

var $combokabupaten = $('#kabupaten').html('<option value="0">-- pilih kabupaten --</option>');

// inject provinsi
for (var i = 0; i < provinsi.length; i++) {
option += '<option value="' + provinsi[i][0] + '">' + provinsi[i][1] + '</option>';
}

$comboprovinsi.html(option).on('change', function() {
var option = '', 
selected = $(this).val();

// jika belum memilih
if (selected == '0') {
$combokabupaten.html('<option value="0">-- pilih kabupaten --</option>');
return;
}

// cacah array kabupaten
for (var i = 0; i < kabupaten.length; i++) {
if (kabupaten[i][1] == selected) {
option += '<option value="' + kabupaten[i][0] + '">' + kabupaten[i][2] + '</option>';
}
}
$combokabupaten.html(option);
});

</script>

Demikianlah combobox dinamis versiku semoga bermanfaat. Jika kamu berminat mendapatkan sourcenya ada disini. Happy coding :)

Rabu, 22 Agustus 2012

Hosting PHP Gratisan Dengan Heroku


Apa itu heroku?


Heroku adalah web hosting berbasis Cloud yang biasanya digunakan untuk mengembangkan web app menggunakan beragam bahasa pemrograman termasuk PHP. Aku tahu heroku saat akan membuat aplikasi facebook, disitu terdapat penawaran untuk menggunakan jasa heroku bagi app yang akan kita buat. Awalnya aku bingung, ini gimana cara kerjanya ya?. Ehm, pada dasarnya menggunakan layanan heroku tidaklah sulit bahkan dapat dikatakan gampang, namun bagi orang yang baru kenal menggunakan layanan heroku akan terasa membingungkan. Pada post ini akan membahas dari awal bagaimana mendeploy app PHP di heroku dan melakukan manajemen file yang ada didalamnya.

Mulai Menggunakan Heroku (Windows)


Aku asumsikan kamu sudah terdaftar di heroku, jika belum silakan daftar disini: https://api.heroku.com/signup. Setelah itu kamu perlu mendownload heroku-toolbelt di https://toolbelt.heroku.com/. Setelah heroku-toolbelt diinstal seharusnya akan ada menu baru di Context Menu (menu yang muncul saat kamu klik kanan Explorer atau Desktop) yaitu "Git Init Here", "Git Gui" dan "Git Bash". Anggap saja kamu punya sebuah aplikasi PHP di folder manapun (biasanya di htdocs). Klik kanan di jendela Explorer lalu pilih menu "Git Bash".



Akan muncul kotak console. Lalu ketikkan perintah berikut:

$ heroku login

tanda $ akan muncul sendirinya jadi kamu cukup mengetik "heroku login" saja. Setelah itu masukkan email dan password untuk login di heroku (sama saat kamu login di halaman webnya heroku). Tampilan yang muncul kira-kira seperti ini (jika kamu login pertama kali mungkin beda sedikit tapi yang penting sukses autentifikasi).



Deploy App dan Menggunakan Git


Selanjutnya kita akan membuat subdomain di heroku, sekaligus tempat bagi aplikasi yang akan kita buat. Caranya adalah dengan mengetikkan perintah:

$ heroku create nama_app --stack cedar

"nama_app" bisa kamu ganti apapun, jika kamu tidak menentukannya maka heroku akan mengenerate otomatis untukmu. saat berhasil dibuat maka akan muncul keterangan alamat URL dari sub domain kita dan alamat dari git repository. Konsep dasarnya adalah: ada dua git yang kita gunakan, satu git yang ada di komputer lokal kita dan git remote yang ada di server heroku. Git ini akan mencatat perubahan susunan file, apa yang diedit, dihapus atau ditambah, sehingga file yang ada dikomputer kita akan selalu sama dengan yang diserver. Pencatatan seperti ini sangat berguna jika kita bekerja membuat project bekerja sama dengan orang lain.

Misalkan aku membuat project bersama programmer A, aku bisa mencopy (download) semua file yang ada diserver dengan perintah git clone. Lalu saat aku mengedit di komputer lokal dan mengupload ke server aku selalu memberi semacam "tanda" perubahan apa saja yang aku lakukan dengan perintah git commit. Programmer A pasti tidak akan kebingungan saat melihat ada perubahan karena dia bisa melihat apa saja yang aku lakukan pada project tersebut berdasarkan commit yang aku buat.

Sekarang aku sudah punya git di server heroku yaitu "git@heroku.com:nama_app.git" dan git ini masih kosong (iya lah, kan masih baru dibuat). Terus ada beberapa file PHP yang akan aku upload ke server dan sudah aku letakkan di folder htdocs, maka untuk itu aku harus membuat juga git di komputerku dengan perintah:

$ git init

kamu akan melihat ada folder .git tersembunyi di dalam folder htdocs. Setelah itu kita update git lokal kita dengan perintah:

$ git add .

ini akan menambahkan semua file disitu. kalau ingin menambah satu file maka perintahnya: $ git add namafile.ext. Saat kamu selesai mengedit suatu file maka kamu harus memanggil perintah git add agar git di lokal tahu bahwa file kita berubah. Setelah di add selanjutnya kita memerintahkan agar git mencatat semua perubahan yang kita buat dengan perintah:

$ git commit -am "keterangan perubahan"



oh iya, untuk menghapus kita gunakan git rm. Setelah perintah "git commit" digunakan berarti git lokal kita sudah terupdate, sekarang waktunya meng-uptodate git di server heroku. Kita beritahu dulu git remotenya ada dimana dengan perintah:

$ git remote add heroku git@heroku.com:nama_app.git

setelah itu saatnya mengupload dengan perintah:

$ git push heroku master



Catatan: setelah ini kamu bisa membuang kata-kata "master" dan ada satu hal lagi yaitu pastikan bahwa ada satu file "index.php" di folder kerjamu.

$ git push heroku

Seperti itulah, mudah kan?. Jadi kalau mengedit atau menambah file tinggal di git add, menghapus file tinggal di git rm, atau kalau males tinggal git add . lalu terakhir di git commit agar git kita terupdate. Setelah semua oke baru digunakan git push untuk menyimpan file kita ke server sekaligus menyamakan git lokal dengan git server. Demikianlah posting kali ini, semoga bermanfaat, dan Happy Coding.

Jika tertarik melihat hasil ujicobaku di heroku berdasarkan kode di http://nazoftware.blogspot.com/2012/08/belajar-yql.html (dengan sedikit modifikasi), bisa dilihat disini: http://nazoftware.heroku.com

Senin, 20 Agustus 2012

Membangun Facebook Apps di Localhost


Pernahkan kamu menggunakan aplikasi di fb seperti bermain game (poker, cityville, dsb), zodiak harian, random ayat, dsb? pasti pernah kan. Apa kamu terpikir untuk membuat sebuah aplikasi di facebook sendiri, karyamu sendiri, entah game, tebak-tebakan atau sekedar iseng berisi fotomu saja :). Kalau sudah terpikirkan lalu pasti muncul pertanyaan, "bagaimana membuatnya?", "susah tidak?".

Sebenarnya untuk membuat aplikasi yang "sesungguhnya" yang bisa diakses orang banyak, kamu perlu web hosting yang mendukung https, sebagai canvas dari aplikasi yang akan kamu buat. Untuk mendapatkannya kamu harus beli atau bisa juga menggunakan layanan hosting gratisan. Tapi jangan khawatir, intinya ada niat dulu, urusan lain belakangan, bisa diakali :D. Di tulisan ini masih belum menggunakan layanan hosting (baik bayar atau gratis) karena kita akan belajar membangun aplikasi facebook hanya di komputer lokal saja.

Untuk membuat aplikasi yang harus online seperti facebook apps agak meribetkan, biasanya dan seringkali kamu harus mengupload file editan terbaru berkali-kali hanya untuk memperbaiki sedikit kesalahan. Disamping nantinya kesulitan dalam menelusur versi aplikasi, pekerjaan edit lalu upload ke server bisa menjadi hal yang menjengkelkan dan melelahkan. Nah, di tulisan ini kita akan membuat apps di facebook yang dibangun pertama di server lokal komputer kita dulu (*tapi dapat semua fitur dari facebook), dan tentu saja setelah aplikasi selesai kita harus menguploadnya ke server agar dapat diakses oleh orang lain secara online.

Disini bahasa pemrograman yang dipakai adalah PHP. Jika kamu belum tahu apa itu PHP maka kamu perlu googling sebentar dan mencari tahu apa itu PHP, lalu buat program sederhana dengan PHP, baru balik kesini lagi :D. Singkatnya PHP adalah script (program) yang berjalan di server yang bertugas melayani request dari client. Tidak perlu mahir PHP atau jadi programmer top untuk membuat aplikasi di fb, tapi dengan pengetahuan PHP yang cukup akan dapat meringankan tugasmu dalam membangun aplikasi di facebook.

Yang kamu butuhkan untuk mengikuti cara pembuatan fb apps di tulisan ini adalah kamu harus memiliki:
1. web server yang terinstall di komputermu (aku menggunakan Apache dalam paket XAMPP), dengan PHP yang memiliki modul curl enabled.
2. akses internet pastinya,
3. dan sedikit pengetahuan PHP seperti yang aku bilang sebelumnya.

Daftarkan Aplikasi ke Facebook

Pertama kali kamu harus mendaftarkan aplikasi yang akan kamu buat ke facebook developer yaitu di https://developers.facebook.com/apps. Klik tombok Create New App. Selanjutnya di gambar berikut aku membuat aplikasi bernama "Unira Card Dev", dengan namespace "uniracarddev". Ikuti saja isiannya sesuai gambar terutama bagian Site URL, Canvas dsb.



Setelah terisi seperti itu lalu tekan Simpan Perubahan. Catatan: Harap simpan atau catat bagian App ID dan App Secret karena nilainya akan digunakan dalam aplikasi kita.

Download Facebook PHP SDK

Kamu bisa download di https://github.com/facebook/facebook-php-sdk yang berisi beberapa file PHP yang akan menyediakan bermacam fungsi untuk mengakses Facebook server API. Sebenarnya yang kamu perlukan cuma yang ada dalam folder "src" namun kamu bisa menggunakan beberapa contoh cara penggunaannya di folder "examples". Letakkan file-file SDK ini ke server (htdocs) mu.

Buat Aplikasinya

Sekarang buat file index.php dan letakkan di folder root (htdocs). Isi dari file index.php tersebut adalah:

<?php
define('APP_ID', 'isi dengan app id mu');
define('APP_SECRET', 'isi dengan app secret mu');

// pathnya sesuaikan dengah letak file yang kamu punya
require 'fb-php-sdk/facebook.php';

$facebook = new Facebook(array(
    'appId'  => APP_ID,
    'secret' => APP_SECRET,
));

// ada user?
$user = $facebook->getUser();

// jika iya
if ($user) {
  try {
    // dapatkan profil user yang sudah masuk
    $user_profile = $facebook->api('/me');
  } catch (FacebookApiException $e) {
    error_log($e);
    $user = null;
  }
}

if ($user) {
  $logoutUrl = $facebook->getLogoutUrl();
} else {
  $loginUrl = $facebook->getLoginUrl();
}
?>
<!doctype html>
<html xmlns:fb="http://www.facebook.com/2008/fbml">
  <head>
    <title>php-sdk</title>
    <style>
      body {
        font-family: 'Lucida Grande', Verdana, Arial, sans-serif;
      }
      h1 a {
        text-decoration: none;
        color: #3b5998;
      }
      h1 a:hover {
        text-decoration: underline;
      }
    </style>
  </head>
  <body>
    <h1>php-sdk</h1>

    <?php if ($user): ?>
      <a href="<?php echo $logoutUrl; ?>">Logout</a>
    <?php else: ?>
      <div>
        Login using OAuth 2.0 handled by the PHP SDK:
        <a href="<?php echo $loginUrl; ?>">Login with Facebook</a>
      </div>
    <?php endif ?>

    <?php if ($user): ?>
      <h3><?php echo $user_profile['name'] ?></h3>
      <img src="https://graph.facebook.com/<?php echo $user; ?>/picture">

      <h3>Your User Object (/me)</h3>
      <pre><?php print_r($user_profile); ?></pre>
    <?php else: ?>
      <strong><em>You are not Connected.</em></strong>
    <?php endif ?>
  </body>
</html>

Source codenya aku ambil dari contoh yang sudah ada dengan sedikit modifikasi. Sekarang buka browsermu dan ketik: "https://localhost" (tanpa quote/tanda petik dan perhatikan https-nya) di address bar. Jika beruntung :D kamu akan mendapatkan tampilan seperti ini:



*-- Catatan:
1. Jika yang muncul tombol login ke Facebook, klik saja.
2. Jika kamu ingin melihat aplikasimu muncul di fb buka saja halaman: https://apps.facebook.com/nama_namespace
contoh: https://apps.facebook.com/uniracarddev

Virtual Host


Secara default saat kita menginstall XAMPP kita hanya memiliki satu "domain" yaitu "localhost" sehingga kalau kamu memiliki banyak halaman web harus diletakkan dibawah "localhost" pada folder yang berbeda-beda. Dengan virtual host kamu bisa memiliki lebih banyak "domain" di komputermu contohnya: "http://kerjaanA/", "http://kerjaanB/", dsb. Keuntungan lain kamu bisa meletakkan file php-mu dimanapun (tidak hanya di htdocs saja).

Jika kamu mengembangkan banyak facebook app maka sangat dianjurkan kamu membuat virtual host di komputermu. Ada beberapa tutorial cara membuat virtual host yang bisa kamu ikuti yaitu:
1. http://sawmac.com/xampp/virtualhosts/ (berbahasa Inggris)
2. https://ri32.wordpress.com/2012/01/20/membuat-virtual-host-di-xampp/

Setelah virtual host dibuat maka nama hosting tersebut akan digunakan sebagai Site URL, Canvas URL bagi aplikasi facebook yang kamu buat.


Sekarang kamu bisa mengedit dan membang aplikasi sesukamu di localhost dan langsung mengeceknya secara langsung, kalau sudah selesai baru deh berpikir cari hosting dan kemudian upload filemu ke server yang sebenarnya. Jika kamu tertarik dengan hosting PHP gratis coba lihat disini: http://nazoftware.blogspot.com/2012/08/hosting-php-gratisan-dengan-heroku.html. Happy coding :D

Jumat, 17 Agustus 2012

Belajar YQL

YQL adalah singkatan dari Yahoo Query Language merupakan tool yang dipastikan akan dapat mempercepat penyelesaian pekerjaan pada web development. Ada banyak sekali web apps dan web service yang ada saat ini dan masing-masing memiliki API yang mau tidak mau harus dipelajari untuk dapat menggunakannya pada project yang kita buat. Dengan YQL kita tidak perlu lagi mempelajari satu persatu API tersebut, cukup dengan satu bahasa YQL maka semua akan terselesaikan dengan mudah.

Bagaimana Menggunakannya?

Tampilan console untuk YQL adalah seperti ini, kamu dapat mengaksesnya di http://developer.yahoo.com/yql/console/:


disisi kanan kamu bisa memilih "table" dalam "database". Contoh query akan muncul di kotak statement. Dibawah kotak statement akan muncul data hasil dari query baik dalam format xml atau json. Sekarang kita coba query untuk mengambil data dari feed pada alamat web tertentu:

select title from rss where url="http://rss.news.yahoo.com/rss/topstories"

Penggunaan query tersebut akan menghasilkan item terbaru dalam feed Yahoo News Top Stories. Kemudian kamu mungkin berpikir bahwa YQL hanya untuk situs-situs Yahoo saja? Jawabnya adalah "tidak". Klik "Show Community Tables" di sisi kanan YQL Console dan kamu akan menemukan banyak "database" dari Netflix, Github, Twitter, dsb.

Membaca Tweet Terbaru dari Twitter

Pada umumnya YQL digunakan dengan cURL (baca: see URL), tapi dengan Javascript saja sebenarnya kita sudah dapat menggunakan YQL. Pada kasus kita ini yaitu membaca Tweet terbaru dari Twitter akan menggunakan cURL di PHP. URL yang digunakan berasal dari hasil query yang dilakukan di YQL Console di bagian THE REST QUERY.

// YQL
$screen_name = 'SECRETsongjieun'; // ubah disini!
$query = "SELECT * FROM twitter.user.timeline WHERE screen_name='$screen_name'";  
$url = 'https://query.yahooapis.com/v1/public/yql?format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&q=' . urlencode($query);  

// cURL  
$c = curl_init();  
curl_setopt($c, CURLOPT_URL, $url);  
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);  
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE);  
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, FALSE);  

$rawdata = curl_exec($c);  
curl_close($c);  
$data = json_decode($rawdata);

// Tampilkan data
echo '<pre>';  
print_r($data);  
echo '</pre>';

Dari hasil print_r diatas seharusnya kamu punya bayangan kira-kira seperti apa data akan ditampilkan.  Sekarang kita buat file HTML + CSS lengkapnya, kode sebelumnya letakkan sebelum perintah HTML dan hapus yang bagian tampilkan data (tag pre)

<!DOCTYPE html>
<html>
<head>
<title><?php echo $user_name ?>'s Tweet</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="default.css" />
<!-- kode sumber: http://net.tutsplus.com/tutorials/other/an-api-for-the-web-learning-yql/
-->
</head>
<body>
<h1><?php echo $user_name ?>: Latest Tweets</h1>
<ul>
...
</ul>
</body>
</html> <?php echo $user_name ?>'s Tweet
Isi default.css:

body {  
    font: 13px/1.5 'Helvetica Neue', Arial, 'Liberation Sans', FreeSans, sans-serif;  
    background:#ececec;  
    padding:10px;  
}  
img {  
    border:0;  
}
ul {  
    margin:0;  
    padding:0;  
    border:1px solid #474747;  
    border-radius:5px;  
    -moz-border-radius:5px;  
    -webkit-border-radius:5px;  
    background:#ccc;  
    width:50%;  
}  
li {  
    min-height:50px;  
    padding:5px;  
    list-style-type:none;  
    border-bottom:1px solid #474747;  
    border-top:1px solid #ececec;  
}  
li div {  
    padding-left:58px;  
}  
li a.img {  
    float:left;  
    padding-right:5px;  
}  
li a {  
    text-decoration: none;
color: #1D74CC;
}  
li:first-child {  
    border-radius:5px 5px 0 0;  
    -moz-border-radius:5px 5px 0 0;  
    -webkit-border-radius:5px 5px 0 0;  
}  
li:last-child {  
    border-bottom:0;  
} 
li:hover {  
    box-shadow: 0px 0px 15px #000;  
    -moz-box-shadow: 0px 0px 15px #000;  
    -webkit-box-shadow: 0px 0px 15px #000;  
}


Nah, sekarang adalah kode perulangan untuk menampilkan Tweet, letakkan di dalam tag ul yang sudah ada:

<?php
// ambil bagian status
$status = $data->query->results->statuses->status;

// loop untuk menampilkan
for ($i = 0; $i < count($status); $i++):
$user = $status[$i]->user;
$text = $status[$i]->text;
$created = $status[$i]->created_at;
$source = $status[$i]->source;

// modify text
$text = preg_replace('/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/', '<a href="$1" target="_blank">$1</a>', $text);
$text = preg_replace('/@([a-zA-Z0-9_]+)/', '<a href="http://twitter.com/$1" target="_blank" class="username">@$1</a>', $text);

// user
$screen_name = $user->screen_name;
$name = $user->name;
$profile_image = $user->profile_image_url;
?>
<li>
<a class="img" href="http://twitter.com/<?php echo $screen_name ?>" target="_blank"><img src="<?php echo $profile_image ?>" alt="<?php echo $name ?>"></a>
<div>
<small><a href="http://twitter.com/<?php echo $screen_name ?>" target="_blank"><?php echo $screen_name ?></a> (<?php echo $name ?>) &mdash; <?php echo $created ?></small><br />
<?php echo $text ?><br />
<small><?php echo $source ?></small>
</div>
</li>
<?php
endfor
?>

Sekarang tampilan dari kode yang kita buat adalah seperti berikut:



Kesimpulan

Pada contoh diatas kita menggunakan cURL dan PHP untuk mendapatkan hasil dari Tweet di Twitter menggunakan YQL. Kamu mungkin dapat mencoba menggunakan Javascript saja untuk menghasilkan output yang sama namun yang terpenting adalah dengan YQL maka semua API yang harus kita pelajari jadi berkurang sehingga mempermudah developer dan mempercepat kerjanya.
Jika kamu ingin mendapatkan file yang digunakan pada contoh diatas dapat diunduh disini: bit.ly/NLulgU

Sumber:

Jumat, 07 Oktober 2011

Membuat robot web crawler dengan PHP

Membuat robot web crawler dengan PHP



Beberapa waktu yang lalu ada sebuah posting yang membahas tentang sebuah situs yang bisa mengambil isi situs lain dan kemudian disimpan dalam format PDF sehingga bisa dibaca secara offline. Nah, sekarang kita juga akan membuat program semacam situs itu dimana nanti program PHP yang kita buat akan mampu mengambil isi situs lain, mengubahnya menjadi format PDF dan kemudian siap didownload untuk disimpan. Kita akan menggunakan cURL (baca: see URL) yang ada di PHP untuk mengambil content situs orang lain, dan untuk mengubah content tersebut menjadi format PDF kita akan menggunakan class TCPDF. Saya juga akan menggunakan class buatan saya sendiri yang saya beri nama JSLoc untuk "memvalidasi" isi situs sebelum dimasukkan pada method di class TCPDF.



1. Pengenalan



- Apakah cURL?

    Menurut PHP manual, cURL (baca (*sekali lagi): see URL) adalah sebuah pustaka (library) yang dibuat oleh Daniel Stenberg dimana kita bisa melakukan koneksi dan komunikasi pada banyak jenis server dengan banyak jenis protokol. Pustaka ini mendukung protokol http, https, ftp, gopher, telnet, dict, file, dan ldap (*buat yang bingung segera cari sesuatu untuk dipegang, hehehe..). Selain itu dia juga mendukung sertifikat HTTPS, HTTP POST, HTTP PUT, unggah dengan FTP, unggah dengan form HTTP, proxies, cookies dan autentifikasi user+password. Untuk menggunakan cURL kamu tidak perlu menginstal apa-apa, hampir semua server (ataupun yang pakai xampp, dsb) biasanya menggunakan PHP yang sudah memiliki library cURL.



- Apakah TCPDF?

    TCPDF adalah sebuah class di PHP yang dapat digunakan untuk membuat file PDF secara langsung tanpa membutuhkan ekstensi eksternal. Dia mendukung semua format halaman, character set, bahasa right-to-left, bermacam fonts, memproses image, dan banyak lagi. Kamu bisa dapatkan versi terbaru dari TCPDF di www.tcpdf.org atau www.sourceforge.net/projects/tcpdf



- Apakah JSLoc?

    JSLoc adalah sebuah class (*buatan saya sendiri, dan sekalian promosi, hehehe..) yang digunakan untuk melakukan optimasi dan validasi kode HTML, CSS dan Javascript. Kita akan membuang tag-tag HTML yang tidak diperlukan menggunakan class ini. Kamu bisa dapatkan versi terbaru (*sementara cuma ada satu versi :D) di www.sourceforge.net/projects/jsloc



- Gantengan mana hedy sama anaknya?

    Nah, yang ini gak nyambung dan gak perlu dibahas...



2. Persiapan



Mungkin pertama kamu bisa mencoba program yang akan kita buat di mesin lokal dulu, jadi letakkan file PHP yang akan kita buat nanti di foler "htdocs" (jika menggunakan Apache). Unduh dan kemudian ekstrak TCPDF dan JSLoc sesuai dengan gambaran path file berikut:





Untuk TCPDF sebaiknya letakkan pada folder khusus seperti pada gambaran path diatas, trus file dengan nama "fileyangakankitabuat.php" atau kalau disingkat "fyakb.php" bisa kamu ubah menjadi "index.php" atau nama apapun terserah kamu asalkan tetap menggunakan ekstension php. Sedangkan file "web2pdf.pdf" jangan diganti namanya kecuali kamu tahu alasannya.



3. Mulai coding



Oke, daripada berlama-lama entar malah jadi bosen, kita langsung aja memulai pembuatan program ini. Saya akan membuat sebuah halaman antarmuka dan sebuah file berisi class lengkap yang mungkin jadi agak panjang kodenya, karena itu siapkan minuman penyegar mata (*emang ada?) biar bisa terus jelalatan memandang kode berikut. Saya akan gunakan cara lama yaitu semua kode saya lempar semua baru dijelaskan. Ini kode lengkapnya: (*oh iya, jika kamu udah eneg duluan, kamu bisa unduh source code dari program ini di: http://bit.ly/n0iEhK  , atau mencoba program yang sudah jadi dan sudah online di: http://bit.ly/mTwonU ).



Kita akan membuat interfacenya dulu, dimana halaman ini cuma berisi form yang berisi inputan untuk memasukkan URL dari situs yang akan diambil contentnya. Setelah form dikirim maka file ini juga sekaligus menjadi responder yang akan memanggil class "web2pdf" yang akan kita simpan di file "web2pdf.php". Isi dari file "fyakb.php" adalah seperti berikut:



<?php

if (isset($_POST['url']) && ! empty($_POST['url'])) {

    if ( ! file_exists('tcpdf/tcpdf.php')) {

        return trigger_error('Class TCPDF tidak ditemukan, unduh dulu!', E_USER_ERROR);

    } else {

        require_once('tcpdf/tcpdf.php');

    }



    @require_once('web2pdf.php');



    $w2pdf = new Web2PDF($_POST['url']);

    $w2pdf->with_image(TRUE);

    $w2pdf->get_result();

}

?><html>

<head>

<title>Web 2 PDF</title>

<style type="text/css">

body {

    font-family: "Lucida Grande", Tahoma, Verdana, Arial;

    font-size: 0.8em;

}

#main { width: 80%; margin: 20px 10%; }

</style>

</head>

<body>

    <div id="main">

        <h1>Web To PDF</h1><br />

        <p>

            Web2PDF akan membuat salinan content dari suatu website ke dalam format PDF. Anda masukkan saja URL dari situs target (terserah, tapi biasanya yang berisi artikel atau berita) lalu klik SIMPAN. Jika berhasil maka Anda akan mulai mengunduh dokumen PDF yang berisi dokumen dari URL yang Anda masukkan. Semoga berhasil :D

        </p>

        <br />

        <form method="post" action="">

            <label for="url">Masukkan URL: </label>

            <input type="text" name="url" maxlength="120" style="width: 400px; height: 28px; border: 1px solid #C5C5EE;" />

            <input type="submit" name="submit" value="SIMPAN" />

        </form>

    </div>

</body>

</html>



Dibaris-baris awal kamu akan menemukan beberapa baris kode PHP yang berhubungan dengan respon bila user mengklik tombol SIMPAN. Disitu kita memasukkan beberapa file dengan perintah require_once, dan setelah itu kita membuat sebuah object dengan nama "$w2pdf" yang berasal dari class "Web2PDF". Pada constructor class ini kita bisa mengeset URL yang menjadi target karena itu kita menggunakan perintah "$w2pdf = new Web2PDF($_POST['url']);" yang mana kita melewatkan isi dari $_POST['url'] ke fungsi constructornya.



Setelah itu kita tentukan apakah file PDF nanti juga memasukkan image/gambar dengan menggunakan method "with_image" dan diberi nilai TRUE (berarti dengan gambar, defaultnya FALSE berarti tanpa gambar). Pemberian gambar pada dokumen mungkin saja menyebabkan kegagalan karena banyak faktor, jadi misalkan kamu mencoba menggunakan gambar selalu gagal maka ada baiknya kamu tidak menggunakan gambar dengan cara: "$w2pdf->with_image(FALSE);" atau dengan tidak memanggil method ini sama sekali karena nilai defaultnya adalah FALSE.



Kemudian untuk menampilkan output kita menggunakan method "get_result" seperti ini: "$w2pdf->get_result();" yang sebenarnya method ini memiliki satu parameter yang menentukan apakah output PDF akan langsung diunduh (defaultnya) atau disimpan di server. Untuk menyimpan di server di sebelah file "fyakb.php" kita cukup menggunakan parameter bernilai TRUE pada pemanggilan method ini, misalnya: "$w2pdf->get_result(TRUE);"



Sekarang kita akan membuat class Web2PDF yang nantinya akan disimpan di file "web2pdf.php" yang diletakkan disebelah file "fyakb.php". Isi filenya seperti ini (kodenya memang agak panjang tapi gak pendek, hehehe):



<?php

/**

 * Web crawler yang menyimpan content website menjadi PDF

 * @author    M. Nazir Arifin

 * @date    2011, October 1

 */

class Web2PDF {

    private $url       = '',

            $wimage    = FALSE,

            $doc_cont  = '',

            $doc_title = '';



    public static $purl = '';



    public function __construct($url = '') {

        if ( ! function_exists('curl_init'))

            return trigger_error('Library cURL tidak tersedia', E_USER_ERROR);



        if ( ! class_exists('jsloc')) {

            if ( ! file_exists('jsloc.php'))

                return trigger_error('Class JSLoc tidak ditemukan, unduh dulu!', E_USER_ERROR);

            else

                @include_once('jsloc.php');

        }



        if ( ! empty($url)) $this->set_url($url);

    }



    public function set_url($url = '') {

        if (empty($url))

            return trigger_error('URL kosong dicoba diset!', E_USER_ERROR);



        if ( ! preg_match('/^(http|https|ftp)/', $url))

            $url = 'http://' . $url;



        if ( ! filter_var($url, FILTER_VALIDATE_URL))

            return trigger_error('URL tidak valid!', E_USER_ERROR);



        self::$purl = $this->url = $url;

    }



    public function with_image($p = FALSE) {

        if ($p != $this->wimage && is_bool($p)) $this->wimage = $p;

    }



    public function get_result($save_pdf = FALSE) {

        if ( ! empty($this->url)) {

            $this->do_curl();

            $this->filter_html();

            $this->gen_pdf($save_pdf);

        } else {

            return trigger_error('URL belum ditentukan!', E_USER_ERROR);

        }

    }



    private function do_curl() {

        $ch = curl_init();



        curl_setopt_array($ch, array(

            CURLOPT_URL => $this->url,

            CURLOPT_AUTOREFERER => TRUE,

            CURLOPT_FAILONERROR => TRUE,

            CURLOPT_USERAGENT => 'web2pdf 1.0',

        ));

        $redirect       = 0;

        $this->doc_cont = $this->curl_redirect_exec($ch, $redirect);

        curl_close($ch);



        if ($this->doc_cont === FALSE)

            return trigger_error('cURL gagal total :(, <a href="">Kembali?</a>', E_USER_ERROR);

    }



    private function curl_redirect_exec($ch, &$redirects, $curlopt_header = FALSE) {

        curl_setopt($ch, CURLOPT_HEADER, TRUE);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);



        $data = curl_exec($ch);

        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);



        if ($http_code == 301 || $http_code == 302) {

            list ($header) = explode("\r\n\r\n", $data, 2);

            $matches = array();

            preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);

            $url = trim(array_pop($matches));

            $url_parsed = parse_url($url);



            if ( ! empty($url_parsed)) {

                self::$purl = $this->url = $this->fix_url($url);

                curl_setopt($ch, CURLOPT_URL, $this->url);

                $redirects++;

                return $this->curl_redirect_exec($ch, $redirects);

            }

        }



        if ($curlopt_header)

            return $data;

        else {

            list(,$body) = explode("\r\n\r\n", $data, 2);

            return $body;

        }

    }



    private function filter_html() {

        if (empty($this->doc_cont)) return;



        $allow_tags = array(

            'a', 'b', 'blockquote', 'br', 'dd', 'del', 'div', 'dl', 'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'li', 'ol', 'p', 'pre', 'small', 'span', 'strong', 'sub', 'sup', 'table', 'tcpdf', 'td', 'th', 'thead', 'tr', 'tt', 'u', 'ul',

        );



        if ($this->wimage === TRUE) $allow_tags[] = 'img';

        jsloc::allowable_tags($allow_tags);

        $this->doc_cont = jsloc::minHTML($this->doc_cont);



        $this->doc_cont = preg_replace('/^(.*)(<body>)(.+)(<\/body>)(<\/html>)$/', '$2$3$4', $this->doc_cont);

        $doc = new DOMDocument('1.0', 'UTF-8');

        @$doc->loadHTML($this->doc_cont);



        $title = @$doc->getElementsByTagName('title')->item(0)->nodeValue;

        $this->doc_title = (is_null($title) ? $this->url : $title);



        $links = @$doc->getElementsByTagName('a');

        for ($i = 0; $i < $links->length; $i++) {

            $att = $links->item($i)->attributes;

            foreach ($att as $item) {

                if ($item->name == 'href') {

                    $item->value = htmlentities($item->value);

                }

            }

        }



        if ($this->wimage === TRUE) {

            $imgs = @$doc->getElementsByTagName('img');

            for ($i = 0; $i < $imgs->length; $i++) {

                $att     = $imgs->item($i)->attributes;

                foreach ($att as $item) {

                    if ($item->name == 'src')

                        $item->value = htmlentities($item->value);

                }

            }

        }



        $this->doc_cont = $doc->saveHTML();

        $this->doc_cont = preg_replace_callback('/(src|href)=(")*([^"\'>]+)(")*/', create_function('$str', '

            $w2pdf = new Web2PDF(Web2PDF::$purl);

            return $str[1] . \'="\' . $w2pdf->fix_url(html_entity_decode($str[3])) . \'"\';

        '), $this->doc_cont);

    }



    private function gen_pdf($save_pdf = FALSE) {

        require_once('tcpdf/config/lang/eng.php');

        $fln = preg_replace('/[^a-z0-9]/', '', $this->doc_title) . '.pdf';



        $pdf = new MyPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);



        $pdf->SetCreator('Web2PDF');

        $pdf->SetAuthor('M. Nazir Arifin');

        $pdf->SetTitle($this->doc_title);

        $pdf->SetSubject('Web To PDF');

        $pdf->SetKeywords('nazir, nazir lagi, nazir cool, nazir the best, narsis on here, oke, ehm..., enough, stop!');

        $pdf->SetFooterText($this->url);

        $pdf->SetHeaderData('', 0, 'Web2PDF', "by M. Nazir Arifin\n\n" . $this->doc_title);

        $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));

        $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));

        $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);

        $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);

        $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);

        $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);

        $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);

        $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

        $pdf->setLanguageArray($l);

        $pdf->SetFont('helvetica', '', 9);

        $pdf->AddPage();

        $pdf->writeHTML($this->doc_cont, true, 0, true, 0);

        $pdf->lastPage();

        $pdf->Output($fln, $save_pdf === FALSE ? 'D' : 'F');

    }



    public function fix_url($url = '') {

        $purl = parse_url($this->url);

        $surl = parse_url(html_entity_decode($url));



        if ($url == '' OR $url == '#')

            return $this->url . $url;



        if ( ! isset($surl['scheme'])) {

            if ( ! isset($surl['host'])) {

                $split         = explode('/', $surl['path']);

                if (isset($purl['path']) && dirname($purl['path']) != '.')

                    array_unshift($split, ltrim(dirname($purl['path']), '/'));



                $query       = ( ! isset($surl['query'])) ? '' : '?' . $surl['query'];

                $frag        = ( ! isset($surl['fragment'])) ? '' : '#' . $surl['fragment'];



                if ($split[0] == '.') array_shift($split);

                while ($split[0] == '..')

                    @array_shift($split);



                return $purl['scheme'] . '://' . $purl['host'] . '/' . implode('/', $split) . $query . $frag;

            } else

                return $purl['scheme'] . '://' . $url;

        } else return $url;

    }

}



class MyPDF extends TCPDF {

    public function SetFooterText($t = '') {

        $this->footer_text = $t;

    }



    public function Footer() {

        $this->SetY(-15);

        $this->SetFont('helvetica', 'I', 8);

        $this->Cell(0, 10, "sumber asli: {$this->footer_text}", 0, 0, 'L');

    }

}



Haruskah aku menjelaskan perbarisnya? sepertinya tidak :). Oh iya, jika kamu mengunduh source program ini pada link diatas maka saya memberi beberapa komentar yang mungkin sedikit (sekali) membantu mengenai apa yang dikerjakan oleh kode tersebut. Saya coba sedikit saja memberikan gambaran kode diatas, apa saja yang dilakukan dan bagaimana prosesnya. Kita memiliki dua class yaitu "Web2PDF" yang menjadi class pemroses dan class "MyPDF" (turunan dari class TCPDF) yang terpaksa aku buat untuk membuat custom footer. Kita bahas class Web2PDF saja karena class MyPDF secara teknis tidak begitu berpengaruh pada alur program keseluruhan (tapi jangan dihapus lho ya..!).



Class Web2PDF memiliki tiga public method (get_result, set_url, with_image) dan empat private method (do_curl, curl_redirec_exec, filter_html, gen_pdf, fix_url). Semoga dari nama methodnya kamu bisa punya bayangan tentang apa yang dilakukan oleh tiap-tiap method. Dari ketiga public method yang saya sebutkan mungkin yang belum kenal adalah method set_url. Method ini sebenarnya dipanggil oleh constructor ketika kamu memasukkan sebuah nilai saat pembuatan object. Untuk mengeset URL secara manual tanpa menggunakan constructor maka kamu bisa menggunakan method set_url ini sebelum memanggil fungsi get_result().



Sekarang kita bahas private methodnya.

    1. do_curl(), berikut ini cuplikan kodenya:



        $ch = curl_init();



        curl_setopt_array($ch, array(

            CURLOPT_URL => $this->url,

            CURLOPT_AUTOREFERER => TRUE,

            CURLOPT_FAILONERROR => TRUE,

            CURLOPT_USERAGENT => 'web2pdf 1.0',

        ));

        $redirect       = 0;

        $this->doc_cont = $this->curl_redirect_exec($ch, $redirect);

        curl_close($ch);



        if ($this->doc_cont === FALSE)

            return trigger_error('cURL gagal total :(, <a href="">Kembali?</a>', E_USER_ERROR);



Pertama kita buat resource untuk curl menggunakan fungsi curl_init(). Setelah itu kita set beberapa konfigurasi pada resource yang kita buat menggunakan fungsi curl_setopt_array(). Parameter kedua dari fungsi ini adalah berisi array dengan menggunakan key index berupa konstanta yang sudah ada di PHP. Untuk arti lengkap dan daftar lengkap dari konstanta di curl kamu bisa melihat ke situs www.php.net/curl_setopt



Pada awalnya kodenya tidak seperti ini. Waktu aku tes di webserver online ternyata safe_mode dan open_basedir didisabled sehingga aku tidak bisa menggunakan konstanta CURLOPT_FOLLOWLOCATION. Setelah aku baca di php.net ada source yang bisa mengatasi permasalah ini sehingga curl kita nanti tetap akan mengikuti redirect dari situs target. Methodnya bernama curl_redirect_exec dimana nanti dalam method ini kita akan memanggil fungsi curl_exec dan jika ada redirect maka akan diulangi membuat koneksi curl lagi. Ini kodenya:



    2. curl_redirect_exec()



        curl_setopt($ch, CURLOPT_HEADER, TRUE);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);



        $data = curl_exec($ch);

        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);



        if ($http_code == 301 || $http_code == 302) {

            list ($header) = explode("\r\n\r\n", $data, 2);

            $matches = array();

            preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);

            $url = trim(array_pop($matches));

            $url_parsed = parse_url($url);



            if ( ! empty($url_parsed)) {

                self::$purl = $this->url = $this->fix_url($url);

                curl_setopt($ch, CURLOPT_URL, $this->url);

                $redirects++;

                return $this->curl_redirect_exec($ch, $redirects);

            }

        }



        if ($curlopt_header)

            return $data;

        else {

            list(,$body) = explode("\r\n\r\n", $data, 2);

            return $body;

        }



    Disitu kamu bisa melihat bahwa kita cek terlebih dahulu header yang dikirimkan oleh server. Jika kode header 301 (redirect permanen) atau 302 (redirect sementara) maka proses curl akan diulangi lagi dan menggunakan url baru sesuai dengan isi dari data Location/URI yang dalam header. Terakhir kita mereturn isi dari eksekusi curl yang telah dijalankan.



    2. filter_html(), berikut ini cuplikan kodenya:



        if (empty($this->doc_cont)) return;



        $allow_tags = array(

            'a', 'b', 'blockquote', 'br', 'dd', 'del', 'div', 'dl', 'dt', 'em', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'li', 'ol', 'p', 'pre', 'small', 'span', 'strong', 'sub', 'sup', 'table', 'tcpdf', 'td', 'th', 'thead', 'tr', 'tt', 'u', 'ul',

        );



        if ($this->wimage === TRUE) $allow_tags[] = 'img';

        jsloc::allowable_tags($allow_tags);

        $this->doc_cont = jsloc::minHTML($this->doc_cont);



        $this->doc_cont = preg_replace('/^(.*)(<body>)(.+)(<\/body>)(<\/html>)$/', '$2$3$4', $this->doc_cont);

        $doc = new DOMDocument('1.0', 'UTF-8');

        @$doc->loadHTML($this->doc_cont);



        $title = @$doc->getElementsByTagName('title')->item(0)->nodeValue;

        $this->doc_title = (is_null($title) ? $this->url : $title);



        $links = @$doc->getElementsByTagName('a');

        for ($i = 0; $i < $links->length; $i++) {

            $att = $links->item($i)->attributes;

            foreach ($att as $item) {

                if ($item->name == 'href') {

                    $item->value = htmlentities($item->value);

                }

            }

        }



        if ($this->wimage === TRUE) {

            $imgs = @$doc->getElementsByTagName('img');

            for ($i = 0; $i < $imgs->length; $i++) {

                $att     = $imgs->item($i)->attributes;

                foreach ($att as $item) {

                    if ($item->name == 'src')

                        $item->value = htmlentities($item->value);

                }

            }

        }



        $this->doc_cont = $doc->saveHTML();

        $this->doc_cont = preg_replace_callback('/(src|href)=(")*([^"\'>]+)(")*/', create_function('$str', '

            $w2pdf = new Web2PDF(Web2PDF::$purl);

            return $str[1] . \'="\' . $w2pdf->fix_url(html_entity_decode($str[3])) . \'"\';

        '), $this->doc_cont);



Ya, kita menggunakan jsloc dan DOM untuk memfilter dan menvalidasi kode HTML yang kita dapat dari cURL. Sekali lagi kode saya yang awal tidak seperti ini, dibaris-baris terakhir kamu akan melihat "keterpaksaan" saya membuat static properti (Web2PDF::$purl) demi memperbaiki url agar lebih valid. Seringkali alamat URL disitus orang menggunakan query yang berlebihan :) dan menggunakan tanda ampersand (&) sehingga DOM langsung macet karena ada entiti yang tidak diescape. Salah satu cara melakukan escape dengan menggunakan fungsi htmlentities pada URL tersebut, tapi tentu harus html_entity_decode biar kembali lagi. Nah, proses ini yang menambah panjang kode dan penambahan properti lain.



    3. gen_pdf(), dengan cuplikan kode seperti berikut:



        require_once('tcpdf/config/lang/eng.php');

        $fln = preg_replace('/[^a-z0-9]/', '', $this->doc_title) . '.pdf';



        $pdf = new MyPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);



        $pdf->SetCreator('Web2PDF');

        $pdf->SetAuthor('M. Nazir Arifin');

        $pdf->SetTitle($this->doc_title);

        $pdf->SetSubject('Web To PDF');

        $pdf->SetKeywords('nazir, nazir lagi, nazir cool, nazir the best, narsis on here, oke, ehm..., enough, stop!');

        $pdf->SetFooterText($this->url);

        $pdf->SetHeaderData('', 0, 'Web2PDF', "by M. Nazir Arifin\n\n" . $this->doc_title);

        $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));

        $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));

        $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);

        $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);

        $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);

        $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);

        $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);

        $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

        $pdf->setLanguageArray($l);

        $pdf->SetFont('helvetica', '', 9);

        $pdf->AddPage();

        $pdf->writeHTML($this->doc_cont, true, 0, true, 0);

        $pdf->lastPage();

        $pdf->Output($fln, $save_pdf === FALSE ? 'D' : 'F');



Secara teknis, sebagian besar kode diatas ada di dokumentasi TCPDF, jadi kalau kamu ingin tahu lebih jauh tentang kode-kode diatas dan apa maksudnya bisa kamu lihat di situsnya TCPDF. Ada satu method yang saya buat dan digunakan dikode diatas adalah SetFooterText yang berguna mengeset teks di footer file PDF yang dihasilkan.



    4. fix_url, dengan cuplikan kodenya seperti berikut:



        $purl = parse_url($this->url);

        $surl = parse_url(html_entity_decode($url));



        if ($url == '' OR $url == '#')

            return $this->url . $url;



        if ( ! isset($surl['scheme'])) {

            if ( ! isset($surl['host'])) {

                $split         = explode('/', $surl['path']);

                if (isset($purl['path']) && dirname($purl['path']) != '.')

                    array_unshift($split, ltrim(dirname($purl['path']), '/'));



                $query       = ( ! isset($surl['query'])) ? '' : '?' . $surl['query'];

                $frag        = ( ! isset($surl['fragment'])) ? '' : '#' . $surl['fragment'];



                if ($split[0] == '.') array_shift($split);

                while ($split[0] == '..')

                    @array_shift($split);



                return $purl['scheme'] . '://' . $purl['host'] . '/' . implode('/', $split) . $query . $frag;

            } else

                return $purl['scheme'] . '://' . $url;

        } else return $url;



Jujur saja aku agak kurang yakin dengan "kedigdayaan" method ini jadi beri aku usul jika ada yang lebih baik ataupun kamu menemukan kesalahan fatal disitu. Yang menjadi titik berat penggunaan fungsi ini adalah mengubah url tanpa scheme dan host (atau yang menggunakan tanda ./, ../) menjadi absolute path sehingga dokumen PDF yang kita hasilkan menjadi lebih valid baik link maupun image yang dimasukkan. Sekali lagi, bila kamu sering mengalami kegagalan bila menggunakan image maka ada baiknya kamu mendisable image dengan method "with_image(FALSE)".



-------------------



Maka demikianlah, program web2pdf yang kita buat, memang saya tidak menjelaskan kode perbarisnya karena kebetulan kodenya agak banyak, takutnya yang baca jadi bosen dan akhirnya muntah-muntah, nangis darah, kencing manis. Semoga bermanfaat. Sekali lagi jika ingin mendapatkan source lengkapnya (kamu juga tidak perlu mengunduh TCPDF atau JSLoc lagi karena semua sudah ada dan tinggal digunakan), kamu bisa unduh di: http://bit.ly/n0iEhK . Dan untuk contoh program yang sudah online kamu bisa coba disini:http://bit.ly/mTwonU . Sampai jumpa lagi dan bye !!!!