Commit cea5a813 authored by 顾文旭's avatar 顾文旭

update

parent aef1482e
composer.lock
/vendor/
.idea
.DS_Store
.project
\ No newline at end of file
生活圈通用业务
负责人:崔伟峰
\ No newline at end of file
{
"name": "api/php_services",
"description": "bp api php_services",
"type": "library",
"require": {
"php": "7.2.*",
"perftools/php-profiler": "^0.18.0",
"endroid/qr-code": "^3.9"
},
"autoload": {
"psr-4": {
"Api\\PhpServices\\": "src/"
}
}
}
<?php
namespace Api\PhpServices\Certification;
class DesEncryptor
{
protected $_key;
protected $_iv;
protected $_blocksize = 8;
protected $_encrypt;
protected $_cipher;
/**
* Creates a symmetric Data Encryption Standard (DES) encryptor object
* with the specified key and initialization vector.
*
* @param $key
* @param $iv
* @param bool $encrypt
*/
public function __construct($key, $iv, $encrypt = true)
{
$this->_key = $key;
$this->_iv = $iv;
$this->_encrypt = $encrypt;
$this->_cipher = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init($this->_cipher, $this->_key, $this->_iv);
}
public function __destruct()
{
mcrypt_generic_deinit($this->_cipher);
mcrypt_module_close($this->_cipher);
}
/**
* Transforms the specified region of the specified byte array using PCKS7 padding.
* @param $text
* @return string
*/
public function transformFinalBlock($text)
{
if ($this->_encrypt)
{
$padding = $this->_blocksize - strlen($text) % $this->_blocksize;
$text .= str_repeat(pack('C', $padding), $padding);
}
$text = $this->transformBlock($text);
if (!$this->_encrypt)
{
$aPadding = array_values(unpack('C', substr($text, -1)));
$padding = $aPadding[0];
$text = substr($text, 0, strlen($text) - $padding);
}
return $text;
}
/**
* Transforms the specified region of the specified byte array.
* @param $text
* @return string
*/
public function transformBlock($text)
{
if ($this->_encrypt)
{
return mcrypt_generic($this->_cipher, $text);
}
return mdecrypt_generic($this->_cipher, $text);
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Certification;
use Api\PhpUtils\Http\Request;
class IdCertification
{
private const key = '_v7QkFPgzb887YD6BuBqzHPJMJalJ6Zt';
private const secret = 'mDenoicZs2U_wd2jVmQQpCOPeM8jaFRu';
public const kuangshi_ocr_url = 'https://api.megvii.com/faceid/v3/ocridcard';
public const kuangshi_get_token = 'https://api.megvii.com/faceid/v3/sdk/get_biz_token';
public const kuangshi_face_compare = 'https://api.megvii.com/faceid/v3/sdk/verify';
/**
* 身份证合法校验
* @param $id_number
* @return bool
*/
public static function checkIdcard (string $id_number) :bool
{
$weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
$codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
if (strlen($id_number) !== 18) {
return false;
}
$validate = substr($id_number, 0, 17);
$sum = 0;
for ($i = 0; $i < 17; $i++) {
$sum += $validate[$i] * $weight[$i];
}
return $codes[$sum % 11] === $id_number[17];
}
/**
* 获取sign
* @param $api_key
* @param $api_secret
* @param $expired
* @file https://faceid.com/pages/documents/37662604
* @return string
*/
private static function genSign($api_key, $api_secret, $expired) :string
{
$rdm = rand();
$current_time = time();
$expired_time = $current_time + $expired;
$srcStr = "a=%s&b=%d&c=%d&d=%d";
$srcStr = sprintf($srcStr, $api_key, $expired_time, $current_time, $rdm);
return base64_encode(hash_hmac('SHA1', $srcStr, $api_secret, true).$srcStr);
}
/**
* 身份证ocr
* @param $posit_image_url string 身份证人头像图片地址
* @param $back_image_url string 身份证国徽像图片地址
* @file https://faceid.com/pages/documents/10881005
* @return array
*/
public function idCardOcr($posit_image_url,$back_image_url) :array
{
if (!empty($posit_image_url)) {
$result_posit = $this->getIdCardOcr($posit_image_url);
}
if (!empty($back_image_url)) {
$result_back = $this->getIdCardOcr($back_image_url);
}
$final['posit'] = self::analysisPositData($result_posit ?? []);
$final['back'] = self::analysisBackData($result_back ?? []);
return $final;
}
/**
* 单次获取 ocr
* @param $image_url
* @param $return_portrait int 设定是否返回身份证上的人像 “0”:不返回 | “1”:返回人像
* @file https://faceid.com/pages/documents/10881005
* @return array
*/
public function getIdCardOcr($image_url,$return_portrait=1)
{
$get = ['api_key' => self::key,'api_secret'=> self::secret, 'return_portrait' => $return_portrait];
$url = self::kuangshi_ocr_url. '?' . http_build_query($get);
$form_data = [
['name' => 'image' , 'contents' => $this->getFile($image_url)]
];
return (new Request())->post($url, $form_data, 3000, 'multipart',[],1);
}
/**
* 并发请求 身份证ocr
* @param $posit_image_url
* @param $back_image_url
* @return mixed
*/
public function mgetIdCardOcr($posit_image_url,$back_image_url)
{
$posit_image_url = $this->getFile($posit_image_url);
$form_data1 = [
['name' => 'api_key', 'contents' => self::key],
['name' => 'api_secret', 'contents' => self::secret],
['name' => 'image' , 'contents' => fopen($posit_image_url,'r')]
];
$form_data2 = [
['name' => 'api_key', 'contents' => self::key],
['name' => 'api_secret', 'contents' => self::secret],
['name' => 'image' , 'contents' => fopen($back_image_url,'r')]
];
$urls = [
0 => self::kuangshi_ocr_url,
1 => self::kuangshi_ocr_url,
];
$params = [
0 => $form_data1,
1 => $form_data2,
];
$timeouts = [
0 => 5000,
1 => 5000
];
$content_types = [
0 => 'multipart',
1 => 'multipart'
];
$result = (new Request())->concurrencyPost($urls,$params , $timeouts, $content_types);
$final['posit'] = self::analysisPositData($result[0]);
$final['back'] = self::analysisBackData($result[1]);
return $final;
}
/**
* 获取 活体检测token
* @param $id_number string 身份证号
* @param $id_card_name string 姓名
* @param $liveness_type string 检测方式 ("still"(静默) / ”meglive”(动作活体)/ ”flash”(炫彩活体))
* @param $biz_no string 业务号
* @param $expired int 签名生效时长 ,单位秒
* @file https://faceid.com/pages/documents/37661898
* @return string | array
*/
public function getBizToken($id_number,$id_card_name,$liveness_type='meglive',$biz_no='merchat',$expired=10)
{
$form_data = [
['name' => 'sign', 'contents' => self::genSign(self::key,self::secret,$expired)],
['name' => 'sign_version', 'contents' => 'hmac_sha1'],
['name' => 'liveness_type', 'contents' => $liveness_type],
['name' => 'comparison_type', 'contents' => '1'],
['name' => 'idcard_name', 'contents' => $id_card_name],
['name' => 'idcard_number', 'contents' => $id_number],
['name' => 'biz_no', 'contents' => $biz_no],
['name' => 'verbose','contents' => '1'],
['name' => 'get_liveness_video', 'contents' => '1']
];
$result = (new Request())->post(self::kuangshi_get_token, $form_data, 1500, 'multipart');
if (isset($result['code'],$result['response']['biz_token']) && $result['code'] === 0) {
return $result['response']['biz_token'];
}
if(isset($result['http_code']) && $result['http_code'] === 400)
{
if(strpos($result['msg'],'BAD_ARGUMENTS: idcard_name')) {
return ['msg' => '姓名不符合规范'];
}
}
return '';
}
/**
* 人脸比对接口
* @param $biz_token
* @param $meglive_data_url
* @param int $expired
* @file https://faceid.com/pages/documents/37662519
* @return array|mixed
*/
public function verify($biz_token,$meglive_data_url,$expired=10)
{
$form_data = [
['name' => 'sign' , 'contents' => self::genSign(self::key,self::secret,$expired)],
['name' => 'sign_version', 'contents' => 'hmac_sha1'],
['name' => 'biz_token', 'contents' => $biz_token],
['name' => 'meglive_data', 'contents' => $this->getFile($meglive_data_url)]
];
$result = (new Request())->post(self::kuangshi_face_compare, $form_data, 3000, 'multipart',[],1);
if (isset($result['code'], $result['response']) && $result['code'] === 0) {
return $result['response'];
}
return $result['msg']?? '活体检测失败';
}
/**
* 返回文件句柄
* @param $file
* @return bool|false|string
*/
private function getFile($file)
{
if (strpos($file, 'http') === false && !file_exists($file)) {
return false;
}
//获取文件内容
$file_content = fopen($file,'r');
if ($file_content === false) {
return false;
}
return $file_content;
}
/**
* 解析人头像 数据
* @param $ocr_data
* @return array
*/
private static function analysisPositData($ocr_data)
{
$final_data['name'] = $ocr_data['response']['name']['result'] ?? '';
$final_data['gender'] = $ocr_data['response']['gender']['result'] ?? '';
$final_data['address'] = $ocr_data['response']['address']['result'] ?? '';
$final_data['idcard_number'] = $ocr_data['response']['idcard_number']['result'] ?? '';
$final_data['birth_month'] = $ocr_data['response']['birth_month']['result'] ?? '';
$final_data['birth_day'] = $ocr_data['response']['birth_day']['result'] ?? '';
$final_data['nationality'] = $ocr_data['response']['nationality']['result'] ?? '';
$final_data['birth_year'] = $ocr_data['response']['birth_year']['result'] ?? '';
$final_data['completeness'] = $ocr_data['response']['completeness'] ?? -1;
$final_data['legality'] = $ocr_data['response']['legality'] ?? (object)[];
$final_data['code'] = $ocr_data['response']['code'] ?? -1;
return $final_data;
}
/**
* 解析国徽面数据
* @param $ocr_data
* @return array
*/
private static function analysisBackData($ocr_data)
{
$final_data['valid_date_start'] = $ocr_data['response']['valid_date_start']['result'] ?? '';
$final_data['issued_by'] = $ocr_data['response']['issued_by']['result'] ?? '';
$final_data['valid_date_end'] = $ocr_data['response']['valid_date_end']['result'] ?? '';
$final_data['completeness'] = $ocr_data['response']['completeness'] ?? -1;
$final_data['legality'] = $ocr_data['response']['legality'] ?? (object)[];
$final_data['code'] = $ocr_data['response']['code'] ?? -1;
return $final_data;
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Certification;
class PbeWithMd5AndDes
{
/**
* "Magic" keyword used by OpenSSL to put at the beginning of the encrypted
* bytes.
*/
private static $MAGIC_SALTED_BYTES = "Salted__";
private static function _getCharRandonSalt($length = 16): string
{
$salt = '';
for ($n = 0; $n < $length; $n++) {
$salt .= dechex(mt_rand(0, 0xF));
}
return $salt;
}
public static function encrypt($data, $keystring, $salt = null, $iterationsMd5 = 1, $segments = 1)
{
$useRandomSalt = false;
if ($salt === null) {
$salt = self::_getCharRandonSalt();
$useRandomSalt = true;
/**
* Number of iterations -
* needs to be set to 1 for our roundtrip to work.
*/
$iterationsMd5 = 1;
}
$pkcsKeyGenerator = new PkcsKeyGenerator(
$keystring, $salt, $iterationsMd5, $segments);
$encryptor = new DesEncryptor(
$pkcsKeyGenerator->getKey(), $pkcsKeyGenerator->getIv());
$crypt = $encryptor->transformFinalBlock($data);
if ($useRandomSalt) {
// add the magic keyword, salt informazionr and encrypted byte
$crypt = self::$MAGIC_SALTED_BYTES .
pack("H*", $salt) .
$crypt;
}
// base64 encode so we can send it around as a string
return base64_encode($crypt);
}
public static function decrypt($data, $keystring, $salt = null, $iterationsMd5 = 1, $segments = 1)
{
if ($salt === null) {
// get the salt information from the input
$salt = bin2hex(substr(base64_decode($data), 8, 8));
$data = base64_encode(substr(base64_decode($data), 16));
/**
* Number of iterations -
* needs to be set to 1 for our roundtrip to work.
*/
$iterationsMd5 = 1;
}
$pkcsKeyGenerator = new PkcsKeyGenerator(
$keystring, $salt, $iterationsMd5, $segments);
$encryptor = new DesEncryptor(
$pkcsKeyGenerator->getKey(), $pkcsKeyGenerator->getIv(), false);
return $encryptor->transformFinalBlock(base64_decode($data));
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Certification;
class PkcsKeyGenerator
{
protected $_key;
protected $_iv;
/**
* @return string
*/
public function getKey()
{
return $this->_key;
}
/**
* Gets the initialization vector.
* @return string
*/
public function getIv()
{
return $this->_iv;
}
public function __construct($keystring, $salt, $iterationsMd5, $segments)
{
$salt = pack('H*', $salt);
$keyMaterial = '';
$data = $keystring . $salt;
$result = '';
for ($j = 0; $j < $segments; $j++)
{
if ($j === 0)
{
$result = $data;
}
else
{
$result .= $data;
}
for ($i = 0; $i < $iterationsMd5; $i++)
{
$result = md5($result, true);
}
$keyMaterial .= $result;
}
$this->_key = substr($keyMaterial, 0, 8);
$this->_iv = substr($keyMaterial, 8, 8);
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Certification;
use Api\PhpUtils\Http\Request;
class SocialCreditCertification
{
private const account = 'BJyimingzhineng';
private const app_key = 'deee9c9877e5452f8838cfc5130ac5ad';
public const ocr_bussiness_url = 'http://apistore.xmturui.com/apistore/ocr-new';
private const engine_type = 'blic-new';
/**
* 校验社会统一信用代码格式是否合法
* @param $social_creadit_code
* @return bool
*/
public static function checkSocialCredit(string $social_creadit_code) :bool
{
$one = '159Y';//第一位可以出现的字符
$two = '12391';//第二位可以出现的字符
$str = strtoupper($social_creadit_code);
if (strpos($one, $str[1]) === false && strpos($two, $str[2]) === false && !empty($array[substr($str, 2, 6)])) {
return false; //有误
}
$wi = array(1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28);//加权因子数值
$str_organization = substr($str, 0, 17);
$num = 0;
for ($i = 0; $i < 17; $i++) {
$num += self::transformation($str_organization[$i]) * $wi[$i];
}
switch ($num % 31) {
case '0':
$result = 0;
break;
default:
$result = 31 - $num % 31;
break;
}
if ($str[strlen($str) - 1] === self::transformation($result, true)) {
return true;
}
return false;
}
private static function transformation($num, $status = false)
{
$list = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'J' => 18, 'K' => 19, 'L' => 20, 'M' => 21, 'N' => 22, 'P' => 23, 'Q' => 24, 'R' => 25, 'T' => 26, 'U' => 27, 'W' => 28, 'X' => 29, 'Y' => 30);//值转换
if ($status === true) {
$list = array_flip($list);
}
return $list[$num];
}
/**
* 营业执照ocr 识别
* @param $business_image string image_url
* @return array
*/
public function businessLicenseOcr($business_image)
{
$base64_image = self::imgBase64Encode($business_image);
if ($base64_image === false) {
return ['code'=>-1];
}
$post_data = [
'account' => self::account,
'key' => self::app_key,
'enginetype' => self::engine_type,
'databaseImageContent' => $base64_image
];
$result = (new Request())->post(self::ocr_bussiness_url, $post_data, 5000, 'json',[],0);
if (isset($result['code'],$result['response']) && $result['code'] === 0 ) {
return $result['response'];
}
return ['code'=>-1];
}
/**
* base64_encode_image
* @param string $img
* @return bool|string
*/
public static function imgBase64Encode($img = '')
{
if (strpos($img, 'http') === false && !file_exists($img)) {
return false;
}
//获取文件内容
$file_content = file_get_contents($img);
if ($file_content === false) {
return false;
}
return chunk_split(base64_encode($file_content));
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Certification;
use Api\PhpUtils\Http\Request;
class ThreeElementsCertification
{
private const app_key = '392df35aa98721c597cf20b85d21eebc';
//运营商三要素检测接口
public const test_mobile3_ele_Sim_url = 'https://api.goodsdatas.com:8443/credit/Mobile3EleSim';
//加密需要的相关参数
private const salt = 'A99BC8325635E303';
private const iterations = 2;
private const segments = 1;
/**
* 运营商三要素检测
* @param $mobile_num
* @param $id_num
* @param $name
* @return array
*/
public function mobile3EleSimCheck($mobile_num,$id_num,$name)
{
$encry_data = sprintf('idCard=%s&name=%s&mobile=%s',$id_num,$name,$mobile_num);
$crypt = PbeWithMd5AndDes::encrypt(
$encry_data, self::app_key,
self::salt, self::iterations, self::segments
);
$query = [
'rettype' => 'json',
'encryptParam' => $crypt
];
$result = (new Request())->get(self::test_mobile3_ele_Sim_url.'/'.self::app_key,$query,4000,[],1);
if (isset($result['code']) && $result['code'] === 0) {
return $result['response'];
}
return ['code'=>-1];
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Daemon;
use Api\PhpUtils\Cache\ApcuUtil;
use Api\PhpUtils\Log\DaemonLog;
use Api\PhpUtils\Message\Email;
use Yaf\Application;
class Daemon
{
/**
* 任务名
* @var string
*/
protected $task_name;
protected $task_class;
const MAX_WORKER_PROCESS_NUMBER = 16;
const MAX_WORKER_EXECUTE_TIMES = 1000;
protected $process_list = false;
protected $max_process_num = 0;
protected $current_process_num = 0;
protected $matser_process_id = false;
protected $output = false;
protected $terminate = false;
protected $log_signature = "daemon";
protected $env = "dev";
protected $exception_time_cycle = 120; // 脚本异常记录时间周期
protected $exception_save_time = 10; // 异常时间周期内,记录前 n 条到错误日志
protected $exception_alert_time = 100; // 异常时间周期内,超过 n 次异常则邮件报警
public function __construct(string $task_name, $task_class, int $worker_num = 1, array $params =[])
{
$this->checkEnv();
if( $worker_num > self::MAX_WORKER_PROCESS_NUMBER )
{
die("worker进程最大限制为".self::MAX_WORKER_PROCESS_NUMBER."\n");
}
if( !class_exists($task_class) ){
die("任务不存在"."\n");
}
$this->task_name = $task_name;
$this->params = $params;
$this->task_class = $task_class;
$this->max_process_num = $worker_num;
$this->env = Application::app()->environ() ?? "dev";
$this->set_base_config();
if(function_exists('gc_enable')) gc_enable();
}
public static function run(){
throw new \Exception("bbb");
}
/**
* 启动守护进程,并在master进行中监听子进程状态,当子进程退出后重新启动新的子进程( 保持worker进程数为max_process_num )
* 若要结束守护进程可向主进程发送kill -SIGUSR1的信号,子进程完成当前工作后会逐个退出
*/
public function start(){
DaemonLog::info($this->log_signature,'process start now');
$this->daemon();
for($i=0; $i<$this->max_process_num; $i++) {
$this->worker();
}
while(1)
{
//注册信号处理,master进程中捕获SIGUSR1后通知worker进程退出
if( !pcntl_signal(SIGUSR1, array(__CLASS__, "signal_handler"),false) ) {
DaemonLog::error($this->log_signature,'master pcntl SIGUSR1 failed');
}
pcntl_signal_dispatch();
$pid = pcntl_wait($status, WUNTRACED); //阻塞取得子进程结束状态
if( ($key = array_search($pid, $this->process_list)) !==false )
{
$this->current_process_num--;
unset($this->process_list[$key]);
$this->process_list = array_values($this->process_list);
// DaemonLog::info($this->log_signature,"worker process: {".$pid."} exited with {$status}");
if( $this->terminate == false )
{
if( $this->current_process_num < $this->max_process_num )
{
$this->worker();
}
}else
{
if( $this->current_process_num == 0 )
{
break;
}
}
}
}
DaemonLog::info($this->log_signature,"shut down success");
exit(0);
}
protected function daemon()
{
set_time_limit(0);
$pid = pcntl_fork();
if($pid == -1)
{
die('Could not fork 1');
}
if ($pid != 0){ //父进程
exit(0);
}
posix_setsid(); //设置新会话组长,脱离终端
$pid = pcntl_fork();
if($pid == -1)
{
die('Could not fork 2');
}
if ($pid != 0) //第一子进程
{
DaemonLog::info($this->log_signature,'master process pid:'.$pid);
exit(0);
}
chdir(ROOT_PATH);
umask(0);
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$this->matser_process_id = posix_getgid();
// mac 系统不支持此函数,调试时关闭
cli_set_process_title($this->task_name.' '.$this->env.' master process');
}
/**
* 启动worker进程
* @Author wangdanfeng
* @return void
*/
protected function worker()
{
$pid = pcntl_fork();
if( $pid == -1 ) {
DaemonLog::error($this->log_signature,'worker Process fork failed');
}elseif ($pid == 0) {
//子进程
cli_set_process_title($this->task_name . ' ' . $this->env . ' worker process');
DaemonLog::info($this->log_signature,"worker Process {".posix_getpid()."} was created".' master process id:'.posix_getppid());
//注册子进程信号
if( !pcntl_signal(SIGUSR2, array(__CLASS__, "signal_handler"),false) )
{
DaemonLog::error( $this->log_signature ,"worker Process {".posix_getpid()."} pcntl SIGUSR2 failed".' master process id:'.posix_getppid() );
}
// 执行指定次数后自动退出
for ($i=0; $i <self::MAX_WORKER_EXECUTE_TIMES ; $i++)
{
pcntl_signal_dispatch();
try {
$task = new $this->task_class(...$this->params);
$task->run();
}catch (\Exception $e){
// 默认2分钟内最多记录10条异常日志,超过100次则报警
$exception_num = ApcuUtil::apcu_inc($this->log_signature, posix_getppid(),1,$success, $this->exception_time_cycle);
if($success && $exception_num){
if($exception_num < $this->exception_save_time+1){
DaemonLog::error( $this->log_signature ,"worker Process {".posix_getpid()."} throw exception! msg: ".$e->getMessage().' master process id:'.posix_getppid() );
}elseif ($exception_num == $this->exception_alert_time){
$subject= "Daemon 任务异常";
$mail_body = '任务在'.$this->exception_time_cycle.'秒内异常次数达到'.$this->exception_alert_time.'次,请及时处理。'."\r\n" .
'time: ' . date('Y-m-d H:i:s') . "\r\n" .
'task_name: ' . $this->task_name . "\r\n" .
'task_class: ' . $this->task_class . "\r\n" .
'host name: ' . gethostname() . "\r\n";
// $to = 'api@yidian-inc.com';
$to = 'zhangyu1@yidian-inc.com';
Email::sendMail('bp-noreply@yidian-inc.com', $to, $subject, $mail_body);
}
}
}
if($this->terminate==true)
{
exit(0);
}
}
exit(0);
}else
{
$this->process_list[] = $pid;
$this->current_process_num++;
return;
}
}
protected function quit()
{
DaemonLog::info( $this->log_signature ,"process shut down" );
$this->terminate = true;
foreach ($this->process_list as $pid)
{
if( !posix_kill($pid, SIGUSR2) ) {
DaemonLog::error( $this->log_signature ,'master process send SIGUSR2 to '.$pid.' failed' );
}
}
}
/**
* 目前仅支持退出所有进程,后续待完善
* @Author wangdanfeng
* @param [type] $signal [description]
* @return [type] [description]
*/
protected function signal_handler($signal)
{
switch ($signal)
{
case SIGUSR1: //父进程监听信号
$this->quit();
break;
case SIGUSR2: //子进程监听信号
$this->terminate = true;
break;
default:
# code...
break;
}
}
/**
* 运行环境检查
* @Author wangdanfeng
* @return void
*/
protected function checkEnv()
{
php_sapi_name() == "cli" or die("只允许在cli下面运行"."\n");
PHP_VERSION_ID >= 50330 or die("php版本需大于5.3.3"."\n");
function_exists('pcntl_signal') or die("请安装pcntl扩展"."\n");
function_exists('posix_getpid') or die("请安装posix扩展"."\n");
}
/**
* 基本配置
*/
protected function set_base_config(){
ini_set("display_errors", 1);
ini_set('date.timezone','Asia/Shanghai');
ini_set("memory_limit", '2048M');
error_reporting(E_ALL);
//日志存储到 php-error.log
/*
//创建任务日志文件
$log_dir = ROOT_PATH.'/logs/daemon/'.$this->task_name;
$log_path = $log_dir.'/'.$this->task_name.'.log';
ini_set('error_log',$log_path );
if( !file_exists($log_path) )
{
mkdir($log_dir, 0777, true);
if( !touch( $log_path ) )
{
die($log_path."文件无法创建"."\n");
}
}
*/
$this->log_signature = "daemon:".$this->task_name;
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Daemon;
interface DaemonServiceInterface
{
public function run();
}
\ No newline at end of file
This diff is collapsed.
<?php
namespace Api\PhpServices\Idgen;
use Api\PhpUtils\Http\Request;
class Idgen
{
public static function get($partner, $key, $id_snow=[], $id_datetime=[]){
$url = config('interface','service.idgen');
$params = [];
$params['partner'] = $partner;
$params['key'] = $key;
if(!empty($id_snow)){
$params['id_snow'] = $id_snow;
}
if(!empty($id_datetime)){
$params['id_datetime'] = $id_datetime;
}
$res = (new Request())->post($url, $params,5000, 'json');
if(isset($res['code']) && $res['code']==0 && isset($res['response']['result'])){
return $res['response']['result'] ?? [];
}
return [];
}
}
\ No newline at end of file
<?php
/**
* Description of JwUser.php
*
* @author haiming
* Date: 2021/5/21
* Time: 10:32 PM
*/
namespace Api\PhpServices\JwUser;
use Api\PhpUtils\Common\TimeOut;
use Api\PhpUtils\Http\Request;
use App\Exception\custom\CodeSpecialException;
use Api\PhpUtils\Log\FileLog;
use Api\PhpUtils\Mon\MonUtil;
class JwUser
{
/**
* 获取简网用户信息
*
*@param $params['mobile'] 手机号
*
*/
public function getUserInfo($params)
{
$url = config('interface', 'service.jw_user.get_user_info');
if (!$url) {
throw new CodeSpecialException("failed");
}
if (empty($params['mobile'])) {
throw new CodeSpecialException("failed");
}
$params = ["mobilePhone" => $params['mobile']];
//$user_info = (new TimeOut())->runGet($url, $params);
$user_info = (new Request())->get($url, $params);
FileLog::info('jw_user_getUserInfo', json_encode($user_info));
if (!$user_info) {
throw new CodeSpecialException("timeout");
}
return !empty($user_info['response']) ? $user_info['response'] : [];
}
/**
* 获取单条信息
*
*/
public function getUserByUserId($params)
{
$url = config('interface', 'service.jw_user.get_user_info_by_user_id');
if (!$url) {
throw new CodeSpecialException("failed");
}
if (empty($params['user_id'])) {
throw new CodeSpecialException("failed");
}
$params = ["userId" => $params['user_id']];
//$user_info = (new TimeOut())->runPost($url, $params);
$begin = microtime(true);
$user_info = (new Request())->post($url, $params);
$end = microtime(true);
$total_time = round(($end - $begin), 4) * 1000;
if (!empty($user_info['response'])) {
$code = $user_info['response']['code'];
} else {
$code = -1;
}
MonUtil::proxyMon($url, $code, 'jw_user', $total_time);
FileLog::info('jw_user_getUserByUserId', json_encode($user_info));
if (!$user_info) {
throw new CodeSpecialException("timeout");
}
return !empty($user_info['response']) ? $user_info['response'] : [];
}
public function getUserList($params)
{
$url = config('interface', 'service.jw_user.get_user_list');
if (!$url) {
throw new CodeSpecialException("failed");
}
if (empty($params['user_id'])) {
throw new CodeSpecialException("failed");
}
$params = ["userIds" => $params['user_id']];
//$user_info = (new TimeOut())->runPost($url, $params);
$user_info = (new Request())->post($url, $params, 0, '', '', 0, true, 'jw_user');
FileLog::info('jw_user_getUserList', json_encode($user_info));
if (!$user_info) {
throw new CodeSpecialException("timeout");
}
return !empty($user_info['response']) ? $user_info['response'] : [];
}
/**
* 获取城市树接口
*
*
*/
public function getAllCityTree()
{
$url = config('interface', 'service.jw_user.get_all_city_tree');
if (!$url) {
throw new CodeSpecialException("failed");
}
$params = [];
//$city_list = (new TimeOut())->runGet($url, $params);
$city_list = (new Request())->get($url, $params);
FileLog::info('jw_user_getAllCityTree', json_encode($city_list));
if (!$city_list) {
throw new CodeSpecialException("timeout");
}
return !empty($city_list['response']) ? $city_list['response'] : [];
}
/**
* 保存用户与token的对应关系接口
* 支持的token prefix:MMPP 小米推送,UMPP 友盟推送,GTPP 个推
*
*/
public function savePushToken($params)
{
$url = config('interface', 'service.jw_user.save_push_token');
if (!$url) {
throw new CodeSpecialException("failed");
}
if (empty($params)) {
throw new CodeSpecialException("failed");
}
//$pushToken = (new TimeOut())->runPost($url, $params);
$pushToken = (new Request())->post($url, $params, 0, '', '', 0, true, 'jw_user');
FileLog::info('jw_user_savePushToken', json_encode($pushToken));
if (!$pushToken) {
throw new CodeSpecialException("timeout");
}
return !empty($pushToken['response']) ? $pushToken['response'] : [];
}
/**
* 获取简网用户动态
*/
public static function getUserListWithDynamic($params)
{
$url = config('interface', 'service.jw_user.get_user_dynamic');
if (!$url) {
throw new CodeSpecialException("failed");
}
if (empty($params['user_id'])) {
throw new CodeSpecialException("failed");
}
$params = ["userIds" => $params['user_id']];
//$list = (new TimeOut())->runPost($url, $params);
$list = (new Request())->post($url, $params, 0, '', '', 0, true, 'jw_user');
FileLog::info('jw_user_getUserListWithDynamic', json_encode($list));
if (!$list) {
throw new CodeSpecialException("timeout");
}
return !empty($list['response']) ? $list['response'] : [];
}
/**
* 获取简网用户历史赞
*/
public static function getUserDigg($params)
{
$url = config('interface', 'service.jw_user.get_user_digg');
if (!$url) {
throw new CodeSpecialException("failed");
}
if (empty($params['user_id'])) {
throw new CodeSpecialException("failed");
}
$params = ["userId" => $params['user_id']];
//$list = (new TimeOut())->runPost($url, $params);
$list = (new Request())->post($url, $params, 0, '', '', 0, true, 'jw_user');
FileLog::info('jw_user_getUserDigg', json_encode($list));
if (!$list) {
throw new CodeSpecialException("timeout");
}
return !empty($list['response']) ? $list['response'] : [];
}
/**
* 给简网同步生活号
*/
public static function saveUpdateLife($params)
{
$url = config('interface', 'service.jw_user.save_update_life');
if (!$url) {
throw new CodeSpecialException("failed");
}
//$ret = (new TimeOut())->runPost($url, $params);
$ret = (new Request())->post($url, $params, 0, '', '', 0, true, 'jw_user');
FileLog::info('jw_user_saveUpdateLife', json_encode($ret));
if (!$ret) {
throw new CodeSpecialException("timeout");
}
return !empty($ret['response']) ? $ret['response'] : [];
}
/**
* 获取简网微信openid
*/
public static function getWechatOpenid($params)
{
$url = config('interface', 'service.jw_user.get_wechat_openid');
if (!$url) {
throw new CodeSpecialException("failed");
}
//$ret = (new TimeOut())->runPost($url, $params);
$ret = (new Request())->post($url, $params, 0, '', '', 0, true, 'jw_user');
FileLog::info('getWechatOpenid', json_encode($ret));
if (!$ret) {
throw new CodeSpecialException("timeout");
}
return !empty($ret['response']) ? $ret['response'] : [];
}
}
use Api\PhpServices\JwUser\JwUser;
//获取简网用户信息
$jwUser = new JwUser();
$params = [
'mobile' => 13800000000
];
$user_info = $jwUser->getUserInfo($params);
//单个获取
$params = [
'user_id' => 100000000
];
$user_info = $jwUser->getUserByUserId($params);
//批量获取
$params = [
'user_id' => 100000,20000,30000
];
$user_info = $jwUser->getUserList($params);
<?php
namespace Api\PhpServices\Ksy;
use Api\PhpUtils\Http\HttpUtil;
use Api\PhpUtils\Mon\MonUtil;
/**
* 文档: http://ydwiki.yidian-inc.com/pages/viewpage.action?pageId=68515904
* Class Ks3Api
* @package Api\PhpServices\Ksy
*/
class Ks3Api
{
const KSYUN_SK = "3wm9z0P0ja6NceaZYf477EDZrJs7dSSZ";
const KSYUN_AK = "47DA6034D64E7023";
const KS_DATE_SCHEME = 'D, d M Y H:i:s \G\M\T';
const BASE_URL = "http://image-upload.int.yidian-inc.com";
const BASE_GEN_URL = "http://image-urlgen.int.yidian-inc.com";
const PATH_GEN = "/v1/key/gen";
const PATH_SIGNATURE = "/v1/ks3/signature";
const PATH_PIC_ENCRYPT_URL = "/v1/url/gen";
const PATH_PIC_UPLOAD = "/upload";
const AUDIT_ID = "shqbp";
const TYPE_QUALIFICATION = "shq_qualification";//商户资质
const TYPE_GOODS = "shq_goods";//商品图片
public static $typeList = [
self::TYPE_QUALIFICATION,
self::TYPE_GOODS
];
/**
* 获取bucket与objectKey
* @param $type
* @return mixed
*/
public static function gen($type)
{
$url = self::BASE_URL . self::PATH_GEN;
$timestamp = self::msectime();
$md5Str = $type . "&" . $timestamp . "&" . self::KSYUN_SK;
$signature = self::KSYUN_AK . ":" . md5($md5Str);
$params = [
"timestamp" => $timestamp,
"signature" => $signature,
"type" => $type,
];
$begin = microtime(true);
$genRes = HttpUtil::post($url, $params);
$end = microtime(true);
$totalTime = round(($end - $begin), 4) * 1000;
$resCode = $genRes["response"]['code'] === 0 ? 200 : $genRes["response"]['code'];
MonUtil::proxyMon($url, $resCode, 'ks3api', $totalTime);
return $genRes;
}
/**
* 获取KS签名
* @param $resource
* @param $httpMethod
* @param $contentType
* @param $contentMd5
* @param $headers
* @return array
*/
public static function signature($resource, $httpMethod, $contentType, $contentMd5, $headers, $date)
{
$url = self::BASE_URL . self::PATH_SIGNATURE;
$timestamp = self::msectime();
$md5Str = $httpMethod . "&" . $contentType . "&" . $contentMd5 . "&" . $date . "&" . $resource . "&" . $headers . "&" . $timestamp . "&" . self::KSYUN_SK;
$signature = self::KSYUN_AK . ":" . md5($md5Str);
$params = [
"timestamp" => $timestamp,
"signature" => $signature,
"http_method" => $httpMethod,
"content_type" => $contentType,
"date" => $date,
"content_md5" => $contentMd5,
"resource" => $resource,
"headers" => $headers,
];
$begin = microtime(true);
$signatureRes = HttpUtil::post($url, $params);
$end = microtime(true);
$totalTime = round(($end - $begin), 4) * 1000;
$resCode = $signatureRes["response"]['code'] === 0 ? 200 : $signatureRes["response"]['code'];
MonUtil::proxyMon($url, $resCode, 'ks3api', $totalTime);
return $signatureRes;
}
/**
* 生成图片访问加密链接
* @param $imageId
* @param $authId
* @param $widthSize
* @param $highSize
* @param int $expirationTime
* @return mixed
*/
public static function picEncryptUrl($imageId, $widthSize = 0, $highSize = 0, $expirationTime = 60 * 60 * 24 * 365)
{
$url = self::BASE_GEN_URL . self::PATH_PIC_ENCRYPT_URL;
$timestamp = self::msectime();
$extend = [];
$extend["expiration_time"] = $expirationTime;
if (!empty($widthSize) && !empty($highSize)) {
$extend["query"] = "type=thumbnail_" . $widthSize . "x" . $highSize;
}
$extendJsonStr = json_encode($extend);
$md5Str = $extendJsonStr . "&" . $imageId . "&" . self::AUDIT_ID . "&" . $timestamp . "&" . self::KSYUN_SK;
$signature = self::KSYUN_AK . ":" . md5($md5Str);
$contentType = 'multipart/form-data';
$params = [
"image_id" => $imageId,
"auth_id" => self::AUDIT_ID,
"timestamp" => $timestamp,
"signature" => $signature,
"content_type" => $contentType,
"extend" => $extendJsonStr,
];
$begin = microtime(true);
$encryptRes = HttpUtil::post($url, $params);
$end = microtime(true);
$totalTime = round(($end - $begin), 4) * 1000;
$resCode = $encryptRes["response"]['code'] === 0 ? 200 : $encryptRes["response"]['code'];
MonUtil::proxyMon($url, $resCode, 'ks3api', $totalTime);
return $encryptRes;
}
/**
* 上传图片
* @param int $type
* @return mixed
*/
public static function upload($type)
{
$url = self::BASE_URL . self::PATH_PIC_UPLOAD;
$timestamp = self::msectime();
$handle = fopen($_FILES['file']['tmp_name'], 'r');
$content = fread($handle, filesize($_FILES['file']['tmp_name']));
$extend = ["type" => $type];
$extendJsonStr = json_encode($extend);
$md5Str = $extendJsonStr . "&" . md5($content) . "&" . $timestamp . "&" . self::KSYUN_SK;
$signature = self::KSYUN_AK . ":" . md5($md5Str);
$params = [
"pic" => new \CURLFile($_FILES['file']['tmp_name'], $_FILES['file']['type']),
"timestamp" => $timestamp,
"signature" => $signature,
"extend" => $extendJsonStr,
];
$begin = microtime(true);
$uploadRes = HttpUtil::post($url, $params);
$end = microtime(true);
$totalTime = round(($end - $begin), 4) * 1000;
$resCode = $uploadRes["response"]['code'] === 0 ? 200 : $uploadRes["response"]['code'];
MonUtil::proxyMon($url, $resCode, 'ks3api', $totalTime);
return $uploadRes;
}
/**
* 时间戳(毫秒)
* @return float
*/
private static function msectime()
{
list($msec, $sec) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Ksy;
use Api\PhpUtils\Http\Request;
use Api\PhpUtils\Mon\MonUtil;
class Ksyun
{
private const jinshan_ak = 'AKLTnATdoXUnR72IDSGgN2WSOQ'; //AccessKey
private const jinshan_sk = 'OMw7UAOkrLVsRevuP44ctAlfzriDzUm9+JvOFoYuiSoLgaLJWi+kjUa+4G3EWXFakQ=='; //SecretKey
private const bp_bucket = 'bp-yidian';
private const bp_image_yidian = 'bp-image-yidian';
private const get_down_from_ksyun = 'http://video-stream-service.int.yidian-inc.com/auth/url-get';
private const get_down_from_pic_service = 'https://ibp.go2yd.com/imagebp.php'; //来自图片服务
public const scenario_id_card = 'id_card';
public const scenario_living_data = 'living_data';
public const scenario_living_business_license = 'business_license';
public const scenario_living_goods = 'goods';
public const scenario_living_goods_temp = 'goods_temp'; //商品图片临时方案
/**
* 支持批量
* 根据 object_id 从视频团队 获取下载地址 负责人钱昊
* @param $object_ids array ["90.mp4", "17.mp4"]
* @param $appid string 区分不同业务方
* @param $bucket string
* @param $expire_time
* @return array
*/
public static function getDownUrl(array $object_ids,$appid,$bucket,$expire_time=60)
{
if (empty($object_ids)) {
return [];
}
$object_ids = array_values(array_filter($object_ids));
$post_data = [
'keys' => $object_ids,
'from' => $appid,
'bucket' => $bucket,
'expire' => $expire_time,
];
$begin = microtime(true);
$res = (new Request())->post(self::get_down_from_ksyun, $post_data,50, 'json',[],1,true);
$end = microtime(true);
$total_time = round(($end - $begin),4) * 1000;
if(isset($res['response']['code'])){
$code = $res['response']['code'];
}else{
$code = -1;
}
MonUtil::proxyMon(self::get_down_from_ksyun, $code, 'merchant', $total_time);
if (isset($res['code'],$res['response']['status']) && $res['response']['status'] === 'success') {
return $res['response']['data'];
}
return [];
}
/**
*
* @param $url
* @param $appid
* @param int $expire_time
* @param string $scenario
* @return mixed|string
*/
public static function getUrlFromKsyn($url,$appid,$expire_time=60)
{
$del_str = explode('/',$url);
$bucket = $del_str[0] ?? '';
$objectid = $del_str[1] ?? '';
$image_url = self::getDownUrl([$objectid],$appid,$bucket,$expire_time);
if (empty($image_url) || (!isset($image_url[$objectid]) )
) {
return '';
}
return $image_url[$objectid];
}
/**
* 根据金山云文档 生成token
* @param $http_method
* @param $date
* @param $resource
* @param string $headers
* @param string $content_md5
* @param string $content_type
* @file https://docs.ksyun.com/documents/6890
* @return string
*/
public function getToken($http_method,$date,$resource,$headers='',$content_md5='',$content_type='') :string
{
if (!empty($headers))
{
$headers .= "\n";
}
$StringToSign = $http_method . "\n"
. $content_md5 . "\n"
. $content_type . "\n"
. $date . "\n"
. $headers
. $resource;
$signature = base64_encode(hash_hmac('sha1', $StringToSign, self::jinshan_sk, true));
$signature = 'KSS ' . self::jinshan_ak . ':' . $signature;
return $signature;
}
/**
* @param string $appid 应用
* @param $scenario
* @param $http_method
* @param $date
* @param $resource
* @param string $headers
* @param string $content_md5
* @param string $content_type
* @return string
*/
public function getTokenV2($appid,$scenario,$http_method,$date,$resource,$headers='',$content_md5='',$content_type='') : string
{
return $this->getToken($http_method,$date,$resource,$headers,$content_md5,$content_type);
}
/**
* 返回bucket
* @param $appid
* @param $scenario string 区分业务场景
* @return string
*/
public static function getBucket($appid,$scenario) :string
{
if ($appid === 'merchant-b' || $appid === 'merchant-c') {
if ($scenario === self::scenario_living_goods) {
return self::bp_image_yidian;
}
if (in_array($scenario,[self::scenario_id_card,self::scenario_living_business_license,self::scenario_living_data])) {
return self::bp_bucket;
}
}
return '';
}
/**
* 生成objectid 和 bucket
* @param $appid
* @param $scenario string 区分业务场景
* @return array
*/
public static function getObjectAndBucket($appid,$scenario):array
{
return ['bucket' => self::getBucket($appid,$scenario),'objectId' => md5(uniqid(mt_rand(), true))];
}
/**
* 获取可支持裁剪的图片url
* @param $bucket
* @param $objectid
* @param $wideSize
* @param $highSize
* @param string $type 目前只支持 png webp jpeg
* @wiki http://ydwiki.yidian-inc.com/pages/viewpage.action?pageId=41584585
* @return string
*/
public static function getCutPicUrl($bucket,$objectid,$wideSize,$highSize,$type='jepg')
{
if ($bucket !== self::bp_image_yidian || !in_array($type,['png','webp','jpeg'])) {
//目前只有当bucket == bp-image_yidian 才支持可裁剪
return '';
}
return sprintf(self::get_down_from_pic_service.'?'.'url=%s&%s_%sx%s',$objectid,$type,$wideSize,$highSize);
}
/**
* 图片下载地址 的统一出口函数
* @param $appid
* @param $scenario
* @param $url
* @param $wideSize
* @param $highSize
* @param string $type
* @return mixed|string
*/
public static function getPicUrl($appid,$scenario,$url,$wideSize,$highSize,$type='jepg')
{
if (!in_array($appid,['merchant-b','merchant-c'])) {
return '';
}
if (in_array($appid,['merchant-b','merchant-c'])) {
if ($scenario === self::scenario_living_goods_temp) {
$del_str = explode('/',$url);
$bucket = $del_str[0] ?? '';
$objectid = $del_str[1] ?? '';
return self::getCutPicUrl($bucket,$objectid,$wideSize,$highSize,$type);
}
if (in_array($scenario, [self::scenario_living_data, self::scenario_id_card, self::scenario_living_business_license], true)) {
return self::getUrlFromKsyn($url,$appid);
}
}
return '';
}
}
\ No newline at end of file
<?php
/**
* Description of
*
* @author zhiyuan
* Date: 2021/6/12
* Time: 10:32 PM
*/
namespace Api\PhpServices\LifeAccount;
use Api\PhpUtils\Common\TimeOut;
use Api\PhpUtils\Http\Request;
use App\Exception\custom\CodeSpecialException;
class Account
{
/**
* 批量获取生活号角色表数据
*
*@param $params['role_id'] 主键id
*
*/
public static function getRoleList($params)
{
$url = config('interface', 'merchant.account.get_role_list');
if (!$url) {
throw new CodeSpecialException("failed");
}
if (!array_key_exists('role_id', $params) || !array_key_exists('page', $params) || !array_key_exists('page_size', $params)) {
throw new CodeSpecialException("failed");
}
$list = (new TimeOut())->runGet($url, $params);
if (!$list) {
throw new CodeSpecialException("timeout");
}
return $list;
}
/**
* 批量获取生活号表数据
*
*@param $params['user_id'] 主键id
*
*/
public static function getLifeList($params)
{
$url = config('interface', 'merchant.account.get_life_list');
if (!$url) {
throw new CodeSpecialException("failed");
}
$list = (new TimeOut())->runGet($url, $params);
if (!$list) {
throw new CodeSpecialException("timeout");
}
return $list;
}
/**
* 批量获取用户表数据
*
*@param $params['user_id'] 主键id
*
*/
public static function getUserList($params)
{
$url = config('interface', 'merchant.account.get_user_list');
if (!$url) {
throw new CodeSpecialException("failed");
}
$list = (new TimeOut())->runGet($url, $params);
if (!$list) {
throw new CodeSpecialException("timeout");
}
return $list;
}
}
<?php
namespace Api\PhpServices\Login;
use Api\PhpUtils\Common\TimeOut;
use Api\PhpUtils\Http\Request;
use App\Exception\custom\CodeSpecialException;
class Login
{
/**
* 访客内网登录
*
* @doc http://ydwiki.yidian-inc.com/pages/viewpage.action?pageId=59676495
* @param array $user
* @param string $partner 调用方(包括一点资讯yidian,VPN项目hubble,地铁metro)
* @return array
*/
public static function guest(array $user, string $key, string $partner){
$url = config("interface","service.login.guest");
if(!$url){
throw new CodeSpecialException("failed");
}
$user["partner"] = $partner;
$user["key"] = $key;
$res = (new TimeOut())->runGet($url, $user);
if(!$res){
throw new CodeSpecialException("timeout");
}
if(!isset($res["code"])){
throw new CodeSpecialException("user_login");
}
if($res["code"] == 0){
unset($res["code"]);
unset($res["status"]);
return $res;
}
switch ($res["code"]/1){
case 10:
throw new CodeSpecialException("param");
case 14:
throw new CodeSpecialException("permission_denied");
case 15:
throw new CodeSpecialException("sign");
case 21:
throw new CodeSpecialException("mysql");
default:
throw new CodeSpecialException("user_login");
}
}
/**
* 手机号内网登录
*
* @doc http://ydwiki.yidian-inc.com/pages/viewpage.action?pageId=57606923
*/
public static function mobile(array $user, string $key, string $partner){
$url = config("interface","service.login.mobile");
if(!$url){
throw new CodeSpecialException("failed");
}
$user["partner"] = $partner;
$user["key"] = $key;
$res = (new TimeOut())->runGet($url, $user);
if(!$res){
throw new CodeSpecialException("timeout");
}
if(!isset($res["code"])){
throw new CodeSpecialException("user_login");
}
if($res["code"] == 0){
unset($res["code"]);
unset($res["status"]);
return $res;
}
switch ($res["code"]/1){
case 10:
throw new CodeSpecialException("param");
case 14:
throw new CodeSpecialException("permission_denied");
case 21:
throw new CodeSpecialException("user_mobile_error");
case 32:
throw new CodeSpecialException("user_mobile_registed");
default:
throw new CodeSpecialException("user_login");
}
}
/**
* 发送短信验证码服务
* http://ydwiki.yidian-inc.com/pages/viewpage.action?pageId=58693127
* @param array $data
* @param string $template 模板
* @param string $partner 调用方(包括一点资讯yidian,VPN项目hubble,地铁metro等)
* @param int $code_lenght 验证码长度,默认4位
* @param int $code_expire 验证码有效期,默认300秒(5分钟)
* @param int $resend_times 验证周期内验证码最大发送次数,默认10次
* @param int $retry_times 验证周期内每个验证码最大可校验次数,默认10次
* @param int $ticket_expire 验证码验证周期,默认86400秒(1天)
* @throws CodeSpecialException
* @return true
*/
public static function sendSmsCode(array $data, int $template, string $key, string $partner, $code_lenght =4, $code_expire=300, $resend_times=10, $retry_times=10, $ticket_expire=86400){
$url = config("interface","service.login.send_sms_code");
if(!$url){
throw new CodeSpecialException("failed");
}
$data = array_merge($data,[
"key" => $key,
"partner" => $partner,
"template" => $template,
"code_lenght" => $code_lenght,
"ticket_expire" => $ticket_expire,
"code_expire" => $code_expire,
"resend_times" => $resend_times,
"retry_times" => $retry_times,
]);
$res = (new Request())->get($url, $data, 60000);
if(!$res){
throw new CodeSpecialException("timeout");
}
if(!isset($res["code"])){
throw new CodeSpecialException("failed");
}
if($res["code"] == 0){
return true;
}
switch ($res["code"]/1){
case 10:
throw new CodeSpecialException("param");
case 14:
throw new CodeSpecialException("permission_denied");
case 221:
throw new CodeSpecialException("captcha_sent");
case 30:
throw new CodeSpecialException("mobile_error");
case 23:
throw new CodeSpecialException("memcache");
case 224:
throw new CodeSpecialException("captcha_delay_retry");
default:
throw new CodeSpecialException("failed");
}
}
/**
* 校验短信验证码
* @param array $data
* @param string $partner
* @return true
* @throws CodeSpecialException
*/
public static function checkSmsCode(array $data, string $key, string $partner){
$url = config("interface","service.login.check_sms_code");
if(!$url){
throw new CodeSpecialException("failed");
}
$data = array_merge($data,[
"partner" => $partner,
"key" => $key,
]);
$res = (new TimeOut())->runGet($url, $data);
if(!$res){
throw new CodeSpecialException("timeout");
}
if(!isset($res["code"])){
throw new CodeSpecialException("failed");
}
if($res["code"] == 0){
return true;
}
switch ($res["code"]/1){
case 10:
throw new CodeSpecialException("param");
case 14:
throw new CodeSpecialException("permission_denied");
case 220:
$reasion = $res["reason"] ?? "";
throw new CodeSpecialException("captcha", $reasion);
case 222:
throw new CodeSpecialException("captcha_timeout");
case 223:
throw new CodeSpecialException("captcha_forbidden");
default:
throw new CodeSpecialException("failed");
}
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Printer\Fei;
/**
* 飞蛾 打印实现类
*
* @author mengweifu
* @date 2021-7-25 14:00:00
*/
use Api\PhpUtils\Http\HttpUtil;
class FeiPrinter extends \Api\PhpServices\Printer\Printer
{
/**
* *必填*:账号名
*/
private const USER = "yonghui.chen@linkingcities.com";
/**
* *必填*: 飞鹅云后台注册账号后生成的UKEY 【备注:这不是填打印机的KEY】
*/
private const UKEY = "VjPMkB64QNuIIcgQ";
/**
* 飞鹅云打印 api前缀 不需要修改
*/
private const API = "http://api.feieyun.cn/Api/Open/";
/**
* 打印订单
*/
private const API_PRINT = "Open_printMsg";
/**
* 查询打印订单状态
*/
private const API_ORDER_STATUS = "Open_queryOrderState";
/**
* 获取某台打印机状态
*/
private const API_PRINTER_STATUS = "Open_queryPrinterStatus";
/**
* @param string $apiName api 名字
* @return array
*/
private function buildQuery(string $apiName) : array
{
$timestamp = time();
return [
'user' => self::USER,
'stime' => $timestamp,
'sig' => $this->signature(self::USER, self::UKEY, $timestamp),
'apiname' => $apiName
];
}
private function signature(String $user, String $uKey, int $sTime): string
{
return sha1($user . $uKey . $sTime);
}
/**
* 内部函数 查询
* @param string $apiName
* @param array $param
* @return array
*/
private function request(string $apiName,array $param): array
{
$param = $this->buildQuery($apiName) + $param;
return HttpUtil::post(self::API, http_build_query($param));
}
/**
* @inheritDoc
*/
public function addPrinter(array $param): bool
{
// TODO: Implement addPrinter() method.
}
/**
* @inheritDoc
*/
public function deletePrinter(string $printerId): bool
{
// TODO: Implement deletePrinter() method.
}
/**
* @inheritDoc
*/
public function getPrinterStatus(string $printerId): string
{
$res = $this->request(self::API_PRINTER_STATUS, [
'sn' => $printerId,
]);
if ($res['code'] == 0 && isset($res['response'])) {
if ($res['response']['ret'] == 0) {
return $res['response']['data'];
}
throw new Exception($res['response']['msg']);
}
throw new Exception("接口调用异常");
}
/**
* @inheritDoc
*/
public function printContent(string $printerId, array $content):string
{
$formattedContent = "";
$first = true;
foreach ($content as $row) {
$formattedRow = is_array($row) ? implode(' ', $row) : $row;
if ($first) {
$formattedContent .= "<CB>$formattedRow</CB><BR>";
}
else {
$formattedContent .= "$formattedRow<BR>";
}
$first = false;
}
$res = $this->request(self::API_PRINT, [
'sn' => $printerId,
'content' => $formattedContent,
'times' => 1,// 打印联数
]);
if ($res['code'] == 0 && isset($res['response'])) {
if ($res['response']['ret'] == 0) {
return $res['response']['data'];
}
throw new Exception($res['response']['msg']);
}
throw new Exception("接口调用异常");
}
/**
* @inheritDoc
*/
public function getOrderStatus(string $orderId): bool
{
$res = $this->request(self::API_ORDER_STATUS, [
'orderid' => $orderId,
]);
if ($res['code'] == 0 && isset($res['response'])) {
if ($res['response']['ret'] == 0) {
return (bool) $res['response']['data'];
}
throw new Exception($res['response']['msg']);
}
throw new Exception("接口调用异常");
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Printer;
/**
* 打印抽象类
*
* @author mengweifu
* @date 2021-7-25 14:00:00
*/
abstract class Printer
{
/**
* 添加打印机
* @param array $param
* @return bool
*/
abstract public function addPrinter(array $param): bool;
/**
* 删除打印机
* @param string $printerId
* @return bool
*/
abstract public function deletePrinter(string $printerId): bool;
/**
* 获取打印机状态
* @param string $printerId
* @return string 状态描述
*/
abstract public function getPrinterStatus(string $printerId): string;
/**
* 打印
* @param string $printerId
* @param array $content 要打印的内容 支持一位数组 二维数组
* @return string 打印OrderID, ID
*/
abstract public function printContent(string $printerId, array $content): string;
/**
* 查询打印状态
* @param string $orderId 为printContent 返回
* @return bool
*/
abstract public function getOrderStatus(string $orderId): bool;
}
\ No newline at end of file
<?php
namespace Api\PhpServices\Printer;
/**
* 打印工厂类
*
* 如何使用:
* $content = [['aaa'], 'bbb'];
* $FeiPrinter = PrinterFactory::getPrinter('Fei');
* $res = $FeiPrinter->printContent('921617329', $content);
* $res = $FeiPrinter->getOrderStatus('921617329_20210725143642_699302110');
* $res = $FeiPrinter->getPrinterStatus('921617329');
* @author mengweifu
* @date 2021-7-25 14:00:00
*/
class PrinterFactory
{
/**
* 获取打印实现类
* @param string $printerName
* @return mixed
* @throws \Exception
*/
public static function getPrinter(string $printerName) : Printer
{
if (! file_exists(__DIR__ .DIRECTORY_SEPARATOR. $printerName. DIRECTORY_SEPARATOR . $printerName . 'Printer.php')) {
throw new \Exception("相应printer未找到");
}
$printerClass = "Api\\PhpServices\\Printer\\${printerName}\\${printerName}Printer";
return new $printerClass;
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\PushToken;
use Api\PhpUtils\Http\Request;
class Android extends Base
{
/**
* @param bool $err 引用类型,是否存在错误
* @param $appid
* @param $userid
* @param $data
*/
public static function save(&$err = false, $appid, $data, $userid=''){
$new_token = $data['new_token'] ?? "";
$old_token = $data['old_token'] ?? "";
$token = $data['new_token'] ?? $data['old_token'] ?? "";
$version = self::version($data['version'] ?? "");
$personal_rec = $data['personalRec'] ?? 1;
$enable = self::enable($data['enable'] ?? 1, $personal_rec);
$push_key = $data['push_key'] ?? "";
$device_id = $data["device_id"] ?? "";
if($device_id && !self::valid_device_id($device_id)){
$device_id = "";
}
$android_id = $data["androidId"] ?? "";
if($android_id && !self::valid_device_id($android_id)){
$android_id = "";
}
if (!self::valid_appid($appid)){
return ["code"=> self::ERROR_CODE_PARAM, "msg" => "appid有误"];
}
if( empty($token) || !self::valid_android_token($token) ){
$err = true;
return ["code"=> self::ERROR_CODE_PARAM, "msg" => "token有误"];
}
if( !$version ){
$err = true;
return ["code"=> self::ERROR_CODE_PARAM, "msg" => "version有误"];
}
if($new_token && substr($new_token, 0, 4) === 'OPPO' && (empty($push_key)) ){
$err = true;
return ["code"=> self::ERROR_CODE_PARAM, "msg" => "该类型token的push_key必传"];
}
// $action = explode('?', $_SERVER['REQUEST_URI'])[0]; // 与运营中台沟通,暂时写死成 website 路径,之后重构再调整
$action = "/Website/push/BindingTokenForAndroidAction.php";
$send = [
'action' => $action,
'appid' => $appid,
'request_time' => intval($_SERVER['REQUEST_TIME']),
'version' => $version,
'userid' => $userid,
'time_zone' => $data["time_zone"] ?? "",
'personal_rec' => $personal_rec,
'enable' => $enable,
'sound' => $data["sound"] ?? "",
'push_level' => self::set_device_type_from_brand($data["push_level"] ?? "1048576", $data["brand"] ??""),
'old_token' => $old_token,
'new_token' => $new_token,
'push_key' => $push_key,
'cv' => $data["cv"] ?? "",
'device_id' => $device_id,
'android_id' => $android_id,
'os' => $data["os"] ?? "",
'distribution' => $data["distribution"] ?? "",
'platform' => "Android"
];
$send = array_filter ($send,function($v){if($v===''){return false;}else{return true;}});
if(!self::sendKafka($send)){
$err = true;
return ["code"=> self::ERROR_CODE_KAFKA, "msg" => "send failed"];
};
$err = false;
return true;
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\PushToken;
use Api\PhpUtils\Http\Request;
class Base
{
const ERROR_CODE_PARAM = 1;
const ERROR_CODE_KAFKA = 2;
// appid 最大长度
const MAX_APPID_LENGTH = 20;
// android token 的最大长度
const MAX_ANDROID_TOKEN_LENGTH = 40;
// ios token 的最大长度
const MAX_IOS_TOKEN_LENGTH = 80;
// 特殊的appid(普通appid只包含数字字母)
static $SPECIAL_APPIDS = array('web_mixapp' => '');
// android token 合法前缀
static $ANDROID_VALID_TOKEN_PREFIX = array('MMPP', 'UMPP', 'GTPP', 'JGPP', 'OPPP', 'HMSP', 'FCMP', 'OPPO', 'VIVO');
const DEVICE_MASK = 0xF0;
const DEVICE_NONE = 0x00;
const DEVICE_XIAOMI = 0x10;
const DEVICE_HUAWEI = 0x20;
const DEVICE_MEIZU = 0x30;
const DEVICE_UNKNOWN = 0x40;
const DEVICE_NUBIA = 0x50;
const DEVICE_ZTE = 0x60;
const DEVICE_OPPO = 0x70;
const DEVICE_VIVO = 0x80;
const DEVICE_SAMSUNG = 0x90;
const DEVICE_ID_LENGTH = 80;
/**
* 校验appid
* @param $appid
* @return bool
*/
protected static function valid_appid($appid){
return strlen($appid) <= self::MAX_APPID_LENGTH
&& ctype_alnum($appid)
|| isset(self::$SPECIAL_APPIDS[$appid]);
}
/**
* 校验安卓token
* @param $token
* @return bool
*/
protected static function valid_android_token($token)
{
return strlen($token) <= self::MAX_ANDROID_TOKEN_LENGTH
&& in_array(substr($token, 0, 4), self::$ANDROID_VALID_TOKEN_PREFIX)
&& ctype_alnum(substr($token, 4));
}
protected static function valid_ios_token($token)
{
return strlen($token) <= self::MAX_IOS_TOKEN_LENGTH && ctype_alnum($token);
}
protected static function valid_device_id($device_id)
{
return strlen($device_id) < self::DEVICE_ID_LENGTH && ctype_alnum($device_id);
}
protected static function version($version = '', $default = '000000')
{
if ($version)
{
if (preg_match('/\d{6}/', trim($version)))
{
return trim($version);
}
return false;
}
return $default;
}
protected static function enable($enable, $personal_rec){
return $enable == 0 ? '0' : (!$personal_rec ? '3' : '1');
}
protected static function set_device_type_from_brand($push_level, $brand)
{
if(!$brand){
return $push_level;
}
switch ($brand)
{
case 'Xiaomi':
case 'xiaomi':
case 'Redmi':
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_XIAOMI);
break;
case 'HUAWEI':
case 'HONOR':
case 'Huawei':
case 'Honor':
case 'honor':
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_HUAWEI);
break;
case 'Meizu':
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_MEIZU);
break;
case 'nubia':
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_NUBIA);
break;
case 'ZTE':
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_ZTE);
break;
case 'OPPO':
case 'oppo':
case 'realme':
case 'Realme':
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_OPPO);
break;
case 'vivo':
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_VIVO);
break;
case 'samsung':
case 'SAMSUNG':
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_SAMSUNG);
break;
default:
$push_level =
strval(($push_level & (~self::DEVICE_MASK)) | self::DEVICE_UNKNOWN);
break;
}
return $push_level;
}
protected static function sendKafka($data){
// echo json_encode($data);exit();
$url = config("interface","service.push_token") . '?' . config("interface","service.push_token_topic");
$res = (new Request())->post($url, $data, 200000, 'json');
if($res['code']==0){
return true;
}
return false;
}
}
\ No newline at end of file
<?php
namespace Api\PhpServices\PushToken;
use Api\PhpUtils\Http\Request;
class Ios extends Base
{
/**
* @param bool $err 引用类型,是否存在错误
* @param $appid
* @param $userid
* @param $data
*/
public static function save(&$err = false, $appid, $data, $userid=''){
$new_token = $data['new_token'] ?? "";
$old_token = $data['old_token'] ?? "";
$token = $data['new_token'] ?? $data['old_token'] ?? "";
$version = self::version($data['version'] ?? "");
$personal_rec = $data['personalRec'] ?? 1;
$enable = self::enable($data['enable'] ?? 1, $personal_rec);
if (!self::valid_appid($appid)){
return ["code"=> self::ERROR_CODE_PARAM, "msg" => "appid有误"];
}
if( empty($token) || !self::valid_ios_token($token) ){
$err = true;
return ["code"=> self::ERROR_CODE_PARAM, "msg" => "token有误"];
}
if( !$version ){
$err = true;
return ["code"=> self::ERROR_CODE_PARAM, "msg" => "version有误"];
}
// $action = explode('?', $_SERVER['REQUEST_URI'])[0]; // 与运营中台沟通,暂时写死成 website 路径,之后重构再调整
$action = "/Website/push/BindingTokenAction.php";
$send = [
'action' => $action,
'userid' => $userid,
'appid' => $appid,
'request_time' => intval($_SERVER['REQUEST_TIME']),
'version' => $version,
'time_zone' => $data["time_zone"] ?? "",
'personal_rec' => intval($personal_rec),
'enable' => $enable,
'sound' => $data["sound"] ?? "",
'push_level' => $data["push_level"] ?? "",
'old_token' => $old_token,
'new_token' => $new_token,
'push_key' => $data["push_key"] ?? "",
'cv' => $data["cv"] ?? "",
'os' => $data["os"] ?? "",
'distribution' => $data["distribution"] ?? "",
'platform' => "IOS"
];
$send = array_filter ($send,function($v){if($v===''){return false;}else{return true;}});
if(!self::sendKafka($send)){
$err = true;
return ["code"=> self::ERROR_CODE_KAFKA, "msg" => "send failed"];
};
$err = false;
return true;
}
}
\ No newline at end of file
use Api\PhpServices\Sensitive\Sensitive;
//参数描述
businessId = 业务ID 1.一点 2.身边 9.VPN
text 送查内容
scene 场景ID 1.标题 2.简介 3.正文 4.评论 6.昵称 7.搜索
//单个词敏感词
$params = [
'businessId' => !empty($param['businessId']) ? $param['businessId'] : 1,
'text' => !empty($param['text']) ? $param['text'] : '习近平',
'scene' => !empty($param['scene']) ? $param['scene'] : 3,
];
(new Sensitive)->detect($params)
//批量敏感词
$params = [
[
'businessId' => 1,
'text' => '习近平',
'scene' => 3,
]
];
(new Sensitive)->detectBatch($params)
\ No newline at end of file
<?php
/**
*
* @author haiming
* Date: 2021/5/21
* Time: 10:32 PM
*/
namespace Api\PhpServices\Sensitive;
use Api\PhpUtils\Common\TimeOut;
use Api\PhpUtils\Http\Request;
use App\Exception\custom\CodeSpecialException;
class Sensitive
{
/**
* 敏感词
*
*
*/
public function detect($param)
{
$url = config('interface','service.sensitive.detect');
if(!$url){
throw new CodeSpecialException("failed");
}
if (empty($param)) {
throw new CodeSpecialException("failed");
}
$params = [
'businessId' => !empty($param['businessId']) ? $param['businessId'] : 1,
'text' => !empty($param['text']) ? $param['text'] : '',
'scene' => !empty($param['scene']) ? $param['scene'] : 3,
];
$headers = [
'Content-Type' => 'application/json;charset=UTF-8',
];
$detect_info = (new TimeOut())->runPost($url, $params,'json',$headers);
if(!$detect_info){
throw new CodeSpecialException("timeout");
}
return $detect_info;
}
/**
* 敏感词批量
*
*
*/
public function detectBatch($params)
{
$url = config('interface','service.sensitive.detect_batch');
if(!$url){
throw new CodeSpecialException("failed");
}
if (empty($params)) {
throw new CodeSpecialException("failed");
}
$headers = [
'Content-Type' => 'application/json;charset=UTF-8',
];
$detect_info = (new TimeOut())->runPost($url, $params,'json',$headers);
if(!$detect_info){
throw new CodeSpecialException("timeout");
}
return $detect_info;
}
}
## Session服务
#### Usage:
```
use Api\PhpServices\Session\SessionManager;
// write session
SessionManager::set($appid, $userid, $isLogin, $sessionData, $maxLogin=10);
// start session
SessionManager::start();
// destroy session
SessionManager::destroy();
```
\ No newline at end of file
<?php
namespace Api\PhpServices\Session;
use Api\PhpServices\Session\Session;
use Api\PhpServices\Session\RedisSessionHandler;
use Api\PhpUtils\Http\Request;
class RedisSession extends Session
{
protected $redis = null;
protected $key = 'c071f6e5923a648a5ef88f32b6f738e1';
protected $from = 'bpsession';
/**
* 从cookie开启session
* @param boolean $readOnly 是否只读会话,如果是,则在读取session之后直接关闭session
* 只读会话,需要在session更改后,手动调用write()写入,不然更改后的会话不会保存
* @param string $app
* @return boolean
*/
public function start($readOnly = true)
{
if ($this->started) {
return true;
}
$sessionId = $_COOKIE[$this->getSessionName()] ?? '';
if (empty($sessionId) || !$this->checkSessionId($sessionId)) {
return false;
}
$this->sessionId = $sessionId;
$options = [];
if ($readOnly) {
$options['read_and_close'] = true;
}
return $this->doStart($options);
}
/**
* 创建session,多用于用户登录后创建session,用户会话包括:访客会话和登录会话
* @param integer $userid
* @param string $appid session所属app,默认为一点资讯
* @param boolean $isLogin 是否登录
* @return boolean
*/
public function create($appid, $userid, $isLogin = false)
{
// 如果session已开启,需要关闭当前会话
if ($this->started) {
$this->close();
}
$this->setAppid($appid);
if ($userid === null || $appid === null) {
throw new \Exception("userid[{$userid}], or appid[{$appid}] is null");
}
$sessionId = $this->generateSessionId($appid, $userid, $isLogin);
if (empty($sessionId)) {
return false;
}
$this->sessionId = $sessionId;
$options = [];
return $this->doStart($options, [
'userid' => $userid,
]);
}
/**
* start session
* @param array $options session_start()支持的选项
* @param array $params 该方法使用的附加参数
* @return boolean
*/
protected function doStart(array $options = [], array $params = [])
{
// 注册session处理器
$sessionHandler = new RedisSessionHandler();
$sessionHandler->setExpire($this->getExpire($params['userid'] ?? null));
$this->setHandler($sessionHandler, true);
if (empty($options['serialize_handler'])) {
$options['serialize_handler'] = 'php_serialize';
}
// 禁用session_start()默认cookie header发送
$options['use_cookies'] = 0;
//$options['cache_limiter'] = '';
$this->setSessionId();
$this->setSessionName();
return parent::start($options);
}
/**
* 生成用户sessionId
* @param integer $userid
* @param string $username
* @param boolean $isLogin 是否登录
* @return string
*/
public function generateSessionId($appid, $userid, $isLogin = false)
{
$validSessionIds = $this->validSessionIds($appid, $userid, $isLogin);
// 提取其中在用的session
$liveSession = $this->extractLiveSessionIds($validSessionIds);
if (empty($liveSession)) {
return $validSessionIds[rand(0, count($validSessionIds) - 1)];
}
$usableSesssionIds = array_values(array_diff($validSessionIds, array_keys($liveSession)));
if ($usableSesssionIds) {
$sessionId = $usableSesssionIds[array_rand($usableSesssionIds, 1)];
} else {
//10个可用全部用完,随机选一个
$sessionId = $validSessionIds[rand(0, count($validSessionIds) - 1)];
}
return $sessionId;
}
/**
* 删除当前会话
* @return boolean
*/
public function deleteSelf()
{
return $this->delete($this->sessionId);
}
/**
* 删除指定session的redis
* @param array|string $sessionIds
* @return boolean
*/
public function delete($sessionIds)
{
if (empty($sessionIds)) {
return true;
}
if (!is_array($sessionIds)) {
$sessionIds = [$sessionIds];
}
// 如果当前session也被删除,需要先关闭当前session
if (in_array($this->sessionId, $sessionIds)) {
$this->close();
}
$url = $this->getUrl('delete');
$params = ['sessionid' => array_unique($sessionIds), 'key' => $this->key, 'from' => $this->from];
$result = (new Request())->post($url, $params, 0, 'json');
if (isset($result['response']['code']) && $result['response']['code'] == 0 ) {
return true;
}
return false;
}
/**
* 删除用户所有会话
* @param integer $userid
* @param string $username
* @param int $type 0 所有session,1 访客session,2 非访客session
* @return boolean
*/
public function deleteByUser($appid, $userid, $type = 0)
{
$sessionIds = [];
if ($type === 1 || $type === 0) {
$sessionIds = array_merge($sessionIds, $this->validSessionIds($appid, $userid, false));
}
if ($type === 2 || $type === 0) {
$sessionIds = array_merge($sessionIds, $this->validSessionIds($appid, $userid, true));
}
return $this->delete($sessionIds);
}
/**
* 提取在用的session id
* @param array $sessionIds
* @return array
*/
public function extractLiveSessionIds(array $sessionIds)
{
$data = [];
$url = $this->getUrl('mget');
$params = ['sessionid' => $sessionIds, 'key' => $this->key, 'from' => $this->from];
$result = (new Request())->post($url, $params, 0, 'json');
if (isset($result['response']['code']) && $result['response']['code'] == 0
&& isset($result['response']['result']) && !empty($result['response']['result'])
) {
$liveSession = $result['response']['result'];
foreach ($liveSession as $key => $value) {
if (empty($value)) {
continue;
}
$data[$sessionIds[$key]] = is_string($value) ? unserialize($value) : $value;
}
}
return $data;
}
/**
* get yaconf interface.url
* @return string
*/
public function getUrl($param = '')
{
if (empty($param)){
return "";
}
$env = \Yaf\Application::app()->environ() ?? "test";
$key = 'interface.' . $env . '.service.session.' . $param;
return \Yaconf::get($key);
}
}
<?php
namespace Api\PhpServices\Session;
use Api\PhpUtils\Http\Request;
/**
* Customer Redis Session Handler
*/
class RedisSessionHandler implements \SessionHandlerInterface
{
protected $key = 'c071f6e5923a648a5ef88f32b6f738e1';
protected $expire = 0;
protected $from = 'bpsession';
/**
* open session
* @param string $savePath
* @param string $sessionName
* @return boolean
*/
public function open($savePath, $sessionName)
{
return true;
}
/**
* read session
* @param string $sessionId
* @return string
*/
public function read($sessionId)
{
$url = $this->getUrl('get');
$query = ['sessionid' => $sessionId, 'from' => $this->from];
$result = (new Request())->get($url, $query);
$data = [];
if (isset($result['response']['code']) && $result['response']['code'] == 0 && isset($result['response']['result'])) {
$data = $result['response']['result'];
}
return empty($data) ? '' : (is_array($data) ? serialize($data) : $data);
}
/**
* write session
* @param string $sessionId
* @param string $sessionData
* @return boolean
*/
public function write($sessionId, $sessionData)
{
if (!$_SESSION) {
return true;
}
$url = $this->getUrl('set');
$params = ['sessionid' => $sessionId, 'data' => $_SESSION, 'expire' => $this->expire, 'key' => $this->key, 'from' => $this->from];
$result = (new Request())->post($url, $params, 3000, 'json');
if (isset($result['response']['code']) && $result['response']['code'] == 0 ) {
return true;
}
return false;
}
/**
* close session
* @return boolean
*/
public function close()
{
return true;
}
/**
* destroy session
* @param string $sessionId
* @return boolean
*/
public function destroy($sessionId)
{
$url = $this->getUrl('delete');
$params = ['sessionid' => $sessionId, 'key' => $this->key, 'from' => $this->from];
$result = (new Request())->post($url, $params, 3000, 'json');
if (isset($result['response']['code']) && $result['response']['code'] == 0 ) {
return true;
}
return false;
}
/**
* garbage clean session
* session in redis would be auto cleaned when expired
* @param integer $maxlifetime
* @return integer
*/
public function gc($maxlifetime)
{
return 0;
}
/**
* set session expire
* @param integer $expire second
* @return RedisSessionHandler
*/
public function setExpire($expire)
{
$this->expire = $expire;
return $this;
}
/**
* get session expire
* @return integer
*/
public function getExpire()
{
return $this->expire;
}
/**
* get yaconf interface.url
* @return string
*/
public function getUrl($param = '')
{
if (empty($param)){
return "";
}
$env = \Yaf\Application::app()->environ() ?? "test";
$key = 'interface.' . $env . '.service.session.' . $param;
return \Yaconf::get($key);
}
}
<?php
namespace Api\PhpServices\Session;
/**
* Session base class
*/
abstract class Session
{
protected $sessionId = '';
protected $sessionName = 'JSESSIONID';
protected $started = false;
protected $handler = null;
protected $appid = '';
protected static $instance = null;
protected function __construct()
{
}
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new static();
}
return self::$instance;
}
/**
* session started, or not
* @return boolean
*/
public function started()
{
$this->started = false;
if (session_status() === PHP_SESSION_ACTIVE) {
$this->started = true;
}
return $this->started;
}
public function getAppid()
{
return $this->appid;
}
public function setAppid($appid)
{
$this->appid = $appid;
return $this;
}
/**
* get session id
* @return string
*/
public function getSessionId()
{
return $this->sessionId;
}
/**
* set session id
* @param string $sessionId
* @return boolean
*/
public function setSessionId($sessionId = null)
{
if ($sessionId) {
if (!$this->checkSessionId($sessionId)) {
throw new \Exception("session id [{$sessionId}] invalid");
}
$this->sessionId = $sessionId;
}
if (!empty($this->sessionId)) {
return session_id($this->sessionId);
}
return false;
}
/**
* get session name
* @return string
*/
public function getSessionName()
{
return $this->sessionName;
}
/**
* set session name
* @param string $sessionName
* @return boolean
*/
public function setSessionName($sessionName = null)
{
if ($sessionName) {
$this->sessionName = $sessionName;
} else {
$sessionName = $this->sessionName;
}
return session_name($sessionName);
}
/**
* get session handler
* @return SessionHandlerInterface
*/
public function getHandler()
{
return $this->handler;
}
/**
* set session handler
* @param object $handler
* @param boolean $registerShutdown
* @return boolean
*/
public function setHandler($handler, $registerShutdown = true)
{
$this->handler = $handler;
return session_set_save_handler($handler, $registerShutdown);
}
/**
* session start
* @param array $options
* @return boolean
*/
public function start($options = [])
{
if (session_start($options) === false) {
return false;
}
$this->started();
return true;
}
/**
* get session expire (second)
* @param string $userid
* @return integer
*/
public function getExpire($userid = null)
{
if (empty($userid) || !in_array($userid, [
1211920133,
1215304799,
])) {
return 2592000;
}
return 3600;
}
/**
* flush session to database
* @return boolean
*/
public function write()
{
return $this->handler ? $this->handler->write(
$this->sessionId,
serialize($_SESSION)
) : false;
}
/**
* destroy session
* @return boolean
*/
public function destroy()
{
$this->started = false;
return session_destroy();
}
/**
* close session
* @return boolean
*/
public function close()
{
if (!$this->started()) {
$this->write();
$this->closeHandler();
$this->started = false;
return true;
}
session_write_close();
$this->started = false;
return true;
}
/**
* close session handler
* @return boolean
*/
protected function closeHandler()
{
return $this->handler ? $this->handler->close() : false;
}
/**
* set cookie
* @param integer $expire expire time (s)
* @param boolean $replace replace previous similar cookie
* @return boolean
*/
public function setCookie($expire = 0, $replace = true)
{
if ($replace) {
$cookieKeyword = $this->getSessionName()
. '=' . $this->getSessionId() . ';';
$this->removeCookie($cookieKeyword);
}
if ($expire != 0) {
$expire += time();
}
setcookie(
$this->getSessionName(),
$this->getSessionId(),
$expire, '/', '', false, true);
$_COOKIE[$this->getSessionName()] = $this->getSessionId();
return true;
}
/**
* generate valid session id
* @param string $appid
* @param integer $userid
* @param boolean $isLogin 是否登录
* @return array
*/
public function validSessionIds($appid, $userid, $isLogin = false)
{
$guest = $isLogin ? 'nonguest' : 'guest';
// 使用codis hash tag保证同一个文章的正文及信息流缓存落入同一台codis server
$tag = '{'.strtolower(str_replace(array('+','/','='), array(''), base64_encode($userid))).'}';
$sessionIds = [];
for ($i = 0; $i < 10; $i++) {
$sessionId = $tag . md5($i . $appid . $userid . $guest);
$sessionIds[] = $sessionId . substr(sha1($sessionId), -2);
}
return $sessionIds;
}
/**
* check session id
* @return boolean
*/
public function checkSessionId($sessionId = null)
{
if(!$sessionId) {
return false;
}
$verifyCode = substr($sessionId, -2);
$encodeStr = substr($sessionId, 0, -2);
if (substr(sha1($encodeStr), -2) !== $verifyCode) {
return false;
}
return true;
}
/**
* remove cookie
* @param string $keyword
* @return boolean
*/
protected function removeCookie($keyword = null)
{
if (is_null($keyword)) {
header_remove('Set-Cookie');
return true;
}
$keyword = " {$keyword}";
$otherCookies = [];
foreach (headers_list() as $header) {
if (stripos($header, 'Set-Cookie:') !== 0) {
continue;
}
if (strpos($header, $keyword, 11) !== 11) {
$otherCookies[] = $header;
}
}
header_remove('Set-Cookie');
$otherCookies = array_unique($otherCookies);
foreach ($otherCookies as $cookie) {
header($cookie, false);
}
return true;
}
}
<?php
namespace Api\PhpServices\Session;
use Api\PhpServices\Session\RedisSession;
class SessionManager
{
/**
* get session instance
* @return RedisSession
*/
public static function getSession()
{
return RedisSession::getInstance();
}
/**
* set session app
* @param string $app
* @return boolean
*/
public static function setAppid($app)
{
self::getSession()->setAppid($app);
return true;
}
/**
* get session app
* @return string
*/
public static function getAppid()
{
return self::getSession()->getAppid();
}
/**
* get session name
* @return string
*/
public static function name()
{
return self::getSession()->getSessionName();
}
/**
* get session id
* @return string
*/
public static function sid()
{
return self::getSession()->getSessionId();
}
/**
* whether session started
* @return boolean
*/
public static function started()
{
return self::getSession()->started();
}
/**
* 删除非访客session
*
* @param int $userid
* @param string $username
* @param string $app
* @return bool
*/
public static function delete_nonguest($appid, $userid)
{
$session = self::getSession();
return $session->deleteByUser($appid, $userid, 2);
}
/**
* delete all sessions of the user
* @param integer $userid
* @param string $username
* @param string $app
* @return boolean
*/
public static function delete_all($appid, $userid)
{
$session = self::getSession();
return $session->deleteByUser($appid, $userid);
}
/**
* delete sessions
* @param array|string $sessionIds
* @return boolean
*/
public static function delete($sessionIds)
{
return self::getSession()->delete($sessionIds);
}
/**
* destroy session
* @return boolean
*/
public static function destroy()
{
$session = self::getSession();
if (!self::started()) {
$sessionId = $_COOKIE[$session->getSessionName()] ?? '';
if (empty($sessionId) || !$session->checkSessionId($sessionId)) {
return false;
}
return $session->delete($sessionId);
}
if ($session->destroy()) {
$_SESSION = [];
return true;
}
return false;
}
/**
* start session from cookie
* @param boolean $readOnly 是否只读会话
* 以只读形式打开的会话,如果session发生了更改,需要手动调用write()写入会话
* @param string $app
* @return RedisSession
*/
public static function start($readOnly = true)
{
$session = self::getSession();
if ($session->start($readOnly)) {
if (!empty($_SESSION)
&& (!isset($_SESSION['utime']) || (time() - $_SESSION['utime']) > 86400)) {
$_SESSION['utime'] = time();
self::write();
}
return $session;
}
return false;
}
/**
* set session
* @param array $session
* @param boolean $readonly
* @param integer $cookieExpire
* @return boolean
*/
public static function set($appid, $userid, $isLogin, array $session, $maxLogin = 10, $cookieExpire = 0)
{
// 只允许单台设备登录,先清除所有已登录用户的sessionid
if ($isLogin && $maxLogin === 1) {
self::delete_nonguest($appid, $userid);
}
// @todo 大于1小于10, 让用户选择需要下线的设备信息,暂无此需求
$sessionInstance = self::getSession();
if (!$sessionInstance->create($appid, $userid, $isLogin)) {
return false;
// throw new \Exception('session was not started');
}
self::fillup($session);
self::write();
$sessionInstance->setCookie($cookieExpire);
return $sessionInstance->getSessionName() . '=' . $sessionInstance->getSessionId();
}
/**
* fillup $_SESSION
* @param array $session
* @param boolean $readonly
* @return array
*/
public static function fillup(array $session)
{
$_SESSION['utime'] = time();
foreach ($session as $key => $value) {
$_SESSION[$key] = $value;
}
return $_SESSION;
}
/**
* read session data
* @return array
*/
public static function read()
{
self::pickup();
if (!empty($_SESSION)
&& (!isset($_SESSION['utime']) || (time() - $_SESSION['utime']) > 86400)) {
$_SESSION['utime'] = time();
if (self::started()) {
self::write();
} else {
self::close();
}
}
return $_SESSION;
}
/**
* pickup data from session
*/
public static function pickup()
{
if (!empty($_SESSION['userid'])) {
$_GET['userid'] = $_SESSION['userid'];
$_POST['userid'] = $_SESSION['userid'];
$_REQUEST['userid'] = $_SESSION['userid'];
}
if (!isset($_GET['version']) && isset($_SESSION['version'])) {
$_GET['version'] = $_SESSION['version'];
}
if (isset($_SESSION['usertype'])) {
$_GET['usertype'] = $_SESSION['usertype'];
}
if (isset($_SESSION['readonly'])) {
$_GET['readonly'] = $_SESSION['readonly'];
}
}
/**
* get session data
* @return array
*/
public static function get()
{
return $_SESSION;
}
/**
* write session data
* @return boolean
*/
public static function write()
{
return self::getSession()->write();
}
/**
* close session
* @return boolean
*/
public static function close()
{
return self::getSession()->close();
}
}
This diff is collapsed.
<?php
namespace Api\PhpServices\ShopImage;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\QrCode;
class QR
{
private $_content;
private $_size = 300;
private $_logo_url = '';
private $_logo_size = 80;
private $_writeFile = false;
private $_blockSize = QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN;
// private $_errorCorrectionLevel;
public function setRoundBlockSize($_blockSize)
{
$this->_blockSize = $_blockSize;
}
public function setWriteFile(bool $writeFile): void
{
$this->_writeFile = $writeFile;
}
public function setContent($content): void
{
$this->_content = $content;
}
public function setSize(int $size): void
{
$this->_size = $size;
}
public function setLogoUrl(string $logo_url): void
{
$this->_logo_url = $logo_url;
}
public function setLogoSize(int $logo_size): void
{
$this->_logo_size = $logo_size;
}
public function __construct($content)
{
$this->_content = $content;
}
public function get(){
$qr = new QrCode($this->_content);
$qr->setSize($this->_size);
$qr->setRoundBlockSize(true, $this->_blockSize);
if(!empty($this->_logo_url)){
$qr->setLogoPath($this->_logo_url);
$qr->setLogoSize($this->_logo_size);
}
if (!$this->_writeFile) {
header('Content-Type: ' . $qr->getContentType());
}
return $qr->writeString();
}
}
\ No newline at end of file
This diff is collapsed.
### bp暂未接入
```
/**
* 申请 towerpro key
*/
public function keyAction(){
$appid = "test9_appid";
$env = 0;
$version = "124441";
$os = 1;
$creator = "subway";
$keyTag = "test";
$res = Towerpro::create($appid, $env, $version, $os, $creator, $keyTag, $note=null);
$data = [
"keyInfo" => null,
'data' => null
];
if($res && isset($res["result"]) && $res["result"]){
if (isset($res["result"]["data"])){
$data["data"] = $res["result"]["data"];
unset($res["result"]["data"]);
}
$data["keyInfo"] = $res["result"];
}
echo json_encode($res);
return;
}
/**
* 用 key 配置信息
*/
public function setAction(){
$res = Towerpro::set("df436947f7e0d4ad7cc4a9cefdc0a708",[
]);
if($res["code"] == 0){
$this->success();
return;
}
echo json_encode($res);
return;
}
/**
* 用 key 获取信息
*/
public function getAction(){
$res = Towerpro::get("df436947f7e0d4ad7cc4a9cefdc0a708", 1);
echo json_encode($res);
return;
}
```
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
composer.lock
/vendor/
.idea
.DS_Store
.project
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment