Skip to content

Commit 0b0b414

Browse files
committed
The SMS Counter class
1 parent 5d5f912 commit 0b0b414

File tree

1 file changed

+291
-0
lines changed

1 file changed

+291
-0
lines changed

sms_counter.php

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
<?php
2+
3+
/**
4+
* The SMSCounter class
5+
* Inspired by the Javascript library https://github.com/danxexe/sms-counter
6+
* @author - acpmasquerade <acpamsquerade@gmail.com>
7+
* @date - 05th March, 2014
8+
*
9+
* License Information
10+
* -------------------------------------------------------------------------------
11+
* | Permission is hereby granted, free of charge, to any person obtaining a copy
12+
* | of this software and associated documentation files (the "Software"), to deal
13+
* | in the Software without restriction, including without limitation the rights
14+
* | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15+
* | copies of the Software, and to permit persons to whom the Software is
16+
* | furnished to do so, subject to the following conditions:
17+
* |
18+
* | The above copyright notice and this permission notice shall be included in
19+
* | all copies or substantial portions of the Software.
20+
* |
21+
* | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22+
* | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
* | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24+
* | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
* | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26+
* | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27+
* | THE SOFTWARE.
28+
* -------------------------------------------------------------------------------
29+
*/
30+
31+
class SMSCounter{
32+
33+
# character set for GSM 7 Bit charset
34+
# @deprecated
35+
const gsm_7bit_chars = "\$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";
36+
37+
# character set for GSM 7 Bit charset (each character takes two length)
38+
# @deprecated
39+
const gsm_7bitEx_chars = "\\^{}\\\\\\€[~\\]\\|";
40+
41+
const GSM_7BIT = 'GSM_7BIT';
42+
const GSM_7BIT_EX = 'GSM_7BIT_EX';
43+
const UTF16 = 'UTF16';
44+
45+
public static function int_gsm_7bit_map(){
46+
return array(10,32,33,34,35,36,37,38,39,40,41,42,44,45,46,47,48,49,50,
47+
51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,
48+
71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,
49+
92,95,97,98,99,100,101,102,103,104,105,106,107,108,109,110,
50+
111,112,113,114,115,116,117,118,119,120,121,122,
51+
161,163,164,165,191,196,197,198,199,201,209,214,
52+
216,220,223,224,228,229,230,232,233,236,241,242,
53+
246,248,249,252,915,916,920,923,926,928,931,934,
54+
936,937);
55+
}
56+
57+
public static function int_gsm_7bit_ex_map(){
58+
return array(91,92,93,94,123,124,125,126,8364);
59+
}
60+
61+
public static function int_gsm_7bit_combined_map(){
62+
return array_merge(self::int_gsm_7bit_map(), self::int_gsm_7bit_ex_map());
63+
}
64+
65+
# message length for GSM 7 Bit charset
66+
const messageLength_GSM_7BIT = 160;
67+
# message length for GSM 7 Bit charset with extended characters
68+
const messageLength_GSM_7BIT_EX = 160;
69+
# message length for UTF16 charset
70+
const messageLength_UTF16 = 70;
71+
72+
# message length for multipart message in GSM 7 Bit encoding
73+
const multiMessageLength_GSM_7BIT = 153;
74+
# message length for multipart message in GSM 7 Bit encoding with extended characters
75+
const multiMessageLength_GSM_7BIT_EX = 153;
76+
# message length for multipart message in UTF16 encoding
77+
const multiMessageLength_UTF16 = 67;
78+
79+
/**
80+
* function count($text)
81+
* Detects the encoding, Counts the characters, message length, remaining characters
82+
* @return - stdClass Object with params encoding,length,per_message,remaining,messages
83+
*/
84+
public static function count($text){
85+
86+
$unicode_array = self::utf8_to_unicode($text);
87+
88+
# variable to catch if any ex chars while encoding detection.
89+
$ex_chars = array();
90+
$encoding = self::detect_encoding($unicode_array, $ex_chars);
91+
92+
$length = count($unicode_array);
93+
94+
if ( $encoding === self::GSM_7BIT_EX){
95+
$length_exchars = count($ex_chars);
96+
# Each exchar in the GSM 7 Bit encoding takes one more space
97+
# Hence the length increases by one char for each of those Ex chars.
98+
$length += $length_exchars;
99+
}
100+
101+
# Select the per message length according to encoding and the message length
102+
switch($encoding){
103+
case self::GSM_7BIT:
104+
if ( $length > self::messageLength_GSM_7BIT){
105+
$per_message = self::multiMessageLength_GSM_7BIT;
106+
}else{
107+
$per_message = self::messageLength_GSM_7BIT;
108+
}
109+
break;
110+
111+
case self::GSM_7BIT_EX:
112+
if ( $length > self::messageLength_GSM_7BIT_EX){
113+
$per_message = self::multiMessageLength_GSM_7BIT_EX;
114+
}else{
115+
$per_message = self::messageLength_GSM_7BIT_EX;
116+
}
117+
break;
118+
119+
default:
120+
if($length > self::messageLength_UTF16){
121+
$per_message = self::multiMessageLength_UTF16;
122+
}else{
123+
$per_message = self::messageLength_UTF16;
124+
}
125+
break;
126+
}
127+
128+
$messages = ceil($length / $per_message);
129+
$remaining = ( $per_message * $messages ) - $length ;
130+
131+
$returnset = new stdClass();
132+
133+
$returnset->encoding = $encoding;
134+
$returnset->length = $length;
135+
$returnset->per_message = $per_message;
136+
$returnset->remaining = $remaining;
137+
$returnset->messages = $messages;
138+
139+
return $returnset;
140+
141+
}
142+
143+
/**
144+
* function detect_encoding($text)
145+
* Detects the encoding of a particular text
146+
* @return - one of GSM_7BIT, GSM_7BIT_EX, UTF16
147+
*/
148+
public static function detect_encoding ($text, & $ex_chars) {
149+
150+
if(!is_array($text)){
151+
$text = utf8_to_unicode($text);
152+
}
153+
154+
$utf16_chars = array_diff($text, self::int_gsm_7bit_combined_map());
155+
156+
if(count($utf16_chars)){
157+
return self::UTF16;
158+
}
159+
160+
$ex_chars = array_intersect($text, self::int_gsm_7bit_ex_map());
161+
162+
if(count($ex_chars)){
163+
return self::GSM_7BIT_EX;
164+
}else{
165+
return self::GSM_7BIT;
166+
}
167+
168+
}
169+
170+
/**
171+
* function utf8_to_unicode ($str)
172+
* Generates array of unicode points for the utf8 string
173+
* @return array
174+
*/
175+
public static function utf8_to_unicode( $str ) {
176+
177+
$unicode = array();
178+
$values = array();
179+
$looking_for = 1;
180+
181+
for ($i = 0; $i < strlen( $str ); $i++ ) {
182+
183+
$this_value = ord( $str[ $i ] );
184+
185+
if ( $this_value < 128 ) $unicode[] = $this_value;
186+
else {
187+
188+
if ( count( $values ) == 0 ) $looking_for = ( $this_value < 224 ) ? 2 : 3;
189+
190+
$values[] = $this_value;
191+
192+
if ( count( $values ) == $looking_for ) {
193+
194+
$number = ( $looking_for == 3 ) ?
195+
( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ):
196+
( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 );
197+
198+
$unicode[] = $number;
199+
$values = array();
200+
$looking_for = 1;
201+
202+
} # if
203+
204+
} # if
205+
206+
} # for
207+
208+
return $unicode;
209+
210+
} # utf8_to_unicode
211+
212+
/**
213+
* unicode equivalent chr() function
214+
* @return character
215+
*/
216+
public static function utf8_chr($unicode){
217+
$unicode=intval($unicode);
218+
219+
if($unicode<128){
220+
$utf8char=chr($unicode);
221+
}
222+
else if ($unicode >= 128 && $unicode < 2048){
223+
$utf8char = chr(192 | ($unicode >> 6)) . chr(128 | ($unicode & 0x3F));
224+
}
225+
else if ($unicode >= 2048 && $unicode < 65536){
226+
$utf8char = chr(224 | ($unicode >> 12)) . chr(128 | (($unicode >> 6) & 0x3F)) . chr(128 | ($unicode & 0x3F));
227+
}
228+
else{
229+
$utf8char = chr(240 | ($unicode >> 18)) . chr(128 | (($unicode >> 12) & 0x3F)) . chr(128 | (($unicode >> 6) & 0x3F)) . chr(128 | ($unicode & 0x3F));
230+
}
231+
232+
return $utf8char;
233+
}
234+
235+
public static function unicode_to_utf8($array){
236+
$str = '';
237+
foreach($array as $a){
238+
$str .= self::utf8_chr($a);
239+
}
240+
241+
return $str;
242+
}
243+
244+
/**
245+
* Removes non GSM characters from a string
246+
* @return string
247+
*/
248+
public static function remove_non_gsm_chars( $str ){
249+
# replace non gsm chars with a null character
250+
return self::replace_non_gsm_chars($str, null);
251+
}
252+
253+
/**
254+
* Replaces non GSM characters from a string
255+
* @param $str - string to be replaced
256+
* @param $replacement - character to be replaced with
257+
* @return string
258+
* @return false, if replacement string is more than 1 character in length
259+
*/
260+
public static function replace_non_gsm_chars( $str , $replacement = null){
261+
262+
$valid_chars = self::int_gsm_7bit_combined_map();
263+
264+
$all_chars = self::utf8_to_unicode($str);
265+
266+
if(strlen($replacement) > 1){
267+
return FALSE;
268+
}
269+
270+
$replacement_array = array();
271+
$replacement_unicode = array_pop(self::utf8_to_unicode($replacement));
272+
273+
foreach($all_chars as $some_position=>$some_char){
274+
if(!in_array($some_char, $valid_chars)){
275+
$replacement_array[] = $some_position;
276+
}
277+
}
278+
279+
if($replacement){
280+
foreach($replacement_array as $some_position){
281+
$all_chars[$some_position] = $replacement_unicode;
282+
}
283+
}else{
284+
foreach($replacement_array as $some_position){
285+
unset($all_chars[$some_position]);
286+
}
287+
}
288+
289+
return self::unicode_to_utf8($all_chars);
290+
}
291+
}

0 commit comments

Comments
 (0)