<?php
namespace api\components;
use common\helper\CaptchaHelper;
use phpDocumentor\Reflection\Types\True_;
use services\CommonService;
use services\users\UserService;
use share\jobs\users\CommonJobs;
use share\models\Users;
use yii;
use yii\web\Controller;
use yii\web\Response;
use yii\web\HttpException;
use yii\base\UserException;
class ApiController extends Controller
{
private $debug = HT_DEBUG;
protected $needLogin = true;
protected $needSign = true;
protected $userId = 0;
protected $_user ;
protected $params ;
protected $_post ;
protected $format = Response::FORMAT_JSON;
protected $_data = [];
const AUTO_CHECK = false;
protected $_no_encode = [ 'config' , 'error' , 'wechat' ];
// HUATANG_API_SECRET_NEWYEAR
protected $sign_secret = 'HUATANG_API_SECRET' ;
/**
* @var array $_no_catch 不拦截的action列表
* key 为module/controller
* value 为,号拼接的action列表, 如果为空,则controller不需要拦截
*/
protected $_no_catch = [
'user' . D_S . 'attention' => 'news,more,list,scope' ,
];
public $enableCsrfValidation = false;
public function init()
{
parent::init();
// \Yii::$app->cache->flush();
Yii:: $app ->getResponse()->on(Response::EVENT_BEFORE_SEND, [ $this , 'beforeSend' ]);
}
/**
* 尝试次数限制
* 通过ip进行限制
* @param $params
* @param $funcName
* @param int $userId
*/
public function controllerLimit( $params , $funcName , $userId = 0)
{
foreach ( $params as $v ) {
if ( $v [ 'url' ] == $funcName ) {
$this ->tryLimit( $v [ 'url' ], "urlLimit:" . $userId , $v [ 'time_limit' ], $v [ 'try_times' ], $v [ 'time_lock' ]);
}
}
}
/**
* 尝试次数限制
* @param $key
* @param $prefix //前缀,用于跟key组合存redis
* @param $timeLimit // 限制的频率时间
* @param $tryTimes // 限制的次数
* @param $time_lock // 锁死时间
*/
public function tryLimit( $key , $prefix , $timeLimit , $tryTimes , $time_lock )
{
if (Yii:: $app ->redis->exists( $key . ':lock:' . $prefix )) {
return $this -> end ( '亲,操作太频繁,稍后再试!' );
}
$times = Yii:: $app ->redis->get( $key . $prefix ) ?: 0;
if ( $times >= $tryTimes ) {
// 一小时只能获取$tryTimes次
Yii:: $app ->redis->setex( $key . ':lock:' . $prefix , $time_lock , time());
return $this -> end ( '亲,操作太频繁,稍后再试!' );
} else {
Yii:: $app ->redis->setex( $key . $prefix , $timeLimit , $times + 1);
}
}
/*
* 检查是否在不需要拦截的接口列表中
*
* @return bool true=在不需要拦截的接口列表中, false=不在
*/
protected function checkInNoCatch()
{
$moduleID = strtolower (\Yii:: $app ->controller->module->id); // @todo
$controllerID = strtolower (\Yii:: $app ->controller->id);
$controllerID = $moduleID . D_S . $controllerID ;
$actionID = strtolower (\Yii:: $app ->controller->action->id);
if (isset( $this ->_no_catch[ $controllerID ])) {
$actions = $this ->_no_catch[ $controllerID ];
if (! empty ( $actions )) {
$actions = array_flip ( explode ( ',' , $actions ));
if (!isset( $actions [ $actionID ])) {
return false;
}
}
return true;
}
return false;
}
public function beforeAction( $action )
{
$this ->params = $this ->getRequestData();
if ( $this ->checkInNoCatch() || $this ->needLogin == false) {
return true;
} else {
$this ->checkParams([ 'token' , 'platform' ]);
$this ->checkToken( $this ->params[ 'token' ], $this ->params[ 'platform' ]);
}
return true;
}
public function afterAction( $action , $result )
{
}
public function checkToken( $token , $platform )
{
if ( $user_id = UserService::getUserInfoByToken( $token , $platform , 'user_id' )) {
$this ->userId = (int) $user_id ;
// 根据接口频率锁用户
$uri = Yii:: $app ->requestedRoute;
if (in_array( $uri , [
'user/index/info' , 'v2/map/search' , 'map/search'
])) {
$this ->controllerLimit([
// 指定某接口规则
[
'url' => 'user/index/info' ,
'time_limit' => 60, // 频率时长 秒
'try_times' => 2, // 次数
'time_lock' => 86400 * 7, // 秒 用户此接口锁XX秒建议锁到活动结束
],
// [
// 'funciton' => 'v2/map/search',
// 'time_limit' => $time_limit,
// 'try_times' => $try_times,
// ],
// [
// 'funciton' => 'map/search',
// 'time_limit' => $time_limit,
// 'try_times' => $try_times,
// ]
], $uri , $this ->userId);
}
return true;
} else {
return $this -> end ( '请重新登陆' , ErrorCode::ERROR_TOKEN);
}
}
public function render( $err , $msg = '' , $data = null)
{
$ret = [ 'status' => $err , 'msg' => $msg ];
$ret [ 'data' ] = is_null ( $data ) ? (Object)[] : $data ;
if ( empty ( $ret [ 'data' ])) {
unset( $ret [ 'data' ]);
}
return $ret ;
}
public function error( $data , $msg = 'Error' )
{
return $this ->render(ErrorCode::ERROR, $msg , $data );
}
public function success( $data , $msg = 'Success' )
{
return $this ->render(ErrorCode::SUCCESS, $msg , $data );
}
public function getRequestData()
{
$_get = Yii:: $app ->request->getQueryParams();
$_post = Yii:: $app ->request->getBodyParams();
$_data = array_merge ( $_get , $_post );
if ( $_data ) {
$act = Yii:: $app ->controller->id . "/" . Yii:: $app ->controller->action->id;
if (! is_dir (PROJECT_PATH . D_S . 'data' . D_S . 'log' )) {
mkdir (PROJECT_PATH . D_S . 'data' . D_S . 'log' , 0777, true);
}
file_put_contents (PROJECT_PATH . "/data/log/post-" . date ( "y-m-d" ) . ".txt" , date ( 'Y-m-d H:i:s' ) . "[" . $act . "]: " . print_r(json_encode( $_data , JSON_UNESCAPED_UNICODE), true) . "\n" , FILE_APPEND);
if ( $this ->needSign)
$this ->checkSign( $_data );
return $_data ;
}
return false;
}
public function checkParams( $params )
{
}
/**
* 获取客户端ip
* @return string
*/
public function getClientIp()
{
if ( getenv ( 'HTTP_CLIENT_IP' )) {
$ip = getenv ( 'HTTP_CLIENT_IP' );
} else if ( getenv ( 'HTTP_X_FORWARDED_FOR' )) {
$ip = getenv ( 'HTTP_X_FORWARDED_FOR' );
} else if ( getenv ( 'REMOTE_ADDR' )) {
$ip = getenv ( 'REMOTE_ADDR' );
} else {
$ip = $_SERVER [ 'REMOTE_ADDR' ];
}
return $ip ;
}
public function checkSign( $params )
{
}
public function end ( $msg = '' , $code = ErrorCode::ERROR)
{
$response = yii:: $app ->response;
$response ->format = yii\web\Response::FORMAT_JSON;
$response ->data = [ 'status' => $code , 'msg' => $msg ];
$response ->send();
\Yii:: $app -> end ();
}
}
|