Retour au blog

Comment envoyer des SMS depuis l'API d'OVH avec Symfony ?

Dans le cadre de certains projets, selon sa thématique, il arrive que l'on souhaite faire plus qu’envoyer de simples notifications par e-mail à nos interlocuteurs. En effet, il devient aujourd’hui aisé de souscrire à des offres permettant d'envoyer des messages (SMS) à partir d’Internet. Ceci est l'opportunité de doubler l’interaction avec les utilisateurs.

Dans cet article, vous pourrez donc découvrir comment envoyer un message à partir d’une API, celle d’OVH, et Symfony.

Configurer un compte SMS depuis OVH

Avant toute chose, il est nécessaire que vous ayez configuré votre compte SMS depuis votre espace client OVH. Je vous renvoie directement à la documentation d’OVH pour la création de vos identifiants. Vous aurez les informations utiles au développement pour envoyer un SMS par internet, du moins depuis un projet Symfony.

Comment envoyer un SMS via l'espace client d'OVH ?

Pour l’exemple, nous pouvons partir de la création d’une commande Symfony pour envoyer une notification SMS à un numéro de téléphone défini. Depuis cette commande, nous pourrons également : 

  • lister les numéros blacklistés (ceux qui auront envoyé STOP à la suite du SMS)
  • supprimer un numéro de la blacklist.

 

Préparer vos paramètres

Pour commencer, nous aurons besoin de l’API OVI :


composer require ovh/ovh

Nous pourrons ensuite configurer le parameters.yml.dist pour utiliser l’API :


# SMS API OVH
ovh.api:
    application_key: ~
    application_secret: ~
    consumer_key: ~
    end_point: ovh-eu  

Mélanger vos commandes

Pour la commande SMSCommand, on prévoit d’utiliser 3 options (send, list, blacklist) avec l’obligation de renseigner un numéro pour certains cas.


<?php

namespace AppBundle\Command;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SmsCommand extends BaseCommand
{
    protected function configure()
    {
        $this
            ->setName('app:sms:notifications')
            ->setDescription('SMS command (Format number : +336...)')
            ->addOption('send', 's', InputOption::VALUE_REQUIRED, 'Send SMS to an specific number')
            ->addOption('list', 'l', InputOption::VALUE_NONE, 'List number blacklist')
            ->addOption('blacklist', 'b', InputOption::VALUE_REQUIRED, 'Remove an number from blacklist')
        ;
    }
}

Attention : il est important de signaler que vous devrez envoyer des numéros au format +336… à l’API d’OVH pour qu’ils soient bien envoyés. N’hésitez pas à créer un service qui vous permettra de transformer votre numéro au format international !

Pour la première partie de notre commande, on découpe notre function execute() par options qui feront chacune appel à une méthode du SmsProvider :


<?php

namespace AppBundle\Command;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SmsCommand extends BaseCommand
{
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // Exécution de la commande avec l’option ‘send’
        // et son paramètre (numéro au format +336)
        if ($input->getOption('send')) {
            $this->log('info', sprintf('Test to send an SMS to "%s"', $input->getOption('send')));

            try {
                $this->getContainer()->get('app.sms.provider')->sendMessage($input->getOption('send'), 'Votre message');
                $this->log('info', sprintf('SMS send to %s', $input->getOption('send')));
            } catch (\Exception $e) {
                $this->log('info', sprintf('Error to send an SMS to %s : %s', $input->getOption('blacklist'), $e->getMessage()));
            }
        }

        // Exécution de la commande avec l’option ‘list’
        if ($input->getOption('list')) {
           $output->writeln('List number from blacklist :');
           $results = $this->getContainer()->get('app.sms.provider')->getBlacklist();
           $output->writeln($results);
        }

        // Exécution de la commande avec l’option ‘blacklist’
        // et son paramètre (numéro au format +336)
        if ($input->getOption('blacklist')) {
            $this->log('info', sprintf('Remove "%s" from blacklist', $input->getOption('blacklist')));
    
            try {
                $this->getContainer()->get('app.sms.provider')->removeFromBlacklist($input->getOption('blacklist'));
                $this->log('info', sprintf('%s removed from blacklist', $input->getOption('blacklist')));
            } catch (\Exception $e) {
                $this->log('info', sprintf('Error to remove %s from blacklist : %s', $input->getOption('blacklist'), $e->getMessage()));
            }
        }
    }
}

Saupoudrer de Service et à table !

Ensuite, pour envoyer un message, on récupère le numéro au format requis puis on fait appel à notre SmsProvider qui contient les méthodes principales. Il en sera de même pour supprimer un numéro de la blacklist.


<?php

namespace AppBundle\Provider;

use Ovh\Exceptions\InvalidParameterException;
use Psr\Log\LoggerInterface;
use Ovh\Api;

class SmsProvider
{
    /** @var array */
    private $config;
    /** @var LoggerInterface */
    private $logger;

    public function __construct($config, LoggerInterface $logger)
    {
        $this->config = $config;
        $this->logger = $logger;
    }

    /**
     * @param array|string $phoneNumbers
     * @param string $message
     * @return array|bool|mixed
     * @throws \Exception
     */
    public function sendMessage($phoneNumbers, $message)
    {
        $conn = $this->connectToApi();

        $phoneNumbers = (array)$phoneNumbers;

        $content = [
            'charset' => 'UTF-8',
            'class' => 'phoneDisplay',
            'coding' => '7bit',
            'message' => $message,
            'noStopClause' => true,
            'priority' => 'high',
            'receivers' => $phoneNumbers,
            'senderForResponse' => true,
        ];

        try {
            $smsServices = $conn->get('/sms/');
            $result = $conn->post(sprintf('/sms/%s/jobs/', $smsServices[0]), $content);

        } catch (\Exception $e) {
            if (null !== $this->logger) {
                $this->logger->critical(
                    sprintf("Erreur lors de l'envoi SMS : %s . Trace : %s", $e->getMessage(), $e->getTraceAsString()), [
                        'paramsOvh' => $content
                    ]
                );
            }

            $result = false;
        }

        return $result;
    }

    /**
     * @param $phoneNumber
     * @return array|bool
     * @throws InvalidParameterException
     * @throws \Exception
     */
    public function removeFromBlacklist($phoneNumber)
    {
        $conn = $this->connectToApi();

        try {
            $smsServices = $conn->get('/sms/');
            $result = $conn->delete(sprintf('/sms/%s/blacklists/%s', $smsServices[0], $phoneNumber));

        } catch (\Exception $e) {
            if (null !== $this->logger) {
                $this->logger->critical(
                    sprintf('Erreur lors de la suppression du numéro de la blacklist : %s . Trace : %s', $e->getMessage(), $e->getTraceAsString())
                );
            }

            $result = false;
        }

        return $result;
    }

    /**
     * @return array|bool
     * @throws InvalidParameterException
     * @throws \Exception
     */
    public function getBlacklist()
    {
        $conn = $this->connectToApi();

        try {
            $smsServices = $conn->get('/sms/');
            $result = $conn->get(sprintf('/sms/%s/blacklists', $smsServices[0]));

        } catch (\Exception $e) {
            if (null !== $this->logger) {
                $this->logger->critical(
                    sprintf('Erreur lors de la requête GET blacklist : %s . Trace : %s', $e->getMessage(), $e->getTraceAsString())
                );
            }

            $result = false;
        }

        return $result;
    }

    /**
     * @return Api
     * @throws InvalidParameterException
     * @throws \Exception
     */
    private function connectToApi()
    {
        if (!isset($this->config['application_key'],
            $this->config['application_secret'],
            $this->config['consumer_key'],
            $this->config['end_point'])
        ) {
            $this->logger->error('OVH config parameters are missing');
            throw new \Exception('OVH config parameters are missing');
        }

        $applicationKey = $this->config['application_key'];
        $applicationSecret = $this->config['application_secret'];
        $consumerKey = $this->config['consumer_key'];
        $endPoint = $this->config['end_point'];

        try {
            $conn = new Api(
                $applicationKey,
                $applicationSecret,
                $endPoint,
                $consumerKey
            );
        } catch (InvalidParameterException $e) {
            $this->logger->critical(
                sprintf("Erreur lors de la connexion à l'API OVH : %s . Trace : %s", $e->getMessage(), $e->getTraceAsString())
            );

            throw $e;
        }

        return $conn;
    }
}

 

On remarque l’utilisation de $this->log(). Celle-ci permet d’enregistrer l’historique des logs de toutes les informations qui se transmettront de l’API à votre projet et vice-versa. Ces logs serviront, par exemple, à surveiller les utilisateurs qui se désabonnent des SMS.

Pour ce petit plus, on rajoute un monolog spécifique à OVH dans app/config/config_dev.yml (pour vos tests).


monolog:
    handlers:
        ovh:
            type: rotating_file
            path: '%kernel.logs_dir%/%kernel.environment%/ovh-sms.log'
            level: debug
            max_files: 30
            channels: [ovh] 

Il ne vous restera plus qu’à utiliser vos nouvelles commandes :


bin/console app:sms:notifications -send=+33601020304

bin/console app:sms:notifications -list

bin/console app:sms:notifications -blacklist=+33601020304

Note importante : Vous aurez la contrainte de partager des urls complètes dans vos messages, puisque les liens “personnalisés” ne sont pas reconnus