msn和飞信报警用了两三个月了,总结如下:想收到报警消息,139的邮箱是肯定能收到的,有邮件必发短信,但是中间肯定会消耗一些时间;飞信次之十次会有九次收到吧,当然了还是比较稳定的,也比139的短信早到;msn的话,感觉并不是每次都能收到,难道是不在线的时候发了信息上线以后就没有留言?但是有个缺点就是,这三个报警都是依赖别人的服务器,如果人家碰巧出问题了,咱也跟着吃亏?思来想去,觉得最靠谱的还是有自己的短信发送设备.
正好手上有个gsm的modem.因为最近正迷php,所以不打算用其它的二次开发包之类的东西了.说干就干,晚上一回到家就开始找资料.这一查不要紧,你还别说,还真有用php干这事儿的.但是网上传来传去的都是那一篇<<通过串口+GSM MODEM发送短信示例>>.这个示例是windows平台下的,还用到了一个dll文件.我现在家里用的系统也换成ubuntu了,再说以后报警的服务器也是linux,总不能为了发个短信再专门换成windows系统吧.于是决定自己动手,用php的函数写linux下的程序,由此埋下了祸根.
功夫不负有心人啊,很快在国外的一个网站找到了一个php操作串口的类:php_serial.class.于是开始动手用minicom调试modem.因为在以前单位的时候,帮别人用超级终端调试过modem,所以命令还记得一些,很快,用at指令通过minicom发送短信成功(还好俺有两个手机,要不做个实验都没法做).ok,改用php操作modem,用at指令发英文短信,成功!good.没想到这么顺利.取得了点小胜利的我不满足只发送英文短信,于是开始尝试发送中文短信.但是直接通过at指令输入中文,modem不买帐.收到的是空白短信.这可如何是好?于是开始细细研究网上那篇<<通过串口+GSM MODEM发送短信示例>>,于是知道了,想发送中文短信就得用pdu格式,于是又开始研究pdu格式怎么回事儿(你说这就是多干的话,能发英文就行了呗,还求那么完美干啥).一直到睡觉的点,也没从我的modem里发出中文来.不行,先睡觉.
一觉醒来,又细细看了一遍pdu的格式,并一遍一遍的细细学习<<通过串口+GSM MODEM发送短信示例>>的生成方法.经过一遍一遍的尝试终于可以收到一些乱码的中文了,又经过尝试终于收到了和发送字数相同的小方块的短信了.没办法到上班的点了,于是赶紧到单位.间隙的时候,问以前单位负责开始短信群发软件的同事小杨怎么用pdu格式发送短信.小杨告诉了我,要用到的at指令,以及pdu格式的生成方法,虽然没有帮我解决问题但是至少肯定了:1,我的操作方法是对的,因为可以成功收到短信;2,收到字数相等的方块,应该是编码的时候没处理好.晚上回到家又一遍一遍的看之前那篇文章,很不理解,为啥用同样的函数生成的字符串,最后的差距咋就那么大呢?边尝试边找资料,不经意间在网上我发现一篇文章说发送短信”晚上好123″的编码是:”665A4E0A597D003100320033″.我把这个串直接放到我程序里,一发送,嘿,你猜怎么着?还真收到了”晚上好123″.有点意思!于是,我也用我的函数生成”晚上好123″,结果我发现了一个规律!
对的:665A4E0A597D003100320033
我的:5A660A4E7D59310032003300
每四个字符里两两错位!!!发现这个规律以后,就简单了,因为这样就确定确实是编码那块的原因了.但是编码那块:iconv,ord,substr,sprintf好几个系统函数,一个一个熟悉,改来改去都不行,这时候已经晚上十一点半了(我习惯是十点半睡,七八点起,标准的小学生作息时间).但是离终点这么近了,真不甘心放弃!初中时候养成的好习惯,今日事,今日毕,因为明天还有明天的事!洗把脸,重新整理一下思路:虽然大体看明白了pdu格式,但是字符串转换这块,我还真理解不透.怎么办呢?看来从根上解决这个问题,我功力是不够了.往前不行,咱可以迂回嘛.那我就自己写一个函数把这个字符串的顺序变回来!你还真别说,这招好使!而且再发其它的中文短信,也可以正常收到啦!!!呵呵,看来今晚注定好梦了.
虽然凑合能用了,但是还不知道是什么原因啊.自己搞不定不要紧,公司里我周围坐着的可全是php高手.午休的时候,把会军叫过来,说明事情的来来回回,会军看了一遍代码以后,断定是字符的高低字节问题!因为linux系统和windows系统,对unicode处理的时候,正好是高低位相反的!说实话,当时真惊呆了,我咋就没考虑到是操作系统问题呢!知道了问题的原因以后,我和会军开始分别想从源头解决这个问题.但是半个小时过去了,发现要实现这个太难了,于是我提议放弃,就用我写的这个函数凑合着用.但是还是会军老道.虽然放弃了这步,但是最终还是通过修改转码那块的顺序搞定了这个问题!!!
通过这次的编码训练又使我学习了很多东西,关于php,关于解决问题的思路.因为用了开源的php类,也参考了网上其它的同类文章,本着开源精神,现将全部代码整理如下:
<?php
/*-
* 版权没有,欢迎拷贝 (x) .
* 作者: Jacky
*
* $Id: RS232.php,v 0.1 2011-7-29 05:28 PM Exp $
*
* 运行环境:Windows XP,PHP 5.2 (cli),MySQL5.0
* php.ini
* extension=php_mysql.dll
* extension=php_dio.dll
* 硬件要求: PM818A GSM/GPRS MODEM或其他任何GSM MODEM模块
* 相关知识:GSM AT指令集和PDU格式,去google吧
*
* mysql> use smsc;
* mysql> desc sm_submit;
* +———-+———————-+——+—–+———+—————-+
* | Field | Type | Null | Key | Default | Extra |
* +———-+———————-+——+—–+———+—————-+
* | smid | int(11) unsigned | | PRI | NULL | auto_increment |
* | OrgAddr | varchar(11) | YES | | NULL | |
* | DestAddr | varchar(11) | | PRI | | |
* | Time | datetime | YES | | NULL | |
* | USERDATA | mediumtext | YES | | NULL | |
* | stat | smallint(3) unsigned | YES | MUL | NULL | |
* +———-+———————-+——+—–+———+—————-+
*
*/
function gb2unicode($str) {
return iconv(“gb2312”, “UCS-2″, $str);
}
function hex2str($hexstring) {
$str = ”;
for($i=0; $i<strlen($hexstring); $i++){
$str .= sprintf(“%02X”,ord(substr($hexstring,$i,1)));
}
return $str;
}
function InvertNumbers($msisdn) {
$len = strlen($msisdn);
if ( 0 != fmod($len, 2) ) {
$msisdn .= “F”;
$len = $len + 1;
}
for ($i=0; $i<$len; $i+=2) {
$t = $msisdn[$i];
$msisdn[$i] = $msisdn[$i+1];
$msisdn[$i+1] = $t;
}
return $msisdn;
}
/*—————主程序开始—————*/
set_time_limit(0);
$DEBUG = 0;
exec(‘mode COM1: baud=115200 data=8 stop=1 parity=n xon=on’);
$fd = dio_open(‘COM1:’, O_RDWR);
if(!$fd)
{
die(“打开串口COM1失败”);
}
$ff = dio_stat($fd);
print_r($ff);
echo “GSMAT is start on COM1/n”;
// 短信中心号码
$smsc = “8613800538500”;
// 短信最大长度70个汉字,Unicode表示需要280个字节
$max_len = 280;
$invert_smsc = InvertNumbers($smsc);
$sql = mysql_connect(“localhost”, “pangty”, “pangty”);
mysql_select_db(“smsc”,$sql);
$query = “select * from sm_submit where stat=0”;
$result = mysql_query($query, $sql);
$len = 1; $s = chr(13);
while ( $row = mysql_fetch_object($result) ) {
$msisdn = “86”. $row->DestAddr;
$sms_text = $row->USERDATA;if ($DEBUG) echo date(“Y-m-d H:i:s”).” DEBUG $row->DestAddr/n”;
if ($DEBUG) echo date(“Y-m-d H:i:s”).” DEBUG $sms_text/n”;$pdu_text = hex2str(gb2unicode($sms_text));
$invert_msisdn = InvertNumbers($msisdn);// 拆分发送超过70汉字的短信(todo: 没有判断全英文的情况)
do {
$pdu_len = strlen($pdu_text);
if ( $pdu_len > $max_len ) {
$pdu_text1 = substr($pdu_text, 0, $max_len);
$pdu_text = substr($pdu_text, $max_len, $pdu_len – $max_len);
} else {
$pdu_text1 = $pdu_text;
$pdu_text = “”;
}$pdu_len1 = sprintf(“%02X”, strlen($pdu_text1)/2);
$pdu_text1 = $pdu_len1 . $pdu_text1;$pdu_text1 = “11000D91″ . $invert_msisdn .”000800” . $pdu_text1;
$atcmd = “AT+CMGS=” . sprintf(“%d”, strlen($pdu_text1)/2) . chr(13);
$l = strlen($atcmd);
$ll = @dio_write($fd,$atcmd);
while ($l != $ll) {
sleep(10);
$ll = @dio_write($fd,$atcmd);
}
if ($DEBUG) echo date(“Y-m-d H:i:s”).” DEBUG $atcmd/n”;
do {
$data = dio_read($fd, $len);
echo $data;
} while ( $data != $s );
sleep(1);$pdu_text1 = “0891” . $invert_smsc . $pdu_text1 . chr(26).chr(13);
$l = strlen($pdu_text1);
$ll = @dio_write($fd,$pdu_text1);
while ($l != $ll) {
sleep(10);
$ll = @dio_write($fd,$pdu_text1);
}
if ($DEBUG) echo date(“Y-m-d H:i:s”).” DEBUG $pdu_text1/n”;
do {
$data = dio_read($fd, $len);
echo $data;
} while ( $data != $s );sleep(7);
} while ( $pdu_text != “” );mysql_query(“update sm_submit set stat=1 where smid=$row->smid”, $sql);
}
mysql_close($sql);
dio_close($fd);
?>
评论