Merge branch 'feature/promote' of 47.111.118.107:/srv/git/platform into feature/promote

master
zyx 5 years ago
commit cbfb286d53

81
1

@ -0,0 +1,81 @@
111111101001100000110010111001110100011110010111101110111111100110101000001111111
100000101101110101010010000011011000001010010110100011101011011000000111101000001
101110101001101100000101011111100000101011111111110000000000000110001010101011101
101110100011011110100101111010001110000000101111111111101000000001101010101011101
101110100110010010000110111110101101000101101101111110100100000010010000001011101
100000101010001101110100100010110100010011011110100010101110000001001001001000001
111111101010101010101010101010101010101010101010101010101010101010101010101111111
000000001010000100100001100011110100101001001010100010101001000110001111000000000
001110101001010000010001111110001111111111110111111111101010101100000011011100111
111101000000010101101110111000000001100010111011111010001100110110001110111001111
100011100101100001101001100011001000001000101100000011000110100100000100000111010
010001010010110101000011010011110101011111101110111110011010000110111100000100011
110111100001111111000001101111011010111101100100100011000100111111101010110100111
000101011000011000111111110101001110011101001000011100110101010100010000001001110
101001101000011110011110101010110011000111001100100000001111011011010010111010000
000011011101001000010001000000000111010110000101000100001011000001111110101001000
101001100011101011011011000111000010010110000110101110001001111111010111000101000
110001001110001100100101111100001001010100111000000000011110000100011110001111101
000011101001100111111010011101111110111001100100000001000000001110000011111100010
111011011100000110000101011110000011000100000010011100111110000010101100111101110
100110110010000011111010101000000100000100100100110001100110111111100111000000110
001110011011111100101011001001101001100001101000000100110111000100111100110010010
100010110010000111000111111001111001111111101000111111001010001111001100100000110
111111000101011011000011101011101100100101000010110000101000001001110101000001001
011111111010111101010101111111101000011101100010111110100111110101001001111111100
101110001011110010101001100010010010101000100100100010000111001100111100100010011
001010101011110001010100101011001010101011011110101010010010011110000110101010110
110010001001111100111101100010111001010111001000100010111110100011000010100011110
000111111001010110010010111111010110001101111110111111000101111101000110111110111
001101001101001110101000000100000110011011110110010110000111001011100100110100001
000000111011101000000111101111000110010000010011010010001100111010000110000101110
001100000100010010000011001011011100101000100101101110101111000001110011110111101
100011111000110101000000010001110010001100111010111111100100011101000101000001110
011101000011111110110111010110111010001110111001001000101111100000010100110000010
000011111111110000100101111101110111100010000000010000001010111011111010000101110
011000011100110111111000010100000111001010001110011110001100000110100011110111111
101001101000001100000000011100001101110100011111011010101011101100101011111000110
111011000101000101111111011111101010110001111010100000000001000010100101100111100
011000110010111000011001111011011101100000000101100011011011101110000010111110010
011000010111101110011010101011101111100111100011100110101101000110001011100101101
010111110010110010110010100001011110001110101000100001101010001101101110011001010
110011001100001110110001011011100101101100110111001110010101100111011101101010110
101001110011011001111010010010111001100101011000001011111110111100001011001101110
010011001010011111110011001000111000001101100000100111001110000110001110110100101
000011101111000011101110111100000010001100011001000111100010000111101110010001001
000110011111111110100101110011011011000111101011101000110010101111100100111100011
100111110101101101010100110000111100000110111001001110000100101111010110001100000
100111010001000000111101010011101100111100100101010101100101001000001101110001110
100011111000010111101001111110011011100001111000111111010110000110001100111111001
110110001101000000101100100010010000101111011110100011111100100000000111100010011
100110101100111100000010101011011010010101110111101010001010011111010110101010100
011110001100011000001010100010110101010001011110100011111010010101111011100011110
100111111010111111001010111110100101010111001000111110010010100000001100111111010
111000010110001000110101010101110000111011000001101000110100000010001100000000001
001100110110001111100010010001010001110100011110001001101110111111111010101000110
001000010101011010101100101001010001001011100111000011111111000010001100011001101
101000111110011010110101111001000101000001100100100111110110110000001110100110001
001001011101111100011110000001100001001100101011100101010101101000000100011000000
001101100110101000101110000111011010101001000010001000000110001101010010000100011
000111011100101110100111000110110110110000101110010011001001001110011011001000100
101100110001001100101100010110000100111100111001100000100000000100000010100111000
110111001110111100111010100001011101001011100010010100111100001100111001011001111
011010111000101001110100101100011111001010001111011010000111100000000111110101011
000100011101001011101000101111111101011110011000010111111001011010011100010100101
111000111101110101110001000100101110000011011010110111000110011111001100110111010
000010010110000010111011011001100111111000010100101000101100001010100100010000100
011001101101110111111101001011001111110010001101101100110010111010011001100100110
000110010101100111000001101011000011111100101001101011001110000101101111011001100
100110110001011010001000010110110101001001111010001110110000010111101100100100010
100010010110111111010101111110011000010001001000110100111100001100100110111010110
011100101111111010000111110011101011010101111010000000111010000100001101111111010
010001010011001111011111111111000101101111110000011011110111101010101101001011101
011100100011110000101010111110101111000001001101111110000010011111000000111111010
000000001001100101111100100011110101101011110001100011101100110110001010100010101
111111100101011111011000101010100001111011101001101010001110111111001010101010010
100000100011101011011100100010011111100011001111100010110011001001000110100011000
101110101011111001001001111111110111011011000101111110000100011110010010111110001
101110101000001010000011111011000011001001101111101000101111000110000100111001100
101110101101010111111101000000011001110010001011000001001000001011100100100001000
100000100110110011111111101011001101100110101010011011011110000111000111010111100
111111100111010110110100111000000100011101111011110011001111101100101011100001010

@ -19,6 +19,8 @@ use BaiduBce\Services\Bos\BosOptions;
use BaiduBce\Auth\SignOptions;
use BaiduBce\Log\LogFactory;
use Think\Think;
use Base\Service\GameSourceService;
use Base\Tool\Printer;
/**
* 后台首页控制器
@ -48,10 +50,10 @@ class AutoPackController extends Think
}
$this->checkPackageStatus();
$this->app_package();//app渠道自动打包
// $this->app_package();//app渠道自动打包
$this->channel();
$this->launch_package(false);
$this->leak_detection();
// $this->launch_package(false);
// $this->leak_detection();
}
/**
@ -74,12 +76,10 @@ class AutoPackController extends Think
->where('1=1')
->group('l.id')
->select();
if(!empty($launchGameIds)) {
if(!empty($launchGameIds)) {
$ids = array_column($launchGameIds, 'id');
$launchModel->where(['id'=>['in',$ids]])->setField('launch_packge', 2);
}
$launchIds = $launchModel
@ -92,18 +92,18 @@ class AutoPackController extends Think
->group('apply_id')
->select();
$launchId='';
$launchId = [];
foreach ($launchIds as $launchValue) {
foreach ($launchAllIds as $launchAllValue) {
if($launchValue['apply_id'] == $launchAllValue['apply_id']
&& $launchValue['count'] == $launchAllValue['count']) {
$launchId[]=$launchValue['apply_id'];
$launchId[] = $launchValue['apply_id'];
}
}
}
if(!empty($launchId)) {
$applyModel->where(['id'=>['in',$launchId]])->setField('enable_status', 1);
$applyModel->where(['id'=> ['in',$launchId]])->setField('enable_status', 1);
}
}
@ -292,14 +292,6 @@ class AutoPackController extends Think
/**
* 渠道游戏打包
*
* 针对每个申请游戏检测是否存在投放申请:有则更改投放申请状态,使其进入准备打包状态;无则进行渠道游戏打包
*
* @author: 鹿文学[lwx]<fyj301415926@126.com>
* @since: 2019\4\17 0017 14:27
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
private function channel() {
$zip = new \ZipArchive();
@ -311,140 +303,44 @@ class AutoPackController extends Think
$gameSourceModel = M('Game_source', 'tab_');
$launchModel = M('apply_launch', 'tab_');
$apply_data = $applyModel
-> field('id,game_id,game_name,promote_id,promote_account,sdk_version')
-> where($map)
-> order('bale_sort desc,id desc')
-> limit(200)
-> select();
if (!empty($apply_data)) {
foreach ($apply_data as $key => $value) {
$game_so = $gameSourceModel
-> field('id,file_name,source_version')
-> where(['game_id' => $value['game_id']])
-> find();
if (!file_exists(get_game_source_file_url($value['game_id'])) || null == $game_so) {
$applyModel -> where(['id' => $value['id']]) -> setField('enable_status', -1);
continue;
}
/* 检测是否存在投放申请,存在则更改投放申请信息,否则进行渠道打包 */
$launchCount = $launchModel->where(['apply_id'=>$value['id']])->count();
if($launchCount>0) {
$applyModel->where(['id' => $value['id']]) -> setField('enable_status', 3);
$launchModel->where(['apply_id'=>$value['id'], 'launch_packge'=>['in',[0,2,3]]])->save(['launch_packge'=>2,'launch_down_url'=>'','launch_plist_url'=>'']);
$applys = $applyModel
->field('id,game_id,game_name,promote_id,promote_account,sdk_version')
->where($map)
->order('bale_sort desc,id desc')
->limit(200)
->select();
if (count($applys) == 0) {
Printer::export('无等待队列', true);
}
$applyIds = array_column($applys, 'id');
$gameIds = array_unique(array_column($applys, 'game_id'));
$games = M('game', 'tab_')->field(['id', 'game_appid'])->where(['id' => ['in', $gameIds]])->select();
$games = index_by_column('id', $games);
$launchCountList = $launchModel->field(['apply_id', 'count(*) count'])->where(['apply_id' => ['in', $applyIds]])->group('apply_id')->select();
$launchCountList = index_by_column('apply_id', $launchCountList);
$gameSources = M('game_source', 'tab_')->field(['id', 'file_name', 'source_version', 'file_type', 'bao_name', 'game_id'])->where(['game_id' => ['in', $gameIds]])->select();
$gameSources = index_by_column('game_id', $gameSources);
$gameSourceService = new GameSourceService();
if (!empty($applys)) {
foreach ($applys as $apply) {
$gameSource = $gameSources[$apply['game_id']] ?? null;
$game = $games[$apply['game_id']];
$launchCount = $launchCountList[$apply['id']] ?? 0;
$result = $gameSourceService->channelPack($gameSource, $game, $apply, $launchCount);
$message = '游戏['. $apply['game_id'] . '],渠道['. $apply['promote_id'] . ']打包,';
if ($result['status']) {
$message = 'SUCCESS ----- ' . $message . $result['message'];
} else {
$applyModel -> where(['id' => $value['id']]) -> setField('enable_status', 3);
if ($value['sdk_version'] == 1) {
$str_ver = ".apk";
$file_name = "GamePack";
$url_ver = "META-INF/mch.properties";
} else {
$zip_open_game_source = zip_open(get_game_source_file_url($value['game_id']));
if ($zip_open_game_source) {
while ($zip_entry = zip_read($zip_open_game_source)) {
if (preg_match("/.app/", zip_entry_name($zip_entry))) {
$ios_app = substr(zip_entry_name($zip_entry), 8) . "<br/>";
}
$new_ios_1 = explode("/", $ios_app);
}
zip_close($zip_open_game_source);
}
$str_ver = ".ipa";
$file_name = "IosGamePack";
$url_ver = "Payload/" . $new_ios_1[0] . "/_CodeSignature/TXChannel";
}
$new_name = "game_package" . $value['game_id'] . "-" . $value['promote_id'] . $str_ver;
$to = "./Uploads/" . $file_name . "/" . $new_name;
$localPath = ROOTTT . ltrim($to, './');
copy(get_game_source_file_url($value['game_id']), $localPath);
$zip_res = $zip -> open(ROOTTT . ltrim($to, './'), \ZipArchive::CREATE);
if ($zip_res == true) {
#打包数据
$pack_data = array(
"game_id" => $value["game_id"],
"game_name" => $value['game_name'],
"game_appid" => get_game_appid($value["game_id"], "id"),
"promote_id" => $value['promote_id'],
"promote_account" => $value['promote_account'],
"source_version" => $game_so['source_version'],
);
$zip -> addFromString($url_ver, json_encode($pack_data));
$zip -> close();
$newname = "game_package" . $value["game_id"] . "-" . $value['promote_id'] . $str_ver;
if (get_tool_status("oss_storage") == 1) {
if (C("oss_storage.is_cname")) {
$to = "http://" . C("oss_storage.domain") . "/" . str_replace("IosGamePack", "GamePack", $file_name) . "/" . $newname;
} else {
$to = "https://" . C("oss_storage.bucket") . "." . C("oss_storage.domain") . "/" . str_replace("IosGamePack", "GamePack", $file_name) . "/" . $newname;
$to = str_replace('-internal', '', $to);
}
if (!empty(C('oss_storage.bd_domain')) && strlen(C('oss_storage.bd_domain')) > 5) {
$to = C('oss_storage.bd_domain') . "/GamePack/" . $newname;
}
$new_to = ROOTTT . "Uploads/" . $file_name . "/" . $newname;
$updata['savename'] = $newname;
$updata['path'] = $new_to;
$this -> upload_game_pak_oss($updata);
if (file_exists($new_to)) {
@unlink($new_to);
}
} elseif (get_tool_status("qiniu_storage") == 1) {
$this -> dleteQiNiuFile($newname);
$url = $this -> upQiNiuFile($newname, ROOTTT . ltrim($to, './'));
if (empty($url)) {
$this -> error('七牛错误,请检查七牛配置,并确保七牛空间权限正确!');
}
@unlink(ROOTTT . ltrim($to, './'));
$to = "http://" . $url;
} elseif (get_tool_status("cos_storage") == 1) {
$new_to = ROOTTT . "Uploads/" . $file_name . "/" . $newname;
$updata['path'] = $new_to;
$updata['savename'] = 'GamePack/'. $newname;
$to = $this->upload_cos($updata);
} elseif (get_tool_status("bos_storage") == 1) {
$newname = "game_package" . $value["game_id"] . "-" . $value['promote_id'] . $str_ver;
$to = "http://" . C("bos_storage.bucket") . "." . C("bos_storage.domain") . "/" . $file_name . "/" . $newname;
$to = str_replace('-internal', '', $to);
$new_to = ROOTTT . "Uploads/" . $file_name . "/" . $newname;
$updata['savename'] = $newname;
$updata['path'] = $new_to;
$this -> upload_bos($updata);
}
$promote = array('game_id' => $value['game_id'], 'promote_id' => $value['promote_id']);
$plist_url = '';
if ($value['sdk_version'] == 2) {
$plist_url = $this -> create_plist($promote['game_id'], $promote['promote_id'], get_payload_name($value['game_id']), $to);
}
$jieguo = $this -> updateinfo($value['id'], $to, $promote, $plist_url);
}
$message = 'ERROR ----- ' . $message . $result['message'];
}
Printer::export($message);
}
}
}
@ -456,21 +352,26 @@ class AutoPackController extends Think
$map['a.status'] = 1;
$map['a.enable_status'] = 1;
$map['al.launch_packge'] = array('in', [0, 2, 3]);
$apply = $applymodel -> alias('a')
-> field('a.id,a.game_id,a.game_name,a.promote_account,a.pack_url,a.plist_url,a.promote_id,a.sdk_version,a.enable_status')
-> join('tab_apply_launch as al on (al.apply_id=a.id) ')
-> where($map) -> limit(3) -> group('a.id') -> select();
$apply = $applymodel->alias('a')
->field('a.id,a.game_id,a.game_name,a.promote_account,a.pack_url,a.plist_url,a.promote_id,a.sdk_version,a.enable_status')
->join('tab_apply_launch as al on (al.apply_id=a.id) ')
->where($map)
->limit(300)
->group('a.id')
->select();
foreach ($apply as $key => $value) {
$game_so = $game_somodel -> field('id,file_name,source_version') -> where(['game_id' => $value['game_id']]) -> find();
if (!file_exists(get_game_source_file_url($value['game_id'])) || null == $game_so) {
$gameSource = $gameSourceModel
->field('id,file_name,source_version,file_type')
->where(['game_id' => $value['game_id']])
->find();
$gameSourceUrl = $gameSourceService->getGameSourceUrl($gameSource);
if ($gameSource || !file_exists($gameSourceUrl)) {
M('apply', 'tab_') -> where(['id' => $value['id']]) -> setField('enable_status', -1);
$launchmodel -> where(['apply_id' => $value['id']]) -> setField('launch_packge', 0);
continue;
}
$url = get_game_source_file_url($value['game_id']);
if (!empty($url) && is_file($url)) {
if (!empty($gameSourceUrl) && is_file($gameSourceUrl)) {
$launch = $launchmodel -> where(['apply_id' => $value['id'], 'launch_packge' => array('in', [0, 2, 3])]) -> select();
$zip = new \ZipArchive();
@ -478,19 +379,19 @@ class AutoPackController extends Think
if ($value['sdk_version'] == 1) {
if (!empty($v['game_source_filename'])) {
if ($v['game_source_filename'] == $game_so['file_name']) {
if ($v['game_source_filename'] == $gameSource['file_name']) {
if (!empty($v['launch_down_url'])) {
$launchmodel -> where(['id' => $v['id']]) -> setField(['launch_packge' => 1]);
continue;
}
}
}
$str_ver = ".apk";
$str_ver = '.apk';
$file_name = "GamePack";
$url_ver = "META-INF/mch.properties";
} else {
if (!empty($v['game_source_filename'])) {
if ($v['game_source_filename'] == $game_so['file_name']) {
if ($v['game_source_filename'] == $gameSource['file_name']) {
if (!empty($v['launch_plist_url'])) {
if (!empty($v['launch_down_url'])) {
$launchmodel -> where(['id' => $v['id']]) -> setField(['launch_packge' => 1]);
@ -499,7 +400,7 @@ class AutoPackController extends Think
}
}
}
$zip_open_game_source = zip_open($url);
$zip_open_game_source = zip_open($gameSourceUrl);
if ($zip_open_game_source) {
while ($zip_entry = zip_read($zip_open_game_source)) {
if (preg_match("/.app/", zip_entry_name($zip_entry))) {
@ -516,7 +417,7 @@ class AutoPackController extends Think
}
$new_name = "game_package" . $value['game_id'] . "-" . $value['promote_id'] . "-" . $v['platform_id'] . "-" . $v['position'] . $str_ver;
$to = "./Uploads/" . $file_name . "/" . $new_name;
copy($url, ROOTTT . ltrim($to, './'));
copy($gameSourceUrl, ROOTTT . ltrim($to, './'));
$zip_res = $zip -> open(ROOTTT . ltrim($to, './'), \ZipArchive::CREATE);
if ($zip_res == true) {
#打包数据
@ -526,7 +427,7 @@ class AutoPackController extends Think
"game_appid" => get_game_appid($value["game_id"], "id"),
"promote_id" => $value['promote_id'],
"promote_account" => $value['promote_account'],
"source_version" => $game_so['source_version'],
"source_version" => $gameSource['source_version'],
'launch_id' => $v['platform_id'],
'position' => $v['position'],
);
@ -595,7 +496,7 @@ class AutoPackController extends Think
if ($value['sdk_version'] == 2) {
$plist_url = $this -> create_plist($promote['game_id'], $promote['promote_id'], get_payload_name($value['game_id']), $to, $v['platform_id'], $v['position']);
}
$jg = $this -> update_launch_info(['platform_id' => $v['platform_id'], 'apply_id' => $value['id'], 'position'=>$v['position']], $to, $plist_url, $game_so['file_name']);
$jg = $this -> update_launch_info(['platform_id' => $v['platform_id'], 'apply_id' => $value['id'], 'position'=>$v['position']], $to, $plist_url, $gameSource['file_name']);
}
@ -643,7 +544,7 @@ class AutoPackController extends Think
{
$map['status'] = 1;
$map['enable_status'] = 2;
$arr_id = M('app_apply', 'tab_') -> field('id') -> where($map) -> order('id desc') -> limit(3) -> select();
$arr_id = M('app_apply', 'tab_')->field('id')->where($map)->order('id desc')->limit(300)->select();
if (empty($arr_id)) {
return false;
}
@ -722,8 +623,6 @@ class AutoPackController extends Think
$apply_data['dow_url'] = $to;
$apply_data['enable_status'] = 1;
M('app_apply', 'tab_') -> save($apply_data);
}
}
@ -736,7 +635,7 @@ class AutoPackController extends Think
*/
public function updateinfo($id, $pack_url, $promote, $plist_url)
{
$model = M('Apply', "tab_");
$data = [];
$data['id'] = $id;
$data['pack_url'] = $pack_url;
$data['dow_url'] = '/index.php?s=/Home/Down/down_file/game_id/' . $promote['game_id'] . '/promote_id/' . $promote['promote_id'];
@ -745,7 +644,7 @@ class AutoPackController extends Think
$data['dispose_id'] = UID;
$data['dispose_time'] = NOW_TIME;
$data['plist_url'] = $plist_url;
$res = $model -> save($data);
$res = M('Apply', 'tab_')->save($data);
return $res;
}

@ -0,0 +1,27 @@
<?php
/**
* 定时自动完成
*/
namespace Admin\Controller;
use Admin\Model\SpendModel;
use Think\Think;
use Org\RedisSDK\Redis;
class AutoController extends Think {
protected function _initialize()
{
C(api('Config/lists'));
}
public function modifyUserRole()
{
M('user_play_info', 'tab_')->select(['game_id', 'server_id', 'role_id'])->group('game_id, server_id, role_id')->having('count(*)>1')->select();
}
public function modifyRecharge()
{
}
}

@ -54,8 +54,8 @@ class GameSourceController extends ThinkController
$extend = substr($_POST['file_name'], strlen($_POST['file_name']) - 3, 3);
if ($_POST['file_type'] == 1 && $extend != 'apk') {
$this -> error('游戏原包格式不正确!');
} else if ($_POST['file_type'] == 2 && $extend != 'ipa' || $_POST['file_type'] == 2 && empty($_POST['bao_name'])) {
$this -> error('游戏原包格式不正确/包名不能为空');
} else if ($_POST['file_type'] == 2 && $extend != 'ipa') {
$this -> error('游戏原包格式不正确');
}
}
$map['game_id'] = $_POST['game_id'];
@ -136,17 +136,17 @@ class GameSourceController extends ThinkController
$extend = substr($_POST['file_name'], strlen($str) - 3, 3);
if ($_POST['file_type'] == 1 && $extend != 'apk') {
$this -> error('游戏原包格式不正确!');
} else if ($_POST['file_type'] == 2 && $extend != 'ipa' || $_POST['file_type'] == 2 && empty($_POST['bao_name'])) {
$this -> error('游戏原包格式不正确/包名不能为空');
} else if ($_POST['file_type'] == 2 && $extend != 'ipa') {
$this -> error('游戏原包格式不正确');
}
}
$map['file_type'] = $_POST['file_type'];
$d = D('Game_source') -> where($map) -> find();
$source = A('Source', 'Event');
if (empty($d)) {
$source -> add_source();
$source->add_source();
} else {
$source -> update_source($d['id'], $d['file_name']);
$source->update_source($d['id'], $d['file_name']);
}
} else {
$d = M('GameSource', "tab_") -> where($map) -> find();

@ -9,6 +9,9 @@
namespace Admin\Event;
use Think\Controller;
use Base\Service\GameSourceService;
use Base\Tool\PlistParser;
use Base\Tool\ApkParser;
/**
* 后台首页控制器
@ -20,38 +23,52 @@ class SourceEvent extends Controller
public function add_source()
{
$model = D('Game_source');
$plist = A("Plist");
$data = $_REQUEST;
$data['file_size'] = round($data['file_size'] / pow(1024, 2), 2) . "MB";
/*if ($data['file_type'] == 2) {
if (preg_match("/.ipa/", $data['file_name'])) {
//copy($data['file_url'] . "/" . $data['file_name'], "./Uploads/Ios/original/" . $data['file_name']);
//@unlink($data['file_url'] . "/" . $data['file_name']);
//$data['file_url'] = "./Uploads/Ios/original";
}
}*/
$data['file_url'] = $data['file_url'] . "/" . $data['file_name'];
$data['sdk_version'] = $data['file_type'];
$data['op_id'] = UID;
$data['version'] = $_POST['version'];
$data['op_account'] = session("user_auth.username");
$data['create_time'] = NOW_TIME;
$remark = str_replace(array("\r\n", "\r", "\n"), "@@@", $_POST['remark']);
$data['remark'] = json_encode(explode('@@@', $remark));
if ($data['file_type'] == 2) {
$data['plist_url'] = "./Uploads/SourcePlist/" . $data['game_id'] . ".Plist";
$data['org_plist_url'] = "./Uploads/OrgSourcePlist/" . $data['game_id'] . ".Plist";
$plist -> create_plist($data['game_id'], 0, $data['bao_name'], $data['file_url']);
$data['source_version'] = 0;
$version = '';
$packageName = '';
if ($data['file_type'] == 1) {
$parser = new ApkParser();
$parser->open($data['file_url']);
$version = $parser->getVersionName();
$packageName = $parser->getPackage();
} elseif($data['file_type'] == 2) {
$parser = new PlistParser();
$parser->openFromIpa($data['file_url'], PlistParser::PREG_INFO_PLIST);
$result = $parser->getResult();
$version = $result['CFBundleShortVersionString'];
$packageName = $result['CFBundleIdentifier'];
}
$res = $model -> add($data);
if ($res) {
$data['version'] = $version;
$data['bao_name'] = $packageName;
$game = M('game', 'tab_')->where(['id' => $data['game_id']])->find();
$gameSourceService = new GameSourceService();
$result = $gameSourceService->sourcePack($data, $game);
var_dump($result);
if (!$result['status']) {
var_dump($result);die();
$this->error('添加失败' , U('GameSource/lists', ['type' => $data['type']]));
}
$data['plist_url'] = $result['data']['plistUrl'];
$data['org_plist_url'] = $result['data']['orgPlistUrl'];
$data['file_url'] = $result['data']['fileUrl'];
$data['original_url'] = $result['data']['originalUrl'];
if (M('game_source', 'tab_')->add($data)) {
//原包打包
$this -> soure_pack($data['game_id'], $data['file_url'], $data['file_type'], 1, $data['bao_name']);
$this -> update_game_size($data);
$this -> success('添加成功', U('GameSource/lists', array('type' => $data['type'])));
$this->update_game_size($data);
var_dump('success');die();
$this->success('添加成功', U('GameSource/lists', ['type' => $data['type']]));
} else {
$this -> error('添加失败', U('GameSource/lists', array('type' => $data['type'])));
var_dump('error');die();
$this->error('添加失败', U('GameSource/lists', ['type' => $data['type']]));
}
}
@ -65,23 +82,8 @@ class SourceEvent extends Controller
$plist = A("Plist");
$data = $_REQUEST;
$url = $data['file_url'];
$urll = $data['file_url2'];
/*if ($data['file_type'] == 2) {
if (preg_match("/.ipa/", $data['file_name']) && ($data['file_name'] != $file_name)) {
//copy($data['file_url'] . "/" . $data['file_name'], "./Uploads/Ios/original/" . $data['file_name']);
//@unlink($data['file_url'] . "/" . $data['file_name']);
//$data['file_url'] = "./Uploads/Ios/original";
//$url = "./Uploads/Ios/original";
}
}*/
$urll = $data['file_url2'];
$data['file_size'] = strpos($data['file_size'], 'MB') ? $data['file_size'] : round($data['file_size'] / pow(1024, 2), 2) . "MB";
/*$extend = substr($data['file_url'], strlen($str) - 3, 3);
if ($extend != "apk" && $extend != "ipa") {
$data['file_url'] = $data['file_url'] . "/" . $data['file_name'];
}*/
$data['file_url'] = $data['file_url'] . "/" . $data['file_name'];
$data['id'] = $id;
$data['op_id'] = UID;
@ -89,69 +91,72 @@ class SourceEvent extends Controller
$data['create_time'] = NOW_TIME;
$remark = str_replace(array("\r\n", "\r", "\n"), "@@@", $_POST['remark']);
$data['remark'] = json_encode(explode('@@@', $remark));
$game_source = $model -> where(array('id' => $id)) -> find();
$game_source = $model->where(['id' => $id])->find();
if($game_source['file_name'] == $data['file_name']) {
if ($from == "dev") {
$this -> success('修改成功', U('Developers/source'));
} else {
$this -> success('修改成功', U('GameSource/lists'));
}
}
if ($data['file_type'] == 2) {
$data['plist_url'] = "./Uploads/SourcePlist/" . $data['game_id'] . ".Plist";
$data['org_plist_url'] = "./Uploads/OrgSourcePlist/" . $data['game_id'] . ".Plist";
$plist -> create_plist($data['game_id'], 0, $data['bao_name'], $data['file_url']);
}
$data['source_version'] = $game_source['source_version'] + 1;
$res = $model -> save($data);
$game = M('game', 'tab_')->where(['id' => $data['game_id']])->find();
$gameSourceService = new GameSourceService();
$result = $gameSourceService->sourcePack($data, $game);
if (!$result['status']) {
if ($from == "dev") {
$this->error('修改失败', U('Developers/source'));
} else {
$this->error('修改失败', U('GameSource/lists'));
}
}
$data['plist_url'] = $result['data']['plistUrl'];
$data['org_plist_url'] = $result['data']['orgPlistUrl'];
$data['file_url'] = $result['data']['fileUrl'];
$data['original_url'] = $result['data']['originalUrl'];
if ($res) {
//原包打包
$this -> soure_pack($game_source['game_id'], $data['file_url'], $data['file_type'], $data['source_version'], $data['bao_name'], 1, $file_name);
if ($model->save($data)) {
//渠道包加入打包队列
$appmodel = M('Apply', 'tab_');
$app_map['status'] = 1;
$app_map['game_id'] = $game_source['game_id'];
$app_data = $appmodel -> where($app_map) -> select();
$app_data = $appmodel->where($app_map)->select();
if ($app_data) {
M() -> startTrans();
$app_res = $appmodel -> where($app_map) ->save(['enable_status'=>2, 'pack_url'=>'', 'plist_url'=>'']);
M('apply_launch', 'tab_') -> where(['launch_game_id'=>$game_source['game_id']]) -> setField('launch_packge', 0);
M()->startTrans();
$app_res = $appmodel->where($app_map)->save(['enable_status'=>2, 'pack_url'=>'', 'plist_url'=>'']);
M('apply_launch', 'tab_') -> where(['launch_game_id'=>$game_source['game_id']])->setField('launch_packge', 0);
if ($app_res === false) {
M() -> rollback();
M()->rollback();
if ($from == "dev") {
$this -> error('渠道包打包失败', U('Developers/source'));
$this->error('渠道包打包失败', U('Developers/source'));
} else {
$this -> error('渠道包打包失败', U('GameSource/lists'));
$this->error('渠道包打包失败', U('GameSource/lists'));
}
} else {
M() -> commit();
M()->commit();
}
}
@unlink($url . "/" . $file_name);
@unlink($urll . "/" . str_replace('.ipa', '.mobileprovision', $file_name));
$this -> update_game_size($data);
$this->update_game_size($data);
//发送站内信
$user_id = M('ucenter_member') -> where('status=1') -> field('id') -> select();
$content = '游戏:' . get_game_name($data['game_id']) . ' 已更新,请尽快处理渠道包';
$sdk_version = M('game', 'tab_') -> field('sdk_version') -> where(['id' => $data['game_id']]) -> find();
D('Msg') -> sendMsg2($user_id, $content, $sdk_version['sdk_version'], $data['game_id']);
if ($from == "dev") {
$this -> success('修改成功', U('Developers/source'));
$users = M('ucenter_member')->where('status=1') -> field('id')->select();
$content = '游戏:' . $game['game_name'] . ' 已更新,请尽快处理渠道包';
D('Msg')->sendMsg2($users, $content, $game['sdk_version'], $game['id']);
if ($from == "dev") {
$this->success('修改成功', U('Developers/source'));
} else {
$this -> success('修改成功', U('GameSource/lists'));
$this->success('修改成功', U('GameSource/lists'));
}
} else {
if ($from == "dev") {
$this -> error('修改失败', U('Developers/source'));
$this->error('修改失败', U('Developers/source'));
} else {
$this -> error('修改失败', U('GameSource/lists'));
$this->error('修改失败', U('GameSource/lists'));
}
}
@ -280,23 +285,18 @@ class SourceEvent extends Controller
Vendor('OSS.autoload');
$ossClient = new \OSS\OssClient(C("oss_storage.accesskeyid"), C("oss_storage.accesskeysecr"), C("oss_storage.domain"), C("oss_storage.is_cname"));
} catch (OssException $e) {
$this -> error($e -> getMessage());
$this -> error($e->getMessage());
}
$bucket = C('oss_storage.bucket');
// if(preg_match('/.apk/',$return_data['savename']) ){
$oss_name = "SourcePack";
// }else{
// $oss_name="IosGamePack";
// }
$oss_file_path = $oss_name . "/" . $return_data["savename"];
$avatar = $return_data["path"];
try {
$this -> multiuploadFile($ossClient, $bucket, $oss_file_path, $avatar);
$this->multiuploadFile($ossClient, $bucket, $oss_file_path, $avatar);
return true;
} catch (OssException $e) {
/* 返回JSON数据 */
$this -> error($e -> getMessage());
$this->error($e -> getMessage());
}
}

@ -123,13 +123,13 @@
<tr>
<td class="l"><i class="mustmark" style="margin-left:-7px;display:none" id="apply_bz">*</i>包名:</td>
<td class="r">
<input type="text" class="txt" name="bao_name" value="">
<input type="text" class="txt" name="bao_name" style="background:#E7E7E7" value="无需填写,自动生成" disabled="disabled">
</td>
</tr>
<tr>
<td class="l">原包版本:</td>
<td class="r">
<input type="text" class="txt" name="version" value="">
<input type="text" class="txt" name="version" style="background:#E7E7E7" value="无需填写,自动生成" disabled="disabled">
</td>
</tr>

@ -110,14 +110,13 @@
</eq>
包名:</td>
<td class="r">
<input type="text" class="txt" name="bao_name" value="{$data['bao_name']}">
<input type="text" class="txt" name="bao_name" style="background:#E8E8E8" value="{$data['bao_name']}" disabled="disabled" readonly="true">
</td>
</tr>
<tr>
<td class="l">原包版本:</td>
<td class="r">
<input type="text" class="txt table_btn_input" name="version" value="{$data['version']}" readonly="true">
<a href="javascript:" id='version_click' class="table_click">点击修改</a>
<input type="text" class="txt table_btn_input" style="background:#E8E8E8" name="version" value="{$data['version']}" disabled="disabled" readonly="true">
</td>
</tr>

@ -0,0 +1,26 @@
<?php
namespace Base\Facade;
use Base\Tool\Request as BaseRequest;
/**
* @author elf<360197197@qq.com>
*/
class Request {
private static $instance;
public static function getInstance()
{
if (self::$instance == null) {
self::$instance = new BaseRequest();
}
return self::$instance;
}
public static function __callStatic($name, $arguments)
{
$instance = self::getInstance();
return call_user_func_array([$instance, $name], $arguments);
}
}

@ -3,14 +3,51 @@ namespace Base\Service;
use Base\Model\PromoteModel;
use Base\Model\ApplyModel;
use Base\Facade\Request;
class ApplyService {
private $model;
const ENCRYPT_METHOD = 'AES-256-ECB';
const ENCRYPT_KEY = 'WmtX1@#Landing&Download2048';
const ENCRYPT_TYPE_DOWNLOAD = 1;
const ENCRYPT_TYPE_LANDING_PAGE = 2;
public static $enableStatusList = [
'-1' => '打包失败',
'0' => '打包失败',
'1' => '打包成功 ',
'2' => '准备打包 ',
'3' => '打包中',
];
public function __construct()
{
$this->model = new ApplyModel();
}
public function checkApplyStatus($apply)
{
if ($apply['status'] == 0) {
return [
'status' => false,
'message' => '游戏未审核',
];
}
if ($apply['offline_status'] == 1) {
return [
'status' => false,
'message' => '游戏已下架',
];
}
if ($apply['enable_status'] != 1) {
return [
'status' => false,
'message' => self::$enableStatusList[$apply['enable_status']] ?? '未知错误',
];
}
return [
'status' => true,
'message' => '游戏打包成功',
];
}
public function cancelGame($gameId, $promoteId) {
@ -22,4 +59,85 @@ class ApplyService {
M('apply', 'tab_')->where(['game_id' => $gameId, 'promote_id' => ['in', $ids]])->save($save);
}
public function updateAfterPack($apply, $packageUrl, $plistUrl)
{
$data = [];
$data['id'] = $apply['id'];
$data['pack_url'] = $packageUrl;
$data['dow_url'] = '/index.php?s=/Home/Down/down_file/game_id/' . $apply['game_id'] . '/promote_id/' . $apply['promote_id'];
$data['dow_status'] = 1;
$data['enable_status'] = 1;
$data['dispose_id'] = 0;
$data['dispose_time'] = time();
$data['plist_url'] = $plistUrl;
return M('Apply', 'tab_')->save($data);
}
public function getDownloadUrl($apply)
{
$host = Request::getHost();
$code = $this->encodeApplyCode($apply, self::ENCRYPT_TYPE_DOWNLOAD);
return $host . '/index.php?s=/Home/Download/index/code/' . $code;
}
public function getLandingPageUrl($apply)
{
$host = Request::getHost();
$code = $this->encodeApplyCode($apply, self::ENCRYPT_TYPE_LANDING_PAGE);
return $host . '/index.php?s=/Home/Home/landingPage/code/' . $code;
}
public function encodeApplyCode($apply, $type)
{
$expiresIn = 0;
$data = [
'promote_id' => $apply['promote_id'],
'game_id' => $apply['game_id'],
'expires_in' => $expiresIn,
'created_at' => date('Y-m-d H:i:s'),
'type' => $type
];
$jsonStr = json_encode($data);
return base64_encode(openssl_encrypt($jsonStr, self::ENCRYPT_METHOD, self::ENCRYPT_KEY));
}
public function decodeApplyCode($code)
{
$decryptStr = openssl_decrypt(base64_decode($code), self::ENCRYPT_METHOD, self::ENCRYPT_KEY);
return json_decode($decryptStr, true);
}
public function checkApplyCode($data, $type)
{
if (
!isset($data['promote_id']) ||
!isset($data['game_id']) ||
!isset($data['expires_in']) ||
!isset($data['created_at']) ||
!isset($data['type'])
) {
return [
'status' => false,
'message' => '参数异常',
];
}
if ($data['type'] != $type) {
return [
'status' => false,
'message' => '参数异常',
];
}
if ($data['expires_in'] > 0 && time() > (strtotime($data['created_at']) + $data['expires_in'])) {
return [
'status' => false,
'message' => '链接已过期',
];
}
return [
'status' => true,
'message' => '验证成功',
];
}
}

@ -3,38 +3,62 @@ namespace Base\Service;
use Base\Model\PromoteModel;
use Base\Model\ApplyModel;
use Base\Tool\Base62;
class GameSourceService {
const IS_FIXED_IOS13 = true;
public function __construct()
{
}
public function getChannelConfigFile($gameSource) {
/**
* 获取IPA中的.app后缀目录
*/
public function getIpaAppPath($ipaPath)
{
$appPath = '';
$zipGameSource = zip_open($ipaPath);
if ($zipGameSource) {
while ($zipEntry = zip_read($zipGameSource)) {
if (preg_match("/^Payload.*?\.app/", zip_entry_name($zipEntry), $matches)) {
$appPath = $matches[0];
break;
}
}
zip_close($zipGameSource);
}
return $appPath;
}
public function getChannelConfigFile($gameSource)
{
$configUrl = '';
if ($gameSource['sdk_version'] == 1) {
$configUrl = "META-INF/mch.properties";
} else {
$preUrl = '';
$zipGameSource = zip_open($this->getGameSourceUrl($gameSource));
if ($zipGameSource) {
while ($zipEntry = zip_read($zipGameSource)) {
if (preg_match("/^Payload.*?\.app/", zip_entry_name($zipEntry), $matches)) {
$preUrl = $matches[0];
break;
}
}
zip_close($zipGameSource);
}
$configUrl = $preUrl . '/_CodeSignature/TXChannel';
$appPath = $this->getIpaAppPath($this->getGameSourceUrl($gameSource));
$configUrl = $appPath . '/_CodeSignature/TXChannel';
}
return $configUrl;
}
public function getGameSourceUrl($gameSource){
public function getChannelConfigFolder($gameSource, array $packData)
{
$gameSourceUrl = $this->getGameSourceUrl($gameSource);
$appPath = $this->getIpaAppPath($this->getGameSourceUrl($gameSource));
return $appPath . '/' . Base62::encode($packData);
}
public function getGameSourceUrl($gameSource)
{
if (empty($gameSource)) {
return '';
}
$path = '';
if($gameSource['file_type'] == '1'){
if($gameSource['file_type'] == 1){
$path = './Uploads/SourcePack/';
}else{
$path = './Uploads/Ios/original/';
@ -42,4 +66,324 @@ class GameSourceService {
$fileUrl = $path . $gameSource['file_name'];
return ROOTTT . ltrim($fileUrl, './');
}
public function packChannel($localPath, $game, $gameSource, $apply = null)
{
$packData = [
'game_id' => $game['id'],
'game_name' => $game['game_name'],
'game_appid' => $game['game_appid'],
'promote_id' => $apply ? $apply['promote_id'] : '',
'promote_account' => $apply ? $apply['promote_account'] : '自然渠道',
'source_version' => $gameSource['source_version'],
];
if (self::IS_FIXED_IOS13 && $game['sdk_version'] == 2) {
$channelFolder = $this->getChannelConfigFolder($gameSource, $packData);
return $this->packChannelFolder($localPath, $channelFolder);
} else {
$channelFile = $this->getChannelConfigFile($gameSource);
return $this->packChannelFile($localPath, $channelFile, $packData);
}
return false;
}
/**
* 打入渠道信息文件
* @param string $zipFile 包文件地址
* @param string $distFile 打入文件名
* @param array $packData 打入信息
* @return boolean 是否成功
*/
public function packChannelFile($zipFile, $distFile, array $packData)
{
$zip = new \ZipArchive();
if ($zip->open($zipFile, \ZipArchive::CREATE)) {
$zip->addFromString($distFile, json_encode($packData));
$zip->close();
return true;
}
return false;
}
/**
* 打入渠道信息目录用于IOS主要为了解决IOS13问题
* @param string $zipFile 包文件地址
* @param string $distFolder 打入文件夹
* @return boolean 是否成功
*/
public function packChannelFolder($zipFile, $distFolder)
{
$zip = new \ZipArchive();
if ($zip->open($zipFile, \ZipArchive::CREATE)) {
$zip->addEmptyDir($distFolder);
$zip->close();
return true;
}
return false;
}
/**
* 原包打包
*/
public function sourcePack($gameSource, $game)
{
$relativeUrl = $gameSource['file_url'];
$localPath = ROOTTT . ltrim($relativeUrl, './');
$originalUrl = '';
if ($game['sdk_version'] == 2) {
$oldLocalPath = $localPath;
$localPath = str_replace('Uploads/SourcePack', 'Uploads/Ios/original', $oldLocalPath);
$originalUrl = $relativeUrl;
copy($oldLocalPath, $localPath);
}
$status = $this->packChannel($localPath, $game, $gameSource);
if (!$status) {
return [
'status' => false,
'message' => '打包失败,原包加入信息失败!',
];
}
$distFilePath = 'SourcePack/' . $gameSource['file_name'];
$result = $this->uploadPackage($localPath, $distFilePath);
$fileUrl = '';
if ($result['status']) {
$fileUrl = $result['data']['url'];
$fileUrl = $fileUrl == '@' ? $relativeUrl : $fileUrl;
} else {
return [
'status' => false,
'message' => '打包失败上传OSS失败' . $result['message'],
];
}
$plistUrl = '';
$orgPlistUrl = '';
if ($game['sdk_version'] == 2) {
$params = [
'domain' => '',
'packageName' => $gameSource['bao_name'],
'gameId' => $game['id'],
'promoteId' => 0,
'packageUrl' => $fileUrl,
'gameIcon' => '',
'type' => 'pack'
];
$result = $this->createPlist($params);
if ($result['status']) {
$plistUrl = $result['data']['path'];
} else {
return [
'status' => false,
'message' => '打包失败生成plist文件失败' . $result['message'],
];
}
$params['type'] = 'org';
$result = $this->createPlist($params);
if ($result['status']) {
$orgPlistUrl = $result['data']['path'];
} else {
return [
'status' => false,
'message' => '打包失败生成原包plist文件失败' . $result['message'],
];
}
}
return [
'status' => true,
'message' => '打包成功!',
'data' => [
'plistUrl' => $plistUrl,
'orgPlistUrl' => $orgPlistUrl,
'fileUrl' => $fileUrl,
'originalUrl' => $originalUrl,
]
];
}
/**
* 渠道打包
*/
public function channelPack($gameSource, $game, $apply, $launchCount = 0)
{
$gameSourceUrl = $this->getGameSourceUrl($gameSource);
if ($gameSource == null || !file_exists($gameSourceUrl)) {
M('apply', 'tab_')->where(['id' => $apply['id']])->setField('enable_status', -1);
}
/* 检测是否存在投放申请,存在则更改投放申请信息,否则进行渠道打包 */
if ($launchCount > 0) {
M('apply', 'tab_')->where(['id' => $apply['id']])->setField('enable_status', 3);
$launchData = ['launch_packge' => 2, 'launch_down_url'=>'' , 'launch_plist_url'=>''];
M('apply_launch', 'tab_')->where(['apply_id' => $apply['id'], 'launch_packge'=>['in', [0, 2, 3]]])->save($launchData);
}
$savePath = '';
$fileName = 'game_package' . $apply['game_id'] . '-' . $apply['promote_id'];
if ($apply['sdk_version'] == 1) {
$fileName .= '.apk';
$savePath = 'Uploads/GamePack/' . $fileName;
} else {
$fileName .= '.ipa';
$savePath = 'Uploads/IosGamePack/' . $fileName;
}
$relativePath = './' . $savePath;
$localPath = ROOTTT . $savePath;
copy($gameSourceUrl, $localPath);
$status = $this->packChannel($localPath, $game, $gameSource, $apply);
if (!$status) {
return [
'status' => false,
'message' => '打包失败,加入渠道信息失败!',
];
}
$distFilePath = 'GamePack/' . $fileName;
$result = $this->uploadPackage($localPath, $distFilePath, false);
if ($result['status']) {
$packageUrl = $result['data']['url'];
$packageUrl = $packageUrl == '@' ? $relativePath : $packageUrl;
} else {
return [
'status' => false,
'message' => '打包失败上传OSS失败' . $result['message'],
];
}
$plistInfo = ['game_id' => $apply['game_id'], 'promote_id' => $apply['promote_id']];
$plistUrl = '';
if ($apply['sdk_version'] == 2) {
$params = [
'domain' => '',
'packageName' => $gameSource['bao_name'],
'gameId' => $game['id'],
'promoteId' => $apply['promote_id'],
'packageUrl' => $packageUrl,
'gameIcon' => '',
'type' => 'pack'
];
$result = $this->createPlist($params);
if ($result['status']) {
$plistUrl = $result['data']['path'];
} else {
return [
'status' => false,
'message' => '打包失败生成plist文件失败' . $result['message'],
];
}
}
$applyService = new ApplyService();
$applyService->updateAfterPack($apply, $packageUrl, $plistUrl);
return [
'status' => true,
'message' => '打包成功!',
'data' => [
'plistUrl' => $plistUrl,
]
];
}
public function uploadPackage($localFilePath, $distFilePath, $isDeleteLocal = false)
{
if (get_tool_status('oss_storage') == 1) {
$ossService = new OssService();
$result = $ossService->upload($localFilePath, $distFilePath);
if ($isDeleteLocal && file_exists($localFilePath)) {
@unlink($localFilePath);
}
return $result;
} else {
// 不上传OSS等第三方服务器
return [
'status' => true,
'message' => '上传成功',
'data' => [
'url' => '@'
],
];
}
}
//生成游戏渠道plist文件
public function createPlist($params)
{
$domain = $params['domain'] ?? '';
$packageName = $params['packageName'] ?? '';
$gameId = $params['gameId'] ?? 0;
$promoteId = $params['promoteId'] ?? 0;
$packageUrl = $params['packageUrl'] ?? '';
$platformId = $params['platformId'] ?? 0;
$position = $params['position'] ?? 0;
$gameIcon = $params['gameIcon'] ?? '';
$type = $params['type'] ?? '';
if ($gameId == 0) {
return [
'status' => false,
'message' => '游戏ID错误',
];
}
if ($type == '' || !in_array($type, ['org', 'pack'])) {
return [
'status' => false,
'message' => '类型错误',
];
}
$xml = new \DOMDocument();
$xml->load(ROOTTT . 'Uploads/Plist/testdemo.Plist');
$online = $xml->getElementsByTagName('dict'); //查找节点
$elements = $online->item(1)->getElementsByTagName('string'); //第二个节点下所有string
foreach ($elements as $element) {
switch ($element->textContent) {
case 'ipa_url':
if (preg_match("/http/", $packageUrl)) {
$element->nodeValue = $packageUrl;
} else {
$element->nodeValue = "https://" . $domain . ltrim($packageUrl, '.');
}
break;
case 'icon':
if (preg_match("/http/", $gameIcon)) {
$element->nodeValue = $gameIcon;
} else {
$element->nodeValue = "https://" . $domain . $gameIcon;
}
break;
case 'com.dell':
$element->nodeValue = $packageName;
break;
case '1.0.0':
$element->nodeValue = false;
break;
case 'mchdemo':
$element->nodeValue = false;
break;
}
}
$fileName = '';
if ($type == 'pack') {
if ($promoteId == 0) {
$fileName = 'Uploads/SourcePlist/'. $gameId . '.Plist';
} elseif ($platformId > 0) {
$fileName = 'Uploads/GamePlist/'. $gameId . '-' . $promoteId . '-' . $platformId . '-' .$position . '.Plist';
} else {
$fileName = 'Uploads/GamePlist/'. $gameId . '-' . $promoteId . '.Plist';
}
} elseif ($type == 'org') {
$fileName = 'Uploads/OrgSourcePlist/'. $gameId . '.Plist';
}
$xml->save('./' . $fileName);
return [
'status' => true,
'message' => '生成成功',
'data' => [
'path' => './' . $fileName
]
];
}
}

@ -0,0 +1,123 @@
<?php
namespace Base\Service;
use OSS\Core\OssUtil;
use OSS\OssClient;
use OSS\Core\OSsException;
/**
* 目前仅支持阿里云OSS
*/
class OssService {
private $accessKeyId = '';
private $accessKeySecret = '';
private $domain = '';
private $isCName = false;
private $bucket = '';
private $bdDomain = '';
private $client;
private $errorMessage = '';
public function __construct()
{
Vendor('OSS.autoload');
$this->accessKeyId = C('oss_storage.accesskeyid');
$this->accessKeySecret = C('oss_storage.accesskeysecr');
$this->domain = C('oss_storage.domain');
$this->isCName = C('oss_storage.is_cname');
$this->bdDomain = C('oss_storage.bd_domain');
$this->bucket = C('oss_storage.bucket');
$this->client = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->domain, $this->isCName);
}
public function upload($localFilePath, $saveFileName)
{
try {
$this->multiuploadFile($localFilePath, $saveFileName);
return [
'status' => true,
'message' => '上传OSS成功',
'data' => [
'url' => $this->getUrl($saveFileName)
]
];
} catch (OssException $e) {
return [
'status' => false,
'message' => $e->getMessage()
];
}
}
private function multiuploadFile($file, $saveFileName)
{
$uploadId = $this->client->initiateMultipartUpload($this->bucket, $saveFileName);
/*
* step 2. 上传分片
*/
$partSize = 5 * 1000 * 1024;
$uploadFile = $file;
$uploadFileSize = filesize($uploadFile);
$pieces = $this->client->generateMultiuploadParts($uploadFileSize, $partSize);
$responseUploadPart = [];
$uploadPosition = 0;
$isCheckMd5 = true;
foreach ($pieces as $i => $piece) {
$fromPos = $uploadPosition + (integer) $piece[OssClient::OSS_SEEK_TO];
$toPos = (integer) $piece[OssClient::OSS_LENGTH] + $fromPos - 1;
$upOptions = [
OssClient::OSS_FILE_UPLOAD => $uploadFile,
OssClient::OSS_PART_NUM => ($i + 1),
OssClient::OSS_SEEK_TO => $fromPos,
OssClient::OSS_LENGTH => $toPos - $fromPos + 1,
OssClient::OSS_CHECK_MD5 => $isCheckMd5,
];
if ($isCheckMd5) {
$contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
$upOptions[OssClient::OSS_CONTENT_MD5] = $contentMd5;
}
// 2. 将每一分片上传到OSS
$responseUploadPart[] = $this->client->uploadPart($this->bucket, $saveFileName, $uploadId, $upOptions);
}
$uploadParts = [];
foreach ($responseUploadPart as $i => $eTag) {
$uploadParts[] = [
'PartNumber' => ($i + 1),
'ETag' => $eTag,
];
}
/**
* step 3. 完成上传
*/
$this->client->completeMultipartUpload($this->bucket, $saveFileName, $uploadId, $uploadParts);
}
/**
*删除文件
*/
public function deleteObject($deleteFile)
{
$this->client->deleteObject($this->bucket, $deleteFile);
}
private function getUrl($saveFileName)
{
$url = '';
if ($this->isCName) {
$url = 'http://' . $this->domain . '/' . $saveFileName;
} else {
$url = 'https://' . $this->bucket . '.' . $this->domain . '/' . $saveFileName;
$url = str_replace('-internal', '', $url);
}
/**
* @todo unknown
*/
if (!empty($this->bdDomain) && strlen($this->bdDomain) > 5) {
$url = $this->bdDomain . $saveFileName;
}
return $url;
}
}

@ -0,0 +1,450 @@
<?php
namespace Base\Tool;
use \ZipArchive;
/**
* 用于读取apk信息
* @author elf<360197197@qq.com>
*/
class ApkParser
{
const AXML_FILE = 0x00080003;
const STRING_BLOCK = 0x001C0001;
const RESOURCEIDS = 0x00080180;
const START_NAMESPACE = 0x00100100;
const END_NAMESPACE = 0x00100101;
const START_TAG = 0x00100102;
const END_TAG = 0x00100103;
const TEXT = 0x00100104;
const TYPE_NULL = 0;
const TYPE_REFERENCE = 1;
const TYPE_ATTRIBUTE = 2;
const TYPE_STRING = 3;
const TYPE_FLOAT = 4;
const TYPE_DIMENSION = 5;
const TYPE_FRACTION = 6;
const TYPE_INT_DEC = 16;
const TYPE_INT_HEX = 17;
const TYPE_INT_BOOLEAN = 18;
const TYPE_INT_COLOR_ARGB8 = 28;
const TYPE_INT_COLOR_RGB8 = 29;
const TYPE_INT_COLOR_ARGB4 = 30;
const TYPE_INT_COLOR_RGB4 = 31;
const UNIT_MASK = 15;
private static $radixMults = [0.00390625, 3.051758E-005, 1.192093E-007, 4.656613E-010];
private static $dimensionUnits = ["px","dip","sp","pt","in","mm","",""];
private static $fractionUnits = ["%","%p","","","","","",""];
private $xml='';
private $length = 0;
private $stringCount = 0;
private $styleCount = 0;
private $stringTab = [];
private $styleTab = [];
private $resourceIDs = [];
private $ns = [];
private $cur_ns = null;
private $root = null;
private $line = 0;
public function open($apkFile, $xmlFile='AndroidManifest.xml')
{
$zip = new ZipArchive;
if ($zip->open($apkFile) === true) {
$xml = $zip->getFromName($xmlFile);
$zip->close();
if ($xml){
try {
return $this->parseString($xml);
}catch (Exception $e){
}
}
}
return false;
}
public function parseString($xml)
{
$this->xml = $xml;
$this->length = strlen($xml);
$this->root = $this->parseBlock(self::AXML_FILE);
return true;
}
public function getXML($node = null, $lv = -1)
{
if ($lv == -1) $node = $this->root;
if (!$node) return '';
if ($node['type'] == self::END_TAG) $lv--;
$xml = ($node['line'] == 0 || $node['line'] == $this->line) ? '' : "\n".str_repeat(' ', $lv);
$xml .= $node['tag'];
$this->line = $node['line'];
foreach ($node['child'] as $c){
$xml .= $this->getXML($c, $lv+1);
}
return $xml;
}
public function getPackage()
{
return $this->getAttribute('manifest', 'package');
}
public function getVersionName()
{
return $this->getAttribute('manifest', 'android:versionName');
}
public function getVersionCode()
{
return $this->getAttribute('manifest', 'android:versionCode');
}
public function getAppName()
{
return $this->getAttribute('manifest/application', 'android:name');
}
public function getMainActivity()
{
for ($id=0; true; $id++){
$act = $this->getAttribute("manifest/application/activity[{$id}]/intent-filter/action", 'android:name');
if (!$act) break;
if ($act == 'android.intent.action.MAIN') return $this->getActivity($id);
}
return null;
}
public function getActivity($idx=0)
{
$idx = intval($idx);
return $this->getAttribute("manifest/application/activity[{$idx}]", 'android:name');
}
public function getAttribute($path, $name)
{
$r = $this->getElement($path);
if (is_null($r)) {
return null;
}
if (isset($r['attrs'])){
foreach ($r['attrs'] as $a) {
if ($a['ns_name'] == $name) {
return $this->getAttributeValue($a);
}
}
}
return null;
}
private function getElement($path)
{
if (!$this->root) return NULL;
$ps = explode('/', $path);
$r = $this->root;
foreach ($ps as $v){
if (preg_match('/([^ ]+)\[([09]+)$/', $v, $ms)){
$v = $ms[1];
$off = $ms[2];
}else {
$off = 0;
}
foreach ($r['child'] as $c){
if ($c['type'] == self::START_TAG && $c['ns_name'] == $v){
if ($off == 0){
$r = $c; continue 2;
}else {
$off--;
}
}
}
// 没有找到节点
return NULL;
}
return $r;
}
private function parseBlock($need = 0)
{
$o = 0;
$type = $this->get32($o);
if ($need && $type != $need) throw new Exception('Block Type Error', 1);
$size = $this->get32($o);
if ($size < 8 || $size > $this->length) throw new Exception('Block Size Error', 2);
$left = $this->length - $size;
$props = false;
switch ($type){
case self::AXML_FILE:
$props = [
'line' => 0,
'tag' => '<?xml version="1.0" encoding="utf-8"?>'
];
break;
case self::STRING_BLOCK:
$this->stringCount = $this->get32($o);
$this->styleCount = $this->get32($o);
$o += 4;
$strOffset = $this->get32($o);
$styOffset = $this->get32($o);
$strListOffset = $this->get32array($o, $this->stringCount);
$styListOffset = $this->get32array($o, $this->styleCount);
$this->stringTab = $this->stringCount > 0 ? $this->getStringTab($strOffset, $strListOffset) : [];
$this->styleTab = $this->styleCount > 0 ? $this->getStringTab($styOffset, $styListOffset) : [];
$o = $size;
break;
case self::RESOURCEIDS:
$count = $size / 4 - 2;
$this->resourceIDs = $this->get32array($o, $count);
break;
case self::START_NAMESPACE:
$o += 8;
$prefix = $this->get32($o);
$uri = $this->get32($o);
if (empty($this->cur_ns)){
$this->cur_ns = [];
$this->ns[] = &$this->cur_ns;
}
$this->cur_ns[$uri] = $prefix;
break;
case self::END_NAMESPACE:
$o += 8;
$prefix = $this->get32($o);
$uri = $this->get32($o);
if (empty($this->cur_ns)) {
break;
}
unset($this->cur_ns[$uri]);
break;
case self::START_TAG:
$line = $this->get32($o);
$o += 4;
$attrs = [];
$props = array(
'line' => $line,
'ns' => $this->getNameSpace($this->get32($o)),
'name' => $this->getString($this->get32($o)),
'flag' => $this->get32($o),
'count' => $this->get16($o),
'id' => $this->get16($o)-1,
'class' => $this->get16($o)-1,
'style' => $this->get16($o)-1,
'attrs' => &$attrs
);
$props['ns_name'] = $props['ns'].$props['name'];
for ($i=0; $i < $props['count']; $i++){
$a = array(
'ns' => $this->getNameSpace($this->get32($o)),
'name' => $this->getString($this->get32($o)),
'val_str' => $this->get32($o),
'val_type' => $this->get32($o),
'val_data' => $this->get32($o)
);
$a['ns_name'] = $a['ns'].$a['name'];
$a['val_type'] >>= 24;
$attrs[] = $a;
}
// 处理TAG字符串
$tag = "<{$props['ns_name']}";
foreach ($this->cur_ns as $uri => $prefix){
$uri = $this->getString($uri);
$prefix = $this->getString($prefix);
$tag .= " xmlns:{$prefix}=\"{$uri}\"";
}
foreach ($props['attrs'] as $a){
$tag .= " {$a['ns_name']}=\"".
$this->getAttributeValue($a).
'"';
}
$tag .= '>';
$props['tag'] = $tag;
unset($this->cur_ns);
$this->cur_ns = [];
$this->ns[] = &$this->cur_ns;
$left = -1;
break;
case self::END_TAG:
$line = $this->get32($o);
$o += 4;
$props = array(
'line' => $line,
'ns' => $this->getNameSpace($this->get32($o)),
'name' => $this->getString($this->get32($o))
);
$props['ns_name'] = $props['ns'].$props['name'];
$props['tag'] = "</{$props['ns_name']}>";
if (count($this->ns) > 1){
array_pop($this->ns);
unset($this->cur_ns);
$this->cur_ns = array_pop($this->ns);
$this->ns[] = &$this->cur_ns;
}
break;
case self::TEXT:
$o += 8;
$props = array(
'tag' => $this->getString($this->get32($o))
);
$o += 8;
break;
default:
throw new Exception('Block Type Error', 3);
break;
}
$this->skip($o);
$child = [];
while ($this->length > $left){
$c = $this->parseBlock();
if ($props && $c) $child[] = $c;
if ($left == -1 && $c['type'] == self::END_TAG){
$left = $this->length;
break;
}
}
if ($this->length != $left) throw new Exception('Block Overflow Error', 4);
if ($props){
$props['type'] = $type;
$props['size'] = $size;
$props['child'] = $child;
return $props;
}else {
return false;
}
}
private function getAttributeValue($a)
{
$type = &$a['val_type'];
$data = &$a['val_data'];
switch ($type){
case self::TYPE_STRING:
return $this->getString($a['val_str']);
case self::TYPE_ATTRIBUTE:
return sprintf('?%s%08X', self::_getPackage($data), $data);
case self::TYPE_REFERENCE:
return sprintf('@%s%08X', self::_getPackage($data), $data);
case self::TYPE_INT_HEX:
return sprintf('0x%08X', $data);
case self::TYPE_INT_BOOLEAN:
return ($data != 0 ? 'true' : 'false');
case self::TYPE_INT_COLOR_ARGB8:
case self::TYPE_INT_COLOR_RGB8:
case self::TYPE_INT_COLOR_ARGB4:
case self::TYPE_INT_COLOR_RGB4:
return sprintf('#%08X', $data);
case self::TYPE_DIMENSION:
return $this->_complexToFloat($data).self::$dimensionUnits[$data & self::UNIT_MASK];
case self::TYPE_FRACTION:
return $this->_complexToFloat($data).self::$fractionUnits[$data & self::UNIT_MASK];
case self::TYPE_FLOAT:
return $this->_int2float($data);
}
if ($type >=self::TYPE_INT_DEC && $type < self::TYPE_INT_COLOR_ARGB8){
return (string)$data;
}
return sprintf('<0x%X, type 0x%02X>', $data, $type);
}
private function _complexToFloat($data)
{
return (float)($data & 0xFFFFFF00) * self::$radixMults[($data>>4) & 3];
}
private function _int2float($v)
{
$x = ($v & ((1 << 23) - 1)) + (1 << 23) * ($v >> 31 | 1);
$exp = ($v >> 23 & 0xFF) - 127;
return $x * pow(2, $exp - 23);
}
private static function _getPackage($data)
{
return ($data >> 24 == 1) ? 'android:' : '';
}
private function getStringTab($base, $list)
{
$tab = [];
foreach ($list as $off){
$off += $base;
$len = $this->get16($off);
$mask = ($len >> 0x8) & 0xFF;
$len = $len & 0xFF;
if ($len == $mask){
if ($off + $len > $this->length) throw new Exception('String Table Overflow', 11);
$tab[] = substr($this->xml, $off, $len);
}else {
if ($off + $len * 2 > $this->length) throw new Exception('String Table Overflow', 11);
$str = substr($this->xml, $off, $len * 2);
$tab[] = mb_convert_encoding($str, 'UTF-8', 'UCS-2LE');
}
}
return $tab;
}
private function getString($id)
{
if ($id > -1 && $id < $this->stringCount){
return $this->stringTab[$id];
}else {
return '';
}
}
private function getNameSpace($uri)
{
for ($i=count($this->ns); $i > 0; ){
$ns = $this->ns[--$i];
if (isset($ns[$uri])){
$ns = $this->getString($ns[$uri]);
if (!empty($ns)) $ns .= ':';
return $ns;
}
}
return '';
}
private function get32(&$off)
{
$int = unpack('V', substr($this->xml, $off, 4));
$off += 4;
return array_shift($int);
}
private function get32array(&$off, $size)
{
if ($size <= 0) {
return null;
}
$arr = unpack('V*', substr($this->xml, $off, 4 * $size));
if (count($arr) != $size) throw new Exception('Array Size Error', 10);
$off += 4 * $size;
return $arr;
}
private function get16(&$off)
{
$int = unpack('v', substr($this->xml, $off, 2));
$off += 2;
return array_shift($int);
}
private function skip($size)
{
$this->xml = substr($this->xml, $size);
$this->length -= $size;
}
}

@ -0,0 +1,109 @@
<?php
namespace Base\Tool;
class Base62
{
const ENCODES = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/';
private static function getCharArray($string)
{
$list = [];
$length = strlen($string);
for ($i = 0; $i < $length; $i++) {
$list[] = $string[$i];
}
return $list;
}
private static function getIndexChars($string) {
$length = strlen($string);
$chars = [];
for($i = 0; $i < 256; $i++) {
$chars[] = 0;
}
for($i = 0; $i < $length; $i++) {
$chars[$string[$i]] = $i ;
}
return $chars;
}
public static function encode($string)
{
$encodes = self::getCharArray(self::ENCODES);
$bytes = self::stringToBytes($string);
$pos = 0;
$val = 0;
$result = [];
for ($i = 0; $i < count($bytes); $i++) {
$val = ($val << 8) | ($bytes[$i] & 0xFF);
$pos += 8;
while ($pos > 5) {
$char = $encodes[$val >> ($pos -= 6)];
$result[] = (
$char == 'i' ? "ia" :
$char == '+' ? "ib" :
$char == '/' ? "ic" : $char
);
$val &= ((1 << $pos) - 1);
}
}
if ($pos > 0) {
$char = $encodes[$val << (6 - $pos)];
$result[] = (
$char == 'i' ? "ia" :
$char == '+' ? "ib" :
$char == '/' ? "ic" : $char
);
}
return implode('', $result);
}
public static function decode($string, $decodes)
{
$decodes = self::getIndexChars(self::ENCODES);
$chars = self::getCharArray($string);
$pos = 0;
$val = 0;
$bytes = [];
for ($i = 0; $i < count($chars); $i++) {
$char = $chars[$i];
if ($char == 'i') {
$char = $chars[++$i];
$char =
$char == 'a' ? 'i' :
$char == 'b' ? '+' :
$char == 'c' ? '/' : $chars[--$i];
}
$val = ($val << 6) | $decodes[$char];
$pos += 6;
while ($pos > 7) {
$bytes[] = $val >> ($pos -= 8);
$val &= ((1 << $pos) - 1);
}
}
return self::bytesToString($bytes);
}
private static function bytesToString($bytes) {
$string = '';
foreach($bytes as $byte) {
$string .= chr($byte);
}
return $string;
}
private static function stringToBytes($string) {
$length = strlen($string);
$bytes = array();
for($i = 0; $i < $length; $i++) {
if(ord($string[$i]) >= 128){
$byte = ord($string[$i]) - 256;
}else{
$byte = ord($string[$i]);
}
$bytes[] = $byte ;
}
return $bytes;
}
}

@ -0,0 +1,102 @@
<?php
namespace Base\Tool;
use \ZipArchive;
/**
* 用于读取plist文件信息
* @author elf<360197197@qq.com>
*/
class PlistParser
{
const PREG_INFO_PLIST = "/^Payload.*?\.app\/Info.plist$/";
private $xml;
public function openFromIpa($ipaFile, $preg)
{
$zip = new ZipArchive;
if ($zip->open($ipaFile) === true) {
$index = -1;
for( $i = 0; $i < $zip->numFiles; $i++ ){
$stat = $zip->statIndex($i);
if (preg_match($preg, $stat['name'], $matches)) {
$index = $stat['index'];
}
}
$content = $zip->getFromIndex($index);
$zip->close();
if ($content){
$xml = new \DOMDocument();
$xml->loadXML($content);
$this->xml = $xml;
return true;
}
}
die();
return false;
}
public function open($xmlFile)
{
$xml = new \DOMDocument();
$xml->load($xmlFile);
$this->xml = $xml;
return true;
}
public function getResult()
{
$plistTag = $this->xml->getElementsByTagName('plist');
$dict = $plistTag->item(0)->childNodes->item(1);
return $this->parseDictNode($dict);
}
public function parseDictNode($parentNode)
{
$lastKey = '';
$dict = [];
foreach ($parentNode->childNodes as $node) {
if ($node instanceof \DOMElement) {
if ($node->nodeName == 'key') {
$lastKey = $node->textContent;
} else {
if ($node->nodeName == 'dict') {
$dict[$lastKey] = $this->parseDictNode($node);
} elseif ($node->nodeName == 'array') {
$dict[$lastKey] = $this->parseArrayNode($node);
} elseif($node->nodeName == 'true') {
$dict[$lastKey] = true;
} elseif($node->nodeName == 'false') {
$dict[$lastKey] = false;
} else {
$dict[$lastKey] = $node->textContent;
}
}
}
}
return $dict;
}
public function parseArrayNode($parentNode)
{
$list = [];
foreach ($parentNode->childNodes as $node) {
if ($node instanceof \DOMElement) {
if ($node->nodeName == 'dict') {
$list[] = $this->parseDictNode($node);
} elseif ($node->nodeName == 'array') {
$list[] = $this->parseArrayNode($node);
} elseif($node->nodeName == 'true') {
$list[] = true;
} elseif($node->nodeName == 'false') {
$list[] = false;
} else {
$list[] = $node->textContent;
}
}
}
return $list;
}
}

@ -0,0 +1,13 @@
<?php
namespace Base\Tool;
class Printer
{
public static function export($content, $isExit = false)
{
echo $content . ' ----- ' . date('Y-m-d H:i:s') . PHP_EOL;
if ($isExit) {
exit(0);
}
}
}

@ -0,0 +1,122 @@
<?php
namespace Base\Tool;
/**
* @author elf<360197197@qq.com>
*/
class Request {
private $serverInfo;
private $scheme;
public function __construct()
{
$this->serverInfo = $_SERVER;
}
public function isWechat()
{
$userAgent = $this->getUserAgent();
if (strpos($userAgent, 'MicroMessenger') == false && strpos($userAgent, 'Windows Phone') == false) {
return false;
} else {
return true;
}
}
public function getUserAgent()
{
return $this->serverInfo['HTTP_USER_AGENT'] ?? '';
}
public function isMobile()
{
$isMobile = false;
$userAgent = $this->getUserAgent();
$mobileAgents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad','iPod'];
foreach ($mobileAgents as $mobileAgent) {
if (stripos($userAgent, $mobileAgent) !== false) {
$isMobile = true;
}
}
return $isMobile;
}
public function isIOS()
{
$userAgent = $this->getUserAgent();
if(stripos($userAgent, 'iphone') !== false || strpos($userAgent, 'ipad') !== false) {
return true;
}
return false;
}
public function isAndroid()
{
$userAgent = $this->getUserAgent();
if(strpos($userAgent, 'android')) {
return true;
}
return false;
}
public function isIOS13()
{
if (preg_match('/OS [1][3-9]_[1-9][_\d]* like Mac OS X/i')) {
return true;
}
return false;
}
/**
* 获取客户端IP
*/
public function getClientIP()
{
$serverInfo = $this->serverInfo;
$ip = '0.0.0.0';
if (isset($serverInfo['HTTP_X_FORWARDED_FOR'])) {
$items = explode(',', $serverInfo['HTTP_X_FORWARDED_FOR']);
$position = array_search('unknown', $items);
if (false !== $position) {
unset($items[$position]);
}
$ip = trim($items[0]);
} elseif (isset($serverInfo['HTTP_CLIENT_IP'])) {
$ip = $serverInfo['HTTP_CLIENT_IP'];
} elseif (isset($this->serverInfo['REMOTE_ADDR'])) {
$ip = $serverInfo['REMOTE_ADDR'];
}
return $ip;
}
public function getHost()
{
$host = $this->getScheme() . '://' . $this->serverInfo['SERVER_NAME'];
if (in_array($this->serverInfo['SERVER_PORT'], [80, 443])) {
return $host;
}
return $host . ':' . $this->serverInfo['SERVER_PORT'];
}
public function getScheme()
{
if ($this->scheme) {
return $this->scheme;
}
$serverInfo = $this->serverInfo;
if (isset($serverInfo['REQUEST_SCHEME'])) {
$this->scheme = $serverInfo['REQUEST_SCHEME'];
return $this->scheme;
}
if ((isset($serverInfo['HTTPS']) && $serverInfo['HTTPS'] == 'on')
|| (isset($serverInfo['HTTP_X_FORWARDED_PROTO']) && $serverInfo['HTTP_X_FORWARDED_PROTO'] == 'https'
|| (isset($serverInfo['SERVER_PORT']) && $serverInfo['SERVER_PORT'] == 443))
) {
$this->scheme = 'https';
} else {
$this->scheme = 'http';
}
return $this->scheme;
}
}

@ -5,6 +5,8 @@ namespace Home\Controller;
use OT\DataDictionary;
use Admin\Model\ApplyModel;
use Think\Model;
use Base\Facade\Request;
use Base\Service\ApplyService;
/**
@ -633,9 +635,7 @@ class ApplyController extends BaseController
if ($_REQUEST['pattern'] != null) {
$map['tab_apply.pattern'] = $_REQUEST['pattern'];
}
// $map['tab_apply.status'] = 1;
// $map['tab_game.game_status'] = 1;//游戏状态
// empty(I('sdk_version')) || $map['tab_game.sdk_version'] = I('sdk_version');
$page = intval(I('get.p', 0));
$page = $page ? $page : 1; //默认显示第一页数据
@ -1751,7 +1751,80 @@ class ApplyController extends BaseController
$this->ajaxReturn($result);
}
}
public function getDownloadUrl()
{
$gameId = I('game_id', 0);
$promote = $this->getLoginPromote();
$apply = M('apply', 'tab_')->where(['promote_id' => $promote['id'], 'game_id' => $gameId])->find();
$game = M('game', 'tab_')->field(['icon'])->where(['id' => $gameId])->find();
if ($apply == null) {
$this->ajaxReturn([
'status' => 0,
'message' => '游戏不存在',
'data' => [
]
]);
}
$icon = Request::getHost() . '/' . get_cover($game['icon'], 'path');
$applyService = new ApplyService();
$result = $applyService->checkApplyStatus($apply);
if (!$result['status']) {
$this->ajaxReturn([
'status' => 0,
'message' => $result['message'],
'data' => [
]
]);
}
$url = $applyService->getDownloadUrl($apply);
$this->ajaxReturn([
'status' => 1,
'message' => '获取成功',
'data' => [
'url' => $url,
]
]);
}
public function getLandingPageUrl()
{
$gameId = I('game_id', 0);
$promote = $this->getLoginPromote();
$apply = M('apply', 'tab_')->where(['promote_id' => $promote['id'], 'game_id' => $gameId])->find();
$game = M('game', 'tab_')->field(['icon'])->where(['id' => $gameId])->find();
if ($apply == null) {
$this->ajaxReturn([
'status' => 1,
'message' => '游戏不存在',
'data' => [
]
]);
}
$icon = Request::getHost() . '/' . get_cover($game['icon'], 'path');
$applyService = new ApplyService();
$result = $applyService->checkApplyStatus($apply);
if (!$result['status']) {
$this->ajaxReturn([
'status' => 0,
'message' => $result['message'],
'data' => [
]
]);
}
$url = $applyService->getLandingPageUrl($apply);
$this->ajaxReturn([
'status' => 1,
'message' => '获取成功',
'data' => [
'url' => $url,
]
]);
}
}

@ -0,0 +1,86 @@
<?php
namespace Home\Controller;
use Think\Controller;
use Base\Facade\Request;
use Base\Service\ApplyService;
/**
* @author elf<360197197@qq.com>
*/
class DownloadController extends Controller {
public function downloadError($message)
{
$this->assign('message', $message);
$this->display('error');
}
public function index()
{
$code = I('code', '');
if ($code == '') {
$this->redirect("download/downloadError", ['message' => '访问错误']);
}
$applyService = new ApplyService();
$data = $applyService->decodeApplyCode($code);
$result = $applyService->checkApplyCode($data, ApplyService::ENCRYPT_TYPE_DOWNLOAD);
if (!$result['status']) {
$this->error($result['message']);
}
$gameId = $data['game_id'];
$promoteId = $data['promote_id'];
$map = [];
$map['status'] = 1;
$map['enable_status'] = 1;
$map['game_id'] = $gameId;
$map['promote_id'] = $promoteId;
$columns = ['game_id', 'promote_id', 'promote_account', 'pack_url', 'plist_url', 'status', 'enable_status'];
$apply = M('apply','tab_')->field($columns)->where($map)->find();
$game = M('game','tab_')->field(['id', 'game_name', 'sdk_version'])->where(['id' => $apply['game_id']])->find();
if (Request::isMobile()) {
if (!Request::isAndroid() && $game['sdk_version'] == 1) {
$this->redirect("download/downloadError", ['message' => '请使用安卓浏览器下载']);
}
if (!Request::isIOS() && $game['sdk_version'] == 2) {
$this->redirect("download/downloadError", ['message' => '请使用ios浏览器下载']);
}
}
$packageUrl = $game['sdk_version'] == 1 ? $apply['pack_url'] : $apply['plist_url'];
M('game','tab_')->where(['id' => $game['id']])->setInc('dow_num');
if (Request::isAndroid()) {
$this->gotoPkgUrl($packageUrl);
} else if (Request::isIOS()) {
$plistUrl = substr($packageUrl, 1, strlen($packageUrl));
header("HTTP/1.1 303 See Other");
header("Location: "."itms-services://?action=download-manifest&url=" . "https://" . Request::getHost() . "/" . $plistUrl);
} else {
$this->gotoPkgUrl($packageUrl);
}
}
private function gotoPkgUrl($packageUrl)
{
if (preg_match("/oss/", $packageUrl)) {
$url = str_replace('-internal', '', $packageUrl);
echo "<script>window.location.href='$url';</script>";
} elseif (preg_match("/clouddn/", $packageUrl)) {
$url = "http://".$packageUrl;
redirect($url);
} elseif (preg_match("/myqcloud/", $packageUrl)) {
redirect($packageUrl);
} elseif(preg_match("/bcebos/", $packageUrl)) {
redirect($packageUrl);
} else {
if (!file_exists($packageUrl)) {
$this->error('文件不存在哦,亲!');
}else{
redirect(Request::getHost() . ltrim($packageUrl, '.'));
}
}
}
}

@ -1,24 +1,10 @@
<?php
// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
namespace Home\Controller;
use Think\Controller;
use User\Api\MemberApi;
use Base\Facade\Request;
use Base\Service\ApplyService;
/**
* 前台公共控制器
@ -142,6 +128,80 @@ class HomeController extends Controller
$this->display();
}
public function landingPage()
{
$code = I('code', '');
if ($code == '') {
$this->redirect("download/downloadError", ['message' => '访问错误']);
}
$applyService = new ApplyService();
$data = $applyService->decodeApplyCode($code);
$result = $applyService->checkApplyCode($data, ApplyService::ENCRYPT_TYPE_LANDING_PAGE);
if (!$result['status']) {
$this->error($result['message']);
}
$isWechat = Request::isWechat();
$isIOS = Request::isIOS();
$isAndroid = Request::isAndroid();
$isIOS13 = Request::isIOS13();
$columns = [
'id',
'sdk_version',
'icon',
'screenshot',
'relation_game_id',
'relation_game_name',
'dow_status',
'features',
'flooring_page_imgs',
];
$map = ['id' => intval($data['game_id'])];
$game = M('game', 'tab_')->field($columns)->where($map)->find();
if ($game['sdk_version'] == 1 && $isIOS) {
$map['relation_game_id'] = $game['relation_game_id'];
$map['sdk_version'] = 2;
$game = M('game', 'tab_')->field($columns)->where($map)->find();
} elseif ($game['sdk_version'] == 2 && $isAndroid) {
$map['relation_game_id'] = $game['relation_game_id'];
$map['sdk_version'] = 1;
$game = M('game', 'tab_')->field($columns)->where($map)->find();
}
$apply = M('apply', 'tab_')->field(['game_id', 'enable_status', 'promote_id'])
->where(['promote_id' => $data['promote_id'], 'game_id' => $game['id']])
->find();
$game['icon'] = get_cover($game['icon'], 'path');
$imageIds = explode(',', $game['flooring_page_imgs']) ?? [];
$imageUrls = [];
foreach ($imageIds as $imageId) {
$imageUrls[] = get_cover($imageId, 'path');
}
$game['flooring_page_imgs'] = $imageUrls;
$downloadUrl = '';
if ($isIOS13) {
$gameSource = M('GameSource', 'tab_')->where(array('game_id' => $game['id']))->getField('org_plist_url');
$downloadUrl = 'itms-services://?action=download-manifest&url=' . Request::getHost() . ltrim($gameSource['org_plist_url'], '.');
} else {
$applyService = new ApplyService();
$downloadUrl = $applyService->getDownloadUrl($apply);
}
$this->assign('downloadUrl', $downloadUrl);
$this->assign('isIOS13', $isIOS13);
$this->assign('isWechat', $isWechat);
$this->assign('isIOS', $isIOS);
$this->assign('isAndroid', $isAndroid);
$this->assign('apply', $apply);
$this->assign('game', $game);
$this->display();
}
public function iosDown()
{
$gameId = I('get.gid');

@ -3,93 +3,10 @@
<link href="__CSS__/20180207/data.css" rel="stylesheet">
<link href="__CSS__/20180207/game.css" rel="stylesheet">
<link href="__CSS__/game_detailed.css" rel="stylesheet">
<link href="__CSS__/my_game.css" rel="stylesheet">
<link href="__STATIC__/icons_alibaba/iconfont.css" rel="stylesheet">
<link href="__STATIC__/jqueryselect/css/layui.css" rel="stylesheet">
<script src="__STATIC__/jqueryselect/js/MySearch.js" type="text/javascript" charset="utf-8"></script>
<style>
body {
font: 400 14px/1.5 'Microsoft YaHei','微软雅黑',Tahoma,Verdana,Arial,'宋体',sans-serif;
}
.zclip embed {
margin-top: -14px;
}
.trunk-list {
position: relative;
min-height: 66vh;
}
.pagenation {
position: relative;
text-align: center;
line-height: 5vh;
bottom: 1%;
}
.pic-prev:hover, .pic-next:hover {
background-color: #4ac5c3;
}
</style>
<style>
.layui-btn{
background-color: #5fb878;
}
.label{
padding: 2px 5px;
background: #5FB878;
border-radius: 2px;
color: #fff;
display: block;
line-height: 20px;
height: 20px;
margin: 2px 5px 2px 0;
float: left;
}
i{
display: inline-block;
width: 18px;
height: 18px;
line-height: 18px;
text-align: center
}
.label:hover{color: white;}
.label i:hover {
background-color: #009E94;
border-radius: 2px;
}
.layui-form-select dl dd:hover {
background-color: #5FB878;
color: white;
}
.AD{
width: 210px;
margin-left: 40px;
overflow-y: auto;
max-height: 200px;
border: 2px solid #5fb878;
border-radius: 6px;
padding: 1px 2px;
}
#add_promote_data label {
width: 70px;
margin-right: 0;
padding-left: 0;
text-align: left;
}
#add_promote_data .AD {
white-space: nowrap;
margin-bottom: 2px;
overflow:scroll;
}
.btn-role-border {
border-left: 0;
}
</style>
</block>
<block name="body">
@ -108,15 +25,7 @@
<a href="{:U($game, array('type' => 2))}" class="">IOS游戏</a>
<a href="{:U($game, array('type' => 1))}" class="">Android游戏</a>
<a href="javascript:;" class="current">我的游戏</a>
<!-- <a href="javascript:void(0);" title="集成推广多款游戏,生成游戏大全推广页" style="background:#ffffff;width:68px;height:68px; position:relative" onmouseover="this.style.background='#E3E5E4'" onmouseout="this.style.background='#ffffff'" class="spread"><img src="/Public/Home/images/generalization.png" />
<img src="/Public/Home/images/hot.png" style="width: 20px;
height: 20px;
position: absolute;
right: 2px;top:0" />
</a>
-->
</div>
<div class="clearfix"></div>
<div class="tab marg_top20" style="clear:both;display: flex;">
<div style="display: flex;">
@ -167,13 +76,6 @@
</if>
</div>
</div>
<!-- <div class="zwm_examinediv">-->
<!-- <a class="btn_calc" href="javascript:;">审核通过</a>-->
<!-- <a class="btn_calc examine_a" href="{:U('my_game_ch')}">审核中</a>-->
<!-- </div>-->
<!-- <form class="marg_top20" action="{:U($myGame,array('row'=>I('get.row')))}" method="post"-->
<!-- enctype="multipart/form-data">-->
<div class="form-group normal_space fr">
<input type="submit" class="submit" id='submit' url="{:U($myGame,array('model'=>$model['name'],'type'=>$type),false)}"
value="查询">
@ -252,20 +154,6 @@
<span>游戏类型:<span>{$vo.game_type_name}</span>&nbsp;&nbsp;</span>
</p>
</div>
<?php
$qrcode = get_cover($vo['icon'],'path');
if (stripos($qrcode,'http') === false) {
if (stripos($qrcode,'.com') === false) {
$qrcode = 'http://'.C('APPLY_DOWN_DOMAIN').$qrcode;
} else {
$qrcode = 'http://'.$qrcode;
}
}
$qrcodes = $qrcode;
$qrcode = base64_encode(base64_encode($qrcode));
?>
<div class="game-operating" data-url="{$qrcodes}" style="width: 35%;">
<if condition="$promoteRole == 1">
<if condition="$loginPromote['level'] eq 1">
@ -278,10 +166,8 @@
<span class="add-game" game-id="{$vo.id}" promote-type="4" style="cursor: pointer;margin-right: 10px;"><u>添加推广员游戏</u></span>
</if>
</if>
<?php $downloadUrl = get_apply_dow_url($vo['id'],$vo['promote_id']);?>
<span class="game-link" data-qrcode="{:U('Apply/qrcode',['url'=>base64_encode(base64_encode($downloadUrl)),'logo'=>$qrcode])}" data-url="{$downloadUrl}" data-clipboard-text="{$downloadUrl}" data-apply-id="{$vo.applyid}" style="cursor: pointer;margin-right: 10px;"><u>复制下载链接</u></span>
<?php $flooringPageUrl = 'http://'.C('APPLY_DOWN_DOMAIN').U('Home/promitionofregestion',array('gid'=>$vo['id'],'pid'=>$vo['promote_id']));?>
<span class="game-link" data-qrcode="{:U('Apply/qrcode',['url'=>base64_encode(base64_encode($flooringPageUrl)),'logo'=>$qrcode])}" data-url="{$flooringPageUrl}" data-clipboard-text="{$flooringPageUrl}" data-apply-id="{$vo.applyid}" style="cursor: pointer;margin-right: 10px;"><u>落地页链接</u></span>
<span class="game-link" data-type="download" data-game-id="{$vo.id}" style="cursor: pointer;margin-right: 10px;"><u>复制下载链接</u></span>
<span class="game-link" data-type="landing-page" data-game-id="{$vo.id}" style="cursor: pointer;margin-right: 10px;"><u>落地页链接</u></span>
<span class="down-game-btn" data-id="{$vo.id}" style="cursor: pointer;margin-right: 10px;color: #999"><u>下架</u></span>
</div>
</div>
@ -368,16 +254,11 @@
<div class="game-window-content" style="text-align: center;width: auto;padding-bottom: 0px;">
<div class="game-window-content-eveyone" style="display: block;color: #3A97FF;font-size: 1.1rem;">
<label style="margin-right: 20px;">下载地址:</label>
<span id="game_link_address"></span>
<span id="game_link_address" style="word-wrap: break-word;white-space: normal;"></span>
<button id="clipboard-btn" style="display: none;" data-text="">复制</button>
</div>
</div>
<!-- <div class="game-window-btns" style="margin-top: 10px;">-->
<!-- <div class="game-window-btn-box">-->
<!-- <input class="game-window-btn btn-blue" type="button" id="download_copy" data-url="" value="复制">-->
<!-- </div>-->
<!-- </div>-->
<div class="game-window-content" style="text-align: center;width: auto;padding-top: 5px;">
<div class="game-window-content-eveyone" style="display: block;color: #999;font-size: 1.1rem;">
<span>复制成功,ctrl+v粘贴即可</span>
@ -385,8 +266,8 @@
</div>
<div class="game-window-content" style="text-align: center;width: auto;padding-bottom: 5px;">
<div class="game-window-content-eveyone" style="display: block;color: #999;font-size: 1.1rem;">
<img id="game_link_ercode" style="width: 200px;height: 200px;">
<div id="game_link_ercode" class="game-window-content-eveyone" style="display: block;color: #999;font-size: 1.1rem;">
<!-- <img id="game_link_ercode" style="width: 200px;height: 200px;"> -->
</div>
</div>
@ -447,68 +328,16 @@
</div>
</div>
</div>
<!-- <div class="game-detail-right fr">-->
<!-- <div class="detail-con game-date panel panel-bordered">-->
<!-- <div class="panel-heading"><h3 class="panel-title">游戏开服</h3></div>-->
<!-- <div class="date-box ">-->
<!-- <ul class="date-tit">-->
<!-- <li>时间</li>-->
<!-- <li>服务器名称</li>-->
<!-- </ul>-->
<!-- <div class="list-outer ">-->
<!-- <ul class="date-list">-->
<!-- <li><span class="android"></span></li>-->
<!-- </ul>-->
<!-- <ul class="date-list">-->
<!-- <li><span>09-06 16:00</span></li>-->
<!-- <li>天宫73区</li>-->
<!-- </ul>-->
<!-- <ul class="date-list">-->
<!-- <li><span>09-07 16:00</span></li>-->
<!-- <li>天宫74区</li>-->
<!-- </ul>-->
<!-- <ul class="date-list">-->
<!-- <li><span>09-09 16:00</span></li>-->
<!-- <li>天宫75区</li>-->
<!-- </ul>-->
<!-- <ul class="date-list">-->
<!-- <li><span>09-10 16:00</span></li>-->
<!-- <li>天宫76区</li>-->
<!-- </ul>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="detail-con game-pack panel panel-bordered">-->
<!-- <div class="panel-heading"><h3 class="panel-title">游戏礼包</h3></div>-->
<!-- <div class="pack-box ">-->
<!-- <ul id="GamePackInfo">-->
<!-- <li class="">-->
<!-- <div class="pack-inner">-->
<!-- <p class="pack-tit">《天宫计》新手礼包</p>-->
<!-- <p class="pack-word">天女礼物礼包*1、悬赏令*1、铜币*5000</p>-->
<!-- <p class="pack-num">剩余:<b>82.2%</b></p>-->
<!-- </div>-->
<!-- </li>-->
<!-- <li class="current">-->
<!-- <div class="pack-inner">-->
<!-- <p class="pack-tit">《天宫计》媒体礼包</p>-->
<!-- <p class="pack-word">技能书礼包*1、宠物经验丹*1、铜币*5000</p>-->
<!-- <p class="pack-num">剩余:<b>83.3%</b></p>-->
<!-- </div>-->
<!-- </li>-->
<!-- </ul>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
</div>
</div>
</block>
<block name='script'>
<script src="__STATIC__/clipboard/clipboard.min.js"></script>
<script src="__STATIC__/clipboard.min.js"></script>
<script src="__STATIC__/layer/layer.js"></script>
<script type="text/javascript" src="__JS__/20170831/select2.min.js"></script>
<script type="text/javascript" src="__JS__/jquery.qrcode.min.js"></script>
<script type="text/javascript">
highlight_subnav("{:U('Apply/'.$game)}");
setValue('type', {$Think.request.type |default = '""'});
@ -536,7 +365,6 @@
if (!thisElement.hasClass('highlight')) {
var promoteRole = thisElement.attr('promote-role');
console.log(promoteRole);
setValue('promote_role', promoteRole);
@ -838,37 +666,36 @@
dataType: "json",
data: {'game_id': gameId,'promote_type':promoteType},
success: function (data) {
console.log(data);
$('#add_game_name').text(data.game_data.game_name);
$('#add_game_id').val(data.game_data.id);
$('#add_game_features').text(data.game_data.features);
$('#add_sdk_version').text(data.game_data.sdk_name);
console.log(data.game_data.sdk_version);
var tagData = [];
if (data.promote_data.length > 0) {
var html ='';
$.each(data.promote_data, function (index, item) {
var promoteName = item.account + '(' + (item.real_name ? item.real_name : '') +')';
var jsonData = {};
jsonData.name = promoteName;
jsonData.id = item.id;
tagData.push(jsonData);
});
}
if (promoteType == 3) {
$('#add_promote_title').text('添加推广员:');
}
$.myMethod("#add_promote_data",tagData,"add_promote_ids");
$(".sumbit").on("click",function(){
console.log($("form").serialize())
$('#add_game_name').text(data.game_data.game_name);
$('#add_game_id').val(data.game_data.id);
$('#add_game_features').text(data.game_data.features);
$('#add_sdk_version').text(data.game_data.sdk_name);
var tagData = [];
if (data.promote_data.length > 0) {
var html ='';
$.each(data.promote_data, function (index, item) {
var promoteName = item.account + '(' + (item.real_name ? item.real_name : '') +')';
var jsonData = {};
jsonData.name = promoteName;
jsonData.id = item.id;
tagData.push(jsonData);
});
}
if (promoteType == 3) {
$('#add_promote_title').text('添加推广员:');
}
$.myMethod("#add_promote_data",tagData,"add_promote_ids");
$(".sumbit").on("click",function(){
console.log($("form").serialize())
});
$('#add_game').show();
$('.game-window-bg').show();
$('#add_game').show();
$('.game-window-bg').show();
},
error: function (result) {
layer.msg('网络异常', {icon: 5});
@ -907,15 +734,14 @@
dataType: "json",
data: {'game_id': gameId,'promote_ids':promoteIds},
success: function (data) {
if (data.status == 0) {
layer.msg(data.msg, {icon: 1});
setTimeout(function () {
location.reload();
}, 2000);
} else {
layer.msg(data.msg, {icon: 5});
}
console.log(data);
if (data.status == 0) {
layer.msg(data.msg, {icon: 1});
setTimeout(function () {
location.reload();
}, 2000);
} else {
layer.msg(data.msg, {icon: 5});
}
},
error: function (result) {
layer.msg('网络异常', {icon: 5});
@ -995,69 +821,67 @@
});
$('.game-link').on('click', function () {
var url = $(this).attr('data-url');
var qrcode = $(this).attr('data-qrcode');
var applyId = parseInt($(this).attr('data-apply-id'));
$.ajax({
type: "post",
url: "__URL__/getEnableStatus",
dataType: "json",
data: {'apply_id': applyId},
success: function (data) {
if (data.status == 0) {
layer.msg(data.msg, {icon: 5});
return false;
}
var enableStatus = parseInt(data.data);
if (enableStatus == 1) {
$('#game_link_ercode').attr('src',qrcode);
$('#game_link_address').text(url);
$('#game_link').show();
$('.game-window-bg').show();
} else {
var iconIndex = 7;
var enableStatusName = '';
switch (enableStatus) {
case 0:
enableStatusName = '未打包';
break;
case 2:
case 3:
enableStatusName = '打包中';
break;
case -1:
iconIndex = 5;
enableStatusName = '打包失败';
break;
}
layer.alert(enableStatusName, {icon: iconIndex});
return false;
}
},
error: function (result) {
layer.msg('网络异常', {icon: 5});
}
});
});
var btn = document.getElementsByClassName('game-link');
var clipboard = new Clipboard(btn);
clipboard.on('success', function(e) {
// console.log(e);
var linkTag = this
var gameId = parseInt($(this).attr('data-game-id'))
var type = $(this).attr('data-type')
var url = ''
if (type == 'download') {
url = "__URL__/getDownloadUrl"
} else if (type == 'landing-page') {
url = "__URL__/getLandingPageUrl"
}
$.ajax({
url: url,
type: 'post',
dataType: "json",
data: {game_id: gameId},
success: function (response) {
if (response.status == 1) {
var qrcodeWidth = 200
var qrcodeHeight = 200
var logoWidth = qrcodeWidth/4
var logoHeight = qrcodeHeight/4
var options = {
render: 'canvas',
ecLevel: 'H',//识别度
fill: '#000',//二维码颜色
background: '#ffffff',//背景颜色
quiet: 2,//边距
width: 200,//宽度
height: 200,
text: response.data.url,//二维码内容
label: 'jQuery.qrcode',
fontname: 'Ubuntu',
fontcolor: '#ff9818',
};
var logo = $(linkTag).parents('.game-li').eq(0).find('.img-box').children('img')[0]
$('#game_link_ercode').empty().qrcode(options);
$("#game_link_ercode canvas")[0].getContext('2d').drawImage(logo, (qrcodeWidth - logoWidth) / 2, (qrcodeHeight - logoHeight) / 2, logoWidth, logoHeight);
$('#clipboard-btn').attr('data-text', response.data.url)
$('#clipboard-btn').click()
$('#game_link_address').text(response.data.url);
$('#game_link').show();
$('.game-window-bg').show();
} else {
layer.alert(response.message, {icon: 7});
}
},
error: function (result) {
layer.msg('网络异常', {icon: 5});
}
});
});
clipboard.on('error', function(e) {
// console.log(e);
});
new ClipboardJS('#clipboard-btn', {
text: function(trigger) {
return trigger.getAttribute('data-text');
}
})
$('#submit').click(function () {
var url = $(this).attr('url');
console.log(url);
var query = $('.jssearch').find('input').serialize();
query += "&" + $('.jssearch').find('select').serialize();
query = query.replace(/(&|^)(\w*?\d*?\-*?_*?)*?=?((?=&)|(?=$))/g, '');

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<link href="{:get_cover(C('CH_SET_ICO'),'path')}" type="image/x-icon" rel="shortcut icon">
<title>下载失败</title>
<link rel="stylesheet" href="__CSS__/20180207/promition.css">
<link rel="stylesheet" href="__CSS__/20180207/game.css">
</head>
<body class="main_bg">
<div class="h_wrap p_t_30 p_lr_10" style="padding-top:15px;">
<p>{$message}</p>
</div>
</body>
</html>

@ -0,0 +1,133 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta itemprop="name" content="{$game['relation_game_name']}"/>
<meta itemprop="image" content="{$game['icon']}"/>
<meta name="description" itemprop="description" content="{$game['features']}"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<script type="text/javascript" src="__JS__/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="https://res2.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<link href="{:get_cover(C('CH_SET_ICO'),'path')}" type="image/x-icon" rel="shortcut icon">
<title>{$game['relation_game_name']}</title>
<link rel="stylesheet" href="__CSS__/20180207/promition.css">
<link rel="stylesheet" href="__CSS__/20180207/game.css">
<link href="__STATIC__/ios9/css/common.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="__CSS__/landing_page.css">
</head>
<body class="main_bg" style="background-color: #0a0a0a;height: auto;">
<input type="hidden" name="title" value="{$game['relation_game_name']}">
<input type="hidden" name="icon" value="{$game['icon']}">
<input type="hidden" name="desc" value="{$game['features']}">
<input type="hidden" name="isIOS13" value="<?php if($isIOS13):?>1<?php else:?>0<?php endif;?>">
<?php if ($isWechat):?>
<?php if ($isAndroid):?>
<div class="bn-rule" style="display: none;"><img id="rule-img" src="__STATIC__/ios9/images/android-rule.png"></div>
<?php elseif ($isIOS):?>
<div class="bn-rule" style="display: none;"><img id="rule-img" src="__STATIC__/ios9/images/ios-rule.png"></div>
<?php endif;?>
<?php endif;?>
<div class="h_wrap">
<div id="data-2">
<volist name="game['flooring_page_imgs']" id="item">
<?php if ($downloadUrl == 'https://'.$_SERVER['HTTP_HOST']) :?>
<a href="#" class="no-package"><img src="{$item}" style="width: 100%;"/></a>
<?php else :?>
<a href="javascript:;" class="down-link" down-link="{$downloadUrl}"><img src="{$item}" style="width: 100%;"/></a>
<?php endif ;?>
</volist>
</div>
</div>
<script src="__STATIC__/layer/layer.js"></script>
<script src="__STATIC__/ios9/js/layer/layer.js?VerNo=20190923" type="text/javascript"></script>
<script type="text/javascript">
$('.down-link').on('click', function () {
if ($('.bn-rule').length > 0) {
$('.bn-rule').css('display','block')
$('.bn-rule').css('z-index','12')
return
}
if ($('input[name=isIOS13]').val() == 1) {
if (parseInt("{:I('get.status')}") > 0) {
location.href = "{:U('iosDown',array('gid'=>$gameId,'pid'=>I('get.pid'),'status'=>1))}"
return
} else {
layer.confirm('请先到官网注册', {title: '提示'}, function () {
location.href = "/mobile.php?s=/User/login/pid/" + "{:I('get.pid')}" + "/gid/" + "{:I('get.gid')}" + ".html"
})
return
}
}
var downLink = $(this).attr('down-link')
location.href = downLink
});
$('.no-package').click(function() {
layer.msg('暂无下载', {
icon: 7,
time: 2000
})
})
$.ajax({
url: "{:U('Home/generateWechatSign')}",
dataType: 'json',
type: 'post',
data: {url: window.location.href},
success: function(response) {
if (response.status) {
wx.config({
// debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来若要查看传入的参数可以在pc端打开参数信息会通过log打出仅在pc端时才会打印。
appId: response.data.appid,
timestamp: response.data.time,
nonceStr: response.data.randStr,
signature: response.data.sign,
jsApiList: ['onMenuShareAppMessage', 'onMenuShareTimeline', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone']
})
var title = $('[name=title]').val();
var description = $('[name=desc]').val();
var icon = $('[name=icon]').val();
wxReady(title, description, icon)
}
}
});
function wxReady(title, description, img) {
wx.ready(function () {
wx.onMenuShareAppMessage({
title: title,
desc: description,
link: window.location.href,
imgUrl: img,
type: '',
dataUrl: ''
});
wx.onMenuShareTimeline({
title: title,
link: window.location.href,
imgUrl: img
});
wx.onMenuShareQQ({
title: title,
desc: description,
link: window.location.href,
imgUrl: img
});
wx.onMenuShareWeibo({
title: title,
desc: description,
link: window.location.href,
imgUrl: img
});
wx.onMenuShareQZone({
title: title,
desc: description,
link: window.location.href,
imgUrl: img
});
});
}
</script>
</body>
</html>

@ -0,0 +1,102 @@
.weixin {
position: absolute;
top: -80px;
right: 0;
width: 17rem;
height: 30rem;
margin-top: 2px;
background: url(../images/img_sign.png) left top no-repeat;
background-size: 100% 100%;
z-index: 99;
}
html {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
body, div {
margin: 0;
padding: 0;
}
.bn-rule {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: #333;
}
.bn-rule img {
margin-top: 21px;
width: 100%;
}
.register-box-max {
width: 80%;
height: 280px;
top: calc(50% - 140px);
left: 10%;
position: fixed;
z-index: 10;
background-color: #fff;
border-radius: 10px;
}
@media screen and (min-width: 768px) {
.register-box-max {
width: 50%;
left: 25%;
}
}
.register-bg {
width: 100%;
height: inherit;
position: fixed;
background-color: #0a0a0a;
opacity: 0.5;
}
.register-title-box {
padding: 10px 10px;
margin-top: 10px;
text-align: center;
font-size: 1.2rem;
}
.register-title-box span {
font-weight: 600;
}
.register-input-box {
text-align: center;
font-size: 1rem;
}
.register-input-box input {
width: calc(80% - 5px);
height: 2rem;
padding-left: 5px;
margin-top: 10px;
margin-bottom: 10px;
border: 1px solid #6f6f6f;
border-radius: 3px;
}
.register-btn-box {
margin-top: 40px;
text-align: center;
}
.register-btn-box button {
width: 80%;
height: 2.5rem;
border: 0;
border-radius: 18px;
background-color: #1993ff;
color: #fff;
font-size: 1.1rem;
}

@ -0,0 +1,76 @@
body {
font: 400 14px/1.5 'Microsoft YaHei','微软雅黑',Tahoma,Verdana,Arial,'宋体',sans-serif;
}
.zclip embed {
margin-top: -14px;
}
.trunk-list {
position: relative;
min-height: 66vh;
}
.pagenation {
position: relative;
text-align: center;
line-height: 5vh;
bottom: 1%;
}
.pic-prev:hover, .pic-next:hover {
background-color: #4ac5c3;
}
.layui-btn{
background-color: #5fb878;
}
.label{
padding: 2px 5px;
background: #5FB878;
border-radius: 2px;
color: #fff;
display: block;
line-height: 20px;
height: 20px;
margin: 2px 5px 2px 0;
float: left;
}
i{
display: inline-block;
width: 18px;
height: 18px;
line-height: 18px;
text-align: center
}
.label:hover{color: white;}
.label i:hover {
background-color: #009E94;
border-radius: 2px;
}
.layui-form-select dl dd:hover {
background-color: #5FB878;
color: white;
}
.AD{
width: 210px;
margin-left: 40px;
overflow-y: auto;
max-height: 200px;
border: 2px solid #5fb878;
border-radius: 6px;
padding: 1px 2px;
}
#add_promote_data label {
width: 70px;
margin-right: 0;
padding-left: 0;
text-align: left;
}
#add_promote_data .AD {
white-space: nowrap;
margin-bottom: 2px;
overflow:scroll;
}

@ -0,0 +1,28 @@
(function(r){r.fn.qrcode=function(h){var s;function u(a){this.mode=s;this.data=a}function o(a,c){this.typeNumber=a;this.errorCorrectLevel=c;this.modules=null;this.moduleCount=0;this.dataCache=null;this.dataList=[]}function q(a,c){if(void 0==a.length)throw Error(a.length+"/"+c);for(var d=0;d<a.length&&0==a[d];)d++;this.num=Array(a.length-d+c);for(var b=0;b<a.length-d;b++)this.num[b]=a[b+d]}function p(a,c){this.totalCount=a;this.dataCount=c}function t(){this.buffer=[];this.length=0}u.prototype={getLength:function(){return this.data.length},
write:function(a){for(var c=0;c<this.data.length;c++)a.put(this.data.charCodeAt(c),8)}};o.prototype={addData:function(a){this.dataList.push(new u(a));this.dataCache=null},isDark:function(a,c){if(0>a||this.moduleCount<=a||0>c||this.moduleCount<=c)throw Error(a+","+c);return this.modules[a][c]},getModuleCount:function(){return this.moduleCount},make:function(){if(1>this.typeNumber){for(var a=1,a=1;40>a;a++){for(var c=p.getRSBlocks(a,this.errorCorrectLevel),d=new t,b=0,e=0;e<c.length;e++)b+=c[e].dataCount;
for(e=0;e<this.dataList.length;e++)c=this.dataList[e],d.put(c.mode,4),d.put(c.getLength(),j.getLengthInBits(c.mode,a)),c.write(d);if(d.getLengthInBits()<=8*b)break}this.typeNumber=a}this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17;this.modules=Array(this.moduleCount);for(var d=0;d<this.moduleCount;d++){this.modules[d]=Array(this.moduleCount);for(var b=0;b<this.moduleCount;b++)this.modules[d][b]=null}this.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-
7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(a,c);7<=this.typeNumber&&this.setupTypeNumber(a);null==this.dataCache&&(this.dataCache=o.createData(this.typeNumber,this.errorCorrectLevel,this.dataList));this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,c){for(var d=-1;7>=d;d++)if(!(-1>=a+d||this.moduleCount<=a+d))for(var b=-1;7>=b;b++)-1>=c+b||this.moduleCount<=c+b||(this.modules[a+d][c+b]=
0<=d&&6>=d&&(0==b||6==b)||0<=b&&6>=b&&(0==d||6==d)||2<=d&&4>=d&&2<=b&&4>=b?!0:!1)},getBestMaskPattern:function(){for(var a=0,c=0,d=0;8>d;d++){this.makeImpl(!0,d);var b=j.getLostPoint(this);if(0==d||a>b)a=b,c=d}return c},createMovieClip:function(a,c,d){a=a.createEmptyMovieClip(c,d);this.make();for(c=0;c<this.modules.length;c++)for(var d=1*c,b=0;b<this.modules[c].length;b++){var e=1*b;this.modules[c][b]&&(a.beginFill(0,100),a.moveTo(e,d),a.lineTo(e+1,d),a.lineTo(e+1,d+1),a.lineTo(e,d+1),a.endFill())}return a},
setupTimingPattern:function(){for(var a=8;a<this.moduleCount-8;a++)null==this.modules[a][6]&&(this.modules[a][6]=0==a%2);for(a=8;a<this.moduleCount-8;a++)null==this.modules[6][a]&&(this.modules[6][a]=0==a%2)},setupPositionAdjustPattern:function(){for(var a=j.getPatternPosition(this.typeNumber),c=0;c<a.length;c++)for(var d=0;d<a.length;d++){var b=a[c],e=a[d];if(null==this.modules[b][e])for(var f=-2;2>=f;f++)for(var i=-2;2>=i;i++)this.modules[b+f][e+i]=-2==f||2==f||-2==i||2==i||0==f&&0==i?!0:!1}},setupTypeNumber:function(a){for(var c=
j.getBCHTypeNumber(this.typeNumber),d=0;18>d;d++){var b=!a&&1==(c>>d&1);this.modules[Math.floor(d/3)][d%3+this.moduleCount-8-3]=b}for(d=0;18>d;d++)b=!a&&1==(c>>d&1),this.modules[d%3+this.moduleCount-8-3][Math.floor(d/3)]=b},setupTypeInfo:function(a,c){for(var d=j.getBCHTypeInfo(this.errorCorrectLevel<<3|c),b=0;15>b;b++){var e=!a&&1==(d>>b&1);6>b?this.modules[b][8]=e:8>b?this.modules[b+1][8]=e:this.modules[this.moduleCount-15+b][8]=e}for(b=0;15>b;b++)e=!a&&1==(d>>b&1),8>b?this.modules[8][this.moduleCount-
b-1]=e:9>b?this.modules[8][15-b-1+1]=e:this.modules[8][15-b-1]=e;this.modules[this.moduleCount-8][8]=!a},mapData:function(a,c){for(var d=-1,b=this.moduleCount-1,e=7,f=0,i=this.moduleCount-1;0<i;i-=2)for(6==i&&i--;;){for(var g=0;2>g;g++)if(null==this.modules[b][i-g]){var n=!1;f<a.length&&(n=1==(a[f]>>>e&1));j.getMask(c,b,i-g)&&(n=!n);this.modules[b][i-g]=n;e--; -1==e&&(f++,e=7)}b+=d;if(0>b||this.moduleCount<=b){b-=d;d=-d;break}}}};o.PAD0=236;o.PAD1=17;o.createData=function(a,c,d){for(var c=p.getRSBlocks(a,
c),b=new t,e=0;e<d.length;e++){var f=d[e];b.put(f.mode,4);b.put(f.getLength(),j.getLengthInBits(f.mode,a));f.write(b)}for(e=a=0;e<c.length;e++)a+=c[e].dataCount;if(b.getLengthInBits()>8*a)throw Error("code length overflow. ("+b.getLengthInBits()+">"+8*a+")");for(b.getLengthInBits()+4<=8*a&&b.put(0,4);0!=b.getLengthInBits()%8;)b.putBit(!1);for(;!(b.getLengthInBits()>=8*a);){b.put(o.PAD0,8);if(b.getLengthInBits()>=8*a)break;b.put(o.PAD1,8)}return o.createBytes(b,c)};o.createBytes=function(a,c){for(var d=
0,b=0,e=0,f=Array(c.length),i=Array(c.length),g=0;g<c.length;g++){var n=c[g].dataCount,h=c[g].totalCount-n,b=Math.max(b,n),e=Math.max(e,h);f[g]=Array(n);for(var k=0;k<f[g].length;k++)f[g][k]=255&a.buffer[k+d];d+=n;k=j.getErrorCorrectPolynomial(h);n=(new q(f[g],k.getLength()-1)).mod(k);i[g]=Array(k.getLength()-1);for(k=0;k<i[g].length;k++)h=k+n.getLength()-i[g].length,i[g][k]=0<=h?n.get(h):0}for(k=g=0;k<c.length;k++)g+=c[k].totalCount;d=Array(g);for(k=n=0;k<b;k++)for(g=0;g<c.length;g++)k<f[g].length&&
(d[n++]=f[g][k]);for(k=0;k<e;k++)for(g=0;g<c.length;g++)k<i[g].length&&(d[n++]=i[g][k]);return d};s=4;for(var j={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,
78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(a){for(var c=a<<10;0<=j.getBCHDigit(c)-j.getBCHDigit(j.G15);)c^=j.G15<<j.getBCHDigit(c)-j.getBCHDigit(j.G15);return(a<<10|c)^j.G15_MASK},getBCHTypeNumber:function(a){for(var c=a<<12;0<=j.getBCHDigit(c)-
j.getBCHDigit(j.G18);)c^=j.G18<<j.getBCHDigit(c)-j.getBCHDigit(j.G18);return a<<12|c},getBCHDigit:function(a){for(var c=0;0!=a;)c++,a>>>=1;return c},getPatternPosition:function(a){return j.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,c,d){switch(a){case 0:return 0==(c+d)%2;case 1:return 0==c%2;case 2:return 0==d%3;case 3:return 0==(c+d)%3;case 4:return 0==(Math.floor(c/2)+Math.floor(d/3))%2;case 5:return 0==c*d%2+c*d%3;case 6:return 0==(c*d%2+c*d%3)%2;case 7:return 0==(c*d%3+(c+d)%2)%2;default:throw Error("bad maskPattern:"+
a);}},getErrorCorrectPolynomial:function(a){for(var c=new q([1],0),d=0;d<a;d++)c=c.multiply(new q([1,l.gexp(d)],0));return c},getLengthInBits:function(a,c){if(1<=c&&10>c)switch(a){case 1:return 10;case 2:return 9;case s:return 8;case 8:return 8;default:throw Error("mode:"+a);}else if(27>c)switch(a){case 1:return 12;case 2:return 11;case s:return 16;case 8:return 10;default:throw Error("mode:"+a);}else if(41>c)switch(a){case 1:return 14;case 2:return 13;case s:return 16;case 8:return 12;default:throw Error("mode:"+
a);}else throw Error("type:"+c);},getLostPoint:function(a){for(var c=a.getModuleCount(),d=0,b=0;b<c;b++)for(var e=0;e<c;e++){for(var f=0,i=a.isDark(b,e),g=-1;1>=g;g++)if(!(0>b+g||c<=b+g))for(var h=-1;1>=h;h++)0>e+h||c<=e+h||0==g&&0==h||i==a.isDark(b+g,e+h)&&f++;5<f&&(d+=3+f-5)}for(b=0;b<c-1;b++)for(e=0;e<c-1;e++)if(f=0,a.isDark(b,e)&&f++,a.isDark(b+1,e)&&f++,a.isDark(b,e+1)&&f++,a.isDark(b+1,e+1)&&f++,0==f||4==f)d+=3;for(b=0;b<c;b++)for(e=0;e<c-6;e++)a.isDark(b,e)&&!a.isDark(b,e+1)&&a.isDark(b,e+
2)&&a.isDark(b,e+3)&&a.isDark(b,e+4)&&!a.isDark(b,e+5)&&a.isDark(b,e+6)&&(d+=40);for(e=0;e<c;e++)for(b=0;b<c-6;b++)a.isDark(b,e)&&!a.isDark(b+1,e)&&a.isDark(b+2,e)&&a.isDark(b+3,e)&&a.isDark(b+4,e)&&!a.isDark(b+5,e)&&a.isDark(b+6,e)&&(d+=40);for(e=f=0;e<c;e++)for(b=0;b<c;b++)a.isDark(b,e)&&f++;a=Math.abs(100*f/c/c-50)/5;return d+10*a}},l={glog:function(a){if(1>a)throw Error("glog("+a+")");return l.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;256<=a;)a-=255;return l.EXP_TABLE[a]},EXP_TABLE:Array(256),
LOG_TABLE:Array(256)},m=0;8>m;m++)l.EXP_TABLE[m]=1<<m;for(m=8;256>m;m++)l.EXP_TABLE[m]=l.EXP_TABLE[m-4]^l.EXP_TABLE[m-5]^l.EXP_TABLE[m-6]^l.EXP_TABLE[m-8];for(m=0;255>m;m++)l.LOG_TABLE[l.EXP_TABLE[m]]=m;q.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var c=Array(this.getLength()+a.getLength()-1),d=0;d<this.getLength();d++)for(var b=0;b<a.getLength();b++)c[d+b]^=l.gexp(l.glog(this.get(d))+l.glog(a.get(b)));return new q(c,0)},mod:function(a){if(0>
this.getLength()-a.getLength())return this;for(var c=l.glog(this.get(0))-l.glog(a.get(0)),d=Array(this.getLength()),b=0;b<this.getLength();b++)d[b]=this.get(b);for(b=0;b<a.getLength();b++)d[b]^=l.gexp(l.glog(a.get(b))+c);return(new q(d,0)).mod(a)}};p.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],
[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,
116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,
43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,
3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,
55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,
45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];p.getRSBlocks=function(a,c){var d=p.getRsBlockTable(a,c);if(void 0==d)throw Error("bad rs block @ typeNumber:"+a+"/errorCorrectLevel:"+c);for(var b=d.length/3,e=[],f=0;f<b;f++)for(var h=d[3*f+0],g=d[3*f+1],j=d[3*f+2],l=0;l<h;l++)e.push(new p(g,j));return e};p.getRsBlockTable=function(a,c){switch(c){case 1:return p.RS_BLOCK_TABLE[4*(a-1)+0];case 0:return p.RS_BLOCK_TABLE[4*(a-1)+1];case 3:return p.RS_BLOCK_TABLE[4*
(a-1)+2];case 2:return p.RS_BLOCK_TABLE[4*(a-1)+3]}};t.prototype={get:function(a){return 1==(this.buffer[Math.floor(a/8)]>>>7-a%8&1)},put:function(a,c){for(var d=0;d<c;d++)this.putBit(1==(a>>>c-d-1&1))},getLengthInBits:function(){return this.length},putBit:function(a){var c=Math.floor(this.length/8);this.buffer.length<=c&&this.buffer.push(0);a&&(this.buffer[c]|=128>>>this.length%8);this.length++}};"string"===typeof h&&(h={text:h});h=r.extend({},{render:"canvas",width:256,height:256,typeNumber:-1,
correctLevel:2,background:"#ffffff",foreground:"#000000"},h);return this.each(function(){var a;if("canvas"==h.render){a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();var c=document.createElement("canvas");c.width=h.width;c.height=h.height;for(var d=c.getContext("2d"),b=h.width/a.getModuleCount(),e=h.height/a.getModuleCount(),f=0;f<a.getModuleCount();f++)for(var i=0;i<a.getModuleCount();i++){d.fillStyle=a.isDark(f,i)?h.foreground:h.background;var g=Math.ceil((i+1)*b)-Math.floor(i*b),
j=Math.ceil((f+1)*b)-Math.floor(f*b);d.fillRect(Math.round(i*b),Math.round(f*e),g,j)}}else{a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();c=r("<table></table>").css("width",h.width+"px").css("height",h.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",h.background);d=h.width/a.getModuleCount();b=h.height/a.getModuleCount();for(e=0;e<a.getModuleCount();e++){f=r("<tr></tr>").css("height",b+"px").appendTo(c);for(i=0;i<a.getModuleCount();i++)r("<td></td>").css("width",
d+"px").css("background-color",a.isDark(e,i)?h.foreground:h.background).appendTo(f)}}a=c;jQuery(a).appendTo(this)})}})(jQuery);

File diff suppressed because one or more lines are too long

@ -1,745 +0,0 @@
/*!
* clipboard.js v1.5.5
* https://zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Clipboard = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var matches = require('matches-selector')
module.exports = function (element, selector, checkYoSelf) {
var parent = checkYoSelf ? element : element.parentNode
while (parent && parent !== document) {
if (matches(parent, selector)) return parent;
parent = parent.parentNode
}
}
},{"matches-selector":2}],2:[function(require,module,exports){
/**
* Element prototype.
*/
var proto = Element.prototype;
/**
* Vendor function.
*/
var vendor = proto.matchesSelector
|| proto.webkitMatchesSelector
|| proto.mozMatchesSelector
|| proto.msMatchesSelector
|| proto.oMatchesSelector;
/**
* Expose `match()`.
*/
module.exports = match;
/**
* Match `el` to `selector`.
*
* @param {Element} el
* @param {String} selector
* @return {Boolean}
* @api public
*/
function match(el, selector) {
if (vendor) return vendor.call(el, selector);
var nodes = el.parentNode.querySelectorAll(selector);
for (var i = 0; i < nodes.length; ++i) {
if (nodes[i] == el) return true;
}
return false;
}
},{}],3:[function(require,module,exports){
var closest = require('closest');
/**
* Delegates event to a selector.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function delegate(element, selector, type, callback) {
var listenerFn = listener.apply(this, arguments);
element.addEventListener(type, listenerFn);
return {
destroy: function() {
element.removeEventListener(type, listenerFn);
}
}
}
/**
* Finds closest match and invokes callback.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Function}
*/
function listener(element, selector, type, callback) {
return function(e) {
e.delegateTarget = closest(e.target, selector, true);
if (e.delegateTarget) {
callback.call(element, e);
}
}
}
module.exports = delegate;
},{"closest":1}],4:[function(require,module,exports){
/**
* Check if argument is a HTML element.
*
* @param {Object} value
* @return {Boolean}
*/
exports.node = function(value) {
return value !== undefined
&& value instanceof HTMLElement
&& value.nodeType === 1;
};
/**
* Check if argument is a list of HTML elements.
*
* @param {Object} value
* @return {Boolean}
*/
exports.nodeList = function(value) {
var type = Object.prototype.toString.call(value);
return value !== undefined
&& (type === '[object NodeList]' || type === '[object HTMLCollection]')
&& ('length' in value)
&& (value.length === 0 || exports.node(value[0]));
};
/**
* Check if argument is a string.
*
* @param {Object} value
* @return {Boolean}
*/
exports.string = function(value) {
return typeof value === 'string'
|| value instanceof String;
};
/**
* Check if argument is a function.
*
* @param {Object} value
* @return {Boolean}
*/
exports.function = function(value) {
var type = Object.prototype.toString.call(value);
return type === '[object Function]';
};
},{}],5:[function(require,module,exports){
var is = require('./is');
var delegate = require('delegate');
/**
* Validates all params and calls the right
* listener function based on its target type.
*
* @param {String|HTMLElement|HTMLCollection|NodeList} target
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listen(target, type, callback) {
if (!target && !type && !callback) {
throw new Error('Missing required arguments');
}
if (!is.string(type)) {
throw new TypeError('Second argument must be a String');
}
if (!is.function(callback)) {
throw new TypeError('Third argument must be a Function');
}
if (is.node(target)) {
return listenNode(target, type, callback);
}
else if (is.nodeList(target)) {
return listenNodeList(target, type, callback);
}
else if (is.string(target)) {
return listenSelector(target, type, callback);
}
else {
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');
}
}
/**
* Adds an event listener to a HTML element
* and returns a remove listener function.
*
* @param {HTMLElement} node
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNode(node, type, callback) {
node.addEventListener(type, callback);
return {
destroy: function() {
node.removeEventListener(type, callback);
}
}
}
/**
* Add an event listener to a list of HTML elements
* and returns a remove listener function.
*
* @param {NodeList|HTMLCollection} nodeList
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNodeList(nodeList, type, callback) {
Array.prototype.forEach.call(nodeList, function(node) {
node.addEventListener(type, callback);
});
return {
destroy: function() {
Array.prototype.forEach.call(nodeList, function(node) {
node.removeEventListener(type, callback);
});
}
}
}
/**
* Add an event listener to a selector
* and returns a remove listener function.
*
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenSelector(selector, type, callback) {
return delegate(document.body, selector, type, callback);
}
module.exports = listen;
},{"./is":4,"delegate":3}],6:[function(require,module,exports){
function select(element) {
var selectedText;
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
element.focus();
element.setSelectionRange(0, element.value.length);
selectedText = element.value;
}
else {
if (element.hasAttribute('contenteditable')) {
element.focus();
}
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
selectedText = selection.toString();
}
return selectedText;
}
module.exports = select;
},{}],7:[function(require,module,exports){
function E () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener () {
self.off(name, listener);
callback.apply(ctx, arguments);
};
listener._ = callback
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
(liveEvents.length)
? e[name] = liveEvents
: delete e[name];
return this;
}
};
module.exports = E;
},{}],8:[function(require,module,exports){
'use strict';
exports.__esModule = true;
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _select = require('select');
var _select2 = _interopRequireDefault(_select);
/**
* Inner class which performs selection from either `text` or `target`
* properties and then executes copy or cut operations.
*/
var ClipboardAction = (function () {
/**
* @param {Object} options
*/
function ClipboardAction(options) {
_classCallCheck(this, ClipboardAction);
this.resolveOptions(options);
this.initSelection();
}
/**
* Defines base properties passed from constructor.
* @param {Object} options
*/
ClipboardAction.prototype.resolveOptions = function resolveOptions() {
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
this.action = options.action;
this.emitter = options.emitter;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
};
/**
* Decides which selection strategy is going to be applied based
* on the existence of `text` and `target` properties.
*/
ClipboardAction.prototype.initSelection = function initSelection() {
if (this.text && this.target) {
throw new Error('Multiple attributes declared, use either "target" or "text"');
} else if (this.text) {
this.selectFake();
} else if (this.target) {
this.selectTarget();
} else {
throw new Error('Missing required attributes, use either "target" or "text"');
}
};
/**
* Creates a fake textarea element, sets its value from `text` property,
* and makes a selection on it.
*/
ClipboardAction.prototype.selectFake = function selectFake() {
var _this = this;
this.removeFake();
this.fakeHandler = document.body.addEventListener('click', function () {
return _this.removeFake();
});
this.fakeElem = document.createElement('textarea');
this.fakeElem.style.position = 'absolute';
this.fakeElem.style.left = '-9999px';
this.fakeElem.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
this.fakeElem.setAttribute('readonly', '');
this.fakeElem.value = this.text;
document.body.appendChild(this.fakeElem);
this.selectedText = _select2['default'](this.fakeElem);
this.copyText();
};
/**
* Only removes the fake element after another click event, that way
* a user can hit `Ctrl+C` to copy because selection still exists.
*/
ClipboardAction.prototype.removeFake = function removeFake() {
if (this.fakeHandler) {
document.body.removeEventListener('click');
this.fakeHandler = null;
}
if (this.fakeElem) {
document.body.removeChild(this.fakeElem);
this.fakeElem = null;
}
};
/**
* Selects the content from element passed on `target` property.
*/
ClipboardAction.prototype.selectTarget = function selectTarget() {
this.selectedText = _select2['default'](this.target);
this.copyText();
};
/**
* Executes the copy operation based on the current selection.
*/
ClipboardAction.prototype.copyText = function copyText() {
var succeeded = undefined;
try {
succeeded = document.execCommand(this.action);
} catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
};
/**
* Fires an event based on the copy operation result.
* @param {Boolean} succeeded
*/
ClipboardAction.prototype.handleResult = function handleResult(succeeded) {
if (succeeded) {
this.emitter.emit('success', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
} else {
this.emitter.emit('error', {
action: this.action,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
}
};
/**
* Removes current selection and focus from `target` element.
*/
ClipboardAction.prototype.clearSelection = function clearSelection() {
if (this.target) {
this.target.blur();
}
window.getSelection().removeAllRanges();
};
/**
* Sets the `action` to be performed which can be either 'copy' or 'cut'.
* @param {String} action
*/
/**
* Destroy lifecycle.
*/
ClipboardAction.prototype.destroy = function destroy() {
this.removeFake();
};
_createClass(ClipboardAction, [{
key: 'action',
set: function set() {
var action = arguments.length <= 0 || arguments[0] === undefined ? 'copy' : arguments[0];
this._action = action;
if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "action" value, use either "copy" or "cut"');
}
},
/**
* Gets the `action` property.
* @return {String}
*/
get: function get() {
return this._action;
}
/**
* Sets the `target` property using an element
* that will be have its content copied.
* @param {Element} target
*/
}, {
key: 'target',
set: function set(target) {
if (target !== undefined) {
if (target && typeof target === 'object' && target.nodeType === 1) {
this._target = target;
} else {
throw new Error('Invalid "target" value, use a valid Element');
}
}
},
/**
* Gets the `target` property.
* @return {String|HTMLElement}
*/
get: function get() {
return this._target;
}
}]);
return ClipboardAction;
})();
exports['default'] = ClipboardAction;
module.exports = exports['default'];
},{"select":6}],9:[function(require,module,exports){
'use strict';
exports.__esModule = true;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _clipboardAction = require('./clipboard-action');
var _clipboardAction2 = _interopRequireDefault(_clipboardAction);
var _tinyEmitter = require('tiny-emitter');
var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter);
var _goodListener = require('good-listener');
var _goodListener2 = _interopRequireDefault(_goodListener);
/**
* Base class which takes one or more elements, adds event listeners to them,
* and instantiates a new `ClipboardAction` on each click.
*/
var Clipboard = (function (_Emitter) {
_inherits(Clipboard, _Emitter);
/**
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options
*/
function Clipboard(trigger, options) {
_classCallCheck(this, Clipboard);
_Emitter.call(this);
this.resolveOptions(options);
this.listenClick(trigger);
}
/**
* Helper function to retrieve attribute value.
* @param {String} suffix
* @param {Element} element
*/
/**
* Defines if attributes would be resolved using internal setter functions
* or custom functions that were passed in the constructor.
* @param {Object} options
*/
Clipboard.prototype.resolveOptions = function resolveOptions() {
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
};
/**
* Adds a click event listener to the passed trigger.
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
*/
Clipboard.prototype.listenClick = function listenClick(trigger) {
var _this = this;
this.listener = _goodListener2['default'](trigger, 'click', function (e) {
return _this.onClick(e);
});
};
/**
* Defines a new `ClipboardAction` on each click event.
* @param {Event} e
*/
Clipboard.prototype.onClick = function onClick(e) {
var trigger = e.delegateTarget || e.currentTarget;
if (this.clipboardAction) {
this.clipboardAction = null;
}
this.clipboardAction = new _clipboardAction2['default']({
action: this.action(trigger),
target: this.target(trigger),
text: this.text(trigger),
trigger: trigger,
emitter: this
});
};
/**
* Default `action` lookup function.
* @param {Element} trigger
*/
Clipboard.prototype.defaultAction = function defaultAction(trigger) {
return getAttributeValue('action', trigger);
};
/**
* Default `target` lookup function.
* @param {Element} trigger
*/
Clipboard.prototype.defaultTarget = function defaultTarget(trigger) {
var selector = getAttributeValue('target', trigger);
if (selector) {
return document.querySelector(selector);
}
};
/**
* Default `text` lookup function.
* @param {Element} trigger
*/
Clipboard.prototype.defaultText = function defaultText(trigger) {
return getAttributeValue('text', trigger);
};
/**
* Destroy lifecycle.
*/
Clipboard.prototype.destroy = function destroy() {
this.listener.destroy();
if (this.clipboardAction) {
this.clipboardAction.destroy();
this.clipboardAction = null;
}
};
return Clipboard;
})(_tinyEmitter2['default']);
function getAttributeValue(suffix, element) {
var attribute = 'data-clipboard-' + suffix;
if (!element.hasAttribute(attribute)) {
return;
}
return element.getAttribute(attribute);
}
exports['default'] = Clipboard;
module.exports = exports['default'];
},{"./clipboard-action":8,"good-listener":5,"tiny-emitter":7}]},{},[9])(9)
});

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save