Rabu, 09 November 2016

11/09/2016
12
Selamat malam gais, udah lama ya gak posting sesuatu disini, terakhir kali posting bukan februari kemarin. terus kenapa ko saya mau posting lagi disini? 

Sebenarnya dari dulu pengen terus lanjut bikin tutorial disini, tapi bingung juga harus buat apa. Banyak request tapi isinya minta aplikasi full, jadi tidak saya buatkan. Nah bagi teman-teman yang ingin request tutorial apa saja, silahkan bisa melalui email saya atau komentar di blog ini. Pasti akan saya buatkan asalkan tidak request aplikasi full. Untuk sekarang, kemarin saya buka grup CodeIgniter Indonesia saya gak sengaja lihat postingan mengenai fitur chat kayak FB tapi pada PHP tepatnya CodeIgniter, jadi hari ini saya iseng bikin tapi sangat sederhana, saya yakin banyak bug juga, tapi karena hanya contoh jadi teman-teman bisa sempurakan lagi, terlebih pada sisi keamanannya. OK...


Gambar Widget Chat

Diatas merupakan tampilan dari widget chat yang saya buat, mirip facebook? hahaha masih jauh kayaknya. Langusung saja, berikut database yang saya buat.
CREATE TABLE IF NOT EXISTS `chat` (
  `chat_id` int(11) NOT NULL AUTO_INCREMENT,
  `send_to` int(5) NOT NULL,
  `send_by` int(3) NOT NULL,
  `message` tinytext NOT NULL,
  `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`chat_id`),
  KEY `sent_to` (`send_to`),
  KEY `send_by` (`send_by`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=23 ;


CREATE TABLE IF NOT EXISTS `users` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(200) NOT NULL,
  `username` varchar(32) NOT NULL,
  `password` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `users` (`id`, `name`, `username`, `password`) VALUES
(1, 'Dida Nurwanda', 'didanurwanda', '$2y$10$1bxIR4tiYdycEvK6tLyUf.FUyP0EvWqeV/wzffKffnhe0R7e8Bqpe'),
(2, 'Mark', 'mark', '$2y$10$gm8znIyAw3OyDsGFdsPIueRy2X0TmQmfiw5IFnJqyc55Eqd21hSWS'),
(3, 'Ahmad Saepudin', 'ahmadesae', '$2y$10$dfnDoZCGQhT4unXGzWpCI.V8SbBPhJw3hjm4HcCFx53g4WE5nkC4G');

ALTER TABLE `chat`
  ADD CONSTRAINT `chat_ibfk_1` FOREIGN KEY (`send_by`) REFERENCES `users` (`id`);



Sangat sederhana bukan? database tersebut hanya terdiri dari dua buah table, yaitu table user untuk login dan data diri dan table chat untuk menyeimpan pesan antar user.

Selanjutnya silahkan teman-teman persiapkan Framework CodeIgniter dan koneksikan dengan database yang telah teman-teman buat. Saya anggap ini sudah, selanjutnya buka Welcome.php pada folder controllers dan ubah isinya menjadi seperti berikut.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller {

 public function __construct()
 {
  parent::__construct();
  $this->load->library('session');
  $this->load->database();
  $this->load->helper(array('url', 'form'));
 }

 public function index()
 {
  if (isset($_POST['username']))
  {
   $username = $this->input->post('username', true);
   $password = $this->input->post('password', true);
   if ($username !== '' && $password !== '') {
    $db = $this->db->get_where('users', array('username' => $username), 1)->row();
    if ($db !== null && $db !== false && password_verify($password, $db->password)) {
     $newdata = array(
       'user_id' => $db->id,
             'username'  => $username,
             'logged_in' => TRUE
     );
     $this->session->set_userdata($newdata);
     redirect('chat', 'refresh');
    }
   }
  }

  $this->load->view('login');
 }

 public function logout()
 {
  $this->session->sess_destroy();
  redirect('welcome');
 }
}

Tidak ada yang spesial pada controller ini, hanya berisi halaman login dan logout. Saya anggap teman-teman sudah mengerti. Selanjutnya teman-teman buat view bernama login dan isi dengan script berikut

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?><!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="utf-8">
 <title>Welcome to CodeIgniter</title>
 <link rel="stylesheet" type="text/css" href="<?= base_url('assets/styles.css') ?>">
</head>
<body>

<div id="container">
 <h1>Welcome to CodeIgniter!</h1>

 <div id="body">
  <?= form_open() ?>
   <div><label>Username</label></div>
   <div><?= form_input(array('name' => 'username', 'placeholder' => 'Username')) ?></div>
   <div><label>Password</label></div>
   <div><?= form_password(array('name' => 'password', 'placeholder' => 'Password', 'autocomplete' => 'new-password')) ?></div>
   <div><?= form_submit(array('value' => 'Login')) ?></div>
  <?= form_close() ?>
  <hr />
  Demo (Username/Password)
  <hr />
  didanurwanda/didanurwanda
  <br />mark/mark
  <br />ahmadsae/ahmadsae

 </div>

 <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo  (ENVIRONMENT === 'development') ?  'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
</div>

</body>
</html>

Sebelum berlanjut pada tujuan awal (Chat), teman-teman siapkan file jquery dan styles.css simpan di folder assets pada root directory, isi style seperti berikut

::selection { background-color: #E13300; color: white; }
::-moz-selection { background-color: #E13300; color: white; }

body {
    background-color: #fff;
    margin: 40px;
    font: 13px/20px normal Helvetica, Arial, sans-serif;
    color: #4F5155;
}

a {
    color: #003399;
    background-color: transparent;
    font-weight: normal;
}

h1 {
    color: #444;
    background-color: transparent;
    border-bottom: 1px solid #D0D0D0;
    font-size: 19px;
    font-weight: normal;
    margin: 0 0 14px 0;
    padding: 14px 15px 10px 15px;
}

code {
    font-family: Consolas, Monaco, Courier New, Courier, monospace;
    font-size: 12px;
    background-color: #f9f9f9;
    border: 1px solid #D0D0D0;
    color: #002166;
    display: block;
    margin: 14px 0 14px 0;
    padding: 12px 10px 12px 10px;
}

#body {
    margin: 0 15px 0 15px;
}

p.footer {
    text-align: right;
    font-size: 11px;
    border-top: 1px solid #D0D0D0;
    line-height: 32px;
    padding: 0 10px 0 10px;
    margin: 20px 0 0 0;
}

#container {
    margin: 10px;
    border: 1px solid #D0D0D0;
    box-shadow: 0 0 8px #D0D0D0;
}

#table-friend tr {
    height: 30px;
    background: #cddbde;
}

#table-friend tr a {
    text-decoration: none;
    padding-left: 20px;
    color: #444;
}

/* message box header styles*/

.msg-wgt-container {
    position: fixed;
    bottom: 0;
    right: 20px;
    width: 250px;
    height: 300px;
    border: 1px solid #888888;
}

.minimize.msg-wgt-container {
    height: 29px;
}

.msg-wgt-header {
    width: 100%;
    height: 30px;
    line-height: 2.5em;
    text-align: center;
    background: #6f85b5
}

.msg-wgt-header a {
    color: #ffffff;
    text-decoration: none;
}

.msg-wgt-header a.online {
    width: 10px;
    height: 10px;
    background: #66d266;
    position: absolute;
    left: 10px;
    top: 10px;
    border-radius: 10px;
}

.msg-wgt-header a.close {
    position: absolute;
    right: 10px;
    opacity: .7
}

.msg-wgt-message-container {
    width: 100%;
    height: 230px;
    overflow-y: scroll;
}

.msg-wgt-message-list {
    width: 100%;
}

tr.msg-wgt-message-list-header {
    color: #999;
    font-size: 9px;
    vertical-align: top;
}

tr.msg-wgt-message-list-header img {
    width: 42px;
}

tr.msg-wgt-message-list-header .name {
    text-align: left;
}

tr.msg-wgt-message-list-header .time {
    text-align: right;
}

tr.msg-wgt-message-list-body td {
    font-size: 11px;
    color: #777;
}

tr.msg-wgt-message-list-separator td {
    border-bottom: 1px solid #ddd;
}

.msg-wgt-message-form {
    width: 100%;
    height: 40px;
    border-top: 1px solid #ddd;
}

.msg-wgt-message-form textarea {
    width: 98%;
    border: 0;
    height: 40px;
}

Pada file css diatas, sudah berisi dari style untuk widget chat. Selanjutnya buat buat controller baru dengan nama Chat.php dan isi seperti berikut.

<?php

class Chat extends CI_Controller
{
    public $user;

    public function __construct()
    {
        parent::__construct();
        $this->load->library('session');
        $this->load->database();
        $this->load->helper(array('url', 'form'));
        $this->load->library('user_agent');

        if (!isset($this->session->userdata['logged_in']) || $this->session->userdata['logged_in'] === false) {
            redirect('welcome');
        }

        $this->user = $this->db->get_where('users', array('id' => $this->session->userdata['user_id']), 1)->row();
    }

    public function index()
    {
        $teman = $this->db->where('id !=', $this->user->id)->get('users');
        $this->load->view('chat_dashboard', array(
            'teman' => $teman
        ));
    }

    public function getChats()
    {
        header('Content-Type: application/json');
        if ($this->input->is_ajax_request()) {
            // Find friend
            $friend = $this->db->get_where('users', array('id' => $this->input->post('chatWith')), 1)->row();

            // Get Chats
            $chats = $this->db
                ->select('chat.*, users.name')
                ->from('chat')
                ->join('users', 'chat.send_by = users.id')
                ->where('(send_by = '. $this->user->id .' AND send_to = '. $friend->id .')')
                ->or_where('(send_to = '. $this->user->id .' AND send_by = '. $friend->id .')')
                ->order_by('chat.time', 'desc') // updated
                ->limit(100) // updated
                ->get()
                ->result();

            $result = array(
                'name' => $friend->name,
                'chats' => $chats
            );
            echo json_encode($result);
        }
    }

    public function sendMessage()
    {
        $this->db->insert('chat', array(
            'message' => htmlentities($this->input->post('message', true)),
            'send_to' => $this->input->post('chatWith'),
            'send_by' => $this->user->id
        ));
    }
}

Pada controller Chat inilah kita bisa mengirim dan menerima pesan, selanjutnya buat view dengan nama chat_dashboard.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Chat Dashboard</title>
    <link rel="stylesheet" type="text/css" href="<?= base_url('assets/styles.css') ?>">
    <script type="text/javascript" src="<?= base_url('assets/jquery.min.js') ?>"></script>
</head>
<body>

<div id="container">
    <h1>
        Selamat datang <?= $this->user->name ?>!
        <span style="float: right">Browser: <?= $this->agent->browser().' '.$this->agent->version() ?></span>
    </h1>
    
    <div id="body">
        <p>Silahkan pilih teman:</p>
        <table style="width: 100%" id="table-friend">
            <?php foreach ($teman->result() as $item) { ?>
            <tr>
                <td><a href="javascript:;" data-friend="<?= $item->id ?>"><?= $item->name ?></a></td>
            </tr>
            <?php } ?>
        </table>
        <br />
        <br />
        <a href="<?= site_url('welcome/logout') ?>">Logout</a>
    </div>
</div>


<!-- TEMPLATE -->
<div id="wgt-container-template" style="display: none">
    <div class="msg-wgt-container">
        <div class="msg-wgt-header">
            <a href="javascript:;" class="online"></a>
            <a href="javascript:;" class="name"></a>
            <a href="javascript:;" class="close">x</a>
        </div>
        <div class="msg-wgt-message-container">
            <table width="100%" class="msg-wgt-message-list">
            </table>
        </div>
        <div class="msg-wgt-message-form">
            <textarea name="message" placeholder="Type your message. Press Shift + Enter for newline"></textarea>
        </div>
    </div>
</div>

<script type="text/x-template" id="msg-template" style="display: none">
    <tbody>
        <tr class="msg-wgt-message-list-header">
            <td rowspan="2"><img src="<?= base_url('assets/avatar.png') ?>"></td>
            <td class="name"></td>
            <td class="time"></td>
        </tr>
        <tr class="msg-wgt-message-list-body">
            <td colspan="2"></td>
        </tr>
        <tr class="msg-wgt-message-list-separator"><td colspan="3"></td></tr>
    </tbody>
</script>

<script type="text/javascript">
jQuery(document).ready(function($) {
    var chatPosition = [
        false, // 1
        false, // 2
        false, // 3
        false, // 4
        false, // 5
        false, // 6
        false, // 7
        false, // 8
        false, // 9
        false // 10
    ];

    // New chat
    $(document).on('click', 'a[data-friend]', function(e) {
        var $data = $(this).data();
        if ($data.friend !== undefined && chatPosition.indexOf($data.friend) < 0) {
            var posRight = 0;
            var position;
            for(var i in chatPosition) {
                if (chatPosition[i] == false) {
                    posRight = (i * 270) + 20;
                    chatPosition[i] = $data.friend;
                    position = i;
                    break;
                }
            }
            var tpl = $('#wgt-container-template').html();
            var tplBody = $('<div/>').append(tpl);
            tplBody.find('.msg-wgt-container').addClass('msg-wgt-active');
            tplBody.find('.msg-wgt-container').css('right', posRight + 'px');
            tplBody.find('.msg-wgt-container').attr('data-chat-position', position);
            tplBody.find('.msg-wgt-container').attr('data-chat-with', $data.friend);
            $('body').append(tplBody.html());
            initializeChat();
        }
    });

    // Minimize Maximize
    $(document).on('click', '.msg-wgt-header > a.name', function() {
        var parent = $(this).parent().parent();
        if (parent.hasClass('minimize')) {
            parent.removeClass('minimize')
        } else {
            parent.addClass('minimize');
        }
    });

    // Close
    $(document).on('click', '.msg-wgt-header > a.close', function() {
        var parent = $(this).parent().parent();
        var $data = parent.data();
        parent.remove();
        chatPosition[$data.chatPosition] = false;
        setTimeout(function() {
            initializeChat();
        }, 1000)
    });

    var chatInterval = [];

    var initializeChat = function() {
        $.each(chatInterval, function(index, val) {
            clearInterval(chatInterval[index]);   
        });

        $('.msg-wgt-active').each(function(index, el) {
            var $data = $(this).data();
            var $that = $(this);
            var $container = $that.find('.msg-wgt-message-container');

            chatInterval.push(setInterval(function() {
                var oldscrollHeight = $container[0].scrollHeight;
                var oldLength = 0;
                $.post('<?= site_url('chat/getChats') ?>', {chatWith: $data.chatWith}, function(data, textStatus, xhr) {
                    $that.find('a.name').text(data.name);
                    // from last
                    var chatLength = data.chats.length;
                    var newIndex = data.chats.length;
                    $.each(data.chats, function(index, el) {
                        newIndex--;
                        var val = data.chats[newIndex];

                        var tpl = $('#msg-template').html();
                        var tplBody = $('<div/>').append(tpl);
                        var id = (val.chat_id +'_'+ val.send_by +'_'+ val.send_to).toString();
                        


                        if ($that.find('#'+ id).length == 0) {
                            tplBody.find('tbody').attr('id', id); // set id
                            tplBody.find('td.name').text(val.name); // set name
                            tplBody.find('td.time').text(val.time); // set time
                            tplBody.find('.msg-wgt-message-list-body > td').html(nl2br(val.message)); // set message
                            $that.find('.msg-wgt-message-list').append(tplBody.html()); // append message

                            //Auto-scroll
                            var newscrollHeight = $container[0].scrollHeight - 20; //Scroll height after the request
                            if (newIndex === 0) {
                                $container.animate({ scrollTop: newscrollHeight }, 'normal'); //Autoscroll to bottom of div
                            }
                        }
                    });
                });
            }, 1000));

            $that.find('textarea').on('keydown', function(e) {
                var $textArea = $(this);
                if (e.keyCode === 13 && e.shiftKey === false) {
                    $.post('<?= site_url('chat/sendMessage') ?>', {message: $textArea.val(), chatWith: $data.chatWith}, function(data, textStatus, xhr) {
                    });
                    $textArea.val(''); // clear input

                    e.preventDefault(); // stop 
                    return false;
                }
            });
        });
    }

    var nl2br = function(str, is_xhtml) { // PHP JS
        var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br ' + '/>' : '<br>'; // Adjust comment to avoid issue on phpjs.org display
        return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2');
    }

    // on load
    initializeChat();
});
</script>

</body>
</html>

Pembuatan file selesai dan saya tidak menggunakan model pada contoh kali ini karena isinya sangat sederhana.  Sedikit penjelasan, pada chat ini saya membuat 2 template untuk widget dan untuk isi chat, teman-teman dapat melihatnya pada chat_dashboard, dengan template ini kita bisa menambahkan widget dengan cepat tanpa harus membuat manual dengan javascript. Widget ini juga saya batasi hanya dapat menampung 10 chat saja. Tidak banyak memang, teman-teman bisa menambahkannya sesuka hati kok. Berikut adalah tampilannya




Diatas merupakan contoh aplikasinya. Teman-teman juga dapat mencoba dan mendownload aplikasi tersebut pada tombol/gambar dibawah ini.

 Download
Download

 Demo
Demo

12 komentar:

  1. Keren. ijin minta yap. buat belajar.

    BalasHapus
  2. gan kalo chatan biar gak di bawah gimana ?

    BalasHapus
    Balasan
    1. tinggal hapus aja baris autoscroll.
      $(...).animate(blablabla)

      Hapus
  3. Kalo di tambah ada emo, sama bisa attach file / gambar itu gimana ya mas ?

    BalasHapus
    Balasan
    1. bisa dong, kirimnya pake kode kodean : D atau : P nanti di replace pesannya di client/js

      Hapus
  4. gan passwordnya memakai enkripsi apa? terima kasih

    BalasHapus
    Balasan
    1. pakai password_hash http://php.net/manual/en/function.password-hash.php

      Hapus

Mohon tidak mencantumkan URL pada komentar yang bersifat promosi.