移动点对点CMPP协议接口类(PHP版本)
2017-01-11 16:10
926 查看
【项目需求】
用PHP语言实现通过短连接方式使用移动短信接口发送短信。
【项目疑难点】
理解接口数据格式和要求,结合PHP语言特点实现。
【代码举例】
AdcCmpp.class.php 发送短信接口类
用PHP语言实现通过短连接方式使用移动短信接口发送短信。
【项目疑难点】
理解接口数据格式和要求,结合PHP语言特点实现。
【代码举例】
AdcCmpp.class.php 发送短信接口类
<?php /** * 移动点对点CMPP协议接口 * * PHP version 5 * * @category Lib * @package COM * @subpackage GZNC * @author zhongyiwen * @version SVN: $Id: AdcCmpp.class.php 129 2015-01-26 11:51:20Z zhongyw $ */ /** * 命令或响应类型 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); // 激活测试应答 define('CMPP_FWD', 0x00000009); // 消息前转 define('CMPP_FWD_RESP', 0x80000009); // 消息前转应答 define('CMPP_MT_ROUTE', 0x00000010); // MT路由请求 define('CMPP_MT_ROUTE_RESP', 0x80000010); // MT路由请求应答 define('CMPP_MO_ROUTE', 0x00000011); // MO路由请求 define('CMPP_MO_ROUTE_RESP', 0x80000011); // MO路由请求应答 define('CMPP_GET_ROUTE', 0x00000012); // 获取路由请求 define('CMPP_GET_ROUTE_RESP', 0x80000012); // 获取路由请求应答 define('CMPP_MT_ROUTE_UPDATE', 0x00000013); // MT路由更新 define('CMPP_MT_ROUTE_UPDATE_RESP', 0x80000013); // MT路由更新应答 define('CMPP_MO_ROUTE_UPDATE', 0x00000014); // MO路由更新 define('CMPP_MO_ROUTE_UPDATE_RESP', 0x80000014); // MO路由更新应答 define('CMPP_PUSH_MT_ROUTE_UPDATE', 0x00000015); // MT路由更新 define('CMPP_PUSH_MT_ROUTE_UPDATE_RESP', 0x80000015); // MT路由更新应答 define('CMPP_PUSH_MO_ROUTE_UPDATE', 0x00000016); // MO路由更新 define('CMPP_PUSH_MO_ROUTE_UPDATE_RESP', 0x80000016); // MO路由更新应答 class AdcCmpp extends Adc{ /** * 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; /** * 收到数据的数组格式 * @var array */ protected $_ArrayModeData = array(); public function __construct($Config=NULL){ parent::__construct($Config); $this->_socket = NULL; $this->_sequence_number = 1; $this->_message_sequence = rand(1,255); } /* This method initiates an SMPP session. It is to be called BEFORE using the Send() method. Parameters: $host : SMPP ip to connect to. $port : port # to connect to. $username : SMPP system ID $password : SMPP passord. $system_type : SMPP System type Returns: true if successful, otherwise false Example: $smpp->Start("smpp.chimit.nl", 2345, "chimit", "my_password", "client01"); */ public function Start($host, $port, $username, $password) { $this->_socket = fsockopen($host, $port, $errno, $errstr, 20); // todo: sanity check on input parameters if (!$this->_socket) { $this->_log("Error opening CMPP session.", ADC_LOG_ERR); $this->_log("Error was: $errstr.", ADC_LOG_ERR); return false; } socket_set_timeout($this->_socket, 1200); $status = $this->_CMPP_CONNECT($username, $password); if (false===$status) { $this->_log("Error Connect to CMPP server. Invalid credentials?", ADC_LOG_ERR); } return $status; } /* This method ends a SMPP session. Parameters: none Returns: true if successful, otherwise false Example: $smpp->End(); */ public function End() { if (!$this->_socket) { // not connected return; } $status = $this->_CMPP_TERMINATE(); if (false==$status) { $this->_log("CMPP Server returned error $status", ADC_LOG_ERR); return false; } fclose($this->_socket); $this->_socket = NULL; 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.!!", ADC_LOG_ERR); return false; } $elength = fread($this->_socket, 4); if (empty($elength)) { $this->_log("Connection lost.", ADC_LOG_ERR); return false; } extract(unpack("Nlength", $elength)); $this->_log("Reading PDU : $length bytes.", ADC_LOG_DEBUG); $stream = fread($this->_socket, $length - 4); $this->_log("Stream len : " . strlen($stream), ADC_LOG_DEBUG); extract(unpack("Ncommand_id/Nsequence_number", $stream)); $command_id &= 0x0fffffff; $this->_log("Command id : $command_id", ADC_LOG_DEBUG); $this->_log("sequence_number : $sequence_number", ADC_LOG_DEBUG); $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; default: $this->_log("Got unknown CMPP pdu."); break; } $this->_log("Received PDU: " . self::pduord(pack('N', $elength).$stream) , ADC_LOG_DEBUG); } while ($sequence_number != $our_sequence_number); $this->_responseData = $data; $command_status = false===$data?false:true; return $command_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", ADC_LOG_DEBUG); $this->_log("Sending PDU, header-len == " . strlen($header), ADC_LOG_DEBUG); $this->_log("Sending PDU, command_id == " . $command_id, ADC_LOG_DEBUG); $this->_log("Sending PDU, sequence_number == " . $this->_sequence_number, ADC_LOG_DEBUG); $this->_sendData = $requestd; fwrite($this->_socket, $header . $pdu, $length); $status = $this->_ExpectPDU($this->_sequence_number, $requestd); $this->_sequence_number = $this->_sequence_number + 1; return $status; } protected function _CMPP_TERMINATE() { $pdu = ""; $this->_log("CMPP_TERMINATE PDU: " . self::pduord($pdu), ADC_LOG_DEBUG); return $this->_SendPDU(CMPP_TERMINATE, $pdu); } 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; //$data['Version'] = 0x20; // 用于鉴别源地址。其值通过单向MD5 hash计算得出,表示如下: // AuthenticatorSource= MD5(Source_Addr+9 字节的0 +shared secret+timestamp) // Shared secret 由中国移动与源地址实体事先商定,timestamp 格式为:MMDDHHMMSS,即月日时分秒,10位。 //$AuthenticatorSource_ori = $data['Source_Addr'] . str_pad('', 9, '0') . $data['Shared_Secret'] . $data['Timestamp']; $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), ADC_LOG_DEBUG); $this->_log("CMPP_CONNECT SPEC: " . $format, ADC_LOG_DEBUG); $this->_log("CMPP_CONNECT DATA: " . print_r($debug_data, true), ADC_LOG_DEBUG); unset($debug_data); //$this->_log('AuthenticatorSource Len: ' . strlen($data['AuthenticatorSource']), ADC_LOG_DEBUG); //$this->_log('AuthenticatorSource Ori: ' . $AuthenticatorSource_ori, ADC_LOG_DEBUG); //$this->_log('AuthenticatorSource MD5: ' . md5($AuthenticatorSource_ori), ADC_LOG_DEBUG); 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), ADC_LOG_DEBUG); $this->_log("CMPP_CONNECT_RESP SPEC: " . $format, ADC_LOG_DEBUG); $this->_log("CMPP_CONNECT_RESP DATA: " . print_r($data, true), ADC_LOG_DEBUG); $this->_log("AuthenticatorISMG: " . self::pduord($data['AuthenticatorISMG']), ADC_LOG_DEBUG); /** * ISMG认证码,用于鉴别ISMG。 其值通过单向MD5 hash计算得出,表示如下:AuthenticatorISMG =MD5(Status+AuthenticatorSource+shared secret) ,Shared secret 由中国移动与源地址实体事先商定,AuthenticatorSource为源地址实体发送给ISMG 的对应消息CMPP_Connect中的值。认证出错时,此项为空。 */ $ c7b9 status = intval($data['Status']); if(strcasecmp('0', $status)){ return $this->_throw_exception( self::cmpp_connect_resp_status_error($status) , ADC_ERR_RESPONSE_STATUS , $data , __FILE__, __LINE__ ); }elseif(0==strlen($data['AuthenticatorISMG'])){ return $this->_throw_exception( 'ISMG认证码为空' , ADC_ERR_RESPONSE_STATUS , $data , __FILE__, __LINE__ ); } $checkAuthenticatorISMG = md5($data['Status'].$requestd['AuthenticatorSource'].$requestd['Shared_Secret'], true); if(strcmp($checkAuthenticatorISMG, $data['AuthenticatorISMG'])){ return $this->_throw_exception( 'ISMG认证码校验失败' , ADC_ERR_RESPONSE_STATUS , array('PDU DATA'=>$data, 'checkAuthenticatorISMG' => $checkAuthenticatorISMG) , __FILE__, __LINE__ ); } return $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 = "a8CCCCa10Ca21CCCa6a2a6a17a17a21Ca{$Dest_terminal_Id_len}Ca{$Msg_Content_len}a8"; $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['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['Msg_Length'] , $data['Msg_Content'] , $data['Reserve'] ); $this->_log("CMPP_SUBMIT PDU: " . self::pduord($pdu), ADC_LOG_DEBUG); $this->_log("CMPP_SUBMIT SPEC: " . $format, ADC_LOG_DEBUG); $this->_log("CMPP_SUBMIT DATA: " . print_r($data, true), ADC_LOG_DEBUG); return $this->_SendPDU(CMPP_SUBMIT, $pdu, $data); } protected function _CMPP_SUBMIT_RESP($pdu, $requestd){ $format = "N2Msg_Id/CResult"; //$format = "C8Msg_Id/CResult"; $data = unpack($format, $pdu); $this->_log("CMPP_SUBMIT_RESP PDU: " . self::pduord($pdu), ADC_LOG_DEBUG); $this->_log("CMPP_SUBMIT_RESP SPEC: " . $format, ADC_LOG_DEBUG); $this->_log("CMPP_SUBMIT_RESP DATA: " . print_r($data, true), ADC_LOG_DEBUG); $result = intval($data['Result']); if(strcasecmp('0', $result)){ return $this->_throw_exception( self::cmpp_connect_resp_status_error($result) , ADC_ERR_RESPONSE_STATUS , $data , __FILE__, __LINE__ ); } 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 '未知错误'; } } protected function _CMPP_QUERY($data){ $format = "a8Ca10a8"; $pdu = pack($format , $data['Time'] , $data['Query_Type'] , $data['Query_Code'] , $data['Reserve'] ); $this->_log("CMPP_QUERY PDU: " . self::pduord($pdu), ADC_LOG_DEBUG); $this->_log("CMPP_QUERY SPEC: " . $format, ADC_LOG_DEBUG); $this->_log("CMPP_QUERY DATA: " . print_r($data, true), ADC_LOG_DEBUG); $status = $this->_SendPDU(CMPP_QUERY, $pdu, $data); return $status; } protected function _CMPP_QUERY_RESP($pdu, $requestd){ $format = "a8Time/CQuery_Type/a10Query_Code/NMT_TLMsg/NMT_Tlusr/NMT_Scs/NMT_WT/NMT_FL/NMO_Scs/NMO_WT/NMO_FL"; $data = unpack($format, $pdu); $this->_log("CMPP_QUERY_RESP PDU: " . self::pduord($pdu), ADC_LOG_DEBUG); $this->_log("CMPP_QUERY_RESP SPEC: " . $format, ADC_LOG_DEBUG); $this->_log("CMPP_QUERY_RESP DATA: " . print_r($data, true), ADC_LOG_DEBUG); if(empty($data)){ return $this->_throw_exception( "Empty CMPP_QUERY_RESP" , ADC_ERR_RESPONSE_EMPTY , $data , __FILE__, __LINE__ ); } return $data; } /* This method sends out one SMS message. Parameters: $to : destination address. $text : text of message to send. $unicode: Optional. Indicates if sending text in unicode format. $text_encoding: Optional. encoding of text Returns: true if messages sent successfull, otherwise false. Example: $cmpp->Send("31649072766", "This is an SMPP Test message."); $cmpp->Send("31648072766", "صباحالخير", true); */ /** * 发送短消息 * * Example: $cmpp->Send("31649072766", "This is an SMPP Test message."); $cmpp->Send("31648072766", "صباحالخير", true, 'HTML-ENTITIES') * @param mixed $to 手机号码,传单个电话号码或者数组 * @param stirng $text 短消息内容,如果超长会自动切分短消息变成多条发送 * @param bool $unicode 是否UCS2编码方式发送,默认是,注意中文必须以UCS2编码发送 * @param string $text_encoding 短消息内容的编码,默认UTF-8,可选值参考函数:mb_convert_encoding() * @return boolean 发送成功返回true,失败返回false */ public function Send($to, $text, $unicode = true, $text_encoding='UTF-8'){ if(is_array($to)){ $Dest_terminal_Id = ''; $DestUsr_tl = count($to); foreach($to as $dest){ $Dest_terminal_Id .= pack('a21', $dest); } }else{ $Dest_terminal_Id = $to; $DestUsr_tl = 1; } $Msg_Content = ''; $data = array(); $data['Msg_Id'] = 0; $data['Pk_total'] = 1; $data['Pk_number'] = 1; // 是否要求返回状态确认报告 // 0:不需要 // 1:需要 // 2:产生SMC话单(该类型短信仅供网关计费使用,不发送给目的终端) $data['Registered_Delivery'] = $DestUsr_tl>1?0:0; // 信息级别 // 0:普通优先级(缺省值) // 1:高优先级 // >1:保留 $data['Msg_level'] = 0; // 业务类型 $data['Service_Id'] = $this->Config->AdcServiceId; //计费用户类型字段 //0:对目的终端MSISDN计费; //1:对源终端MSISDN计费; //2:对SP计费; //3:表示本字段无效,对谁计费参见Fee_terminal_Id字段 $data['Fee_UserType'] = 0; // 被计费用户的号码(如本字节填空,则表示本字段无效,对谁计费参见Fee_UserType 字段,本字段与Fee_UserType字段互斥) $data['Fee_terminal_Id'] = ''; // GSM协议类型 $data['TP_pId'] = 0; $data['TP_udhi'] = 0; // 信息格式 // 0:ASCII串 // 3:短信写卡操作 // 4:二进制信息 // 8:UCS2编码 // 15:含GB汉字 。。。。。。 $data['Msg_Fmt'] = 0; // 信息内容来源(SP_Id) $data['Msg_src'] = $this->Config->AdcAspId; // 资费类别 //01:对“计费用户号码”免费 //02:对“计费用户号码”按条计信息费 //03:对“计费用户号码”按包月收取信息费 //04:对“计费用户号码”的信息费封顶 //05:对“计费用户号码”的收费是由SP实现 $data['FeeType'] = '03'; // 资费代码(以分为单位) $data['FeeCode'] = ''; // 存活有效期,格式遵循SMPP3.3 协议 $data['ValId_Time'] = ''; // 定时发送时间,格式遵循SMPP3.3 协议 $data['At_Time'] = ''; // 源号码 //SP 的服务代码或前缀为服务代码的长号码, //网关将该号码完整的填到SMPP协议Submit_SM 消息相应的source_addr字段, //该号码最终在用户手机上显示为短消息的主叫号码 $data['Src_Id'] = $this->Config->AdcAspCode; // 接收信息的用户数量(小于100 个用户) $data['DestUsr_tl'] = $DestUsr_tl; if($data['DestUsr_tl']>100){ return $this->_throw_exception( "Over max DestUsr_tl<100" , SCRIPT_ERR_CONFIG , $data , __FILE__, __LINE__ ); } // 接收短信的MSISDN 号码 $data['Dest_terminal_Id'] = $Dest_terminal_Id; // 信息长度(Msg_Fmt 值为0 时:<160 个字节;其它<=140 个字节) $data['Msg_Length'] = strlen($Msg_Content); /* $max_msg_len = $data['Msg_Fmt']==0?160:140; if($data['Msg_Length']>$max_msg_len){ return $this->_throw_exception( "Over max Msg_Length<{$max_msg_len}" , SCRIPT_ERR_CONFIG , $data , __FILE__, __LINE__ ); } unset($max_msg_len);*/ // 信息内容 $data['Msg_Content'] = $Msg_Content; $data['Reserve'] = ''; /** * 消息转码分隔 */ if ($unicode) { if(strcasecmp("UCS-2BE", $text_encoding)){ $unicode_text = mb_convert_encoding($text, "UCS-2BE", $text_encoding); /* UCS-2BE */ }else{ $unicode_text = $text; } $multi_texts = $this->_split_message_unicode($unicode_text); unset($unicode_text); $data['Msg_Fmt'] = 8; } else { $multi_texts = $this->_split_message($text); } if (count($multi_texts) > 1) { $data['TP_udhi'] = 1; $data['Pk_total'] = count($multi_texts); } $result = true; reset($multi_texts); while (list($pos, $part) = each($multi_texts)) { $Msg_Content = $part; $data['Pk_number'] = $pos+1; $data['Msg_Content'] = $Msg_Content; $data['Msg_Length'] = strlen($Msg_Content); $status = $this->_CMPP_SUBMIT($data); if (false===$status) { $this->_log("CMPP server returned error $status.", ADC_LOG_ERR); $result = false; } } return $result; } /** * PDU数据包转化ASCII数字 * @param string $pdu * @return string */ public static function pduord($pdu){ $ord_pdu = ''; for ($i = 0; $i < strlen($pdu); $i++) { $ord_pdu .= ord($pdu[$i]) . ' '; } if($ord_pdu){ $ord_pdu = substr($ord_pdu, 0, -1); } return $ord_pdu; } /** * PDU数据包转为字符串(不可见字符转为ASCII数字) * @param string $pdu * @return string */ public static function pdustr($pdu){ $str_pdu = ''; for ($i = 0; $i < strlen($pdu); $i++) { $n = ord($pdu[$i]); if($n<=32 || $n>=127){ $str_pdu .= '('. $n . ')'; }else{ $str_pdu .= $pdu[$i]; } $str_pdu .= ' '; } if($str_pdu){ $str_pdu = substr($str_pdu, 0, -1); } return $str_pdu; } protected function _split_message($text) { $this->_log("In split_message.", ADC_LOG_DEBUG); $max_len = 153; $res = array(); if (strlen($text) <= 160) { $this->_log("One message: " . strlen($text), ADC_LOG_DEBUG); $res[] = $text; return $res; } $pos = 0; $msg_sequence = $this->_message_sequence++; $num_messages = ceil(strlen($text) / $max_len); $part_no = 1; while ($pos < strlen($text)) { $ttext = substr($text, $pos, $max_len); $pos += strlen($ttext); $udh = pack("cccccc", 5, 0, 3, $msg_sequence, $num_messages, $part_no); $part_no++; $res[] = $udh . $ttext; $this->_log("Split: UDH = " . self::pduord($udh), ADC_LOG_DEBUG); $this->_log("Split: $ttext.", ADC_LOG_DEBUG); } return $res; } protected function _split_message_unicode($text) { $this->_log("In split_message.", ADC_LOG_DEBUG); $max_len = 134; $res = array(); if (mb_strlen($text) <= 140) { $this->debug("One message: " . mb_strlen($text), ADC_LOG_DEBUG); $res[] = $text; return $res; } $pos = 0; $msg_sequence = $this->_message_sequence++; $num_messages = ceil(mb_strlen($text) / $max_len); $part_no = 1; while ($pos < mb_strlen($text)) { $ttext = mb_substr($text, $pos, $max_len); $pos += mb_strlen($ttext); $udh = pack("cccccc", 5, 0, 3, $msg_sequence, $num_messages, $part_no); $part_no++; $res[] = $udh . $ttext; $this->_log("Split: UDH = " . self::pduord($udh), ADC_LOG_DEBUG); $this->_log("Split: $ttext.", ADC_LOG_DEBUG); } return $res; } }
相关文章推荐
- 七牛云存储官方接口PHP版本
- 七牛云存储官方接口PHP版本
- php开发移动app(api)接口时应该注意的事项
- PHP:API 接口规范完整版本
- PHP开发APP接口(六):APP版本升级以及APP演示
- 小I机器人接口[PHP版本 08.12.7]
- php 开发移动应用接口
- PHP 对接 支付宝 移动接口
- PHP开发APP接口(六):APP版本升级以及APP演示
- 七牛云存储官方接口PHP版本
- php开发移动app(api)接口时应该注意的事项(仅供参考)
- PHP 开发 APP 接口 学习笔记与总结 - APP 接口实例 [6] 版本升级接口开发
- 使用php开发移动APP接口
- PHP开发移动客户端接口---获取表中记录总数
- 七牛云存储官方接口PHP版本
- PHP 开发 APP 接口 学习笔记与总结 - APP 接口实例 [5] 版本设计分析及数据表设计
- PHP开发移动客户端接口---插入数据接口
- Php实现版本比较接口
- 移动开发者快速上手php接口开发
- PHP与移动客户端接口安全校验