Kaherecode

[Laravel] comment intégrer l'API SMS d'Orange

Diallo Mamoudou
@Moudjames23 24 juin 2020
0

Dans ce tutoriel, nous allons apprendre ensemble comment intégrer l'API SMS d'Orange dans une application web avec le framework PHP Laravel.

Vous aviez été nombreux à me demander comment tu fais pour envoyer les SMS de Kisal? (Oui oui on va faire comme les influenceurs Instagram). Comme l'indique le titre, l'application sera développée en Laravel et je suppose déjà que vous aviez les bases si ce n'est pas le cas ce tutorielpourra vous servir à l'implémenter sur d'autres techno.

Je sais que vous êtes pressés à taper du code mais on va se calmer d'abord. Je sais que vous êtes pressés de taper du code mais on va se calmer

Avant de passer aux choses sérieuses, on va créer un projet sur Orange developer  pour avoir la possibilité d'utiliser leur API.

Créer un compte sur Orange developer, à la fin de la création vous recevrez un e-mail d'activation (On est tous de grands garçons et de grandes filles  donc pas besoin de l'expliquer)

Cliquez sur le bouton "My apps" en haut à droite

Donnez un nom avec application et une petite description

Normalement vous devriez avoir cette page en face de vous. Orange dispose de plusieurs APIs qui sont souvent accessibles selon le pays. Dans notre cas, c'est l'API SMS qui nous intéresse donc pour l'ajouter il faudra cliquer sur le bouton "Add an API", voir la capture ci-dessous. 

Maintenant choisissez la bonne API, dans notre cas ça sera "SMS Guinea Conakry(1.1)", après cliquer sur le bouton "Next" puis accepter les conditions d'utilisation (si vous pouvez lire ce qui est dit )

A cet stade, notre projet est prêt parce que nous avions configuré l'API SMS de la Guinée (Au passage Guinée-Conakry n'existe pas mais ça c'est un autre débat). 

Juste une petite précision, LES SMS NE SONT PAS GRATUITS.

Euh revenez ne fuyez pas. Je vous assure que ça coûte pas cher non plus:

Je vous conseille d'acheter le pack de 15 ou 100 SMS pour faire vos tests, ça sera largement suffisant.

Vous remarquerez qu'il y'a une nouvelle section qui est apparue cliquer sur le bouton "Configure" pour passer à l'achat. (Voir image ci-dessous)

Choisissez le pack qui vous convient, moi j'ai choisi celui de 100 SMS qui coûte 20 000 GNF, après à gauche sélectionnez le mode de paiement et cliquer sur le bouton "Buy".

Vous apercevrez une zone de saisie dans laquelle vous mettrez votre numéro de téléphone. Cliquer sur le bouton "Ok". Patientez un instant vous allez recevoir un SMS contenant un code de confirmation que vous copierez dans la zone de saisie puis cliquer sur le bouton "Continue". Si tout se passe bien, vous aviez été facturé en fonction du pack que vous aviez choisi donc dans mon cas c'est 20 000 GNF (100 SMS).

Bravo on a finit la première étape

Vous êtes prêt là ?

Pour vous faire gagner en temps, j'ai un projet laravel de base que je clone à chaque fois je commence un nouveau. J'ai la gestion des utilisateurs, la gestion des rôles et permissions et l'intégration d'un template admin qui sont déjà faites, vous pouvez le télécharger ici

Télécharger les librairies nécessaires

$ composer update

Configurer le fichier .env, remplacez les informations de connexion 

APP_NAME=Laravel
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=sms_devscom
DB_USERNAME=root
DB_PASSWORD=

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

Générer la clé

$ php artisan key:generate

N'oubliez pas de configurer la base de donnée et d'exécuter la commande

$ php artisan migrate --seed

Lancer l'application en tapant: 

$ php artisan serve

Sur la page d'authentification les identifiants sont les suivants: admin@gmail.com et le mot de passe: password. Lors de la première connexion on vous demandera de modifier le mot de passe.

Normalement vous devriez avoir cette page devant vos yeux.

Super ! jusqu'ici tout va bien, maintenant notre objectif sera d'avoir deux zones de saisie une pour le numéro de téléphone et une autre pour le message à envoyer.

Pour nous faciliter on va utiliser cette librairie, tout ce qui nous intéresse c'est la classe src/Osms.php.

Créer un dossier Helpers dans le répertoire App. Copiez-y la classe Osms.php en la renommant simplement en Sms.php

Sms.php

<?php

namespace App\Helpers;

class Sms {

    const BASE_URL = 'https://api.orange.com';

    /**
     * Client Identifier. Unique ID provided by the Orange backend server to identify
     * your application.
     *
     * @var string
     */
    protected $clientId = '';

    /**
     * Client Secret. Used to sign/crypt the requests.
     *
     * @var string
     */
    protected $clientSecret = '6Av9unjOuAF0mI7F';

    /**
     * The Token will be used for all further API calls.
     *
     * @var string
     */
    protected $token = '';

    /**
     * cURL option for whether to verify the peer's certificate or not.
     *
     * @var bool
     */
    protected $verifyPeerSSL = true;

    /**
     * Creates a new Osms instance. If the user doesn't know his token or doesn't have a
     * token yet, he can leave $token empty and retrieve a token with
     * getTokenFromConsumerKey() method later.
     *
     * @param  array  $config  An associative array that can contain clientId, clientSecret,
     *                         token, and verifyPeerSSL
     *
     * @return void
     */
    public function __construct($config = array())
    {
        if (array_key_exists('clientId', $config)) {
            $this->clientId = $config['clientId'];
        }
        if (array_key_exists('clientSecret', $config)) {
            $this->clientSecret = $config['clientSecret'];
        }
        if (array_key_exists('token', $config)) {
            $this->token = $config['token'];
        }
        if (array_key_exists('verifyPeerSSL', $config)) {
            $this->verifyPeerSSL = $config['verifyPeerSSL'];
        } else {
            $this->verifyPeerSSL = true;
        }
    }

    /**
     * Retrieves a token from Orange server, that will be used for all further API calls.
     *
     * @return array
     */
    public function getTokenFromConsumerKey()
    {
        $url = self::BASE_URL . '/oauth/v3/token';

        $credentials = $this->getClientId() . ':' . $this->getClientSecret();

        $headers = array('Authorization: Basic ' . base64_encode($credentials));

        $args = array('grant_type' => 'client_credentials');

        $response = $this->callApi($headers, $args, $url, 'POST', 200);

        if (!empty($response['access_token'])) {
            $this->setToken($response['access_token']);
        }

        return $response;
    }

    /**
     * Sends SMS.
     *
     * @param  string  $senderAddress    The receiver address in this format:
     *                                   "tel:+22500000000"
     * @param  string  $receiverAddress  The receiver address in this format:
     *                                   "tel:+22500000000"
     * @param  string  $message          The content of the SMS, must not exceed
     *                                   160 characters
     * @param  string  $senderName       The sender name
     *
     * @return array
     */
    public function sendSms(
        $senderAddress,
        $receiverAddress,
        $message,
        $senderName
    ) {
        $url = self::BASE_URL . '/smsmessaging/v1/outbound/' . urlencode($senderAddress)
            . '/requests';

        $headers = array(
            'Authorization: Bearer ' . $this->getToken(),
            'Content-Type: application/json'
        );

        if (!empty($senderName)) {
            $args = array(
                'outboundSMSMessageRequest' => array(
                    'address'                   => $receiverAddress,
                    'senderAddress'             => $senderAddress,
                    'senderName'                => urlencode($senderName),
                    'outboundSMSTextMessage'    => array(
                        'message' => $message
                    )
                )
            );
        } else {
            $args = array(
                'outboundSMSMessageRequest' => array(
                    'address'                   => $receiverAddress,
                    'senderAddress'             => $senderAddress,
                    'outboundSMSTextMessage'    => array(
                        'message' => $message
                    )
                )
            );
        }

        return $this->callApi($headers, $args, $url, 'POST', 201, true);
    }

    /**
     * Lists SMS usage statistics per application.
     *
     * @param  array  $args  An associative array to filter the results, containing
     *                       country (the international 3 digits country code) and/or
     *                       appid (you can retrieve your application ID from your
     *                       dashboard application)
     *
     * @return array
     */
    public function getAdminStats($args = null)
    {
        $url = self::BASE_URL . '/sms/admin/v1/statistics';

        $headers = array('Authorization: Bearer ' . $this->getToken());

        return $this->callApi($headers, $args, $url, 'GET', 200);
    }

    /**
     * Displays how many SMS you can still send.
     *
     * @param  string  $country  The country to filter on (the international 3 digits
     *                           country)
     *
     * @return array
     */
    public function getAdminContracts($country = '')
    {
        $url = self::BASE_URL . '/sms/admin/v1/contracts';

        $headers = array('Authorization: Bearer ' . $this->getToken());

        $args = null;

        if (!empty($country)) {
            $args = array('country' => $country);
        }

        return $this->callApi($headers, $args, $url, 'GET', 200);
    }

    /**
     *  Lists your purchase history.
     *
     * @param  string  $country  The country to filter on (the international 3 digits
     *                           country)
     *
     * @return array
     */
    public function getAdminPurchasedBundles($country = '')
    {
        $url = self::BASE_URL . '/sms/admin/v1/purchaseorders';

        $headers = array('Authorization: Bearer ' . $this->getToken());

        $args = null;

        if (!empty($country)) {
            $args = array('country' => $country);
        }

        return $this->callApi($headers, $args, $url, 'GET', 200);
    }

    /**
     *  Calls API Endpoints.
     *
     * @param  array   $headers         An array of HTTP header fields to set
     * @param  array   $args            The data to send
     * @param  string  $url             The URL to fetch
     * @param  string  $method          Whether to do a HTTP POST or a HTTP GET
     * @param  int     $successCode     The HTTP code that will be returned on
     *                                  success
     * @param  bool    $jsonEncodeArgs  Whether or not to json_encode $args
     *
     * @return array   Contains the results returned by the endpoint or an error
     *                 message
     */
    public function callApi(
        $headers,
        $args,
        $url,
        $method,
        $successCode,
        $jsonEncodeArgs = false
    ) {
        $ch = curl_init();

        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_POST, true);

            if (!empty($args)) {
                if ($jsonEncodeArgs === true) {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($args));
                } else {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($args));
                }
            }
        } else /* $method === 'GET' */ {
            if (!empty($args)) {
                curl_setopt($ch, CURLOPT_URL, $url . '?' . http_build_query($args));
            } else {
                curl_setopt($ch, CURLOPT_URL, $url);
            }
        }

        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        if ($this->getVerifyPeerSSL() === false) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }
        // Make sure we can access the response when we execute the call
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $data = curl_exec($ch);

        if ($data === false) {
            return array('error' => 'API call failed with cURL error: ' . curl_error($ch));
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        curl_close($ch);

        $response = json_decode($data, true);

        $jsonErrorCode = json_last_error();
        if ($jsonErrorCode !== JSON_ERROR_NONE) {
            return array(
                'error' => 'API response not well-formed (json error code: '
                    . $jsonErrorCode . ')'
            );
        }

        if ($httpCode !== $successCode) {
            $errorMessage = '';

            if (!empty($response['error_description'])) {
                $errorMessage = $response['error_description'];
            } elseif (!empty($response['error'])) {
                $errorMessage = $response['error'];
            } elseif (!empty($response['description'])) {
                $errorMessage = $response['description'];
            } elseif (!empty($response['message'])) {
                $errorMessage = $response['message'];
            } elseif (!empty($response['requestError']['serviceException'])) {
                $errorMessage = $response['requestError']['serviceException']['text']
                    . ' ' . $response['requestError']['serviceException']['variables'];
            } elseif (!empty($response['requestError']['policyException'])) {
                $errorMessage = $response['requestError']['policyException']['text']
                    . ' ' . $response['requestError']['policyException']['variables'];
            }

            return array('error' => $errorMessage);
        }

        return $response;
    }

    /**
     *  Gets the Cliend ID.
     *
     * @return string
     */
    public function getClientId()
    {
        return $this->clientId;
    }

    /**
     *  Sets the Client ID.
     *
     * @param  string  $clientId  the Client ID
     */
    public function setClientId($clientId)
    {
        $this->clientId = $clientId;
    }

    /**
     *  Gets the Client Secret.
     *
     * @return string
     */
    public function getClientSecret()
    {
        return $this->clientSecret;
    }

    /**
     *  Sets the Client Secret.
     *
     * @param  string  $clientSecret  the Client Secret
     */
    public function setClientSecret($clientSecret)
    {
        $this->clientSecret = $clientSecret;
    }

    /**
     *  Gets the (local/current) Token.
     *
     * @return string
     */
    public function getToken()
    {
        return $this->token;
    }

    /**
     *  Sets the Token value.
     *
     * @param  string  $token  the token
     */
    public function setToken($token)
    {
        $this->token = $token;
    }

    /**
     *  Gets the CURLOPT_SSL_VERIFYPEER value.
     *
     * @return bool
     */
    public function getVerifyPeerSSL()
    {
        return $this->verifyPeerSSL;
    }

    /**
     *  Sets the CURLOPT_SSL_VERIFYPEER value.
     *
     * @param  bool  $verifyPeerSSL  FALSE to stop cURL from verifying the
     *                               peer's certificate. TRUE otherwise.
     */
    public function setVerifyPeerSSL($verifyPeerSSL)
    {
        $this->verifyPeerSSL = $verifyPeerSSL;
    }
}

Pour envoyer un SMS faudra instancier cette classe en lui donnant les bonnes informations. on va créer une méthode sendSMS

public function sendSMS($phone, $message)
    {
        $config = array(
            'clientId' => config('app.clientId'),
            'clientSecret' =>  config('app.clientSecret'),
        );

        $osms = new Sms($config);

        $data = $osms->getTokenFromConsumerKey();
        $token = array(
            'token' => $data['access_token']
        );

        $response = $osms->sendSms(
        // sender
            'tel:+224620000000',
            // receiver
            'tel:+224' . $phone,
            // message
            $message,
            'Devscom'
        );
    }

Cette méthode prend deux paramètres, le premier c'est le numéro de téléphone auquel on envoie le SMS et le deuxième le message qu'on veut lui envoyer.

Pour avoir le clientId et le clientSecret, cliquer sur le bouton "Show" comme indiquer sur la capture suivante. On demandera de retaper votre mot de passe avant que ces informations ne soient visibles. 

Ouvrer le fichier config/app.php et remplacer le clientId et le clientSecret par les bonnes informations

'clientId' => '',
'clientSecret' => '',

routes/web.php

/********* ENVOIE SMS ****************/
    Route::get('message', 'MessageController@create')->name('message.create');
    Route::post('message', 'MessageController@send')->name('message.store');

resources/views/backend/messages/create.blade.php

@extends('backend.base')
@section('content')
    <div class="col-sm-8 col-lg-offset-2">
        <div class="panel">
            <div class="panel-heading">
                <h3 class="panel-title">{{ $title }}</h3>
            </div>

            <!--Horizontal Form-->
            <!--===================================================-->

            {!! Form::open(['method' => 'POST', 'class' => 'panel-body form-horizontal form-padding', 'url' => route('message.store')]) !!}
            <div class="panel-body">
                <div class="panel-body">
                    @include('backend.messages._form')
                </div>
                <div class="panel-footer text-right">
                    <button class="btn btn-success" type="submit">Envoyer</button>
                </div>
            </div>

            {!! Form::close() !!}
            <!--===================================================-->
            <!--End Horizontal Form-->

        </div>
    </div>
@endsection

resources/views/backend/messages/_form.blade.php

<div class="form-group">
    <label class="col-sm-3 control-label" for="email"><b>Numéro de téléphone</b></label>
    <div class="col-sm-9">
        <input type="text" placeholder="Numéro de téléphone sans le +224" id="phone" name="phone" class="form-control">
        {!! $errors->first('phone', '
        <small class="help-block ">:message</small>
        ') !!}
    </div>
</div>

<div class="form-group">
    <label class="col-sm-3 control-label" for="email"><b>Message</b></label>
    <div class="col-sm-9">
        <textarea name="message" id="" cols="63" rows="10"></textarea>
        {!! $errors->first('message', '
        <small class="help-block ">:message</small>
        ') !!}
    </div>
</div>

app/http/controllers/MessageController.php

<?php

namespace App\Http\Controllers;

use App\Helpers\Sms;
use Illuminate\Http\Request;

class MessageController extends Controller
{

    public function create()
    {
        $title = 'Nouveau message';

        return view('backend.messages.create', compact(['title']));
    }

    public function send(Request $request)
    {
        $this->validate($request, [
            'phone' => 'required|numeric',
            'message' => 'required|max:255',
        ]);

        $this->sendSMS($request['phone'], $request['message']);

        return redirect(route('message.create'));
    }

    public function sendSMS($phone, $message)
    {
        $config = array(
            'clientId' => config('app.clientId'),
            'clientSecret' =>  config('app.clientSecret'),
        );

        $osms = new Sms($config);

        $data = $osms->getTokenFromConsumerKey();
        $token = array(
            'token' => $data['access_token']
        );

        $response = $osms->sendSms(
        // sender
            'tel:+224620000000',
            // receiver
            'tel:+224' . $phone,
            // message
            $message,
            'Devscom'
        );
    }
}

Je sais pertinemment qu'on a dû laisser certains mais si vous êtes toujours là bravo à vous. Maintenant passons à l'heure de vérité en testant si tout marche bien.

Et bim !

Et voilà notre objectif est atteint. Félicitations ! Le code source est téléchargeable ici.


Partage ce tutoriel


Merci à

Diallo Mamoudou

Continue de lire

Discussion

Tu dois être connecté pour participer à la discussion. Me connecter.