短信接口服务运营商以互亿无线为例
1.定义路由
首先定义api路由:routes/api.php
Route::post('sms','SmsController@sms');
Route::post(‘send_sms’,‘SmsController@send_sms’);
2.设置路由
位置:app/Providers/RouteServiceProvider.php
// 项目的路由地址
protected $customNamespace = ‘App\Http\Api’;
protected function mapApiRoutes()
{
Route::prefix(‘api’)
->middleware(‘api’)
->namespace($this->customNamespace)
->group(base_path(‘routes/api.php’));
}
3.创建api文件(创建到app\http\api目录下)
命令:php artisan make:controller App\Http\Api\SmsController
4.创建数据库模型Model
命令:php artisan make:model Model\Sms -m(同时创建Model和对应数据表迁移文件)
<?php
namespace App\Model;
//use Illuminate\Database\Eloquent\Model as SmsModel;
class Sms extends Model
{
protected $table = 'sms';
protected $fillable = ['sms_phone','ver_code','sms_time','sms_count'];
}
$table 模型关联数据表
$fillable 指定字段白名单,只有这个里面的字段才允许操作
}
}
database/migrations/2018_09_11_180044_create_sms_models_table.php内容:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSmsModelsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sms_models', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('tel',11)->comment('电话号码');
$table->string('code')->comment('验证码');
$table->integer('num')->comment('次数');
$table->string('timesms')->comment('时间');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('sms_models');
}
}
在SmsController里面实现逻辑(此接口主要逻辑:接收参数电话号码,按照运营商提供的规则,生成发送短信请求,将电话号码和验证码存入redis里面,设置过期时间:如60s,避免同一个号码反复发送),例如:
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/9/11 0011
* Time: 11:18
*/
namespace App\Http\Api;
use App\Model\TestModel;
use Illuminate\Support\Facades\Redis;
use App\Model\Sms;
//开启SESSION
$GLOBALS['ihuyi']['appid'] = 'C66713053';
$GLOBALS['ihuyi']['appkey'] = '699bfa3db9fbeddda629b1c78b04f890';
$GLOBALS['ihuyi']['sms_send_time'] = 60;
$GLOBALS['ihuyi']['sms_send_num'] = 5;
$GLOBALS['ihuyi']['sms_send_black_time'] = 600;
$GLOBALS['ihuyi']['url'] = "http://106.ihuyi.cn/webservice/sms.php?method=Submit";
$GLOBALS['ihuyi']['is_open_send_limit'] = 1;
class TestController extends Controller
{
public function __construct(){
header("Content-type:text/html; charset=UTF-8");
}
//请求数据到短信接口,检查环境是否 开启 curl init。
private function post($curlPost,$url){
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_NOBODY, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curlPost);
$return_str = curl_exec($curl);
curl_close($curl);
return $return_str;
}
//将 xml数据转换为数组格式。
private function xml_to_array($xml){
$reg = "/<(\w+)[^>]*>([\\x00-\\xFF]*)<\\/\\1>/";
if(preg_match_all($reg, $xml, $matches)){
$count = count($matches[0]);
for($i = 0; $i < $count; $i++){
$subxml= $matches[2][$i];
$key = $matches[1][$i];
if(preg_match( $reg, $subxml )){
$arr[$key] = $this-> xml_to_array( $subxml );
}else{
$arr[$key] = $subxml;
}
}
}
return $arr;
}
//random() 函数返回随机整数。
private function random($length = 6 , $numeric = 0) {
PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000);
if($numeric) {
$hash = sprintf('%0'.$length.'d', mt_rand(0, pow(10, $length) - 1));
} else {
$hash = '';
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789abcdefghjkmnpqrstuvwxyz';
$max = strlen($chars) - 1;
for($i = 0; $i < $length; $i++) {
$hash .= $chars[mt_rand(0, $max)];
}
}
return $hash;
}
//防止恶意攻击
/*private function sms_safe(){
if($GLOBALS['ihuyi']['is_open_send_limit']!=1){
return;
}
if (!empty($_SESSION['sms_send_black']) && $_SESSION['sms_send_black'] + $GLOBALS['ihuyi']['sms_send_black_time'] > time()) {
exit('操作频繁,请'.ceil(($_SESSION['sms_send_black'] + $GLOBALS['ihuyi']['sms_send_black_time'] - time())/60).'分钟后重试');
}
if (empty($_SESSION['sms_send_num'])) {
$_SESSION['sms_send_num'] = 1;
}
if(!empty($_SESSION['sms_send_time']) && $_SESSION['sms_send_time'] + $GLOBALS['ihuyi']['sms_send_time'] > time()){
exit('操作频繁,请'.($_SESSION['sms_send_time'] + $GLOBALS['ihuyi']['sms_send_time'] - time()).'秒后重试');
}
if ($_SESSION['sms_send_num'] > $GLOBALS['ihuyi']['sms_send_num']) {
$_SESSION['sms_send_black'] = time();
unset($_SESSION['sms_send_num']);
unset($_SESSION['sms_send_time']);
exit('发送次数超过限制');
}
}*/
//发送短信验证码
public function send_sms(Request $request){
//获取手机号
$mobile=$request->input('mobile');
if(Redis::exists($mobile)){//判断电话号码是否存在
$data['code']='200';
$data['success']='false';
$data['msg']='请60s后请求接口';
$data['data']=null;
return $data;
}
Redis::setex($mobile,60,'1');//设置过期时间60s过期
// 短信接口地址
$target = $GLOBALS['ihuyi']['url'];
//生成的随机数
$mobile_code = $this->random(6,1);
if(empty($mobile)){
exit('手机号码不能为空');
}
$preg = "/^1[3456789]\d{9}$/";
if (!preg_match($preg, $mobile)) {
exit('手机号码不正确');
}
//防止恶意攻击 session 部分代码最好通过redis代替session实现
// $this->sms_safe();
$content = "您的验证码是:".$mobile_code."。请不要把验证码泄露给其他人。" ;
$post_data = "account=".$GLOBALS['ihuyi']['appid'] ."&password=".$GLOBALS['ihuyi']['appkey'] ."&mobile=".$mobile."&content=".rawurlencode($content);
$sms_phone = Sms::where('sms_phone',$mobile)->get()->toArray();
$gets = $this-> xml_to_array($this->post($post_data, $target));
if($gets['SubmitResult']['code']==2) {
if (empty($sms_phone)) {
Sms::create([
'sms_phone' => $mobile,
'ver_code' => $mobile_code,
'sms_time' => time(),
'sms_count' => 1,
]);
} else {
Sms::where('sms_phone', $mobile)->update([
'ver_code' => $mobile_code,
'sms_time' => time()
]);
Sms::increment('sms_count', 1);
}
}
$data=array([
'code'=>$gets['SubmitResult']['code'],
'msg'=>$gets['SubmitResult']['msg'],
'data'=>null,
]);
return $data;
}
}