我的一个同事最近在替换方维p2p系统的短信接口,版本为3.5。短信接口我们公司使用的是短信宝( 网址:http://www.smsbao.com)的短信接口,短信宝的接口稳定,快速,值得向大家推荐。因为方维p2p的用户使用量非常大,而且我研究了一下,方维p2p的其他版本的短信接口替换都大同小异的,所以我在这里和大家分享一下修改全过程,让有这方面业务需求的小伙伴能够快速学会。
为了帮助更多的用户解决方维p2p的短信接口替换问题,我已经把功能代码打包成了插件,提供给了短信宝官网,直接去他们的网站下载即可。下载地址:http://www.smsbao.com/plugin/80.html
下面我来阐述一下替换过程:
1.首先要开启短信的功能,在系统设置->邮件与短信中开启设置。如图所示:
2.创建一个sms_trans.php文件上传至项目根目录下的system\sms\smsbao这个文件下(smsbao目录需要创建),代码如下:
<?php /* 模块的基本信息 */ if (isset($read_modules) && $read_modules == true) { $module['class_name'] = 'smsbao'; /* 名称 */ $module['name'] = "短信宝增值平台 (<a href='http://www.smsbao.com/reg?r=5001' target='_blank'><font color='red'>还没账号?点击这免费注册</font></a>)"; $module['server_url'] = 'http://www.smsbao.com/sms'; if(ACTION_NAME == "install" || ACTION_NAME == "edit"){ $module['lang'] = array(); $module['config'] = array(); } return $module; } // 企信通短信平台 require_once APP_ROOT_PATH."system/libs/sms.php"; //引入接口 require_once APP_ROOT_PATH."system/sms/smsbao/sms_trans.php"; class smsbao_sms implements sms { public $sms; public $message = ""; // 短信宝的状态码 private $statusStr = array( "0" => "短信发送成功", "-1" => "参数不全", "-2" => "服务器空间不支持,请确认支持curl或者fsocket,联系您的空间商解决或者更换空间!", "30" => "密码错误", "40" => "账号不存在", "41" => "余额不足", "42" => "帐户已过期", "43" => "IP地址限制", "50" => "内容含有敏感词" ); public function __construct($smsInfo = '') { if(!empty($smsInfo)) { $this->sms = $smsInfo; } } public function sendSMS($mobile_number,$content,$is_adv=0) { if(is_array($mobile_number)) { $mobile_number = implode(",",$mobile_number); } $sms = new sms_trans(); // 设置提交的参数 $params = array( "u"=>$this->sms['user_name'], "p"=>md5($this->sms['password']), "m"=>$mobile_number, "c"=>urlencode($content) ); $result = $sms->request($this->sms['server_url'],$params); $code = $result['body']; if($code=='0') { $result['status'] = 1; } else { $result['status'] = 0; $result['msg'] = $this->statusStr[$code]; } return $result; } public function getSmsInfo() { return "短信宝增值平台"; } public function check_fee() { es_session::start(); $last_visit = intval(es_session::get("last_visit_smsbao")); if(get_gmtime() - $last_visit > 10) { $sms = new sms_trans(); $params = array( "u"=>$this->sms['user_name'], "p"=>md5($this->sms['password']) ); $url = "http://www.smsbao.com/query"; $result = $sms->request($url,$params); $match = explode(',',$result['body']); if ($match[0] != '') { $remain = (int)$match[1]; $str = sprintf('短信宝增值平台 剩余:%d 条', $remain); } else { $str = "短信宝增值平台 (<a href='http://www.smsbao.com/reg?r=5001' target='_blank'><font color='red'>还没账号?点击这免费注册</font></a>)"; } es_session::set("smsbao_info",$str); es_session::set("last_visit_smsbao",get_gmtime()); return $str; } else { $qxt_info = es_session::get("smsbao_info"); if($smsbao_info) return $smsbao_info; else return "短信宝增值平台 (<a href='http://www.smsbao.com/reg?r=5001' target='_blank'><font color='red'>还没账号?点击这免费注册</font></a>)"; } } }
3.创建smsbao_sms.php这个文件上传至项目根目录下的system/sms文件下,代码如下:
<?php class sms_trans { /** * 脚本执行时间。-1表示采用PHP的默认值。 * * @access private * @var integer $time_limit */ var $time_limit = -1; /** * 在多少秒之内,如果连接不可用,脚本就停止连接。-1表示采用PHP的默认值。 * * @access private * @var integer $connect_timeout */ var $connect_timeout = -1; /** * 连接后,限定多少秒超时。-1表示采用PHP的默认值。此项仅当采用CURL库时启用。 * * @access private * @var integer $stream_timeout */ var $stream_timeout = -1; /** * 是否使用CURL库来连接。false表示采用fsockopen进行连接。 * * @access private * @var boolean $use_curl */ var $use_curl = false; /** * 构造函数 * * @access public * @param integer $time_limit * @param integer $connect_timeout * @param integer $stream_timeout * @param boolean $use_curl * @return void */ function __construct($time_limit = -1, $connect_timeout = -1, $stream_timeout = -1, $use_curl = false) { //$this->transport($time_limit, $connect_timeout, $stream_timeout, $use_curl); $this->time_limit = $time_limit; $this->connect_timeout = $connect_timeout; $this->stream_timeout = $stream_timeout; $this->use_curl = $use_curl; } /** * 请求远程服务器 * * @access public * @param string $url 远程服务器的URL * @param mix $params 查询参数,形如bar=foo&foo=bar;或者是一维关联数组,形如array('a'=>'aa',...) * @param string $method 请求方式,是POST还是GET * @param array $my_header 用户要发送的头部信息,为一维关联数组,形如array('a'=>'aa',...) * @return array 成功返回一维关联数组,形如array('header'=>'bar', 'body'=>'foo'), * 重大错误程序直接停止运行,否则返回false。 */ function request($url, $params = '', $method = 'POST', $my_header = '') { $fsock_exists = function_exists('fsockopen'); $curl_exists = function_exists('curl_init'); if (!$fsock_exists && !$curl_exists) { die('No method available!'); } if (!$url) { die('Invalid url!'); } if ($this->time_limit > -1)//如果为0,不限制执行时间 { set_time_limit($this->time_limit); } $method = $method === 'GET' ? $method : 'POST'; $response = ''; $temp_str = ''; /* 格式化将要发要送的参数 */ if ($params && is_array($params)) { foreach ($params AS $key => $value) { $temp_str .= '&' . $key . '=' . $value; } $params = preg_replace('/^&/', '', $temp_str); } /* 如果fsockopen存在,且用户不指定使用curl,则调用use_socket函数 */ if ($fsock_exists && !$this->use_curl) { $response = $this->use_socket($url, $params, $method, $my_header); } /* 只要上述条件中的任一个不成立,流程就转向这里,这时如果curl模块可用,就调用use_curl函数 */ elseif ($curl_exists) { $response = $this->use_curl($url, $params, $method, $my_header); } /* 空响应或者传输过程中发生错误,程序将返回false */ if (!$response) { return false; } return $response; } /** * 使用fsockopen进行连接 * * @access private * @param string $url 远程服务器的URL * @param string $params 查询参数,形如bar=foo&foo=bar * @param string $method 请求方式,是POST还是GET * @param array $my_header 用户要发送的头部信息,为一维关联数组,形如array('a'=>'aa',...) * @return array 成功返回一维关联数组,形如array('header'=>'bar', 'body'=>'foo'), * 否则返回false。 */ function use_socket($url, $params, $method, $my_header) { $query = ''; $auth = ''; $content_type = ''; $content_length = ''; $request_body = ''; $request = ''; $http_response = ''; $temp_str = ''; $error = ''; $errstr = ''; $crlf = $this->generate_crlf(); if ($method === 'GET') { $query = $params ? "?$params" : ''; } else { $request_body = $params; $content_type = 'Content-Type: application/x-www-form-urlencoded' . $crlf; $content_length = 'Content-Length: ' . strlen($request_body) . $crlf . $crlf; } $url_parts = $this->parse_raw_url($url); $path = $url_parts['path'] . $query; if (!empty($url_parts['user'])) { $auth = 'Authorization: Basic ' . base64_encode($url_parts['user'] . ':' . $url_parts['pass']) . $crlf; } /* 格式化自定义头部信息 */ if ($my_header && is_array($my_header)) { foreach ($my_header AS $key => $value) { $temp_str .= $key . ': ' . $value . $crlf; } $my_header = $temp_str; } /* 构造HTTP请求头部 */ $request = "$method $path HTTP/1.0$crlf" . 'Host: ' . $url_parts['host'] . $crlf . $auth . $my_header . $content_type . $content_length . $request_body; if ($this->connect_timeout > -1) { $fp = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr, $connect_timeout); } else { $fp = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr); } if (!$fp) { return false;//打开失败 } if (!@fwrite($fp, $request)) { return false;//写入失败 } while (!feof($fp)) { $http_response .= fgets($fp); } if (!$http_response) { return false;//空响应 } $separator = '/\r\n\r\n|\n\n|\r\r/'; list($http_header, $http_body) = preg_split($separator, $http_response, 2); $http_response = array('header' => $http_header,//header肯定有值 'body' => $http_body);//body可能为空 @fclose($fp); return $http_response; } /** * 使用curl进行连接 * * @access private * @param string $url 远程服务器的URL * @param string $params 查询参数,形如bar=foo&foo=bar * @param string $method 请求方式,是POST还是GET * @param array $my_header 用户要发送的头部信息,为一维关联数组,形如array('a'=>'aa',...) * @return array 成功返回一维关联数组,形如array('header'=>'bar', 'body'=>'foo'), * 失败返回false。 */ function use_curl($url, $params, $method, $my_header) { /* 开始一个新会话 */ $curl_session = curl_init(); /* 基本设置 */ curl_setopt($curl_session, CURLOPT_FORBID_REUSE, true); // 处理完后,关闭连接,释放资源 curl_setopt($curl_session, CURLOPT_HEADER, true);//结果中包含头部信息 curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);//把结果返回,而非直接输出 curl_setopt($curl_session, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);//采用1.0版的HTTP协议 $url_parts = $this->parse_raw_url($url); /* 设置验证策略 */ if (!empty($url_parts['user'])) { $auth = $url_parts['user'] . ':' . $url_parts['pass']; curl_setopt($curl_session, CURLOPT_USERPWD, $auth); curl_setopt($curl_session, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } $header = array(); /* 设置主机 */ $header[] = 'Host: ' . $url_parts['host']; /* 格式化自定义头部信息 */ if ($my_header && is_array($my_header)) { foreach ($my_header AS $key => $value) { $header[] = $key . ': ' . $value; } } if ($method === 'GET') { curl_setopt($curl_session, CURLOPT_HTTPGET, true); $url .= $params ? '?' . $params : ''; } else { curl_setopt($curl_session, CURLOPT_POST, true); $header[] = 'Content-Type: application/x-www-form-urlencoded'; $header[] = 'Content-Length: ' . strlen($params); curl_setopt($curl_session, CURLOPT_POSTFIELDS, $params); } /* 设置请求地址 */ curl_setopt($curl_session, CURLOPT_URL, $url); /* 设置头部信息 */ curl_setopt($curl_session, CURLOPT_HTTPHEADER, $header); if ($this->connect_timeout > -1) { curl_setopt($curl_session, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout); } if ($this->stream_timeout > -1) { curl_setopt($curl_session, CURLOPT_TIMEOUT, $this->stream_timeout); } /* 发送请求 */ $http_response = curl_exec($curl_session); if (curl_errno($curl_session) != 0) { return false; } $separator = '/\r\n\r\n|\n\n|\r\r/'; list($http_header, $http_body) = preg_split($separator, $http_response, 2); $http_response = array('header' => $http_header,//肯定有值 'body' => $http_body); //可能为空 curl_close($curl_session); return $http_response; } /** * Similar to PHP's builtin parse_url() function, but makes sure what the schema, * path and port keys are set to http, /, 80 respectively if they're missing * * @access private * @param string $raw_url Raw URL to be split into an array * @author http://www.cpaint.net/ * @return array */ function parse_raw_url($raw_url) { $retval = array(); $raw_url = (string) $raw_url; // make sure parse_url() recognizes the URL correctly. if (strpos($raw_url, '://') === false) { $raw_url = 'http://' . $raw_url; } // split request into array $retval = parse_url($raw_url); // make sure a path key exists if (!isset($retval['path'])) { $retval['path'] = '/'; } // set port to 80 if none exists if (!isset($retval['port'])) { $retval['port'] = '80'; } return $retval; } /** * 产生一个换行符,不同的操作系统会有不同的换行符 * * @access private * @return string 用双引号引用的换行符 */ function generate_crlf() { $crlf = ''; if (strtoupper(substr(PHP_OS, 0, 3) === 'WIN')) { $crlf = "\r\n"; } elseif (strtoupper(substr(PHP_OS, 0, 3) === 'MAC')) { $crlf = "\r"; } else { $crlf = "\n"; } return $crlf; } }
4.进行短信宝接口配置:在后台->系统配置->短信接口列表中,启用短信宝的配置,并进行编辑:
5.最后进行短信宝的接口测试,可以使用前台的注册功能测试,如图:
通过以上测试,短信接口修改算是完成了,是不是很方便呀。
到这儿方维p2p的短信接口修改算是完成了,在调试的时候也遇到了一些问题,我也一并分享给大家:
1. 首先,要确认在php环境配置文件php.ini中开启了curl的扩展,并且服务器或空间商支持curl或者fsocket。
2. 其次是短信宝接口配置一切都正确,但是短信还是发不出去。这时找到系统设置->队列管理->业务队列列表,全选列表数据,执行彻底删除操作,并执行队列发送。这样就可以了。发生此类问题的原因是队列任务卡死造成的。
如果还有什么不明白的地方,可以去短信宝官网(http://www.smsbao.com),找他们的在线客服解决问题,他们的客服可是很热情的哦。