Лучший способ обнаружить количество SMS, необходимое для отправки текста

StackOverflow https://stackoverflow.com/questions/8349831

Вопрос

Я ищу код/LIB в PHP, который я назову и передам ему текст, и он скажет мне:

  1. Какой код мне нужно использовать, чтобы отправить этот текст в виде SMS (7,8,16 бит)
  2. Сколько сообщений SMS я буду использовать для отправки этого текста (должно быть умно считать «информацию о сегменте», как в http://ozekisms.com/index.php?owpn=612)

Есть ли у вас есть представление о каком -либо кодексе/LIB, которое сделает это для меня?

Опять я не ищу отправки SMS или конвертации SMS, просто чтобы дать мне информацию о тексте

Обновлять:

Хорошо, я сделал приведенный ниже код, и он, кажется, работает нормально, дайте мне знать, если у вас есть лучший/оптимизированный код/решение/lib

$text = '\@£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ -./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà^{}[~]|€' ; //"\\". //'"';//' ';

print $text . "\n";
print isGsm7bit($text). "\n";
print getNumberOfSMSsegments($text). "\n";




function getNumberOfSMSsegments($text,$MaxSegments=6){
/*
http://en.wikipedia.org/wiki/SMS

Larger content (concatenated SMS, multipart or segmented SMS, or "long SMS") can be sent using multiple messages, 
in which case each message will start with a user data header (UDH) containing segmentation information. 
Since UDH is part of the payload, the number of available characters per segment is lower: 
153 for 7-bit encoding, 
134 for 8-bit encoding and 
67 for 16-bit encoding. 
The receiving handset is then responsible for reassembling the message and presenting it to the user as one long message. 
While the standard theoretically permits up to 255 segments,[35] 6 to 8 segment messages are the practical maximum, 
and long messages are often billed as equivalent to multiple SMS messages. See concatenated SMS for more information. 
Some providers have offered length-oriented pricing schemes for messages, however, the phenomenon is disappearing.
*/
$TotalSegment=0;
$textlen = mb_strlen($text);
if($textlen==0) return false; //I can see most mobile devices will not allow you to send empty sms, with this check we make sure we don't allow empty SMS

if(isGsm7bit($text)){ //7-bit
    $SingleMax=160;
    $ConcatMax=153;
}else{ //UCS-2 Encoding (16-bit)
    $SingleMax=70;
    $ConcatMax=67;
}

if($textlen<=$SingleMax){
    $TotalSegment = 1;
}else{
    $TotalSegment = ceil($textlen/$ConcatMax);
}

if($TotalSegment>$MaxSegments) return false; //SMS is very big.
return $TotalSegment;
}

function isGsm7bit($text){
$gsm7bitChars = "\\\@£\$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà^{}[~]|€";
$textlen = mb_strlen($text);
for ($i = 0;$i < $textlen; $i++){
    if ((strpos($gsm7bitChars, $text[$i])==false) && ($text[$i]!="\\")){return false;} //strpos not able to detect \ in string
}
return true;
}
Это было полезно?

Решение 2

Лучшее решение, которое у меня есть до сих пор:

$text = '\@£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ -./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà^{}[~]|€' ; //"\\". //'"';//' ';

print $text . "\n";
print isGsm7bit($text). "\n";
print getNumberOfSMSsegments($text). "\n";

function getNumberOfSMSsegments($text,$MaxSegments=6){
/*
http://en.wikipedia.org/wiki/SMS

Larger content (concatenated SMS, multipart or segmented SMS, or "long SMS") can be sent using multiple messages, 
in which case each message will start with a user data header (UDH) containing segmentation information. 
Since UDH is part of the payload, the number of available characters per segment is lower: 
153 for 7-bit encoding, 
134 for 8-bit encoding and 
67 for 16-bit encoding. 
The receiving handset is then responsible for reassembling the message and presenting it to the user as one long message. 
While the standard theoretically permits up to 255 segments,[35] 6 to 8 segment messages are the practical maximum, 
and long messages are often billed as equivalent to multiple SMS messages. See concatenated SMS for more information. 
Some providers have offered length-oriented pricing schemes for messages, however, the phenomenon is disappearing.
*/
$TotalSegment=0;
$textlen = mb_strlen($text);
if($textlen==0) return false; //I can see most mobile devices will not allow you to send empty sms, with this check we make sure we don't allow empty SMS

if(isGsm7bit($text)){ //7-bit
    $SingleMax=160;
    $ConcatMax=153;
}else{ //UCS-2 Encoding (16-bit)
    $SingleMax=70;
    $ConcatMax=67;
}

if($textlen<=$SingleMax){
    $TotalSegment = 1;
}else{
    $TotalSegment = ceil($textlen/$ConcatMax);
}

if($TotalSegment>$MaxSegments) return false; //SMS is very big.
return $TotalSegment;
}

function isGsm7bit($text){
$gsm7bitChars = "\\\@£\$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà^{}[~]|€";
$textlen = mb_strlen($text);
for ($i = 0;$i < $textlen; $i++){
    if ((strpos($gsm7bitChars, $text[$i])==false) && ($text[$i]!="\\")){return false;} //strpos not     able to detect \ in string
}
return true;
}

Другие советы

Я добавляю здесь дополнительную информацию, потому что предыдущий ответ не совсем верен.

Это проблемы:

  • Ты необходимость Чтобы указать текущую строку, кодирующуюся в MB_STRING, в противном случае это может быть неправильно собрано
  • В 7-битном кодировании GSM основные расширенные символы Charset (^{} [~] | €) требуют 14-битных для кодирования, поэтому они считаются по двум символам в каждом.
  • В кодировании UCS-2 вы должны быть осторожны с эмодзи и другими персонажами за пределами 16-битного BMP, потому что ...
  • GSM с UCS-2 подсчитывает 16-битные символы, поэтому, если у вас есть 💩 символ (U+1F4A9), а ваш перевозчик и телефон мягко поддерживают UTF-16, а не только UCS-2, он будет закодирован как суррогатная пара 16-битные символы в UTF-16 и, таким образом, считаются двумя 16-битными символами к длине вашей строки. mb_strlen Считает это только единственным персонажем.

Как считать 7-битные символы:

Что я придумал до сих пор, так это следующее, чтобы считать 7-битные символы:

// Internal encoding must be set to UTF-8,
// and the input string must be UTF-8 encoded for this to work correctly
protected function count_gsm_string($str)
{
    // Basic GSM character set (one 7-bit encoded char each)
    $gsm_7bit_basic = "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";

    // Extended set (requires escape code before character thus 2x7-bit encodings per)
    $gsm_7bit_extended = "^{}\\[~]|€";

    $len = 0;

    for($i = 0; $i < mb_strlen($str); $i++) {
        if(mb_strpos($gsm_7bit_basic, $str[$i]) !== FALSE) {
            $len++;
        } else if(mb_strpos($gsm_7bit_extended, $str[$i]) !== FALSE) {
            $len += 2;
        } else {
            return -1; // cannot be encoded as GSM, immediately return -1
        }
    }

    return $len;
}

Как считать 16-битные символы:

  • Преобразовать строку в представление UTF-16 (для сохранения символов эмодзи с помощью mb_convert_encoding($str, 'UTF-16', 'UTF-8').
    • не надо преобразовать в UCS-2, так как это потеря с mb_convert_encoding)
  • Считайте байты с count(unpack('C*', $utf16str)) и разделите на два, чтобы получить количество 16-битных символов UCS-2, которые учитываются по отношению к длине GSM Multipart

*Emptor предостерегает, слово о подсчете байтов:

  • Не надо использовать strlen Подсчитать количество байтов. Пока это может работать, strlen Часто перегружен в установки PHP с помощью версии, способствующей мультибит, а также является кандидатом на изменение API в будущем
  • Избегать mb_strlen($str, 'UCS-2'). Анкет Пока это происходит В данный момент Работа и вернется, правильно, 2 для кучи символа Poo (так как это выглядит как два 16-битных символа UCS-2), его конюшня. mb_convert_encoding Потеря при преобразовании из> 16-битного в UCS-2. Кто скажет, что в будущем MB_STRLEN не будет потерям?
  • Избегать mb_strlen($str, '8bit') / 2. Анкет Это также В данный момент Работает и рекомендуется в комментарии PHP Docs как способ считать байты. Но IMO он страдает от той же проблемы, что и вышеупомянутая техника UCS-2.
  • Это оставляет самый безопасный ток (IMO) в качестве unpackв массив байтов и подсчитывая это.

Итак, как это выглядит?

// Internal encoding must be set to UTF-8,
// and the input string must be UTF-8 encoded for this to work correctly
protected function count_ucs2_string($str)
{
    $utf16str = mb_convert_encoding($str, 'UTF-16', 'UTF-8');
    // C* option gives an unsigned 16-bit integer representation of each byte
    // which option you choose doesn't actually matter as long as you get one value per byte
    $byteArray = unpack('C*', $utf16str);
    return count($byteArray) / 2;
}

Соберите все вместе:

function multipart_count($str)
{
    $one_part_limit = 160; // use a constant i.e. GSM::SMS_SINGLE_7BIT
    $multi_limit = 153; // again, use a constant
    $max_parts = 3; // ... constant

    $str_length = count_gsm_string($str);
    if($str_length === -1) {
        $one_part_limit = 70; // ... constant
        $multi_limit = 67; // ... constant
        $str_length = count_ucs2_string($str);
    }

    if($str_length <= $one_part_limit) {
        // fits in one part
        return 1;
    } else if($str_length > ($max_parts * $multi_limit) {
        // too long
        return -1; // or throw exception, or false, etc.
    } else {
        // divide the string length by multi_limit and round up to get number of parts
        return ceil($str_length / $multi_limit);
    }
}

Превратил это в библиотеку ...

https://bitbucket.org/solvam/smstools

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top