SMS Modülü Yazma

1.6k görüntülenme Markdown

SMS modülü, metin mesajını bir geçide teslim eden sürücüdür. Mail'den farklı olarak üç iş yapar: bildirim, uluslararası gönderim ve bazen fiyat ile teslim raporlaması.

Genel Bakış

Taban sınıf yoktur. Sözleşme Mail gibi ördek tiplemesine dayanır: çekirdek, dizin adını taşıyan sınıfı yükler ve bilinen metotları çağırır.

İki config anahtarı sürücü gösterir: modules/sms bildirimler, modules/sms-intl uluslararası trafik için. Yurt içi geçit yabancı numaraları ikincisine devreder, bu yüzden iki kova tutulur.

Üçüncü yol modülündür: controllers/ dosyalarınız sürücüyü kaydedilmemiş kimlik bilgileriyle kurabilir.

Ön Koşullar

  • coremio/modules/SMS/ altına yazma erişimi.
  • Geçit kimlik bilgileri ve genelde kayıtlı bir gönderici kimliği.
  • Geçidiniz yurt içi mi, uluslararası mı? Yetenek işaretlerini bu belirler.
  • Mail Modülü Yazma.

Yapı

Dizin, dosya ve sınıf adı aynı dizedir, ad alanı yoktur.

düzen
coremio/modules/SMS/Acme/
├── Acme.php          sürücü sınıfı, adı Acme, ad alanı yok
├── config.php        künye (uluslararası bayrağıyla) + kaydedilmiş kimlik bilgileri
├── Source/class.php  isteğe bağlı geçit istemcisi, kurucu tarafından dahil edilir
├── lang/en.php
├── lang/tr.php
└── logo.png          isteğe bağlı, config meta.logo ile gösterilir

Adım Adım

Sürücü Sınıfını Kurma

  1. coremio/modules/SMS/Acme/Acme.php dosyasını açıp class Acme tanımlayın.
  2. Yetenek işaretlerini public özellik olarak bildirin.
  3. Yapıcıda kayıtlı config'i verilen diziyle birleştirin; verilen üstün gelir.
  4. body(), title(), AddNumber() metotlarını her biri $this döndürecek şekilde uygulayın.
  5. submit() uygulayın: yurt içi kovayı gönderin, ötekini devredin.
  6. getTitle(), getBody(), getNumbers(), getError() uygulayın.

Gönderici Kimliği ve Numaralar

  1. Göndericiyi yapıcıda config'ten doldurun.
  2. AddNumber() üç biçimi kabul etmeli: numara, ülke kodlu numara, dizi.
  3. Dikey çizgi taşıyan değer ülkeKodu|numara demektir.
  4. Devir yasaklanmadıysa sonucu ülke koduna göre kovaya yönlendirin.
  5. Her iki kovayı da body() içinde sıfırlayın.

Ayarlar ve Raporlar

  1. Gizli alanlar, etkinleştirme kutusu ve kimlik alanlarıyla page_settings() ekleyin.
  2. controller_save() ekleyin: değişenleri config.php içine yazın, modules/sms çevirin.
  3. Kredi bakiyesi için getBalance(); çekirdek çağırmaz.
  4. Toplu gönderim kimliği için getReportID() ve getReport() uygulayın.
  5. get_prices() yalnız uluslararası geçitler içindir.

Referans

Çekirdek Neyi Çağırır

Dağıtıcı mesajı kurar, sonra alıcıları gezer.

MetotÇekirdek ne zaman çağırırNe döndürmeli
__construct($external_config = [])Gönderim başına bir kezhiçbir şey
body($text, $template, $variables, $lang, $user)İlk sırada; kovaları sıfırlar$this
use_otp()Tek kullanımlık kod şablonlarında, body()'den sonra. Sunulduğunda.$this
title($arg)Gönderici kimliği değiştirilirse$this
AddNumber($arg, $cc)Alıcı başına, ya da bir diziyle$this
submit($isthis = false)Alıcılar girildikten sonrabaşarıda doğru değer, hatada false
getTitle()Başarılı gönderimden sonradize
getBody()Başarılı gönderimden sonradize
getNumbers()Başarılı gönderimden sonraiki kova, tek dizi
getError()Yanlış değer dönen gönderimden sonrahata metni
numbers_reset()Kendi body() metodunuzokunmaz
getReportID(), getReport($id), get_prices()Sunulduğundaaşağıya bakın
getBalance()Çekirdek çağırmazkendi biçiminiz

Harf durumuna dikkat: dağıtıcı addNumber(), sürücüler AddNumber() yazar. PHP ikisini de aynı metoda çözer.

Metot İmzaları

imzalar
public function __construct($external_config = []);

// HER İKİ alıcı kovasını sıfırlar, sonra şablon verildiyse onu işler.
// $template "group/name" biçimindedir, örn. "user/gsm-activation"; false ise $text nihaidir.
public function body($text = '', $template = false, $variables = [], $lang = '', $user = 0);

// Cihazda görünen gönderici kimliği / originator.
public function title($arg = '');

// SIRA TUZAĞI: ÖNCE numara, SONRA ülke kodu gelir.
// $arg şunları kabul eder: "5551234567", "90|5551234567", ya da ikisinden birinin dizisi.
// $cc yalnız $arg bir dizi değilken dikkate alınır.
public function AddNumber($arg = 0, $cc = null);

// $isthis = true boolean yerine sürücüyü döndürür.
public function submit($isthis = false);

public function getTitle();
public function getBody();
public function getNumbers();
public function getError();
public function numbers_reset();

// İsteğe bağlı, özellik özellik. Çekirdek her birini çağırmadan önce method_exists() ile yoklar.
public function getReportID();                // son gönderimin ürettiği toplu gönderim kimliği
public function getReport($id = 0);           // bir toplu gönderim için teslim raporu
public function get_prices();                 // uluslararası fiyat listesi, aşağıya bakın
public function use_otp(bool $on = true);     // sağlayıcının OTP rotası; $this döndürür

// Modüle özgü konvansiyon: çekirdek bunu hiç çağırmaz. Yalnız kendi
// controllers/*.php ve pages/*.php dosyalarınızdan ulaşılır, yani argüman listesi sizindir.
public function getBalance();                 // kalan kredi, ya da $error dolu olarak false

İki dönüş biçimi ada göre okunur:

dönüş biçimleri
// getReport(): üç adlandırılmış kova, her biri ham satırlar ve bir sayaç taşır.
// Rapor okuyucu ayrıca 'delivered' / 'sending' / 'failed' adlarını takma ad olarak kabul eder.
return [
    'waiting'   => ['data' => $waitingRows,   'count' => count($waitingRows)],
    'conducted' => ['data' => $deliveredRows, 'count' => count($deliveredRows)],
    'erroneous' => ['data' => $failedRows,    'count' => count($failedRows)],
];

// get_prices(): ülke kodu => para birimi kodu => mesaj başına maliyet.
// Config'in supported-currencies anahtarı birini belirtmedikçe kullanılabilir ilk para birimi kazanır.
return [
    'TR' => ['EUR' => 0.0180],
    'DE' => ['EUR' => 0.0640, 'USD' => 0.0700],
    'US' => ['USD' => 0.0075],
];

get_prices() maliyetleri birincil para birimine çevrilir, sms/profit-rate marjı eklenir ve ülke haritası yeniden yazılır.

Yetenek İşaretleri

Bunlar metot değil public özelliktir. Çekirdek onları hem örnekte hem config'te okur, ikisi uyuşmalıdır.

$international Geçit ülke dışına teslim edebiliyorsa true.
$prevent_transmission_to_intl Yabancı numaraları yurt içi kovada tutar; iki metotta da buna uyun.
$otp Tek kullanımlık kod gönderimini işaretler. body() sıfırlar, çekirdek use_otp() ile açar; submit() rotayı buna göre seçer.
$error getError() olmasına rağmen doğrudan okunur.
meta.international Aynı cevabın config.php hâli; seçici buna bakar. Özellik ile meta uyuşmalıdır.

Config Anahtarları

meta.name Görünen ad; dil dosyasındaki name anahtarı üstün gelir.
meta.poweredby Geçit markası.
origin Kayıtlı gönderici kimliği; title() bundan doldurulur.
supported-currencies get_prices() birkaç para birimi sunarsa tercih listesi. Boşsa ilki alınır.
Crypt::encode() Şifreli saklanır: Crypt::encode($v, Config::get("crypt/user")) ile yazın, Crypt::decode() ile okuyun.

Hangi Sürücü Çalışır

Üçüncü çözümlemeyi yanlış yapmak, müşterinin hesabı yerine operatörün geçit hesabıyla gönderir.

YolÖrnek nasıl kurulurKullanılan kimlik bilgileri
BildirimlerAdsız Modules::Load("SMS"), sonra new $smsModule()kayıtlı config
Uluslararası gönderimModules::getInstance("SMS", Config::get("modules/sms-intl"))kayıtlı config
Modülün kendi sayfalarınew Modulunuz($external)formdan gelen değerler, kayıtlı config üzerine

Yapıcının $external_config taşıma sebebi budur; çekirdek onu geçmez. Fabrikanın üçüncü argümanı yapıcı için konumsal argüman listesidir.

Örnek

Kendi ülkesini kapsayan ve yabancı numaraları devreden bir geçit.

"Kendi ülke kodu" geçidinizin hizmet verdiği ülkedir; config'inizden okunur. Karşılaştırmadan önce baştaki + işaretini temizleyin ve operatöre dikkat edin: != ile '90' ve '+90' eşit sayılır, !== ile sayılmaz.

Acme.php
<?php
defined('CORE_FOLDER') OR exit('You can not get in here!');

class Acme
{
    public $international = false;
    public $prevent_transmission_to_intl = false;
    public $otp = false;
    public $error = null;
    public $lang = [];
    public $config = [];

    private $title = '';
    private $body = '';
    private $numbers = [];
    private $numbers_intl = [];

    public function __construct($external_config = [])
    {
        $this->lang   = Modules::Lang('SMS', __CLASS__);
        $this->config = array_merge(Modules::Config('SMS', __CLASS__) ?: [], $external_config);
        $this->title  = (string) ($this->config['origin'] ?? '');
    }

    public function title($arg = '')
    {
        $this->title = (string) $arg;
        return $this;
    }

    public function body($text = '', $template = false, $variables = [], $lang = '', $user = 0)
    {
        // Dağıtıcı alıcı başına tek örneği yeniden kullanır; bu olmadan kovalar büyür.
        $this->numbers_reset();

        if ($template) {
            $look = View::notifications('sms', $template, $text, $variables, $lang, $user);
            if ($look !== false && isset($look['content'])) {
                if (isset($look['title'])) $this->title($look['title']);
                $text = $look['content'];
            }
        }

        $this->body = (string) $text;
        return $this;
    }

    public function use_otp(bool $on = true)
    {
        // Çekirdek bunu kod şablonlarında body()'den sonra çağırır; son sözü modülün kendi ayarı verir.
        $this->otp = $on && (bool) ($this->config['otp'] ?? false);
        return $this;
    }

    public function AddNumber($arg = 0, $cc = null)
    {
        if (!is_array($arg)) $arg = $cc ? [$cc . '|' . $arg] : [$arg];

        foreach ($arg as $num) {
            if (!str_contains((string) $num, '|')) {
                $this->numbers[] = Filter::numbers((string) $num);
                continue;
            }

            // Geçidin kendi ülkesi, config'inden okunur — asla sabit yazılmaz.
            $home = ltrim((string) ($this->config['home_cc'] ?? ''), '+');

            [$ccPart, $numPart] = explode('|', (string) $num, 2);
            $ccPart = ltrim($ccPart, '+') ?: $home;
            $full   = $ccPart . Filter::numbers($numPart);

            if (!$this->prevent_transmission_to_intl && $home !== '' && $ccPart !== $home) $this->numbers_intl[] = $full;
            else $this->numbers[] = $full;
        }

        return $this;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function getBody()
    {
        return $this->body;
    }

    public function getNumbers()
    {
        return array_merge($this->numbers, $this->numbers_intl);
    }

    public function getError()
    {
        return $this->error;
    }

    public function numbers_reset()
    {
        $this->otp          = false;
        $this->numbers      = [];
        $this->numbers_intl = [];
        return true;
    }

    public function submit($isthis = false)
    {
        if (Validation::isEmpty($this->body)) {
            $this->error = 'Message content can not be left blank!';
            return false;
        }

        if (!$this->numbers && !$this->numbers_intl) {
            $this->error = 'Enter the phone number to be sent.';
            return false;
        }

        $send = false;

        // Yabancı numaralar modules/sms-intl anahtarını hangi sürücü tutuyorsa ona gider.
        if (!$this->prevent_transmission_to_intl && $this->numbers_intl) {
            $intl = (string) Config::get("modules/sms-intl");
            if ($intl !== '' && $intl !== 'none') {
                $peer = Modules::getInstance('SMS', $intl);
                if ($peer) {
                    $send = $peer->body($this->getBody())->AddNumber($this->numbers_intl)->submit();

                    // Yurt içi numara kalmadı, yani karşı sürücünün sonucu sonucun tamamıdır.
                    if (!$this->numbers) {
                        $this->error = $peer->getError();
                        return $isthis ? $this : $send;
                    }
                }
            }
        }

        if ($this->numbers) {
            $response = Utility::HttpRequest([
                'url'  => 'https://api.example.com/sms/send',
                'type' => 'POST',
                'data' => [
                    'user'    => $this->config['username'] ?? '',
                    'pass'    => Crypt::decode($this->config['password'] ?? '', Config::get("crypt/user")),
                    'header'  => $this->title,
                    'message' => $this->body,
                    'to'      => implode(',', $this->numbers),
                    'otp'     => $this->otp ? 1 : 0,
                ],
            ]);

            $decoded = Utility::jdecode((string) $response, true) ?: [];
            $send    = (string) ($decoded['code'] ?? '') === '00';

            // Dağıtıcı yanlış değer dönüşünden sonra hatayı okur; fırlatmaları yakalamaz.
            if (!$send) $this->error = $decoded['message'] ?? 'Acme refused the batch.';
        }

        return $isthis ? $this : $send;
    }
}
coremio/helpers/notification.php
Modules::Load("SMS");
$smsModule = Config::get("modules/sms");
$sms = $smsModule && $smsModule !== 'none' ? new $smsModule() : false;

// $phone "number|countryCode|lang" olarak gelir, yani parçalar konuma göre açılır.
foreach ($adminContacts['phones'] as $phone) {
    $parse   = explode("|", (string) $phone);
    $aLang   = $parse[2] ?? $localLang;
    $sendSms = $sms->body($body, $templatePath, $variables, $aLang);

    if (isset($parse[1])) $sendSms->addNumber($parse[0], $parse[1]);
    else $sendSms->addNumber($parse[0]);

    $sendSms = $sendSms->submit();

    if ($sendSms) LogManager::Sms_Log(0, $reason, $sms->getTitle(), $sms->getBody(), implode(",", $sms->getNumbers()));
    else $errors['sms'][$phone] = $sms->getError();
}

Tuzaklar

AddNumber: önce numara, sonra ülke kodu

Birleşik biçim bunun tersidir, ülkeKodu|numara; kayıtlı kişi numara|ülkeKodu|dil olarak açılır. Yer değiştirmek makul görünen ama düşen bir numara üretir.

body() kovaları sıfırlamalıdır

Mail alıcıları subject() içinde sıfırlar; SMS body() içinde. Sıfırlama olmazsa ikinci alıcı, içinde birinci alıcı da olan bir gönderim alır.

İşaret, para hareket etmeden önce kontrol edilir

Müşteri paneli gönderimi fiyatlar, sürücünün $international özelliği true değilse reddeder, sonra bakiyeden düşer. Desteği yalnız config.php içinde iddia eden sürücü düşer.

submit() hatayı false döndürerek bildirir

Bildirim döngüsü try/catch içinde değildir ve yanlış değer dönen çağrıdan sonra getError() okur. Ayar controller'larınız fırlatabilir.

OTP işaretini şablon adından açmayın

Bildirim dağıtıcısı body()'yi şablon adı vermeden çağırır, yani şablon adına bakan bir koşul hiç çalışmaz. Kod şablonunu çekirdek seçer ve use_otp() çağırır; sürücü yalnız kendi ayarını birleştirir.

Kum havuzu sürücüsüyle test edin

SampleSMS her şeyi kabul eder ve her mesajı temp/sample-sms/ altına metin dosyası olarak yazar.

Faydalı oldu mu?

Geri bildiriminiz için teşekkürler!

Hâlâ Yardıma mı İhtiyacınız Var?

Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.