<?php
namespace imcat;
// 手机短信接口类
class extSms{
public $cfg_mchar = 70; // 一条信息,文字个数(小灵通65个字)
public $cfg_mtels = 200; // 一次发送,最多200个手机号码个数
public $api = ''; //api接口类型(提供商)
public $smsdo = NULL; //api对象
public $cfgs = array(); //api配置
public $cnow = array('name'=>'-','unit'=>'-'); //now配置
public $amap = array(); //api列表
//function __destory(){ }
function __construct(){
require DIR_IMCAT."/adpt/smsapi/api_cfgs.php"; // 加载
$_cfgs = glbConfig::read('sms', 'ex');
$api = @$_cfgs['cfg_api'];
if($api && isset($_apis[$api])){
$this->api = $api;
$this->cfgs = $_cfgs;
$this->cnow = $_apis[$api];
$cfile = 'sms'.ucfirst($this->api);
// 统一实例化一个 api对象 // load sms libs
require DIR_IMCAT."/adpt/smsapi/$cfile.php"; // 加载
$class = "\\imcat\\$cfile";
$this->smsdo = new $class($_cfgs);
}
$this->amap = $_apis;
}
// 短信接口是否关闭
function isClosed(){
if(empty($this->api)){
return true;
}else{
return false;
} //&&$sms_cfg_api!='(close)'
}
// 余额查询
// 结果说明:array(1,1234.5): 成功,余额为1234.5;array(-1,'失败原因'):
function getBalance(){
return $this->smsdo->getBalance();
}
/** 模板短信发送
* @param string $mobiles 手机号码,参考sendSMS()
* @param array $params 参数:array('code'=>'1234','name'=>'peace',)
* @param string $tid 模版id
* @param string $sign 签名
**/
function sendTid($mobiles, $tid='', $params=[], $cfgs=[]){ // , $sign='', $limit=1, $pid=''
if(!method_exists($this->smsdo, 'sendTid')){
return array(-1, "a:{sendTid}不支持!");
}
$sign = empty($cfgs['sign']) ? '' : $cfgs['sign'];
$pid = empty($cfgs['pid']) ? 1 : $cfgs['pid'];
$limit = empty($cfgs['limit']) ? 1 : $cfgs['limit'];
$res = $this->smsdo->sendTid($mobiles, $params, $tid, $sign);
$tid || $tid = '(def)'; $sign || $sign = '(def)';
$this->loger($mobiles, json_encode($params)."(tid=$tid:sign=$sign)", $res, $limit, $pid); //写记录-db
return $res;
}
/** 短信发送,支持短信模版替换,
* @param string $mobiles 手机号码,参考sendSMS()
* @param string $tpl 支持模版,如:{subject}{name}标记
* @param array $source 替换源:array('subject'=>'hellow corp!','name'=>'peace',)
* @param string $type 发送方式/发送身份,参考sendSMS()
* @return array --- 结果数组,参考sendSMS()
**/
function sendTpl($mobiles, $tpl, $source, $cfgs=array()){
$tpl = str_replace(array("\r\n","\r","\n"),array(' ',' ',' '),$tpl);
if(preg_match_all('/{\s*([a-zA-Z_0-9]\w*)\s*}/i', $tpl, $matchs)){
if(!empty($matchs[0])){
foreach($matchs[0] as $v){
$k = str_replace(array('{','}'), '', $v);
$val = isset($source[$k]) ? $source[$k] : (isset($GLOBALS[$k]) ? $GLOBALS[$k] : "{\$$k}");
$tpl = str_replace($v, $val, $tpl);
}
}
}
return $this->sendSMS($mobiles, $tpl, 5, $cfgs);
}
/** 短信发送
* @param string $mobiles 手机号码,array/string(英文逗号分开)
* @param string $content 255个字符以内
* @param string $limit xxx :
* @return array --- 结果数组,如:array(1,'操作成功'):
**/
function sendSMS($mobiles, $content, $limit=1, $cfgs=array()){
$pid = empty($cfgs['pid']) ? '' : $cfgs['pid'];
if(!method_exists($this->smsdo, 'sendSMS')){
return array(-1, "a:{sendSMS}不支持!");
}
// 格式化 $mobiles,$content,
$atel = $this->telFormat($mobiles);
$amsg = $this->msgCount($content);
if(empty($atel)) return array('-2',basLang::show('sms_errtel'));
if(empty($amsg[0])) return array('-2',basLang::show('sms_errmsg'));
$nmsg = count($atel)*$amsg[1];
// 需扣费计算条数,检查余额
$balance = $this->smsdo->getBalance();
if((float)$balance[1]<=0){
$mobiles = implode(',',$atel);
$this->balanceWarn("--tels:$mobiles\n --cmsg:$content"); //写记录
return array('-2',basLang::show('sms_charge0'));
}
if($limit && $limit<$nmsg){
return array('-2',basLang::show('sms_charged'));
}
// 发送及结果
if(count($atel)>$this->cfg_mtels){ // 分组发送
$groups = array_chunk($atel,$this->cfg_mtels);
$res = array('-2',basLang::show('sms_msenderr'));
$flag = false; //成功标记
foreach($groups as $group){
$res_temp = $this->smsdo->sendSMS($group, $content);
if($res_temp[0]=='1'){ //只要一组发送成功,则都算成功.
$res = $res_temp;
}
}
}else{
$res = $this->smsdo->sendSMS($atel, $content);
}
$this->loger($atel, $amsg[0], $res, $nmsg, $pid); //写记录-db
return $res;
}
// 写记录-db
function loger($tel, $msg, $res, $nmsg=1, $pid=''){
// 写记录-db
$stel = is_array($tel) ? implode(',',$tel) : $tel;
if(strlen($stel)>255) $stel = substr($stel,0,240).'...'.substr($stel,strlen($stel)-5,255);
$data = array(
'kid'=>basKeyid::kidTemp(), 'pid'=>$pid,
'tel'=>$stel, 'msg'=>basReq::in($msg),
'res'=>implode(':',$res),'api'=>$this->api,'amount'=>$nmsg,
);
$data = $data + basSql::logData();
glbDBObj::dbObj()->table('plus_smsend')->data($data)->insert();
// 扣钱 for 0test_balance.txt
if($this->api=='0test' && $res[0]=='1'){
$this->smsdo->deductingCharge($nmsg);
}
}
/** 余额报警检测,余额报警记录
* @param int $flag int/string数字/
* 数字,多少小时被修改(记录了余额不足)过,
* flag=str,记录信息内容
* @return NULL
**/
function balanceWarn($flag){
global $_cbase;
$file = "debug/balance_apiwarn.wlog";
comFiles::chkDirs($file,'dtmp');
if(is_numeric($flag)){ //检查文件,多少时间(day)内修改过
return extCache::cfGet("/$file",'24h');
}else{
$onlineip = $_cbase['run']['userip']; $data = '';
if(file_exists($file)){
$data = comFiles::get($file);
}
$fp = fopen(DIR_VARS."/$file", 'a');
$data = date('Y-m-d H:i:s')."^ ".'mname'." ^ $onlineip \n $flag\r\n\r\n$data";
flock($fp, 2); fwrite($fp, $data); fclose($fp);
}
}
// 电话号码 格式化/过滤
// 初始的电话号码array/string
// 格式化并过滤后的电话号码
function telFormat($tel){
if(is_string($tel)){
$tel = str_replace(array("-","("," ",')'), '', $tel);
$tel = str_replace(array("\r\n","\r","\n",';'), ',', $tel);
$arr = explode(',',$tel);
}else{
$arr = $tel;
}
$arr = array_filter($arr);
$re = array();
for($i=0;$i<count($arr);$i++){
// 手机/^1\d{4,10}$/; 95168合法号码/^[1-9]{1}\d{4,10}$/; 0769-12345678小灵通
if(preg_match('/^\d{5,12}$/',$arr[$i])) $re[] = $arr[$i];
}
return $re;
}
// 短信内容 截取/计数
// param string $msg 初始的短信内容
// param int $slen 最多截取多少文字
// return array $re 返回array(文字,信息条数,文字个数)
function msgCount($msg, $slen=255){
global $_cbase;
$cset = $_cbase['sys']['cset'];
$cnt = mb_strlen($msg, $cset);
if($cnt>255){
$msg = mb_substr($str, 0, 250, $cset);
$cnt = 250;
}
if($cnt>$this->cfg_mchar){ // >70字
$ncnt = ceil($cnt/($this->cfg_mchar-3)); //(70-3)个字算一条信息
}else{
$ncnt = 1;
}
return array($msg,$ncnt,$cnt);
}
// 部分接口有此方法
function chargeUp($charge){
return $this->smsdo->chargeUp($charge);
}
}