该代码已经使用到正式项目中,且稳定运行。
注意:
1、保持心跳,可让连接生效一个小时左右,超过一个小时请重连。 可使用if (feof($cmpp30->_socket)) 判断是否需要重连。
1、不保持心跳的情况下,连接50秒过期。
保持心跳方法。建议每三十秒保持一次 $cmpp30->Active();
<?php
namespace CMPP30;
date_default_timezone_set("PRC");
/**
* 移动点对点CMPP协议接口
*
* PHP version 5
*/
/**
* 命令或响应类型 Command_Id定义
*/
define('CMPP_CONNECT', 0x00000001); // 请求连接
define('CMPP_CONNECT_RESP', 0x80000001); // 请求连接应答
define('CMPP_TERMINATE', 0x00000002); // 终止连接
define('CMPP_TERMINATE_RESP', 0x80000002); // 终止连接应答
define('CMPP_SUBMIT', 0x00000004); // 提交短信
define('CMPP_SUBMIT_RESP', 0x80000004); // 提交短信应答
define('CMPP_DELIVER', 0x00000005); // 短信下发
define('CMPP_DELIVER_RESP', 0x80000005); // 下发短信应答
define('CMPP_QUERY', 0x00000006); // 发送短信状态查询
define('CMPP_QUERY_RESP', 0x80000006); // 发送短信状态查询应答
define('CMPP_CANCEL', 0x00000007); // 删除短信
define('CMPP_CANCEL_RESP', 0x80000007); // 删除短信应答
define('CMPP_ACTIVE_TEST', 0x00000008); // 激活测试
define('CMPP_ACTIVE_TEST_RESP', 0x80000008); // 激活测试应答
class Cmpp30{
protected $_normal_service_id="";
protected $_template_service_id="";
protected $_msg_src="";
protected $_serv_addr="";
/**
* Socket连接
* @var resource
*/
protected $_socket = NULL;
/**
* 消息流水号
* 顺序累加,步长为1,循环使用(一对请求和应答消息的流水号必须相同)
* @var int
*/
protected $_sequence_number = 1;
protected $_message_sequence = 1;
/**
* 发送的数据
* 已经排除access_token值
* @var mixed
*/
protected $_sendData = NULL;
/**
* 收到的数据
* @var string
*/
protected $_responseData = NULL;
public function __construct(){
$this->_socket = NULL;
$this->_sequence_number = 1;
$this->_message_sequence = rand(1,255);
}
protected function _log($message)
{
printf("%s\n",$message);
}
/**
* PDU数据包转化ASCII数字
* @param string $pdu
* @return string
*/
public static function pduord($pdu){
$ord_pdu = '';
for ($i = 0; $i < strlen($pdu); $i++) {
$ord_pdu .= sprintf("%02x",ord($pdu[$i])) . ' ';
}
if($ord_pdu){
$ord_pdu = substr($ord_pdu, 0, -1);
}
return $ord_pdu;
}
//主机 端口 用户名 密码
// template_service_id template_service_id as Service_Id 业务标识,是数字、字母和符号的组合。
//$msg_src as msg_src信息内容来源(SP_Id,SP的企业代码)
//$serv_addr as Src_Id 源号码
public function Start($host, $port, $username, $password,$normal_service_id,$template_service_id,$msg_src,$serv_addr)
{
$this->_normal_service_id=$normal_service_id;
$this->_template_service_id=$template_service_id;
$this->_serv_addr=$serv_addr;
$this->_msg_src=$msg_src;
$this->_socket = fsockopen($host, $port, $errno, $errstr, 600*1200);
if (!$this->_socket) {
$this->_log("Error opening CMPP session.");
$this->_log("Error was: $errstr.");
return false;
}
socket_set_timeout($this->_socket, 600*1200);
$status = $this->_CMPP_CONNECT($username, $password);
if (false===$status) {
$this->_log("Error Connect to CMPP server. Invalid credentials?");
}
return $status;
}
public function End()
{
if (!$this->_socket) {
// not connected
return;
}
$status = $this->_CMPP_TERMINATE();
if (false==$status) {
$this->_log("CMPP Server returned error $status");
return false;
}
fclose($this->_socket);
$this->_socket = NULL;
return $status;
}
protected function _SendPDU($command_id, $pdu, $requestd)
{
$length = strlen($pdu) + 12;
$header = pack("NNN", $length, $command_id, $this->_sequence_number);
$this->_log("Sending PDU, len == $length");
$this->_log("Sending PDU, header-len == " . strlen($header));
$this->_log("Sending PDU, command_id == " . $command_id);
$this->_log("Sending PDU, sequence_number == " . $this->_sequence_number);
$this->_log("Sending PDU, header == ".self::pduord($header));
$this->_sendData = $requestd;
fwrite($this->_socket, $header . $pdu, $length);usleep(3000);
$status = $this->_ExpectPDU($this->_sequence_number, $requestd);
$this->_sequence_number = $this->_sequence_number + 1;
return $status;
}
protected function _ExpectPDU($our_sequence_number, $requestd=NULL)
{
do {
$this->_log("Trying to read PDU.");
if (feof($this->_socket)) {
$this->_log("Socket was closed.!!");
return false;
}
$elength = fread($this->_socket, 4);
if (empty($elength)) {
$this->_log("Connection lost.");
return false;
}
extract(unpack("Nlength", $elength));
$this->_log("Reading PDU : $length bytes.");
$stream = fread($this->_socket, $length - 4);
$this->_log("Stream len : " . strlen($stream));
extract(unpack("Ncommand_id/Nsequence_number", $stream));
$command_id &= 0x0fffffff;
$this->_log("Command id : $command_id");
$this->_log("sequence_number : $sequence_number");
$pdu = substr($stream, 8);
$data = NULL;
switch ($command_id) {
case CMPP_CONNECT:
$this->_log("Got CMPP_CONNECT_RESP.");
$data = $this->_CMPP_CONNECT_RESP($pdu, $requestd);
break;
case CMPP_SUBMIT:
$this->_log("Got CMPP_SUBMIT_RESP.");
$data = $this->_CMPP_SUBMIT_RESP($pdu, $requestd);
break;
case CMPP_TERMINATE:
$this->_log("Got CMPP_TERMINATE_RESP.");
break;
case CMPP_ACTIVE_TEST:
$this->_log("Got CMPP_ACTIVE_TEST.");
break;
default:
$this->_log("Got unknown CMPP pdu.");
break;
}
$this->_log("Received PDU: " . self::pduord(pack('N', $elength).$stream));
} while ($sequence_number != $our_sequence_number);
$this->_responseData = $data;
$command_status = false===$data?false:true;
return $command_status;
}
protected function _CMPP_CONNECT($Source_Addr, $Shared_Secret, $Version=0x20)
{
$data = array();
// 源地址,此处为SP_Id,即SP的企业代码。
$data['Source_Addr'] = $Source_Addr;
$Source_Addr_len = 6;
$data['Shared_Secret'] = $Shared_Secret;
$data['Timestamp'] = date('mdHis');
$data['Version'] = $Version;
$AuthenticatorSource_ori = $data['Source_Addr'] . pack('a9', '') . $data['Shared_Secret'] . $data['Timestamp'];
$data['AuthenticatorSource'] = md5($AuthenticatorSource_ori, true);
$AuthenticatorSource_len = 16;
$format = "a{$Source_Addr_len}a{$AuthenticatorSource_len}CN";
$pdu = pack($format, $data['Source_Addr'], $data['AuthenticatorSource'], $data['Version'], $data['Timestamp']);
$debug_data = $data;
$debug_data['AuthenticatorSource'] = self::pduord($debug_data['AuthenticatorSource']);
$this->_log("CMPP_CONNECT PDU: " . self::pduord($pdu));
$this->_log("CMPP_CONNECT SPEC: " . $format);
$this->_log("CMPP_CONNECT DATA: " . print_r($debug_data, true));
unset($debug_data);
return $this->_SendPDU(CMPP_CONNECT, $pdu, $data);
}
protected function _CMPP_CONNECT_RESP($pdu, $requestd){
$format = "CStatus/a16AuthenticatorISMG/CVersion";
$data = unpack($format, $pdu);
$this->_log("CMPP_CONNECT_RESP PDU: " . self::pduord($pdu));
$this->_log("CMPP_CONNECT_RESP SPEC: " . $format);
$this->_log("CMPP_CONNECT_RESP DATA: " . print_r($data, true));
$this->_log("AuthenticatorISMG: " . self::pduord($data['AuthenticatorISMG']));
$status = intval($data['Status']);
if(strcasecmp('0', $status)){
return self::cmpp_connect_resp_status_error($status);
}elseif(0==strlen($data['AuthenticatorISMG'])){
return 'ISMG认证码为空';
}
$checkAuthenticatorISMG = md5($data['Status'].$requestd['AuthenticatorSource'].$requestd['Shared_Secret'], true);
if(strcmp($checkAuthenticatorISMG, $data['AuthenticatorISMG'])){
return 'ISMG认证码校验失败';
}
return $data;
}
protected function _CMPP_TERMINATE()
{
$data="";
$pdu = "";
$this->_log("CMPP_TERMINATE PDU: " . self::pduord($pdu));
return $this->_SendPDU(CMPP_TERMINATE, $pdu, $data);
}
public static function cmpp_connect_resp_status_error($status){
$errors = array(
0 => '正确',
1 => '消息结构错',
2 => '非法源地址',
3 => '认证错',
4 => '版本太高',
);
if($status>=0){
if($status>=5){
return '其他错误';
}else{
return $errors[$status];
}
}else{
return '未知错误';
}
}
protected function _CMPP_SUBMIT($data){
$Dest_terminal_Id_len = 21*$data['DestUsr_tl'];
$Msg_Content_len = strlen($data['Msg_Content']);
//$format = "N2CCCCa10CC21CCCa6a2a6a17a17a21Ca{$Dest_terminal_Id_len}Ca{$Msg_Content_len}a8";
//$format = "a8CCCCa10Ca32CCCCa6a2a6a17a17a21Ca32CCa140a20";
$format = "a8CCCCa10Ca32CCCCa6a2a6a17a17a21Ca32CCa{$Msg_Content_len}a20";
$pdu = pack($format
, $data['Msg_Id']
, $data['Pk_total'], $data['Pk_number'], $data['Registered_Delivery'], $data['Msg_level']
, $data['Service_Id']
, $data['Fee_UserType']
, $data['Fee_terminal_Id'], $data['Fee_terminal_Type']
, $data['TP_pId'], $data['TP_udhi'], $data['Msg_Fmt']
, $data['Msg_src']
, $data['FeeType']
, $data['FeeCode']
, $data['ValId_Time'], $data['At_Time']
, $data['Src_Id']
, $data['DestUsr_tl']
, $data['Dest_terminal_Id'], $data['Dest_terminal_Type']
, $data['Msg_Length']
, $data['Msg_Content']
, $data['Reserve']
);
$this->_log("CMPP_SUBMIT PDU: " . self::pduord($pdu));
$this->_log("CMPP_SUBMIT SPEC: " . $format);
$this->_log("CMPP_SUBMIT DATA: " . print_r($data, true));
return $this->_SendPDU(CMPP_SUBMIT, $pdu, $data);
}
protected function _CMPP_SUBMIT_RESP($pdu, $requestd){
$format = "N2Msg_Id/NResult";
//$format = "C8Msg_Id/CResult";
$data = unpack($format, $pdu);
$this->_log("CMPP_SUBMIT_RESP PDU: " . self::pduord($pdu));
$this->_log("CMPP_SUBMIT_RESP SPEC: " . $format);
$this->_log("CMPP_SUBMIT_RESP DATA: " . print_r($data, true));
$result = intval($data['Result']);
if(strcasecmp('0', $result)){
return self::cmpp_connect_resp_status_error($result);
}
return $data;
}
public static function cmpp_submit_resp_result_error($result){
$errors = array(
0 => '正确',
1 => '消息结构错',
2 => '命令字错',
3 => '消息序号重复',
4 => '消息长度错',
5 => '资费代码错',
6 => '超过最大信息长',
7 => '业务代码错',
8 => '流量控制错',
);
if($result>=0){
if($result>=9){
return '其他错误';
}else{
return $errors[$result];
}
}else{
return '未知错误';
}
}
public function SendSms($mobile,$context,$text_encoding='UTF-8')
{
$data=Array();
$data['Msg_Id']=0;
$data['Registered_Delivery']=0;
$data['Msg_level']=0;
$data['Service_Id']=$this->_normal_service_id;
$data['Fee_UserType']=3;
$data['Fee_terminal_Id']=$mobile;
$data['Fee_terminal_Type']=0;
$data['TP_pId']=0;
$data['TP_udhi']=1;
$data['Msg_Fmt']=8;
$data['Msg_src']=$this->_msg_src;
$data['FeeType']="01";
$data['FeeCode']="000000";
$data['ValId_Time']="";
$data['At_Time']="";
$data['Src_Id']=$this->_serv_addr;
$data['DestUsr_tl']=1;
$data['Dest_terminal_Id']=$mobile;
$data['Dest_terminal_Type']=0;
$txt_head = 6;
$txt_len = 140;
$max_len = $txt_len-$txt_head;
$Msg_Content=mb_convert_encoding($context, "UCS-2BE", $text_encoding);
$msg_sequence = $this->_message_sequence++;
if(strlen($Msg_Content)<$max_len)
{
$data['Pk_total']=1;
$data['Pk_number']=1;
$udh = pack("cccccc", 5, 0, 3, $msg_sequence, 1, 1);
$data['Msg_Content']=$udh .$Msg_Content;
$data['Msg_Length']=strlen($data['Msg_Content']);
$data['Reserve']='';
$this->_log("CMPP_SUBMIT_DATA PDU: " . self::pduord($data['Msg_Content']));
$status = $this->_CMPP_SUBMIT($data);
$this->_log($status);
return ;
}
$pos = 0;
$num_messages = ceil(strlen($Msg_Content) / $max_len);
$this->_log($num_messages);
for($i=0;$i<$num_messages;$i++)
{
$data['Pk_total']=$num_messages;
$data['Pk_number']=$i+1;
$udh = pack("cccccc", 5, 0, 3, $msg_sequence, $num_messages, $i+1);
$data['Msg_Content']=$udh .substr($Msg_Content, $i*$max_len, $max_len);
$data['Msg_Length']=strlen($data['Msg_Content']);
$data['Reserve']='';
$this->_log("CMPP_SUBMIT_DATA PDU: " . self::pduord($data['Msg_Content']));
$status = $this->_CMPP_SUBMIT($data);
$this->_log($status);
}
}
public function SendSmsT($mobile,$strKey,$param,$text_encoding='UTF-8')
{
$data=Array();
$data['Msg_Id']=0;
$data['Pk_total']=1;
$data['Pk_number']=1;
$data['Registered_Delivery']=0;
$data['Msg_level']=0;
$data['Service_Id']=$this->_template_service_id;
$data['Fee_UserType']=3;
$data['Fee_terminal_Id']=$mobile;
$data['Fee_terminal_Type']=0;
$data['TP_pId']=0;
$data['TP_udhi']=0;
$data['Msg_Fmt']=8;
$data['Msg_src']=$this->_msg_src;
$data['FeeType']="01";
$data['FeeCode']="000000";
$data['ValId_Time']="";
$data['At_Time']="";
$data['Src_Id']=$this->_serv_addr;
$data['DestUsr_tl']=1;
$data['Dest_terminal_Id']=$mobile;
$data['Dest_terminal_Type']=0;
if(!is_array($param)) { $this->_log("Your params none!");return ;}
$context="<cmppTemplate><template>{$strKey}</template>";
for($i=0;$i<count($param);$i++)
{
$context.=sprintf("<node%d>%s</node%d>",$i+1,$param[$i],$i+1);
}
$context.="</cmppTemplate>";
$this->_log($context);
$data['Msg_Content']=mb_convert_encoding($context, "UCS-2BE", $text_encoding);
$data['Msg_Length']=strlen($data['Msg_Content']);
$data['Reserve']='';
$status = $this->_CMPP_SUBMIT($data);
$this->_log($status);
}
public function Active()
{
$data="";
$this->_SendPDU(CMPP_ACTIVE_TEST, "", $data);
}
}
$context="经济观察网 实习记者 骆贝贝7月18日,欧盟宣布,对全球第一大芯片制造商高通公司处以高达2.42亿欧元(约合18.69亿元人民币)的罚款,原因是高通在2009年至2011年期间,为了让英国手机软件制造商Icera退出竞争,“以掠夺性定价方式伤害竞争对手”。而这是一年多时间以来,高通第二次受到欧盟的反垄断处罚。";
$cmpp=new Cmpp30();
$cmpp->Start("",7891,"","@","","","","");
//$cmpp->SendSms("13888888888","123131313112313131311231313131123131313112313131311231313131123131313112313131311231313131123131313112313131311231313131123131313112313131311231313131123131313112313131311231313131");
?>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。