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 !!!!

Rabu, 28 September 2011

Membuat Menu Drop-Down dengan CSS

Membuat menu Drop-Down tanpa Javascript

Pada awalnya ada pertanyaan bagaimana membuat menu dropdown yang ringkas dan tanpa kode Javascript yang njlimet. Pertanyaannya sebenarnya sudah dijawab tapi saya ingin membahas lebih rinci tentang hal ini agar mungkin saja dapat menambah wawasan dan pengetahuan tentang penggunaan CSS. Nantinya saya akan mencoba memberikan penjelasan yang lengkap tentang arti dari kode CSS yang digunakan.

1. Kode HTML

Kita mulai dengan membuat sebuah dokumen HTML sederhana yang hanya berisi menu yang akan kita buat. Tentu saja kamu bisa menambah isinya agar menjadi halaman web yang lebih lengkap tapi sekarang kita fokuskan hanya pada bagian menu dropdown yang akan kita buat saja. Berikut ini kode HTML-nya:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="id">
<head>
<title>Menu Drop-Down</title>
<style type="text/css" media="screen, projection">
/* CSS-nya ditulis di disini ! */

</style>
</head>
<body>
<ul id="menu">
<li><a href="#">Beranda</a></li>
<li><a href="#">Tentang</a>
<ul>
<li><a href="#">Sejarah</a></li>
<li><a href="#">Tim</a></li>
<li><a href="#">Kantor</a></li>
</ul>
</li>
<li><a href="#">Layanan</a>
<ul>
<li><a href="#">Desain Web</a></li>
<li><a href="#">Internet Marketing</a></li>
<li><a href="#">Hosting</a></li>
<li><a href="#">Domain Names</a></li>
<li><a href="#">Broadband</a></li>
</ul>
</li>
    </ul>
</body>
</html>

Catatan: untuk mempersingkat penulisan, kode berikutnya harus kamu letakkan di dalam blok style di bagian head (yang ada tulisan "CSS-nya ditulis disini !").

2. Mulai membentuk menu dropdown

Kamu perhatikan bahwa saya menggunakan unordered list (ul) untuk membuat menu karena dengan penggunaan tag ul maka susunan menu akan nampak lebih jelas. Untuk membuat submenu maka saya membuat ul dalam ul yang bisa saja kamu kembangkan dan tambah lagi kedalaman menunya. Perhatikan bahwa tag ul terluar saya beri nama id "menu" sehingga untuk CSS selector bisa menggunakan: ul#menu atau cukup dengan #menu saja.

Sebelumnya saya akan memberitahukan bahwa menu utama nanti akan saya buat berjajar kesamping secara horizontal, untuk membuat menu utama bertumpuk kebawah kamu cukup membuang properti "float: left" pada li. Untuk bentuk list saya buat secara umum saja hiasannya karena nanti terserah kamu ingin diberi hiasan gambar atau apapun sesuai keinginannmu. Kita mulai memberi style pada tag ul utamanya. (*sekali lagi kode berikut letakkan di bagian style!)

#menu {
margin: 0;
padding: 0;
list-style: none;
min-width: 450px;
}

Dimulai pada bagian ul utama: Pemberian margin dan padding dengan nilai 0 akan membuat "efek" list akan hilang karena pada umumnya list item akan menjorok masuk kedalam. Kemudian list-style diberi nilai "none" agar list yang muncul tidak memiliki style apapun (beberapa list-style yang mungkin kamu kenal antara lain circle, square, dan disc). Pemberian nilai min-width: 450px; dikarenakan saya memiliki tiga menu utama yaitu Beranda, Tentang dan Layanan yang masing-masing memiliki lebar 150px (150 pixel). Jika kamu memiliki menu yang lebih banyak kamu bisa menambahkan angka ini. Penggunaan properti min-width akan berguna bila kita ingin suatu elemen memiliki lebar minimal dimana jika isinya lebih panjang maka dia akan memanjang dengan sendirinya. Jika kamu menggunakan properti "width" dan bukan "min-width" maka elemen itu akan tetap segitu biarpun isinya lebih panjang.

#menu li {
position: relative;
width: 150px;
height: 25px;
float: left;
}

Kita lanjutkan ke tag li (list item) yang berlaku pada semua tag li dibawah ul utama. Penggunaan properti "position: relative" agar kita bisa menempatkan elemen ul dibawahnya secara tepat / absolute (kamu akan lihat nanti di kode berikutnya). Saya tentukan lebar dan tinggi dari menu kita adalah 150 pixel dan 25 pixel. Kemudian pemberian properti "float: left" akan membuat tiap list item akan memaksa berjejer ke kiri dan tidak turun kebawah (defaultnya li akan turun kebawah). Ada dua kelompok elemen di HTML yaitu elemen "inline" (elemen ini akan berusaha mengisi ruang disebelahnya dan akan turun kebawah bila tidak ada ruang lagi, contohnya: a, img, span, em) dan elemen "block" (elemen ini akan selalu turun kebawah elemen sebelumnya seperti kalau ditekan tombol "Enter", contohnya: p, div, ul). Perilaku default tiap elemen bisa diubah dengan menggunakan properti "display", misalkan tag a yang inline bisa diubah menjadi block dengan memberi properti "display: block;".

#menu li a {
display: block;
width: 150px;
height: 25px;
border: 1px solid #ccc;
background-color: whitesmoke;
}

Kita akan memberi efek pada tag a yang ada di dalam tag li. Seperti yang saya bilang sebelumnya kita akan mengubah perilaku tag a yang inline menjadi block agar tag a dapat mengisi semua ruang kosong di li. Kemudian kita buat lebar dan tinggi tag a sama dengan tag li containernya dan kita beri border berupa garis tipis 1 pixel dengan warna #ccc menggunakan perintah "border: 1px solid #ccc". Dan baris terakhir pada kode diatas kita memberi warna background whitesmoke pada tag a.

#menu li ul {
margin: 0;
padding: 0;
position: absolute;
top: 26px;
list-style: none;
display: none;
}

Selanjutnya kita memberi style pada elemen ul dalam ul utama, yang hampir sama dengan ul utama dalam hal margin dan padding serta list-style (diset 0 dan list-stylenya none). Perhatikan bahwa saya memberi properti "position: absolute;" sehingga saya dapat meletakkan elemen ini dengan tepat per pixelnya menggunakan perintah "left" dan "top" (kamu juga bisa menggunakan perintah "right" dan "bottom"). Nilai top saya beri angka 26 pixel agar elemen ul tidak menutupi link sebelumnya karena tiap tag a memiliki tinggi 25 pixel (tambah 1 pixel lagi menjadi 26).

Kalau kamu lihat di browser sekarang mungkin kamu akan menyadari bahwa kita tidak melihat submenu lagi disitu dan cuma ada tiga menu utama saja yang nampak. Hal ini dikarenakan kita menggunakan properti "display: none;" sehingga elemen ul tersebut hilang (beda dengan tidak kelihatan). Untuk menyembunyikan elemen kita bisa menggunakan dua macam cara yaitu "display: none" dan "visibility: hidden" dan untuk memunculkan lagi (jangan2 kamu cuma bisa menyembunyikan tapi tidak bisa memunculkannya lagi :D) dengan "display: block" dan "visibility: visible". Lalu apa perbedaan keduanya? Jika kamu menggunakan "display: none" maka elemen tersebut benar-benar hilang dan tidak mengambil ruang apapun di layar sedangkan "visibility: hidden" elemen tersebut cuma tidak kelihatan tapi tetap mengambil ruang disekitarnya. Tahu kan maksud saya?

#menu li:hover ul {
display: block;
}

Ini dia "keajaiban" dari CSS nya yaitu penggunaan pseudo-class :hover pada elemen li. Sebenarnya ada beberapa pseudo-class lain seperti :link, :visited, :active (ketiganya biasanya untuk tag a). Beberapa browser jadul tidak mendukung penggunakan pseudo-class :hover pada elemen selain a tapi saya tidak akan membahasnya karena sebagian besar browser sekarang sudah dapat menjalankan kode ini dengan benar. Technically, menu kita sudah jadi :), coba lintaskan mouse ke menu maka submenunya akan tampil.

3. Sentuhan terakhir

Kamu tambahkan baris berikut ke dalam bagian #menu li a:

text-decoration: none;
text-indent: 7px;
color: #4B4B4B;

Kode diatas akan membuat teks link tidak memiliki "hiasan" garis bawah, membuat teks agak menjorok kedalam sebanyak 7 pixel (biar tidak terlalu mepet ke kiri) dan terakhir kita memberi warna pada teks link yang kita buat. Selanjutnya kita ingin memberi efek mouse melintas pada tag a dengan mengubah warna background yang dimilikinya. Ini kodenya dan kamu bisa letakkan dimana saja.

#menu li a:hover {
background-color: #C7C7C7;
}

#menu li ul li a:hover {
background-color: #727272;
color: #FFF;
}

Ehm, saya kira menunya sudah lumayan jelek :), dan gak enak dilihat.. jadi untuk hiasan atau pengembangan selanjutnya terserah kamu. Mungkin nanti kamu akan menambah banyak properti atau dengan mengubah kode HTML-nya (misalkan dengan menambah nama class tertentu), itu semua terserah kamu dan tidak ada seorang pun yang melarang. Dan jika gagal tidak ada seorangpun yang akan menolong :D. Kode lengkap dari apa yang kita lakukan dari awal sampai akhir adalah seperti ini:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="id">
<head>
<title>Menu Drop-Down</title>
<style type="text/css" media="screen, projection">
#menu {
margin: 0;
padding: 0;
list-style: none;
min-width: 450px;
}
#menu li {
position: relative;
width: 150px;
height: 25px;
float: left;
}
#menu li a {
display: block;
width: 150px;
height: 25px;
border: 1px solid #ccc;
background-color: whitesmoke;
text-decoration: none;
text-indent: 7px;
color: #4B4B4B;
}
#menu li a:hover {
background-color: #C7C7C7;
}
#menu li ul li a:hover {
background-color: #727272;
color: #FFF;
}
#menu li ul {
margin: 0;
padding: 0;
position: absolute;
top: 26px;
list-style: none;
display: none;
}
#menu li:hover ul {
display: block;
}
</style>
</head>
<body>
<ul id="menu">
<li><a href="#">Beranda</a></li>
<li><a href="#">Tentang</a>
<ul>
<li><a href="#">Sejarah</a></li>
<li><a href="#">Tim</a></li>
<li><a href="#">Kantor</a></li>
</ul>
</li>
<li><a href="#">Layanan</a>
<ul>
<li><a href="#">Desain Web</a></li>
<li><a href="#">Internet Marketing</a></li>
<li><a href="#">Hosting</a></li>
<li><a href="#">Domain Names</a></li>
<li><a href="#">Broadband</a></li>
</ul>
</li>
    </ul>
</body>
</html>

4. Kesimpulan

Menjadi web master tidaklah harus dengan menguasai kode Javascript atau kode PHP dengan baik tapi sebenarnya jika mau berusaha maka cukup dengan HTML dan CSS kamu sudah bisa menunjukkan ke-master-anmu dalam bidang web. Jujur tidak lah mudah untuk menguasai CSS karena dibutuhkan banyak sekali pengetahuan dasar yang harus dipelajari dan dilatih. CSS bukanlah bahasa mudah yang bisa dikesampingkan karena justru CSS akan menjadi "muka" dari apa yang kita kerjakan. Serumit dan sebagus apapun kode PHP dan Javascript yang kita buat tapi jika kode CSS-nya hancur dan berakibat halaman web kita juga hancur maka semua akan menjadi percuma dan sia-sia. User awam tidak peduli Javascript, tidak peduli PHP, yang mereka tahu bahwa tampilan web kita bagus, itu saja.

Selamat berlatih dan belajar, karena berlatih dan belajar akan kita lakukan bersama-sama dan akan terus kita lakukan sampai akhir hayat kita. Sampai jumpa :D

.... oh iya, ini screenshot hasil akhir kerja kita:

Jumat, 23 September 2011

Javascript 3 (DOM dan AJAX)

Sudah pernahkah kamu mendengar istilah DOM (Document Object Model) dan AJAX (Asynchronous JavaScript and XML)? Jika belum, kamu bisa membaca terus tulisan ini dan jika sudah kamu juga bisa terus membaca tulisan ini :). Sebaiknya kamu membaca dulu tulisan bagian 1 (Pengetahuan Dasar) dan 2 (Konsep OOP) agar kamu punya sedikit gambaran Javascript yang ada dalam pembahasan kali ini.

        a. DOM (Document Object Model)
       
Ketika browser yang mendukung CSS membaca dokumen HTML yang kamu buat, mereka akan menganalisa strukturnya dan membuat sebuah titik-titik struktur (nodes), yang dapat kamu bayangkan sebagai potongan kecil informasi yang mendeskripsikan dokumenmu. Setiap node berasal dari setiap tag HTML yang kamu tulis dan akan menjadi sebuah object yang saling berhubungan dengan node lain. Sebagai ilustrasi saya berikan kode HTML berikut:

<body>
<p>
   Teks awal
   <img src="gambar.jpg">
   <em>Teks lagi</em>
</p>
</body>

Jika kamu pernah belajar struktur data, terdapat salah satu struktur data yang dikenalkan yaitu TREE. Nah, struktur dari kode HTML diatas mirip dengan tree. Diawali dengan "body" yang memiliki child node "p" dan "p" memiliki tiga child node yaitu "#text" (berisi "Teks awal"), "img" dan child terakhir adalah "em" yang memiliki satu child "#text" berisi teks "Teks lagi". Dari dokumen diatas dapat diambil beberapa pernyataan seperti berikut:

1. parentNode dari "p" adalah "body"
2. firstChild dari "p" adalah "#text" dan lastChild nya adalah "em"
3. "p" berarti juga memiliki array childNodes
4. "img" memiliki previousSibling (saudara) "#text" dan memiliki nextSibling yaitu "em"
5. karena "#text" tidak memiliki node disebelumnya dan tidak memiliki elemen lagi didalamnya maka previousSibling dan firstChild nya memiliki nilai null

Pada umumnya nama node berasal dari nama tag tapi menggunakan huruf kecil (lowercase). Kata-kata parentNode, firstChild, lastChild dan sebagainya akan sering kamu temui dalam DOM. Tapi kamu jangan merasa diintimidasi dulu dengan kata-kata yang mungkin asing dan terkesan ribet bagimu karena nanti kalau sudah terbiasa maka istilah tersebut akan kamu ingat diluar kepala. Jika kamu menggunakan jQuery, akan ada perbedaan istilah yang mungkin akan mempermudah dirimu untuk mengingatnya, misalkan "parentNode" akan diganti dengan kata "parent" saja atau childNodes akan diganti dengan "child".

        b. CARA MENDAPATKAN ELEMEN MENJADI NODE
       
Javascript memiliki beberapa method yang dapat digunakan untuk mendapatkan sebuah object dalam dokumen yang kita buat untuk melakukan analisa struktur dokumen HTML. Untuk mendapatkan object dari node-node tersebut ada tiga method yang umum digunakan dan semuanya ada di class "document" yaitu:

1. document.getElementById
2. document.getElementsByName
3. document.getElementsByTagName

Biasanya saya sering menggunakan method yang pertama dan ketiga saja sedangkan method yang kedua hampir tidak pernah saya gunakan. Method pertama yaitu "getElementById" akan mencari node dengan nama ID yang dijadikan parameter dalam fungsi ini (contoh: <div id="blok">, berarti elemen div dengan id "blok"). Dalam satu dokumen tidak boleh ada node yang memiliki nama id yang sama karena itu method ini menggunakan kata "getElement" dan bukan "getElements". Contoh penggunaannya:

var blok = document.getElementById('blok');
if (blok == null) { alert('node tidak ketemu!'); }

Pada kode diatas, jika elemen dengan id "blok" ditemukan kita dapat melakukan bermacam operasi pada object blok. Sedangkan method getElementByName dan getElementByTagName sesuai dengan namanya kamu pasti sudah tahu kegunaannya. Dua method ini biasanya akan mengembalikan hasil berupa array dari object. Misalkan di dokumen kita ada beberapa tag paragraf (p) tapi kita ingin melakukan operasi pada paragraf yang pertama saja maka kita dapat menggunakan cara seperti berikut:

var paragraf = document.getElementsByTagName('p')[0];
paragraf.className = 'pertama';

Kode diatas memberikan nama class "pertama" pada paragraf pertama dalam dokumen. Karena method getElementsByTagName mereturn array maka kita langsung dapat mengakses elemen pertama dari array tersebut menggunakan tanda "[0]" setelah pemanggilan method getElementsByTagName seperti pada contoh diatas.

    c. DOM ready
   
Jika kamu membuat kode dengan DOM yang dijalankan saat browser meload halaman (otomatis dijalankan saat halaman muncul) maka kamu harus memastikan bahwa semua elemen sudah dirender oleh browser agar tidak menghasilkan nilai NULL. Pada umumnya kita membuat kode Javascript di dalam bagian HEAD yang dieksekusi oleh browser sebelum masuk ke bagian BODY. Jika bagian BODY belum dirender oleh browser maka kodemu di HEAD akan gagal karena node-node nya belum ada. Nah agar kodemu dijalankan setelah browser selesai merender semua elemen kamu bisa menggunakan event "onload" di class "window" seperti contoh berikut:

<html>
<head>
<title>DOM ready</title>
<script type="text/javascript">
window.onload = function(e) {
    var p = document.getElementsByTagName('p');
    alert(p[0].innerHTML);
}
</script>
</head>
<body>
<p>Paragraf pertama</p>
<p>Paragraf kedua</p>
</body>
</html>

Cara atau alternatif lain agar kode DOM kita tidak gagal adalah dengan meletakkan blok kode Javascript di akhir document sebelum tag tutup body karena dijamin semua elemen pasti sudah dirender oleh browser.

    d. Membuat elemen secara dinamis dengan DOM

Sekarang kita buat contoh sederhana pengaplikasian DOM untuk membuat beberapa elemen secara dinamis tanpa mengetikkan secara langsung kode HTMLnya. Saya akan menambahkan tag P (paragraf) dan A (anchor, untuk link) pada elemen body dengan DOM.

<html>
<head>
<title>DOM</title>
<script type="text/javascript">
function buatTagElement(nama) {
    return document.createElement(nama); // membuat element
}
function buatTextElement(teks) {
    return document.createTextNode(teks); // membuat text node
}

window.onload = function(e) {
    var p     = buatTagElement('p'),
        br    = buatTagElement('br'),
        a    = buatTagElement('a'),
        b    = document.getElementsByTagName('body')[0];
    a.href = 'www.posank.com';
    a.appendChild(buatTextElement('posank?'));
    p.style.fontSize = '20px';
    p.appendChild(buatTextElement('kamu'));
    p.appendChild(br);
    p.appendChild(a);
    // hapus elemen sebelumnya
    b.removeChild(document.getElementsByTagName('p')[0]);
    // tambahkan elemen baru
    b.appendChild(p);
}
</script>
</head>
<body>Teks default</body>
</html>

Jika kamu jalankan kode diatas di browser maka akan muncul beberapa elemen yang kita tambahkan secara dinamis seperti pada contoh diatas (kamu posank? :). Untuk dapat melakukan pemrograman menggunakan DOM secara baik diperlukan banyak latihan karena ada banyak kata kunci dan logika yang harus dipelajari dan dilatih. Untuk daftar lengkap method dan property yang digunakan dalam DOM bisa kamu cari di sumber lain atau jika kamu menggunakan browser Google Chrome cukup klik kanan tampilan lalu pilih menu inspect elements atau periksa elemen dan lihat di bagian Elements.

    e. innerHTML
   
innerHTML bukanlah bagian dari DOM tapi property innerHTML sangatlah powerful untuk melakukan beragam operasi pada elemen HTML. Jika pada contoh sebelumnya untuk menghapus atau menambahkan elemen terkesan ribet dan berbelit-belit maka dengan innerHTML kita dapat langsung mengubah isi dari suatu elemen dengan sangat cepat. Perhatikan contoh berikut yang menghasilkan output yang sama dengan kode sebelumnya tapi sekarang kita menggunakan innerHTML.

<html>
<head>
<title>DOM</title>
<script type="text/javascript">
window.onload = function() {
    // string isi yang akan ditambahkan
    var isi = '<p>kamu<br /><a href="www.posank.com">'
            + 'posank?</a></p>';
    // tambahkan isi ke body
    document.getElementsByTagName('body')[0].innerHTML = isi;
    // berikan style ke p
    document.getElementsByTagName('p')[0].style.fontSize = '20px';
}
</script>
</head>
<body>Teks default</body>
</html>

Mudahkan? Nah, bicara soal AJAX, pada umumnya operasi AJAX menggunakan innerHTML ini untuk mengubah sebagian isi dari halaman dengan content dari hasil request yang dilakukan olehnya.

    f. AJAX (Asynchronous JavaScript and XML)
   
Javascript juga dapat melakukan koneksi dibalik layar tanpa kita sadari menggunakan XMLHttpRequest untuk meminta content dari server. Jika kamu menggunakan facebook dan muncul gambar loading lalu tiba-tiba bagian tersebut berubah sendiri maka perubahan tersebut dilakukan dengan AJAX. Karena sifatnya yang Asynchronous itu maka kita tidak perlu merefresh atau mereload keseluruhan halaman tapi Javascript cukup mengubah sebagian elemen menggunakan DOM ataupun innerHTML berdasarkan hasil request yang dilakukannya.

Kamu mungkin tidak perlu tahu kode sesungguhnya untuk melakukan koneksi XMLHttpRequest karena sudah ada banyak class atau framework yang menyediakan interface mudah yang tinggal kamu pakai untuk melakukan koneksi menggunakan AJAX. Tapi jika kamu belum pernah mencoba menggunakan AJAX sama sekali, saya akan berikan source file untuk melakukan koneksi AJAX sederhana menggunakan XMLHttpRequest. Kamu bisa download DISINI. Didalamnya ada tiga file yaitu: "conn.js" sebuah file javascript sebagai penghubung koneksinya, "test.php" sebagai interface contoh koneksinya dan terakhir file "tests.php" sebagai responder bila ada koneksi ajax.

Cara penggunaannya letakkan tiga file tersebut ke webserver atau jika kamu menggunakan mesin lokal dan menggunakan XAMPP letakkan di folder htdocs. Buka browser dan akses file 'test.php' (misal: localhost/test.php). Disitu akan muncul sebuah isian nama yang jika kamu mencoba mengetikkan satu huruf disitu maka akan muncul semacam popup dibawah inputan yang mana isi dari popup ini berasal dari hasil request AJAX ke file 'tests.php'.

Jika saya jelaskan secara detil teknisnya mungkin akan terkesan bertele-tele jadi silakan kamu lihat dan analisa apa dan bagaimana cara melakukan koneksi sederhana menggunakan AJAX. File yang perlu kamu perhatikan adalah file 'test.php' sebagai interfacenya, lalu kamu lihat file 'tests.php' sebagai pemroses dari request yang dikirim oleh file 'test.php' melalui AJAX.

    g. eventListener
   
Pada setiap elemen HTML yang kita buat bisa kita tambahkan event listener yang akan merespon bila ada sebuah event yang terjadi pada element tersebut. Jika kamu pernah menulis atribut "onclick" pada link, maka sebenarnya kamu sudah menambahkan eventlistener pada link tersebut untuk merespon bila terjadi event click. Beberapa event lain antara lain "onchange", "onblur", "onkeypress", "onkeyup", "onload", "onmouseover", dsb. Dengan DOM kita bisa menambahkan eventlistener pada hampir semua elemen dengan menggunakan method addEventListener() pada node yang ada. Method ini mememiliki tiga parameter yaitu:
    1. nama event (tanpa kata "on")
    2. nama fungsi yang dipanggil bila event terjadi
    3. apakah menggunakan capture (true jika iya, false jika menggunakan bubbling)
contohnya adalah seperti: box.addEventListener('click', expand, false) yang berarti kita menambahkan eventlistener pada node box untuk event click yang akan memanggil fungsi expand dan jenis event yang digunakan adalah bubbling. Berikut ini saya buatkan contoh pengaplikasian eventlistener dan DOM untuk membuat animasi sederhana di halaman web.
   
<html>
<head>
<title>Animasi</title>
<script type="text/javascript">
var c = {
    'i'            : null,
    'box'        : null,
    'state'        : 'b',
    'init'        : function() {
        this.box = document.getElementById('box');
        this._setStyle();
        this.box.addEventListener('click', c.ubahUkuran, false);
    },
    '_setStyle'    : function() {
        var bs = this.box.style;
        bs.width = '300px';
        bs.height = '300px';
        bs.margin = '20px auto';
        bs.border = '1px solid #000';
        bs.background = 'orange';
    },
    'ubahUkuran': function() {
        var w = parseInt(c.box.style.width.replace('px', ''));
        var l = c.state == 'b' ? 80 : 300;
        if (w == l) {
            clearInterval(c.i);
            c.i = null;
            c.state = c.state == 'b' ? 's' : 'b';
            c.box.addEventListener('click', c.ubahUkuran, false);
            return;
        } else {
            w = c.state == 'b' ? w - 5 : w + 5;
            c.box.style.width = w + 'px';
            c.box.style.height = w + 'px';
            c.box.removeEventListener('click', c.ubahUkuran, false);
        }
        if (c.i == null)
            c.i = setInterval(c.ubahUkuran, 13);
    }
}
window.onload = function() {
    c.init();
}
</script>
</head>
<body><div id="box"></div>
</body>
</html>

Coba kamu klik kotak yang ada di tengah halaman web dari hasil kode diatas maka kotak berwarna oranye tersebut akan mengecil. Klik sekali lagi maka kotak kembali membesar dan begitu seterusnya.

    h. Membuat teks berkedip dan bergerak dengan DOM dan CSS

Sekarang kita buat sesuatu yang real yang bisa kita rasakan kegunaan dari DOM. Untuk membuat animasi ini kamu harus sedikit paham tentang Cascading Style Sheet (CSS) karena yang kita lakukan hanya mengubah-ubah properti CSS pada elemen yang akan kita animasikan. Kode lengkapnya adalah seperti berikut:

<html>
<head>
<title>Animasi</title>
<style type="text/css">
#wadah { width: 90%; margin: 50px 5%; position: relative; }
#teks {
    font: bold 20px 'lucida grande', sans-serif;
    position: absolute; left: 0px; opacity: 1.0;
}
</style>
<script type="text/javascript">
// object untuk animasi
var anim = {
    intval        : null, // timer untuk animasi
    objek        : null, // objek dari elemen
    state        : ['dim', 'right'], // opacity dan arah gerakan
    speed        : 3, // kecepatan gerakan
    stop        : function() {
        clearInterval(anim.intval);
        anim.intval = null;
        anim.init();
    },
    init        : function() {
        if (this.objek == null)
            this.objek = document.getElementById('teks');
        // kecepatan animasi per 20 milisecond
        this.intval = setInterval(anim.animasi, 20);
    },
    animasi        : function() {
        // untuk berkedip gunakan opacity, IE 6 gak bisa!
        var opac = parseFloat(getComputedStyle(anim.objek, null).opacity);
        opac = anim.state[0] == 'dim' ? opac - 0.1 : opac + 0.1;
        if (opac == 0.1)
            anim.state[0] = 'highlight';
        if (opac == 1)
            anim.state[0] = 'dim';
        anim.objek.style.opacity = opac;
       
        // untuk bergerak gunakan left
        var left = parseInt(getComputedStyle(anim.objek, null).left.replace('px', ''));
        left = anim.state[1] == 'right' ? left + anim.speed : left - anim.speed;
        if (left > 500)
            anim.state[1] = 'left';
        if (left < 0)
            anim.state[1] = 'right';
        anim.objek.style.left = left + 'px';
       
        // refresh counter
        if (anim.intval > 500)
            anim.stop();
    }
};
window.onload = function() {
    anim.init();
}
</script>
</head>
<body>
<div id="wadah">
    <div id="teks">Teks ini terus bergerak dan berkedip</div>
</div>
</body>
</html>

Oh iya, kode diatas tidak akan dapat berjalan di browser Internet Explorer 6 bawaan XP jadi kamu harus gunakan browser lain yang lebih standar dan mendukung DOM seperti Firefox atau Chrome.

    i. DOM di PHP

DOM tidak hanya ada di JavaScript tapi PHP juga memiliki beberapa class untuk beroperasi dengan DOM. Nama method yang digunakan juga hampir sama seperti getElementById, dsb. jadi jika kamu terbiasa dengan DOM menggunakan JavaScript maka dijamin akan dengan mudah menggunakan fitur DOM di PHP. Berikut ini saya beri contoh kode PHP sederhana untuk membuat dokumen HTML dengan DOM (hasilnya akan sama dengan DOM Javascript pada contoh sebelumnya):

<?php
function buatTagElement($o, $e = '') { return $o->createElement($e); }
function buatTextElement($o, $s = '') { return $o->createTextNode($s); }

$html = '<html>
<head>
<title>Cek</title>
</head>
<body></body>
</html>';

$doc = new DOMDocument('1.0');
$doc->loadHTML($html);

$p     = buatTagElement($doc, 'p');
$br    = buatTagElement($doc, 'br');
$a    = buatTagElement($doc, 'a');
$b     = $doc->getElementsByTagName('body')->item(0);
$a->setAttribute('href', 'www.posank.com');
$a->appendChild(buatTextElement($doc, 'posank?'));
$p->setAttribute('style', 'font-size: 20px');
$p->appendChild(buatTextElement($doc, 'kamu'));
$p->appendChild($br);
$p->appendChild($a);
$b->appendChild($p);

echo $doc->saveHTML();
?>

    j. Kesimpulan :)
   
Jika kamu berminat menjadi web designer yang ingin membuat halaman yang dinamis dan menarik maka pengetahuan tentang DOM mutlak kamu kuasai. Dengan DOM kamu bisa memanipulasi semua elemen yang ada pada dokumen, mengubah atributnya, menambah elemen baru atau menghilangkan elemen yang lain serta membuat animasi ringan dengan Javascript dan CSS. Semua animasi yang pernah kamu lihat pada website modern pasti menggunakan DOM (kecuali animasinya pakai Flash). Pertama mungkin terkesan ruwet dan banyak yang harus dipelajari tapi begitu kamu masuk sedikit kedalam DOM maka kamu akan merasa ketagihan dan dibuat terkagum-kagum dengan hasil kerjamu :D.

Pembahasan berikutnya kita akan membahas jQuery, sebuah framework Javascript yang membuat kerjamu dengan DOM akan semudah membalik telapak tangan. Membuat animasi, memanipulasi elemen, semua dilakukan dengan sedikit kode dan logika jika kamu menggunakan jQuery. Sekian dulu pembahasan kali ini dan sampai jumpa!!

Javascript 2 (Konsep OOP di Javascript)

Pembahasan tentang konsep OOP di bagian kedua ini mungkin cenderung teoritis karena membahas fitur dari bahasa pemrograman dan biasanya dilakukan oleh orang sudah benar-benar paham. Tapi saya akan berusaha membahas sebatas kemampuan saya dan apabila ada kesalahan mohon diingatkan. Tulisan ini mencoba mengulas tentang tiga konsep dari OOP yaitu Encapsulation, Inheritance dan Polymorphism yang diterapkan di bahasa pemrograman Javascript serta isu lain yang berhubungan dengan object.

        a. PEMBUATAN OBJECT
       
Sebelum membuat sebuah object maka kita harus mendefinisikan class terlebih dahulu. Tidak seperti bahasa pemrograman lain yang menggunakan kata kunci "class", pembuatan class di Javascript sama seperti saat kita membuat fungsi biasa. Mungkin yang sedikit membedakan adalah adanya kesepakatan bahwa untuk pembuatan class maka nama fungsinya diawali dengan huruf kapital dan biasanya berupa kata benda sedangkan untuk pembuatan fungsi biasa diawali dengan huruf kecil (lowercase) dan berupa kata kerja. Berikut ini contoh definisi class di Javascript:

// ini class
function Kalkulator() {
    // ... disini method dan property
}
var kalk = new Kalkulator;

// ini fungsi biasa
function kalikan(a, b) {
    return a*b;
}

Pada dasarnya semua fungsi di Javascript bisa menjadi class :). Jika suatu fungsi diberi kata "new", maka dia akan menjadi fungsi constructor (fungsi yang otomatis dipanggil pertama kali saat object dibuat) seperti fungsi Kalkulator diatas.

        b. PROPERTY dan METHOD
       
Sebuah class pada umumnya memiliki setidaknya satu property ataupun method. Property adalah variabel yang didefinisikan dalam class tersebut sedangkan method adalah fungsi yang biasanya bekerja dengan property dari class. Untuk mengakses property atau method digunakan operator titik/dot "." setelah nama object/class yang ditentukan. Contohnya adalah "Math.PI" (mengakses property PI di class Math) dan "kalk.kalikan(2,3)" (mengakses method kalikan() di object kalk).

Class "Kalkulator" pada contoh sebelumnya masih belum memiliki property atau method yang didefinisikan. Di Javascript kamu bisa menambahkan property setiap saat secara dinamis pada object buatan class tersebut. Contohnya seperti ini:

function Kalkulator() { }
var kalk = new Kalkulator;
kalk.angka1 = 5;

alert(kalk.angka1); // 5

Masalahnya property "angka1" hanya dimiliki oleh objek "kalk" saja dan tidak dimiliki oleh objek lain seandainya kita membuat object lagi dari class Kalkulator. Kita bisa menggunakan kata kunci "this" di fungsi constructor untuk membuat property yang akan selalu ada pada semua object yang dibuat dari class Kalkulator dengan cara seperti berikut:

function Kalkulator() {
    this.angka1 = 5;
}
var kalk = new Kalkulator; // object baru
var kalk2 = new Kalkulator; // object lain

Kata kunci "this" untuk menggantikan nama object dirinya sendiri atau bisa dikatakan sebagai object saat ini. Sekarang semua object yang dibuat dari class Kalkulator pasti memiliki property "angka1". Tapi class Kalkulator masih kurang lengkap karena dia tidak memiliki method. Untuk menambahkan method sama seperti saat menambahkan property dan disini aku akan menggunakan fungsi anonim (baca bagian 1 - Javascript Pengetahuan Dasar).

function Kalkulator() {
    this.angka1 = 5;
    this.angka2 = 4;
    this.kalikan = function() {
        return this.angka1 * this.angka2;
    };
}
var kalk = new Kalkulator;
alert( kalk.angka1 ); // contoh akses dari luar object
alert( kalk.kalikan() ); // 20

        c. ENCAPSULATION
       
Pada class Kalkulator diatas kita dapat mengakses property angka1 dan angka2 dari luar object sehingga variabel ini terekspos secara umum (kita bisa mengubah nilai di angka1 dan angka2 dengan mudah dari luar object yang mungkin tidak kita inginkan). Salah satu konsep dari OOP adalah Encapsulation dimana kita bisa menyembunyikan property atau method dari akses yang berasal dari luar object sehingga anggota object lebih terlindungi dan objek dapat berjalan seperti yang diharapkan. Setiap property atau method bisa diberi hak akses apakah dia bisa diakses dari luar atau hanya bisa diakses dari dalam object saja. Encapsulation dianalogikan, adalah seperti tidak semua barang yang kita pakai bisa dan boleh dilihat orang kan?

Untuk membuat property atau method yang memiliki hak akses private (hanya bisa diakses dari dalam object saja) maka kita mengganti kata kunci "this" menjadi "var" di dalam fungsi constructornya. Sekarang kita ingin agar variabel "angka1" dan "angka2" memiliki akses private yaitu dengan cara:

function Kalkulator() {
    var angka1 = 5;
    var angka2 = 4;
    this.kalikan = function() {
        return angka1 * angka2;
    };
}
var kalk = new Kalkulator;
alert( kalk.angka1 ); // undefined karena sekarang private
alert( kalk.kalikan() ); // 20

Sekarang kita tidak bisa lagi mengakses property angka1 dan angka2 dari luar object seperti pada contoh diatas (baris kedua dari bawah) jika kita mencoba mengakses property angka1 yang muncul adalah tipe data "undefined" (tidak terdefinisikan). Dapat disimpulkan bahwa dengan menggunakan kata kunci "var" untuk property maka otomatis property tersebut akan memiliki hak akses private dan hanya dapat diakses dari dalam class saja. Sekarang muncul pertanyaan, bagaimana cara mengubah nilai property dengan akses private dari luar object?

        d. GETTER dan SETTER
       
Dalam OOP ada istilah getter dan setter yang berguna untuk mengubah data dari object yang memiliki akses private. Setter adalah method public yang berfungsi untuk mengeset nilai property yang private sedangkan getter berfungsi untuk mereturn nilai dari property yang memiliki akses private. Contohnya getter dan setter adalah seperti berikut:

function Kalkulator() {
    var angka1 = 0;
    var angka2 = 0;
    var hasil = 0;
   
    this.setAngka1 = function(a1) { // setter untuk angka1
        angka1 = a1;
    };
    this.setAngka2 = function(a2) { // setter untuk angka2
        angka2 = a2;
    };
    this.getHasil = function() { // getter untuk "hasil"
        return hasil;
    };
    this.kalikan = function() { // perkalian simpan ke "hasil"
        hasil = angka1 * angka2;
    }
}
var kalk = new Kalkulator;
kalk.kalikan();
alert( kalk.getHasil() ); // 0
kalk.setAngka1(3); // jadikan angka1 = 3
kalk.setAngka2(4); // jadikan angka2 = 4;
kalk.kalikan();
alert( kalk.getHasil() ); // 12;

Kita memiliki dua setter yaitu setAngka1 dan setAngka2 serta satu getter yaitu getHasil untuk mengubah atau mengakses nilai dari property dengan hak akses private. Selain tidak bisa diakses dari luar object, property dengan akses private juga tidak diwariskan pada object turunannya. Apa ini kok ada warisan segala?? Siapa yang meninggal?

        e. PEWARISAN/INHERITANCE
       
Salah satu konsep lain dari OOP adalah inheritance dimana property atau method suatu object bisa diwariskan pada object lain dengan tujuan untuk dikembangkan kemampuannya. Pada class Kalkulator diatas kita cuma mempunyai satu method "kalikan()" saja, nah daripada kita mengubah class tersebut lebih baik kalau property class tersebut kita turunkan pada class lain lalu kita kembangkan lagi class yang baru agar lebih baik. Mungkin kamu berpikir buat apa diturunkan ke class lain segala, diedit classnya aja kan sudah jadi dan lebih cepat? Ehm, iya kalau classnya seperti contoh diatas cuma memiliki beberapa property dan satu method, bagaimana kalau kamu diberi class yang memiliki ratusan property dan puluhan method yang kamu gak ngerti cara kerjanya?

Di Javascript, konsep inheritance diaplikasikan dengan menggunakan object prototype. Katanya prototype ini adalah template dari property yang dishare oleh semua instance dari object. Jadi semua object akan mewarisi nilai dari property dari prototype (semoga kata-kataku masuk akal :D). Kita langsung pada contoh saja:

// class induk/superclass
function Kalkulator() {
    var angka1 = 0; // private tidak diwariskan
    var    angka2 = 0; // ini juga private
    this.setAngka = function() {}; // ini public dan diwariskan
    this.getHasil = function() {}; // ini juga public
}
KalkulatorTambah.prototype = new Kalkulator; // turunkan class
KalkulatorTambah.prototype.constructor = KalkulatorTambah; // ubah constructor
// class anak/subclass
function KalkulatorTambah() {
    var angka1 = 1;
    var angka2 = 1;
    var hasil = 1;
    this.setAngka = function(a1, a2) { // override method induk
        angka1 = a1;
        angka2 = a2;
    };
    this.tambahkan = function() { // menambah method baru
        hasil = angka1 + angka2;
    };
    this.getHasil = function() { // override method induk
        return hasil;
    }
}
KalkulatorKali.prototype = new Kalkulator;
KalkulatorKali.prototype.constructor = KalkulatorKali;
// class anak lagi
function KalkulatorKali() {
    var angka1 = 2;
    var angka2 = 2;
    var hasil = 2;
    this.setAngka = function(a1, a2) {
        angka1 = a1;
        angka2 = a2;
    };
    this.kalikan = function() {
        hasil = angka1 * angka2;
    }
    this.getHasil = function() {
        return hasil;
    }
}

var kalk1 = new KalkulatorTambah;
var kalk2 = new KalkulatorKali;
kalk1.setAngka(2, 4);
kalk2.setAngka(2, 4);
kalk1.tambahkan();
kalk2.kalikan();
alert( kalk1.getHasil() ); // 6
alert( kalk2.getHasil() ); // 8

Yah, lumayan panjang juga untuk menunjukkan konsep inheritance ini :(. Pada contoh diatas kita buat dua anak turunan (subclass) dari class induk (superclass) Kalkulator yaitu KalkulatorTambah dan KalkulatorKali. Tiap turunan menambahkan method baru ataupun melakukan override (mengubah) method induknya. Semoga kamu bisa membayangkan apa yang terjadi pada class-class tersebut :). Dengan menuliskan "KalkulatorKali.prototype = new Kalkulator" itu berarti kita mewariskan semua property dengan akses public dari object "Kalkulator" ke object "KalkulatorKali". Agar constructor "KalkulatorKali" adalah dirinya sendiri (dan bukan induk) maka kita harus menuliskan "KalkulatorKali.prototype.constructor = KalkulatorKali" karena jika tidak maka object turunan akan tetap memanggil constructor induknya.
Jika kita memanggil sebuah property atau method maka Javascript pertamakali kali mencarinya di definisi classnya apakah didefinisikan secara eksplisit. Jika tidak ditemukan Javascript akan mencari ke prototype class tersebut dan jika tetap tidak ketemu akan dicari di class induknya. Begitu seterusnya hingga Javascript menemukan property yang kita panggil tersebut.

        f. POLYMORPHISM
       
Konsep terakhir dari OOP adalah polymorphism. Kamu lihat lagi contoh diatas dimana ada dua object yang memiliki method yang sama (setAngka dan getHasil). Nah, itu yang disebut polymorphism!. Sesederhana itukah? Jawabannya adalah iya.

Sekali lagi saya ingin mengatakan bahwa pembahasan ini cenderung teoritis artinya kamu gak perlu risau jika kodemu tidak seperti ini (punya inheritance, encapsulation, dsb). Tapi alangkah baiknya, karena tujuan OOP itu untuk mempermudah kerja programmer maka seharusnyalah kamu belajar untuk mengaplikasikan semua konsep diatas pada kode yang kamu buat. Jika kamu bekerja sendiri tanpa tim mungkin tidak masalah tapi jika bekerja dengan tim maka penggunaan OOP akan mempercepat kerjamu dan orang lain dalam timmu. Misalkan, kamu langsung saja memberi tahu kalau method yang public ini, ini dan ini, nah orang lain gak perlu baca keseluruhan kodemu atau edit sana edit sini, mereka cukup menggunakan class buatanmu yang sudah ada, atau jika perlu mereka bisa membuat turunan dari class yang kamu buat, selesai.


        g. CARA LAIN PEMBUATAN OBJECT
       
Pada contoh sebelumnya kita harus mendefinisikan dulu class untuk object yang akan kita buat, nah ada cara baru yang akan aku perkenalkan yaitu pembuatan object secara langsung seperti berikut:

var kalk = {
    "hasil" : 0,
    "kalikan" : function(a1, a2) {
        this.hasil = a1 * a2;
    },
    "getHasil": function() {
        return this.hasil;
    }
}
kalk.kalikan(2,3);
alert( kalk.getHasil() );

Tidak seperti contoh sebelumnya dimana kita harus membuat fungsi constructor lebih dahulu, sekarang kita bisa langsung membuat object secara instan. Objek yang kita inginkan sudah jadi, dan siap digunakan tanpa harus menulis fungsi constructor atau kata kunci "new" lagi. Seperti contoh diatas, untuk membuat object digunakan tanda kurung kurawal {} dan semua method atau properti ditulis dengan bentuk: { "namanya": "nilainya" } dan tiap properti dipisahkan dengan tanda koma (*perhatikan bahwa tanda koma tidak boleh ada setelah elemen terakhir). Object bentukan ini bisa langsung di assign ke variabel seperti contoh diatas langsung di assign ke variabel "kalk" ataupun di pass ke suatu fungsi sebagai parameter seperti berikut:

showResult({ "hasil": 0, "angka1": 2, "angka2": 4 });

Contoh diatas adalah contoh melakukan pass sebuah object kedalam fungsi. Yang perlu kamu catat adalah dengan membuat object seperti ini maka semua property atau method yang kamu deklarasikan akan memiliki hak akses public. Sebagian programmer mengawali nama property atau method dengan underscore (_) untuk menandakan bahwa dia tidak seharusnya diakses langsung dan memiliki hak akses private (contohnya: "_init()", "_width", dsb.)

        h. JSON (JavaScript Object Notation)
       
JSON mirip dengan penulisan object menggunakan kurang kurawal {} yang biasanya digunakan untuk pertukaran data (selain menggunakan XML). Karena JSON berupa string maka JSON dapat dipass ke URL atau metode request lain sehingga object yang sudah jadi tersebut siap digunakan tanpa harus diproses lagi oleh client ataupun oleh server. PHP memiliki dua fungsi yang berhubungan dengan JSON yaitu "json_encode" (melakukan encode object/array PHP ke JSON) dan "json_decode" (melakukan decode JSON ke dalam object/array PHP). Contoh penggunaan fungsi json_decode adalah seperti berikut:

<?php
$json = '{"nama": "amir"}';
$obj = json_decode($json);
print $obj->{'nama'}; // amir
?>

JSON bukanlah Javascript tapi subset dari Javascript sehingga spesifikasi JSON sedikit berbeda. Kode dibawah ini valid Javascript tapi tidak untuk JSON:

var data = { 'nama': "amir", umur: 27, "alamat": "indonesia" }

Alasan tidak valid JSON karena pada JSON nama properti dan nilainya harus diapit tanda double quoute (") dan tidak seperti kode diatas properti nama menggunakan single quote dan umur bahkan tidak menggunakan tanda quote sama sekali.

Karena JSON digunakan untuk pertukaran data maka kita tidak bisa mempass method melalui JSON. Nah bagaimana Javascript menghandle JSON? Jika Javascript menerima data dalam bentuk JSON maka sangat mudah mengubahnya menjadi object yaitu dengan menggunakan fungsi "eval()" atau bila tersedia bisa menggunakan method "window.JSON.parse()" untuk mengubah string JSON ke object yang sebenarnya.
       
        i. STATIC METHOD / PROPERTY
       
Secara singkat, static method atau property adalah method/property yang dimiliki oleh class dan bukan object sehingga untuk mengakses static method/property kita tidak perlu menggunakan kata kunci "new". Secara singkat cara pembuatan static method/property pada Javascript sama seperti menggunakan Prototype tapi sekarang kita hilangkan kata prototype seperti berikut:

function Kalkulator() {
    // definisi class
}
Kalkulator.kalikan = function(a1, a2) { // static method
    return a1 * a2;
}
// Tanpa new dan langsung nama class diikuti nama method kalikan
alert( Kalkulator.kalikan(2, 3) );

Static properti atau method biasanya digunakan jika kamu merasa bahwa ada method/property yang tidak tergantung pada property/method lain dari class tersebut sehingga akan lebih efektif bila kamu membuatnya menjadi static.
       
        -----------------
Saya rasa pembahasan tentang konsep OOP di Javascript sudah dicukupkan sampai sini saja dan semoga yang sedikit ini bisa bermanfaat. Terima kasih atas waktu dan perhatiannya dan sampai jumpa. Oh iya, pada bagian ketiga nanti saya akan membahas tentang DOM dan AJAX. See you!