Membangun SMS Gateway dengan Android, SMSGateway.me, dan Laravel


SMS gateway memungkinkan kita untuk mengirim dan menerima SMS untuk berbagai keperluan pada aplikasi, misal untuk reminder, notifikasi, serta konfirmasi.

SMS gateway adalah sebuah sistem aplikasi yang digunakan untuk mengirim juga menerima SMS, dan biasanya digunakan pada aplikasi bisnis, baik untuk kepentingan broadcast promosi (Bulk SMS), servis informasi terhadap pengguna, penyebaran content produk/jasa dan lain lain.
Umumnya, ada dua cara yang digunakan untuk membangun SMS gateway.

  • Menggunakan perangkat tambahan berupa modem dan aplikasi pendukung seperti Gammu.
  • Menggunakan layanan berbayar pihak ketiga seperti Raja SMS atau Zenziva misalnya.

Masing-masing cara di atas memiliki kekurangan dan kelebihan.

Seperti perangkat tambahan modem misalnya. Kita harus menancapkan modem tersebut pada sebuah PC atau laptop selama 24 jam penuh (atau selama SMS akan digunakan). Ini seperti kita membangun server mini untuk sebuah task khusus. Kelebihannya, kita bisa mengontrol SMS masuk maupun keluar sesuka hati.

Lain lagi dengan layanan menggunakan pihak ketiga. Cara ini terbilang mudah digunakan. Kita cukup mengirim SMS secara programatically ke server mereka, sisanya sistem dan perangkat mereka yang akan mengirimkan SMS ke penerima. Kekurangannya, harga per SMS-nya jauh lebih mahal dibandign SMS reguler. Selain itu, untuk paket SMS paling murah, hanya bisa digunakan untuk mengirim SMS, tidak bisa menerima SMS. Nomornya pun terbatas dan (kebanyakan) bersifat acak. Bisa sih menggunakan momor premium, namun harganya tentu juga tidak murah.

SMSGateway.me

Apa Itu SMSGateway.me?

SMSGateway.me memungkinkan kita untuk mengirim dan menerima SMS secara programmatically (dari aplikasi) dan menjadikan smartphone Android kita sebagai perangkatnya.

Syaratnya tidak ribet, cukup instal aplikasi SMSGateway.me di Android, pastikan pulsa untuk mengirim SMS mencukupi, serta smartphone dalam keadaan menyala saat digunakan.

Alur kerja untuk mengirim SMS adalah sebagai berikut:

  1. Aplikasi mengirim SMS secara programmatically ke server SMSGateway.me.
  2. Data diterima Server.
  3. Aplikasi mengecek server SMSGateway.me untuk mendapatkan antrian SMS.
  4. Jika ada antrian, aplikasi mengirim SMS langsung melalui smartphone.

Hal yang sama juga berlaku untuk alur kerja untuk menerima SMS.

  1. Aplikasi melakukan permintaaan ke server SMSGateway.me.
  2. Permintaan diteruskan ke aplikasi SMSGateway.me di Android.
  3. Jika ada SMS masuk, mengirimkan SMS tersebut ke server SMSGateway.me.
  4. Server SMSGateway.me mengembalikan balasan berupa data SMS masuk.

Using our free service you can turn your Android phone into a free SMS Gateway. Allowing you to both send and receive SMS messages programmatically using our restful API.

Mempersiapkan SMS Gateway

Daftar terlebih dahulu pada layanan SMSGateway.me, untuk mendapatkan email (username) dan password. Tenang, layanan ini gratis — setidaknya untuk sampai saat ini — .

Instal aplikasi SMSGateway.me pada smartphone Android yang ingin digunakan sebagai SMS server. Setelah aplikasi diinstal, login ke aplikasi SMSGateway.me di Android dengan email dan password yang sama pada saat kita mendaftar pada versi web.

Dengan login ke dalam aplikasi Android, kita akan mendaftarkan dan mendapatkan informasi baru berupa Device ID. Device ID ini nantinya akan selalu digunakan untuk autentikasi bersamaan dengan email & password pada saat mengirim SMS dari aplikasi.

Sebagai informasi tambahan, device yang didaftarkan dalam layanan bisa lebih dari satu. Hal tersebut dapat dilakukan dengan cara menginstal aplikasi SMSGateway.me untuk Android pada smartphone yang berbeda.

Mempersiapkan Aplikasi Berbasis Laravel

Penjelasan untuk membangun aplikasi hanya saya tulis secara garis besar. Saya anggap kalian sudah familiar dengan Laravel beserta fitur di dalamnya.

Migrations

Buat sebuah tabel dengan nama messages menggunakan migrations. Pastikan konfigurasi basisdata sudah diatur sebelumnya.

$ php artisan make:migration create_messages_table --create=messages

Tambahkan beberapa kolom pada tabel messages.

/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::create('messages', function (Blueprint $table) {
        $table->increments('id');
 
        // contact information
        $table->integer('contact_id');
        $table->string('contact_number', 30);
        $table->string('contact_name', 100);
 
        // message information
        $table->string('device_id', 30);
        $table->text('message');
        $table->enum('type', ['inbox', 'outbox', 'draft'])->default('outbox');
        $table->dateTime('expired_at');
        $table->timestamps();
 
        $table->index(['contact_name', 'contact_number']);
    });
}

Sejatinya, dalam proses pengiriman SMS, tabel ini tidak harus digunakan. Namun, tak ada salahnya kita menyimpan pesan keluar sebagi log. Tabel ini nantinya akan sangat berguna ketika digunakan untuk menyimpan pesan masuk dari smartphone.

Eksekusi migrations di atas dengan perintah berikut.

$ php artisan migrate

Model

Migrations dan tabel messages sudah dibuat, selanjutnya adalah membuat model.

$ php artisan make:model Message

Adapun lokasi berkas model tersebut ada di app/Message.php.

Tambahkan kolom expired_at ke dalam magic property $dates agar nilai kembaliannya berupa objek Carbon layaknya kolom created_at dan updated_at.

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Message extends Model
{
    /**
     * @var array
     */
    protected $dates = ['expired_at'];
}

Konfigurasi

Buat config baru dengan menambahkan berkas smsgateway.php pada direktori config. Config ini nanti berisi informasi credential seperti email, password, dan device ID yang akan digunakan pada controller untuk mengirim dan menerima SMS melalui API.

<?php
 
return [
    'email'    => env('SMS_EMAIL', 'mail@laravel.web.id'),    // insert your email here
    'password' => env('SMS_PASSWORD', ''), // insert your password here
    'device'   => env('SMS_DEVICE', ''),   // insert your device ID here
];

Pada config di atas, saya menggunakan fungsi env() yang memungkinkan kita menambahkan dan mengatur nilainya dari berkas .env.

Validasi dengan Form Request

Agar controller lebih ramping, untuk validasinya kita menggunakan form request yang dapat dibuat melalui artisan.

$ php artisan make:request Message/ValidationRequest

Adapun isi lengkapnya adalah sebagai berikut.

<?php
 
namespace App\Http\Requests\Message;
 
use Illuminate\Foundation\Http\FormRequest;
 
class ValidationRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }
 
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'number'  => 'required|max:30',
            'name'    => 'required|string|max:50',
            'message' => 'required',
        ];
    }
}

Controller

Buat controller baru dengan nama MessageController menggunakan artisan.

$ php artisan make:controller MessageController

// untuk mendapatkan layout default berbasis bootstrap
$ php artisan make:auth

Di dalam controller ini, kita akan menambahkan dua buah method, yaitu form() dan send(). Yang mana, method form() berfungsi untuk menampilkan masukan nomor telepon tujuan, nama, serta pesan yang akan dikirim. Sedangkan method send() berfungsi untuk mengirim SMS mengunakan SMSGateway.me.

Berikut isi class MessageController.

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Requests\Message\ValidationRequest;
use App\Message;
 
/**
 * @author Yugo <dedy.yugo.purwanto@gmail.com>
 * @copyright Laravel.web.id - 2016
 */
class MessageController extends Controller
{
    /**
     * Show form for send messae
     */
    public function form()
    {
        return view('contents.messages.form');
    }
 
    /**
     * @param ValidationRequest $request
     */
    public function send(ValidationRequest $request)
    {
        abort_if(!function_exists('curl_init'), 400, 'CURL is not installed.');
 
        $curl = curl_init('http://smsgateway.me/api/v3/messages/send');
 
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, [
            'email'    => config('smsgateway.email'),
            'password' => config('smsgateway.password'),
            'device'   => config('smsgateway.device'),
            'number'   => $request->number,
            'name'     => $request->name,
            'message'  => $request->message,
        ]);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
 
        $response = json_decode(curl_exec($curl));
 
        curl_close($curl);
 
        if ($response->success === true) {
            if (!empty($response->result->fails)) {
                \Log::debug($response->result->fails);
            } else {
                foreach ($response->result->success as $success) {
                    $messages[] = [
                        'type'           => 'outbox',
                        'contact_id'     => $success->contact->id,
                        'contact_name'   => $success->contact->name,
                        'contact_number' => $success->contact->number,
                        'device_id'      => $success->device_id,
                        'message'        => $success->message,
                        'expired_at'     => \Carbon\Carbon::now()->timestamp($success->expires_at),
                        'created_at'     => \Carbon\Carbon::now(),
                        'updated_at'     => \Carbon\Carbon::now(),
                    ];
                }
 
                Message::insert($messages);
 
                return redirect()
                    ->route('message.form')
                    ->withSuccess('Message has been sent successfully.');
            }
        } else {
            \Log::debug(json_encode($response->errors));
        }
 
        return redirect()
            ->back()
            ->withError('Failed to send message.');
    }
}

PHP supports libcurl, a library created by Daniel Stenberg, that allows you to connect and communicate to many different types of servers with many different types of protocols. libcurl currently supports the http, https, ftp, gopher, telnet, dict, file, and ldap protocols. libcurl also supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading (this can also be done with PHP’s ftp extension), HTTP form based upload, proxies, cookies, and user+password authentication.

Sedikit penjelasan. Dalam method send() saya menggunakan librari cURL untuk mengirim data ke server SMSGateway.me. Adapun method-nya sendiri berupa POST dengan isi data nomor telepon, nama, dan pesan.

Response dari API SMSGateway.me diproses kembali untuk kemudian disimpan ke dalam tabel messages menggunakan model yang telah dibuat sebelumnya.

Contoh respon data ketika berhasil.

{
    "success": true,
    "result": {
        "success": [
            {
                "id": "308",
                "device_id": "4",
                "message": "hello world!",
                "status": "pending",
                "send_at": "1414624856",
                "queued_at": "0",
                "sent_at": "0",
                "delivered_at": "0",
                "expires_at": "1414634856",
                "canceled_at": "0",
                "failed_at": "0",
                "received_at": "0",
                "error": "None",
                "created_at": "1414624856",
                "contact": {
                    "id": "14",
                    "name": "Phyllis Turner",
                    "number": "+447791064713"
                }
            }
        ],
        "fails": [
        ]
    }
}

SMSgateway.me juga menyediakan librari PHP siap pakai untuk memudahkan dalam mengirim dan mengambil data dari server mereka. Librarinya sendiri dapat diunduh pada tautan berikut smsgateway.me/sms-api-libraries/sms-gateway-me-php.zip.

Form

Buat berkas baru dengan nama form.blade.php pada direktori resources/views/contents/messages. Salin template di bawah untuk membuat form kirim SMS. Kalau perlu, dimodifikasi sedemkian rupa agar lebih nyaman dalam penggunaan.

@extends('layouts.app')
 
@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">{{ $title or 'Send Message' }}</div>
                <div class="panel-body">
 
                    @if (session()->has('error'))
                        <div class="alert alert-danger">{{ session('error') }}</div>
                    @endif
 
                    @if (session()->has('success'))
                        <div class="alert alert-success">{{ session('success') }}</div>
                    @endif
 
                    <form class="form-horizontal" role="form" method="POST" action="{{ route('message.send') }}">
                        {{ csrf_field() }}
                        {{ method_field('post') }}
 
                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">Recipient Number</label>
 
                            <div class="col-md-6">
                                <input id="number" type="text" class="form-control" name="number" value="{{ old('email') }}" autofocus>
 
                                @if ($errors->has('number'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('number') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
 
                        <div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
                            <label for="name" class="col-md-4 control-label">Name</label>
 
                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}">
 
                                @if ($errors->has('name'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('name') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
 
                        <div class="form-group{{ $errors->has('message') ? ' has-error' : '' }}">
                            <label for="message" class="col-md-4 control-label">Message</label>
 
                            <div class="col-md-6">
                                <textarea class="form-control" name="message">{{ old('message') }}</textarea>
 
                                @if ($errors->has('message'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('message') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
 
                        <div class="form-group">
                            <div class="col-md-8 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Send Message
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Hasil akhir form di atas dapat dilihat pada gambar di bawah.

Route

MVC sudah siap, langkah terakhir adalah mendefinisikan URI baru pada berkas routes/web.php.

Route::get('message/send', 'MessageController@form')->name('message.form');
Route::post('message/send', 'MessageController@send')->name('message.send');

Ada dua definisi URI yang sama , yaitu message/send. Meskipun begitu, keduanya memiliki HTTP Verb yang berbeda, di mana baris pertama menggunakan GET, sedangkan baris berikutnya menggunakan POST.

$ php artisan route:list

Uji Coba

Jalankan built-in server dengan perintah php artisan serve dan akses aplikasi melalui peramban dengan URL http://localhost/message/send.

Isikan data nomor telepon, nama, dan pesan, kemudian klik tombol Send. Apakah SMS terkirim dan diterima dengan benar?

Jika iya, Selamat! Kalian sudah berhasil membuat aplikasi sederhana menggunakan SMS gateway.

Fitur

Daftar fitur yang ada saat ini dan yang akan dikembangkan.

Saat ini:

  • Kirim SMS
  • Manajemen pesan masuk dan pesan keluar

Dalam pengembangan:

  • Manajemen kontak
  • Kirim pesan menggunakan antrian (queue) Laravel
  • Tambahkan sebagi channel notifikasi

Konklusi

Aplikasi di atas masih terbatas hanya berupa mengirim SMS. Padahal, dalam dokumentasi API SMSGateway.me ada banyak data yang dapat dikelola. Mulai dari autentikasi, device, pesan masuk/keluar, sampai dengan daftar kontak. Dokumentasi lengkapnya sendiri dapat dilihat pada halaman ini.

Contoh lengkap aplikasi di atas dapat dilihat pada repositori Github Laravel.web.id. Jika pada tulisan ini hanya dicontohkan untuk mengirim SMS saja, di repositori akan selalu saya perbarui mengikuti fitur yang disediakan oleh SMSGateway.me.

Kalian juga dapat berkontribusi pada repositori tersebut dengan membuat Pull Request atau melaporkan bug melalui halaman Issues. 😉

Tak Berkategori

Yugo Purwanto

Pemrogram PHP dan JavaScript yang sedang sibuk mengembangkan aplikasi Glosarium Bahasa Indonesia.

6 comments

  1. Makasi banyak mas atas tutorial nya sangat membantu saya dlm mengerjakan project menggunakan laravel.. btw mas saya penasaran kenapa ketika request POST menggunakan postman dia sampai langsung ke penerima, tapi ketika saya pakai curl/guzzle sms memang sudah terkirim tapi tidak pernah sampai di penerima, apa ada config tambahan ya mas?

  2. Saya sudah mengikuti langkah-langkahnya. Namun terjadi error saat ingin mengkakses halaman.
    Route [message.send] not defined. (View: /home/vagrant/Code/Laravel/resources/views/contents/messages/form.blade.php)

    • Halo,
      Mohon maaf kesalahan saya. Di bagian route, namanya diganti menjadi seperti berikut:

      Route::get('message/send', 'MessageController@form')->name('message.form');
      Route::post('message/send', 'MessageController@send')->name('message.send');
      
    • Bisa pakai librari yang sudah disediakan oleh SMSGateway.me. Disediakan juga contoh implementasinya.

Tinggalkan Balasan