pull/1/head v2.4
zorlan 2021-09-10 11:28:01 +08:00
parent f5af21e5ef
commit b1497d0ad5
517 changed files with 68059 additions and 58395 deletions

View File

@ -15,49 +15,64 @@ use skycaiji\admin\controller\BaseController;
class Init{
public function run(){
$curController=strtolower(request()->controller());
if('store'==$curController){
controller('Store','controller')->_checkCors(true);
}
/*自动登录*/
$muser=model('User');
$s_userid=session('user_id');
if(!IS_CLI&&empty($s_userid)){
$s_userlogin=session('user_login');
if(!IS_CLI&&empty($s_userlogin)){
$login_history=cookie('login_history');
if(!empty($login_history)){
$login_history=explode('|', $login_history);
$user=$muser->where('username',$login_history[0])->find();
$loginHistory=cookie('login_history');
if(!empty($loginHistory)){
$loginHistory=explode('|', $loginHistory);
$user=$muser->getByUid($loginHistory[0]);
if(!empty($user)){
$user['username']=strtolower($user['username']);
if($user['username']==$login_history[0]&&$login_history[1]==md5($user['username'].$user['password'])){
session('user_id',$user['uid']);
if($loginHistory[1]==$muser->generate_key($user)){
$muser->setLoginSession($user);
}
}
unset($user);
}
$s_userid=session('user_id');
$s_userlogin=session('user_login');
}
$s_userlogin=is_array($s_userlogin)?$s_userlogin:array();
$s_userid=intval($s_userlogin['uid']);
$isAdmin=null;
$user=null;
if($s_userid>0){
$GLOBALS['_sc']['user']=$muser->getByUid($s_userid);
if(!empty($GLOBALS['_sc']['user'])){
$GLOBALS['_sc']['user']=$GLOBALS['_sc']['user']->toArray();
$GLOBALS['_sc']['user']['group']=model('Usergroup')->getById($GLOBALS['_sc']['user']['groupid']);
if(!empty($GLOBALS['_sc']['user']['group'])){
$GLOBALS['_sc']['user']['group']=$GLOBALS['_sc']['user']['group']->toArray();
if(model('Usergroup')->is_admin($GLOBALS['_sc']['user']['group'])){
session('is_admin',true);
}else{
session('is_admin',null);
$userKeyIsRight=false;
$user=$muser->getByUid($s_userid);
if(!empty($user)){
$user=$user->toArray();
$user['group']=model('Usergroup')->getById($user['groupid']);
if(!empty($user['group'])){
$user['group']=$user['group']->toArray();
if(model('Usergroup')->is_admin($user['group'])){
$isAdmin=true;
}
}
if($s_userlogin['key']==$muser->generate_key($user)){
$userKeyIsRight=true;
}
}
if(!$userKeyIsRight){
$user=null;
}
}
if(empty($user)){
$muser->setLoginSession(null);
}
if(!empty($GLOBALS['_sc']['user'])&&session('is_admin')){
set_g_sc('user',$user);
session('is_admin',$isAdmin);
if(!is_empty(g_sc('user'))&&$isAdmin){
/*是管理员,进行下列操作*/
if('index'==$curController&&'index'==strtolower(request()->action())){
@ -89,13 +104,25 @@ class Init{
$mconfig->cacheConfigList();
$configList=$mconfig->getConfigList();
}
$GLOBALS['_sc']['c']=$configList;
set_g_sc('c',$configList);
set_g_sc('c_caiji_interval',intval(g_sc_c('caiji','interval')));
if(!empty($GLOBALS['_sc']['c']['site']['closelog'])){
$timezone=g_sc_c('site','timezone');
if(!empty($timezone)){
if(strpos($timezone, 'UTC')===0){
$timezone=str_replace(array('UTC+','UTC-'), array('Etc/GMT-','Etc/GMT+'), $timezone);
}
date_default_timezone_set($timezone);
}
if(!is_empty(g_sc_c('site','closelog'))){
\think\Log::init(array('type'=>'test','level'=>array()));
}
if(!empty($GLOBALS['_sc']['c']['site']['dblong'])){
if(!is_empty(g_sc_c('site','dblong'))){
$dbParams=config('database.params');
$dbParams[\PDO::ATTR_PERSISTENT]=true;
@ -103,13 +130,13 @@ class Init{
}
if(empty($GLOBALS['_sc']['c']['download_img'])){
$GLOBALS['_sc']['c']['download_img']=$mconfig->get_img_config_from_caiji($GLOBALS['_sc']['c']['caiji']);
if(is_empty(g_sc_c('download_img'))){
set_g_sc(['c','download_img'],$mconfig->get_img_config_from_caiji(g_sc_c('caiji')));
}
$GLOBALS['_sc']['clientinfo']=clientinfo();
if(!empty($GLOBALS['_sc']['clientinfo'])){
$GLOBALS['_sc']['clientinfo']=base64_encode(json_encode($GLOBALS['_sc']['clientinfo']));
set_g_sc('clientinfo',clientinfo());
if(!is_empty(g_sc('clientinfo'))){
set_g_sc('clientinfo',base64_encode(json_encode(g_sc('clientinfo'))));
}
@ -120,7 +147,7 @@ class Init{
$usertoken=md5($usertoken);
session('usertoken',$usertoken);
}
$GLOBALS['_sc']['usertoken']=$usertoken;
set_g_sc('usertoken',$usertoken);
}
}

View File

@ -23,8 +23,10 @@ class Collect extends Command{
$this->setName('collect')
->addArgument('op', Argument::OPTIONAL, "op")
->addOption('cli_user', null, Option::VALUE_REQUIRED, 'cli user')
->addOption('task_id', null, Option::VALUE_REQUIRED, 'collect:task_id')
->addOption('task_id', null, Option::VALUE_REQUIRED, 'task:task_id')
->addOption('task_ids', null, Option::VALUE_REQUIRED, 'batch:task_ids')
->addOption('rele_id', null, Option::VALUE_REQUIRED, 'test:rele_id')
->addOption('logid', null, Option::VALUE_REQUIRED, 'logid')
->setDescription('collect task');
}
@ -34,9 +36,12 @@ class Collect extends Command{
if(is_array($cacheConfig)){
\think\Config::set($cacheConfig);
}
\skycaiji\common\model\Config::set_url_compatible();
$op=$input->getArgument('op');
static $loginOps=array('task','batch');
static $loginOps=array('task','batch','test');
if(in_array($op, $loginOps)){
@ -48,24 +53,31 @@ class Collect extends Command{
if(!empty($cliUser[0])){
$muser=new \skycaiji\admin\model\User();
$user=$muser->where('username',$cliUser[0])->find();
$user=$muser->getByUid($cliUser[0]);
if(!empty($user)){
$user['username']=strtolower($user['username']);
if($user['username']==$cliUser[0]&&$cliUser[1]==md5($user['username'].$user['password'])){
session('user_id',$user['uid']);
if($cliUser[1]==$muser->generate_key($user)){
$muser->setLoginSession($user);
}
}
}
}
if(!session('?user_id')){
$sUserlogin=session('user_login');
if(empty($sUserlogin)){
$this->error_msg('抱歉,必须传入账号信息!');
}
}
$logid='';
if ($input->hasOption('logid')){
$logid=$input->getOption('logid');
$logid=base64_decode($logid);
}
$rootUrl=\think\Config::get('root_website').'/index.php?s=';
if('task'==$op){
$taskId=0;
@ -75,6 +87,7 @@ class Collect extends Command{
}
$curUrl=$rootUrl.'/admin/task/collect&backstage=1&id='.urlencode($taskId);
$curUrl=$this->url_append_logid($curUrl,$logid);
\think\Request::create($curUrl);
define('BIND_MODULE', "admin/task/collect");
@ -87,17 +100,33 @@ class Collect extends Command{
$taskIds=$input->getOption('task_ids');
}
$curUrl=$rootUrl.'/admin/task/collectBatch&backstage=1&ids='.urlencode($taskIds);
$curUrl=$this->url_append_logid($curUrl,$logid);
\think\Request::create($curUrl);
define('BIND_MODULE', "admin/task/collectBatch");
\think\App::run()->send();
}elseif('test'==$op){
$releId=0;
if ($input->hasOption('rele_id')){
$releId=$input->getOption('rele_id');
$releId=intval($releId);
}
$curUrl=$rootUrl.'/admin/release/test&backstage=1&id='.urlencode($releId);
$curUrl=$this->url_append_logid($curUrl,$logid);
\think\Request::create($curUrl);
define('BIND_MODULE', "admin/release/test");
\think\App::run()->send();
}elseif('backstage'==$op){
set_time_limit(0);
$curKey=CacheModel::getInstance()->getCache('admin_index_backstage_key', 'data');
do{
$cacheKey=CacheModel::getInstance()->getCache('admin_index_backstage_key', 'data');
$curKey=CacheModel::getInstance()->getCache('collect_backstage_key', 'data');
do{
CacheModel::getInstance()->setCache('collect_backstage_time',time());
$cacheKey=CacheModel::getInstance()->getCache('collect_backstage_key', 'data');
if(empty($curKey)||$curKey!=$cacheKey){
@ -107,7 +136,7 @@ class Collect extends Command{
$mconfig=new \skycaiji\admin\model\Config();
$caijiConfig=$mconfig->getConfig('caiji','data');
if($caijiConfig['server']!='cli'){
if(!$mconfig->server_is_cli(true,$caijiConfig['server'])){
$this->error_msg('不是cli命令行模式');
}
if(empty($caijiConfig['auto'])){
@ -117,23 +146,24 @@ class Collect extends Command{
$this->error_msg('不是后台运行方式');
}
$url=$rootUrl.'/admin/api/collect&backstage=1';
try{
\util\Curl::get($url,null,array('timeout'=>3));
}catch(\Exception $ex){
$checkCollectWait=\skycaiji\admin\model\Config::check_collect_wait();
if(!$checkCollectWait){
$url=$rootUrl.'/admin/api/collect&backstage=1';
try{
\util\Curl::get($url,null,array('timeout'=>3));
}catch(\Exception $ex){
}
}
$waitTime=$caijiConfig['interval']*60;
$waitTime=$waitTime>0?$waitTime:60;
sleep($waitTime);
sleep(60);
}while(1==1);
}elseif('auto'==$op){
$curUrl=$rootUrl.'/admin/api/collect&backstage=1';
$curUrl=$this->url_append_logid($curUrl,$logid);
\think\Request::create($curUrl);
define('BIND_MODULE', "admin/api/collect");
@ -144,4 +174,12 @@ class Collect extends Command{
protected function error_msg($msg){
exit($msg);
}
protected function url_append_logid($url,$logid){
if(!empty($logid)){
$url=$url.(strpos($url,'?')===false?'?':'&').'logid='.urlencode($logid);
}
return $url;
}
}

View File

@ -10,12 +10,16 @@
*/
/*采集规则标签*/
function cp_sign($sign,$num=''){
function cp_sign($sign,$id=''){
$sign=strtolower($sign);
if($sign=='match'){
return lang('sign_match',array('num'=>$num));
if($id==':id'){
$id='(?P<id>\w*)';
}
return lang('sign_match',array('id'=>$id));
}else{
return '';
}
}
/*密码验证*/
@ -64,18 +68,13 @@ function program_filemd5_list($path,&$md5FileList){
}
}
}
/*验证用户token*/
function check_usertoken(){
if($GLOBALS['_sc']['usertoken']!=input('_usertoken_')){
return false;
}else{
return true;
}
}
/*输出用户token*/
function html_usertoken(){
return '<input type="hidden" name="_usertoken_" value="'.$GLOBALS['_sc']['usertoken'].'" />';
return '<input type="hidden" name="_usertoken_" value="'.g_sc('usertoken').'" />';
}
function url_usertoken(){
return '_usertoken_='.rawurlencode(g_sc('usertoken'));
}
/*判断正在执行采集任务*/
@ -106,100 +105,150 @@ function cli_command_exec($paramStr){
}
}
$phpExeFile=$GLOBALS['_sc']['c']['caiji']['server_php'];
if(empty($phpExeFile)){
$phpExeFile=model('Config')->detect_php_exe();
$commandStr=g_sc_c('caiji','server_php');
if(empty($commandStr)){
$commandStr=\skycaiji\admin\model\Config::detect_php_exe();
}
$commandStr=$phpExeFile;
if(IS_WIN){
$commandStr='"'.$commandStr.'"';
}
$cliUser=strtolower($GLOBALS['_sc']['user']['username']);
$cliUser=$cliUser.'_'.md5($cliUser.$GLOBALS['_sc']['user']['password']);
$paramStr.=' --cli_user '.base64_encode($cliUser);
$commandStr.=' '.config('root_path').DIRECTORY_SEPARATOR.'caiji '.$paramStr;
$descriptorspec = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
);
$pipes=array();
$handle=proc_open($commandStr,$descriptorspec,$pipes);
$hdStatus=proc_get_status($handle);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
if(!empty($commandStr)){
$commandStr=\skycaiji\admin\model\Config::cli_safe_filename($commandStr);
$cliUser=intval(g_sc('user','uid')).'_'.model('User')->generate_key(g_sc('user'));
$paramStr.=' --cli_user '.base64_encode($cliUser);
$commandStr.=' '.config('root_path').DIRECTORY_SEPARATOR.'caiji '.$paramStr;
if(session_status()!==PHP_SESSION_ACTIVE){
session_start();
}
session_write_close();
proc_open_exec($commandStr,false);
}
exit();
}
function is_official_url($url){
if(preg_match('/skycaiji\.com/i', $url)){
return true;
}else{
return false;
}
function proc_open_exec($commandStr,$returnInfo=false,$timeout=10,$closeProc=false){
$info=array('status'=>'','output'=>'','error'=>'');
$timeout=intval($timeout);
if($timeout<=0){
$timeout=10;
}
if(!empty($commandStr)){
$descriptorspec = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
);
$pipes=array();
$otherOptions=IS_WIN?array('suppress_errors'=>true,'bypass_shell'=>true):array();
$handle=proc_open($commandStr,$descriptorspec,$pipes,null,null,$otherOptions);
if($returnInfo){
if(!is_resource($handle)){
$info['error']='命令执行失败,请检查可执行文件是否存在,以及'.\util\Funcs::web_server_name().'服务器的用户权限';
}else{
$returnInfo=$returnInfo=='all'?array('status','output','error'):explode(',',$returnInfo);
$nowtime=time();
if(in_array('status',$returnInfo)){
$info['status']=proc_get_status($handle);
}
if(in_array('output',$returnInfo)){
if(function_exists('stream_set_blocking')){
stream_set_blocking($pipes[1],false);
}
if(function_exists('stream_set_timeout')){
stream_set_timeout($pipes[1],$timeout);
}
while(is_resource($pipes[1])&&!feof($pipes[1])){
$info['output'].=fgets($pipes[1]);
if((time()-$nowtime)>$timeout){
break;
}
}
}
$nowtime=time();
if(in_array('error',$returnInfo)){
if(function_exists('stream_set_blocking')){
stream_set_blocking($pipes[2],false);
}
if(function_exists('stream_set_timeout')){
stream_set_timeout($pipes[2],$timeout);
}
while(is_resource($pipes[2])&&!feof($pipes[2])){
$info['error'].=fgets($pipes[2]);
if((time()-$nowtime)>$timeout){
break;
}
}
}
foreach (array('output','error') as $key){
if(!empty($info[$key])){
$encode=mb_detect_encoding($info[$key], array('ASCII','UTF-8','GB2312','GBK','BIG5'));
if($encode!='UTF-8'){
$info[$key] = iconv ( $encode, 'utf-8//IGNORE', $info[$key] );
}
}
}
}
}
if(is_resource($pipes[0])){
fclose($pipes[0]);
}
if(is_resource($pipes[1])){
fclose($pipes[1]);
}
if(is_resource($pipes[2])){
fclose($pipes[2]);
}
if($closeProc&&is_resource($handle)){
proc_terminate($handle);
proc_close($handle);
}
}
return $info;
}
function convert_html2json($html,$returnStr=false){
static $jsonpRegExp='/^(\s*[\$\w\-]+\s*[\{\(])+(?P<json>[\s\S]+)(?P<end>[\}\]])\s*\)\s*[\;]{0,1}/i';
$json=json_decode($html,true);
if(!empty($json)){
if($returnStr){
$json=$html;
}
}elseif(preg_match($jsonpRegExp,$html,$json)){
$json=trim($json['json']).$json['end'];
if(!$returnStr){
$json=json_decode($json,true);
}
}
return $json?$json:null;
function trim_input_array($arrName){
if(empty($arrName)){
return null;
}
$data=input($arrName.'/a',array(),'trim');
$data=\util\Funcs::array_array_map('trim', $data);
return $data;
}
function curl_skycaiji($uri,$headers=null,$options=array(),$postData=null,$returnInfo=false){
$url='://www.skycaiji.com'.$uri;
$info=get_html('https'.$url,$headers,$options,'utf-8',$postData,true);
$info=is_array($info)?$info:array();
if(empty($info['ok'])){
$info=get_html('http'.$url,$headers,$options,'utf-8',$postData,true);
$info=is_array($info)?$info:array();
}
return $returnInfo?$info:$info['html'];
}
function array_filter_keep0($list){
if(is_array($list)){
foreach ($list as $k=>$v){
if(empty($v)&&$v!==0&&$v!=='0'){
unset($list[$k]);
}
}
}
return $list;
}
function strip_phpcode_comment($code){
if($code){
$tokens=token_get_all($code);
$newCode='';
foreach ($tokens as $key=>$token){
if (!is_array($token)){
$newCode.=$token;
}else{
if($token[0]==T_COMMENT||$token[0]==T_DOC_COMMENT){
if(preg_match('/[\r\n]+$/', $token[1])){
$newCode.=PHP_EOL;
}
}else{
$newCode.=$token[1];
}
}
}
$code=$newCode;
}
return $code;
function curl_store($providerUrl,$uri,$headers=null,$options=array(),$postData=null){
$html=null;
if(empty($providerUrl)){
$html=curl_skycaiji($uri,$headers,$options,$postData);
}else{
$html=get_html($providerUrl.$uri,$headers,$options,'utf-8',$postData);
}
return $html;
}

View File

@ -15,7 +15,7 @@ use skycaiji\admin\model\CacheModel;
class Api extends BaseController{
/*任务api发布*/
public function taskAction(){
define('CLOSE_ECHO_MSG', 1);
define('CLOSE_ECHO_MSG', true);
$taskId=input('id/d',0);
$apiurl=input('apiurl');
$releData=model('Release')->where(array('task_id'=>$taskId))->find();
@ -23,74 +23,137 @@ class Api extends BaseController{
if($apiurl!=$releData['config']['api']['url']){
exit('api地址错误');
}
define('API_TASK_RESPONSE_JSON', true);
header('Content-type:text/json');
controller('admin/Task','controller')->_collect($taskId);
}
/*执行采集*/
public function collectAction(){
if(input('?backstage')){
if(!IS_CLI){
ignore_user_abort(true);
if($GLOBALS['_sc']['c']['caiji']['server']=='cli'){
cli_command_exec('collect auto');
exit();
}
}
}
if(!input('?backstage')){
config('dispatch_error_tmpl','common:error');
config('dispatch_success_tmpl','common:success');
}
$this->_backstage_cli_collect('auto');
define('IS_COLLECTING', 1);
$mcache=CacheModel::getInstance();
$autoCacheData=$mcache->getCache('auto_collecting');
if($autoCacheData){
if((time()-intval($autoCacheData['dateline']))>60*($GLOBALS['_sc']['c']['caiji']['interval']+15)){
$autoInterval=time()-intval($autoCacheData['dateline']);
if($autoInterval<=60*(g_sc('c_caiji_interval')+10)){
}else{
$this->error('有任务正在自动采集');
$this->echo_msg_exit('有任务正在自动采集');
}
}
$mcache->setCache('auto_collecting',1);
register_shutdown_function('remove_auto_collecting');
if(input('?backstage')||!session('user_id')){
define('CLOSE_ECHO_MSG', true);
}
ignore_user_abort(true);
if($GLOBALS['_sc']['c']['caiji']['timeout']>0){
set_time_limit(60*$GLOBALS['_sc']['c']['caiji']['timeout']);
if(g_sc_c('caiji','timeout')>0){
set_time_limit(60*g_sc_c('caiji','timeout'));
}else{
set_time_limit(0);
}
if(empty($GLOBALS['_sc']['c']['caiji']['auto'])){
$this->error('请先开启自动采集','Admin/Setting/caiji');
if(is_empty(g_sc_c('caiji','auto'))){
$this->echo_msg_exit('请先开启自动采集 <a href="'.url('Admin/Setting/caiji').'" target="_blank">设置</a>');
}
$lastCollectTime=cache('last_collect_time');
if($GLOBALS['_sc']['c']['caiji']['interval']>0){
$waitTime=(60*$GLOBALS['_sc']['c']['caiji']['interval'])-abs(time()-$lastCollectTime);
if($waitTime>0){
$this->error('再次采集需等待'.(($waitTime<60)?($waitTime.'秒'):(sprintf("%.2f", $waitTime/60).'分钟')),'Admin/Api/collect',null,$waitTime);
}
$checkCollectWait=\skycaiji\admin\model\Config::check_collect_wait();
if($checkCollectWait){
$this->echo_msg_exit($checkCollectWait['msg'].' <a href="'.url('Admin/Setting/caiji').'" target="_blank">设置运行间隔</a>');
}
$mtask=model('Task');
$taskList=$mtask->alias('t')->join(model('Collector')->get_table_name().' c','t.id=c.task_id')
->field('t.*')->where("t.auto=1 and t.module='pattern'")->order('t.caijitime asc')->select();
if(empty($taskList)){
$this->error('没有可自动采集的任务');
$taskIds=$mtask->alias('t')->join(model('Collector')->get_table_name().' c','t.id=c.task_id')
->field('task_id')->where("t.auto=1 and t.module='pattern'")->order('t.caijitime asc')->column('task_id');
if(empty($taskIds)){
$this->echo_msg_exit('没有可自动采集的任务 <a href="'.url('Admin/Task/list').'" target="_blank">设置</a>');
}
$taskList=collection($taskList)->toArray();
cache('last_collect_time',time());
controller('admin/Task','controller')->_collect_batch($taskList);
controller('admin/Task','controller')->_collect_batch($taskIds);
$this->echo_msg('所有任务执行完毕!','green');
$this->_echo_msg_end();
}
/*客户端信息*/
public function clientinfoAction(){
return json(clientinfo());
}
/*验证站点*/
public function certificateAction(){
$data=array('code'=>0,'msg'=>'','data'=>array());
$mprov=model('Provider');
$resultData=$mprov->storeAuthResult();
if(!$resultData['success']){
$data['msg']=$resultData['msg'];
}else{
$data['code']=1;
$data['data']['clientinfo']=clientinfo();
}
return json($data);
}
/*云平台检测更新*/
public function store_updateAction(){
$updateResult=array('code'=>0,'msg'=>'','data'=>array());
$mprov=model('Provider');
$resultData=$mprov->storeAuthResult();
if(!$resultData['success']){
$updateResult['msg']=$resultData['msg'];
}else{
$resultData=$resultData['data'];
$provId=$resultData['provider_id'];
$storeAddons=input('store_addons');
$storeAddons=json_decode(base64_decode($storeAddons),true);
$storeAddons=is_array($storeAddons)?$storeAddons:array();
if(!empty($storeAddons['rule'])&&is_array($storeAddons['rule'])){
$cond=array('store_id'=>array('in',$storeAddons['rule']),'provider_id'=>$provId);
$list=model('Rule')->field('`id`,`store_id`,`uptime`')->where($cond)->column('uptime','store_id');
$updateResult['data']['rule']=$list;
}
if(!empty($storeAddons['plugin'])&&is_array($storeAddons['plugin'])){
$cond=array('app'=>array('in',$storeAddons['plugin']),'provider_id'=>$provId);
$listRelease=model('ReleaseApp')->where($cond)->column('uptime','app');
$listRelease=is_array($listRelease)?$listRelease:array();
$listFunc=model('FuncApp')->where($cond)->column('uptime','app');
$listFunc=is_array($listFunc)?$listFunc:array();
$updateResult['data']['plugin']=array_merge($listRelease,$listFunc);
}
if(!empty($storeAddons['app'])&&is_array($storeAddons['app'])){
$list=array();
foreach ($storeAddons['app'] as $app){
$appVer=model('App')->app_class($app,false,'version');
if(!empty($appVer)){
$list[$app]=$appVer;
}
}
$updateResult['data']['app']=$list;
}
$updateResult['code']=1;
}
return json($updateResult);
}
}

View File

@ -27,28 +27,18 @@ class App extends BaseController {
$navPacks=array();
if(is_array($appData['config']['packs'])){
$manageUrl=url('App/manage?app='.$app);
$manageUrl.=strpos($manageUrl,'?')===false?'?':'&';
foreach ($appData['config']['packs'] as $k=>$v){
if($v['type']=='nav'){
$v['nav_link']=str_replace(array('{app}','{apps}'), array(config('root_website').'/app/'.$app.'/',config('root_website').'/app/'),$v['nav_link']);
if(!preg_match('/^\w+\:\/\//', $v['nav_link'])){
$v['nav_link']=$appUrl.$v['nav_link'];
}
if(isset($navid)&&$navid==$k){
$v['is_current']=true;
}
$navPacks[$k]=$v;
}
}
$navPacks=$mapp->convert_packs($appData['config']['packs'],$app,'nav',$navid);
}
$storeUrl='';
$provData=null;
$mprov=model('Provider');
if($appData['provider_id']>0){
$provData=$mprov->where('id',$appData['provider_id'])->find();
$storeUrl=$provData?$provData['url']:'';
}
if(empty($storeUrl)&&\skycaiji\admin\model\Provider::is_official_url($appData['config']['website'])){
$storeUrl=1;
}
$appClass=$mapp->app_class($app);
@ -66,7 +56,7 @@ class App extends BaseController {
$this->assign('navid',$navid);
$this->assign('navPacks',$navPacks);
$this->assign('appData',$appData);
$this->assign('provData',$provData);
$this->assign('storeUrl',$storeUrl);
return $this->fetch();
}
/*协议*/

View File

@ -30,7 +30,7 @@ class Backstage extends BaseController{
'os'=>php_uname('s').' '.php_uname('r'),
'php'=>PHP_VERSION,
'db'=>config('database.type'),
'version'=>$GLOBALS['_sc']['c']['version']?$GLOBALS['_sc']['c']['version']:constant("SKYCAIJI_VERSION"),
'version'=>g_sc_c('version')?g_sc_c('version'):constant("SKYCAIJI_VERSION"),
'server'=>$_SERVER["SERVER_SOFTWARE"],
'upload_max'=>ini_get('upload_max_filesize')
);
@ -42,33 +42,35 @@ class Backstage extends BaseController{
$runInfo['auto_status']='良好';
/*设置采集状态*/
if($GLOBALS['_sc']['c']['caiji']['auto']){
if(g_sc_c('caiji','auto')){
$lastTime=cache('last_collect_time');
$taskAutoCount=model('Task')->where('auto',1)->count();
if($taskAutoCount<=0){
$autoTaskCount=model('Task')->where('auto',1)->count();
if($autoTaskCount<=0){
$serverData['caiji']='<a href="'.url('Admin/Task/list').'">未设置自动采集任务</a>';
$runInfo['auto_status']='无任务';
}else{
$runInfo['auto_status']='运行良好';
if($lastTime>0){
$runInfo['auto_status']='运行良好';
$serverData['caiji']='最近采集:'.date('Y-m-d H:i:s',$lastTime).' &nbsp;';
if($GLOBALS['_sc']['c']['caiji']['run']=='backstage'){
if(NOW_TIME-$lastTime>60*($GLOBALS['_sc']['c']['caiji']['interval']+15)){
$serverData['caiji'].='<p class="help-block">自动采集似乎停止了,请<a href="'.
url('Admin/Setting/caiji').'">重新保存设置</a>以便激活采集</p>';
$runInfo['auto_status']='停止运行';
}
}
$serverData['caiji']='最近采集:'.date('Y-m-d H:i:s',$lastTime).' &nbsp;';
}
if(g_sc_c('caiji','run')=='backstage'){
$collectBackstageTime=CacheModel::getInstance()->getCache('collect_backstage_time','data');
$collectBackstageTime=intval($collectBackstageTime);
if((time()-$collectBackstageTime)>60*3){
$runInfo['auto_status']='停止运行';
$serverData['caiji'].='<p class="help-block">自动采集停止了,请重新<a href="'.url('Admin/Setting/caiji').'">保存设置</a>以便激活采集</p>';
}
}
$serverData['caiji'].='<a href="javascript:;" id="a_collect_now">实时采集</a>';
}
}else{
$runInfo['auto_status']='已停止';
$runInfo['auto_status']='未开启';
$serverData['caiji']='<a href="'.url('Admin/Setting/caiji').'">未开启自动采集</a>';
}
@ -82,14 +84,29 @@ class Backstage extends BaseController{
$systemData=$LocSystem->environment();
$systemWarning=array('php'=>array(),'path_write'=>array(),'path_read'=>array());
if(is_array($systemData['php'])){
foreach ($systemData['php'] as $k=>$v){
if(empty($v[1])){
if(empty($v['loaded'])){
$systemWarning['php'][$v[0]]=$v[0];
$systemWarning['php'][$v['name']]=$v['name'];
}elseif(!empty($v['lack'])){
$systemWarning['php'][$v['name']]=$v['name'].' (需支持'.$v['lack'].')';
}
}
}
if(model('Config')->server_is_cli()||g_sc_c('page_render','tool')){
$procFuncs=array('proc_open','proc_get_status','proc_terminate','proc_close');
foreach ($procFuncs as $procFunc){
if(!function_exists($procFunc)){
$systemWarning['php'][$procFunc]=$procFunc;
}
}
}
if(is_array($systemData['path'])){
foreach ($systemData['path'] as $k=>$v){
if(empty($v[1])){
@ -114,36 +131,113 @@ class Backstage extends BaseController{
}
$adminIndexData=cache('backstage_admin_index');
$timeout=NOW_TIME-(3600*24*30);
$timeout=time()-(3600*24*30);
$mcacheSource=CacheModel::getInstance('source_url');
$mcacheSource->db()->where('dateline','<',$timeout)->delete();
$mcacheLevel=CacheModel::getInstance('level_url');
$mcacheLevel->db()->where('dateline','<',$timeout)->delete();
$timeout=NOW_TIME-(3600*24);
$timeout=time()-(3600*24);
$mcacheCont=CacheModel::getInstance('cont_url');
$mcacheCont->db()->where('dateline','<',$timeout)->delete();
$GLOBALS['_sc']['p_name']='后台管理';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Backstage/index'),'title'=>'首页')));
$openBasedir=null;
if(!cache('ignore_open_basedir_tips')){
$openBasedir=ini_get('open_basedir');
if(!empty($openBasedir)){
$openBasedir=explode(IS_WIN?';':':', $openBasedir);
$openBasedir=implode('、', $openBasedir);
}
}
set_g_sc('p_name','后台管理');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Backstage/index'),'title'=>'首页'))));
$this->assign('runInfo',$runInfo);
$this->assign('serverData',$serverData);
$this->assign('upgradeDb',$upgradeDb);
$this->assign('systemWarning',$systemWarning);
$this->assign('adminIndexData',$adminIndexData);
$this->assign('openBasedir',$openBasedir);
return $this->fetch('backstage/index');
}
public function checkUpAction(){
$info=array(
'pageRenderInvalid'=>false,
'phpInvalid'=>false,
);
$mconfig=model('Config');
if($mconfig->server_is_cli()){
$phpvInfo=$mconfig->exec_php_version(g_sc_c('caiji','server_php'));
if(empty($phpvInfo)||!$phpvInfo['success']){
$info['phpInvalid']=true;
}
}
$autoTaskIds=model('Task')->where('auto',1)->column('id');
if(!empty($autoTaskIds)){
foreach ($autoTaskIds as $autoTaskId){
$collConfig=model('Collector')->where('task_id',$autoTaskId)->value('config');
$collConfig=unserialize($collConfig);
if($collConfig['page_render']){
$pageRender=g_sc_c('page_render');
if(empty($pageRender['tool'])){
$info['pageRenderInvalid']=true;
}elseif($mconfig->page_render_is_chrome()){
$chromeSoket=new \util\ChromeSocket($pageRender['chrome']['host'],$pageRender['chrome']['port'],$pageRender['timeout'],$pageRender['chrome']['filename'],$pageRender['chrome']);
$info['pageRenderInvalid']=$chromeSoket->hostIsOpen()?false:true;
}
break;
}
}
}
$this->success('','',$info);
}
/*实时采集*/
public function collectAction(){
remove_auto_collecting();
controller('admin/Api','controller')->collectAction();
}
/*检测更新*/
public function newVersionAction(){
$version=curl_skycaiji('/client/info/version?v='.SKYCAIJI_VERSION);
$version=json_decode($version,true);
$version=is_array($version)?$version:array();
$new_version=trim($version['new_version']);
$cur_version=g_sc_c('version');
if(version_compare($new_version,$cur_version,'>')){
$version['is_new_version']=true;
}
$cacheIx=cache('backstage_admin_index');
if(empty($cacheIx)||$cacheIx['ver']!=$version['admin_index_ver']){
$version['is_new_admin_index']=true;
}
$this->success('',null,$version);
}
/*获取推送消息*/
public function adminIndexAction(){
$refresh=input('refresh');
@ -151,8 +245,9 @@ class Backstage extends BaseController{
$data=is_array($data)?$data:array();
if($refresh||empty($data['html'])){
$data=get_html('https://www.skycaiji.com/store/client/adminIndex?v='.SKYCAIJI_VERSION,null,null,'utf-8');
$data=curl_skycaiji('/client/info/push?v='.SKYCAIJI_VERSION);
$data=json_decode($data,true);
$data=is_array($data)?$data:array();
$data=array(
'ver'=>$data['ver'],
@ -230,8 +325,10 @@ class Backstage extends BaseController{
}
}
}
$count=$mcache->db()->where('ctype',$taskType)->count();
$count0=$mcache->db()->where('ctype',0)->count();
$count1=$mcache->db()->where('ctype',1)->count();
$this->assign('list',$list);
$this->assign('cacheList',$cacheList);
@ -239,7 +336,7 @@ class Backstage extends BaseController{
$this->assign('pagenav',$pagenav);
$html=$this->fetch('bk_task_list')->getContent();
$this->success('',null,array('html'=>$html,'count'=>$count));
$this->success('',null,array('html'=>$html,'count0'=>$count0,'count1'=>$count1));
}elseif('collected'==$op){
$taskId=input('tid/d');
if($taskId<=0){
@ -274,6 +371,12 @@ class Backstage extends BaseController{
}
public function ignoreOpenBasedirAction(){
cache('ignore_open_basedir_tips',1);
$this->success();
}
public function createJsLangAction(){
$langs=array();
$langs['zh-cn']='zh-cn';
@ -291,12 +394,13 @@ class Backstage extends BaseController{
$tpl_lang=array_merge($common_lang,$module_lang);
$tpl_lang='var tpl_lang='.json_encode($tpl_lang).';';
write_dir_file(config('root_path').'/public/static/js/langs/'.$lv.'.js',$tpl_lang);
echo "ok{$lv}<br>";
echo "ok:{$lv}<br>";
}
}
/* 排查重复的语言变量 */
public function checkRepeatLangAction() {
$file = config ( 'app_path' ) . '/admin/lang/zh-cn.php';
$txt = file_get_contents ( $file );
@ -311,5 +415,4 @@ class Backstage extends BaseController{
}
print_r ( $repeatList );
}
}

View File

@ -12,6 +12,17 @@
namespace skycaiji\admin\controller;
class BaseController extends \skycaiji\common\controller\BaseController{
protected function _initialize(){
if(request()->isPost()){
$curController=strtolower(request()->controller());
if($curController!='api'){
$this->check_usertoken();
}
}
}
/*输出模板防止ajax时乱码*/
public function fetch($template = '', $vars = [], $replace = [], $config = []){
if(request()->isAjax()){
@ -24,60 +35,179 @@ class BaseController extends \skycaiji\common\controller\BaseController{
/*输出内容函数*/
private static $echo_msg_head=null;
public function echo_msg($str,$color='red',$echo=true,$end_str=''){
public function echo_msg($str,$color='red',$echo=true,$end_str='',$div_style=''){
if(defined('CLOSE_ECHO_MSG')){
$echo=false;
}
if($echo){
$color=empty($color)?'red':$color;
$isBackstage=input('?backstage');
$logid=input('logid','');
$logFilename=\skycaiji\admin\model\Collector::echo_msg_log_filename($logid);
$differSeconds=input('differ_seconds/d',0);
if(!isset(self::$echo_msg_head)){
self::$echo_msg_head=true;
header('Content-type: text/html; charset=utf-8');
header('X-Accel-Buffering: no');
@ini_set('output_buffering','Off');
ob_end_clean();
@ob_implicit_flush(1);
$outputSize=ini_get('output_buffering');
$outputSize=intval($outputSize);
if(preg_match('/\biis\b/i', $_SERVER["SERVER_SOFTWARE"])){
if($outputSize<1024*1024*4){
$outputSize=1024*1024*4;
echo '<!-- iis默认需输出4mb数据才能实时显示-->';
}
if(file_exists($logFilename)){
unlink($logFilename);
}
echo '<style type="text/css">body{padding:0 5px;font-size:14px;color:#000;}p{padding:0;margin:0;}a{color:#aaa;}</style>';
$allowOutput=false;
if($outputSize>1024*1024){
$mobileDetect=new \util\MobileDetect();
if(!$mobileDetect->isMobile()){
$allowOutput=true;
}
}else{
$allowOutput=true;
if(!file_exists($logFilename)){
write_dir_file($logFilename,'');
}
if($allowOutput){
echo str_pad(' ', $outputSize>1050?($outputSize+100):1050);
try {
register_shutdown_function(array($this,'_echo_msg_end'));
}catch (\Exception $ex){}
if(!$isBackstage){
header('Content-type: text/html; charset=utf-8');
header('X-Accel-Buffering: no');
@ini_set('output_buffering','Off');
@ob_end_clean();
@ob_implicit_flush(1);
$outputSize=ini_get('output_buffering');
$outputSize=intval($outputSize);
if(preg_match('/\biis\b/i', $_SERVER["SERVER_SOFTWARE"])){
if($outputSize<1024*1024*4){
$outputSize=1024*1024*4;
echo '<!-- iis默认需输出4mb数据才能实时显示-->';
}
}
}
$info=array(
'js_time'=>time()-$differSeconds,
'server'=>\util\Funcs::web_server_name(),
'is_backstage'=>$isBackstage,
'server_is_cli'=>model('Config')->server_is_cli(),
);
$info=json_encode($info);
$cssJs='<style type="text/css">'
.'body{padding:0 5px;font-size:14px;color:#000;line-height:20px;}p{padding:0;margin:0;}a{color:#aaa;}'
.'.clear{width:100%;overflow:hidden;clear:both;}.left{float:left;}'
.'.lurl{float:left;margin-right:3px;height:20px;max-width:70%;overflow:hidden;text-overflow:ellipsis;word-wrap:break-word;word-break:break-all;}'
.'</style>'
.'<script type="text/javascript">window.parent.window.collectorEchoMsg("start",'.$info.');</script>';
$this->_echo_msg_output($cssJs, $logFilename);
if(!$isBackstage){
$allowOutput=false;
if($outputSize>1024*1024){
$mobileDetect=new \util\MobileDetect();
if(!$mobileDetect->isMobile()){
$allowOutput=true;
}
}else{
$allowOutput=true;
}
if($allowOutput){
if($outputSize<1024*100){
echo str_pad(' ', $outputSize>1050?($outputSize+100):1050);
}
}
}
}
echo '<p style="color:'.$color.';">'.$str.'</p>'.$end_str;
if(ob_get_level()>0){
ob_flush();
flush();
$txt='<div style="color:'.$color.';'.$div_style.'">'.$str.'</div>'.$end_str;
$this->_echo_msg_output($txt, $logFilename);
if(!$isBackstage){
if(ob_get_level()>0){
ob_flush();
flush();
}
}
}
}
/*保留旧的入口*/
public function indexAction(){
if(strtolower(request()->controller())=='base'){
$this->redirect('Admin/Backstage/index');
}
public function echo_msg_exit($str,$color='red',$echo=true,$end_str='',$div_style=''){
$this->echo_msg($str,$color,$echo,$end_str,$div_style);
exit();
}
private static $echo_msg_end=null;
public function _echo_msg_end(){
if(!isset(self::$echo_msg_end)){
self::$echo_msg_end=true;
$this->echo_msg('','',true,\skycaiji\admin\model\Collector::echo_msg_end_js(),'display:none;');
}
}
private function _echo_msg_output($txt,$logFilename){
$isBackstage=input('?backstage');
if(!file_exists($logFilename)){
if(!$isBackstage){
echo \skycaiji\admin\model\Collector::echo_msg_end_js();
}
exit();
}
if($isBackstage){
write_dir_file($logFilename,$txt.PHP_EOL,FILE_APPEND);
}else{
echo $txt;
}
}
protected function _backstage_cli_collect($cliStr){
if(input('?backstage')){
$logid=input('logid','');
ignore_user_abort(true);
if(empty($logid)){
define('CLOSE_ECHO_MSG',true);
}
if(!IS_CLI){
if(model('admin/Config')->server_is_cli()){
if(!empty($logid)){
$cliStr.=' --logid '.base64_encode($logid);
}
cli_command_exec('collect '.$cliStr);
exit();
}
}
}else{
ignore_user_abort(false);
$sUserlogin=session('user_login');
if(empty($sUserlogin)){
define('CLOSE_ECHO_MSG',true);
}
}
}
public function check_usertoken(){
if(g_sc('usertoken')!=input('_usertoken_')){
$this->error(lang('usertoken_error'),'');
}
}
}

View File

@ -76,8 +76,10 @@ class Collected extends BaseController {
$taskList=model('Task')->where(array('id'=>array('in',$taskIds)))->column('name','id');
}
}
$GLOBALS['_sc']['p_name']=lang('collected_list');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Collected/list'),'title'=>'已采集数据'),array('url'=>url('Collected/list'),'title'=>'数据列表')));
set_g_sc('p_title',lang('collected_list'));
set_g_sc('p_name',lang('collected_list'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Collected/list'),'title'=>'已采集数据'),array('url'=>url('Collected/list'),'title'=>'数据列表'))));
}
$this->assign('search',$search);
$this->assign('dataList',$dataList);
@ -115,7 +117,7 @@ class Collected extends BaseController {
$this->success(lang('delete_success'));
}elseif($op=='deleteall'){
$ids=input('ids/a',0,'intval');
$ids=input('ids/a',array(),'intval');
if(is_array($ids)&&count($ids)>0){
$mcollected->where(array('id'=>array('in',$ids)))->delete();
}
@ -124,8 +126,9 @@ class Collected extends BaseController {
}
/*图表显示*/
public function chartAction(){
$GLOBALS['_sc']['p_name']='已采集数据:统计图表';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Collected/list'),'title'=>'已采集数据'),array('url'=>url('Collected/chart'),'title'=>'统计图表')));
set_g_sc('p_title','已采集数据:统计图表');
set_g_sc('p_name','已采集数据:统计图表');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Collected/list'),'title'=>'已采集数据'),array('url'=>url('Collected/chart'),'title'=>'统计图表'))));
return $this->fetch();
}

View File

@ -10,6 +10,8 @@
*/
namespace skycaiji\admin\controller;
use skycaiji\admin\model\CacheModel;
use skycaiji\admin\model\FuncApp;
class Collector extends BaseController {
public function indexAction(){
@ -33,7 +35,8 @@ class Collector extends BaseController {
}
$collData=$mcoll->where(array('task_id'=>$taskData['id'],'module'=>$taskData['module']))->find();
if(request()->isPost()){
$effective=input('effective');
$effective=input('effective');
$effectiveEdit=input('effective_edit');
if(empty($effective)){
$this->error(lang('coll_error_empty_effective'));
@ -44,18 +47,24 @@ class Collector extends BaseController {
if(!in_array($module,config('allow_coll_modules'))){
$this->error(lang('coll_error_invalid_module'));
}
$config=input('post.config/a',null,'trim');
$config=array_array_map('trim',$config);
$config=input('post.config/a',array(),'trim');
$config=\util\Funcs::array_array_map('trim',$config);
$acoll=controller('admin/C'.$module,'event');
$config=$acoll->setConfig($config);
$newColl=array('name'=>$name,'module'=>$module,'task_id'=>$taskId,'config'=>serialize($config),'uptime'=>NOW_TIME);
$collId=$collData['id'];
$newColl=array('name'=>$name,'module'=>$module,'task_id'=>$taskId,'config'=>serialize($config),'uptime'=>time());
$collId=0;
if(empty($collData)){
$collId=$mcoll->add_new($newColl);
}else{
$collId=$collData['id'];
if(empty($effectiveEdit)){
$this->error(lang('coll_error_empty_effective'));
}
$mcoll->edit_by_id($collId,$newColl);
}
if($collId>0){
@ -67,15 +76,22 @@ class Collector extends BaseController {
}else{
if(!empty($collData)){
$collData['config']=unserialize($collData['config']);
if(!is_array($collData['config'])){
$collData['config']=array();
}
$collData['config']=$mcoll->compatible_config($collData['config']);
}else{
$collData=array();
}
$GLOBALS['_sc']['p_name']=lang('coll_set').lang('separator').lang('task_module_'.$taskData['module']);
set_g_sc('p_title',lang('coll_set').'_任务:'.$taskData['name']);
set_g_sc('p_name',lang('coll_set').lang('separator').lang('task_module_'.$taskData['module']));
if(input('?easymode')){
$GLOBALS['_sc']['p_name'].=' <small><a href="'.url('Collector/set?task_id='.$taskId).'" onclick="if(window.top){window.top.location.href=$(this).attr(\'href\');return false;}">普通模式</a></small>';
set_g_sc('p_name', g_sc('p_name').' <small><a href="'.url('Collector/set?task_id='.$taskId).'" onclick="if(window.top){window.top.location.href=$(this).attr(\'href\');return false;}" title="切换普通模式">普通模式</a></small>');
}else{
$GLOBALS['_sc']['p_name'].=' <small><a href="'.url('Cpattern/easymode?task_id='.$taskId).'">简单模式</a></small>';
set_g_sc('p_name', g_sc('p_name').' <small><a href="'.url('Cpattern/easymode?task_id='.$taskId).'" title="切换简单模式">简单模式</a></small>');
}
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Task/edit?id='.$taskData['id']),'title'=>lang('task').lang('separator').$taskData['name']),array('url'=>url('Collector/set?task_id='.$taskData['id']),'title'=>lang('coll_set'))));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Task/edit?id='.$taskData['id']),'title'=>lang('task').lang('separator').$taskData['name']),array('url'=>url('Collector/set?task_id='.$taskData['id']),'title'=>lang('coll_set')))));
$this->assign('collData',$collData);
$this->assign('taskData',$taskData);
return $this->fetch();
@ -116,31 +132,6 @@ class Collector extends BaseController {
$this->assign('collList',$collList);
return $this->fetch('list'.(input('tpl')?'_'.input('tpl'):''));
}
/*保存到云端*/
public function save2storeAction(){
$coll_id=input('coll_id/d',0);
$mcoll=model('Collector');
$collData=$mcoll->where(array('id'=>$coll_id))->find();
if(empty($collData)){
$this->error(lang('coll_error_empty_coll'));
}
$collData=$collData->toArray();
if(!in_array($collData['module'],config('allow_coll_modules'))){
$this->error(lang('coll_error_invalid_module'));
}
$config=unserialize($collData['config']);
if(empty($config)){
$this->error('规则不存在');
}
if(empty($config['source_url'])){
$this->error('请先完善起始页网址!');
}
if(empty($config['field_list'])){
$this->error('请先完善字段列表!');
}
$this->assign('collData',$collData);
return $this->fetch();
}
/*导出规则*/
public function exportAction(){
$coll_id=input('coll_id/d',0);
@ -175,11 +166,178 @@ class Collector extends BaseController {
header("Content-transfer-encoding: binary");
header("Accept-Length: " .mb_strlen($txt));
if (preg_match("/MSIE/i", $_SERVER["HTTP_USER_AGENT"])) {
header('Content-Disposition: attachment; filename="'.urlencode($name).'.skycaiji"');
header('Content-Disposition: attachment; filename="'.urlencode($name).'.scj"');
}else{
header('Content-Disposition: attachment; filename="'.$name.'.skycaiji"');
header('Content-Disposition: attachment; filename="'.$name.'.scj"');
}
echo $txt;
ob_end_flush();
}
public function echo_msgAction(){
$op=input('op');
$mcache=CacheModel::getInstance();
$cBackstageName='echo_msg_backstage';
$cIntervalName='echo_msg_interval';
if($op=='set_backstage'){
$isBackstage=input('backstage/d',0);
$isBackstage=$isBackstage>0?1:0;
$mcache->setCache($cBackstageName,$isBackstage);
if(model('Config')->server_is_cli()){
$isBackstage=$isBackstage?'cli后台':'web服务器';
}else{
$isBackstage=$isBackstage?'后台':'实时';
}
$this->success('已设置为'.$isBackstage.'模式,请重试采集','');
}elseif($op=='set_interval'){
$interval=input('interval/d',2);
$mcache->setCache($cIntervalName,$interval);
$this->success('设置成功','');
}elseif($op=='collect'){
$jsTime=input('js_time',0);
$jsTime=substr($jsTime,0,-3);
$jsTime=intval($jsTime);
$differSeconds=time()-$jsTime;
$isBackstage=$mcache->getCache($cBackstageName,'data');
$interval=$mcache->getCache($cIntervalName,'data');
$interval=intval($interval);
if($interval<=0){
$interval=2;
}
$this->assign('is_backstage',$isBackstage);
$this->assign('interval',$interval);
$this->assign('server_is_cli',model('Config')->server_is_cli());
$this->assign('differ_seconds',$differSeconds);
return $this->fetch('echo_msg_collect');
}elseif($op=='read'){
$list=array();
$logid=input('logid','');
$line=input('line/d');
$line=empty($line)?0:($line+1);
$filename=\skycaiji\admin\model\Collector::echo_msg_log_filename($logid);
if(file_exists($filename)){
$max=30;
$num=0;
if(class_exists('SplFileObject')){
$sfo = new \SplFileObject($filename, 'r');
if($sfo->seek($line)==0){
while (!$sfo->eof()&&$num<$max) {
$txt=$sfo->current();
$list[$sfo->key()]=$txt;
$sfo->next();
$num++;
}
}
$sfo=null;
unset($sfo);
}else{
$fp = fopen($filename,'r');
while (!feof($fp)&&$num<$max) {
$txt=fgets($fp);
if($num>=$line){
$list[$num]=$txt;
}
$num++;
}
fclose($fp);
unset($fp);
}
$isEnd=false;
foreach ($list as $k=>$txt){
if(!$isEnd&&strpos($txt,'data-echo-msg-is-end')!==false){
$isEnd=true;
}
$txt=preg_replace('/<[^<>]*\bsection\b[^<>]*>/i', '', $txt);
$list[$k]=$txt;
}
if($isEnd){
if(file_exists($filename)){
unlink($filename);
}
}
}elseif($line>0){
$list[$line]=\skycaiji\admin\model\Collector::echo_msg_end_js();
}
$list=array_filter($list);
$data=array('list'=>$list,'line'=>0);
if(!empty($list)){
$data['line']=max(array_keys($list));
$data['line']=intval($data['line']);
if($data['line']<0){
$data['line']=0;
}
}
$this->success('','',$data);
}elseif($op=='stop'){
$logid=input('logid','');
$filename=\skycaiji\admin\model\Collector::echo_msg_log_filename($logid);
if(file_exists($filename)){
unlink($filename);
}
$this->success('','');
}
}
public function plugin_funcAction(){
$module=input('module');
if(empty($module)){
$this->error('模块错误');
}
$mfuncApp=new FuncApp();
$cacheName='cache_plugin_func_method_'.$module;
$cacheFuncs=cache($cacheName);
$enableApps=$mfuncApp->where(array('module'=>$module,'enable'=>1))->column('uptime','app');
foreach ($enableApps as $k=>$v){
$appFilename=$mfuncApp->filename($module, $k);
if(file_exists($appFilename)){
$v.=','.filemtime($appFilename);
}
$enableApps[$k]=$v;
}
ksort($enableApps);
$enableApps=md5(serialize($enableApps));
$apps=array();
if(empty($cacheFuncs)||$enableApps!=$cacheFuncs['key']||abs(time()-$cacheFuncs['time'])>3600){
$appList=$mfuncApp->where(array('module'=>$module,'enable'=>1))->column('uptime','app');
$apps=array();
if(!empty($appList)){
foreach ($appList as $k=>$v){
$appClass=$mfuncApp->get_app_class($module,$k,array('comment_cut'=>1,'method_params'=>1));
if(!empty($appClass['methods'])&&is_array($appClass['methods'])){
$apps[$k]=$appClass;
}
}
}
cache($cacheName,array('list'=>$apps,'time'=>time(),'key'=>md5(serialize($appList))));
}else{
$apps=$cacheFuncs['list'];
}
$this->success('',null,$apps);
}
}

View File

@ -11,16 +11,14 @@
namespace skycaiji\admin\controller;
use skycaiji\admin\model\FuncApp;
/*采集器:规则采集*/
class Cpattern extends BaseController {
/**
* 起始页网址
*/
public function sourceAction(){
$is_sub=input('sub');
if(request()->isPost()&&$is_sub){
$source=input('source/a','','trim');
if(request()->isPost()&&input('is_submit')){
$source=input('source/a',array(),'trim');
if($source['type']=='custom'){
if(preg_match_all('/^\w+\:\/\/[^\r\n]+/im',$source['urls'],$urls)){
@ -157,9 +155,9 @@ class Cpattern extends BaseController {
* 字段
*/
public function fieldAction(){
if(request()->isPost()){
if(request()->isPost()&&input('is_submit')){
$objid=input('post.objid');
$field=input('post.field/a',null,'trim');
$field=input('post.field/a',array(),'trim');
if(empty($field['name'])){
$this->error('请输入字段名称');
}
@ -172,7 +170,6 @@ class Cpattern extends BaseController {
case 'auto':if(empty($field['auto']))$this->error('请选择自动获取的类型');break;
case 'xpath':if(empty($field['xpath']))$this->error('XPath规则不能为空');break;
case 'json':if(empty($field['json']))$this->error('提取规则不能为空!');break;
case 'page':if(empty($field['page']))$this->error('请选择页面!');if(empty($field['page_rule']))$this->error('规则不能为空!');break;
case 'num':
$randNum=0;
$field['num_start']=intval($field['num_start']);
@ -194,12 +191,11 @@ class Cpattern extends BaseController {
'auto' =>'auto',
'xpath' =>array('xpath','xpath_multi','xpath_multi_type','xpath_multi_str','xpath_attr','xpath_attr_custom'),
'json' =>array('json','json_arr','json_arr_implode','json_loop'),
'page' =>array('page','page_rule','page_rule_merge','page_rule_multi','page_rule_multi_str'),
'words' =>'words',
'num' => array('num_start','num_end'),
'time' => array ('time_format','time_start','time_end','time_stamp'),
'list' => 'list',
'extract' =>array('extract','extract_module','extract_rule','extract_xpath','extract_xpath_attr','extract_xpath_attr_custom','extract_json','extract_json_arr','extract_json_arr_implode'),
'extract' =>array('extract','extract_module','extract_rule','extract_rule_merge','extract_rule_multi','extract_rule_multi_str','extract_xpath','extract_xpath_attr','extract_xpath_attr_custom','extract_xpath_multi','extract_xpath_multi_str','extract_json','extract_json_arr','extract_json_arr_implode'),
'merge' => 'merge',
'sign' => 'sign'
);
@ -241,9 +237,21 @@ class Cpattern extends BaseController {
return $this->fetch();
}
}
/**
* 数据处理
*/
/*复制字段*/
public function clone_fieldAction(){
if(request()->isPost()){
$field=input('field','','url_b64decode');
$field=$field?json_decode($field,true):array();
$process=input('process','','url_b64decode');
$process=$process?json_decode($process,true):'';
$this->success('',null,array('field'=>$field,'process'=>$process));
}else{
$this->error('复制失败');
}
}
/*数据处理*/
public function processAction(){
$type=input('type');
@ -252,9 +260,9 @@ class Cpattern extends BaseController {
$transApiLangs=null;
if(!empty($GLOBALS['_sc']['c']['translate'])&&!empty($GLOBALS['_sc']['c']['translate']['open'])){
if(!is_empty(g_sc_c('translate'))&&!is_empty(g_sc_c('translate','open'))){
$transApiLangs=\util\Translator::get_api_langs($GLOBALS['_sc']['c']['translate']['api']);
$transApiLangs=\util\Translator::get_api_langs(g_sc_c('translate','api'));
$transApiLangs=$transApiLangs?$transApiLangs:null;
}
$this->assign('transApiLangs',$transApiLangs);
@ -270,16 +278,11 @@ class Cpattern extends BaseController {
return $this->fetch();
}elseif($op=='sub'){
$process=input('process/a',null,'trim');
$process=array_array_map('trim', $process);
$process=trim_input_array('process');
if(empty($process)){
$process='';
}else{
foreach($process as $k=>$v){
if(!empty($v['title'])){
$process[$k]['title']=str_replace(array("'",'"'),'',strip_tags($v['title']));
}
}
$process=controller('admin/Cpattern','event')->set_process($process);
}
$objid=input('objid','');
$this->success('',null,array('process'=>$process,'process_json'=>empty($process)?'':json_encode($process),'objid'=>$objid));
@ -290,45 +293,53 @@ class Cpattern extends BaseController {
return $this->fetch();
}elseif($op=='load'){
$process=input('process/a',null,'trim');
$process=array_array_map('trim', $process);
$process=trim_input_array('process');
$this->assign('process',$process);
return $this->fetch('process_load');
}
}
}
/*获取函数插件列表*/
public function process_funcAction(){
$module=input('module');
if(empty($module)){
$this->error('模块错误');
}
$mfuncApp=new FuncApp();
$cacheName='cpattern_process_func_methods_'.$module;
$cacheFuncs=cache($cacheName);
$enableApps=$mfuncApp->where(array('module'=>$module,'enable'=>1))->column('uptime','app');
$enableApps=md5(serialize($enableApps));
$apps=array();
if(empty($cacheFuncs)||$enableApps!=$cacheFuncs['key']||abs(time()-$cacheFuncs['time'])>600){
$appList=$mfuncApp->where(array('module'=>$module,'enable'=>1))->column('uptime','app');
$apps=array();
if(!empty($appList)){
foreach ($appList as $k=>$v){
$appClass=$mfuncApp->get_app_class($module, $k);
if(!empty($appClass['methods'])){
$apps[$k]=$appClass;
}
}
}
cache($cacheName,array('list'=>$apps,'time'=>time(),'key'=>md5(serialize($appList))));
}else{
$apps=$cacheFuncs['list'];
}
$this->success('',null,$apps);
/*复制数据处理*/
public function clone_processAction(){
$op=input('op','');
if(empty($op)||$op=='copy'){
if(request()->isPost()){
$process=trim_input_array('process');
if(is_array($process)){
$process=reset($process);
}else{
$process=array();
}
$msg='';
if($op=='copy'){
cache('cpattern_clone_process_data',$process);
$msg='已拷贝,可在任意数据处理中粘贴';
}else{
$msg='已复制';
}
$this->success($msg,null,$process);
}else{
$this->error('无效的操作');
}
}elseif($op=='paste'){
$process=cache('cpattern_clone_process_data');
if(!empty($process)){
$this->success('已粘贴',null,$process);
}else{
$this->error('请先拷贝一个处理内容');
}
}else{
$this->error('无效的操作');
}
}
/**
* 内容分页
@ -337,7 +348,7 @@ class Cpattern extends BaseController {
public function paging_fieldAction(){
if(request()->isPost()){
$objid=input('post.objid');
$pagingField=input('post.paging_field/a',null,'trim');
$pagingField=trim_input_array('post.paging_field');
if(empty($pagingField['field'])){
$this->error('请选择字段');
}
@ -348,18 +359,21 @@ class Cpattern extends BaseController {
$pagingField=$pagingField?json_decode($pagingField,true):'';
$this->assign('pagingField',$pagingField);
$this->assign('objid',$objid);
$this->assign('isLoop',input('is_loop'));
return $this->fetch();
}
}
/*多级网址规则*/
public function level_urlAction(){
if(request()->isPost()){
if(request()->isPost()&&input('is_submit')){
$objid=input('post.objid');
$level_url=input('post.level_url/a',null,'trim');
$level_url=trim_input_array('post.level_url');
if(empty($level_url['name'])){
$this->error('请输入名称');
}
$this->_check_name($level_url['name'],'多级名称');
$this->_check_name($level_url['name'],'多级页名称');
$level_url=controller('admin/Cpattern','event')->set_config_url_web($level_url);
$this->success('',null,array('level_url'=>$level_url,'objid'=>$objid));
}else{
@ -371,11 +385,22 @@ class Cpattern extends BaseController {
return $this->fetch();
}
}
/*复制多级页*/
public function clone_level_urlAction(){
if(request()->isPost()){
$levelUrl=input('level_url','','url_b64decode');
$levelUrl=$levelUrl?json_decode($levelUrl,true):array();
$this->success('',null,array('level_url'=>$levelUrl));
}else{
$this->error('复制失败');
}
}
/*关联网址规则*/
public function relation_urlAction(){
if(request()->isPost()){
if(request()->isPost()&&input('is_submit')){
$objid=input('post.objid');
$relation_url=input('post.relation_url/a',null,'trim');
$relation_url=trim_input_array('post.relation_url');
if(empty($relation_url['name'])){
$this->error('请输入名称');
}
@ -384,6 +409,9 @@ class Cpattern extends BaseController {
if(empty($relation_url['url_rule'])){
$this->error('请输入提取网址规则');
}
$relation_url=controller('admin/Cpattern','event')->set_config_url_web($relation_url);
$this->success('',null,array('relation_url'=>$relation_url,'objid'=>$objid));
}else{
$relation_url=input('relation_url','','url_b64decode');
@ -394,374 +422,243 @@ class Cpattern extends BaseController {
return $this->fetch();
}
}
/*测试*/
public function testAction(){
set_time_limit(600);
$coll_id=input('coll_id/d',0);
$mcoll=model('Collector');
$collData=$mcoll->where(array('id'=>$coll_id))->find();
if(empty($collData)){
$this->error(lang('coll_error_empty_coll'));
}
if(!in_array($collData['module'],config('allow_coll_modules'))){
$this->error(lang('coll_error_invalid_module'));
}
$this->assign('collData',$collData);
$eCpattern=controller('admin/Cpattern','event');
$eCpattern->init($collData);
$op=input('op');
$taskData=model('Task')->getById($eCpattern->collector['task_id']);
model('Task')->loadConfig($taskData);
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Collector/set?task_id='.$taskData['id']),'title'=>lang('task').lang('separator').$taskData['name']),array('url'=>url('Cpattern/test&op='.$op.'&coll_id='.$coll_id),'title'=>'测试')));
if('source_urls'==$op){
$source_urls=array();
foreach ($eCpattern->config['source_url'] as $k => $v) {
if(empty($v)){
continue;
}
$source_urls[$v] = $eCpattern->convert_source_url ( $v );
}
if(!$eCpattern->config['source_is_url']){
$source_urls1=array();
foreach ($source_urls as $k=>$v){
if (is_array ( $v )) {
$source_urls1 = array_merge ( $source_urls1, $v );
} else {
$source_urls1 [] = $v;
}
}
$source_urls=$source_urls1;
}
$eCpattern->assign('source_urls',$source_urls);
$eCpattern->assign('config',$eCpattern->config);
return $eCpattern->fetch('cpattern:test_source_urls');
}elseif('cont_urls'==$op){
$source_url=input('source_url','','trim');
$curLevel=input('level/d',0);
$curLevel=$curLevel>0?$curLevel:0;
$levelData=$eCpattern->collLevelUrls($source_url,$curLevel);
$eCpattern->success('',null,array('urls'=>$levelData['urls'],'levelName'=>$levelData['levelName'],'nextLevel'=>$levelData['nextLevel']));
}elseif('cont_url'==$op){
$GLOBALS['_sc']['p_name']='测试抓取';
$cont_url=input('cont_url','','trim');
$test=input('test');
$url_post=$eCpattern->config['url_post'];
$input_urls=array();
foreach ($eCpattern->config['new_field_list'] as $field){
if(empty($field['field']['source'])){
if($field['field']['module']=='sign'){
if(empty($eCpattern->config['level_urls'])){
$input_urls['source_url']=input('source_url','');
}else{
$endLevelNum=count($eCpattern->config['level_urls']);
$endLevel=$eCpattern->config['level_urls'][$endLevelNum-1];
$input_urls['level_url'][$endLevelNum]=array('level'=>$endLevelNum,'name'=>$endLevel['name'],'url'=>input('level_'.$endLevelNum));
}
}
}elseif('source_url'==strtolower($field['field']['source'])){
$input_urls['source_url']=input('source_url','');
}elseif(preg_match('/level_url:/i', $field['field']['source'])){
foreach($eCpattern->config['level_urls'] as $levIx=>$levVal){
if($field['field']['source']==('level_url:'.$levVal['name'])){
$level=$levIx+1;
if($field['field']['module']=='sign'){
if($level==1){
$input_urls['source_url']=input('source_url','');
}else{
$prevLevel=$level-1;
$input_urls['level_url'][$prevLevel]=array('level'=>$prevLevel,'name'=>$eCpattern->config['level_urls'][$prevLevel-1]['name'],'url'=>input('level_'.$prevLevel));
}
}else{
$input_urls['level_url'][$level]=array('level'=>$level,'name'=>$levVal['name'],'url'=>input('level_'.$level));
}
break;
}
}
}
}
$eCpattern->assign('cont_url',$cont_url);
$eCpattern->assign('url_post',$url_post);
$eCpattern->assign('input_urls',$input_urls);
$eCpattern->assign('test',$test);
if(request()->isAjax()){
return view('cpattern:test_cont_url_ajax');
}else{
return $eCpattern->fetch('cpattern:test_cont_url');
}
}elseif(in_array($op, array('get_fields','get_paging_urls','get_relation_urls','get_html'))){
$cont_url=input('cont_url','','trim');
if(!preg_match('/^\w+\:\/\//',$cont_url)){
$cont_url='http://'.$cont_url;
}
$html='get_fields'==$op?'':$eCpattern->get_html($cont_url,false,$eCpattern->config['url_post']);
if('get_fields'==$op){
if(input('?source_url')){
$eCpattern->cur_source_url=input('source_url');
}
foreach (input('param.') as $k=>$v){
if(preg_match('/^level_(\d+)$/',$k,$mLevel)){
$mLevel=intval($mLevel[1])-1;
$eCpattern->cur_level_urls[$eCpattern->config['level_urls'][$mLevel]['name']]=$v;
}
}
$signLevels=array();
$signCont=false;
foreach($eCpattern->config['new_field_list'] as $fieldConfig){
if($fieldConfig['field']['module']=='sign'){
if(empty($fieldConfig['field']['source'])){
$signCont=true;
}elseif(preg_match('/^level_url:(.*+)$/i', $fieldConfig['field']['source'],$levelName)){
$levelName=$levelName[1];
$signLevels[$levelName]=$levelName;
}
}
}
if(!empty($signLevels)){
foreach ($eCpattern->config['level_urls'] as $k=>$v){
if(in_array($v['name'],$signLevels)){
if($k==0){
$eCpattern->getLevelUrls($eCpattern->cur_source_url,$k+1,true);
}else{
$prevLevelUrl=$eCpattern->config['level_urls'][$k-1];
$eCpattern->getLevelUrls($eCpattern->cur_level_urls[$prevLevelUrl['name']],$k+1,true);
}
}
}
}
if($signCont){
if(empty($eCpattern->config['level_urls'])){
$eCpattern->getContUrls($eCpattern->cur_source_url);
}else{
$endLevelNum=count($eCpattern->config['level_urls']);
$endLevel=$eCpattern->config['level_urls'][$endLevelNum-1];
$eCpattern->getContUrls($eCpattern->cur_level_urls[$endLevel['name']]);
}
}
$val_list=$eCpattern->getFields($cont_url);
if(empty($eCpattern->first_loop_field)){
$val_list=array($val_list);
}
$md5Url=md5($cont_url);
$msg='';
if(isset($eCpattern->exclude_cont_urls[$md5Url])){
if(empty($eCpattern->first_loop_field)){
$msg=reset($eCpattern->exclude_cont_urls[$md5Url]);
$msg=$eCpattern->exclude_url_msg($msg);
$this->error('中断采集 &gt; '.$msg);
}else{
$num=0;
foreach ($eCpattern->exclude_cont_urls[$md5Url] as $k=>$v){
$num+=count((array)$v);
}
$msg='通过数据处理筛除了'.$num.'条数据';
}
}
foreach ($val_list as $v_k=>$vals){
foreach ($vals as $k=>$v){
$vals[$k]=$v['value'];
}
$val_list[$v_k]=$vals;
}
$eCpattern->success($msg,null,$val_list);
}elseif('get_paging_urls'==$op){
$paging_urls=$eCpattern->getPagingUrls($cont_url,$html,true);
if(empty($paging_urls)){
$eCpattern->error('没有抓取到分页链接');
}else{
$eCpattern->success('',null,$paging_urls);
}
}elseif('get_html'==$op){
if(empty($html)){
exit('没有抓取到源码');
}else{
exit($html);
}
}elseif('get_relation_urls'==$op){
$url_list=array();
foreach ($eCpattern->config['new_relation_urls'] as $k=>$v){
$url_list[$v['name']]=$eCpattern->getRelationUrl($v['name'], $cont_url, $html);
}
if(empty($url_list)){
$eCpattern->error('没有关联页');
}else{
$eCpattern->success('',null,$url_list);
}
}
}elseif('match'==$op){
$GLOBALS['_sc']['p_name']='模拟匹配';
if(request()->isPost()){
$type=strtolower(input('type'));
$content=input('content','','trim');
$match=input('match','','trim');
if(empty($content)){
$eCpattern->error('请输入网址或内容');
}
if(empty($match)){
$eCpattern->error('请输入规则');
}
if(preg_match('/^\w+\:\/\//', $content)){
$content=$eCpattern->get_html($content);
}
if(empty($content)){
$eCpattern->error('内容空');
}
$val='';
switch ($type){
case 'rule':
$match=$eCpattern->convert_sign_match($match);
$match=preg_replace('/\\\*([\'\/])/', "\\\\$1",$match);
$match=str_replace('(*)', '[\s\S]*?', $match);
$rule_merge=$eCpattern->set_merge_default($match, '');
$val=$eCpattern->field_module_rule(array('reg_rule'=>$match,'rule_merge'=>$rule_merge), $content);
if(empty($val)){
if(preg_match('/'.$match.'/i', $content,$val)){
$val=$val[0];
}
}
break;
case 'xpath':
$val=$eCpattern->field_module_xpath(array('xpath'=>$match,'xpath_attr'=>''), $content);
break;
case 'json':
$val=$eCpattern->field_module_json(array('json'=>$match,'json_arr_implode'=>"\r\n"), $content);
$val=trim($val);
break;
}
if(empty($val)){
$eCpattern->error('没有获取到数据');
}else{
$eCpattern->success($val);
}
}else{
if(request()->isAjax()){
return view('cpattern:test_match_ajax');
}else{
return $eCpattern->fetch('cpattern:test_match');
}
}
}elseif('elements'==$op){
$cont_url=input('cont_url','','trim');
$this->redirect('Cpattern/browser?coll_id='.$coll_id.'&url='.rawurlencode($cont_url));
}
/*复制关联页*/
public function clone_relation_urlAction(){
if(request()->isPost()){
$relationUrl=input('relation_url','','url_b64decode');
$relationUrl=$relationUrl?json_decode($relationUrl,true):array();
$this->success('',null,array('relation_url'=>$relationUrl));
}else{
$this->error('复制失败');
}
}
/*编辑规则:简单模式*/
public function easymodeAction(){
$taskId=input('task_id/d',0);
$collId=model('Collector')->where('task_id',$taskId)->value('id');
$this->assign('taskId',$taskId);
$this->assign('collId',$collId);
return $this->fetch();
}
/*浏览器*/
public function browserAction(){
$coll_id=input('coll_id/d',0);
$mcoll=model('Collector');
$collData=$mcoll->where(array('id'=>$coll_id))->find();
$taskData=model('Task')->getById($taskId);
$collId=$mcoll->where('task_id',$taskId)->value('id');
$collData=$mcoll->where(array('id'=>$collId))->find();
if(empty($collData)){
$collData=array();
$collData=array();
}else{
$collData=$collData->toArray();
$collData=$collData->toArray();
}
$eCpattern=controller('admin/Cpattern','event');
$eCpattern->init($collData);
$url=input('url','','trim');
if(!preg_match('/^\w+\:\/\//',$url)){
$url='http://'.$url;
}
$html=$eCpattern->get_html($url,false,$eCpattern->config['url_post']);
$pageSources=$eCpattern->page_source_options();
$jsonHtml=convert_html2json($html,true);
set_g_sc('p_title','简单模式_任务:'.$taskData['name']);
$config=$eCpattern->config;
$config=is_array($config)?$config:array();
if(empty($jsonHtml)){
$html=preg_replace('/<script[^<>]*?>[\s\S]*?<\/script>/i', '', $html);
$html=preg_replace('/<meta[^<>]*charset[^<>]*?>/i', '', $html);
$html=preg_replace('/<meta[^<>]*http-equiv\s*=\s*[\'\"]{0,1}refresh\b[\'\"]{0,1}[^<>]*?>/i', '', $html);
header("Content-type:text/html;charset=utf-8");
$eCpattern->assign('html',$html);
$eCpattern->assign('config',$config);
return $eCpattern->fetch('cpattern:browser');
}else{
$GLOBALS['_sc']['p_name']='分析网页';
$eCpattern->assign('jsonHtml',$jsonHtml);
return $eCpattern->fetch('cpattern:browser_json');
}
$this->assign('taskId',$taskId);
$this->assign('collId',$collId);
$this->assign('pageSources',$pageSources);
return $this->fetch();
}
/*获取父级页面的标签列表*/
public function parentPageSignsAction(){
if(request()->isPost()){
$level_urls=input('level_urls/a',array(),'url_b64decode');
$relation_urls=input('relation_urls/a',array(),'url_b64decode');
$urlConfig=input('url_config/a',array(),'trim');
$pageConfig=input('page_config/a',array(),'trim');
$isAreaOrUrl=input('is_area_or_url','');
$pageType=input('page_type','','trim');
$eCpattern=controller('admin/Cpattern','event');
$levelSigns=array();
$relationSigns=array();
$urlSigns=array();
$pageSigns=array();
$relationUrls=array();
foreach ($level_urls as $k=>$v){
$v=$v?json_decode($v,true):array();
$levelSigns[$v['name']]=array(
'area'=>$this->_get_rule_signs($v['area'],'',true,false),
'url'=>$this->_get_rule_signs('',$v['url_rule'],false,true),
);
}
if($pageType=='relation_url'){
foreach ($relation_urls as $k=>$v){
$v=$v?json_decode($v,true):array();
$relationSigns[$v['name']]=array(
'area'=>$this->_get_rule_signs($v['area'],'',true,false),
'url'=>$this->_get_rule_signs('',$v['url_rule'],false,true),
);
$relationUrls[$v['name']]=$v;
}
}
if($pageType=='relation_url'||$pageType=='url'){
if($pageType=='url'&&$isAreaOrUrl=='area'){
$urlSigns=array(
'area'=>$this->_get_rule_signs($urlConfig['area'],'',true,false),
);
}else{
$urlSigns=array(
'area'=>$this->_get_rule_signs($urlConfig['area'],'',true,false),
'url'=>$this->_get_rule_signs('',$urlConfig['url_rule'],false,true),
);
}
}
if($isAreaOrUrl=='area'){
$pageSigns=array(
'area'=>$this->_get_rule_signs($pageConfig['area'],'',true,false),
);
}else{
$pageSigns=array(
'area'=>$this->_get_rule_signs($pageConfig['area'],'',true,false),
'url'=>$this->_get_rule_signs('',$pageConfig['url_rule'],false,true),
);
}
if($pageType=='level_url'){
if($pageConfig['name']&&isset($levelSigns[$pageConfig['name']])){
$newLevelSigns=array();
foreach($levelSigns as $k=>$v){
if($pageConfig['name']==$k){
$newLevelSigns['_cur_']=$pageSigns;
break;
}else{
$newLevelSigns[$k]=$v;
}
}
$levelSigns=$newLevelSigns;
}else{
$levelSigns['_cur_']=$pageSigns;
}
}elseif($pageType=='relation_url'){
$newRelationSigns=array();
$newRelationSigns['_cur_']=$pageSigns;
$relationUrls[$pageConfig['name']]=$pageConfig;
$relationParentPages=$eCpattern->relation_parent_pages($pageConfig['name'],$relationUrls);
foreach ($relationParentPages as $relationParentPage){
$newRelationSigns[$relationParentPage]=$relationSigns[$relationParentPage];
}
$relationSigns=$newRelationSigns;
}
$levelSigns=array_reverse($levelSigns,true);
$allSigns=array();
foreach ($relationSigns as $k=>$v){
if($k=='_cur_'){
$allSigns[]=array('name'=>'当前关联页','signs'=>$v,'cur'=>true);
}else{
$allSigns[]=array('name'=>'关联页:'.$k,'signs'=>$v);
}
}
if($pageType=='relation_url'||$pageType=='url'){
$allSigns[]=array('name'=>($pageType=='url'?'当前':'').'内容页','signs'=>$urlSigns,'cur'=>($pageType=='url'?true:false));
}
foreach ($levelSigns as $k=>$v){
if($k=='_cur_'){
$allSigns[]=array('name'=>'当前多级页','signs'=>$v,'cur'=>true);
}else{
$allSigns[]=array('name'=>'多级页:'.$k,'signs'=>$v);
}
}
$existSigns=array();
foreach ($allSigns as $ask=>$asv){
$asv=is_array($asv)?$asv:array();
$signs=$asv['signs'];
$newSigns=array('area'=>array(),'url'=>array(),'area_global'=>array(),'url_global'=>array());
if(!is_array($signs)){
$signs=array();
}
if(!is_array($signs['area'])){
$signs['area']=array();
}
if(!is_array($signs['url'])){
$signs['url']=array();
}
foreach ($signs['url'] as $k=>$v){
if(!in_array($v, $existSigns)){
$existSigns[]=$v;
$newSigns['url_global'][]=$v;
}
}
foreach ($signs['area'] as $k=>$v){
if(!in_array($v, $existSigns)){
$existSigns[]=$v;
$newSigns['area_global'][]=$v;
}
}
$newSigns['area']=$signs['area'];
$newSigns['url']=$signs['url'];
$asv['signs']=$newSigns;
$allSigns[$ask]=$asv;
}
$this->success('',null,$allSigns);
}else{
$this->error();
}
}
/*名称命名规范*/
public function _check_name($name,$nameStr=''){
if(!preg_match('/^[\x{4e00}-\x{9fa5}\w\-]+$/u', $name)){
$this->error(($nameStr?$nameStr:'名称').'只能由汉字、字母、数字和下划线组成');
return false;
}else{
return true;
}
if(!preg_match('/^[\x{4e00}-\x{9fa5}\w\-]+$/u', $name)){
$this->error(($nameStr?$nameStr:'名称').'只能由汉字、字母、数字和下划线组成');
return false;
}else{
return true;
}
}
private function _get_rule_signs($areaRule,$urlRule,$areaDef=true,$urlDef=true){
$eCpattern=controller('admin/Cpattern','event');
$areaRule=$areaRule?$areaRule:'';
$urlRule=$urlRule?$urlRule:'';
$areaRule=$eCpattern->convert_sign_match($areaRule);
$urlRule=$eCpattern->convert_sign_match($urlRule);
$areaSigns=$eCpattern->rule_str_signs($areaRule);
$urlSigns=$eCpattern->rule_str_signs($urlRule);
if(empty($areaSigns)){
$areaSigns=$areaDef?array(cp_sign('match')):array();
}
if(empty($urlSigns)){
$urlSigns=$urlDef?array(cp_sign('match')):array();
}
foreach ($areaSigns as $k=>$v){
if(in_array($v,$urlSigns)){
unset($areaSigns[$k]);
}
}
return array_merge($areaSigns,$urlSigns);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -66,9 +66,9 @@ class Develop extends BaseController {
$this->error('cms程序名必须由字母或数字组成且首位不能为数字');
}
if(empty($identifier)){
$this->error('请输入插件功能标识');
$this->error('请输入功能标识');
}elseif(!preg_match('/^[a-z][a-z0-9]*$/i', $identifier)){
$this->error('插件功能标识必须由字母或数字组成且首位不能为数字!');
$this->error('功能标识必须由字母或数字组成且首位不能为数字!');
}
if(empty($copyright)){
$this->error('请输入作者版权');
@ -82,7 +82,7 @@ class Develop extends BaseController {
$appName=ucfirst(input('app'));
}
$params=input('params/a');
$params=input('params/a',array());
if(empty($params)||!is_array($params)){
$this->error('请添加参数');
}
@ -162,9 +162,9 @@ class Develop extends BaseController {
}
}
}
$GLOBALS['_sc']['p_name']='开发CMS发布插件 <small><a href="https://www.skycaiji.com/manual/doc/cms" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Mystore/ReleaseApp'),'title'=>'CMS发布插件'),array('url'=>url('Develop/releaseCms'),'title'=>'开发CMS发布插件')));
set_g_sc('p_title','开发CMS发布插件');
set_g_sc('p_name','开发CMS发布插件 <small><a href="https://www.skycaiji.com/manual/doc/cms" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Mystore/ReleaseApp'),'title'=>'CMS发布插件'),array('url'=>url('Develop/releaseCms'),'title'=>'开发CMS发布插件'))));
$this->assign('config',$config);
$this->assign('is_old_plugin',$is_old_plugin);
@ -174,8 +174,8 @@ class Develop extends BaseController {
/*添加参数*/
public function cmsAddParamAction(){
if(request()->isPost()){
$param=input('param/a');
$param=array_array_map('trim', $param);
$param=input('param/a',array());
$param=\util\Funcs::array_array_map('trim', $param);
if(empty($param['key'])){
$this->error('请输入变量名');
}
@ -402,7 +402,7 @@ EOF;
$this->error('修改失败,该应用不存在!');
}
$framework=input('framework');
$frameworkVersion=input('framework_version/a');
$frameworkVersion=input('framework_version/a',array());
$frameworkVersion=$frameworkVersion[$framework];
$config=array(
@ -422,8 +422,8 @@ EOF;
if(!empty($framework)&&empty($frameworkVersion)){
$this->error('请选择框架版本');
}
$packs=input('packs/a');
$packs=input('packs/a',array());
if(empty($config['name'])){
$this->error('请输入应用名称');
}
@ -443,7 +443,17 @@ EOF;
if(!$mapp->right_version($config['version'])){
$this->error('版本号格式错误');
}
if(empty($install)){
$this->error('请输入安装应用接口');
}
if(empty($uninstall)){
$this->error('请输入卸载应用接口');
}
if(empty($upgrade)){
$this->error('请输入升级应用接口');
}
if(is_array($packs)){
foreach ($packs as $k=>$v){
@ -561,12 +571,13 @@ EOF;
$this->success('修改成功','Develop/app?app='.$app);
}
}else{
$GLOBALS['_sc']['p_name']='开发应用程序 <small><a href="https://www.skycaiji.com/manual/doc/app" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>';
set_g_sc('p_title','开发应用程序');
set_g_sc('p_name','开发应用程序 <small><a href="https://www.skycaiji.com/manual/doc/app" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>');
if($appData){
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('App/manage?app='.$appData['app']),'title'=>$appData['config']['name']),array('url'=>url('Develop/app?app='.$appData['app']),'title'=>'开发应用')));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('App/manage?app='.$appData['app']),'title'=>$appData['config']['name']),array('url'=>url('Develop/app?app='.$appData['app']),'title'=>'开发应用'))));
}else{
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Mystore/app'),'title'=>'应用程序'),array('url'=>url('Develop/app'),'title'=>'开发应用')));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Mystore/app'),'title'=>'应用程序'),array('url'=>url('Develop/app'),'title'=>'开发应用'))));
}
$appClass=$mapp->app_class($app);
@ -596,11 +607,11 @@ EOF;
/*添加扩展*/
public function appAddPackAction(){
if(request()->isPost()){
$pack=input('pack/a','','trim');
$pack=input('pack/a',array(),'trim');
$pack['name']=strip_tags($pack['name']);
$pack['type']=strip_tags($pack['type']);
$pack['target']=intval($pack['target']);
$pack=array_array_map('trim', $pack);
$pack=\util\Funcs::array_array_map('trim', $pack);
if(empty($pack['name'])){
$this->error('请输入名称');
}
@ -631,7 +642,6 @@ EOF;
/*下载安装框架*/
public function installFrameworkAction(){
$app=input('app');
$op=input('op');
if(empty($app)){
$this->error('应用app标识错误');
@ -649,98 +659,48 @@ EOF;
if(empty($appClass->config['framework_version'])){
$this->error('框架版本错误');
}
$appFrameworkPath=$appClass->appFrameworkPath();
if(is_dir($appFrameworkPath)){
$this->error('该应用已有框架,如需重新设置框架,请先删除:'.$appFrameworkPath);
}
$eachSize=1024*100;
$fileUrl='https://www.skycaiji.com/download/framework/'.$appClass->config['framework'].'/'.$appClass->config['framework_version'].'.zip';
$filePath=RUNTIME_PATH.'/cache_framework/'.$appClass->config['framework'].$appClass->config['framework_version'].'/';
if('files'==$op){
$fileHeader=get_headers($fileUrl,true);
if(!preg_match('/\s+20\d\s+ok/i',$fileHeader[0])){
$this->error('文件获取失败');
}
$fileSize=$fileHeader['Content-Length'];
$list=array();
$count=ceil($fileSize/$eachSize);
for($i=0;$i<$count;$i++){
$list[$i]=array('id'=>$i+1,'start'=>$i*$eachSize,'end'=>($i+1)*$eachSize);
if($list[$i]['end']>=$fileSize){
$list[$i]['end']=$fileSize;
}
$list[$i]['end']-=1;
}
$this->success(true,'',array('size'=>$fileSize,'list'=>$list));
}elseif('down'==$op){
$fileSize=input('size/d');
$startSize=input('start_size/d');
$endSize=input('end_size/d');
$id=input('id/d');
$fileCont=file_get_contents($filePath.$id);
if(!empty($fileCont)){
$this->success();
}else{
$blockData=$this->_down_file($fileUrl,null,"{$startSize}-{$endSize}");
if(empty($blockData)){
$this->error();
}else{
write_dir_file($filePath.$id, $blockData);
$this->success();
}
}
}elseif('install'==$op){
$fileSize=input('size/d');
$count=ceil($fileSize/$eachSize);
$is_end=true;
for($i=1;$i<=$count;$i++){
if(!file_exists($filePath.$i)){
$is_end=false;
break;
}
}
if($is_end){
$error='';
$allData='';
for($i=1;$i<=$count;$i++){
$allData.=file_get_contents($filePath.$i);
}
write_dir_file($filePath.'framework.zip', $allData);
try {
$zipClass=new \ZipArchive();
if($zipClass->open($filePath.'framework.zip')===TRUE){
$zipClass->extractTo($appClass->appPath);
$zipClass->close();
}else{
$error='解压失败';
}
}catch(\Exception $ex){
$error='您的服务器不支持ZipArchive解压';
}
if(!empty($error)){
$error.=',请自行将文件'.$filePath.'framework.zip 解压到'.$appClass->appPath.'里';
}
if($error){
$this->error($error);
}else{
clear_dir($filePath);
$this->success('安装成功','Develop/app?app='.$app);
}
}
$this->error();
$mprov=model('Provider');
$timestamp=time();
$clientinfo=clientinfo();
$authsign=$mprov->createAuthsign($mprov->getAuthkey(null),$clientinfo['url'],'https://www.skycaiji.com',$timestamp);
$uriParams=array(
'authsign'=>$authsign,
'client_url'=>$clientinfo['url'],
'timestamp'=>$timestamp,
'name'=>$appClass->config['framework'],
'version'=>$appClass->config['framework_version'],
'block_no'=>input('block_no/d',0)
);
$fileData=curl_skycaiji('/client/download/framework?'.http_build_query($uriParams));
$fileData=json_decode($fileData,true);
$fileData=is_array($fileData)?$fileData:array();
if(!$fileData['code']){
$this->error($fileData['msg']);
}
$fileData=is_array($fileData['data'])?$fileData['data']:array();
$fileData=json_decode(base64_decode($fileData['file']),true);
$fileData=is_array($fileData)?$fileData:array();
$filePath=RUNTIME_PATH.'zip_framework/'.$appClass->config['framework'].$appClass->config['framework_version'];
$result=\util\Funcs::install_downloaded_zip($fileData, $filePath, $appClass->appPath);
if($result['success']){
$this->success('框架安装成功','Develop/app?app='.$app,$result);
}else{
$this->error($result['msg']);
}
}
/*开发函数插件*/
@ -765,7 +725,7 @@ EOF;
$copyright=input('copyright');
$identifier=input('identifier');
$name=input('name');
$methods=input('methods/a');
$methods=input('methods/a',array());
if(empty($module)){
$this->error('请选择类型');
@ -813,8 +773,9 @@ EOF;
}
}
}else{
$GLOBALS['_sc']['p_name']='开发函数插件 <small><a href="https://www.skycaiji.com/manual/doc/func" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Mystore/funcApp'),'title'=>'函数插件'),array('url'=>url('Develop/func'),'title'=>'开发函数插件')));
set_g_sc('p_title','开发函数插件');
set_g_sc('p_name','开发函数插件 <small><a href="https://www.skycaiji.com/manual/doc/func" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Mystore/funcApp'),'title'=>'函数插件'),array('url'=>url('Develop/func'),'title'=>'开发函数插件'))));
if(input('?app')){
@ -832,14 +793,6 @@ EOF;
}
}
/*保存到云端*/
public function save2storeAction(){
$type=input('type');
$app=input('app');
$pluginData=$this->_get_plugin_data($type,$app);
$this->assign('pluginData',$pluginData);
return $this->fetch();
}
/*导出插件*/
public function exportAction(){
$type=input('type');
@ -859,9 +812,9 @@ EOF;
header("Content-transfer-encoding: binary");
header("Accept-Length: " .mb_strlen($txt));
if (preg_match("/MSIE/i", $_SERVER["HTTP_USER_AGENT"])) {
header('Content-Disposition: attachment; filename="'.urlencode($name).'.skycaiji"');
header('Content-Disposition: attachment; filename="'.urlencode($name).'.scj"');
}else{
header('Content-Disposition: attachment; filename="'.$name.'.skycaiji"');
header('Content-Disposition: attachment; filename="'.$name.'.scj"');
}
echo $txt;
ob_end_flush();
@ -894,8 +847,9 @@ EOF;
if(!empty($pluginDb['provider_id'])){
$provData=model('Provider')->where('id',$pluginDb['provider_id'])->find();
$pluginData['store_url']=$provData['url'].'/client/plugin/detail?app='.$pluginDb['app'];
$mprov=model('Provider');
$provData=$mprov->where('id',$pluginDb['provider_id'])->find();
$pluginData['store_url']=\skycaiji\admin\model\Provider::create_store_url($provData['url'],'client/addon/plugin',array('app'=>$pluginDb['app']));
}
if(empty($pluginData['name'])){
@ -965,36 +919,4 @@ EOF;
}
}
}
/*获取内容*/
public function _down_file($url, $header=null,$size) {
$useragents=array(
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
);
static $useragent;
if(empty($useragent)){
$useragent=$useragents[array_rand($useragents)];
}
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_TIMEOUT, 100 );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
curl_setopt ( $ch, CURLOPT_HEADER, 0 );
curl_setopt ( $ch, CURLOPT_USERAGENT, $useragent);
curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
if (! empty ( $header )) {
curl_setopt ( $ch, CURLOPT_HTTPHEADER, $header );
}
curl_setopt($ch, CURLOPT_RANGE, $size);
$bytes = curl_exec ( $ch );
curl_close ( $ch );
return $bytes;
}
}

View File

@ -19,7 +19,7 @@ class Index extends BaseController{
/*后台运行采集,会无限运行下去*/
public function backstageAction(){
$key=input('key');
$cacheKey=CacheModel::getInstance()->getCache('admin_index_backstage_key', 'data');
$cacheKey=CacheModel::getInstance()->getCache('collect_backstage_key', 'data');
if(empty($key)||$key!=$cacheKey){
@ -37,7 +37,7 @@ class Index extends BaseController{
$this->error('不是后台运行方式');
}
if($caijiConfig['server']=='cli'){
if($mconfig->server_is_cli(true,$caijiConfig['server'])){
cli_command_exec('collect backstage');
}else{
@ -56,6 +56,8 @@ class Index extends BaseController{
ignore_user_abort(true);
set_time_limit(0);
CacheModel::getInstance()->setCache('collect_backstage_time',time());
try{
get_html(url('Admin/Api/collect?backstage=1',null,false,true),null,array('timeout'=>3));
}catch(\Exception $ex){
@ -71,7 +73,7 @@ class Index extends BaseController{
$cacheKey=CacheModel::getInstance()->getCache('admin_index_backstage_key', 'data');
$cacheKey=CacheModel::getInstance()->getCache('collect_backstage_key', 'data');
if(empty($key)||$key!=$cacheKey){
@ -111,16 +113,25 @@ class Index extends BaseController{
}
}
/*访问执行采集*/
public function caijiAction(){
if(empty($GLOBALS['_sc']['c']['caiji']['auto'])){
if(is_empty(g_sc_c('caiji','auto'))){
$this->error('请先开启自动采集','Admin/Setting/caiji');
}
$checkCollectWait=\skycaiji\admin\model\Config::check_collect_wait();
if($checkCollectWait){
$this->error($checkCollectWait['msg'],'Admin/Index/caiji',null,$checkCollectWait['wait']);
}
@get_html(url('Admin/Api/collect?backstage=1',null,false,true),null,array('timeout'=>3));
$waitTime=$GLOBALS['_sc']['c']['caiji']['interval']*60;
$waitTime=g_sc('c_caiji_interval')*60;
$waitTime=$waitTime>0?$waitTime:60;
$this->success('正在采集...','Admin/Index/caiji',null,$waitTime);
}
/*任务api发布*/
public function apiTaskAction(){
controller('admin/Api','controller')->taskAction();
@ -128,25 +139,30 @@ class Index extends BaseController{
public function loginAction(){
if(request()->isPost()){
if(!check_usertoken()){
$this->error(lang('usertoken_error'),'Admin/Index/login');
}
$mcacheLogin=CacheModel::getInstance('login');
$config_login=$GLOBALS['_sc']['c']['site']['login'];
$config_login=g_sc_c('site','login');
$clientIpMd5=md5(request()->ip());
$nowTime=time();
if(!empty($config_login['limit'])){
$ipLoginData=$mcacheLogin->getCache($clientIpMd5,'data');
if((NOW_TIME-$ipLoginData['lastdate'])<($config_login['time']*3600)&&$ipLoginData['failed']>=$config_login['failed']){
try{
$ipLoginData=$mcacheLogin->getCache($clientIpMd5,'data');
if(!is_array($ipLoginData)){
$ipLoginData=array();
}
}catch (\Exception $ex){
$this->error($ex->getMessage());
}
if(($nowTime-$ipLoginData['lastdate'])<($config_login['time']*3600)&&$ipLoginData['failed']>=$config_login['failed']){
$this->error("您已登录失败{$ipLoginData['failed']}次,被锁定{$config_login['time']}小时");
}
}
if(input('post.sublogin')){
$username=strtolower(trim(input('post.username')));
$username=User::lower_username(input('post.username'));
$pwd=trim(input('post.password'));
if($GLOBALS['_sc']['c']['site']['verifycode']){
if(g_sc_c('site','verifycode')){
$verifycode=trim(input('post.verifycode'));
$check=check_verify($verifycode);
@ -155,7 +171,6 @@ class Index extends BaseController{
}
}
$check=User::right_username($username);
if(!$check['success']){
$this->error($check['msg']);
@ -164,9 +179,14 @@ class Index extends BaseController{
if(!$check['success']){
$this->error($check['msg']);
}
$muser=new \skycaiji\admin\model\User();
$userData=$muser->where('username',$username)->find();
try{
$userData=$muser->where('username',$username)->find();
}catch (\Exception $ex){
$this->error($ex->getMessage());
}
if(empty($userData)||$userData['password']!=\skycaiji\admin\model\User::pwd_encrypt($pwd,$userData['salt'])){
if(!empty($config_login['limit'])){
@ -174,17 +194,17 @@ class Index extends BaseController{
$ipLoginData=$mcacheLogin->getCache($clientIpMd5,'data');
if(!empty($ipLoginData)){
if((NOW_TIME-$ipLoginData['lastdate'])<($config_login['time']*3600)){
if(($nowTime-$ipLoginData['lastdate'])<($config_login['time']*3600)){
$ipLoginData['failed']++;
}else{
$ipLoginData['lastdate']=NOW_TIME;
$ipLoginData['lastdate']=$nowTime;
$ipLoginData['failed']=1;
}
}else{
$ipLoginData['lastdate']=NOW_TIME;
$ipLoginData['lastdate']=$nowTime;
$ipLoginData['failed']=1;
}
$ipLoginData['ip']=request()->ip();
@ -196,17 +216,10 @@ class Index extends BaseController{
if(input('post.auto')){
cookie('login_history',$username.'|'.md5($username.$userData['password']),array('expire'=>3600*24*15));
cookie('login_history',intval($userData['uid']).'|'.$muser->generate_key($userData),array('expire'=>3600*24*15));
}
session('user_id',$userData['uid']);
$userGroup=model('Usergroup')->getById($userData['groupid']);
if(model('Usergroup')->is_admin($userGroup)){
session('is_admin',true);
}else{
session('is_admin',null);
}
$muser->setLoginSession($userData);
$serverinfo=input('_serverinfo');
if(empty($serverinfo)){
@ -232,16 +245,19 @@ class Index extends BaseController{
/*退出*/
public function logoutAction(){
\think\Cookie::delete('login_history');
unset($GLOBALS['_sc']['user']);
session('user_id',null);
session('is_admin',null);
set_g_sc('user',null);
model('User')->setLoginSession(null);
$this->success(lang('op_success'),'Admin/Index/index');
}
/*验证码*/
public function verifyAction(){
$len=g_sc_c('site','verifycode_len');
$len=intval($len);
$len=min(max(3,$len),20);
$config=array(
'fontSize'=>30,
'length'=>3,
'length'=>$len,
'fontttf'=>'5.ttf',
'useCurve'=>true,
'useNoise'=>true
@ -251,6 +267,28 @@ class Index extends BaseController{
$captcha = new \think\captcha\Captcha($config);
return $captcha->entry();
}
public function verify_img_errorAction(){
$LocSystem=new \skycaiji\install\event\LocSystem();
$LocSystem=$LocSystem->environmentPhp();
$gd=$LocSystem['gd'];
$error='';
if(empty($gd['loaded'])){
$error='php未启用gd模块';
}elseif(!empty($gd['lack'])){
$error='php未启用gd模块(需支持'.$gd['lack'].')';
}
if($error){
$error='图片验证码错误:'.$error;
$this->error($error);
}else{
$this->success('');
}
}
/*找回密码*/
public function find_passwordAction(){
$username=trim(input('post.username'));
@ -281,10 +319,7 @@ class Index extends BaseController{
}
if($step===1){
if(!check_usertoken()){
$this->error(lang('usertoken_error'),'Admin/Index/find_password');
}
if($GLOBALS['_sc']['c']['site']['verifycode']){
if(g_sc_c('site','verifycode')){
$verifycode=trim(input('verifycode'));
$check=check_verify($verifycode);
@ -361,25 +396,26 @@ class Index extends BaseController{
}else{
if($step===2){
$emailStatus=array('success'=>false,'msg'=>'');
if(empty($GLOBALS['_sc']['c']['email'])){
if(is_empty(g_sc_c('email'))){
$emailStatus['msg']=lang('config_error_none_email');
}else{
$waitTime=60;
$waitSname='send_yzm_wait';
$passTime=abs(NOW_TIME-session($waitSname));
$nowTime=time();
$passTime=abs($nowTime-session($waitSname));
if($passTime<=$waitTime){
$emailStatus['msg']=lang('find_pwd_email_wait',array('seconds'=>$waitTime-$passTime));
}else{
$expire=config('yzm_expire');
$minutes=floor($expire/60);
$yzm=mt_rand(100000,999999);
session($waitSname,NOW_TIME);
$mailReturn=send_mail($GLOBALS['_sc']['c']['email'], $stepSession['user']['email'], $stepSession['user']['username'],lang('find_pwd_email_subject'),lang('find_pwd_email_body',array('yzm'=>$yzm,'minutes'=>$minutes)));
session($waitSname,$nowTime);
$mailReturn=send_mail(g_sc_c('email'), $stepSession['user']['email'], $stepSession['user']['username'],lang('find_pwd_email_subject'),lang('find_pwd_email_body',array('yzm'=>$yzm,'minutes'=>$minutes)));
if($mailReturn===true){
$yzmSname='send_yzm.'.md5($username);
session(array('name'=>$yzmSname,'expire'=>$expire));
session($yzmSname,array('yzm'=>$yzm,'time'=>NOW_TIME));
session($yzmSname,array('yzm'=>$yzm,'time'=>$nowTime));
$emailStatus['success']=true;
$emailStatus['msg']=lang('find_pwd_sended',array('email'=>preg_replace('/.{2}\@/', '**@', $stepSession['user']['email'])));
}else{
@ -402,18 +438,4 @@ class Index extends BaseController{
return $this->fetch();
}
}
/*验证站点*/
public function site_certificationAction(){
$keyFile=cache('site_certification');
$key=$keyFile['key'];
if(abs(NOW_TIME-$keyFile['time'])>60){
$key='';
}
exit($key);
}
/*客户端信息*/
public function clientinfoAction(){
return json(clientinfo());
}
}

View File

@ -17,37 +17,54 @@ class Mystore extends BaseController {
$this->redirect('Mystore/store');
}
public function storeAction(){
$url=input('url','','strip_tags');
if(!empty($url)&&!is_official_url($url)){
set_g_sc('p_title','云平台');
$url=input('url','','trim');
$notSafe='';
if(!empty($url)&&!\skycaiji\admin\model\Provider::is_official_url($url)){
$provData=model('Provider')->where('url',$url)->find();
set_g_sc('p_title','第三方平台');
if(empty($provData)){
$this->error($url.' 平台未添加');
$this->error($url.' 平台未添加','');
}
if(empty($provData['enable'])){
$this->error($url.' 已设置为拒绝访问');
$this->error($url.' 已设置为拒绝访问','');
}
$url=$provData['url'];
set_g_sc('p_title','第三方:'.$provData['title']);
$url.=strpos($url, '?')===false?'?':'&';
$url.='clientinfo='.urlencode($GLOBALS['_sc']['clientinfo']);
$this->assign('provData',$provData);
$storeData=curl_skycaiji('/client/info/store?url='.rawurlencode($url).'&clientinfo='.rawurlencode(g_sc('clientinfo')));
$storeData=json_decode($storeData,true);
if(!is_array($storeData)){
$storeData=array();
}
if(empty($storeData)||empty($storeData['safe'])){
$notSafe=empty($storeData)?'安全检测失败,是否继续访问?':$storeData['msg'];
}
}
if(empty($url)){
$url='https://www.skycaiji.com/store';
}
if(!empty($url)){
$url=\skycaiji\admin\model\Provider::create_store_url(null,'store');
}
$GLOBALS['_sc']['p_name']=lang('store');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Mystore/store'),'title'=>lang('store'))));
$url.=(strpos($url,'?')===false?'?':'&').'clientinfo='.rawurlencode(g_sc('clientinfo'));
$this->assign('url',$url);
return $this->fetch();
if(empty($notSafe)){
$this->redirect($url);
}else{
set_g_sc('p_name',lang('store'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Mystore/store'),'title'=>lang('store')))));
$this->assign('storeInfo',array('url'=>$url,'notSafe'=>$notSafe));
return $this->fetch();
}
}
public function ruleAction(){
$mrule=model('Rule');
$type=input('type','collect');
@ -79,19 +96,22 @@ class Mystore extends BaseController {
foreach ($ruleList as $k=>$v){
$provList[$v['provider_id']]=$v['provider_id'];
}
$provList=model('Provider')->where('id','in',$provList)->column('*','id');
$mprov=model('Provider');
$provList=$mprov->where('id','in',$provList)->column('*','id');
foreach ($ruleList as $k=>$v){
$url='https://www.skycaiji.com';
$url='';
if(!empty($v['provider_id'])&&!empty($provList[$v['provider_id']])){
$url=$provList[$v['provider_id']]['url'];
$ruleList[$k]['_is_provider']=true;
}
$ruleList[$k]['store_url']=$url.'/client/rule/detail?id='.$v['store_id'];
$ruleList[$k]['_store_url']=\skycaiji\admin\model\Provider::create_store_url($url,'client/addon/rule',array('id'=>$v['store_id']));
}
}
$GLOBALS['_sc']['p_name']='已下载';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Mystore/rule'),'title'=>'已下载:'.lang('rule_'.$type))));
set_g_sc('p_title',lang('rule_'.$type));
set_g_sc('p_name','已下载');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Mystore/rule'),'title'=>'已下载:'.lang('rule_'.$type)))));
$this->assign('ruleList',$ruleList);
@ -117,7 +137,7 @@ class Mystore extends BaseController {
$this->success(lang('delete_success'));
}elseif($op=='deleteall'){
$ids=input('ids/a');
$ids=input('ids/a',array());
if(is_array($ids)&&count($ids)>0){
$mrule->where(array('id'=>array('in',$ids)))->delete();
}
@ -133,7 +153,7 @@ class Mystore extends BaseController {
}
}elseif($op=='check_store_update'){
$ids=input('ids/a');
$ids=input('ids/a',array());
if(!empty($ids)){
$ruleList=model('Rule')->where(array('id'=>array('in',$ids)))->select();
@ -163,21 +183,7 @@ class Mystore extends BaseController {
}
foreach ($provStoreIds as $provId=>$storeIds){
$url='';
$storeIds=implode(',',$storeIds);
$storeIds=rawurlencode($storeIds);
if(empty($provId)){
$url='https://www.skycaiji.com';
}elseif(!empty($provList[$provId])){
$url=$provList[$provId]['url'];
}
$url.='/client/rule/update?ids='.$storeIds;
$uptimeList=get_html($url,null,array('timeout'=>2));
$uptimeList=json_decode($uptimeList,true);
$uptimeList=$this->_get_store_uptimes($provList[$provId],'rule',$storeIds);
if(!empty($uptimeList)){
foreach ($uptimeList as $storeId=>$storeUptime){
@ -225,23 +231,28 @@ class Mystore extends BaseController {
$provList[$v['provider_id']]=$v['provider_id'];
}
}
$provList=model('Provider')->where('id','in',$provList)->column('*','id');
$mprov=model('Provider');
$provList=$mprov->where('id','in',$provList)->column('*','id');
foreach ($appList as $k=>$v){
$url='https://www.skycaiji.com';
$url='';
if(!empty($v['provider_id'])&&!empty($provList[$v['provider_id']])){
$url=$provList[$v['provider_id']]['url'];
$url=$provList[$v['provider_id']]['url'];
$appList[$k]['_is_provider']=true;
}
$appList[$k]['store_url']=$url.'/client/plugin/detail?app='.$v['app'];
$appList[$k]['_store_url']=\skycaiji\admin\model\Provider::create_store_url($url,'client/addon/plugin',array('app'=>$v['app']));
}
}
$GLOBALS['_sc']['p_name']='已下载';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Mystore/releaseApp'),'title'=>'已下载:发布插件')));
set_g_sc('p_title','发布插件');
set_g_sc('p_name','已下载');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Mystore/releaseApp'),'title'=>'已下载:发布插件'))));
$this->assign('appList',$appList);
return $this->fetch('releaseApp');
return $this->fetch('release_app');
}
public function releaseAppOpAction(){
$id=input('id/d',0);
@ -259,7 +270,7 @@ class Mystore extends BaseController {
$this->success(lang('delete_success'));
}elseif($op=='deleteall'){
$ids=input('ids/a');
$ids=input('ids/a',array());
if(is_array($ids)&&count($ids)>0){
foreach ($ids as $idv){
$this->_deleteReleaseApp($idv);
@ -271,7 +282,7 @@ class Mystore extends BaseController {
$this->_auto_check_plugin();
}elseif($op=='check_store_update'){
$ids=input('ids/a');
$ids=input('ids/a',array());
$appList=model('ReleaseApp')->where(array('module'=>'cms','id'=>array('in',$ids)))->column('*','app');
$updateList=$this->_check_store_plugin_update($appList);
@ -386,10 +397,57 @@ class Mystore extends BaseController {
}
}
}
$GLOBALS['_sc']['p_name']='应用程序';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Mystore/app'),'title'=>'应用程序')));
foreach ($dbApps as $k=>$v){
$storeUrl='';
if(!empty($provList[$v['provider_id']])){
$storeUrl=$provList[$v['provider_id']]['url'];
$dbApps[$k]['_is_provider']=true;
}
$dbApps[$k]['_store_url']=\skycaiji\admin\model\Provider::create_store_url($storeUrl,'client/addon/app',array('app'=>$k));
if(is_array($v['config'])){
if(is_array($v['config']['packs'])){
$dbApps[$k]['_nav_packs']=$mapp->convert_packs($v['config']['packs'],$v['app'],'nav');
}
$content='';
if($v['config']['author']){
$content='作者:'.htmlspecialchars($v['config']['author'],ENT_QUOTES);
}
if($v['config']['desc']){
$content.=($content?'<br>描述:':'').htmlspecialchars($v['config']['desc'],ENT_QUOTES);
}
$dbApps[$k]['_content']=$content;
}
}
foreach ($pathApps as $k=>$v){
$storeUrl='';
if(!empty($provList[$v['provider_id']])){
$storeUrl=$provList[$v['provider_id']]['url'];
$pathApps[$k]['_is_provider']=true;
}
$pathApps[$k]['_store_url']=\skycaiji\admin\model\Provider::create_store_url($storeUrl,'client/addon/app',array('app'=>$k));
if(is_array($v['config'])){
$content='';
if($v['config']['author']){
$content='作者:'.htmlspecialchars($v['config']['author'],ENT_QUOTES);
}
if($v['config']['desc']){
$content.=($content?'<br>描述:':'').htmlspecialchars($v['config']['desc'],ENT_QUOTES);
}
$pathApps[$k]['_content']=$content;
}
}
set_g_sc('p_title','应用程序');
set_g_sc('p_name','应用程序');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Mystore/app'),'title'=>'应用程序'))));
$this->assign('pagenav',$pagenav);
$this->assign('dbApps',$dbApps);
$this->assign('pathApps',$pathApps);
@ -412,7 +470,7 @@ class Mystore extends BaseController {
}
}elseif($op=='check_store_update'){
$apps=input('apps/a');
$apps=input('apps/a',array());
$mprov=model('Provider');
$appList=array();
@ -438,31 +496,13 @@ class Mystore extends BaseController {
$provList=$mprov->where('id','in',$provList)->column('*','id');
foreach($provApps as $provId=>$apps){
$apps=implode(',',$apps);
$apps=rawurlencode($apps);
$url='';
$appUrl='';
$isProv=false;
if(!empty($provList[$provId])){
$verList=$this->_get_store_uptimes($provList[$provId],'app',$apps);
if(!empty($verList)){
$url=$provList[$provId]['url'];
$isProv=true;
}else{
$url='https://www.skycaiji.com';
}
$appUrl=$url;
$url.='/client/app/update?apps='.$apps;
$storeList=get_html($url,null,array('timeout'=>2));
$storeList=json_decode($storeList,true);
if(!empty($storeList)){
foreach ($storeList as $storeApp=>$storeVer){
if(!empty($storeVer)&&version_compare($storeVer,$appList[$app]['version'],'>')){
foreach ($verList as $verK=>$verV){
if(!empty($verV)&&version_compare($verV,$appList[$app]['version'],'>')){
$updateList[]=array('app'=>$storeApp,'is_provider'=>$isProv,'app_url'=>$appUrl.'/client/app/detail?app='.rawurlencode($storeApp));
$updateList[]=$verK;
}
}
}
@ -471,7 +511,7 @@ class Mystore extends BaseController {
if(!empty($updateList)){
$this->success('',null,$updateList);
}else{
$this->error('无更新');
$this->error();
}
}
}
@ -504,20 +544,24 @@ class Mystore extends BaseController {
$provList[$v['provider_id']]=$v['provider_id'];
}
}
$provList=model('Provider')->where('id','in',$provList)->column('*','id');
$mprov=model('Provider');
$provList=$mprov->where('id','in',$provList)->column('*','id');
foreach ($appList as $k=>$v){
$url='https://www.skycaiji.com';
$url='';
if(!empty($v['provider_id'])&&!empty($provList[$v['provider_id']])){
$url=$provList[$v['provider_id']]['url'];
$url=$provList[$v['provider_id']]['url'];
$appList[$k]['_is_provider']=true;
}
$appList[$k]['store_url']=$url.'/client/plugin/detail?app='.$v['app'];
$appList[$k]['_store_url']=\skycaiji\admin\model\Provider::create_store_url($url,'client/addon/plugin',array('app'=>$v['app']));
}
}
$GLOBALS['_sc']['p_name']='已下载';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Mystore/funcApp'),'title'=>'已下载:函数插件')));
set_g_sc('p_title','函数插件');
set_g_sc('p_name','已下载');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Mystore/funcApp'),'title'=>'已下载:函数插件'))));
$this->assign('appList',$appList);
$this->assign('modules',$mfuncApp->funcModules);
@ -528,7 +572,7 @@ class Mystore extends BaseController {
$op=input('op');
$id=input('id');
$ops=array('item'=>array('delete','enable','detail'),'list'=>array('deleteall','check_store_update'),'else'=>array('auto_check'));
$ops=array('item'=>array('delete','enable','detail','method'),'list'=>array('deleteall','check_store_update'),'else'=>array('auto_check'));
if(!in_array($op,$ops['item'])&&!in_array($op,$ops['list'])&&!in_array($op,$ops['else'])){
$this->error(lang('invalid_op'));
@ -537,8 +581,20 @@ class Mystore extends BaseController {
$mfuncApp=new FuncApp();
$appData=$mfuncApp->where('id',$id)->find();
if($op=='detail'){
$appClass=empty($appData)?array():$mfuncApp->get_app_class($appData['module'], $appData['app']);
$this->success('',null,$appClass);
$appClass=empty($appData)?array():$mfuncApp->get_app_class($appData['module'], $appData['app'],array('comment_cut'=>1));
$this->success('',null,$appClass);
}elseif($op=='method'){
$methodName=input('name');
if(empty($methodName)){
$this->error('方法名为空');
}
$appClass=empty($appData)?array():$mfuncApp->get_app_class($appData['module'], $appData['app'],array('doc_comment'=>1,'method_code'=>1));
$methodData=$appClass['methods'][$methodName];
if(!is_array($methodData)){
$methodData=array();
}
$this->assign('methodData',$methodData);
return $this->fetch('func_method');
}elseif($op=='enable'){
$enable=input('enable/d');
$mfuncApp->where('id',$appData['id'])->update(array('enable'=>$enable));
@ -554,7 +610,7 @@ class Mystore extends BaseController {
$this->success('删除成功');
}elseif($op=='deleteall'){
$ids=input('ids/a');
$ids=input('ids/a',array());
if(is_array($ids)&&count($ids)>0){
foreach ($ids as $idv){
@ -576,7 +632,7 @@ class Mystore extends BaseController {
$this->_auto_check_plugin();
}elseif($op=='check_store_update'){
$ids=input('ids/a');
$ids=input('ids/a',array());
$appList=model('FuncApp')->where(array('id'=>array('in',$ids)))->column('*','app');
$updateList=$this->_check_store_plugin_update($appList);
@ -590,10 +646,7 @@ class Mystore extends BaseController {
/*导入插件*/
public function uploadAction(){
if(request()->isPost()){
if(!check_usertoken()){
$this->error(lang('usertoken_error'));
}
if($GLOBALS['_sc']['c']['site']['verifycode']){
if(g_sc_c('site','verifycode')){
$verifycode=trim(input('verifycode'));
$check=check_verify($verifycode);
@ -627,7 +680,7 @@ class Mystore extends BaseController {
$pluginDb=$mapp->where('app',$pluginData['app'])->find();
if(!empty($pluginDb)){
$this->error('插件已存在',null,array('js'=>"confirmRight('插件已存在,是否替换?',win_submit_replace)"));
$this->error('',null,array('js'=>"confirmRight('插件已存在,是否替换?',win_submit_replace)"));
}
}
@ -653,7 +706,7 @@ class Mystore extends BaseController {
$this->error('插件设置为手动检测更新');
}
}
/*检测插件云平台c插件更新*/
/*检测插件云平台插件更新*/
public function _check_store_plugin_update($appList=array()){
$appList1=array();
foreach ($appList as $k=>$v){
@ -678,18 +731,7 @@ class Mystore extends BaseController {
}
foreach ($provApps as $provId=>$apps){
$apps=implode(',',$apps);
$apps=rawurlencode($apps);
$url='https://www.skycaiji.com';
if(!empty($provId)&&!empty($provList[$provId])){
$url=$provList[$provId]['url'];
}
$url.='/client/plugin/update?apps='.$apps;
$uptimeList=get_html($url,null,array('timeout'=>2));
$uptimeList=json_decode($uptimeList,true);
$uptimeList=$this->_get_store_uptimes($provList[$provId], 'plugin', $apps);
if(!empty($uptimeList)){
foreach ($uptimeList as $app=>$uptime){
@ -703,4 +745,36 @@ class Mystore extends BaseController {
}
return $updateList;
}
public function _get_store_uptimes($provData,$addonCat,$addonIds){
$uptimeList=array();
if(!empty($addonCat)&&!empty($addonIds)){
$mprov=model('Provider');
$storeUrl=$mprov->getStoreUrl($provData);
$authkey=$mprov->getAuthkey($provData);
$timestamp=time();
$clientinfo=clientinfo();
$authsign=$mprov->createAuthsign($authkey,$clientinfo['url'],$storeUrl,$timestamp);
$postParams=array(
'authsign'=>$authsign,
'client_url'=>$clientinfo['url'],
'timestamp'=>$timestamp,
'addons'=>array(
$addonCat=>implode(',',$addonIds),
)
);
$uptimeList=curl_store($provData?$provData['url']:'','/client/addon/update',null,array('timeout'=>3),$postParams);
$uptimeList=json_decode($uptimeList,true);
if(is_array($uptimeList)&&$uptimeList['code']&&is_array($uptimeList['data'])){
$uptimeList=$uptimeList['data'][$addonCat];
$uptimeList=is_array($uptimeList)?$uptimeList:array();
}else{
$uptimeList=array();
}
}
return $uptimeList;
}
}

View File

@ -14,8 +14,8 @@ namespace skycaiji\admin\controller;
class Provider extends BaseController {
/*第三方平台*/
public function listAction(){
$url=input('url');
$title=input('title');
$url=input('url','');
$title=input('title','');
$mprovider=model('Provider');
@ -31,12 +31,19 @@ class Provider extends BaseController {
$pagenav=$list->render();
$list=$list->all();
$GLOBALS['_sc']['p_name']='第三方平台';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Provider/list'),'title'=>'第三方平台')));
set_g_sc('p_title','第三方平台');
set_g_sc('p_name','第三方平台');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Provider/list'),'title'=>'第三方平台'))));
$this->assign('cacheTip',cache('provider_tip_close'));
$this->assign('list',$list);
$this->assign('pagenav',$pagenav);
$this->assign('search',array(
'url'=>$url,
'title'=>$title
));
return $this->fetch();
}
public function deleteAction(){
@ -71,12 +78,15 @@ class Provider extends BaseController {
$this->assign('proData',$proData);
}
if(request()->isPost()){
$sameAsPwd=input('same_as_pwd');
$url=input('url','','strip_tags');
$title=input('title');
$sort=input('sort/d',0);
$sort=min($sort,999999);
$authkey=input('authkey','','trim');
$enable=input('enable/d',0);
$domain=\skycaiji\admin\model\Provider::match_domain($url);
$domain=\skycaiji\admin\model\Provider::match_domain_http($url);
if(empty($domain)){
$this->error('网址格式错误');
}
@ -100,6 +110,11 @@ class Provider extends BaseController {
$this->error($domain.' 域名已存在');
}
$check=$mprovider->checkAuthkey($authkey,$sameAsPwd);
if(!$check['success']){
$this->error($check['msg'],'',$check['data']);
}
if(empty($title)){
$html=get_html($url,null,array('timeout'=>3));
if(preg_match('/<title[^<>]*>(.*?)<\/title>/i', $html,$title)){
@ -113,6 +128,7 @@ class Provider extends BaseController {
'url'=>$url,
'title'=>$title,
'domain'=>$domain,
'authkey'=>$authkey,
'enable'=>$enable,
'sort'=>$sort
);
@ -131,13 +147,76 @@ class Provider extends BaseController {
}
public function saveallAction(){
$newsort=input('newsort/a');
$newsort=input('newsort/a',array());
$mprovider=model('Provider');
if(is_array($newsort)&&count($newsort)>0){
foreach ($newsort as $key=>$val){
$mprovider->strict(false)->where('id',intval($key))->update(array('sort'=>intval($val)));
$val=min(intval($val),999999);
$mprovider->strict(false)->where('id',intval($key))->update(array('sort'=>$val));
}
}
$this->success('保存成功','Provider/list');
}
public function tip_closeAction(){
cache('provider_tip_close',1);
$this->success();
}
public function authkeysAction(){
$url=input('url','');
$title=input('title','');
$mprovider=model('Provider');
$cond=array();
if(!empty($url)){
$cond['url']=array('like','%'.$url.'%');
}
if(!empty($title)){
$cond['title']=array('like','%'.$title.'%');
}
$list=$mprovider->where($cond)->order('sort desc')->paginate(20,false,paginate_auto_config());
$pagenav=$list->render();
$list=$list->all();
$this->assign('list',$list);
$this->assign('pagenav',$pagenav);
$this->assign('search',array(
'url'=>$url,
'title'=>$title
));
return $this->fetch();
}
public function authkeys_saveAction(){
if(request()->isPost()){
$sameAsPwd=input('same_as_pwd');
$authkeys=input('authkeys/a','','trim');
$authkeys=is_array($authkeys)?$authkeys:array();
$mprov=model('Provider');
foreach ($authkeys as $provId=>$authkey){
$check=$mprov->checkAuthkey($authkey,$sameAsPwd);
if(!$check['success']){
$check['data']['prov_id']=$provId;
$this->error($check['msg'],'',$check['data']);
}
}
foreach ($authkeys as $provId=>$authkey){
model('Provider')->strict(false)->where('id',$provId)->update(array('authkey'=>$authkey));
}
$this->success('修改成功');
}else{
$this->error('操作失败');
}
}
}

View File

@ -132,19 +132,20 @@ class Proxy extends BaseController {
$mproxy=model('Proxyip');
$proxyTypes=$mproxy->proxy_types();
if(request()->isPost()){
$ip_list=input('ip_list/a','','trim');
$user_list=input('user_list/a','','trim');
$pwd_list=input('pwd_list/a','','trim');
$type_list=input('type_list/a','','trim');
$ip_list=input('ip_list/a',array(),'trim');
$user_list=input('user_list/a',array(),'trim');
$pwd_list=input('pwd_list/a',array(),'trim');
$type_list=input('type_list/a',array(),'trim');
if(!empty($ip_list)){
$nowTime=time();
foreach($ip_list as $k=>$v){
$newData=array(
'ip'=>$v,
'user'=>$user_list[$k],
'pwd'=>$pwd_list[$k],
'type'=>$type_list[$k],
'addtime'=>NOW_TIME
'addtime'=>$nowTime
);
$mproxy->db()->strict(false)->insert($newData,true);
}
@ -210,16 +211,16 @@ class Proxy extends BaseController {
}
}
/*清理无效ip*/
public function clearInvalidAction(){
$mproxy=model('Proxyip');
$mproxy->where('invalid',1)->delete();
$this->success('清理完成','Setting/proxy');
}
/*测试代理接口*/
public function testApiAction(){
$config=input('config/a','','trim');
$config=input('config/a',array(),'trim');
$mproxy=model('Proxyip');
$html=get_html($config['api_url']);

View File

@ -25,7 +25,7 @@ class Release extends BaseController{
}
$releData=$mrele->where(array('task_id'=>$taskData['id']))->find();
if(request()->isPost()){
$newData=array('task_id'=>$taskData['id'],'addtime'=>NOW_TIME,'config'=>array());
$newData=array('task_id'=>$taskData['id'],'addtime'=>time(),'config'=>array());
if($releaseId>0){
$importRele=$mrele->where(array('id'=>$releaseId))->find();
@ -60,17 +60,31 @@ class Release extends BaseController{
$this->error(lang('op_failed'));
}
}else{
$GLOBALS['_sc']['p_name']=lang('rele_set');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Task/edit?id='.$taskData['id']),'title'=>lang('task').lang('separator').$taskData['name']),array('url'=>url('Release/set?task_id='.$taskData['id']),'title'=>lang('rele_set'))));
set_g_sc('p_title',lang('rele_set').'_任务:'.$taskData['name']);
set_g_sc('p_name',lang('rele_set'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Task/edit?id='.$taskData['id']),'title'=>lang('task').lang('separator').$taskData['name']),array('url'=>url('Release/set?task_id='.$taskData['id']),'title'=>lang('rele_set')))));
$this->assign('taskData',$taskData);
if(!empty($releData)){
$releData=$releData->toArray();
$releData['config']=unserialize($releData['config']);
$config=$releData['config'];
$this->assign('config',$config);
$this->assign('releData',$releData);
}else{
$releData=array();
}
if(!is_array($releData['config'])){
$releData['config']=array();
}
foreach (config('release_modules') as $v){
if(!is_array($releData['config'][$v])){
$releData['config'][$v]=array();
}
}
$this->assign('config',$releData['config']);
$this->assign('releData',$releData);
$apiRootUrl=config('root_website');
if(stripos(\think\Request::instance()->root(),'/index.php?s=')!==false){
@ -166,7 +180,7 @@ class Release extends BaseController{
* 设置可不先入库进行测试绑定
* */
public function cmsBindAction(){
$cmsSet=input('cms/a');
$cmsSet=input('cms/a',array());
$taskId=input('task_id/d',0);
$cmsPath=$cmsSet['path'];
if(empty($cmsPath)){
@ -176,7 +190,13 @@ class Release extends BaseController{
$acms=controller('admin/Rcms','event');
$cmsName=$acms->cms_name($cmsPath);
if(empty($cmsName)){
$this->error('未知的cms程序请确保路径存在如需指定CMS程序请在路径结尾加上@CMS程序名例如@discuz');
list($cmsPath,$cmsName)=explode('@', $cmsPath);
$msg='未知的cms程序请确保路径存在如需指定CMS程序请在路径结尾加上@CMS程序名例如@discuz';
if(\skycaiji\admin\model\Config::check_basedir_limited($cmsPath)){
$msg.='<br/>注意:'.lang('error_open_basedir');
}
$this->error($msg);
}
$cmsApp=$cmsSet['app'];
@ -221,44 +241,54 @@ class Release extends BaseController{
$this->assign('cmsApp',$cmsApp);
return $this->fetch('cmsBind');
}
public function testAction(){
set_time_limit(600);
$releId=input('id/d',0);
$releData=model('Release')->getById($releId);
if(empty($releData)){
$this->echo_msg(lang('rele_error_empty_rele'));
exit();
}
$taskData=model('Task')->getById($releData['task_id']);
if(empty($taskData)){
$this->echo_msg(lang('task_error_empty_task'));
exit();
}
model('Task')->loadConfig($taskData);
$collData=model('Collector')->where(array('task_id'=>$taskData['id'],'module'=>$taskData['module']))->find();
if(empty($collData)){
$this->echo_msg(lang('coll_error_empty_coll'));
exit();
}
$acoll=controller('admin/C'.$collData['module'],'event');
$acoll->init($collData);
$fieldsList=$acoll->collect(1);
if(empty($fieldsList)||!is_array($fieldsList)){
$this->echo_msg('没有采集到数据','orange');
}else{
$releObj=controller('admin/R'.strtolower($releData['module']),'event');
$releObj->init($releData);
if('api'==$releData['module']){
$releObj->config['api']['cache_time']=0;
}
$releObj->export($fieldsList);
}
set_time_limit(600);
$releId=input('id/d',0);
$this->_backstage_cli_collect('test --rele_id '.$releId);
$releData=model('Release')->getById($releId);
if(empty($releData)){
$this->echo_msg_exit(lang('rele_error_empty_rele'));
}
$mtask=model('Task');
$taskData=$mtask->getById($releData['task_id']);
if(empty($taskData)){
$this->echo_msg_exit(lang('task_error_empty_task'));
}
if(input('?backstage')){
$mtask->backstage_task($taskData['id']);
}
$mtask->loadConfig($taskData);
$collData=model('Collector')->where(array('task_id'=>$taskData['id'],'module'=>$taskData['module']))->find();
if(empty($collData)){
$this->echo_msg_exit(lang('coll_error_empty_coll'));
}
$acoll=controller('admin/C'.$collData['module'],'event');
$acoll->init($collData);
$fieldsList=$acoll->collect(1);
if(empty($fieldsList)||!is_array($fieldsList)){
$this->echo_msg('没有采集到数据','orange');
}else{
$releObj=controller('admin/R'.strtolower($releData['module']),'event');
$releObj->init($releData);
if('api'==$releData['module']){
$releObj->config['api']['cache_time']=0;
}
$releObj->doExport($fieldsList);
}
$this->_echo_msg_end();
}
/*读取数据库表*/
public function dbTablesAction(){
@ -285,7 +315,7 @@ class Release extends BaseController{
/*测试连接数据库*/
public function dbConnectAction(){
$op=input('op');
$db=input('db/a','','trim');
$db=input('db/a',array(),'trim');
$no_check=array('db_pwd');
if('db_names'==$op){

View File

@ -19,11 +19,15 @@ class Setting extends BaseController {
if(request()->isPost()){
$config=array();
$config['verifycode']=input('verifycode/d',0);
$config['verifycode_len']=input('verifycode_len/d',0);
$config['hidehome']=input('hidehome/d',0);
$config['closelog']=input('closelog/d',0);
$config['dblong']=input('dblong/d',0);
$config['login']=input('login/a');
$config['login']=input('login/a',array());
$config['closetrans']=input('closetrans/d',0);
$config['timezone']=input('timezone','');
$config['verifycode_len']=min(max(3,$config['verifycode_len']),20);
if($config['login']['limit']){
@ -38,13 +42,39 @@ class Setting extends BaseController {
$mconfig->setConfig('site',$config);
$this->success(lang('op_success'),'Setting/site');
}else{
$GLOBALS['_sc']['p_name']=lang('setting_site');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Setting/site'),'title'=>lang('setting_site'))));
set_g_sc('p_title',lang('setting_site'));
set_g_sc('p_name',lang('setting_site'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Setting/site'),'title'=>lang('setting_site')))));
$siteConfig=$mconfig->getConfig('site','data');
$this->assign('showTime','服务器时间:'.date('Y-m-d H:i:s').' , 服务器的协调世界时(UTC)'.gmdate('Y-m-d H:i:s'));
$this->assign('siteConfig',$siteConfig);
}
return $this->fetch();
}
public function site_timezoneAction(){
if(request()->isPost()){
$offset=input('offset/d',0);
$jsTime=input('time',0);
$jsTime=$jsTime?intval(substr($jsTime,0,-3)):0;
if($jsTime<=0){
$this->error('时间错误');
}
if(abs(time()-$jsTime)>60){
$this->error('抱歉,您的服务器时间与实际时间不符!');
}
$timezone='';
if($offset==0){
$timezone='UTC';
}else{
$timezone='UTC'.($offset>0?'-':'+').abs($offset);
}
$this->success('','',array('timezone'=>$timezone));
}else{
$this->error('自动调整失败');
}
}
/*采集设置*/
public function caijiAction(){
$mconfig=model('Config');
@ -69,18 +99,23 @@ class Setting extends BaseController {
$config['num']=input('num/d',0);
$config['interval']=input('interval/d',0);
$config['timeout']=input('timeout/d',0);
$config['html_interval']=input('html_interval/d',0);
$config['interval_html']=input('interval_html/d',0);
$config['real_time']=input('real_time/d',0);
$config['retry']=input('retry/d',0);
$config['wait']=input('wait/d',0);
unset($config['download_img']);
if($config['server']=='cli'){
if($mconfig->server_is_cli(true,$config['server'])){
$this->_check_userpwd();
if(!function_exists('proc_open')){
$this->error('抱歉cli命令行模式需开启proc_open函数');
}
}
$mconfig->setConfig('caiji',$config);
if($config['auto']){
@ -88,18 +123,24 @@ class Setting extends BaseController {
if($config['run']=='backstage'){
$runkey=md5(time().rand(1, 1000000));
CacheModel::getInstance()->setCache('admin_index_backstage_key', $runkey);
CacheModel::getInstance()->setCache('collect_backstage_key', $runkey);
@get_html(url('Admin/Index/backstage?key='.$runkey,null,false,true),null,array('timeout'=>3));
}
}
$this->success(lang('op_success'),'Setting/caiji');
}else{
$GLOBALS['_sc']['p_name']=lang('setting_caiji');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji'))));
set_g_sc('p_title',lang('setting_caiji'));
set_g_sc('p_name',lang('setting_caiji'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')))));
$caijiConfig=$mconfig->getConfig('caiji','data');
$caijiConfig=is_array($caijiConfig)?$caijiConfig:array();
if($caijiConfig['html_interval']>0){
$caijiConfig['interval_html']=intval($caijiConfig['html_interval'])*1000;
}
$phpExeFile=$mconfig->detect_php_exe();
$phpExeFile=\skycaiji\admin\model\Config::detect_php_exe();
$this->assign('caijiConfig',$caijiConfig);
$this->assign('phpExeFile',$phpExeFile);
@ -111,15 +152,41 @@ class Setting extends BaseController {
$mconfig=model('Config');
if(request()->isPost()){
$config=array();
$config['download_img']=input('download_img/d',0);
$config['data_image']=input('data_image/d',0);
$config['interval_img']=input('interval_img/d',0);
$config['img_timeout']=input('img_timeout/d',0);
$config['more_suffix']=input('more_suffix','');
$config['retry']=input('retry/d',0);
$config['wait']=input('wait/d',0);
$config['img_path']=trim(input('img_path',''));
$config['img_url']=input('img_url','','trim');
$config['img_name']=input('img_name','');
$config['img_timeout']=input('img_timeout/d',0);
$config['img_interval']=input('img_interval/d',0);
$config['img_max']=input('img_max/d',0);
$config['name_custom_path']=input('name_custom_path','');
$config['name_custom_name']=input('name_custom_name','');
$config['charset']=input('charset','');
$config['charset_custom']=input('charset_custom','');
$config['img_max']=input('img_max/d',0);
$config['img_func']=input('img_func','');
$config['img_func_param']=input('img_func_param','');
if(!empty($config['more_suffix'])){
if(preg_match_all('/\b[a-zA-Z]\w+\b/i', $config['more_suffix'],$msuffix)){
$msuffix=$msuffix[0];
$msuffix=implode(',', $msuffix);
$config['more_suffix']=strtolower($msuffix);
}else{
$config['more_suffix']='';
}
}
if(!empty($config['img_path'])){
$checkImgPath=$mconfig->check_img_path($config['img_path']);
@ -127,6 +194,7 @@ class Setting extends BaseController {
$this->error($checkImgPath['msg']);
}
}
if(!empty($config['img_url'])){
$checkImgUrl=$mconfig->check_img_url($config['img_url']);
@ -135,6 +203,7 @@ class Setting extends BaseController {
}
}
$checkNamePath=$mconfig->check_img_name_path($config['name_custom_path']);
if($config['img_name']=='custom'){
@ -164,18 +233,44 @@ class Setting extends BaseController {
}
}
if($config['charset']=='custom'&&empty($config['charset_custom'])){
$this->error('请输入系统编码自定义内容');
}
$mconfig->setConfig('download_img',$config);
$this->success(lang('op_success'),'Setting/download_img');
}else{
$GLOBALS['_sc']['p_name']='图片本地化设置';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')),array('url'=>url('Setting/download_img'),'title'=>'图片本地化')));
set_g_sc('p_title','图片本地化设置');
set_g_sc('p_name','图片本地化设置');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')),array('url'=>url('Setting/download_img'),'title'=>'图片本地化'))));
$imgConfig=$mconfig->getConfig('download_img','data');
if(empty($imgConfig)){
$caijiConfig=$mconfig->getConfig('caiji','data');
$imgConfig=$mconfig->get_img_config_from_caiji($caijiConfig);
}
if(!is_array($imgConfig)){
$imgConfig=array();
}
if(empty($imgConfig)){
$imgConfig['img_timeout']=0;
$imgConfig['img_max']=0;
$imgConfig['interval_img']=0;
$imgConfig['wait']=0;
$imgConfig['retry']=0;
}else{
if($imgConfig['img_interval']>0){
$imgConfig['interval_img']=$imgConfig['img_interval']*1000;
}
}
$this->assign('imgConfig',$imgConfig);
return $this->fetch('download_img');
}
@ -218,6 +313,7 @@ class Setting extends BaseController {
$type_list=array_map('trim', $type_list);
$nowTime=time();
for($k=count($ip_list);$k>=0;$k--){
$v=$ip_list[$k];
if(empty($v)){
@ -233,7 +329,7 @@ class Setting extends BaseController {
'failed'=>0,
'num'=>0,
'time'=>0,
'addtime'=>NOW_TIME,
'addtime'=>$nowTime,
);
if($mproxy->where(array('ip'=>$newData['ip']))->count()>0){
@ -248,8 +344,8 @@ class Setting extends BaseController {
}
$config['api']=input('api/a','','trim');
$config['apis']=input('apis/a','','trim');
$config['api']=input('api/a',array(),'trim');
$config['apis']=input('apis/a',array(),'trim');
$config['apis']=is_array($config['apis'])?$config['apis']:array();
foreach ($config['apis'] as $k=>$v){
if(empty($v['api_url'])||!preg_match('/^\w+\:\/\//',$v['api_url'])){
@ -262,8 +358,9 @@ class Setting extends BaseController {
$mconfig->setConfig('proxy',$config);
$this->success(lang('op_success'),'Setting/Proxy');
}else{
$GLOBALS['_sc']['p_name']='代理设置';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')),array('url'=>url('Setting/Proxy'),'title'=>'代理')));
set_g_sc('p_title','代理设置');
set_g_sc('p_name','代理设置');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')),array('url'=>url('Setting/Proxy'),'title'=>'代理'))));
$proxyConfig=$mconfig->getConfig('proxy','data');
$proxyConfig['ip_count']=$mproxy->count();
@ -280,10 +377,13 @@ class Setting extends BaseController {
$config=array();
$config['open']=input('open/d',0);
$config['api']=input('api','','strtolower');
$config['pass_html']=input('pass_html/d',0);
$config['interval']=input('interval/d',0);
$config['retry']=input('retry/d',0);
$config['wait']=input('wait/d',0);
foreach ($apiTypes as $v){
$config[$v]=input($v.'/a',null,'trim');
$config[$v]=input($v.'/a',array(),'trim');
}
if(!empty($config['api'])){
@ -300,9 +400,13 @@ class Setting extends BaseController {
$mconfig->setConfig('translate',$config);
$this->success(lang('op_success'),'Setting/translate');
}else{
$GLOBALS['_sc']['p_name']='翻译设置';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')),array('url'=>url('Setting/translate'),'title'=>'翻译')));
set_g_sc('p_title','翻译设置');
set_g_sc('p_name','翻译设置');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')),array('url'=>url('Setting/translate'),'title'=>'翻译'))));
$transConfig=$mconfig->getConfig('translate','data');
if(!is_array($transConfig)){
$transConfig=array();
}
$apiLangs=array();
foreach ($apiTypes as $api){
$transConfig[$api]=is_array($transConfig[$api])?$transConfig[$api]:array();
@ -318,6 +422,45 @@ class Setting extends BaseController {
return $this->fetch();
}
}
/*云端设置*/
public function storeAction(){
$mconfig=model('Config');
if(request()->isPost()){
$sameAsPwd=input('same_as_pwd');
$config=array();
$config['authkey']=input('authkey','','trim');
$config['authkey_store']=input('authkey_store','','trim');
$mprov=model('Provider');
$check=$mprov->checkAuthkey($config['authkey'],$sameAsPwd);
if(!$check['success']){
$this->error($check['msg'],'',$check['data']);
}
$check=$mprov->checkAuthkey($config['authkey_store'],$sameAsPwd);
if(!$check['success']){
$this->error($check['msg'],'',$check['data']);
}
$mconfig->setConfig('store',$config);
$this->success(lang('op_success'),'Setting/store');
}else{
set_g_sc('p_title',lang('setting_store'));
set_g_sc('p_name',lang('setting_store'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Setting/store'),'title'=>lang('setting_store')))));
$storeConfig=$mconfig->getConfig('store','data');
if(empty($storeConfig)){
$storeConfig=array();
}
$provCount=model('Provider')->count();
$provCount=intval($provCount);
$this->assign('storeConfig',$storeConfig);
$this->assign('provCount',$provCount);
}
return $this->fetch();
}
/*邮箱设置*/
public function emailAction(){
$is_test=input('is_test/d',0);
@ -344,43 +487,36 @@ class Setting extends BaseController {
$this->success(lang('op_success'),'Setting/email');
}
}else{
$GLOBALS['_sc']['p_name']=lang('setting_email');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Setting/email'),'title'=>lang('setting_email'))));
set_g_sc('p_title',lang('setting_email'));
set_g_sc('p_name',lang('setting_email'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Setting/email'),'title'=>lang('setting_email')))));
$emailConfig=$mconfig->getConfig('email','data');
if(empty($emailConfig)){
$emailConfig=array();
}
$this->assign('emailConfig',$emailConfig);
}
return $this->fetch();
}
/*页面渲染设置*/
public function page_renderAction(){
$is_test=input('is_test/d',0);
$mconfig=model('Config');
if(request()->isPost()){
$config=array();
$config['tool']=strtolower(input('tool'));
$config['chrome']=input('chrome/a');
$config['chrome']=input('chrome/a',array());
$config['timeout']=input('timeout/d');
if(!in_array($config['tool'],array('chrome'))){
$config['tool']='';
}
if(empty($config['tool'])){
if(!empty($config['tool'])){
$this->_check_userpwd();
}
if($config['tool']=='chrome'){
if(version_compare(PHP_VERSION,'5.5','<')){
$this->error('该功能仅支持php5.5及以上版本');
}
if($config['chrome']['port']==80){
$this->error('不能设置为80端口','');
}
}
$mconfig->setConfig('page_render',$config);
if($config['tool']=='chrome'){
set_time_limit(10);
$chromeSoket=new \util\ChromeSocket($config['chrome']['host'],$config['chrome']['port'],$config['timeout'],$config['chrome']['filename']);
$chromeSoket=new \util\ChromeSocket($config['chrome']['host'],$config['chrome']['port'],$config['timeout'],$config['chrome']['filename'],$config['chrome']);
try {
$chromeSoket->openHost();
}catch (\Exception $ex){
@ -389,15 +525,16 @@ class Setting extends BaseController {
}
$this->success(lang('op_success'),'Setting/page_render');
}else{
$GLOBALS['_sc']['p_name']='页面渲染设置 <small><a href="https://www.skycaiji.com/manual/doc/page_render" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')),array('url'=>url('Setting/page_render'),'title'=>'页面渲染')));
set_g_sc('p_title','页面渲染设置');
set_g_sc('p_name','页面渲染设置 <small><a href="https://www.skycaiji.com/manual/doc/page_render" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji')),array('url'=>url('Setting/page_render'),'title'=>'页面渲染'))));
$config=$mconfig->getConfig('page_render','data');
$this->assign('config',$config);
if($config['tool']=='chrome'){
if($mconfig->page_render_is_chrome(true,$config['tool'])){
$cConfig=$config['chrome'];
$chromeSoket=new \util\ChromeSocket($cConfig['host'],$cConfig['port'],$config['timeout'],$cConfig['filename']);
$chromeSoket=new \util\ChromeSocket($cConfig['host'],$cConfig['port'],$config['timeout'],$cConfig['filename'],$cConfig);
$toolIsOpen=$chromeSoket->hostIsOpen();
$this->assign('toolIsOpen',$toolIsOpen);
}
@ -406,9 +543,84 @@ class Setting extends BaseController {
}
/*清理缓存目录*/
public function cleanAction(){
set_time_limit(1000);
$path=realpath(config('root_path').'/runtime');
clear_dir($path);
$this->success();
if(request()->isPost()){
set_time_limit(1000);
$path=realpath(config('root_path').'/runtime');
\util\Funcs::clear_dir($path);
$this->success();
}else{
$this->error();
}
}
private function _check_userpwd(){
if(!input('?_userpwd_')){
$this->error('','',array('_userpwd_'=>true));
}
$userpwd=input('_userpwd_','');
if(empty($userpwd)){
$this->error('请输入密码','',array('_userpwd_'=>true));
}
$user=g_sc('user');
if(empty($user)){
$this->error('请先登录');
}
if(\skycaiji\admin\model\User::pwd_encrypt($userpwd,$user['salt'])!=$user['password']){
$this->error('密码错误','',array('_userpwd_'=>true));
}
}
/*测试php*/
public function test_phpAction(){
if(request()->isPost()){
$this->_check_userpwd();
if(!function_exists('proc_open')){
$this->error('需开启proc_open函数');
}else{
$phpFile=input('php','','trim');
$phpvInfo=model('Config')->exec_php_version($phpFile);
if($phpvInfo===false){
$this->error('未检测到PHP可执行文件请手动输入');
}else{
if($phpvInfo['success']){
$this->success($phpvInfo['msg']?$phpvInfo['msg']:'测试成功');
}else{
$this->error($phpvInfo['msg']?$phpvInfo['msg']:'测试失败');
}
}
}
}
$this->error('测试失败');
}
/*测试chrome*/
public function test_chromeAction(){
if(request()->isPost()){
$this->_check_userpwd();
$chrome=input('chrome/a',array());
$return=\util\ChromeSocket::execHeadless($chrome['filename'], $chrome['port'], $chrome, 'all', true);
if(!empty($return['error'])){
$this->error($return['error']);
}else{
$info=is_array($return['info'])?$return['info']:array();
if(is_array($info['status'])&&$info['status']['running']){
if($info['error']){
$this->error($info['error']);
}elseif($info['output']){
$this->success('测试成功:'.$info['output']);
}else{
$this->success('测试成功');
}
}elseif($info['error']){
$this->error($info['error']);
}
}
}
$this->error('测试失败');
}
}

View File

@ -10,249 +10,235 @@
*/
namespace skycaiji\admin\controller;
use think\Controller;
class Store extends BaseController {
public function downloadAction(){
$mprov=model('Provider');
$resultData=$mprov->storeAuthResult();
if(!$resultData['success']){
$this->error($resultData['msg'],'');
}
$resultData=$resultData['data'];
$provId=$resultData['provider_id'];
$storeAddon=input('store_addon','','trim');
$storeAddon=json_decode(base64_decode($storeAddon),true);
if(!is_array($storeAddon)||empty($storeAddon)){
$this->error('下载参数错误','');
}
$storeAddon=array_map('strip_tags', $storeAddon);
list($addonCat,$addonId,$addonVer,$addonName)=$storeAddon;
$addonCat=strtolower($addonCat);
$cats=array('rule'=>'采集规则','plugin'=>'插件','app'=>'应用程序');
$catName=$cats[$addonCat];
$existAddon=false;
$updateAddon=false;
if(in_array($addonCat, array('rule','plugin'))){
if('rule'==$addonCat){
$addonData=model('Rule')->where(array('store_id'=>$addonId,'provider_id'=>$provId))->find();
}elseif('plugin'==$addonCat){
$addonData=model('ReleaseApp')->where('app',$addonId)->find();
if(empty($addonData)){
model('FuncApp')->where('app',$addonId)->find();
}
}
if(!empty($addonData)){
$existAddon=true;
if($addonVer&&version_compare($addonVer, $addonData['uptime'],'>')){
$updateAddon=true;
}
}
}elseif('app'==$addonCat){
$mapp=model('App');
$existAddon=file_exists($mapp->app_class_file($addonId))?true:false;
if($existAddon){
$appVersion=$mapp->app_class($addonId,false,'version');
if($addonVer&&version_compare($addonVer, $appVersion,'>')){
$updateAddon=true;
}
}
}
$tips=$updateAddon?'更新':'下载';
set_g_sc('p_title',$tips.$catName);
set_g_sc('p_name',$tips.$catName);
set_g_sc('p_nav',breadcrumb(array($tips.$catName)));
$downloadData = array(
'provider_id' => $provId,
'addon_cat' => $addonCat,
'addon_id' => $addonId,
'addon_name' => $addonName,
'exist_addon' => $existAddon,
'update_addon' => $updateAddon,
'cat_name' => $catName
);
$this->assign('downloadData',$downloadData);
return $this->fetch();
}
public function installAction(){
$this->check_usertoken();
$provId=input('provider_id/d',0);
$addonCat=input('addon_cat','','strtolower');
$addonId=input('addon_id','','trim');
$provData=null;
$mprov=model('Provider');
if($provId>0){
$provData=$mprov->getById($provId);
$check=$mprov->checkData($provData);
if(!$check['success']){
$this->error($check['msg']);
}
}
$provId=empty($provData)?0:$provData['id'];
$authkey=$mprov->getAuthkey($provData);
$storeUrl=$mprov->getStoreUrl($provData);
$timestamp=time();
$clientinfo=clientinfo();
$authsign=$mprov->createAuthsign($authkey,$clientinfo['url'],$storeUrl,$timestamp);
$uriParams=array(
'authsign'=>$authsign,
'client_url'=>$clientinfo['url'],
'timestamp'=>$timestamp,
'addon'=>$addonCat.':'.$addonId,
);
if($addonCat=='app'){
$blockNo=input('block_no/d',0);
$uriParams['block_no']=$blockNo;
}
$storeData=curl_store($provData?$provData['url']:'','/client/addon/download?'.http_build_query($uriParams));
$storeData=json_decode($storeData,true);
$storeData=is_array($storeData)?$storeData:array();
$storeData['data']=is_array($storeData['data'])?$storeData['data']:array();
if(!$storeData['code']){
$this->error('下载失败'.($storeData['msg']?(''.$storeData['msg']):''));
}
$result=array();
$successUrl='';
$successData=array();
if($addonCat=='rule'){
$rule=$storeData['data']['rule'];
$rule=json_decode(base64_decode($rule),true);
$result=$this->_installRule($rule,$provId);
$successUrl='Mystore/rule';
}elseif($addonCat=='plugin'){
$plugin=$storeData['data']['plugin'];
$plugin=json_decode(base64_decode($plugin),true);
$result=$this->_installPlugin($plugin,$provId);
$successUrl='Mystore/'.$plugin['type'].'App';
}elseif($addonCat=='app'){
$app=$storeData['data']['app'];
$app=json_decode(base64_decode($app),true);
$result=$this->_installApp($app,$provId);
$successUrl='Mystore/app';
$successData=$result;
}
if($result['success']){
$this->success('下载完成',$successUrl,$successData);
}else{
$this->error('安装失败'.($result['msg']?(''.$result['msg']):''));
}
}
private function _installRule($rule,$provId=0){
$result=array('success'=>false,'msg'=>'');
$rule=is_array($rule)?$rule:array();
$rule=array_map('strip_tags', $rule);
$store_id=intval($rule['store_id']);
if($store_id<=0){
$result['msg']='规则id为空';
return $result;
}
if(empty($rule['name'])){
$result['msg']='规则名称为空';
return $result;
}
if(empty($rule['type'])){
$result['msg']='规则类型为空';
return $result;
}
if(empty($rule['module'])){
$result['msg']='规则模块为空';
return $result;
}
$rule['config']=base64_decode($rule['config']);
if(empty($rule['config'])){
$result['msg']='规则为空';
return $result;
}
$newRule=array('type'=>$rule['type'],'module'=>$rule['module'],'store_id'=>$store_id,'name'=>$rule['name'],'uptime'=>($rule['uptime']>0?$rule['uptime']:time()),'config'=>$rule['config']);
$mrule=model('Rule');
if(!empty($rule['store_url'])){
$newRule['provider_id']=model('Provider')->getIdByUrl($rule['store_url']);
}else{
$newRule['provider_id']=intval($provId);
}
$ruleData=$mrule->where(array('store_id'=>$newRule['store_id'],'provider_id'=>$newRule['provider_id']))->find();
if(empty($ruleData)){
$newRule['addtime']=time();
$mrule->isUpdate(false)->allowField(true)->save($newRule);
}else{
$mrule->strict(false)->where(array('id'=>$ruleData['id']))->update($newRule);
}
$result['success']=true;
return $result;
}
public function isLoginAction(){
if(empty($GLOBALS['_sc']['user'])){
$this->dispatchJump(false,lang('user_error_is_not_admin'),url('Admin/Index/index',null,null,true));
}else{
$token=$this->_getToken();
if(empty($token)){
$token=md5(request()->server('HTTP_ORIGIN').date('Y-m-d H:i:s',time()).rand(1,1000000));
session('store_token',array('token'=>$token,time=>time()));
}
$this->dispatchJump(true,$token);
}
}
/*安装规则*/
public function installRuleAction(){
$this->_checkRequest();
$mrule=model('Rule');
$rule=json_decode(base64_decode(input('post.rule')),true);
$store_id=intval($rule['store_id']);
if(empty($store_id)){
$this->dispatchJump(false,'规则id为空');
}
if(empty($rule['name'])){
$this->dispatchJump(false,'名称为空');
}
if(empty($rule['type'])){
$this->dispatchJump(false,'类型错误');
}
if(empty($rule['module'])){
$this->dispatchJump(false,'模块错误');
}
$rule['config']=base64_decode($rule['config']);
if(empty($rule['config'])){
$this->dispatchJump(false,'规则为空');
}
if($store_id>0){
$newRule=array('type'=>$rule['type'],'module'=>$rule['module'],'store_id'=>$store_id,'name'=>$rule['name'],'uptime'=>($rule['uptime']>0?$rule['uptime']:time()),'config'=>$rule['config']);
$newRule['provider_id']=$this->_getStoreProvid($rule['store_url']);
$ruleData=$mrule->where(array('store_id'=>$newRule['store_id'],'provider_id'=>$newRule['provider_id']))->find();
if(empty($ruleData)){
$newRule['addtime']=NOW_TIME;
$mrule->isUpdate(false)->allowField(true)->save($newRule);
$ruleId=$mrule->id;
}else{
$mrule->strict(false)->where(array('id'=>$ruleData['id']))->update($newRule);
$ruleId=$ruleData['id'];
}
$this->dispatchJump(true,$ruleId);
}else{
$this->dispatchJump(false,'id错误');
}
}
/*安装插件*/
public function installPluginAction(){
$this->_checkRequest();
$plugin=json_decode(base64_decode(input('post.plugin')),true);
$result=$this->_installPlugin($plugin);
$this->dispatchJump($result['success'],$result['msg']);
}
/*安装应用程序*/
public function installAppAction(){
$this->_checkRequest();
$app=json_decode(base64_decode(input('post.app')),true);
if(empty($app['app'])){
$this->dispatchJump(false,'app标识错误');
}
if(!preg_match('/^[\w\-]+$/',$app['app'])){
$this->dispatchJump(false,'app标识不规范');
}
if(empty($app['data'])){
$this->dispatchJump(false,'数据错误');
}
$app['data']=base64_decode($app['data']);
$filePath=RUNTIME_PATH.'/cache_app_zip/'.$app['app'].'/';
$complete=false;
if($app['block']>0){
$app['no']=intval($app['no']);
write_dir_file($filePath.$app['no'],$app['data']);
$blockComplete=true;
for($i=1;$i<=$app['block'];$i++){
if(!file_exists($filePath.$i)){
$blockComplete=false;
break;
}
}
if($blockComplete){
$data=null;
for($i=1;$i<=$app['block'];$i++){
$data.=file_get_contents($filePath.$i);
}
write_dir_file($filePath.$app['app'].'.zip',$data);
$complete=true;
unset($data);
}
}else{
write_dir_file($filePath.$app['app'].'.zip',$app['data']);
$complete=true;
}
if($complete){
$error='';
try {
$zipClass=new \ZipArchive();
if($zipClass->open($filePath.$app['app'].'.zip')===TRUE){
$zipClass->extractTo(config('apps_path').'/'.$app['app']);
$zipClass->close();
}else{
$error='解压失败';
}
}catch(\Exception $ex){
$error='您的服务器不支持ZipArchive解压';
}
if($error){
$this->dispatchJump(false,$error);
}else{
clear_dir($filePath);
$this->dispatchJump(true);
}
}else{
$this->dispatchJump(true);
}
}
/*统一检测更新*/
public function updateAction(){
$updateList=array('status'=>1,'data'=>array());
if(request()->isAjax()){
$storeIds=input('store_ids');
$storeIds=explode(',', $storeIds);
$storeApps=input('store_apps');
$storeApps=explode(',', $storeApps);
$storeIdList=array();
foreach ($storeIds as $id){
if(preg_match('/^(\w+)_(\w+)$/',$id,$id)){
$storeIdList[$id[1]][$id[2]]=$id[2];
}
}
$storeAppList=array();
foreach ($storeApps as $app){
if(preg_match('/^(\w+)_(\w+)$/',$app,$app)){
$storeAppList[$app[1]][$app[2]]=$app[2];
}
}
$provId=$this->_getStoreProvid(input('store_url'));
if(!empty($storeIdList)){
foreach ($storeIdList as $type=>$ids){
$list=array();
$cond=array('store_id'=>array('in',$ids),'provider_id'=>$provId,'type'=>$type);
$list=model('Rule')->field('`id`,`store_id`,`uptime`')->where($cond)->column('uptime','store_id');
$list=is_array($list)?$list:array();
$updateList['data'][$type]=$list;
}
}
if(!empty($storeAppList)){
foreach ($storeAppList as $type=>$apps){
if(empty($type)){
continue;
}
$list=array();
$cond=array('app'=>array('in',$apps),'provider_id'=>$provId);
if($type=='release'||$type=='cms'){
$list=model('ReleaseApp')->where($cond)->column('uptime','app');
}elseif($type=='func'){
$list=model('FuncApp')->where($cond)->column('uptime','app');
}elseif($type=='app'){
foreach ($apps as $app){
$appClass=model('App')->app_class($app,false);
$list[$app]=$appClass->config['version'];
}
}
$list=is_array($list)?$list:array();
$updateList['data'][$type]=$list;
}
}
}
return jsonp($updateList);
}
/*站点验证*/
public function siteCertificationAction(){
$this->_checkRequest();
$op=input('op');
if($op=='set_key'){
$key=input('post.key');
if(empty($key)){
$this->dispatchJump(false,'密钥错误');
}
cache('site_certification',array('key'=>$key,'time'=>NOW_TIME));
$this->dispatchJump(true);
}else{
$this->dispatchJump(false,'错误操作!');
}
}
public function _installPlugin($plugin){
public function _installPlugin($plugin,$provId=0){
$result=array('success'=>false,'msg'=>'');
$plugin=is_array($plugin)?$plugin:array();
$plugin=array_map('strip_tags', $plugin);
$plugin['code']=base64_decode($plugin['code']);
if(empty($plugin['app'])){
$result['msg']='标识错误';
$result['msg']='插件标识为空';
return $result;
}
if(empty($plugin['name'])){
$result['msg']='名称错误';
$result['msg']='插件名称为空';
return $result;
}
if(empty($plugin['type'])){
$result['msg']='类型错误';
$result['msg']='插件类型为空';
return $result;
}
if(empty($plugin['module'])){
$result['msg']='模块错误';
$result['msg']='插件模块为空';
return $result;
}
if(empty($plugin['code'])){
$result['msg']='插件文件错误';
$result['msg']='插件代码为空';
return $result;
}
if(!empty($plugin['tpl'])){
@ -263,8 +249,13 @@ class Store extends BaseController {
$newData=array('app'=>$plugin['app'],'name'=>$plugin['name'],'desc'=>$plugin['desc'],'uptime'=>$plugin['uptime']);
$newData['provider_id']=$this->_getStoreProvid($plugin['store_url']);
if(!empty($plugin['store_url'])){
$newData['provider_id']=model('Provider')->getIdByUrl($plugin['store_url']);
}else{
$newData['provider_id']=intval($provId);
}
if($plugin['type']=='release'){
$success=model('ReleaseApp')->addCms($newData,$plugin['code'],$plugin['tpl']);
@ -277,120 +268,32 @@ class Store extends BaseController {
$result['success']=$success?true:false;
$result['msg']=$result['success']?'成功':'无效的插件';
}else{
$result['msg']='类型错误';
$result['msg']='插件类型错误';
}
return $result;
}
/*获取平台域名Id*/
protected function _getStoreProvid($storeUrl=null){
if(empty($storeUrl)){
$referer=request()->server('HTTP_REFERER');
if(!empty($referer)){
$storeUrl=$referer;
}
}
$provId=model('Provider')->getIdByUrl($storeUrl);
return $provId;
}
/*验证请求源*/
protected function _checkRequest(){
$token=request()->server('HTTP_X_STORE_TOKEN');
$sessionToken=$this->_getToken();
if(empty($token)||empty($sessionToken)||$token!=$sessionToken){
$this->dispatchJump(false,'token验证失败请刷新页面或清除缓存');
}
$this->_checkCors(false);
}
protected function _getToken(){
$storeToken=session('store_token');
$token=null;
if(empty($storeToken)||!is_array($storeToken)||empty($storeToken['token'])){
$token='';
}else{
$token=$storeToken['token'];
}
return $token;
}
public function _checkCors($openCorsHeader=true){
$action=request()->action();
if($action=='update'){
return;
private function _installApp($app,$provId=0){
$result=array('success'=>false,'msg'=>'','blocks'=>0,'next_block_no'=>0);
$app=is_array($app)?$app:array();
$app=array_map('strip_tags', $app);
if(empty($app['app'])){
$result['msg']='应用标识为空';
return $result;
}
$httpOrigin=strtolower(request()->server('HTTP_ORIGIN'));
if(empty($httpOrigin)){
$httpOrigin='';
}else{
if(preg_match('/^\w+\:\/\//', $httpOrigin)){
$httpOrigin=rtrim($httpOrigin,'/');
}else{
$httpOrigin='';
}
if(!preg_match('/^[\w\-]+$/',$app['app'])){
$result['msg']='应用标识不规范';
return $result;
}
$isAllowOrigin=false;
$provData=null;
if(!empty($httpOrigin)){
if(in_array($httpOrigin,config('allow_origins'))){
$isAllowOrigin=true;
}else{
$provData=model('Provider')->where(array('domain'=>$httpOrigin))->find();
if(!empty($provData)&&$provData['enable']==1){
$isAllowOrigin=true;
}
}
if($isAllowOrigin&&$openCorsHeader){
header('Access-Control-Allow-Origin:'.$httpOrigin);
header('Access-Control-Allow-Credentials:true');
header('Access-Control-Allow-Methods:POST,GET');
header('Access-Control-Allow-Headers:X-Requested-With,X-Store-Token,Content-Type');
}
}
$httpWith=request()->server('HTTP_X_REQUESTED_WITH');
if(empty($httpWith)||strtolower($httpWith)!='xmlhttprequest'){
$this->dispatchJump(false,'不是ajax请求');
}
if(empty($httpOrigin)){
$this->dispatchJump(false,'未知来源');
}else{
if(!$isAllowOrigin){
if(empty($provData)){
$this->dispatchJump(false,'未知的第三方来源:'.$httpOrigin);
}else{
$this->dispatchJump(false,'未受信任的第三方来源:'.$httpOrigin);
}
}
if(empty($app['md5'])){
$result['msg']='应用md5码为空';
return $result;
}
$filePath=RUNTIME_PATH.'zip_app/'.$app['app'];
$result=\util\Funcs::install_downloaded_zip($app, $filePath, config('apps_path').'/'.$app['app']);
return $result;
}
}

View File

@ -121,8 +121,9 @@ class Task extends BaseController {
$this->assign('pagenav',$pagenav);
}
$showChange=$show=='list'?'folder':'list';
$GLOBALS['_sc']['p_name']=lang('task_list').' <small><a href="'.url('Task/list?show='.$showChange).'">'.lang('task_change_'.$showChange).'</a></small>';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list'))));
set_g_sc('p_title',lang('task_list'));
set_g_sc('p_name',lang('task_list').' <small><a href="'.url('Task/list?show='.$showChange).'" title="切换'.lang('task_change_'.$showChange).'">'.lang('task_change_'.$showChange).'</a></small>');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list')))));
return $this->fetch('list_'.$show);
}
/*任务列表,打开文件夹*/
@ -163,9 +164,10 @@ class Task extends BaseController {
if(input('?config.img_url')){
$newData['config']['img_url']=input('config.img_url','','trim');
}
$newData['sort']=min(intval($newData['sort']),999999);
$newData['config']=$this->_save_config($newData['config']);
$newData['config']=serialize($newData['config']);
$newData['addtime']=NOW_TIME;
$newData['addtime']=time();
$importColl=null;
$importRele=null;
@ -202,7 +204,7 @@ class Task extends BaseController {
$importRele=$importRele->toArray();
$importRele['task_id']=$taskData['id'];
$importRele['addtime']=NOW_TIME;
$importRele['addtime']=time();
unset($importRele['id']);
model('Release')->isUpdate(false)->allowField(true)->save($importRele);
}
@ -221,9 +223,12 @@ class Task extends BaseController {
$mtaskgroup=model('Taskgroup');
$tgSelect=$mtaskgroup->getLevelSelect();
$GLOBALS['_sc']['p_name']=lang('task_add');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list')),array('url'=>url('Task/add'),'title'=>lang('task_add'))));
set_g_sc('p_title',lang('task_add'));
set_g_sc('p_name',lang('task_add'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list')),array('url'=>url('Task/add'),'title'=>lang('task_add')))));
$this->assign('gConfig',$this->_global_caiji_config());
$this->assign('tgSelect',$tgSelect);
if(request()->isAjax()){
@ -249,7 +254,6 @@ class Task extends BaseController {
if(request()->isPost()){
$newData=input('param.');
$validate=Loader::validate('Task');
if(!$validate->scene('edit')->check($newData)){
@ -258,6 +262,7 @@ class Task extends BaseController {
if(input('?config.img_url')){
$newData['config']['img_url']=input('config.img_url','','trim');
}
$newData['sort']=min(intval($newData['sort']),999999);
$newData['config']=$this->_save_config($newData['config']);
$newData['config']=serialize($newData['config']);
if($taskData['name']!=$newData['name']){
@ -281,14 +286,16 @@ class Task extends BaseController {
}
}else{
$taskData=$taskData->getData();
$taskData=is_array($taskData)?$taskData:array();
$taskData['config']=unserialize($taskData['config']);
$taskData['config']=is_array($taskData['config'])?$taskData['config']:array();
$mtaskgroup=model('Taskgroup');
$tgSelect=$mtaskgroup->getLevelSelect();
$GLOBALS['_sc']['p_name']=lang('task_edit').''.$taskData['name'];
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list')),array('url'=>url('Task/edit?id='.$taskData['id']),'title'=>$taskData['name'])));
set_g_sc('p_title','任务:'.$taskData['name']);
set_g_sc('p_name',lang('task_edit').''.$taskData['name']);
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list')),array('url'=>url('Task/edit?id='.$taskData['id']),'title'=>$taskData['name']))));
$fieldList=array();
$collData=model('Collector')->where(array('task_id'=>$taskData['id']))->find();
@ -303,6 +310,7 @@ class Task extends BaseController {
}
}
$this->assign('gConfig',$this->_global_caiji_config());
$this->assign('tgSelect',$tgSelect);
$this->assign('taskData',$taskData);
$this->assign('fieldList',$fieldList);
@ -313,27 +321,93 @@ class Task extends BaseController {
}
}
}
private function _global_caiji_config(){
$imgFuncParam=g_sc_c('download_img','img_func_param');
if($imgFuncParam){
$imgFuncParam=str_replace("\r", '\r', $imgFuncParam);
$imgFuncParam=str_replace("\n", '\n', $imgFuncParam);
$imgFuncParam=htmlspecialchars($imgFuncParam,ENT_QUOTES);
}else{
$imgFuncParam='';
}
$gConfig=array(
'num'=>intval(g_sc_c('caiji','num')),
'interval'=>intval(g_sc('c_caiji_interval')),
'interval_html'=>intval(g_sc_c('caiji','interval_html')),
'real_time'=>g_sc_c('caiji','real_time')>0?'是':'否',
'proxy'=>g_sc_c('proxy','open')>0?'是':'否',
'download_img'=>g_sc_c('download_img','download_img')>0,
'img_path'=>g_sc_c('download_img','img_path')?g_sc_c('download_img','img_path'):(config('root_path').DS.'data'.DS.'images'),
'img_url'=>g_sc_c('download_img','img_url')?g_sc_c('download_img','img_url'):(config('root_website').'/data/images'),
'img_name'=>g_sc_c('download_img','img_name'),
'name_custom_path'=>g_sc_c('download_img','name_custom_path')?g_sc_c('download_img','name_custom_path'):'无',
'name_custom_name'=>lang('down_img_name_custom_name_'.g_sc_c('download_img','name_custom_name')),
'interval_img'=>intval(g_sc_c('download_img','interval_img')),
'img_func'=>g_sc_c('download_img','img_func'),
'img_func_param'=>$imgFuncParam
);
return $gConfig;
}
/*保持更多设置*/
public function _save_config($config=array()){
$config=is_array($config)?$config:array();
$config['num']=intval($config['num']);
$config['interval']=intval($config['interval']);
$config['interval_html']=intval($config['interval_html']);
$config['img_path']=trim($config['img_path']);
$config['img_url']=trim($config['img_url']);
$config['interval_img']=intval($config['interval_img']);
$mconfig=model('Config');
if(!empty($config['img_path'])){
$checkImgPath=model('Config')->check_img_path($config['img_path']);
$checkImgPath=$mconfig->check_img_path($config['img_path']);
if(!$checkImgPath['success']){
$this->error($checkImgPath['msg']);
}
}
if(!empty($config['img_url'])){
$checkImgUrl=model('Config')->check_img_url($config['img_url']);
$checkImgUrl=$mconfig->check_img_url($config['img_url']);
if(!$checkImgUrl['success']){
$this->error($checkImgUrl['msg']);
}
}
$checkNamePath=$mconfig->check_img_name_path($config['name_custom_path']);
if($config['img_name']=='custom'){
if(empty($config['name_custom_path'])&&is_empty(g_sc_c('download_img','name_custom_path'))){
$this->error('请输入图片名称自定义路径');
}
if(!$checkNamePath['success']){
$this->error($checkNamePath['msg']);
}
}else{
if(!$checkNamePath['success']){
$config['name_custom_path']='';
}
}
$checkNameName=$mconfig->check_img_name_name($config['name_custom_name']);
if($config['img_name']=='custom'){
if(!empty($config['name_custom_name'])&&!$checkNameName['success']){
$this->error($checkNameName['msg']);
}
}else{
if(!$checkNameName['success']){
$config['name_custom_name']='';
}
}
return $config;
}
/*导入规则*/
@ -381,7 +455,7 @@ class Task extends BaseController {
$collData=$mcoll->where(array('task_id'=>$taskData['id'],'module'=>$module))->find();
$newColl=array('name'=>$name,'module'=>$module,'task_id'=>$taskData['id'],'config'=>$config,'uptime'=>NOW_TIME);
$newColl=array('name'=>$name,'module'=>$module,'task_id'=>$taskData['id'],'config'=>$config,'uptime'=>time());
if(empty($collData)){
$mcoll->add_new($newColl);
}else{
@ -421,10 +495,11 @@ class Task extends BaseController {
$this->success(lang('op_success'));
}elseif($op=='saveall'){
$newsort=input('newsort/a');
$newsort=input('newsort/a',array());
if(is_array($newsort)&&count($newsort)>0){
foreach ($newsort as $key=>$val){
$mtask->strict(false)->where('id',intval($key))->update(array('sort'=>intval($val)));
foreach ($newsort as $key=>$val){
$val=min(intval($val),999999);
$mtask->strict(false)->where('id',intval($key))->update(array('sort'=>$val));
}
}
$this->success(lang('op_success'),'Task/list?show='.input('show'));
@ -440,114 +515,58 @@ class Task extends BaseController {
/*执行任务采集*/
public function collectAction(){
$taskId=input('id/d',0);
$this->_backstage_cli_collect('task --task_id '.$taskId);
if(input('?backstage')){
if(!IS_CLI){
ignore_user_abort(true);
if($GLOBALS['_sc']['c']['caiji']['server']=='cli'){
cli_command_exec('collect task --task_id '.$taskId);
exit();
}
}
ignore_user_abort(true);
define('CLOSE_ECHO_MSG',true);
$this->_backstage_task($taskId);
}else{
ignore_user_abort(false);
model('Task')->backstage_task($taskId);
}
$this->_collect($taskId);
$this->_echo_msg_end();
}
/*批量执行任务采集*/
public function collectBatchAction(){
$taskIds=input('ids');
if(empty($taskIds)){
$this->echo_msg('没有选中任务');
exit();
$this->echo_msg_exit('没有选中任务');
}
$taskIds=explode(',', $taskIds);
$taskIds=array_map('intval', $taskIds);
if(input('?backstage')){
if(!IS_CLI){
ignore_user_abort(true);
if($GLOBALS['_sc']['c']['caiji']['server']=='cli'){
cli_command_exec('collect batch --task_ids '.implode(',',$taskIds));
exit();
}
}
ignore_user_abort(true);
define('CLOSE_ECHO_MSG',true);
}else{
ignore_user_abort(false);
}
$this->_backstage_cli_collect('batch --task_ids '.implode(',',$taskIds));
if($GLOBALS['_sc']['c']['caiji']['timeout']>0){
set_time_limit(60*$GLOBALS['_sc']['c']['caiji']['timeout']);
if(g_sc_c('caiji','timeout')>0){
set_time_limit(60*g_sc_c('caiji','timeout'));
}else{
set_time_limit(0);
}
$taskList=model('Task')->where('id','in',$taskIds)->column('*','id');
$taskList=model('Task')->where('id','in',$taskIds)->column('name','id');
if(empty($taskList)){
$this->echo_msg('没有任务');
exit();
$this->echo_msg_exit('没有任务');
}
$sortTasks=array();
$sortIds=array();
foreach ($taskIds as $v){
$sortTasks[$v]=$taskList[$v];
if(isset($taskList[$v])){
$sortIds[$v]=$v;
}
}
$taskList=$sortTasks;
unset($sortTasks);
$this->_collect_batch($taskList);
$this->_collect_batch($sortIds);
$this->echo_msg('所有任务采集完毕!','green');
}
/*将任务标记为后台运行*/
public function _backstage_task($taskId){
$GLOBALS['_sc']['backstage_task_runtime']=time();
if(model('Task')->where('id',$taskId)->count()>0){
$mcache=CacheModel::getInstance('backstage_task');
$mcache->db()->strict(false)->insert(array(
'cname'=>$taskId,
'dateline'=>$GLOBALS['_sc']['backstage_task_runtime'],
'ctype'=>0,
'data'=>''
),true);
if(!isset($GLOBALS['_sc']['backstage_task_ids'])){
$GLOBALS['_sc']['backstage_task_ids']=array();
}
$GLOBALS['_sc']['backstage_task_ids'][$taskId]=$taskId;
static $registered=false;
if(!$registered){
register_shutdown_function(function(){
if(!empty($GLOBALS['_sc']['backstage_task_ids'])&&is_array($GLOBALS['_sc']['backstage_task_ids'])){
$mcache=\skycaiji\admin\model\CacheModel::getInstance('backstage_task');
$mcache->db()->strict(false)->where('cname','in',$GLOBALS['_sc']['backstage_task_ids'])->update(array('ctype'=>1,'data'=>time()));
}
});
$registered=true;
}
}
$this->_echo_msg_end();
}
/*单个任务采集*/
public function _collect($taskId){
static $setted_timeout=null;
if(!isset($setted_timeout)){
if($GLOBALS['_sc']['c']['caiji']['timeout']>0){
set_time_limit(60*$GLOBALS['_sc']['c']['caiji']['timeout']);
if(g_sc_c('caiji','timeout')>0){
set_time_limit(60*g_sc_c('caiji','timeout'));
}else{
set_time_limit(0);
}
@ -557,18 +576,15 @@ class Task extends BaseController {
$mtask=model('Task');
$taskData=$mtask->getById($taskId);
if(empty($taskData)){
$this->echo_msg(lang('task_error_empty_task'));
exit();
$this->echo_msg_exit(lang('task_error_empty_task'));
}
$taskData=$taskData->toArray();
if(empty($taskData['module'])){
$this->echo_msg(lang('task_error_null_module'));
exit();
$this->echo_msg_exit(lang('task_error_null_module'));
}
if(!in_array($taskData['module'],config('allow_coll_modules'))){
$this->echo_msg(lang('coll_error_invalid_module'));
exit();
$this->echo_msg_exit(lang('coll_error_invalid_module'));
}
$taskData['config']=unserialize($taskData['config']);
model('Task')->loadConfig($taskData);
@ -576,19 +592,17 @@ class Task extends BaseController {
$mcoll=model('Collector');
$collData=$mcoll->where(array('task_id'=>$taskData['id'],'module'=>$taskData['module']))->find();
if(empty($collData)){
$this->echo_msg(lang('coll_error_empty_coll'));
exit();
$this->echo_msg_exit(lang('coll_error_empty_coll'));
}
$collData=$collData->toArray();
$mrele=model('Release');
$releData=$mrele->where(array('task_id'=>$taskData['id']))->find();
if(empty($releData)){
$this->echo_msg(lang('rele_error_empty_rele'));
exit();
$this->echo_msg_exit(lang('rele_error_empty_rele'));
}
$releData=$releData->toArray();
$mtask->strict(false)->where('id',$taskData['id'])->update(array('caijitime'=>NOW_TIME));
$mtask->strict(false)->where('id',$taskData['id'])->update(array('caijitime'=>time()));
$acoll=controller('admin/C'.strtolower($collData['module']),'event');
$acoll->init($collData);
$arele=controller('admin/R'.strtolower($releData['module']),'event');
@ -597,22 +611,19 @@ class Task extends BaseController {
if('api'==$releData['module']){
$GLOBALS['_sc']['c']['caiji']['real_time']=0;
set_g_sc(['c','caiji','real_time'],0);
$cacheApiData=$arele->get_cache_fields();
if($cacheApiData!==false){
json($cacheApiData)->send();
exit();
$arele->json_exit($cacheApiData);
}
}
$all_field_list=array();
$caijiNum=intval($GLOBALS['_sc']['c']['caiji']['num']);
$caijiNum=intval(g_sc_c('caiji','num'));
$taskNum=intval($taskData['config']['num']);
if($taskNum<=0||($caijiNum>0&&$taskNum>$caijiNum)){
@ -655,26 +666,29 @@ class Task extends BaseController {
$this->echo_msg('没有采集到数据','orange');
}else{
$this->echo_msg('采集到'.count((array)$all_field_list).'条数据','green');
if(empty($GLOBALS['_sc']['c']['caiji']['real_time'])){
if(is_empty(g_sc_c('caiji','real_time'))){
$addedNum=$arele->export($all_field_list);
$addedNum=$arele->doExport($all_field_list);
$this->echo_msg('成功发布'.$addedNum.'条数据','green');
}
}
}
/*批量任务采集*/
public function _collect_batch($taskList=array()){
public function _collect_batch($taskIds=array()){
$mtask=model('Task');
$mcoll=model('Collector');
$mrele=model('Release');
$caijiNum=intval($GLOBALS['_sc']['c']['caiji']['num']);
$caijiNum=intval(g_sc_c('caiji','num'));
$caijiLimit=false;
if($caijiNum>0){
$caijiLimit=true;
$this->echo_msg('总共需采集'.$caijiNum.'条数据','black');
}
foreach ($taskList as $taskData){
$mtask->strict(false)->where('id',$taskData['id'])->update(array('caijitime'=>time()));
foreach ($taskIds as $taskId){
$taskData=$mtask->getById($taskId);
if(empty($taskData)){
continue;
}
$collData=$mcoll->where(array('task_id'=>$taskData['id'],'module'=>$taskData['module']))->find();
$releData=$mrele->where(array('task_id'=>$taskData['id']))->find();
if(empty($collData)||empty($releData)){
@ -686,18 +700,28 @@ class Task extends BaseController {
$releData=$releData->toArray();
if($releData['module']=='api'){
$this->echo_msg('任务:'.$taskData['name'].'发布方式为API接口,跳过执行','orange');
$this->echo_msg('任务:'.$taskData['name'].' 发布方式为生成api,跳过执行','orange');
continue;
}
if(input('?backstage')){
$this->_backstage_task($taskData['id']);
}
$taskData['config']=unserialize($taskData['config']);
$mtask->loadConfig($taskData);
if(g_sc_c('caiji','interval')>0){
$waitTime=(60*g_sc_c('caiji','interval'))-abs(time()-intval($taskData['caijitime']));
if($waitTime>0){
$this->echo_msg('任务:'.$taskData['name'].' 再次采集需等待'.\skycaiji\admin\model\Config::wait_time_tips($waitTime).' <a href="'.url('Admin/Task/edit?id='.$taskData['id']).'" target="_blank">设置运行间隔</a>','orange');
continue;
}
}
$mtask->strict(false)->where('id',$taskData['id'])->update(array('caijitime'=>time()));
if(input('?backstage')){
$mtask->backstage_task($taskData['id']);
}
$acoll='\\skycaiji\\admin\\event\\C'.strtolower($collData['module']);
$acoll=new $acoll();
$acoll->init($collData);
@ -744,9 +768,9 @@ class Task extends BaseController {
}else{
$this->echo_msg('任务:'.$taskData['name'].' 采集到'.count((array)$all_field_list).'条数据','green');
if(empty($GLOBALS['_sc']['c']['caiji']['real_time'])){
if(is_empty(g_sc_c('caiji','real_time'))){
$addedNum=$arele->export($all_field_list);
$addedNum=$arele->doExport($all_field_list);
$this->echo_msg('成功发布'.$addedNum.'条数据','green');
}
}

View File

@ -74,8 +74,9 @@ class Taskgroup extends BaseController {
$parentTgList=$mtaskgroup->where(array('parent_id'=>0))->order('sort desc')->column('name','id');
$this->assign('parentTgList',$parentTgList);
$GLOBALS['_sc']['p_name']=lang('taskgroup_list');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list'))));
set_g_sc('p_title',lang('taskgroup_list'));
set_g_sc('p_name',lang('taskgroup_list'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list')))));
return $this->fetch();
}
/**
@ -90,6 +91,7 @@ class Taskgroup extends BaseController {
$this->error($validate->getError());
}
$newData['sort']=min(intval($newData['sort']),999999);
$mtaskgroup->isUpdate(false)->allowField(true)->save($newData);
$tgid=$mtaskgroup->id;
@ -102,8 +104,9 @@ class Taskgroup extends BaseController {
$parentTgList=$mtaskgroup->where(array('parent_id'=>0))->order('sort desc')->column('name','id');
$this->assign('parentTgList',$parentTgList);
$GLOBALS['_sc']['p_name']=lang('taskgroup_add');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list')),array('url'=>url('Taskgroup/add'),'title'=>lang('taskgroup_add'))));
set_g_sc('p_title',lang('taskgroup_add'));
set_g_sc('p_name',lang('taskgroup_add'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list')),array('url'=>url('Taskgroup/add'),'title'=>lang('taskgroup_add')))));
if(request()->isAjax()){
return view('add_ajax');
@ -130,6 +133,7 @@ class Taskgroup extends BaseController {
$this->error($validate->getError());
}
$newData['sort']=min(intval($newData['sort']),999999);
if($tgData['name']!=$newData['name']){
if($mtaskgroup->where(array('name'=>$newData['name']))->count()>0){
@ -160,8 +164,9 @@ class Taskgroup extends BaseController {
$this->assign('parentTgList',$parentTgList);
$this->assign('tgData',$tgData);
$GLOBALS['_sc']['p_name']=lang('taskgroup_edit').''.$tgData['name'];
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list')),array('url'=>url('Taskgroup/edit?id='.$tgData['id']),'title'=>$tgData['name'])));
set_g_sc('p_title','分组:'.$tgData['name']);
set_g_sc('p_name',lang('taskgroup_edit').''.$tgData['name']);
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list')),array('url'=>url('Taskgroup/edit?id='.$tgData['id']),'title'=>$tgData['name']))));
if(request()->isAjax()){
return view('add_ajax');
@ -230,7 +235,7 @@ class Taskgroup extends BaseController {
}
}elseif($op=='deleteall'){
$ids=input('ids/a');
$ids=input('ids/a',array());
if(is_array($ids)&&count($ids)>0){
$list=$mtaskgroup->where(array('id'=>array('in',$ids)))->column('*');
$deleteIds=array();
@ -251,14 +256,15 @@ class Taskgroup extends BaseController {
$this->success(lang($hasSub?'tg_deleteall_has_sub':'op_success'));
}elseif($op=='saveall'){
$ids=input('ids/a');
$newsort=input('newsort/a');
$ids=input('ids/a',array());
$newsort=input('newsort/a',array());
if(is_array($ids)&&count($ids)>0){
$ids=array_map('intval', $ids);
$updateSql=' UPDATE '.$mtaskgroup->getQuery()->getTable().' SET `sort` = CASE `id` ';
foreach ($ids as $tgid){
$updateSql.= sprintf(" WHEN %d THEN '%s' ", $tgid, intval($newsort[$tgid]));
$newsort[$tgid]=min(intval($newsort[$tgid]),999999);
$updateSql.= sprintf(" WHEN %d THEN '%s' ", $tgid, $newsort[$tgid]);
}
$updateSql.='END WHERE `id` IN ('. implode(',',$ids).')';
try{

View File

@ -14,12 +14,15 @@ use skycaiji\admin\model\DbCommon;
class Tool extends BaseController {
/*文件管理*/
public function fileManagerAction(){
$GLOBALS['_sc']['p_name']='文件管理';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Tool/fileManager'),'title'=>'文件管理')));
set_g_sc('p_title','文件管理');
set_g_sc('p_name','文件管理');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Tool/fileManager'),'title'=>'文件管理'))));
return $this->fetch('fileManager');
}
/*elfinder文件管理器*/
public function elfinderAction(){
$this->check_usertoken();
$op=input('op');
if(empty($op)){
@ -44,14 +47,21 @@ class Tool extends BaseController {
'uploadDeny' => array('all'),
'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'),
'uploadOrder' => array('deny', 'allow'),
'attributes' => array (
'attributes' => array (
array (
'pattern' => '/\.php$/i',
'read' => false,
'write' => false,
'hidden' => true,
'locked' => false
)
'pattern' => '/\.(php|html|lock)$/i',
'read' => false,
'write' => false,
'hidden' => true,
'locked' => false
),
array (
'pattern' => '/^\/{0,1}$/i',
'read' => true,
'write' => false,
'hidden' => false,
'locked' => false
)
)
)
)
@ -86,21 +96,36 @@ class Tool extends BaseController {
}
}
}
$GLOBALS['_sc']['p_name']='错误日志';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Tool/logs'),'title'=>'错误日志')));
set_g_sc('p_title','错误日志');
set_g_sc('p_name','错误日志');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Tool/logs'),'title'=>'错误日志'))));
$this->assign('logList',$logList);
return $this->fetch();
}
/*读取日志*/
public function logAction(){
config('dispatch_error_tmpl','common:error');
config('dispatch_success_tmpl','common:success');
$file=realpath(input('file'));
$logPath=realpath(config('root_path').'/runtime/log');
if(stripos($file,$logPath)===false){
$this->error('不是日志文件');
$this->error('不是日志文件','');
}
$log=file_get_contents($file);
exit('<pre>'.$log.'</pre>');
if(request()->isPost()){
if(input('upload')){
curl_skycaiji('/client/upload/log',null,array(),array('log'=>$log,'v'=>SKYCAIJI_VERSION));
$this->success('上报成功,感谢支持!','');
}
}else{
return $this->display('<pre>'.$log.'</pre>');
}
}
/*文件校验*/
public function checkfileAction(){
set_time_limit(0);
@ -156,8 +181,9 @@ class Tool extends BaseController {
$this->error('',null,array('files'=>$error_files));
}
}else{
$GLOBALS['_sc']['p_name']='校验文件';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Tool/checkfile'),'title'=>'校验文件')));
set_g_sc('p_title','校验文件');
set_g_sc('p_name','校验文件');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Tool/checkfile'),'title'=>'校验文件'))));
return $this->fetch();
}
}
@ -207,7 +233,7 @@ class Tool extends BaseController {
$this->error('没有获取到表');
}
if(!version_compare($check_db['version'],$GLOBALS['_sc']['c']['version'],'=')){
if(!version_compare($check_db['version'],g_sc_c('version'),'=')){
$this->error('校验文件版本与数据库版本不一致');
}
@ -417,30 +443,38 @@ class Tool extends BaseController {
}
}
}else{
$GLOBALS['_sc']['p_name']='校验数据库';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Tool/checkdb'),'title'=>'校验数据库')));
set_g_sc('p_title','校验数据库');
set_g_sc('p_name','校验数据库');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Tool/checkdb'),'title'=>'校验数据库'))));
return $this->fetch();
}
}
public function json_treeAction(){
if(request()->isPost()){
$url=input('url','','trim');
$html=input('html','','trim');
if(request()->isPost()){
$data=input('data','','trim');
$json='';
$eCpattern=controller('admin/Cpattern','event');
if(!empty($url)){
if(preg_match('/^\w+\:\/\//', $data)){
$html=get_html($url);
$data=get_html($data);
}
if(!empty($html)){
$json=convert_html2json($html,true);
if(!empty($data)){
$json=\util\Funcs::convert_html2json($data,true);
}
$this->success('','',array('json'=>$json));
}else{
$GLOBALS['_sc']['p_name']='JSON解析';
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('Tool/json_tree'),'title'=>'JSON解析')));
return $this->fetch('json_tree');
return $this->_json_tree_view();
}
}
public function json_tree_dataAction(){
$data=input('data','','trim');
$this->assign('data',$data);
return $this->_json_tree_view();
}
private function _json_tree_view(){
set_g_sc('p_title','JSON解析');
set_g_sc('p_name','JSON解析');
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('Tool/json_tree'),'title'=>'JSON解析'))));
return $this->fetch('json_tree');
}
}

View File

@ -17,30 +17,9 @@ class Upgrade extends BaseController{
public function __construct(){
parent::__construct();
set_time_limit(3600);
$this->oldFilePath=config('root_path').'/data/program/backup/skycaiji'.$GLOBALS['_sc']['c']['version'];
$this->newFilePath=config('root_path').'/data/program/upgrade/skycaiji'.$GLOBALS['_sc']['c']['version'];
$this->oldFilePath=config('root_path').'/data/program/backup/skycaiji'.g_sc_c('version');
$this->newFilePath=config('root_path').'/data/program/upgrade/skycaiji'.g_sc_c('version');
}
/*检测更新*/
public function newVersionAction(){
$version=get_html('https://www.skycaiji.com/upgrade/program/version?v='.SKYCAIJI_VERSION,null,null,'utf-8');
$version=json_decode($version,true);
$version=is_array($version)?$version:array();
$new_version=trim($version['new_version']);
$cur_version=$GLOBALS['_sc']['c']['version'];
if(version_compare($new_version,$cur_version,'>')){
$version['is_new_version']=true;
}
$cacheIx=cache('backstage_admin_index');
if(empty($cacheIx)||$cacheIx['ver']!=$version['admin_index_ver']){
$version['is_new_admin_index']=true;
}
$this->success('',null,$version);
}
/*
* 下载的文件完整性检测
* 注意:执行该方法时,旧代码已经编译了,替换文件后还是执行的旧文件代码
@ -96,12 +75,11 @@ class Upgrade extends BaseController{
$this->success();
}
}
$fileUrl='https://www.skycaiji.com/upgrade/program/getFile?filename='.rawurlencode(base64_encode($fileName));
$curl=\util\Curl::get($fileUrl,null,array('timeout'=>100));
if($curl->isOk){
$curlInfo=curl_skycaiji('/client/upgrade/file?filename='.rawurlencode(base64_encode($fileName)),null,array('timeout'=>100),null,true);
if($curlInfo['ok']){
$newFile=$curl->body;
$newFile=$curlInfo['html'];
$oldFile=file_get_contents(config('root_path').$fileName);
if(!empty($oldFile)){
@ -142,7 +120,7 @@ class Upgrade extends BaseController{
unset($md5Files);
$newFileList=get_html('https://www.skycaiji.com/upgrade/program/files',null,array('timeout'=>100),'utf-8');
$newFileList=curl_skycaiji('/client/upgrade/files',null,array('timeout'=>100));
$newFileList=json_decode($newFileList,true);
$downFileList=array();

View File

@ -24,8 +24,9 @@ class User extends BaseController {
$this->assign('pagenav',$pagenav);
$userList=$userList->all();
$GLOBALS['_sc']['p_name']=lang('user_list');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list'))));
set_g_sc('p_title',lang('user_list'));
set_g_sc('p_name',lang('user_list'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list')))));
$groupList=model('Usergroup')->column('*','id');
$this->assign('userList',$userList);
@ -37,11 +38,7 @@ class User extends BaseController {
$muser=model('User');
$musergroup=model('Usergroup');
if(request()->isPost()){
if(!check_usertoken()){
$this->error(lang('usertoken_error'),'Admin/User/add');
}
if($GLOBALS['_sc']['c']['site']['verifycode']){
if(g_sc_c('site','verifycode')){
$verifycode=trim(input('verifycode'));
$check=check_verify($verifycode);
@ -65,9 +62,9 @@ class User extends BaseController {
$newData['password']=\skycaiji\admin\model\User::pwd_encrypt($newData['password'],$newData['salt']);
$newGroup=$musergroup->getById($newData['groupid']);
if($musergroup->user_level_limit($newGroup['level'])){
$this->error('您不能添加“'.$GLOBALS['_sc']['user']['group']['name'].'”用户组');
$this->error('您不能添加“'.g_sc('user','group','name').'”用户组');
}
$newData['regtime']=NOW_TIME;
$newData['regtime']=time();
$muser->isUpdate(false)->allowField(true)->save($newData);
if($muser->uid>0){
$this->success(lang('op_success'),'User/list');
@ -75,9 +72,10 @@ class User extends BaseController {
$this->error(lang('op_failed'));
}
}else{
$subGroupList=$musergroup->get_sub_level($GLOBALS['_sc']['user']['groupid']);
$GLOBALS['_sc']['p_name']=lang('user_add');
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list')),array('url'=>url('User/add'),'title'=>lang('user_add'))));
$subGroupList=$musergroup->get_sub_level(g_sc('user','groupid'));
set_g_sc('p_title',lang('user_add'));
set_g_sc('p_name',lang('user_add'));
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list')),array('url'=>url('User/add'),'title'=>lang('user_add')))));
$this->assign('subGroupList',$subGroupList);
return $this->fetch();
}
@ -95,16 +93,13 @@ class User extends BaseController {
}
$userData['group']=$musergroup->getById($userData['groupid']);
$isOwner=($GLOBALS['_sc']['user']['uid']==$userData['uid'])?true:false;
$isOwner=(g_sc('user','uid')==$userData['uid'])?true:false;
if(!$isOwner&&$musergroup->user_level_limit($userData['group']['level'])){
$this->error('您不能编辑“'.$userData['group']['name'].'”组的用户');
}
if(request()->isPost()){
if(!check_usertoken()){
$this->error(lang('usertoken_error'),'Admin/User/edit?uid='.$userData['uid']);
}
if($GLOBALS['_sc']['c']['site']['verifycode']){
if(g_sc_c('site','verifycode')){
$verifycode=trim(input('verifycode'));
$check=check_verify($verifycode);
@ -135,7 +130,7 @@ class User extends BaseController {
}
$newGroup=$musergroup->getById($newData['groupid']);
if($musergroup->user_level_limit($newGroup['level'])){
$this->error('您不能改为“'.$GLOBALS['_sc']['user']['group']['name'].'”用户组');
$this->error('您不能改为“'.g_sc('user','group','name').'”用户组');
}
if($isOwner||empty($newData['groupid'])){
@ -143,15 +138,22 @@ class User extends BaseController {
}
$muser->strict(false)->where(array('uid'=>$uid))->update($newData);
$this->success(lang('op_success'),'User/list');
if($isOwner){
$userData=$muser->getByUid($uid);
$muser->setLoginSession($userData);
}
$this->success(lang('op_success'),'User/list');
}else{
$this->assign('userData',$userData);
$subGroupList=$musergroup->get_sub_level($GLOBALS['_sc']['user']['groupid']);
$subGroupList=$musergroup->get_sub_level(g_sc('user','groupid'));
$this->assign('subGroupList',$subGroupList);
$this->assign('isOwner',$isOwner);
$GLOBALS['_sc']['p_name']=lang('user_edit').''.$userData['username'];
$GLOBALS['_sc']['p_nav']=breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list')),array('url'=>url('User/edit?uid='.$userData['uid']),'title'=>$userData['username'])));
set_g_sc('p_title','用户:'.$userData['username']);
set_g_sc('p_name',lang('user_edit').''.$userData['username']);
set_g_sc('p_nav',breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list')),array('url'=>url('User/edit?uid='.$userData['uid']),'title'=>$userData['username']))));
return $this->fetch();
}
}
@ -166,7 +168,7 @@ class User extends BaseController {
if(empty($userData)){
$this->error(lang('user_error_empty_user'));
}
if($userData['uid']==$GLOBALS['_sc']['user']['uid']){
if($userData['uid']==g_sc('user','uid')){
$this->error('不能删除自己');
}

View File

@ -24,20 +24,20 @@ abstract class Collector extends \skycaiji\admin\controller\BaseController {
}
}
/*采集器的输出内容需要重写,只有正在采集时才输出内容*/
public function echo_msg($str,$color='red',$echo=true,$end_str=''){
if(is_collecting()){
public function echo_msg($str,$color='red',$echo=true,$end_str='',$div_style=''){
if(is_collecting()){
static $pause_session=null;
if(!isset($pause_session)){
if(session_status()!==2){
if(session_status()!==PHP_SESSION_ACTIVE){
session_start();
}
\think\Session::pause();
session_write_close();
$pause_session=true;
}
parent::echo_msg($str,$color,$echo,$end_str);
parent::echo_msg($str,$color,$echo,$end_str,$div_style);
}
}
/**
@ -67,99 +67,20 @@ abstract class Collector extends \skycaiji\admin\controller\BaseController {
public function set_html_interval(){
if(is_collecting()){
if($GLOBALS['_sc']['c']['caiji']['html_interval']>0){
sleep($GLOBALS['_sc']['c']['caiji']['html_interval']);
return true;
}
$millisecond=g_sc_c('caiji','interval_html');
if(empty($millisecond)&&g_sc_c('caiji','html_interval')>0){
$millisecond=g_sc_c('caiji','html_interval')*1000;
}
if($millisecond>0){
usleep($millisecond*1000);
return true;
}
}
}
/*获取内容*/
public function get_content($html){
try {
$cread=new \util\Readability($html,'utf-8');
$data=$cread->getContent();
}catch (\Exception $ex){
return null;
}
return trim($data['content']);
}
/*获取标题*/
public function get_title($html){
if(preg_match_all('/<h1\b[^<>]*?>(?P<content>[\s\S]+?)<\/h1>/i', $html,$title)){
if (count($title['content'])>1){
$title=null;
}else{
$title=strip_tags(reset($title['content']));
if (preg_match('/^((\&nbsp\;)|\s)*$/i', $title)){
$title=null;
}
}
}else{
$title=null;
}
if (empty($title)){
$pattern = array (
'<(h[12])\b[^<>]*?(id|class)=[\'\"]{0,1}[^\'\"<>]*(title|article)[^<>]*>(?P<content>[\s\S]+?)<\/\1>',
'<title>(?P<content>[\s\S]+?)([\-\_\|][\s\S]+?)*<\/title>'
);
$title=$this->return_preg_match($pattern, $html);
}
return trim(strip_tags($title));
}
public function get_keywords($html){
$patterns=array(
'<meta[^<>]*?name=[\'\"]keywords[\'\"][^<>]*?content=[\'\"](?P<content>[\s\S]*?)[\'\"]',
'<meta[^<>]*?content=[\'\"](?P<content>[\s\S]*?)[\'\"][^<>]*?name=[\'\"]keywords[\'\"]'
);
$data=$this->return_preg_match($patterns, $html);
return trim(strip_tags($data));
}
public function get_description($html){
$patterns=array(
'<meta[^<>]*?name=[\'\"]description[\'\"][^<>]*?content=[\'\"](?P<content>[\s\S]*?)[\'\"]',
'<meta[^<>]*?content=[\'\"](?P<content>[\s\S]*?)[\'\"][^<>]*?name=[\'\"]description[\'\"]'
);
$data=$this->return_preg_match($patterns, $html);
return trim(strip_tags($data));
}
/**
* 匹配规则的值
* @param 规则 $pattern
* @param 来源内容 $content
* @param 返回值得键名 $reg_key
*/
public function return_preg_match($pattern,$content,$reg_key='content'){
if(is_array($pattern)){
foreach ($pattern as $patt){
if(preg_match('/'.$patt.'/i', $content,$cont)){
$cont=$cont[$reg_key];
break;
}else{
$cont=false;
}
}
}else{
if(preg_match('/'.$pattern.'/i', $content,$cont)){
$cont=$cont[$reg_key];
}else{
$cont=false;
}
}
return empty($cont)?'':$cont;
}
/**
* 匹配根目录
* @param string $url 完整的网址
@ -217,8 +138,8 @@ abstract class Collector extends \skycaiji\admin\controller\BaseController {
public function create_complete_url($url,$base_url,$domain_url){
static $base_domain=array();
if(preg_match('/^\w+\:\/\//', $url)){
if(preg_match('/^\w+\:/', $url)){
return $url;
}elseif(strpos($url,'//')===0){

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@ class Rapi extends Release{
* @param unknown $config
*/
public function setConfig($config){
$api=input('api/a');
$api=input('api/a',array());
$api['url']=trim($api['url'],'\/\\');
$api['cache_time']=intval($api['cache_time']);
$api['hide_fields']=is_array($api['hide_fields'])?$api['hide_fields']:array();
@ -45,13 +45,15 @@ class Rapi extends Release{
$mcacheCont->db()->where('cname','in',$contUrls)->delete();
}
$this->hide_coll_fields($this->config['api']['hide_fields'],$collFieldsList);
foreach ($collFieldsList as $collFieldsKey=>$collFields){
$this->hide_coll_fields($this->config['api']['hide_fields'],$collFields);
$collFieldsList[$collFieldsKey]=$collFields;
}
$this->set_cache_fields($collFieldsList);
json($collFieldsList)->send();
exit();
$this->json_exit($collFieldsList);
}
/*设置缓存数据*/
@ -81,5 +83,19 @@ class Rapi extends Release{
return false;
}
}
/*输出json数据*/
public function json_exit($collFieldsList){
if(defined('API_TASK_RESPONSE_JSON')){
json($collFieldsList)->send();
}else{
$html='<form id="win_form_json" method="post" target="_blank" action="'.url('Tool/json_tree_data').'">'.html_usertoken()
.'<p>生成API返回的数据 <a href="javascript:;" onclick="document.getElementById(\'win_form_json\').submit();">解析</a></p>'
.'<textarea name="data" style="width:100%;margin:5px 0;" rows="20">'.htmlspecialchars(json_encode($collFieldsList)).'</textarea></form>';
$this->echo_msg($html,'black');
$this->_echo_msg_end();
}
exit();
}
}
?>

View File

@ -19,8 +19,8 @@ class Rcms extends Release{
* @param unknown $config
*/
public function setConfig($config){
$config['cms']=input('cms/a');
$config['cms_app']=input('cms_app/a');
$config['cms']=input('cms/a',array());
$config['cms_app']=input('cms_app/a',array());
if(empty($config['cms']['path'])){
$this->error('cms路径不能为空');
}
@ -54,11 +54,9 @@ class Rcms extends Release{
if(model('ReleaseApp')->oldFileExists($this->config['cms']['app'],'Cms')){
$this->echo_msg(lang('release_upgrade'));
exit();
$this->echo_msg_exit(lang('release_upgrade'));
}else{
$this->echo_msg('没有cms发布插件'.$this->config['cms']['app']);
exit();
$this->echo_msg_exit('没有cms发布插件'.$this->config['cms']['app']);
}
}

View File

@ -18,7 +18,7 @@ class Rdb extends Release{
* @param unknown $config
*/
public function setConfig($config){
$db=input('db/a','','trim');
$db=input('db/a',array(),'trim');
foreach ($db as $k=>$v){
if(empty($v)&&'pwd'!=$k){
@ -26,7 +26,7 @@ class Rdb extends Release{
}
}
$config['db']=$db;
$config['db_table']=input('db_table/a','','trim');
$config['db_table']=input('db_table/a',array(),'trim');
if(is_array($config['db_table'])&&is_array($config['db_table']['field'])){
foreach($config['db_table']['field'] as $tbName=>$tbFields){
@ -48,6 +48,8 @@ class Rdb extends Release{
public function export($collFieldsList,$options=null){
$db_config=$this->get_db_config($this->config['db']);
$db_config['fields_strict']=false;
$db_key=md5(serialize($db_config));
if(empty($this->db_conn_list[$db_key])){
@ -180,8 +182,8 @@ class Rdb extends Release{
$mdb->commit();
reset($autoidList);
list($firstTable,$firstId) = each($autoidList);
$firstId=intval($firstId);
$firstTable=key($autoidList);
$firstId=intval($autoidList[$firstTable]);
if($firstId>0){
$addedNum++;
$returnData['id']=$firstId;

View File

@ -18,7 +18,7 @@ class Rdiy extends Release{
* @param unknown $config
*/
public function setConfig($config){
$diy=input('diy/a','','trim');
$diy=input('diy/a',array(),'trim');
if(!in_array($diy['type'],array('app','code'))){
$this->error('类型错误');
}
@ -65,17 +65,14 @@ class Rdiy extends Release{
$releDiy=$this->rele_diy_list[$releDiy];
}elseif(model('ReleaseApp')->oldFileExists($appName,'diy')){
$this->echo_msg(lang('release_upgrade'));
exit();
$this->echo_msg_exit(lang('release_upgrade'));
}
}
if(empty($releDiy)){
$this->echo_msg('没有自定义插件:'.$appName);
exit();
$this->echo_msg_exit('没有自定义插件:'.$appName);
}
}catch (\Exception $ex){
$this->echo_msg($ex->getMessage());
exit();
$this->echo_msg_exit($ex->getMessage());
}
$addedNum=0;

View File

@ -27,6 +27,16 @@ abstract class Release extends ReleaseBase{
$this->error(lang('task_error_empty_task'));
}
}
public function doExport($collFieldsList,$options=null){
$addedNum=0;
try{
$addedNum=$this->export($collFieldsList,$options);
}catch (\Exception $ex){
$this->echo_msg($ex->getMessage());
}
return $addedNum;
}
/**
* 优化设置页面post过来的config
* @param unknown $config 页面配置

View File

@ -74,7 +74,7 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
return '';
}
$val=$collFieldVal['value'];
if(!empty($GLOBALS['_sc']['c']['download_img']['download_img'])){
if(!is_empty(g_sc_c('download_img','download_img'))){
if(!empty($collFieldVal['img'])){
@ -96,9 +96,14 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
$curI++;
if($curI<$total){
if(!empty($GLOBALS['_sc']['c']['download_img']['img_interval'])){
sleep($GLOBALS['_sc']['c']['download_img']['img_interval']);
}
$millisecond=g_sc_c('download_img','interval_img');
if(empty($millisecond)&&g_sc_c('download_img','img_interval')>0){
$millisecond=g_sc_c('download_img','img_interval')*1000;
}
if($millisecond>0){
usleep($millisecond*1000);
}
}
}
}
@ -107,11 +112,12 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
}
/*下载图片*/
public function download_img($url){
static $retryCur=0;
static $imgPaths=array();
static $imgUrls=array();
$img_path=$GLOBALS['_sc']['c']['download_img']['img_path'];
$img_url=$GLOBALS['_sc']['c']['download_img']['img_url'];
$img_path=g_sc_c('download_img','img_path');
$img_url=g_sc_c('download_img','img_url');
if(!isset($imgPaths[$img_path])){
if(empty($img_path)){
@ -138,32 +144,76 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
if(empty($url)){
return '';
}
if(!preg_match('/^\w+\:\/\//',$url)){
$isDataImage=stripos($url, 'data:image/')===0?true:false;
if(!preg_match('/^\w+\:\/\//',$url)&&!$isDataImage){
return $url;
}
if(!empty($GLOBALS['_sc']['c']['caiji']['robots'])){
if(!model('Collector')->abide_by_robots($url)){
$this->echo_msg('robots拒绝访问的网址'.$url);
return $url;
}
if($isDataImage&&is_empty(g_sc_c('download_img','data_image'))){
return $url;
}
if(!$isDataImage){
if(!is_empty(g_sc_c('caiji','robots'))){
if(!model('Collector')->abide_by_robots($url)){
$this->echo_msg('robots拒绝访问的网址'.$url);
return $url;
}
}
}
static $imgList=array();
static $imgSuffixes=null;
if(!isset($imgSuffixes)){
$imgSuffixes=array('jpg','jpeg','gif','png','bmp');
$moreSuffix=g_sc_c('download_img','more_suffix');
if(!empty($moreSuffix)){
$moreSuffix=explode(',', $moreSuffix);
if(is_array($moreSuffix)){
$imgSuffixes=array_merge($imgSuffixes,$moreSuffix);
}
}
}
$key=md5($url);
if(!isset($imgList[$key])){
if(preg_match('/\.(jpg|jpeg|gif|png|bmp)\b/i',$url,$prop)){
$prop=strtolower($prop[1]);
}else{
$prop='jpg';
$prop='';
$dataImageCode='';
if($isDataImage){
if(preg_match('/^data\:image\/(.+?)\;base64\,(.*)$/i',$url,$prop)){
$dataImageCode=base64_decode(trim($prop[2]));
$prop=strtolower($prop[1]);
}else{
$prop='';
}
}else{
if(preg_match('/\.([a-zA-Z][\w\-]+)([\?\#]|$)/',$url,$prop)){
$prop=strtolower($prop[1]);
}else{
$prop='';
}
}
if(!in_array($prop, $imgSuffixes)){
$prop='';
}
if(empty($prop)){
$prop='jpg';
}
$filename='';
$imgurl='';
$isExists=false;
$imgname=$GLOBALS['_sc']['c']['download_img']['img_name'];
$imgname=g_sc_c('download_img','img_name');
if('url'==$imgname){
@ -172,6 +222,7 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
$imgname=substr($key,0,2).'/'.substr($key,-2,2).'/'.$key.'.'.$prop;
$filename=$img_path.$imgname;
$filename=$this->_convert_img_charset($filename);
$isExists=file_exists($filename);
if(!$isExists){
@ -179,77 +230,167 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
$imgname=substr($key,0,2).'/'.substr($key,2).'.'.$prop;
$filename=$img_path.$imgname;
$filename=$this->_convert_img_charset($filename);
$isExists=file_exists($filename);
}
}elseif('custom'==$imgname){
$customPath=$GLOBALS['_sc']['c']['download_img']['name_custom_path'];
if(isset($GLOBALS['_sc']['c']['download_img']['_name_custom_path'])){
$customPath=$GLOBALS['_sc']['c']['download_img']['_name_custom_path'];
$customPath=g_sc_c('download_img','name_custom_path');
if(!is_null(g_sc_c('download_img','_name_custom_path'))){
$customPath=g_sc_c('download_img','_name_custom_path');
}
$customName=$GLOBALS['_sc']['c']['download_img']['name_custom_name'];
if(isset($GLOBALS['_sc']['c']['download_img']['_name_custom_name'])){
$customName=$GLOBALS['_sc']['c']['download_img']['_name_custom_name'];
$customName=g_sc_c('download_img','name_custom_name');
if(!is_null(g_sc_c('download_img','_name_custom_name'))){
$customName=g_sc_c('download_img','_name_custom_name');
}
$customPath=model('Config')->convert_img_name_path($customPath,$url);
$customName=model('Config')->convert_img_name_name($customName,$url);
$imgname=$customPath.'/'.$customName.'.'.$prop;
$filename=$img_path.$imgname;
$filename=$img_path.$imgname;
$filename=$this->_convert_img_charset($filename);
$isExists=file_exists($filename);
}else{
$imgname=date('Y-m-d',NOW_TIME).'/'.$key.'.'.$prop;
$imgname=date('Y-m-d',time()).'/'.$key.'.'.$prop;
$filename=$img_path.$imgname;
$filename=$this->_convert_img_charset($filename);
$isExists=file_exists($filename);
}
$imgurl=$img_url.$imgname;
if(!$isExists){
$mproxy=model('Proxyip');
try {
$options=array();
$headers=array();
if(!empty($GLOBALS['_sc']['task_request_headers'])&&!empty($GLOBALS['_sc']['task_request_headers']['request_headers']['download_img'])){
$headers=$GLOBALS['_sc']['task_request_headers']['headers'];
if(!empty($headers['useragent'])){
$options['useragent']=$headers['useragent'];
}
unset($headers['useragent']);
}
if(!empty($GLOBALS['_sc']['c']['download_img']['img_timeout'])){
$options['timeout']=$GLOBALS['_sc']['c']['download_img']['img_timeout'];
}
if(!empty($GLOBALS['_sc']['c']['proxy']['open'])){
$proxyIp=$mproxy->get_usable_ip();
$proxyIp=$mproxy->to_proxy_ip($proxyIp);
if(!empty($proxyIp)){
$options['proxy']=$proxyIp;
}
}
if(!empty($GLOBALS['_sc']['c']['download_img']['img_max'])){
$options['max_bytes']=intval($GLOBALS['_sc']['c']['download_img']['img_max'])*1024*1024;
}
$imgCode=get_html($url,$headers,$options,'utf-8');
if(!empty($imgCode)){
if(write_dir_file($filename,$imgCode)){
$imgList[$key]=$imgurl;
}
}
}catch (\Exception $ex){
}
if($isDataImage){
if(!empty($dataImageCode)){
if(write_dir_file($filename,$dataImageCode)){
$imgList[$key]=$imgurl;
}
}
}else{
$mproxy=model('Proxyip');
$proxyDbIp=null;
try {
$options=array();
$headers=array();
if(!is_empty(g_sc('task_img_headers'))){
$headers=g_sc('task_img_headers');
}
if(!is_empty(g_sc_c('download_img','img_timeout'))){
$options['timeout']=g_sc_c('download_img','img_timeout');
}
if(!is_empty(g_sc_c('proxy','open'))){
$proxyDbIp=$mproxy->get_usable_ip();
$proxyIp=$mproxy->to_proxy_ip($proxyDbIp);
if(!empty($proxyIp)){
$options['proxy']=$proxyIp;
}
}
if(!is_empty(g_sc_c('download_img','img_max'))){
$options['max_bytes']=intval(g_sc_c('download_img','img_max'))*1024*1024;
}
$imgCodeInfo=get_html($url,$headers,$options,'utf-8',null,true);
if(!empty($imgCodeInfo['ok'])){
$retryCur=0;
if(!empty($imgCodeInfo['html'])){
if(preg_match('/\bcontent-type\s*\:\s*image\s*\/(\w+)/i', $imgCodeInfo['header'],$mImgProp)){
$mImgProp=strtolower($mImgProp[1]);
if($prop!=$mImgProp){
if(in_array($mImgProp,$imgSuffixes)){
static $sameImgProp=array('jpg','jpeg');
if(!in_array($prop,$sameImgProp)||!in_array($mImgProp,$sameImgProp)){
$imgname.='.'.$mImgProp;
$imgurl.='.'.$mImgProp;
$filename.='.'.$mImgProp;
if(file_exists($filename)){
$isExists=true;
$imgList[$key]=$imgurl;
}
}
}
}
}
if(!$isExists){
if(write_dir_file($filename,$imgCodeInfo['html'])){
$imgList[$key]=$imgurl;
$funcName=g_sc_c('download_img','img_func');
if(!empty($funcName)){
$paramVals=array(
'[图片:文件名]'=>$filename,
'[图片:路径]'=>$img_path,
'[图片:名称]'=>$imgname,
'[图片:链接]'=>$imgurl,
'[图片:网址]'=>$url
);
$return=model('FuncApp')->execute_func('downloadImg',$funcName,$filename,g_sc_c('download_img','img_func_param'),$paramVals);
if($return['success']){
if($return['data']&&preg_match('/^\w+\:\/\//',$return['data'])){
$imgList[$key]=$return['data'];
}
}elseif($return['msg']){
$this->echo_msg($return['msg']);
}
}
}
}
}
}else{
if($retryCur<=0){
$this->echo_msg('<div class="clear"><span class="left">图片下载失败:</span><a href="'.$url.'" target="_blank" class="lurl">'.$url.'</a></div>','red');
}
if(!empty($proxyDbIp)){
$mproxy->set_ip_failed($proxyDbIp);
}
$failedWait=intval(g_sc_c('download_img','wait'));
if($failedWait>0){
sleep($failedWait);
}
$retryMax=intval(g_sc_c('download_img','retry'));
if($retryMax>0){
if($retryCur<$retryMax){
$retryCur++;
$this->echo_msg(($retryCur>1?'':'重试:').'第'.$retryCur.'次','black',true,'','display:inline;');
return $this->download_img($url);
}else{
$retryCur=0;
$this->echo_msg('图片无效','red',true,'','display:inline;margin-left:10px;');
}
}
}
}catch (\Exception $ex){
}
}
}else{
$imgList[$key]=$imgurl;
@ -257,6 +398,27 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
}
return empty($imgList[$key])?$url:$imgList[$key];
}
private function _convert_img_charset($filename){
static $charset=null;
if(!isset($charset)){
$charset=g_sc_c('download_img','charset');
$charset=empty($charset)?'':strtolower($charset);
if($charset=='custom'){
$charset=g_sc_c('download_img','charset_custom');
$charset=empty($charset)?'':strtolower($charset);
}
if($charset=='utf-8'){
$charset='';
}
}
if(!empty($charset)&&!empty($filename)){
$filename=iconv('utf-8',$charset.'//IGNORE',$filename);
}
return $filename;
}
/*获取采集器字段*/
public function get_coll_fields($taskId,$taskModule){
static $fieldsList=array();
@ -280,12 +442,11 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
}
/*隐藏采集字段(删除字段)*/
public function hide_coll_fields($hideFields,&$collFields){
if(!empty($hideFields)&&!empty($collFields)&&is_array($hideFields)){
foreach ($collFields as $k=>$v){
foreach ($hideFields as $hideField){
unset($collFields[$k]['fields'][$hideField]);
}
}
if(!empty($hideFields)&&is_array($hideFields)&&is_array($collFields)&&is_array($collFields['fields'])){
foreach ($hideFields as $hideField){
unset($collFields['fields'][$hideField]);
}
}
}
@ -299,18 +460,26 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
}
return $val;
}
/*任意编码转换成utf8*/
public function auto_convert2utf8($arr){
$arr=array_array_map('auto_convert2utf8',$arr);
return $arr;
/**
* 任意编码转换成utf8
* @param mixed $val 字符串或数组
*/
public function auto_convert2utf8($val){
if(is_array($val)){
$val=\util\Funcs::array_array_map('auto_convert2utf8',$val);
}else{
$val=auto_convert2utf8($val);
}
return $val;
}
/*写入文件*/
public function write_file($filename,$data){
return write_dir_file($filename,$data);
}
/*初始化下载图片*/
public function init_download_img($taskData,$collFields){
if(!empty($GLOBALS['_sc']['c']['download_img']['download_img'])&&$GLOBALS['_sc']['c']['download_img']['img_name']=='custom'){
if(!is_empty(g_sc_c('download_img','download_img'))&&g_sc_c('download_img','img_name')=='custom'){
if(empty($taskData)){
$taskData=array();
@ -319,7 +488,7 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
$collFields=array();
}
$name_custom_path=$GLOBALS['_sc']['c']['download_img']['name_custom_path'];
$name_custom_path=g_sc_c('download_img','name_custom_path');
$check=model('Config')->check_img_name_path($name_custom_path);
if($check['success']){
$name_custom_path=$this->_convert_img_params($name_custom_path, $taskData, $collFields);
@ -327,10 +496,10 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
$name_custom_path='temp';
}
$GLOBALS['_sc']['c']['download_img']['_name_custom_path']=$name_custom_path;
set_g_sc(['c','download_img','_name_custom_path'],$name_custom_path);
$name_custom_name=$GLOBALS['_sc']['c']['download_img']['name_custom_name'];
$name_custom_name=g_sc_c('download_img','name_custom_name');
$check=model('Config')->check_img_name_name($name_custom_name);
if($check['success']){
$name_custom_name=$this->_convert_img_params($name_custom_name, $taskData, $collFields);
@ -338,11 +507,11 @@ class ReleaseBase extends \skycaiji\admin\controller\BaseController{
$name_custom_name='';
}
$GLOBALS['_sc']['c']['download_img']['_name_custom_name']=$name_custom_name;
set_g_sc(['c','download_img','_name_custom_name'],$name_custom_name);
}else{
unset($GLOBALS['_sc']['c']['download_img']['_name_custom_path']);
unset($GLOBALS['_sc']['c']['download_img']['_name_custom_name']);
set_g_sc(['c','download_img','_name_custom_path'],null);
set_g_sc(['c','download_img','_name_custom_name'],null);
}
}

View File

@ -10,13 +10,14 @@
*/
namespace skycaiji\admin\event;
class Rfile extends Release {
/**
* 设置页面post过来的config
* @param unknown $config
*/
public function setConfig($config){
$file=input('file/a');
$file=input('file/a',array());
$file['path']=trim($file['path'],'\/\\');
$file['hide_fields']=is_array($file['hide_fields'])?$file['hide_fields']:array();
if(empty($file['path'])){
@ -34,21 +35,22 @@ class Rfile extends Release {
/*导出数据*/
public function export($collFieldsList,$options=null){
if(!in_array($this->config['file']['type'],array('xlsx','xls','txt'))){
$this->echo_msg('不支持的文件格式:'.$this->config['file']['type']);
$this->echo_msg_exit('不支持的文件格式:'.$this->config['file']['type']);
}
$this->hide_coll_fields($this->config['file']['hide_fields'],$collFieldsList);
$hideFields=$this->config['file']['hide_fields'];
$filepath=config('root_path').'/data/'.$this->config['file']['path'].'/'.$this->release['task_id'];
$filename=date('Y-m-d',NOW_TIME).'.'.$this->config['file']['type'];
$filename=date('Y-m-d',time()).'.'.$this->config['file']['type'];
$filename=$filepath.'/'.$filename;
$addedNum=0;
$excelType=array('xlsx'=>'Excel2007','xls'=>'Excel5');
if(!empty($excelType[$this->config['file']['type']])){
$excelType=$excelType[$this->config['file']['type']];
if(empty($excelType)){
$this->echo_msg('错误的文件格式');
exit();
$this->echo_msg_exit('错误的文件格式');
}
if(!file_exists($filename)){
@ -61,6 +63,7 @@ class Rfile extends Release {
$newPhpExcel->setActiveSheetIndex(0);
$firstFields=reset($collFieldsList);
$this->hide_coll_fields($hideFields, $firstFields);
$firstFields=array_keys($firstFields['fields']);
foreach ($firstFields as $k=>$v){
$newPhpExcel->getActiveSheet()->setCellValue(chr(65+$k).'1',$v);
@ -71,28 +74,30 @@ class Rfile extends Release {
unset($newPhpExcel);
}
$filename=realpath($filename);
$objReader = \PHPExcel_IOFactory::createReader($excelType);
$phpExcel = $objReader->load($filename);
$phpExcel->setActiveSheetIndex(0);
$rowNum=$phpExcel->getSheet(0)->getHighestRow();
$rowNum=intval($rowNum);
$addedNum=0;
foreach ($collFieldsList as $collFieldsKey=>$collFields){
$this->init_download_img($this->task,$collFields['fields']);
$addedNum++;
$curRow=$rowNum+$addedNum;
$collFields['fields']=is_array($collFields['fields'])?array_values($collFields['fields']):array();
foreach ($collFields['fields'] as $k=>$v){
$phpExcel->getActiveSheet()->setCellValue(chr(65+$k).$curRow,$this->get_field_val($v));
}
$this->record_collected($collFields['url'], array('id'=>1,'target'=>$filename,'desc'=>'行:'.$curRow), $this->release,$collFields['title']);
unset($collFieldsList[$collFieldsKey]['fields']);
if($filename){
$objReader = \PHPExcel_IOFactory::createReader($excelType);
$phpExcel = $objReader->load($filename);
$phpExcel->setActiveSheetIndex(0);
$rowNum=$phpExcel->getSheet(0)->getHighestRow();
$rowNum=intval($rowNum);
foreach ($collFieldsList as $collFieldsKey=>$collFields){
$this->init_download_img($this->task,$collFields['fields']);
$this->hide_coll_fields($hideFields, $collFields);
$addedNum++;
$curRow=$rowNum+$addedNum;
$collFields['fields']=is_array($collFields['fields'])?array_values($collFields['fields']):array();
foreach ($collFields['fields'] as $k=>$v){
$phpExcel->getActiveSheet()->setCellValue(chr(65+$k).$curRow,$this->get_field_val($v));
}
$this->record_collected($collFields['url'], array('id'=>1,'target'=>$filename,'desc'=>'行:'.$curRow), $this->release,$collFields['title']);
unset($collFieldsList[$collFieldsKey]['fields']);
}
$objWriter = \PHPExcel_IOFactory::createWriter($phpExcel,$excelType);
$objWriter->save($filename);
}
$objWriter = \PHPExcel_IOFactory::createWriter($phpExcel,$excelType);
$objWriter->save($filename);
}elseif('txt'==$this->config['file']['type']){
$txtLine=0;
@ -109,30 +114,34 @@ class Rfile extends Release {
fclose($fpTxt);
}else{
write_dir_file( $filename, null);
write_dir_file( $filename, '');
}
foreach ($collFieldsList as $collFieldsKey=>$collFields){
$addedNum++;
$fieldVals=array();
foreach ($collFields['fields'] as $k=>$v){
$fieldVal=str_replace(array("\r","\n"), array('\r','\n'), $this->get_field_val($v));
if(empty($this->config['file']['txt_implode'])){
$fieldVal=str_replace("\t", ' ', $fieldVal);
}
$fieldVals[]=$fieldVal;
}
$fieldVals=implode($this->config['file']['txt_implode']?$this->config['file']['txt_implode']:"\t", $fieldVals);
if(write_dir_file($filename,$fieldVals."\r\n",FILE_APPEND)){
$txtLine++;
$this->record_collected($collFields['url'], array('id'=>1,'target'=>$filename,'desc'=>'行:'.$txtLine), $this->release,$collFields['title']);
}
unset($collFieldsList[$collFieldsKey]['fields']);
$filename=realpath($filename);
if($filename){
foreach ($collFieldsList as $collFieldsKey=>$collFields){
$this->init_download_img($this->task,$collFields['fields']);
$this->hide_coll_fields($hideFields, $collFields);
$addedNum++;
$fieldVals=array();
foreach ($collFields['fields'] as $k=>$v){
$fieldVal=str_replace(array("\r","\n"), array('\r','\n'), $this->get_field_val($v));
if(empty($this->config['file']['txt_implode'])){
$fieldVal=str_replace("\t", ' ', $fieldVal);
}
$fieldVals[]=$fieldVal;
}
$fieldVals=implode($this->config['file']['txt_implode']?$this->config['file']['txt_implode']:"\t", $fieldVals);
if(write_dir_file($filename,$fieldVals."\r\n",FILE_APPEND)){
$txtLine++;
$this->record_collected($collFields['url'], array('id'=>1,'target'=>$filename,'desc'=>'行:'.$txtLine), $this->release,$collFields['title']);
}
unset($collFieldsList[$collFieldsKey]['fields']);
}
}
}

View File

@ -18,7 +18,7 @@ class Rtoapi extends Release{
* @param unknown $config
*/
public function setConfig($config){
$toapi=input('toapi/a','','trim');
$toapi=input('toapi/a',array(),'trim');
if(empty($toapi['url'])){
$this->error('请输入接口地址');
}
@ -31,7 +31,7 @@ class Rtoapi extends Release{
$toapi['param_val']=is_array($toapi['param_val'])?$toapi['param_val']:array();
$toapi['param_addon']=is_array($toapi['param_addon'])?$toapi['param_addon']:array();
if(is_array($toapi['param_name'])){
$toapi['param_name']=array_array_map('trim', $toapi['param_name']);
$toapi['param_name']=\util\Funcs::array_array_map('trim', $toapi['param_name']);
foreach ($toapi['param_name'] as $k=>$v){
if(empty($v)){

View File

@ -13,25 +13,23 @@ return array(
'admincp'=>'后台',
'sign_wildcard'=>'(*)',
'sign_match'=>'[内容{:num}]',
'sign_match'=>'[内容{:id}]',
'tips_sign_wildcard'=>'通配符可匹配任意字符',
'tips_sign_match'=>'匹配任意字符并保存为标签以供调用,等同于捕获组:(?&lt;content编号&gt;.*?)',
'tips_sign_match_only'=>'匹配任意字符并保存为标签以供调用,等同于捕获组:(?&lt;content&gt;.*?)',
'tips_sign_group'=>'捕获组:(?&lt;content编号&gt;[\s\S]*?),匹配正则并保存为[内容]标签以供调用',
'tips_sign_group_only'=>'捕获组:(?&lt;content&gt;[\s\S]*?),匹配正则并保存为[内容]标签以供调用',
'tips_sign_match'=>'匹配任意字符并保存为标签以供调用,等同于捕获组:(?&lt;nr标识&gt;.*?)',
'tips_sign_match_only'=>'匹配任意字符并保存为标签以供调用,等同于捕获组:(?&lt;nr&gt;.*?)',
'tips_sign_group'=>'捕获组:(?&lt;nr标识&gt;[\s\S]*?),匹配正则并保存为[内容]标签以供调用',
'tips_sign_group_only'=>'捕获组:(?&lt;nr&gt;[\s\S]*?),匹配正则并保存为[内容]标签以供调用',
'tips_regular'=>'可使用正则表达式',
'setting'=>'设置',
'setting_site'=>'站点设置',
'setting_site'=>'站点设置',
'set_site_verifycode'=>'开启图片验证码',
'setting_caiji'=>'采集设置',
'set_caiji_auto'=>'开启自动采集',
'set_caiji_run'=>'自动采集运行方式',
'set_caiji_interval'=>'每次采集间隔时间',
'set_caiji_interval'=>'采集运行间隔',
'set_caiji_num'=>'每次采集数量',
'set_caiji_timeout'=>'最大执行时间',
@ -45,8 +43,24 @@ return array(
'set_email_type'=>'SMTP端口类型',
'set_email_test_subject'=>'测试发送邮件',
'set_email_test_body'=>'恭喜,发送邮件成功!',
'setting_store'=>'云端设置',
'store_authkey_error'=>'通信密钥只能由字母和数字组成且长度在6-100位之间',
'down_img_m_'=>'本地存储',
'down_img_m_loc'=>'本地存储',
'down_img_m_func'=>'使用函数',
'down_img_name_'=>'按时间生成(方便日期归类)',
'down_img_name_time'=>'按时间生成(方便日期归类)',
'down_img_name_url'=>'按网址生成(防止重复下载)',
'down_img_name_custom'=>'自定义',
'down_img_name_custom_name_'=>'图片网址MD5码',
'config_error_none_email'=>'没有邮箱服务器配置,请在后台设置!',
@ -57,14 +71,14 @@ return array(
'user_username'=>'用户名',
'user_password'=>'密码',
'user_repassword'=>'确认密码',
'user_newpwd_tips'=>'如果您想修改密码,请在此输入新密码,否则留空',
'user_newpwd_tips'=>'如修改密码,请在此输入新密码,否则留空',
'user_email'=>'邮箱',
'user_email_tips'=>'用于找回账号密码',
'user_groupid'=>'用户组',
'user_error_has_username'=>'用户名已经存在!',
'user_error_edit_not_allow'=>'只有创始人才能编辑他人的账号!',
'user_error_delete_not_allow'=>'只有创始人才能删除账号!',
'user_error_email'=>'邮箱格式错误!',
'user_error_groupid'=>'不是允许的用户组!',
'user_error_del_founder'=>'不能删除创始人账号!',
@ -76,14 +90,14 @@ return array(
'user_login_in'=>'登录中...',
'user_auto_login'=>'正在自动登录...',
'usertoken_error'=>'用户token错误请刷新界面重新获取或清除浏览器缓存',
'usertoken_error'=>'用户token错误请刷新页面或重新登录',
'task'=>'任务',
'task_add'=>'添加任务',
'task_edit'=>'编辑任务',
'task_list'=>'任务列表',
'task_change_list'=>'切换列表模式',
'task_change_folder'=>'切换分组模式',
'task_change_list'=>'列表模式',
'task_change_folder'=>'分组模式',
'task_name'=>'任务名称',
'task_tg'=>'任务分组',
@ -101,12 +115,11 @@ return array(
'task_root'=>'根目录',
'task_loading'=>'正在载入数据',
'task_none_data'=>'无数据',
'task_caiji_ing'=>'正在采集',
'task_set_task'=>'任务设置',
'task_set_collector'=>'采集器设置',
'task_set_release'=>'发布设置',
'task_error_null_id'=>'请输入任务id',
'task_error_empty_task'=>'不存在任务',
'task_error_null_tgid'=>'请输入分组id',
@ -158,9 +171,10 @@ return array(
'field_module_extract'=>'字段提取',
'field_module_sign'=>'[内容]标签',
'process_module_html'=>'html标签过滤',
'process_module_html'=>'html标签过滤',
'process_module_insert'=>'插入内容',
'process_module_replace'=>'内容替换',
'process_module_filter'=>'关键词过滤',
'process_module_filter'=>'关键词过滤',
'process_module_if'=>'条件判断',
'process_module_translate'=>'翻译',
'process_module_tool'=>'工具箱',
@ -219,6 +233,7 @@ return array(
'error_unknown_database'=>'未知的数据库',
'error_null_input'=>'请输入{:str}',
'error_open_basedir'=>'您的网站开启了目录访问限制(open_basedir),请检查是否因该问题导致目录无法读写!',
'collected'=>'已采集数据',
'collected_list'=>'已采集数据列表',
@ -260,7 +275,6 @@ return array(
'yzm_error_please_input'=>'请输入激活码',
'yzm_error_timeout'=>'激活码已过期!请重新发送',
'yzm_error_yzm'=>'激活码错误',
'admincp_style'=>'界面',
'admincp_sidebar_mini'=>'菜单最小化',
@ -314,15 +328,14 @@ return array(
'separator'=>'',
'redirecting'=>'跳转中...',
'close'=>'关闭',
'return_home'=>'{:time}秒钟后返回<a href="{:url}">页面</a>',
'tips_match'=>'示例:&lt;div id=&quot;a&quot;&gt;[内容1]&lt;/div&gt;(*)&lt;div id=&quot;b&quot;&gt;[内容2]&lt;/div&gt;',
'tips_matchn'=>'示例:[内容1] [内容2]',
'tips_match_only'=>'示例:&lt;div id=&quot;content&quot;&gt;[内容]&lt;/div&gt;',
'tips_match_url'=>'示例:&lt;a href=&quot;http://demo.com/[内容1]/[内容2]&quot;&gt;(*)&lt;/a&gt;',
'tips_matchn_url'=>'示例http://www.demo.com/[内容1]-[内容2].html',
'tips_match_only'=>'示例:&lt;div id=&quot;content&quot;&gt;[内容]&lt;/div&gt;',
'tips_match_area'=>'示例:&lt;div id=&quot;a&quot;&gt;[内容123]&lt;/div&gt;(*)&lt;div id=&quot;b&quot;&gt;[内容abc]&lt;/div&gt;',
'tips_matchn_area'=>'示例:[内容123] [内容abc]',
'tips_match_url'=>'示例:&lt;a href=&quot;http://demo.com/[内容123]/[内容abc]&quot;&gt;(*)&lt;/a&gt;',
'tips_matchn_url'=>'示例http://www.demo.com/[内容123]-[内容abc].html',
'release_upgrade'=>'插件版本过低,请升级插件 <a href="https://www.skycaiji.com/manual/doc/release_upgrade" target="_blank">升级教程</a>',
);

View File

@ -11,9 +11,9 @@
namespace skycaiji\admin\model;
class App extends BaseModel{
class App extends \skycaiji\common\model\BaseModel{
/*检测是否是应用并获取配置文件实例化*/
public function app_class($app,$includeClass=true){
public function app_class($app,$includeClass=true,$configKey=null){
static $passPaths=array('.','..','common','admin','skycaiji','vendor');
if($this->right_app($app)){
@ -49,7 +49,14 @@ class App extends BaseModel{
}
if($appClass){
$appClass->config=$this->clear_config($appClass->config);
if(!property_exists($appClass,'config')){
$appClass->config=array();
}
$appClass->config=$this->clear_config($appClass->config);
if(!empty($configKey)){
return $appClass->config[$configKey];
}
return $appClass;
}
}
@ -158,6 +165,32 @@ class App extends BaseModel{
$filename=$this->config_filename($app);
unlink($filename);
}
/*转换扩展*/
public function convert_packs($packs,$app,$returnType=null,$navid=null){
$packs=is_array($packs)?$packs:array();
$appUrl=config('root_website').'/app/'.$app.'/';
$returnPacks=array();
foreach ($packs as $k=>$v){
if($v['type']=='nav'){
$v['nav_link']=str_replace(array('{app}','{apps}'), array($appUrl,config('root_website').'/app/'),$v['nav_link']);
if(!preg_match('/^\w+\:\/\//', $v['nav_link'])){
$v['nav_link']=$appUrl.$v['nav_link'];
}
$v['name']=htmlspecialchars($v['name'],ENT_QUOTES);
if(isset($navid)&&$navid==$k){
$v['is_current']=true;
}
$packs[$k]=$v;
}
if($returnType&&$returnType==$v['type']){
$returnPacks[$k]=$packs[$k];
}
}
return $returnType?$returnPacks:$packs;
}
private function _array_map($callback, $arr1){
if(is_array($arr1)){
$arr=array();

View File

@ -56,9 +56,13 @@ class CacheModel{
public function getCache($cname,$key=null){
$cache=$this->db()->where('cname',$cname)->find();
switch($cache['ctype']){
case 1:$cache['data']=intval($cache['data']);break;
case 2:$cache['data']=unserialize($cache['data']);break;
if(!empty($cache)){
switch($cache['ctype']){
case 1:$cache['data']=intval($cache['data']);break;
case 2:$cache['data']=unserialize($cache['data']);break;
}
}else{
$cache=array();
}
return $key?$cache[$key]:$cache;
}
@ -89,7 +93,7 @@ class CacheModel{
*/
public function expire($cname,$timeout=72000){
$cache=$this->getCache($cname);
if(empty($cache)||abs(NOW_TIME-$cache['dateline']>$timeout)){
if(empty($cache)||abs(time()-$cache['dateline']>$timeout)){
return true;
}else{
return false;

View File

@ -11,7 +11,7 @@
namespace skycaiji\admin\model;
/*采集到的数据库*/
class Collected extends BaseModel{
class Collected extends \skycaiji\common\model\BaseModel{
public function __construct($data=[]){
try {

View File

@ -11,18 +11,18 @@
namespace skycaiji\admin\model;
class Collector extends BaseModel{
class Collector extends \skycaiji\common\model\BaseModel{
public function add_new($data){
$data['addtime']=NOW_TIME;
$data['uptime']=NOW_TIME;
$data['addtime']=time();
$data['uptime']=time();
$this->isUpdate(false)->allowField(true)->save($data);
return $this->id;
}
public function edit_by_id($id,$data){
unset($data['addtime']);
$data['uptime']=NOW_TIME;
$data['uptime']=time();
$this->strict(false)->where(array('id'=>$id))->update($data);
}
@ -130,6 +130,48 @@ class Collector extends BaseModel{
}
return true;
}
public function compatible_config($config){
if(!is_array($config)){
$config=array();
}
if(!isset($config['area'])){
if(!empty($config['area_start'])||!empty($config['area_end'])) {
$config['area']=$config['area_start'] . (!empty($config['area_end']) ? '(?<nr>[\s\S]+?)' : '(?<nr>[\s\S]+)') . $config['area_end'];
}
}
if(!isset($config['url_web'])){
if(!empty($config['url_post'])&&isset($config['url_posts'])){
\util\Funcs::filter_key_val_list($config['url_posts']['names'], $config['url_posts']['vals']);
$config['url_web']=array('open'=>1,'form_method'=>'post','form_names'=>$config['url_posts']['names'],'form_vals'=>$config['url_posts']['vals']);
if(is_array($config['level_urls'])){
foreach ($config['level_urls'] as $k=>$v){
$v['url_web']=$config['url_web'];
$config['level_urls'][$k]=$v;
}
}
}
}
return $config;
}
public static function echo_msg_end_js(){
return '<script type="text/javascript" data-echo-msg-is-end="1">window.parent.window.collectorEchoMsg("end");</script>';
}
public static function echo_msg_log_filename($logid){
$logid=md5($logid);
$filename=RUNTIME_PATH.'echo_msg/'.substr($logid,0,2).'/'.substr($logid,2);
return $filename;
}
}
?>

View File

@ -11,88 +11,46 @@
namespace skycaiji\admin\model;
class Config extends BaseModel {
protected $pk = 'cname';
class Config extends \skycaiji\common\model\Config {
public function convertData($configItem){
if(!empty($configItem)){
switch($configItem['ctype']){
case 1:$configItem['data']=intval($configItem['data']);break;
case 2:$configItem['data']=unserialize($configItem['data']);break;
}
}
return $configItem;
}
/**
* 获取
* @param string $cname 名称
* @param string $key 数据键名
* @return mixed
*/
public function getConfig($cname,$key=null){
$item=$this->where('cname',$cname)->find();
if(!empty($item)){
$item=$item->toArray();
$item=$this->convertData($item);
}
return $key?$item[$key]:$item;
}
/**
* 设置
* @param string $cname 名称
* @param string $value 数据
*/
public function setConfig($cname,$value){
$data=array('cname'=>$cname,'ctype'=>0);
if(is_array($value)){
$data['ctype']=2;
$data['data']=serialize($value);
}elseif(is_integer($value)){
$data['ctype']=1;
$data['data']=intval($value);
}else{
$data['data']=$value;
}
$data['dateline']=time();
$this->insert($data,true);
$this->cacheConfigList();
}
/*缓存所有配置*/
public function cacheConfigList(){
$keyConfig='cache_config_all';
$configDbList=$this->column('*');
$configDbList=empty($configDbList)?array():$configDbList;
$configList=array();
foreach ($configDbList as $configItem){
$configItem=$this->convertData($configItem);
$configList[$configItem['cname']]=$configItem['data'];
}
cache($keyConfig,array('list'=>$configList));
}
public function getConfigList(){
$keyConfig='cache_config_all';
$cacheConfig=cache($keyConfig);
if(!is_array($cacheConfig)){
$cacheConfig=array();
}
$configList=$cacheConfig['list'];
return is_array($configList)?$configList:array();
}
/*设置版本号*/
public function setVersion($version){
$version=trim(strtoupper($version),'V');
$this->setConfig('version', $version);
public function server_is_cli($isInput=false,$val=null){
$value='';
if(empty($isInput)){
$value=g_sc_c('caiji','server');
}else{
$value=$val;
}
$value=$value=='cli'?true:false;
return $value;
}
/*获取数据库的版本*/
public function getVersion(){
$dbVersion=$this->where("`cname`='version'")->find();
if(!empty($dbVersion)){
$dbVersion=$this->convertData($dbVersion);
$dbVersion=$dbVersion['data'];
}
return $dbVersion;
public function page_render_is_chrome($isInput=false,$val=null){
$value='';
if(empty($isInput)){
$value=g_sc_c('page_render','tool');
}else{
$value=$val;
}
$value=$value=='chrome'?true:false;
return $value;
}
/*检查图片路径*/
public function check_img_path($imgPath){
$return=array('success'=>false,'msg'=>'');
@ -102,7 +60,7 @@ class Config extends BaseModel {
$return['msg']='图片目录必须为绝对路径!';
}else{
if(!is_dir($imgPath)){
$return['msg']='图片目录不存在!';
$return['msg']='图片目录不存在!'.(self::check_basedir_limited($imgPath)?lang('error_open_basedir'):'');
}else{
$imgPath=realpath($imgPath);
$root_path=rtrim(realpath(config('root_path')),'\\\/');
@ -134,7 +92,7 @@ class Config extends BaseModel {
}
return $return;
}
/*检查自定义图片名的路径设置*/
public function check_img_name_path($path){
static $check_list=array();
$pathMd5=md5($path);
@ -157,18 +115,19 @@ class Config extends BaseModel {
}
return $return;
}
/*转换自定义图片名的路径*/
public function convert_img_name_path($path,$url){
if(!empty($path)){
$md5=md5($url);
static $tags=array('[年]','[月]','[日]','[时]','[分]','[秒]','[前两位]','[后两位]');
$nowTime=time();
$tagsRe=array(
date('Y',NOW_TIME),
date('m',NOW_TIME),
date('d',NOW_TIME),
date('H',NOW_TIME),
date('i',NOW_TIME),
date('s',NOW_TIME),
date('Y',$nowTime),
date('m',$nowTime),
date('d',$nowTime),
date('H',$nowTime),
date('i',$nowTime),
date('s',$nowTime),
substr($md5,0,2),
substr($md5,-2,2),
);
@ -184,7 +143,7 @@ class Config extends BaseModel {
}
return $path;
}
/*检查自定义图片名的名称设置*/
public function check_img_name_name($name){
static $check_list=array();
$nameMd5=md5($name);
@ -204,29 +163,36 @@ class Config extends BaseModel {
return $return;
}
/*转换自定义图片名的名称*/
public function convert_img_name_name($name,$url){
$md5=md5($url);
if(!empty($name)){
$urlname='';
if(preg_match('/([^\/]+?)\./', $url,$urlname)){
if(preg_match('/([^\/]+?)(\.[a-zA-Z][\w\-]+){0,1}([\?\#]|$)/', $url,$urlname)){
$urlname=$urlname[1];
if(mb_strlen($urlname,'utf-8')>100){
$urlname=mb_substr($urlname,0,100,'utf-8');
}
}else{
$urlname='';
}
if(empty($urlname)){
$urlname=$md5;
}
static $tags=array('[年]','[月]','[日]','[时]','[分]','[秒]','[前两位]','[后两位]','[图片网址MD5码]','[图片原名]');
$nowTime=time();
$tagsRe=array(
date('Y',NOW_TIME),
date('m',NOW_TIME),
date('d',NOW_TIME),
date('H',NOW_TIME),
date('i',NOW_TIME),
date('s',NOW_TIME),
date('Y',$nowTime),
date('m',$nowTime),
date('d',$nowTime),
date('H',$nowTime),
date('i',$nowTime),
date('s',$nowTime),
substr($md5,0,2),
substr($md5,-2,2),
$md5,
@ -242,7 +208,8 @@ class Config extends BaseModel {
}
return $name;
}
/*从采集设置中提取出图片本地化设置*/
public function get_img_config_from_caiji($caijiConfig){
$config=array();
if(!empty($caijiConfig)){
@ -256,8 +223,9 @@ class Config extends BaseModel {
}
return $config;
}
public function detect_php_exe(){
/*检测出php可执行文件路径*/
public static function detect_php_exe(){
static $php_filename=null;
if(!isset($php_filename)){
@ -290,11 +258,125 @@ class Config extends BaseModel {
}
}
}
}else{
$php_filename='php';
}
if(empty($php_filename)){
$php_filename='php';
}
}
return $php_filename;
}
public function exec_php_version($phpFile){
$return=false;
if(empty($phpFile)){
$phpFile=self::detect_php_exe();
}
if(!empty($phpFile)){
$return=array('success'=>false,'msg'=>'');
$phpFile=self::cli_safe_filename($phpFile);
$phpFile.=' -v';
$info=proc_open_exec($phpFile,'all',3,true);
$info=is_array($info)?$info:array();
$info['output']=trim($info['output']);
$info['error']=trim($info['error']);
if(is_array($info['status'])&&$info['status']['running']){
if($info['error']){
$return['msg']=$info['error'];
}elseif($info['output']){
$return['success']=true;
$return['msg']=('测试成功PHP信息'.$info['output']);
}else{
$return['success']=true;
}
}elseif($info['error']){
$return['msg']=$info['error'];
}
}
return $return;
}
public static function cli_safe_filename($filename){
if(!empty($filename)){
if(IS_WIN){
$filename='"'.$filename.'"';
}else{
if(preg_match('/(?<!\\\)\s/', $filename)){
$filename=preg_replace('/(?<!\\\)(\s)/', "\\\\$1", $filename);
}
}
}
return $filename;
}
/*open_basedir目录保护检查目录是否受限*/
public static function check_basedir_limited($path){
$openBasedir=ini_get('open_basedir');
if(empty($openBasedir)){
return false;
}
if(empty($path)){
return false;
}
if(file_exists($path)){
return false;
}
$path=str_replace('\\', '/', $path);
$path=rtrim($path,'/').'/';
$openBasedir=explode(IS_WIN?';':':', $openBasedir);
if(is_array($openBasedir)){
foreach ($openBasedir as $dir){
if(empty($dir)){
continue;
}
$dir=str_replace('\\', '/', $dir);
$dir=rtrim($dir,'/').'/';
if(stripos($path, $dir)===0){
return false;
}
}
}
return true;
}
public static function check_collect_wait(){
$return=false;
$lastCollectTime=cache('last_collect_time');
if(g_sc('c_caiji_interval')>0){
$waitTime=(60*g_sc('c_caiji_interval'))-abs(time()-$lastCollectTime);
if($waitTime>0){
$return=array(
'msg'=>'再次采集需等待'.self::wait_time_tips($waitTime),
'wait'=>$waitTime
);
}
}
return $return;
}
public static function wait_time_tips($seconds){
$seconds=intval($seconds);
if($seconds>0){
if($seconds<60){
$seconds.='秒';
}else{
$seconds=$seconds/60;
$seconds=substr(sprintf("%.3f", $seconds), 0, -2);
$seconds.='分钟';
}
}else{
$seconds='';
}
return $seconds;
}
}
?>

View File

@ -32,7 +32,7 @@ class DbCommon{
'break_reconnect'=>true,
'params'=>array(),
);
if(!empty($GLOBALS['_sc']['c']['site']['dblong'])){
if(!is_empty(g_sc_c('site','dblong'))){
$this->config['params'][\PDO::ATTR_PERSISTENT]=true;
}

View File

@ -10,19 +10,27 @@
*/
namespace skycaiji\admin\model;
class FuncApp extends BaseModel{
class FuncApp extends \skycaiji\common\model\BaseModel{
protected $tableName='func_app';
public $funcPath;
public $funcModules=array(
'process'=>array (
'name'=>'数据处理',
'loc'=>'数据处理»使用函数'
'loc'=>'任务»采集器设置»数据处理»使用函数',
'config'=>'allow_process_func',
'extend'=>'EXTEND_PROCESS_FUNC',
),
'processIf'=>array(
'name'=>'条件判断',
'loc'=>'数据处理»条件判断»使用函数'
)
'loc'=>'任务»采集器设置»数据处理»条件判断»使用函数',
'config'=>'allow_process_if',
'extend'=>'EXTEND_PROCESS_IF',
),
'downloadImg'=>array(
'name'=>'下载图片',
'loc'=>'设置»采集设置»图片本地化»使用函数',
)
);
public function __construct($data = []){
parent::__construct($data);
@ -34,7 +42,8 @@ class FuncApp extends BaseModel{
$data['module']=$this->format_module($data['module']);
$data['name']=strip_tags($data['name']);
$data['addtime']=time();
$data['enable']=0;
$data['enable']=intval($data['enable']);
$data['enable']=$data['enable']>0?1:0;
$data['uptime']=$data['uptime']>0?$data['uptime']:time();
return $this->strict(false)->insert($data,false,true);
}
@ -68,7 +77,7 @@ class FuncApp extends BaseModel{
$funcTpl=str_replace(array('{$module}','{$classname}','{$name}','{$methods}'), array($module,$app,$appData['name'],$appData['methods']), $funcTpl);
if(write_dir_file($funcFile,$funcTpl)){
return $this->insertApp(array('module'=>$module,'app'=>$app,'name'=>$name));
return $this->insertApp(array('module'=>$module,'app'=>$app,'name'=>$name,'enable'=>1));
}else{
return false;
}
@ -90,7 +99,7 @@ class FuncApp extends BaseModel{
return false;
}
$codeFmt=strip_phpcode_comment($code);
$codeFmt=\util\Funcs::strip_phpcode_comment($code);
if(!preg_match('/^\s*namespace\s+plugin\\\func\b/im',$codeFmt)){
@ -127,9 +136,9 @@ class FuncApp extends BaseModel{
return $this->funcPath."{$module}/{$app}.php";
}
/*获取插件文件类的属性*/
public function get_app_class($module,$app){
public function get_app_class($module,$app,$options=array()){
$module=$this->format_module($module);
$filename=$this->funcPath."{$module}/{$app}.php";
$filename=$this->filename($module,$app);
if(file_exists($filename)){
$class=$this->app_classname($module, $app);
if(class_exists($class)){
@ -149,18 +158,74 @@ class FuncApp extends BaseModel{
$reMethods=$reClass->getMethods(\ReflectionMethod::IS_PUBLIC);
$methods=array();
if(!empty($reMethods)){
$phpCode=array();
if(!empty($options['method_code'])||!empty($options['method_params'])){
$phpCode=file($filename);
}
foreach ($reMethods as $reMethod){
$methodData=array();
$methodName=$reMethod->name;
if(empty($methodName)||strpos($methodName,'__')===0){
continue;
}
$methodCmt=$reMethod->getDocComment();
if(empty($options['doc_comment'])){
$methodCmt=preg_replace('/^[\/\*\s]+/m', '', $methodCmt);
$methodCmt=trim($methodCmt);
}
$comment=$reMethod->getDocComment();
$comment=preg_replace('/^[\/\*\s]+/m', '', $comment);
$comment=trim($comment);
$methods[$methodName]=array('comment'=>$comment);
if(!empty($options['comment_cut'])){
$methodCmtCut='';
if($methodCmt){
$methodCmt=preg_replace('/^[\/\*\s]+/m', '', $methodCmt);
$methodCmt=trim($methodCmt);
$methodCmtCut=$methodCmt;
$methodCmtCut=htmlspecialchars($methodCmtCut,ENT_QUOTES);
$methodCmtCut=preg_replace('/[\r\n]+/', ' ', $methodCmtCut);
$methodCmtCut=trim($methodCmtCut);
$maxLen=50;
if(mb_strlen($methodCmtCut,'utf-8')>$maxLen){
$methodCmtCut=mb_substr($methodCmtCut,0,$maxLen,'utf-8').'...';
}
$methodCmt=htmlspecialchars($methodCmt,ENT_QUOTES);
$methodCmt=preg_replace('/[\r\n]+/', '\r\n', $methodCmt);
$methodCmt=trim($methodCmt);
}
$methodData['comment_cut']=$methodCmtCut;
}
$methodData['comment']=$methodCmt;
if(!empty($options['method_code'])||!empty($options['method_params'])){
$methodStart=$reMethod->getStartLine();
$methodEnd=$reMethod->getEndLine();
$methodCode=array_slice($phpCode, $methodStart-1, $methodEnd-$methodStart+1);
$methodCode=is_array($methodCode)?implode('',$methodCode):'';
if(!empty($options['method_code'])){
$methodData['code']=$methodCode;
}
if(!empty($options['method_params'])){
$methodParams='';
if(preg_match('/\bfunction\s+'.addslashes($methodName).'\s*\((.*?)\)\s*\{/i',$methodCode,$methodParams)){
$methodParams=$methodParams[1];
}else{
$methodParams='';
}
$methodData['params']=trim(htmlspecialchars($methodParams,ENT_QUOTES));
}
}
$methods[$methodName]=$methodData;
}
}
return array (
@ -170,7 +235,7 @@ class FuncApp extends BaseModel{
'copyright' => $copyright,
'identifier' => $identifier,
'name' => $name,
'methods' => $methods
'methods' => $methods,
);
}
}
@ -241,6 +306,167 @@ class FuncApp extends BaseModel{
return $appList;
}
/**
* 执行插件函数
* @param string $module 模块
* @param string $funcNameFmt 函数/方法
* @param string $defaultVal 默认传入值
* @param string $paramsStr 输入的参数(有换行符)
* @param array $paramValList 所有参数值(调用参数时使用)
*/
public function execute_func($module,$funcName,$defaultVal,$paramsStr,$paramValList=null){
static $func_class_list=array('process'=>array(),'processIf'=>array(),'downloadImg'=>array());
static $func_param_num_list=array('process'=>array(),'processIf'=>array(),'downloadImg'=>array());
$class_list=&$func_class_list[$module];
$param_num_list=&$func_param_num_list[$module];
$options = $this->funcModules[$module];
$return=array('success'=>false,'msg'=>'','data'=>null);
if(!empty($funcName)){
$funcNameFmt=strpos($funcName, ':')!==false?explode(':', $funcName):$funcName;
if(!is_array($funcNameFmt)){
if(!function_exists($funcNameFmt)&&$funcNameFmt!='empty'){
$return['msg']=$options['loc'].'»无效的函数:'.$funcNameFmt;
}elseif(!array_key_exists($funcNameFmt, config($options['config']))&&!array_key_exists($funcNameFmt, config($options['extend']))){
$return['msg']=$options['loc'].'»未配置函数:'.$funcNameFmt;
}else{
$return['success']=true;
}
}else{
$className=$funcNameFmt[0];
$methodName=$funcNameFmt[1];
if(!isset($class_list[$className])){
$enable=$this->field('enable')->where(array('app'=>$className,'module'=>$module))->value('enable');
if($enable){
$class=$this->app_classname($module,$className);
if(!class_exists($class)){
$class_list[$className]=1;
}else{
$class=new $class();
$class_list[$className]=$class;
}
}else{
$class_list[$className]=2;
}
}
if(is_object($class_list[$className])){
if(!method_exists($class_list[$className], $methodName)){
$return['msg']=$options['loc'].'»不存在方法:'.$className.'-&gt;'.$methodName;
}else{
$return['success']=true;
}
}else{
$msg=$options['loc'].'»';
if($class_list[$className]==1){
$msg.='不存在插件:';
}elseif($class_list[$className]==2){
$msg.='已禁用插件:';
}else{
$msg.='无效的插件:';
}
$return['msg']=$msg.$className;
}
}
if($return['success']){
static $func_param_list=array();
$funcParam=null;
if(empty($paramsStr)){
$funcParam=array($defaultVal);
}else{
$fparamMd5=md5($paramsStr);
if(!isset($func_param_list[$fparamMd5])){
if(preg_match_all('/[^\r\n]+/',$paramsStr,$mfuncParam)){
$func_param_list[$fparamMd5]=$mfuncParam[0];
}
}
$funcParam=$func_param_list[$fparamMd5];
if($funcParam){
foreach ($funcParam as $k=>$v){
$v=str_replace('###', $defaultVal, $v);
if($paramValList&&preg_match_all('/\[(?:\x{5b57}\x{6bb5}|\x{56fe}\x{7247})\:.+?\]/u',$v,$match_params)){
$match_params=$match_params[0];
for($i=0;$i<count($match_params);$i++){
$v=str_replace($match_params[$i],$paramValList[$match_params[$i]],$v);
}
}
$funcParam[$k]=$v;
}
}
}
if(!empty($funcParam)&&is_array($funcParam)){
try {
$callback=null;
$paramNum=array();
if(!is_array($funcNameFmt)){
if($funcNameFmt=='empty'){
$return['data']=empty($funcParam[0]);
}else{
$callback=$funcNameFmt;
if(!isset($param_num_list[$funcNameFmt])){
$refFunc=new \ReflectionFunction($funcNameFmt);
$param_num_list[$funcNameFmt]=array(
'num'=>intval($refFunc->getNumberOfParameters()),
'required'=>intval($refFunc->getNumberOfRequiredParameters()),
);
}
$paramNum=$param_num_list[$funcNameFmt];
}
}else{
$callback=array($class_list[$funcNameFmt[0]],$funcNameFmt[1]);
if(!isset($param_num_list[$funcName])){
$refMethod=(new \ReflectionClass($class_list[$funcNameFmt[0]]))->getMethod($funcNameFmt[1]);
$param_num_list[$funcName]=array(
'num'=>intval($refMethod->getNumberOfParameters()),
'required'=>intval($refMethod->getNumberOfRequiredParameters()),
);
}
$paramNum=$param_num_list[$funcName];
}
if($callback){
$paramCount=count($funcParam);
if($paramCount<$paramNum['required']){
$return['success']=false;
$return['msg']=$options['loc'].'»'.$funcName.'»至少传入'.$paramNum['required'].'个参数';
}elseif($paramCount>$paramNum['num']){
$funcParam=array_slice($funcParam,0,$paramNum['num']);
}
if($return['success']){
$return['data']=call_user_func_array($callback, $funcParam);
}
}
}catch (\Exception $ex){
$return['success']=false;
$return['msg']=$options['loc'].'»'.$funcName.'»运行错误:'.$ex->getMessage();
}
}
}
}
return $return;
}
}
?>

View File

@ -11,32 +11,198 @@
namespace skycaiji\admin\model;
/*第三方服务商*/
class Provider extends BaseModel{
/*匹配域名*/
public static function match_domain($url){
$domain=null;
class Provider extends \skycaiji\common\model\BaseModel{
public static function match_domain_http($url){
$domain='';
if(preg_match('/^\w+\:\/\/[\w\-]+(\.[\w\-]+)*(\:\d+){0,1}/', $url,$domain)){
$domain=rtrim($domain[0],'/');
$domain=strtolower($domain);
$domain=strtolower($domain[0]);
}else{
$domain=null;
$domain='';
}
return $domain;
return $domain?$domain:'';
}
public static function match_domain_name($url){
$domain='';
if(preg_match('/^\w+\:\/\/(?P<domain>[\w\-]+(\.[\w\-]+)*)(\:\d+){0,1}/', $url,$domain)){
$domain=strtolower($domain['domain']);
}else{
$domain='';
}
return $domain?$domain:'';
}
public static function is_official_url($url){
$domain=self::match_domain_http($url);
if(!empty($domain)&&in_array($domain,config('allow_origins'))){
return true;
}else{
return false;
}
}
public static function create_store_url($url,$urlPath,$urlParams=null){
if(empty($url)){
$url='https://www.skycaiji.com';
}
$urlParams=$urlParams?('?'.http_build_query($urlParams)):'';
$url=rtrim($url,'/').'/'.$urlPath.$urlParams;
return $url;
}
/*获取id*/
public function getIdByUrl($url){
$url=self::match_domain($url);
if(is_official_url($url)){
$domain=self::match_domain_http($url);
if(self::is_official_url($domain)){
$url=null;
$domain=null;
}
$id=0;
if(!empty($url)){
$id=model('Provider')->where('domain',$url)->value('id');
if(!empty($domain)){
$id=$this->where('domain',$domain)->value('id');
$id=intval($id);
}
return $id;
}
public function getAuthkey($provData){
$authkey='';
if(!empty($provData)){
$authkey=$provData['authkey'];
}else{
$authkey=g_sc_c('store','authkey_store');
}
if(empty($authkey)){
$authkey=g_sc_c('store','authkey');
}
return $authkey?$authkey:'';
}
public function getStoreUrl($provData){
$url='';
if(!empty($provData)){
$url=$provData['url'];
}else{
$url=self::create_store_url(null,'store');
}
return $url;
}
public function createAuthsign($authkey,$clientUrl,$storeUrl,$timestamp){
$data=array(
'authkey'=>$authkey?md5($authkey):'',
'client_domain'=>self::match_domain_name($clientUrl),
'store_domain'=>self::match_domain_name($storeUrl),
'timestamp'=>$timestamp,
);
ksort($data);
$data=md5(http_build_query($data));
return $data;
}
public function checkData($provData){
$result=array('success'=>false,'msg'=>'');
if(empty($provData)){
$result['msg']='未知的第三方平台';
}elseif(empty($provData['enable'])){
$result['msg']='未受信任的第三方平台:'.$provData['url'];
}else{
$result['success']=true;
}
return $result;
}
public function checkAuthkey($authkey,$sameAsPwd=false){
$result=array('success'=>false,'msg'=>'','data'=>array());
$authkey=$authkey?$authkey:'';
if(!empty($authkey)&&!preg_match('/^[a-zA-Z0-9]{6,100}$/i', $authkey)){
$result['msg']=lang('store_authkey_error');
}else{
$result['success']=true;
if(!$sameAsPwd){
$userData=g_sc('user');
if($userData['password']==\skycaiji\admin\model\User::pwd_encrypt($authkey,$userData['salt'])){
$result['success']=false;
$result['data']['same_as_pwd']='检测到通信密钥与登录密码一致,这容易导致密码泄露,确定设置为该值?';
}
}
}
return $result;
}
public function storeAuthResult(){
$storeUrl=input('store_url','','trim');
$authsign=input('authsign','','trim');
$timestamp=input('timestamp/d',0);
$result=array('success'=>false,'msg'=>'','data'=>array());
if(empty($storeUrl)){
$storeUrl=request()->server('HTTP_REFERER');
}
$storeUrl=$storeUrl?$storeUrl:'';
$provData=null;
$provId=$this->getIdByUrl($storeUrl);
if($provId>0){
$provData=$this->getById($provId);
$provData=empty($provData)?array():$provData->toArray();
$check=$this->checkData($provData);
if(!$check['success']){
$result['msg']=$check['msg'];
return $result;
}
}
if(empty($provData)&&!self::is_official_url($storeUrl)){
$result['msg']='未知的第三方来源:'.$storeUrl;
return $result;
}
$authkey=$this->getAuthkey($provData);
$clientinfo=clientinfo();
$clientSign=$this->createAuthsign($authkey,$clientinfo['url'],$storeUrl,$timestamp);
if($clientSign!=$authsign){
$msg='<div style="font-weight:normal;">验证失败,客户端的<a href="'.url('setting/store','',true,true).'" target="_blank" style="font-weight:bold;">通信密钥</a>与';
$msg.='<a href="'.self::create_store_url($provData?$provData['url']:null,'client/go/authkey',array('clientinfo'=>g_sc('clientinfo'))).'" target="_blank" style="font-weight:bold;">';
$msg.=($provData?'第三方':'云').'平台</a>中的不一致</div>';
$result['msg']=$msg;
return $result;
}else{
$nowTime=time();
if(abs($nowTime-$timestamp)>1000){
$result['msg']=sprintf('连接超时,请校对时间<br>平台端请求:%s<br>客户端响应:%s',date('Y-m-d H:i:s',$timestamp),date('Y-m-d H:i:s',$nowTime));
return $result;
}
}
$result['success']=true;
$result['data']['provider_id']=$provId;
return $result;
}
}
?>

View File

@ -11,12 +11,12 @@
namespace skycaiji\admin\model;
class Proxyip extends BaseModel {
class Proxyip extends \skycaiji\common\model\BaseModel {
public $name='proxy_ip';
public $setting;
public function __construct($data=[]){
parent::__construct($data);
$this->setting=$GLOBALS['_sc']['c']['proxy'];
$this->setting=g_sc_c('proxy');
}
/*数据库ip转换成get_html格式的ip*/
public function to_proxy_ip($proxyDbIp){
@ -45,21 +45,24 @@ class Proxyip extends BaseModel {
if(!empty($this->setting['open'])){
$cond=array();
$order=null;
if(!empty($this->setting['use'])){
if($this->setting['use']=='num'){
$cond['num']=array('lt',$this->setting['use_num']);
$order='no desc';
}elseif($this->setting['use']=='time'){
$cond['time']=array(array('eq',0),array('gt',time()-$this->setting['use_time']*60), 'or') ;
$cond['time']=array(array('eq',0),array('gt',time()-$this->setting['use_time']*60), 'or') ;
$order='no desc';
}
}else{
$cond['num']=array('lt',1);
}
$cond['invalid']=0;
$proxyipData=$this->where($cond)->find();
$proxyipData=$this->where($cond)->order($order)->find();
if(empty($proxyipData)&&!empty($this->setting['api']['open'])){
@ -69,12 +72,12 @@ class Proxyip extends BaseModel {
if($this->where('invalid',0)->count()<=0){
$this->add_api_ips($this->setting);
$proxyipData=$this->where($cond)->find();
$proxyipData=$this->where($cond)->order($order)->find();
}
}elseif($apiInsert=='end'){
$this->add_api_ips($this->setting);
$proxyipData=$this->where($cond)->find();
$proxyipData=$this->where($cond)->order($order)->find();
}
}
@ -91,9 +94,8 @@ class Proxyip extends BaseModel {
$this->strict(false)->where('1=1')->update(array('num'=>0));
}
$proxyipData=$this->where($cond)->find();
$proxyipData=$this->where($cond)->order($order)->find();
}
if(!empty($proxyipData)){
$upData=array();
@ -121,18 +123,18 @@ class Proxyip extends BaseModel {
}
/*ip失败次数*/
public function set_ip_failed($proxy_ip){
if(empty($this->setting['failed'])||$this->setting['failed']<=0){
return;
}
if(empty($proxy_ip)){
return;
}
$upData=array();
$upData['failed']=$proxy_ip['failed']+1;
if($upData['failed']>=$this->setting['failed']){
$upData['invalid']=1;
$upData['failed']=intval($proxy_ip['failed'])+1;
if(!empty($this->setting['failed'])){
if($upData['failed']>=$this->setting['failed']){
$upData['invalid']=1;
}
}
$this->strict(false)->where(array('ip'=>$proxy_ip['ip']))->update($upData);
}
@ -176,12 +178,12 @@ class Proxyip extends BaseModel {
}
return null;
}
/*转换api匹配格式*/
public function convert_format($format){
static $list=array();
$md5=md5($format);
if(!isset($list[$md5])){
$format=preg_replace('/\\\*([\'\/])/',"\\\\$1",$format);
$format=controller('admin/Cpattern','event')->correct_reg_pattern($format);
$format=str_replace(array('[ip]','[端口]','[用户名]','[密码]','(*)')
,array('(?P<ip>(\d+\.){3}\d+)','(?P<port>\d+)','(?P<user>[^\s\\\'\"\<\>\,]*)','(?P<pwd>[^\s\\\'\"\<\>\,]*)','[\s\S]*?')
,$format);
@ -192,10 +194,11 @@ class Proxyip extends BaseModel {
}
return $format;
}
/*转换成数据库形式*/
public function ips_format2db($ipList,$default=array()){
$ipList=is_array($ipList)?$ipList:array();
$default=is_array($default)?$default:array();
$nowTime=time();
foreach ($ipList as $k=>$ip){
if(empty($ip)||empty($ip['ip'])){
unset($ipList[$k]);
@ -208,7 +211,7 @@ class Proxyip extends BaseModel {
}
$ip['ip']=$ip['ip'].':'.$ip['port'];
$ip['type']=$default['type'];
$ip['addtime']=NOW_TIME;
$ip['addtime']=$nowTime;
unset($ip['port']);
$ipList[$k]=$ip;
}

View File

@ -11,7 +11,7 @@
namespace skycaiji\admin\model;
class Release extends BaseModel{
class Release extends \skycaiji\common\model\BaseModel{
public function getByTaskid($taskId){
static $dataList=array();
if(empty($taskId)){

View File

@ -12,7 +12,7 @@
namespace skycaiji\admin\model;
use think\Loader;
class ReleaseApp extends BaseModel{
class ReleaseApp extends \skycaiji\common\model\BaseModel{
protected $tableName='release_app';
public function addCms($cms,$code='',$tpl=''){
@ -21,14 +21,14 @@ class ReleaseApp extends BaseModel{
}
$cms['module']='cms';
$cms['uptime']=$cms['uptime']>0?$cms['uptime']:NOW_TIME;
$cms['uptime']=$cms['uptime']>0?$cms['uptime']:time();
if(!preg_match('/^([A-Z][a-z0-9]*){3}$/',$cms['app'])){
return false;
}
$codeFmt=strip_phpcode_comment($code);
$codeFmt=\util\Funcs::strip_phpcode_comment($code);
if(!preg_match('/^\s*namespace\s+plugin\\\release\b/im',$codeFmt)){
@ -48,7 +48,7 @@ class ReleaseApp extends BaseModel{
$success=true;
}else{
$cms['addtime']=NOW_TIME;
$cms['addtime']=time();
$this->isUpdate(false)->allowField(true)->save($cms);
$cms['id']=$this->id;
$success=$cms['id']>0?true:false;

View File

@ -11,7 +11,7 @@
namespace skycaiji\admin\model;
class Rule extends BaseModel{
class Rule extends \skycaiji\common\model\BaseModel{
}

View File

@ -10,7 +10,7 @@
*/
namespace skycaiji\admin\model;
class Task extends BaseModel{
class Task extends \skycaiji\common\model\BaseModel{
public function loadConfig($taskData){
$config=$taskData['config'];
if(empty($config)){
@ -26,44 +26,90 @@ class Task extends BaseModel{
static $global_config=null;
if(!isset($global_config)){
$global_config=$GLOBALS['_sc']['c'];
}
if(!empty($global_config['download_img']['download_img'])){
if($config['download_img']=='n'){
$GLOBALS['_sc']['c']['download_img']['download_img']=0;
}else{
$GLOBALS['_sc']['c']['download_img']['download_img']=1;
}
}else{
$GLOBALS['_sc']['c']['download_img']['download_img']=0;
}
if(!empty($global_config['proxy']['open'])){
if($config['proxy']=='n'){
$GLOBALS['_sc']['c']['proxy']['open']=0;
}else{
$GLOBALS['_sc']['c']['proxy']['open']=1;
}
}else{
$GLOBALS['_sc']['c']['proxy']['open']=0;
$global_config=g_sc('c');
}
static $imgParams=array('img_path','img_url','img_name','name_custom_path','name_custom_name');
set_g_sc(['c','caiji','interval'],empty($config['interval'])?g_sc('c_caiji_interval'):$config['interval']);
set_g_sc(['c','caiji','interval_html'],empty($config['interval_html'])?$global_config['caiji']['interval_html']:$config['interval_html']);
if(empty($config['real_time'])){
set_g_sc(['c','caiji','real_time'],$global_config['caiji']['real_time']);
}else{
set_g_sc(['c','caiji','real_time'],$config['real_time']=='n'?0:1);
}
if(empty($config['download_img'])){
set_g_sc(['c','download_img','download_img'],$global_config['download_img']['download_img']);
}else{
set_g_sc(['c','download_img','download_img'],$config['download_img']=='n'?0:1);
}
if(empty($config['img_func'])){
set_g_sc(['c','download_img','img_func'],$global_config['download_img']['img_func']);
}else{
set_g_sc(['c','download_img','img_func'],$config['img_func']=='n'?'':$config['img_func']);
}
if(empty($config['proxy'])){
set_g_sc(['c','proxy','open'],$global_config['proxy']['open']);
}else{
set_g_sc(['c','proxy','open'],$config['proxy']=='n'?0:1);
}
static $imgParams=array('img_path','img_url','img_name','name_custom_path','name_custom_name','interval_img','img_func_param');
foreach ($imgParams as $imgParam){
$GLOBALS['_sc']['c']['download_img'][$imgParam]=empty($config[$imgParam])?$global_config['download_img'][$imgParam]:$config[$imgParam];
set_g_sc(['c','download_img',$imgParam],empty($config[$imgParam])?$global_config['download_img'][$imgParam]:$config[$imgParam]);
}
if(empty($config['img_name'])){
$GLOBALS['_sc']['c']['download_img']['name_custom_path']=$global_config['download_img']['name_custom_path'];
$GLOBALS['_sc']['c']['download_img']['name_custom_name']=$global_config['download_img']['name_custom_name'];
set_g_sc(['c','download_img','name_custom_path'],$global_config['download_img']['name_custom_path']);
set_g_sc(['c','download_img','name_custom_name'],$global_config['download_img']['name_custom_name']);
}
}
public function backstage_task($taskId){
set_g_sc('backstage_task_runtime',time());
if($this->where('id',$taskId)->count()>0){
$mcache=\skycaiji\admin\model\CacheModel::getInstance('backstage_task');
$mcache->db()->strict(false)->insert(array(
'cname'=>$taskId,
'dateline'=>g_sc('backstage_task_runtime'),
'ctype'=>0,
'data'=>''
),true);
if(is_null(g_sc('backstage_task_ids'))){
set_g_sc('backstage_task_ids',array());
}
set_g_sc(['backstage_task_ids',$taskId],$taskId);
static $registered=false;
if(!$registered){
$registered=true;
register_shutdown_function(function(){
if(!is_empty(g_sc('backstage_task_ids'))&&is_array(g_sc('backstage_task_ids'))){
$mcache=\skycaiji\admin\model\CacheModel::getInstance('backstage_task');
$mcache->db()->strict(false)->where('cname','in',g_sc('backstage_task_ids'))->update(array('ctype'=>1,'data'=>time()));
}
});
}
}
}
}
?>

View File

@ -10,7 +10,7 @@
*/
namespace skycaiji\admin\model;
class Taskgroup extends BaseModel{
class Taskgroup extends \skycaiji\common\model\BaseModel{
/**
* 获取分级分组
*/

View File

@ -11,60 +11,11 @@
namespace skycaiji\admin\model;
class User extends BaseModel{
/*用户名是否正确*/
public static function right_username($username,$name='username'){
$return=array('name'=>$name);
if(!preg_match('/^.{3,15}$/i', $username)){
$return['msg']=lang('user_error_username');
}else{
$return['success']=true;
}
return $return;
}
/*邮箱是否正确*/
public static function right_email($email,$name='email'){
$return=array('name'=>$name,'field'=>'email');
if(!preg_match('/^[^\s]+\@([\w\-]+\.){1,}\w+$/i', $email)){
$return['msg']=lang('user_error_email');
}else{
$return['success']=true;
}
return $return;
}
/**
* 密码格式是否正确
* @param string $pwd
* @param string $name
* @return Ambigous <multitype:, multitype:string , multitype:boolean string >
*/
public static function right_pwd($pwd,$name='password'){
$return=array('name'=>$name);
if(!preg_match('/^[a-zA-Z0-9\`\~\!\@\#\$\%\^\*\(\)\-\_\+\=\|\{\}\[\]\:\;\,\.\?\&\'\"\<\>]{6,30}$/i', $pwd)){
$return['msg']=lang('user_error_password');
}else{
$return['success']=true;
}
return $return;
}
/**
* 验证密码是否一致
* @param string $pwd
* @param string $repwd
* @param string $name
* @return multitype:string |multitype:boolean string
*/
public static function right_repwd($pwd,$repwd,$name='repassword'){
if($pwd!=$repwd){
return array('msg'=>lang('user_error_repassword'),'name'=>$name);
}else{
return array('success'=>true,'name'=>$name);
}
}
class User extends \skycaiji\common\model\User{
/*用户组*/
public static function right_groupid($groupid,$name='groupid'){
$return=array('name'=>$name);
$count=model('Usergroup')->where('id',$groupid)->count();
$count=model('admin/Usergroup')->where('id',$groupid)->count();
if(empty($count)||$count<=0){
$return['msg']=lang('user_error_groupid');
}else{
@ -97,24 +48,6 @@ class User extends BaseModel{
}
return $check;
}
/*获取随机盐*/
public static function rand_salt($len=20){
$salt="QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm";
$salt=str_shuffle($salt);
if($len>=strlen($salt)){
return $salt;
}else{
return substr($salt,mt_rand(0,strlen($salt)-$len-1),$len);
}
}
/*密码加密*/
public static function pwd_encrypt($pwd,$salt=''){
$pwd=sha1($pwd);
if(!empty($salt)){
$pwd.=$salt;
}
return md5($pwd);
}
/*检测用户名正确且是否存在*/
public function checkUsername($username){
@ -177,6 +110,48 @@ class User extends BaseModel{
}
return array('success'=>true);
}
/*用户名小写化*/
public static function lower_username($username){
$name=$username?$username:'';
$name=trim($name);
$name=strtolower($name);
return $name;
}
/*生成用户唯一标识*/
public function generate_key($userData){
$key='';
if(!empty($userData)){
$username=self::lower_username($userData['username']);
$key=md5($username.':'.$userData['password']);
}
return $key;
}
/*设置登录session*/
public function setLoginSession($userData){
if(empty($userData)){
session('user_login',null);
session('is_admin',null);
}else{
session('user_login',array(
'uid'=>$userData['uid'],
'key'=>$this->generate_key($userData)
));
$mUg=model('admin/Usergroup');
$isAdmin=null;
$userGroup=$mUg->getById($userData['groupid']);
if($mUg->is_admin($userGroup)){
$isAdmin=true;
}
session('is_admin',$isAdmin);
}
}
}
?>

View File

@ -11,7 +11,7 @@
namespace skycaiji\admin\model;
class Usergroup extends BaseModel{
class Usergroup extends \skycaiji\common\model\BaseModel{
/*获取当前组的下属等级组*/
public function get_sub_level($groupid){
$group=$this->getById($groupid);
@ -22,7 +22,7 @@ class Usergroup extends BaseModel{
}
/*等级限制:判断当前用户组等级小于等于传入的等级*/
public function user_level_limit($level){
if($GLOBALS['_sc']['user']['group']['level']<=$level){
if(g_sc('user','group','level')<=$level){
return true;
}else{
return false;

View File

@ -13,7 +13,7 @@ namespace skycaiji\admin\validate;
use think\Validate;
class Taskgroup extends Validate{
protected $rule = [
'name'=>'require|unique:taskgroup',
'name'=>'require|unique:taskgroup',
];
protected $message = [

View File

@ -12,7 +12,7 @@ function apiop_show_msg(msg,success){
var apiName={'install':'安装','uninstall':'卸载','upgrade':'升级'};
var apiUrl='{$apiUrl}';
var op='{$op}';
$.ajax({
ajaxOpen({
type:'get',
dataType:'json',
url:apiUrl,
@ -20,7 +20,7 @@ function apiop_show_msg(msg,success){
if(typeof(data)=='object'){
if(data.status==1){
//接口执行成功
$.ajax({
ajaxOpen({
type:'get',
dataType:'json',
url:"{:url('App/'.$op.'?success=1&app='.$app)}",

View File

@ -18,47 +18,51 @@
<a href="javascript:;" id="enable" data-app="{$appData['app']}" data-enable="{$appData['config']['enable']}">{$appData['config']['enable']?'已开启':'已关闭'}</a>
</dd>
<dt>名称</dt>
<dd>{$appData['config']['name']}</dd>
<dd>{$appData['config']['name']}&nbsp;</dd>
<dt>标识</dt>
<dd>{$appData['app']}</dd>
<dd>{$appData['app']}&nbsp;</dd>
<dt>版本</dt>
<dd>
{$appData['config']['version']}
{$appData['config']['version']} &nbsp;
{if $newest_version}
&nbsp; <a href="javascript:;" id="newest_version" data-app="{$appData['app']}">新版本{$newest_version}</a>
<a href="javascript:;" id="newest_version" data-app="{$appData['app']}">新版本{$newest_version}</a>
{/if}
</dd>
<dt>框架</dt>
<dd>{$appData['config']['framework']?($appData['config']['framework'].$appData['config']['framework_version']):'自定义'}</dd>
<dd>{$appData['config']['framework']?($appData['config']['framework'].$appData['config']['framework_version']):'自定义'}&nbsp;</dd>
{if !empty($appData['config']['phpv'])}
<dt>PHP</dt>
<dd>最低要求php{$appData['config']['phpv']}版本</dd>
<dd>{$appData['config']['phpv']}</dd>
{/if}
<dt>首页</dt>
<dd>
<a href="{$appUrl}" target="_blank">应用首页</a>
</dd>
{if !empty($appData['config']['author'])}
<dt>作者</dt>
<dd>{$appData['config']['author']}</dd>
{/if}
{if !empty($provData)}
<dt>开发</dt>
<dd><a href="{:url('Develop/app?app='.$app)}" class="develop">开发应用</a></dd>
{if !empty($storeUrl)}
<dt>平台</dt>
<dd><a href="{:url('admin/mystore/store?url='.urlencode($provData['url']))}">第三方平台</a></dd>
{if $storeUrl==1}
<dd><a href="{:url('admin/mystore/store')}">云平台</a></dd>
{else/}
<dd><a href="{:url('admin/mystore/store?url='.rawurlencode($storeUrl))}">第三方平台</a></dd>
{/if}
{elseif !empty($appData['config']['website'])}
<dt>网站</dt>
<dd><a href="{$appData['config']['website']}" target="_blank">作者网站</a></dd>
{/if}
{if !empty($appData['config']['author'])}
<dt>作者</dt>
<dd>{$appData['config']['author']}&nbsp;</dd>
{/if}
{if $appData['config']['desc']}
<dt>描述</dt>
<dd>{$appData['config']['desc']}</dd>
<dd>{$appData['config']['desc']}&nbsp;</dd>
{/if}
<dt>开发</dt>
<dd><a href="{:url('Develop/app?app='.$app)}" class="develop">开发应用</a></dd>
</dl>
{else /}
<div class="manage-wrap">
<div class="iframe-loading"><div class="loading">&nbsp;</div>页面加载中...</div>
<div class="iframe-loading"><div class="loading"></div>页面加载中...</div>
<iframe src="{$navPacks[$navid]['nav_link']}" id="iframe_main" class="iframe-main" width="100%" height="100%" frameborder="0" scrolling="yes"></iframe>
</div>
{/if}

View File

@ -12,32 +12,5 @@
</div>
<script type="text/javascript">
'use strict';//严格模式
//任务列表
function win_bk_task_list(op,url){
$('#win_bk_'+op).html('<img src="'+window.site_config.pub+'/static/images/load1.gif" />');
$.ajax({
type: 'get',
dataType: 'json',
async:true,
url:(url?url:ulink('admin/backstage/backstageTask?op='+op)),
success: function (data){
if(data.code==1&&data.data){
var count=parseInt(data.data.count);
$('#win_backstage_task').find('a[href="#win_bk_'+op+'"]').tab('show').find('span').text(count);//显示数量
$('#win_bk_'+op).html(data.data.html);
}else{
$('#win_bk_'+op).html('无任务');
}
backstageTask();//重置数量
}
});
}
//加载任务列表
$('#win_backstage_task a[href="#win_bk_task0"],#win_backstage_task a[href="#win_bk_task1"]').bind('click',function(){
var op=$($(this).attr('href')).attr('data-op');
win_bk_task_list(op);
});
$('#win_backstage_task a[href="#win_bk_task0"]').trigger('click');//默认触发
winBackstageTask('init');
</script>

View File

@ -1,56 +1,42 @@
{if $list}
<div class="table-responsive">
<table class="table table-bordered table-hover datatable" style="margin-bottom:0;">
<thead>
<tr>
<th>#</th>
<th>已发布至</th>
<th>发布方式</th>
<th>添加时间</th>
<th class="url">源网址</th>
</tr>
</thead>
<tbody>
{php}$curIx=0;{/php}
{foreach name="list" item="item"}
<tr>
<td>{php}$curIx++;{/php}{$curIx}</td>
<td class="desc">
{if condition="!empty($item['error'])"}
失败:{$item['error']}
{else /}
{$item['target']} {$item['desc']?$item['desc']:''}
{/if}
</td>
<td>{:lang('collected_rele_'.$item['release'])}</td>
<td>{:date('Y-m-d H:i:s',$item['addtime'])}</td>
<td class="url"><a href="{$item['url']}" target="_blank">{$item['url']}</a></td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{if $pagenav}
<div class="box-body">{$pagenav}</div>
{/if}
<div class="table-responsive">
<table class="table table-bordered table-hover datatable" style="margin-bottom:0;">
<thead>
<tr>
<th>#</th>
<th>已发布至</th>
<th>发布方式</th>
<th>添加时间</th>
<th class="url">源网址</th>
</tr>
</thead>
<tbody>
{php}$curIx=0;{/php}
{foreach name="list" item="item"}
<tr>
<td>{php}$curIx++;{/php}{$curIx}</td>
<td class="desc">
{if condition="!empty($item['error'])"}
失败:{$item['error']}
{else /}
{$item['target']} {$item['desc']?$item['desc']:''}
{/if}
</td>
<td>{:lang('collected_rele_'.$item['release'])}</td>
<td>{:date('Y-m-d H:i:s',$item['addtime'])}</td>
<td class="url"><a href="{$item['url']}" target="_blank">{$item['url']}</a></td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{if $pagenav}
<div class="box-body">{$pagenav}</div>
{/if}
{else /}
<div class="box-body">无数据</div>
{/if}
<script type="text/javascript">
'use strict';//严格模式
$('[id^="win_bk_t_list_"] .pagination').addClass('pagination-sm');
$('[id^="win_bk_t_list_"] .pagination a').bind('click',function(){
var taskId=$(this).parents('[id^="win_bk_t_list_"]').eq(0).attr('data-task-id');
if(window.interval_bk_tasks[taskId]){
//停止自动刷新
clearInterval(window.interval_bk_tasks[taskId]);
}
win_bk_task_collected(taskId,$(this).attr('href'));
return false;
});
{if $taskStatus}
//正在采集任务已完成
$('#win_bk_task_list_0').find('a[href="#win_bk_t_list_{$taskId}"]').find('small').text('已结束');
{/if}
winBackstageTask('init_collected',{taskStatus:'{$taskStatus}',taskId:'{$taskId}'});
</script>

View File

@ -10,7 +10,7 @@
({$cacheList[$task['id']]['collected_count']})
<small>{$cacheList[$task['id']]['enddate']} 结束 </small>
{else /}
<small style="color:inherit;"><span class="fa fa-refresh fa-spin"></span></small>
<div class="is_loading" style="display:inline;"><div class="loading-sm"></div></div>
{/if}
</a>
</h4>
@ -18,7 +18,6 @@
</div>
<div id="win_bk_t_list_{$task['id']}" data-task-id="{$task['id']}" class="panel-collapse collapse">
<div class="box-body">
</div>
</div>
</div>
@ -33,67 +32,5 @@
</div>
<script type="text/javascript">
'use strict';//严格模式
//任务已采集数据
function win_bk_task_collected(taskId,url){
$('#win_bk_t_list_'+taskId+' .box-body').html('<img src="'+window.site_config.pub+'/static/images/load1.gif" />');
$.ajax({
type: 'get',
dataType: 'html',
async:true,
url:(url?url:ulink('admin/backstage/backstageTask?op=collected&tid='+taskId)),
success: function (data){
$('#win_bk_t_list_'+taskId).html(data);
}
});
}
if(!window.interval_bk_tasks){
//定时器全局变量
window.interval_bk_tasks={};
}
$('#win_bk_task_list_0 a[data-parent="#win_bk_task_list_0"]').bind('click',function(){
var taskId=$($(this).attr('href')).attr('data-task-id');
win_bk_task_collected(taskId);//先读取一次
//正在采集自动刷新
if(window.interval_bk_tasks[taskId]){
//先停止
clearInterval(window.interval_bk_tasks[taskId]);
}
window.interval_bk_tasks[taskId]=setInterval(function(){
if($('#win_bk_t_list_'+taskId).is(":hidden")){
//元素不可见停止刷新
clearInterval(window.interval_bk_tasks[taskId]);
}else{
win_bk_task_collected(taskId);
}
},3000);
});
$('#win_bk_task_list_1 a[data-parent="#win_bk_task_list_1"]').bind('click',function(){
//已采集任务
var taskId=$($(this).attr('href')).attr('data-task-id');
win_bk_task_collected(taskId);
});
$('[id^="win_bk_task_list_"] .fa-remove').bind('click',function(){
//删除后台任务
var obj=$(this);
var taskId=$(this).attr('data-task-id');
$.ajax({
type: 'get',
dataType: 'json',
async:true,
url:ulink('admin/task/bkdelete?id='+taskId),
success: function (data){
obj.parents('.panel').remove();
}
});
});
$('#win_bk_task_list_{$taskType} .pagination').addClass('pagination-sm');
$('#win_bk_task_list_{$taskType} .pagination a').bind('click',function(){
var op=$(this).parents('.tab-pane[data-op]').eq(0).attr('data-op');
win_bk_task_list(op,$(this).attr('href'));
return false;
});
winBackstageTask('init_list',{taskType:'{$taskType}'});
</script>

View File

@ -4,44 +4,44 @@
{/block}
{block name="content"}
<div class="row">
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-aqua"><i class="icon ion-ios-pulse"></i></span>
<div class="info-box-content">
<span class="info-box-text">今日采集</span>
<span class="info-box-number">{$runInfo['today_success']|intval}<small>条成功</small></span>
<span class="info-box-number">{$runInfo['today_error']|intval}<small>条失败</small></span>
</div>
</div>
<div class="col-lg-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-aqua"><i class="icon ion-ios-pulse"></i></span>
<div class="info-box-content">
<div class="info-box-text">今日采集</div>
<div class="info-box-number">{$runInfo['today_success']|intval}<div class="tips">条成功</div></div>
<div class="info-box-number">{$runInfo['today_error']|intval}<div class="tips">条失败</div></div>
</div>
</div>
</div>
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-red"><i class="icon ion-stats-bars"></i></span>
<div class="info-box-content">
<span class="info-box-text">已采集数据</span>
<span class="info-box-number">{$runInfo['total_success']|intval}<small>条成功</small></span>
<span class="info-box-number">{$runInfo['total_error']|intval}<small>条失败</small></span>
</div>
</div>
<div class="col-lg-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-red"><i class="icon ion-stats-bars"></i></span>
<div class="info-box-content">
<div class="info-box-text">已采集数据</div>
<div class="info-box-number">{$runInfo['total_success']|intval}<div class="tips">条成功</div></div>
<div class="info-box-number">{$runInfo['total_error']|intval}<div class="tips">条失败</div></div>
</div>
</div>
</div>
<div class="clearfix visible-sm-block"></div>
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-green"><i class="icon ion-ios-settings-strong"></i></span>
<div class="info-box-content">
<span class="info-box-text">任务</span>
<span class="info-box-number">{$runInfo['task_auto']|intval}<small>个自动任务</small></span>
<span class="info-box-number">{$runInfo['task_other']|intval}<small>个手动任务</small></span>
</div>
</div>
</div>
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="col-lg-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="icon ion-load-b"></i></span>
<div class="info-box-content">
<span class="info-box-text">自动采集</span>
<span class="info-box-number" style="margin-top:7px;">{$runInfo['auto_status']}</span>
</div>
<span class="info-box-icon bg-green"><i class="icon ion-ios-settings-strong"></i></span>
<div class="info-box-content">
<div class="info-box-text">任务</div>
<div class="info-box-number">{$runInfo['task_auto']|intval}<div class="tips">个自动任务</div></div>
<div class="info-box-number">{$runInfo['task_other']|intval}<div class="tips">个手动任务</div></div>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="icon ion-load-b"></i></span>
<div class="info-box-content">
<div class="info-box-text">自动采集</div>
<div class="info-box-number" style="margin-top:7px;">{$runInfo['auto_status']}</div>
</div>
</div>
</div>
</div>
@ -77,8 +77,10 @@
<tr>
<th>官方网站</th>
<td>
<a href="http://bbs.skycaiji.com" target="_blank">社区</a>&nbsp;
<a href="http://www.skycaiji.com" target="_blank">官网</a>
<ul class="in-line-mg">
<li><a href="http://bbs.skycaiji.com" target="_blank">社区</a></li>
<li><a href="https://www.skycaiji.com" target="_blank">官网</a></li>
</ul>
</td>
</tr>
<tr>
@ -117,10 +119,16 @@
</div>
</div>
</div>
{if !empty($openBasedir)}
<div class="alert alert-warning alert-dismissible" id="box_open_basedir">
<button type="button" class="close">×</button>
您的网站开启了目录访问限制(open_basedir),受保护的站点目录:{$openBasedir}这会影响到站点目录外的文件读写和CMS程序的访问。如果您未更改图片保存目录(站点目录外)并且cms程序都在站点目录内则可忽略该问题
</div>
{/if}
{if !empty($systemWarning)}
<div class="callout callout-warning">
<div class="alert alert-danger">
{if !empty($systemWarning['php'])}
请开启PHP模块{:implode(' , ',$systemWarning['php'])}<br/>
PHP缺少功能{:implode(' , ',$systemWarning['php'])}<br/>
{/if}
{if !empty($systemWarning['path_write'])}
请设置可写权限:{:implode(' , ',$systemWarning['path_write'])}<br/>
@ -130,7 +138,11 @@
{/if}
</div>
{/if}
<div id="invalid_list" style="display:none;">
<div class="alert alert-danger">
功能失效:<div data-box="1" style="display:inline;"></div>
</div>
</div>
<div class="box box-default">
<div class="box-header with-border">

View File

@ -11,6 +11,7 @@
<button type="button" id="btn_clear_error" class="btn btn-sm btn-warning" style="padding:2px 10px;">一键清理失败的数据</button>
</div>
<form id="form_list" method="post" ajax-submit="true" action="{:url('Collected/op')}">
{:html_usertoken()}
<div class="table-responsive">
<table id="list_table" class="table table-hover datatable">
<thead>
@ -65,6 +66,7 @@
<!-- /.box -->
<div class="list-footer">
<form id="form_search" method="post" action="{:url('Collected/list')}" class="form-inline">
{:html_usertoken()}
<div class="form-group form-group-sm">
<label>每页显示</label>
<select name="num" class="form-control">

View File

@ -0,0 +1,4 @@
<script type="text/javascript">
'use strict';//严格模式
collectorEchoMsg('run',{is_backstage:'{$is_backstage}',interval:'{$interval}',server_is_cli:'{$server_is_cli}',differ_seconds:'{$differ_seconds}'});
</script>

View File

@ -1,17 +0,0 @@
{if condition="!empty($collData)"}
<script src="__PUBLIC__/static/js/admin/store.js?{$Think.config.html_v}"></script>
<div>
<form id="win_form_save2store" action="https://www.skycaiji.com/client/rule/upload" method="post" target="myModalIframe">
<input type="hidden" name="rule" value="{:base64_encode(serialize($collData))}" />
</form>
<script type="text/javascript">
$(document).ready(function(){
/*利用iframe+form post提交*/
var formhtml=$('#win_form_save2store').prop("outerHTML")+'<script type="text\/javascript">$("#win_form_save2store").submit()<\/script>';
windowStore('正在上传...','',{addonBody:formhtml});
});
</script>
</div>
{else /}
规则不存在
{/if}

View File

@ -4,10 +4,12 @@
{/block}
{block name="content"}
<form id="form_coll" class="form-item" method="post" ajax-submit="true" role="form" action="{:url('Collector/set')}">
{:html_usertoken()}
<input type="hidden" name="task_id" value="{$taskData['id']}" />
<input type="hidden" name="module" value="{$taskData['module']}" />
<input type="hidden" name="tab_link" value="{:input('tab_link')}" />
<input type="hidden" name="effective" value="" />
<input type="hidden" name="effective_edit" value="" />
{if input('?easymode')}
<input type="hidden" name="easymode" value="1" />
{/if}

View File

@ -1,6 +0,0 @@
{if condition="!empty($GLOBALS['_sc']['browser_is_old'])"}
<div class="alert alert-error alert-dismissible fade in" role="alert" style="position:fixed;top:0;z-index:9999;width:100%;">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
您的浏览器版本过低不能完全展现页面效果请使用谷歌、火狐或IE9及以上版本的浏览器
</div>
{/if}

View File

@ -2,44 +2,5 @@
$_WP['title']=$msg;
{/php}
{include file="common:header_public" /}
<style type="text/css">
.content-wrapper{background:#fff;}
.breadcrumb{display:none!important;}
.msg_title{
line-height:30px;
margin-left:20px;
color:#2E99D4;
margin-top:10px;
font:16px "microsoft yahei",Arial,Verdana;
font-weight:bold;
}
.msg_message{
line-height:30px;
margin-left:20px;
color:#5C5C5C;
font:14px "microsoft yahei",Arial,Verdana;
}
</style>
</head>
<body class="hold-transition">
<div style="text-align:center;padding:100px 0;">
<img src="__PUBLIC__/static/images/error.png" />
<p class="msg_title">{$msg}</p>
<p class="msg_message">{:lang('return_home',array('url'=>$url,'time'=>'<span id="tmv" style="color:red;font-weight:bold;"></span>'))}</p>
</div>
<script type="text/javascript">
var waitTm={$wait?$wait:'3'};
function goHome(){
if(waitTm>=1){
document.getElementById('tmv').innerHTML=waitTm;
waitTm--;
setTimeout("goHome()",1000);
}else{
window.location.href="{$url}";
}
}
goHome();
</script>
{include file="common@common:message" _success="" /}
{include file="common:footer_public" /}

View File

@ -5,42 +5,5 @@ $_WP['title']=$msg;
{block name="cssjs"}
{/block}
{block name="content"}
<style type="text/css">
.content-wrapper{background:#fff;}
.breadcrumb{display:none!important;}
.msg_title{
line-height:30px;
margin-left:20px;
color:#2E99D4;
margin-top:10px;
font:16px "microsoft yahei",Arial,Verdana;
font-weight:bold;
}
.msg_message{
line-height:30px;
margin-left:20px;
color:#5C5C5C;
font:14px "microsoft yahei",Arial,Verdana;
}
</style>
<div style="text-align:center;padding:50px 0;">
<img src="__PUBLIC__/static/images/error.png" />
<p class="msg_title">{$msg}</p>
<p class="msg_message">{:lang('return_home',array('url'=>$url,'time'=>'<span id="tmv" style="color:red;font-weight:bold;"></span>'))}</p>
</div>
<script type="text/javascript">
var waitTm={$wait?$wait:'3'};
function goHome(){
if(waitTm>=1){
document.getElementById('tmv').innerHTML=waitTm;
waitTm--;
setTimeout("goHome()",1000);
}else{
window.location.href="{$url}";
}
}
goHome();
</script>
{include file="common@common:message" _success="" /}
{/block}

View File

@ -1,4 +1,4 @@
{include file="common:browser_is_old" /}
{include file="common@common:browser_is_old" /}
{include file="common@common:page_translator" /}
<footer class="footer-end">
<p>Powered by <a href="https://www.skycaiji.com" target="_blank">蓝天采集器</a></p>

View File

@ -4,8 +4,9 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<title>蓝天采集器 后台管理</title>
<title>{:g_sc('p_title')?(g_sc('p_title').' - '):''}蓝天采集器后台管理</title>
<meta name="generator" content="skycaiji" />
<link rel="icon" href="data:image/ico;base64,aWNv">
<!-- Bootstrap 3.3.7 -->
<link rel="stylesheet" href="__PUBLIC__/bootstrap/css/bootstrap.min.css?{$Think.config.html_v}">
<!-- Font Awesome -->
@ -45,4 +46,4 @@
<script src="__PUBLIC__/static/js/admin.js?{$Think.config.html_v}"></script>
<link href="__PUBLIC__/static/css/admin.css?{$Think.config.html_v}" rel="stylesheet" type="text/css">
<script type="text/javascript" src="__PUBLIC__/static/js/langs/{php}echo defined('LANG_SET')?LANG_SET:config('DEFAULT_LANG');{/php}.js?{$Think.config.html_v}"></script>
<script type="text/javascript">var site_config={root:"__ROOT__",pub:"__PUBLIC__",clientinfo:"{$GLOBALS['_sc']['clientinfo']}"};</script>
<script type="text/javascript">var site_config={root:"__ROOT__",pub:"__PUBLIC__",usertoken:"{:g_sc('usertoken')}",clientinfo:"{:g_sc('clientinfo')}"};</script>

View File

@ -26,10 +26,10 @@
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<span class="glyphicon glyphicon-user"></span>
<span>{$GLOBALS['_sc']['user']['username']}</span>
<span>{:g_sc('user','username')}</span>
</a>
<ul class="dropdown-menu">
<li><a href="{:url('User/edit?uid='.$GLOBALS['_sc']['user']['uid'])}">{$Think.lang.user_edit}</a></li>
<li><a href="{:url('User/edit?uid='.g_sc('user','uid'))}">{$Think.lang.user_edit}</a></li>
<li><a href="{:url('Admin/Index/logout')}">{$Think.lang.logout}</a></li>
</ul>
</li>
@ -52,6 +52,7 @@
<ul class="treeview-menu">
<li><a href="{:url('Admin/Setting/caiji')}"><i class="fa fa-circle-o"></i> {$Think.lang.setting_caiji}</a></li>
<li><a href="{:url('Admin/Setting/site')}"><i class="fa fa-circle-o"></i> {$Think.lang.setting_site}</a></li>
<li><a href="{:url('Admin/Setting/store')}"><i class="fa fa-circle-o"></i> {$Think.lang.setting_store}</a></li>
<li><a href="{:url('Admin/Setting/email')}"><i class="fa fa-circle-o"></i> {$Think.lang.setting_email}</a></li>
</ul>
</li>
@ -86,7 +87,7 @@
</span>
</a>
<ul class="treeview-menu">
<li><a href="{:url('Admin/Mystore/store')}"><i class="fa fa-circle-o"></i> 云平台</a></li>
<li><a href="{:url('Admin/Mystore/store')}" target="_blank"><i class="fa fa-circle-o"></i> 云平台</a></li>
<li><a href="{:url('Admin/Provider/list')}"><i class="fa fa-circle-o"></i> 第三方</a></li>
<li class="treeview menu-open">
<a href="#"><i class="fa fa-circle-o"></i> 已下载
@ -147,7 +148,7 @@
</ul>
</li>
<li><a href="{:url('Admin/Tool/fileManager')}"><i class="fa fa-circle-o"></i> 文件管理</a></li>
<li><a href="{:url('Admin/Tool/json_tree')}" target="_blank"><i class="fa fa-circle-o"></i> JSON解析</a></li>
<li><a href="{:url('Admin/Tool/json_tree')}"><i class="fa fa-circle-o"></i> JSON解析</a></li>
<li><a href="{:url('Admin/Tool/logs')}"><i class="fa fa-circle-o"></i> 错误日志</a></li>
<li class="treeview{$curSubm['checkfile']}{$curSubm['checkdb']}">
<a href="#"><i class="fa fa-circle-o"></i> 校验
@ -183,10 +184,10 @@
</aside>
<div class="content-wrapper">
<section class="content-header">
<h1>{$GLOBALS['_sc']['p_name']}</h1>
<h1>{:g_sc('p_name')}</h1>
<ol class="breadcrumb">
<li><a href="{:url('Admin/Backstage/index')}"><i class="fa fa-dashboard"></i> {$Think.lang.admincp}</a></li>
{$GLOBALS['_sc']['p_nav']}
{:g_sc('p_nav')}
</ol>
</section>
<section class="content">

View File

@ -2,44 +2,5 @@
$_WP['title']=$msg;
{/php}
{include file="common:header_public" /}
<style type="text/css">
.content-wrapper{background:#fff;}
.breadcrumb{display:none!important;}
.msg_title{
line-height:30px;
margin-left:20px;
color:#2E99D4;
margin-top:10px;
font:16px "microsoft yahei",Arial,Verdana;
font-weight:bold;
}
.msg_message{
line-height:30px;
margin-left:20px;
color:#5C5C5C;
font:14px "microsoft yahei",Arial,Verdana;
}
</style>
</head>
<body class="hold-transition">
<div style="text-align:center;padding:100px 0;">
<img src="__PUBLIC__/static/images/success.jpg" />
<p class="msg_title">{$msg}</p>
<p class="msg_message">{:lang('return_home',array('url'=>$url,'time'=>'<span id="tmv" style="color:red;font-weight:bold;"></span>'))}</p>
</div>
<script type="text/javascript">
var waitTm={$wait?$wait:'3'};
function goHome(){
if(waitTm>=1){
document.getElementById('tmv').innerHTML=waitTm;
waitTm--;
setTimeout("goHome()",1000);
}else{
window.location.href="{$url}";
}
}
goHome();
</script>
{include file="common@common:message" _success="1" /}
{include file="common:footer_public" /}

View File

@ -5,42 +5,5 @@ $_WP['title']=$msg;
{block name="cssjs"}
{/block}
{block name="content"}
<style type="text/css">
.content-wrapper{background:#fff;}
.breadcrumb{display:none!important;}
.msg_title{
line-height:30px;
margin-left:20px;
color:#2E99D4;
margin-top:10px;
font:16px "microsoft yahei",Arial,Verdana;
font-weight:bold;
}
.msg_message{
line-height:30px;
margin-left:20px;
color:#5C5C5C;
font:14px "microsoft yahei",Arial,Verdana;
}
</style>
<div style="text-align:center;padding:50px 0;">
<img src="__PUBLIC__/static/images/success.jpg" />
<p class="msg_title">{$msg}</p>
<p class="msg_message">{:lang('return_home',array('url'=>$url,'time'=>'<span id="tmv" style="color:red;font-weight:bold;"></span>'))}</p>
</div>
<script type="text/javascript">
var waitTm={$wait?$wait:'3'};
function goHome(){
if(waitTm>=1){
document.getElementById('tmv').innerHTML=waitTm;
waitTm--;
setTimeout("goHome()",1000);
}else{
window.location.href="{$url}";
}
}
goHome();
</script>
{include file="common@common:message" _success="1" /}
{/block}

View File

@ -16,11 +16,11 @@
<span class="skycaiji-b-l">当前元素的xpath</span>
<div class="skycaiji-b-c"><input skycaiji-id="xpath" /></div>
<div class="skycaiji-b-r">
<a href="javascript:;" skycaiji-id="show-xpath" data-val="1">显示</a> /
<a href="javascript:;" title="当前元素的所有属性" skycaiji-id="obj-prop">属性</a> /
<a href="javascript:;" title="清理界面" skycaiji-id="obj-clear">清理</a> /
<a href="javascript:;" title="当前元素的父元素" skycaiji-id="obj-parent">父元素</a> /
<a href="javascript:;" title="当前元素的子元素" skycaiji-id="obj-child">子元素</a>
<div style="display:inline;"><a href="javascript:;" skycaiji-id="show-xpath" data-val="1">显示</a> /</div>
<div style="display:inline;"><a href="javascript:;" title="当前元素的所有属性" skycaiji-id="obj-prop">属性</a> /</div>
<div style="display:inline;"><a href="javascript:;" title="清理界面" skycaiji-id="obj-clear">清理</a> /</div>
<div style="display:inline;"><a href="javascript:;" title="当前元素的父元素" skycaiji-id="obj-parent">父元素</a> /</div>
<div style="display:inline;"><a href="javascript:;" title="当前元素的子元素" skycaiji-id="obj-child">子元素</a></div>
</div>
</div>
<div class="skycaiji-block">

View File

@ -1,34 +1,22 @@
{extend name="common:main_clean" /}
{block name="cssjs"}
<link rel="stylesheet" href="__PUBLIC__/static/css/cpattern_browser.css?{$Think.config.html_v}">
<script type="text/javascript" src="__PUBLIC__/jquery/jquery.min.js?{$Think.config.html_v}"></script>
<script type="text/javascript" src="__PUBLIC__/static/js/admin/cpattern_browser.js?{$Think.config.html_v}"></script>
<style type="text/css">
#json_tree{width:100%;overflow:hidden;}
#json_tree ul{list-style:none;margin:0px;padding:0px;padding-left:20px;}
#json_tree li{padding:0;margin:0;}
#json_tree .tree{cursor:pointer;margin-left:-16px;margin-right:2px;}
#json_tree .node{color:#7F007F;}
#json_tree .val{}
</style>
<script src="__PUBLIC__/static/js/admin/json_tree.js?{$Think.config.html_v}"></script>
<script src="__PUBLIC__/static/js/admin/tool_json_tree.js?{$Think.config.html_v}"></script>
{/block}
{block name="content"}
<div class="form-group" style="padding-top:10px;">
<label>抓取到JSON字符串</label>
<textarea id="txt_json" rows="3" class="form-control">{$jsonHtml}</textarea>
<textarea id="txt_json" rows="3" class="form-control">{$jsonHtml|htmlspecialchars}</textarea>
</div>
<label>JSON解析</label>
<div id="json_tree"></div>
<div id="tool_json_tree"></div>
<script type="text/javascript">
'use strict';//严格模式
$(document).ready(function(){
jsonTree.treeId='#json_tree';
jsonTree.treeClass='.tree';
jsonTree.load($('#txt_json').val());
window.tool_json_tree.treeId='#tool_json_tree';
window.tool_json_tree.load($('#txt_json').val());
});
</script>
{/block}

View File

@ -19,6 +19,15 @@
</ul>
</div>
<input type="text" id="browser_url" class="form-control" placeholder="请输入网址" />
<input type="hidden" id="browser_urls" />
<div class="input-group-addon" style="padding:0;border:0;width:110px;">
<select class="form-control" id="browser_source">
<option value="">页面类型</option>
{foreach $pageSources as $k=>$v}
<option value="{$k}"{if $k=='url'} selected="selected"{/if}>{$v}</option>
{/foreach}
</select>
</div>
<span class="input-group-btn">
<button class="btn btn-primary" type="button" id="btn_browser">分析网页</button>
</span>

View File

@ -1,4 +1,6 @@
<form id="form_field" method="post" action="{:url('Cpattern/field')}">
{:html_usertoken()}
<input type="hidden" name="is_submit" value="1" />
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<div class="input-group">
@ -37,33 +39,7 @@
</div>
<div id="c_p_field_module">
<div class="c-p-field-module" module="rule">
<div class="form-group">
<label>规则</label>
<div class="input-group">
<textarea name="field[rule]" class="form-control" rows="3" placeholder="{$Think.lang.tips_match}">{$field['rule']}</textarea>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'field[rule]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
<a href="javascript:;" title="{$Think.lang.tips_sign_match}" class="blk" onclick="cpMatch('[name=\'field[rule]\']')">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group}" class="blk" onclick="cpMatch('[name=\'field[rule]\']',{group:1})">捕获组</a>
</div>
</div>
</div>
<div class="form-group">
<label>拼接成最终内容</label>
<div class="input-group">
<textarea name="field[rule_merge]" class="form-control" rows="2" placeholder="默认拼接所有{:cp_sign('match')}标签,{$Think.lang.tips_matchn}">{$field['rule_merge']}</textarea>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="调用规则中的标签" onclick="cpMatchN('[name=\'field[rule]\']','[name=\'field[rule_merge]\']')">{:cp_sign('match','N')}</a>
</div>
</div>
</div>
<div class="checkbox"><label><input type="checkbox" name="field[rule_multi]" value="1" {$field['rule_multi']?'checked="checked"':''}"> 允许匹配多个元素</label></div>
<div class="input-group" style="display:none;" id="c_p_field_rule_multi_str">
<div class="input-group-addon" style="border-right:0;"><label class="radio-inline"><input type="radio" name="field[rule_multi_type]" value="">拼接为文本</label></div>
<input type="text" style="border-left-style:dashed;" name="field[rule_multi_str]" class="form-control" placeholder="多个元素之间分隔符">
<div class="input-group-addon"><label class="radio-inline"><input type="radio" name="field[rule_multi_type]" value="loop">循环入库</label></div>
</div>
{include file="cpattern:field_rule" _type="rule" _name_pre="" _allow_loop="1" /}
</div>
<div class="c-p-field-module" module="auto" style="display:none;">
<div class="form-group" style="text-align:center;">
@ -89,37 +65,7 @@
</div>
</div>
<div class="c-p-field-module" module="xpath" style="display:none;">
<div class="form-group">
<label>规则</label>
<textarea name="field[xpath]" class="form-control" rows="3">{$field['xpath']}</textarea>
</div>
<div class="form-group">
<label>属性</label>
<select name="field[xpath_attr]" class="form-control">
<option value=""></option>
<option value="innerHtml">innerHtml</option>
<option value="outerHtml">outerHtml</option>
<option value="text">text</option>
<option value="value">value</option>
<option value="id">id</option>
<option value="class">class</option>
<option value="name">name</option>
<option value="href">href</option>
<option value="src">src</option>
<option value="style">style</option>
<option value="width">width</option>
<option value="height">height</option>
<option value="alt">alt</option>
<option value="custom">自定义</option>
</select>
</div>
<input type="text" class="form-control" name="field[xpath_attr_custom]" style="margin-top:10px;display:none;">
<div class="checkbox"><label><input type="checkbox" name="field[xpath_multi]" value="1" {$field['xpath_multi']?'checked="checked"':''}> 允许匹配多个节点</label></div>
<div class="input-group" style="display:none;" id="c_p_field_xpath_multi_str">
<div class="input-group-addon" style="border-right:0;"><label class="radio-inline"><input type="radio" name="field[xpath_multi_type]" value="">拼接为文本</label></div>
<input type="text" style="border-left-style:dashed;" name="field[xpath_multi_str]" class="form-control" placeholder="多个节点之间分隔符">
<div class="input-group-addon"><label class="radio-inline"><input type="radio" name="field[xpath_multi_type]" value="loop">循环入库</label></div>
</div>
{include file="cpattern:field_rule" _type="xpath" _name_pre="" _allow_loop="1" /}
</div>
<div class="c-p-field-module" module="words" style="display:none;">
<textarea name="field[words]" class="form-control" rows="3">{$field['words']}</textarea>
@ -137,10 +83,17 @@
<div class="input-group-addon">格式</div>
<input type="text" name="field[time_format]" class="form-control" />
</div>
<p class="help-block" id="c_p_field_time_format_list">
标签:<a href="javascript:;" data-val="[年]">[]</a> &nbsp; <a href="javascript:;" data-val="[月]">[]</a> &nbsp; <a href="javascript:;" data-val="[日]">[]</a> &nbsp;
<a href="javascript:;" data-val="[时]">[]</a> &nbsp; <a href="javascript:;" data-val="[分]">[]</a> &nbsp; <a href="javascript:;" data-val="[秒]">[]</a>
</p>
<div class="help-block" id="c_p_field_time_format_list">
<span>标签:</span>
<ul class="in-line-mg">
<li><a href="javascript:;" data-val="[年]">[]</a></li>
<li><a href="javascript:;" data-val="[月]">[]</a></li>
<li><a href="javascript:;" data-val="[日]">[]</a></li>
<li><a href="javascript:;" data-val="[时]">[]</a></li>
<li><a href="javascript:;" data-val="[分]">[]</a></li>
<li><a href="javascript:;" data-val="[秒]">[]</a></li>
</ul>
</div>
<div class="input-group">
<div class="input-group-addon">范围随机</div>
<input type="text" name="field[time_start]" class="form-control" placeholder="默认当前时间" />
@ -159,28 +112,12 @@
<div id="c_p_field_merge_list" style="margin-top:5px;"></div>
</div>
<div class="c-p-field-module" module="json" style="display:none;">
<div class="form-group">
<label>提取规则</label>
<input type="text" name="field[json]" class="form-control" />
<p class="help-block">直接输入键名,子元素用:[a][b][c]或a.b.c通配符*</p>
</div>
<div class="form-group">
<div class="checkbox"><label><input type="checkbox" name="field[json_loop]" value="1" {$field['json_loop']?'checked="checked"':''}> 匹配到多个节点允许循环入库</label></div>
</div>
<div class="form-group">
<label>节点值是数组转换为</label>
<select name="field[json_arr]" class="form-control">
<option value="implode">字符串</option>
<option value="jsonencode">json编码</option>
<option value="serialize">序列化</option>
</select>
<textarea name="field[json_arr_implode]" class="form-control" rows="1" placeholder="输入分隔符" style="margin-top:5px;">{$field['json_arr_implode']}</textarea>
</div>
{include file="cpattern:field_rule" _type="json" _name_pre="" _allow_loop="1" /}
</div>
<div class="c-p-field-module" module="extract" style="display:none;">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">选择字段</div>
<div class="input-group-addon" style="background:#f4f4f4;">选择字段</div>
<select name="field[extract]" class="form-control">
<option value="">请选择</option>
</select>
@ -188,7 +125,7 @@
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">提取内容</div>
<div class="input-group-addon" style="background:#f4f4f4;">提取内容</div>
<select name="field[extract_module]" class="form-control">
<option value="">请选择</option>
<option value="cover">第一张图片</option>
@ -201,63 +138,20 @@
</div>
</div>
<div class="c-p-field-extract-module" extract-module="rule" style="display:none;">
<div class="input-group">
<textarea name="field[extract_rule]" class="form-control" rows="3" placeholder="{$Think.lang.tips_match_only}">{$field['extract_rule']}</textarea>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'field[extract_rule]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
<a href="javascript:;" title="{$Think.lang.tips_sign_match_only}" class="blk" onclick="cpMatch('[name=\'field[extract_rule]\']',{only:1})">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group_only}" class="blk" onclick="cpMatch('[name=\'field[extract_rule]\']',{only:1,group:1})">捕获组</a>
</div>
</div>
<p class="help-block"><b>{:cp_sign('match')}</b>标签可获取匹配的数据,否则获取完全匹配的数据</p>
{include file="cpattern:field_rule" _type="rule" _name_pre="extract_" _allow_loop="" /}
</div>
<div class="c-p-field-extract-module" extract-module="xpath" style="display:none;">
<textarea name="field[extract_xpath]" class="form-control" rows="2" placeholder="xpath规则">{$field['extract_xpath']}</textarea>
<div class="input-group" style="margin-top:10px;">
<div class="input-group-addon">属性</div>
<select name="field[extract_xpath_attr]" class="form-control">
<option value=""></option>
<option value="innerHtml">innerHtml</option>
<option value="outerHtml">outerHtml</option>
<option value="text">text</option>
<option value="value">value</option>
<option value="id">id</option>
<option value="class">class</option>
<option value="name">name</option>
<option value="href">href</option>
<option value="src">src</option>
<option value="style">style</option>
<option value="width">width</option>
<option value="height">height</option>
<option value="alt">alt</option>
<option value="custom">自定义</option>
</select>
</div>
<input type="text" class="form-control" name="field[extract_xpath_attr_custom]" placeholder="自定义属性" style="margin-top:10px;display:none;">
{include file="cpattern:field_rule" _type="xpath" _name_pre="extract_" _allow_loop="" /}
</div>
<div class="c-p-field-extract-module" extract-module="json" style="display:none;">
<div class="form-group">
<label>提取规则</label>
<input type="text" name="field[extract_json]" class="form-control" />
<p class="help-block">直接输入键名,子元素用:[a][b][c]或a.b.c通配符*</p>
</div>
<div class="form-group">
<label>结果是数组则转换为</label>
<select name="field[extract_json_arr]" class="form-control">
<option value="implode">字符串</option>
<option value="jsonencode">json编码</option>
<option value="serialize">序列化</option>
</select>
<textarea name="field[extract_json_arr_implode]" class="form-control" rows="1" placeholder="输入分隔符" style="margin-top:5px;">{$field['extract_json_arr_implode']}</textarea>
</div>
{include file="cpattern:field_rule" _type="json" _name_pre="extract_" _allow_loop="" /}
</div>
</div>
<div class="c-p-field-module" module="sign" style="display:none;">
<div class="form-group">
<textarea name="field[sign]" class="form-control" rows="3" placeholder="填入数据源“提取网址规则”中{:cp_sign('match')}标签">{$field['sign']}</textarea>
<div id="c_p_field_sign_list" style="margin-top:5px;"></div>
<p class="help-block"></p>
<textarea name="field[sign]" class="form-control" rows="3" placeholder="填入数据源页面中区域规则或网址规则里的{:cp_sign('match')}标签">{$field['sign']}</textarea>
<div id="c_p_field_sign_list" style="margin-top:10px;"></div>
<p class="help-block">如果区域和网址中存在同名标签,实际获取网址中的标签</p>
</div>
</div>
</div>
@ -269,8 +163,8 @@
<script type="text/javascript">
{if condition="$field"}
c_pattern.field_op('init',{field:{$field|json_encode}});
c_pattern.cpField.init({$field|json_encode});
{else /}
c_pattern.field_op('init');
c_pattern.cpField.init();
{/if}
</script>

View File

@ -0,0 +1,102 @@
{assign name="_tpl_type" value="[_type]" /}
{assign name="_tpl_name_pre" value="[_name_pre]" /}
{assign name="_tpl_allow_loop" value="[_allow_loop]" /}
{if $_tpl_type=='rule'}
<div class="form-group">
<label>规则</label>
<div class="input-group">
<textarea name="field[{$_tpl_name_pre}rule]" class="form-control" rows="3" placeholder="{$Think.lang.tips_match}"></textarea>
<div class="input-group-addon iga-rt">
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'field[{$_tpl_name_pre}rule]\']')">{$Think.lang.sign_wildcard}</a></div>
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_match}" onclick="cpMatch('[name=\'field[{$_tpl_name_pre}rule]\']')">{:cp_sign('match')}</a></div>
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_group}" class="blk" onclick="cpMatch('[name=\'field[{$_tpl_name_pre}rule]\']',{group:1})">捕获组</a></div>
<div>
<span title="{$Think.lang.tips_regular}">正则</span>
<a href="javascript:;" title="提示信息" class="glyphicon glyphicon-info-sign" style="font-size:11px;" onclick="cpRuleTips()"></a>
</div>
</div>
</div>
<p class="help-block">规则中无{:cp_sign('match')}标签时,自动将完全匹配的值保存为{:cp_sign('match')}标签以供拼接调用</p>
</div>
<div class="form-group">
<label>拼接成最终内容</label>
<div class="input-group">
<textarea name="field[{$_tpl_name_pre}rule_merge]" class="form-control" rows="2" placeholder="默认拼接规则中所有{:cp_sign('match')}标签,{$Think.lang.tips_matchn}"></textarea>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="调用规则中的标签" onclick="cpMatchN('[name=\'field[{$_tpl_name_pre}rule]\']','[name=\'field[{$_tpl_name_pre}rule_merge]\']',{def:1})">{:cp_sign('match','N')}</a>
</div>
</div>
</div>
<div class="checkbox"><label><input type="checkbox" name="field[{$_tpl_name_pre}rule_multi]" value="1"> 允许匹配多个结果</label></div>
<div class="input-group" style="display:none;" id="c_p_field_{$_tpl_name_pre}rule_multi_str">
{if $_tpl_allow_loop}
<div class="input-group-addon" style="border-right:0;"><label class="radio-inline"><input type="radio" name="field[{$_tpl_name_pre}rule_multi_type]" value="">拼接为文本 <span title="提示信息" class="glyphicon glyphicon-info-sign icon-delimiter-tips" onclick="cpDelimiterTips()"></span></label></div>
<input type="text" style="border-left-style:dashed;" name="field[{$_tpl_name_pre}rule_multi_str]" class="form-control" placeholder="多个结果之间分隔符">
<div class="input-group-addon"><label class="radio-inline"><input type="radio" name="field[{$_tpl_name_pre}rule_multi_type]" value="loop">循环入库</label></div>
{else /}
<input type="text" name="field[{$_tpl_name_pre}rule_multi_str]" class="form-control" placeholder="多个结果之间分隔符" />
<div class="input-group-addon" style="padding-left:9px;padding-right:9px;"><span title="提示信息" class="glyphicon glyphicon-info-sign icon-delimiter-tips" onclick="cpDelimiterTips()"></span></div>
{/if}
</div>
{elseif $_tpl_type=='xpath' /}
<div class="form-group">
<label>规则</label>
<textarea name="field[{$_tpl_name_pre}xpath]" class="form-control" rows="3" placeholder="xpath规则"></textarea>
</div>
<div class="form-group">
<label>属性</label>
<select name="field[{$_tpl_name_pre}xpath_attr]" class="form-control">
<option value=""></option>
<option value="innerHtml">innerHtml</option>
<option value="outerHtml">outerHtml</option>
<option value="text">text</option>
<option value="value">value</option>
<option value="id">id</option>
<option value="class">class</option>
<option value="name">name</option>
<option value="href">href</option>
<option value="src">src</option>
<option value="style">style</option>
<option value="width">width</option>
<option value="height">height</option>
<option value="alt">alt</option>
<option value="custom">自定义</option>
</select>
<input type="text" class="form-control" name="field[{$_tpl_name_pre}xpath_attr_custom]" style="margin-top:10px;display:none;">
</div>
<div class="checkbox"><label><input type="checkbox" name="field[{$_tpl_name_pre}xpath_multi]" value="1"> 允许匹配多个结果</label></div>
<div class="input-group" style="display:none;" id="c_p_field_{$_tpl_name_pre}xpath_multi_str">
{if $_tpl_allow_loop}
<div class="input-group-addon" style="border-right:0;"><label class="radio-inline"><input type="radio" name="field[{$_tpl_name_pre}xpath_multi_type]" value="">拼接为文本 <span title="提示信息" class="glyphicon glyphicon-info-sign icon-delimiter-tips" onclick="cpDelimiterTips()"></span></label></div>
<input type="text" style="border-left-style:dashed;" name="field[{$_tpl_name_pre}xpath_multi_str]" class="form-control" placeholder="多个结果之间分隔符">
<div class="input-group-addon"><label class="radio-inline"><input type="radio" name="field[{$_tpl_name_pre}xpath_multi_type]" value="loop">循环入库</label></div>
{else /}
<input type="text" name="field[{$_tpl_name_pre}xpath_multi_str]" class="form-control" placeholder="多个结果之间分隔符" />
<div class="input-group-addon" style="padding-left:9px;padding-right:9px;"><span title="提示信息" class="glyphicon glyphicon-info-sign icon-delimiter-tips" onclick="cpDelimiterTips()"></span></div>
{/if}
</div>
{elseif $_tpl_type=='json' /}
<div class="form-group">
<label>提取规则</label>
<input type="text" name="field[{$_tpl_name_pre}json]" class="form-control" />
<p class="help-block">直接输入键名,子元素用:[a][b][c]或a.b.c通配符*</p>
</div>
{if $_tpl_allow_loop}
<div class="form-group">
<div class="checkbox"><label><input type="checkbox" name="field[{$_tpl_name_pre}json_loop]" value="1"> 匹配到多个结果允许循环入库</label></div>
</div>
{/if}
<div class="form-group">
<label>结果是数组则转换为</label>
<select name="field[{$_tpl_name_pre}json_arr]" class="form-control">
<option value="implode">字符串</option>
<option value="jsonencode">json编码</option>
<option value="serialize">序列化</option>
</select>
<div class="input-group" id="c_p_field_{$_tpl_name_pre}json_arr_implode" style="margin-top:5px;">
<textarea name="field[{$_tpl_name_pre}json_arr_implode]" class="form-control" rows="1" placeholder="输入分隔符"></textarea>
<div class="input-group-addon" style="padding-left:9px;padding-right:9px;"><span title="提示信息" class="glyphicon glyphicon-info-sign icon-delimiter-tips" onclick="cpDelimiterTips()"></span></div>
</div>
</div>
{/if}

View File

@ -1,114 +1,20 @@
<form id="form_level_url" method="post" action="{:url('Cpattern/level_url')}">
{:html_usertoken()}
<input type="hidden" name="is_submit" value="1" />
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<label class="control-label">多级名称</label>
<label class="control-label">多级名称</label>
<input type="text" class="form-control" name="level_url[name]" placeholder=""/>
</div>
<div class="form-group">
<label class="control-label">获取网址区域</label>
<div class="input-group">
<textarea name="level_url[area]" class="form-control" rows="3" data-placeholder-json="请输入json规则默认获取所有字符" data-placeholder-xpath="请输入xpath规则默认获取整个页面" placeholder="默认整个页面,{$Think.lang.tips_match_only}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="level_url[area_module]" data-rule-input="level_url[area]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul data-rule-op="level_url[area_module]" class="op">
<li data-module="" style="display:block;">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'level_url[area]\']')">{$Think.lang.sign_wildcard}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_match_only}" onclick="cpMatch('[name=\'level_url[area]\']',{only:1})">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group_only}" class="blk" onclick="cpMatch('[name=\'level_url[area]\']',{only:1,group:1})">捕获组</a>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block" data-rule-set="level_url[area_module]">
<span data-module=""><b>{:cp_sign('match')}</b>标签可获取匹配的数据,否则获取完全匹配的数据</span>
<span data-module="xpath" style="display:none;">获取匹配节点的html代码</span>
<span data-module="json" style="display:none;">获取匹配的json字符串</span>
</p>
</div>
<div class="form-group">
<label class="control-label">提取网址规则</label>
<div class="input-group">
<textarea class="form-control" name="level_url[url_rule]" rows="3" data-placeholder-xpath="请输入xpath规则默认获取所有链接" data-placeholder-json="请输入json规则" placeholder="默认获取所有链接并自动保存为[内容]标签以供拼接调用;{$Think.lang.tips_match_url}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="level_url[url_rule_module]" data-rule-input="level_url[url_rule]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul data-rule-op="level_url[url_rule_module]" class="op">
<li data-module="" style="display:block;">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'level_url[url_rule]\']')">{$Think.lang.sign_wildcard}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_match}" onclick="cpMatch('[name=\'level_url[url_rule]\']')">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group}" class="blk" onclick="cpMatch('[name=\'level_url[url_rule]\']',{group:1})">捕获组</a>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block" data-rule-set="level_url[url_rule_module]">
<span data-module="xpath" style="display:none;">XPATH匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="json" style="display:none;">JSON匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
</p>
</div>
<div class="form-group">
<label class="control-label">拼接成最终网址</label>
<div class="input-group">
<input type="text" class="form-control" name="level_url[url_merge]" placeholder="默认拼接所有{:cp_sign('match')}标签,{$Think.lang.tips_matchn_url}"/>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="调用规则中的标签" onclick="cpMatchN('[name=\'level_url[url_rule]\']','[name=\'level_url[url_merge]\']',{def:1})">{:cp_sign('match','N')}</a>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label">结果网址过滤</label>
<div class="input-group" style="margin-bottom:7px;">
<span class="input-group-addon">必须包含</span>
<input type="text" name="level_url[url_must]" class="form-control" placeholder="可模糊匹配" />
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="mgr" onclick="cpWildcard('[name=\'level_url[url_must]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
</div>
</div>
<div class="input-group">
<span class="input-group-addon">不能包含</span>
<input type="text" name="level_url[url_ban]" class="form-control" placeholder="可模糊匹配" />
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="mgr" onclick="cpWildcard('[name=\'level_url[url_ban]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
</div>
</div>
</div>
{include file="cpattern:set_page" _page_type="level_url" /}
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>
</div>
<div class="panel panel-default panel-sign-field">
<div class="panel-heading">
<div class="panel-title">
<a data-toggle="collapse" href="#c_p_sign_field_level_url">{:cp_sign('match')}添加为字段</a>
<a href="javascript:;" class="glyphicon glyphicon-plus add-level-field" data-val="" title="添加"></a>
</div>
</div>
<div id="c_p_sign_field_level_url" class="panel-collapse collapse">
<div class="panel-body">
<div class="form-group">
<div class="c-p-sign-field-list"></div>
<p class="help-block">将“提取网址规则”中的{:cp_sign('match')}标签添加为字段</p>
</div>
</div>
</div>
</div>
</form>
<script type="text/javascript">
{if condition="$level_url"}
c_pattern.level_url_op('init',{level_url:{$level_url|json_encode}});
c_pattern.cpLevelUrl.init({$level_url|json_encode});
{else /}
c_pattern.level_url_op('init');
c_pattern.cpLevelUrl.init();
{/if}
</script>

View File

@ -1,4 +1,5 @@
<form id="form_paging_field" method="post" action="{:url('Cpattern/paging_field')}">
{:html_usertoken()}
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<div class="input-group">
@ -9,9 +10,12 @@
</div>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">分页分隔符</span>
<div class="input-group-addon">分页分隔符 <span title="提示信息" class="glyphicon glyphicon-info-sign icon-delimiter-tips" onclick="cpDelimiterTips()"></span></div>
<input type="text" name="paging_field[delimiter]" class="form-control" placeholder="选填,内容多页之间插入字符" />
</div>
{if !empty($isLoop)}
<p class="help-block">注意:循环入库已开启,分页分隔符在循环模式中无效仅在非循环模式中将分页内容拼接,循环模式中分页内容以列表形式展现</p>
{/if}
</div>
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>

View File

@ -5,13 +5,14 @@
<select name="process[module]" class="form-control">
<option value="">请选择</option>
<option value="html">{$Think.lang.process_module_html}</option>
<option value="substr">{$Think.lang.process_module_substr}</option>
<option value="insert">{$Think.lang.process_module_insert}</option>
<option value="replace">{$Think.lang.process_module_replace}</option>
<option value="batch">{$Think.lang.process_module_batch}</option>
<option value="tool">{$Think.lang.process_module_tool}</option>
<option value="translate">{$Think.lang.process_module_translate}</option>
<option value="filter">{$Think.lang.process_module_filter}</option>
<option value="if">{$Think.lang.process_module_if}</option>
<option value="substr">{$Think.lang.process_module_substr}</option>
<option value="translate">{$Think.lang.process_module_translate}</option>
<option value="tool">{$Think.lang.process_module_tool}</option>
<option value="func">{$Think.lang.process_module_func}</option>
<option value="api">{$Think.lang.process_module_api}</option>
</select>
@ -23,6 +24,7 @@
{include file="cpattern:process_module" /}
{if condition="empty($type)"}
<form id="form_process" method="post" action="{:url('Cpattern/process?op=sub')}" style="display:none;">
{:html_usertoken()}
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<div class="panel-group c-p-process-accordion">
@ -37,11 +39,11 @@
<script type="text/javascript">
{if condition="empty($type)"}
{if condition="!empty($process)"}
c_pattern.process_op('init',{process:{$process|json_encode}});
c_pattern.cpProcess.init({$process|json_encode},false,false);
{else /}
c_pattern.process_op('init');
c_pattern.cpProcess.init(null,false,false);
{/if}
{elseif condition="$type eq 'common'" /}
c_pattern.process_op('init',{formObj:'#coll_pattern_process'});
c_pattern.cpProcess.init(null,true,false);
{/if}
</script>

View File

@ -3,6 +3,6 @@
</div>
<script type="text/javascript">
{if condition="$type eq 'common'"}
c_pattern.process_op('init',{formObj:'#coll_pattern_process',boxObj:'#c_p_process_load',process:{$process|json_encode}});
c_pattern.cpProcess.init({$process|json_encode},true,true);
{/if}
</script>

View File

@ -41,6 +41,21 @@
<p class="help-block">其它标签可直接输入,用空格或逗号分隔</p>
</section>
</div>
<div class="c-p-process-module" module="insert">
<div class="form-group">
<label>位置</label>
<select data-process="insert:insert_loc" class="form-control">
<option value="head">开头</option>
<option value="" selected="selected">结尾</option>
<option value="rand">随机</option>
</select>
<p class="help-block" style="display:none;">随机在换行(&lt;p&gt; &lt;br&gt;)标签中插入内容,没有换行标签则在开头、结尾中随机插入</p>
</div>
<div class="form-group">
<label>内容</label>
<textarea data-process="insert:insert_txt" rows="3" class="form-control"></textarea>
</div>
</div>
<div class="c-p-process-module" module="replace">
<div class="input-group">
<textarea data-process="replace:replace_from" rows="3" class="form-control"></textarea>
@ -74,7 +89,9 @@
<section>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">条件判断</span>
<span class="input-group-addon">
<a href="javascript:;" class="glyphicon glyphicon-info-sign p-m-if-info" style="color:#999;"></a>
</span>
<select data-process="if:if_type" class="form-control">
<option value="1">{$Think.lang.p_m_if_1}</option>
<option value="2">{$Think.lang.p_m_if_2}</option>
@ -171,15 +188,9 @@
</select>
</div>
<a href="javascript:;" class="input-group-addon p-m-if-func-info"><span class="glyphicon glyphicon-info-sign"></span></a>
<div class="p-m-if-func-tips" style="display:none;">
先选择函数(取反可获取函数结果的相反值),默认会传入当前字段值
<br>如需传入多个参数,一行一个值,用###表示当前字段值
<br>如需扩展系统函数,请在根目录/data/config.php中添加配置'EXTEND_PROCESS_IF'=&gt;array('PHP函数名'=&gt;'描述')
<br>如需扩展插件函数,可以创建<a href="{:url('Develop/func')}" target="_blank">函数插件</a>
</div>
</div>
</td>
<td style="padding:0;padding-top:10px;">
<td style="padding:0;padding-top:13px;">
<a href="javascript:;" class="glyphicon glyphicon-arrow-up" style="font-size:11px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down" style="font-size:11px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove p-m-if-del" style="font-size:11px;"></a>
@ -187,13 +198,6 @@
</tr>
</tbody>
</table>
<p class="help-block">
执行顺序:从上至下判断,逻辑符“并且”的优先级高于“或者”<br>
例如(字母表示条件):<br>
a && b || c && d && e || f || g && h && i && j 等价于<br>
(a && b) || (c && d && e) || f || (g && h && i && j)<br>
从左到右执行, 括号中的条件都为真时才是真否则为假,整条语句中任意一个括号的结果为真最终结果为真,都为假最终结果为假
</p>
</div>
</div>
</section>
@ -266,7 +270,7 @@
</div>
<div class="form-group">
<label>传入参数</label>
<textarea data-process="func:func_param" rows="2" class="form-control" placeholder="默认传入当前字段的值"></textarea>
<textarea data-process="func:func_param" rows="2" class="form-control" data-placeholder="默认传入当前字段的值"></textarea>
<div class="help-block">
一行一个值,可输入任何内容或
<div class="dropdown p-m-func-fields" style="display:inline;">
@ -278,12 +282,7 @@
<li><a href="javascript:;" data-val="###">###表示当前字段</a></li>
</ul>
</div>
,请按函数传参,否则运行出错!<a href="javascript:;" onclick="$(this).parent().find('.p-m-func-tips').show();">扩展函数</a>
<div class="p-m-func-tips" style="display:none;">
如需扩展系统函数,请在根目录/data/config.php中添加配置
'EXTEND_PROCESS_FUNC'=&gt;array('PHP函数名'=&gt;'描述')
<br>如需扩展插件函数,可以创建<a href="{:url('Develop/func')}" target="_blank">函数插件</a>
</div>
&nbsp;请按函数传参,否则运行出错!<a href="javascript:;" onclick="pluginFuncTips('process')">扩展函数</a>
</div>
</div>
</section>
@ -303,15 +302,29 @@
</select>
</div>
<div class="form-group">
<label>请求参数</label>
<label>数据编码</label>
<div class="input-group input-select-custom">
<div class="input-group-btn">
<select data-process="api:api_charset" class="form-control">
<option value="">utf-8</option>
<option value="gbk">gbk</option>
<option value="gb2312">gb2312</option>
<option value="custom">自定义</option>
</select>
</div>
<input type="text" class="form-control" data-process="api:api_charset_custom">
</div>
</div>
<div class="form-group">
<label>发送数据</label>
<a href="javascript:;" class="glyphicon glyphicon-plus p-m-api-add" title="添加"></a>
<div class="table-responsive">
<table class="table table-bordered table-hover p-m-api-table" style="margin-bottom:0;">
<thead>
<tr>
<th>名称</th>
<th></th>
<th style="width:50px;">删除</th>
<td>名称</td>
<td></th>
<td style="width:50px;">删除</td>
</tr>
</thead>
<tbody>
@ -342,11 +355,39 @@
</div>
</div>
<div class="form-group">
<label>请求头信息</label>
<a href="javascript:;" class="glyphicon glyphicon-plus p-m-api-header-add" title="添加"></a>
<div class="table-responsive">
<table class="table table-bordered table-hover p-m-api-header-table" style="margin-bottom:0;">
<thead>
<tr>
<td>名称</td>
<td></td>
<td style="width:50px;">删除</td>
</tr>
</thead>
<tbody>
<tr class="p-m-api-header-table-tpl" style="display:none;">
<td>
<input type="text" data-process="api:api_headers:name:" class="form-control">
</td>
<td>
<input type="text" data-process="api:api_headers:val:" class="form-control">
</td>
<td>
<a href="javascript:;" class="glyphicon glyphicon-remove p-m-api-header-del" style="margin-top:8px;"></a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<label>提取结果</label>
<input type="text" data-process="api:api_json" class="form-control" />
<p class="help-block">json规则 a.b.c 通配符 *</p>
</div>
<div class="form-group">
</div>
<div class="form-group">
<label>结果是数组则转换为</label>
<select data-process="api:api_json_arr" class="form-control">
<option value="implode">字符串</option>
@ -355,6 +396,21 @@
</select>
<textarea data-process="api:api_json_implode" class="form-control" rows="1" placeholder="输入分隔符" style="margin-top:5px;"></textarea>
</div>
<div class="form-group">
<label>调用间隔毫秒1000毫秒=1秒)</label>
<input type="number" data-process="api:api_interval" class="form-control" />
<p class="help-block">如接口有频率限制,可设置间隔时间避免调用过快导致失败</p>
</div>
<div class="form-group">
<label>失败等待(秒)</label>
<input type="number" data-process="api:api_wait" class="form-control" />
<p class="help-block">一般情况下调用失败都是频繁请求接口导致被禁用,设置该值等待一段时间让接口恢复正常</p>
</div>
<div class="form-group">
<label>失败重试</label>
<input type="number" data-process="api:api_retry" class="form-control" />
<p class="help-block">调用失败重试次数留空或0表示不重试</p>
</div>
</section>
</div>
</div>

View File

@ -1,4 +1,6 @@
<form id="form_relation_url" method="post" action="{:url('Cpattern/relation_url')}">
{:html_usertoken()}
<input type="hidden" name="is_submit" value="1" />
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<label class="control-label">关联页名称</label>
@ -10,92 +12,15 @@
<option value="">默认内容页</option>
</select>
</div>
<div class="form-group">
<label class="control-label">获取网址区域</label>
<div class="input-group">
<textarea name="relation_url[area]" class="form-control" rows="3" data-placeholder-json="请输入json规则默认获取所有字符" data-placeholder-xpath="请输入xpath规则默认获取整个页面" placeholder="默认整个页面,{$Think.lang.tips_match_only}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="relation_url[area_module]" data-rule-input="relation_url[area]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul data-rule-op="relation_url[area_module]" class="op">
<li data-module="" style="display:block;">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'relation_url[area]\']')">{$Think.lang.sign_wildcard}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_match_only}" onclick="cpMatch('[name=\'relation_url[area]\']',{only:1})">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group_only}" class="blk" onclick="cpMatch('[name=\'relation_url[area]\']',{only:1,group:1})">捕获组</a>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block" data-rule-set="relation_url[area_module]">
<span data-module=""><b>{:cp_sign('match')}</b>标签可获取匹配的数据,否则获取完全匹配的数据</span>
<span data-module="xpath" style="display:none;">获取匹配节点的html代码</span>
<span data-module="json" style="display:none;">获取匹配的json字符串</span>
</p>
</div>
<div class="form-group">
<label class="control-label">提取网址规则</label>
<div class="input-group">
<textarea class="form-control" name="relation_url[url_rule]" rows="3" data-placeholder-xpath="请输入xpath规则" data-placeholder-json="请输入json规则" placeholder="必须填写规则,{$Think.lang.tips_match_url}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="relation_url[url_rule_module]" data-rule-input="relation_url[url_rule]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul data-rule-op="relation_url[url_rule_module]" class="op">
<li data-module="" style="display:block;">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'relation_url[url_rule]\']')">{$Think.lang.sign_wildcard}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_match}" onclick="cpMatch('[name=\'relation_url[url_rule]\']')">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group}" class="blk" onclick="cpMatch('[name=\'relation_url[url_rule]\']',{group:1})">捕获组</a>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block" data-rule-set="relation_url[url_rule_module]">
<span data-module="xpath" style="display:none;">XPATH匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="json" style="display:none;">JSON匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
</p>
</div>
<div class="form-group">
<label class="control-label">拼接成最终网址</label>
<div class="input-group">
<input type="text" class="form-control" name="relation_url[url_merge]" placeholder="默认拼接所有{:cp_sign('match')}标签,{$Think.lang.tips_matchn_url}"/>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="调用规则中的标签" onclick="cpMatchN('[name=\'relation_url[url_rule]\']','[name=\'relation_url[url_merge]\']',{def:1})">{:cp_sign('match','N')}</a>
</div>
</div>
</div>
{include file="cpattern:set_page" _page_type="relation_url" /}
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>
</div>
<div class="panel panel-default panel-sign-field">
<div class="panel-heading">
<div class="panel-title">
<a data-toggle="collapse" href="#c_p_sign_field_relation_url">{:cp_sign('match')}添加为字段</a>
<a href="javascript:;" class="glyphicon glyphicon-plus add-relation-field" data-val="" title="添加"></a>
</div>
</div>
<div id="c_p_sign_field_relation_url" class="panel-collapse collapse">
<div class="panel-body">
<div class="form-group">
<div class="c-p-sign-field-list"></div>
<p class="help-block">将“提取网址规则”中的{:cp_sign('match')}标签添加为字段</p>
</div>
</div>
</div>
</div>
</form>
<script type="text/javascript">
{if condition="$relation_url"}
c_pattern.relation_url_op('init',{relation_url:{$relation_url|json_encode}});
c_pattern.cpRelationUrl.init({$relation_url|json_encode});
{else /}
c_pattern.relation_url_op('init');
c_pattern.cpRelationUrl.init();
{/if}
</script>

View File

@ -4,11 +4,10 @@
<li><a href="#coll_pattern_link" data-toggle="tab">内容页网址</a></li>
<li><a href="#coll_pattern_field" data-toggle="tab">获取内容</a></li>
{if condition="!empty($collData)"}
<li class="dropdown nav-save2store">
<li class="dropdown nav-save-rule">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">另存为 <span class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="{:url('Collector/export?coll_id='.$collData['id'])}" target="_blank">导出至本地</a></li>
<li><a href="{:url('Collector/save2store?coll_id='.$collData['id'])}" title="云端存储,保存规则更方便!" onclick="windowModal('保存到云端',$(this).attr('href'));return false;">上传至云端</a></li>
</ul>
</li>
{/if}
@ -22,21 +21,25 @@
<input type="text" class="form-control" name="name" value="{$collData['name']}" placeholder="选填">
</div>
<div class="form-group">
<label class="control-label">网站编码</label>
<select name="config[charset]" class="form-control">
<option value="">自动检测</option>
<option value="utf-8">utf-8</option>
<option value="gbk">gbk</option>
<option value="gb2312">gb2312</option>
<option value="custom">自定义</option>
</select>
<input type="text" class="form-control" name="config[charset_custom]" style="margin-top:10px;display:none;">
<label class="control-label">网页编码</label>
<div class="input-group input-select-custom">
<div class="input-group-btn">
<select name="config[charset]" class="form-control">
<option value="">自动检测</option>
<option value="utf-8">utf-8</option>
<option value="gbk">gbk</option>
<option value="gb2312">gb2312</option>
<option value="custom">自定义</option>
</select>
</div>
<input type="text" name="config[charset_custom]" class="form-control">
</div>
</div>
<div class="form-group">
<label class="control-label">自动补全网址</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[url_complete]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[url_complete]" value="0"> </label>
<label class="radio-inline"><input type="radio" name="config[url_complete]" value="0" checked="checked"> </label>
</div>
<p class="help-block">将所有页面源码中的相对地址转换成绝对地址包含超链接、图片、JS链接等</p>
</div>
@ -44,7 +47,7 @@
<label class="control-label">网址不排重</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[url_repeat]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[url_repeat]" value="0"> </label>
<label class="radio-inline"><input type="radio" name="config[url_repeat]" value="0" checked="checked"> </label>
</div>
<p class="help-block">默认将已采集网址排重过滤,选择“是”允许重复采集</p>
</div>
@ -52,7 +55,7 @@
<label class="control-label">倒序采集</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[url_reverse]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[url_reverse]" value="0"> </label>
<label class="radio-inline"><input type="radio" name="config[url_reverse]" value="0" checked="checked"> </label>
</div>
<p class="help-block">以相反的顺序采集内容页网址</p>
</div>
@ -60,10 +63,22 @@
<label class="control-label">页面渲染</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[page_render]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[page_render]" value="0"> </label>
<label class="radio-inline"><input type="radio" name="config[page_render]" value="0" checked="checked"> </label>
</div>
<p class="help-block">需先配置<a href="{:url('Setting/page_render')}">页面渲染</a>可自动加载ajax内容注意渲染后的html源码与未渲染时的不相同原先的规则可能会失效</p>
</div>
<div class="form-group">
<label class="control-label">正则匹配模式</label>
<div>
<label class="checkbox-inline">
<input type="checkbox" name="config[regexp_flags][]" value="case"> 区分大小写
</label>
<label class="checkbox-inline">
<input type="checkbox" name="config[regexp_flags][]" value="unicode"> 识别unicode字符
</label>
</div>
<p class="help-block">使用正则规则时进行以上模式匹配,默认情况下仅忽略大小写</p>
</div>
</div>
</div>
<div class="panel panel-default">
@ -74,67 +89,116 @@
</div>
<div id="coll_pattern_request_headers" class="panel-collapse collapse">
<div class="panel-body">
<div class="form-group" style="margin-bottom:0;">
<label class="control-label">开启</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[request_headers][open]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[request_headers][open]" value="0"> </label>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#c_p_request_headers_open" aria-expanded="false">抓取页面</a>
</h4>
</div>
<div id="c_p_request_headers_open" class="panel-collapse collapse">
<div class="panel-body">
<div class="form-group">
<label class="control-label">全局开启</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[request_headers][open]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[request_headers][open]" value="0" checked="checked"> </label>
</div>
<p class="help-block">采集起始页、多级页、内容页和关联页时使用请求头信息</p>
</div>
<div class="form-group">
<label class="control-label">UserAgent 浏览器标识</label>
<div class="input-group">
<input type="text" class="form-control" name="config[request_headers][useragent]" placeholder="留空不设置" />
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><em style="font-style:normal">常用标识</em> <span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right dm-useragent">
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11">谷歌浏览器(pc端)</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1">火狐浏览器</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)">IE8</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)">IE6</a></li>
<li role="separator" class="divider"></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (Linux; U; Android 4.0.3; zh-cn; M032 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30">安卓系统</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1">IPhone 6</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1">iPad</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Mobile Safari/537.36">三星 Galaxy S5</a></li>
</ul>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label">Cookie 缓存数据</label>
<input type="text" class="form-control" name="config[request_headers][cookie]" placeholder="留空不设置" />
</div>
<div class="form-group">
<label class="control-label">Referer 来源网址</label>
<input type="text" class="form-control" name="config[request_headers][referer]" placeholder="留空不设置" />
</div>
<div class="form-group">
<label class="control-label">自定义 <a href="javascript:;" class="glyphicon glyphicon-plus add-request-header" title="添加"></a></label>
<div class="table-responsive">
<table class="table table-bordered c-p-request-headers" style="margin-bottom:0;">
<thead>
<tr>
<td>名称</td>
<td></td>
<td>删除</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<p class="help-block">添加新的或者覆盖已有的请求头信息</p>
</div>
</div>
</div>
</div>
<div id="c_p_request_headers_open" style="display:none;margin-top:15px;">
<div class="form-group">
<label class="control-label">UserAgent 浏览器标识</label>
<div class="input-group">
<input type="text" class="form-control" name="config[request_headers][useragent]">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><em style="font-style:normal">常用标识</em> <span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right dm-useragent">
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11">谷歌浏览器(pc端)</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1">火狐浏览器</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)">IE8</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)">IE6</a></li>
<li role="separator" class="divider"></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (Linux; U; Android 4.0.3; zh-cn; M032 Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30">安卓系统</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1">IPhone 6</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1">iPad</a></li>
<li><a href="javascript:;" data-useragent="Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Mobile Safari/537.36">三星 Galaxy S5</a></li>
</ul>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label">Cookie 缓存数据</label>
<input type="text" class="form-control" name="config[request_headers][cookie]">
</div>
<div class="form-group">
<label class="control-label">Referer 来源网址</label>
<input type="text" class="form-control" name="config[request_headers][referer]">
</div>
<div class="form-group">
<label class="control-label">自定义 <a href="javascript:;" class="glyphicon glyphicon-plus add-request-header" title="添加" style="font-size:12px;"></a></label>
<div class="table-responsive">
<table class="table c-p-request-headers" style="margin-bottom:0;">
<thead>
<tr>
<th class="col-xs-4">名称</th>
<th class="col-xs-6"></th>
<th class="col-xs-2">删除</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<label class="control-label">下载图片使用请求头</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[request_headers][download_img]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[request_headers][download_img]" value="0"> </label>
</div>
<p class="help-block">下载图片时是否使用该请求头设置</p>
</div>
</div>
<div class="panel panel-default" style="margin-bottom:0;">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#c_p_request_headers_img" aria-expanded="false">下载图片</a>
</h4>
</div>
<div id="c_p_request_headers_img" class="panel-collapse collapse">
<div class="panel-body">
<div class="form-group">
<label class="control-label">开启</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[request_headers][img]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[request_headers][img]" value="0" checked="checked"> </label>
</div>
<p class="help-block">下载图片时使用请求头</p>
</div>
<div class="form-group">
<label class="control-label">使用全局请求头</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[request_headers][img_use_page]" value="" checked="checked"> 默认</label>
<label class="radio-inline"><input type="radio" name="config[request_headers][img_use_page]" value="y"> 强制使用</label>
<label class="radio-inline"><input type="radio" name="config[request_headers][img_use_page]" value="n"> 强制禁用</label>
</div>
<p class="help-block">默认使用采集器设置»请求头信息»抓取页面中的设置(受全局开启状态影响)</p>
</div>
<div class="form-group">
<label class="control-label">自定义 <a href="javascript:;" class="glyphicon glyphicon-plus add-request-header-img" title="添加"></a></label>
<div class="table-responsive">
<table class="table table-bordered c-p-request-headers-img" style="margin-bottom:0;">
<thead>
<tr>
<td>名称</td>
<td></td>
<td>删除</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<p class="help-block">添加新的或者覆盖已有的请求头信息</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@ -171,14 +235,14 @@
<div class="panel panel-default" id="panel_coll_pattern_level_url">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_level_url" aria-expanded="false">多级网址获取</a>
<a data-toggle="collapse" href="#coll_pattern_level_url" aria-expanded="false">多级网址获取</a>
</h4>
</div>
<div id="coll_pattern_level_url" class="panel-collapse collapse">
<div class="panel-body">
<div class="h-title">
<span class="is-loading"></span>
<label class="control-label">多级网址规则</label>
<label class="control-label">多级规则</label>
<a href="javascript:;" class="glyphicon glyphicon-plus add-level-url" title="添加"></a>
</div>
<div class="table-responsive">
@ -187,6 +251,7 @@
<tr>
<th>级别</th>
<th>名称</th>
<th class="sign" title="区域和网址规则中的{:cp_sign('match')}标签"><span class="sign-th">{:cp_sign('match')}标签</span></th>
<th>操作</th>
</tr>
</thead>
@ -203,161 +268,7 @@
<h4 class="panel-title">内容页网址获取</h4>
</div>
<div class="panel-body">
<!-- coll_pattern_link -->
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_link_area" aria-expanded="false" class="collapsed">从选定区域中提取网址</a>
</h4>
</div>
<div id="coll_pattern_link_area" class="panel-collapse collapse" aria-expanded="false" style="height: 0px;">
<div class="panel-body">
<div class="form-group">
<label class="control-label">获取网址区域</label>
<div class="input-group">
<textarea name="config[area]" class="form-control" rows="3" data-placeholder-json="请输入json规则默认获取所有字符" data-placeholder-xpath="请输入xpath规则默认获取整个页面" placeholder="默认整个页面,{$Think.lang.tips_match_only}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="config[area_module]" data-rule-input="config[area]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul data-rule-op="config[area_module]" class="op">
<li data-module="" style="display:block;">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'config[area]\']')">{$Think.lang.sign_wildcard}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_match_only}" onclick="cpMatch('[name=\'config[area]\']',{only:1})">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group_only}" class="blk" onclick="cpMatch('[name=\'config[area]\']',{only:1,group:1})">捕获组</a>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block" data-rule-set="config[area_module]">
<span data-module=""><b>{:cp_sign('match')}</b>标签可获取匹配的数据,否则获取完全匹配的数据</span>
<span data-module="xpath" style="display:none;">获取匹配节点的html代码</span>
<span data-module="json" style="display:none;">获取匹配的json字符串</span>
</p>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_link_match" class="" aria-expanded="true">匹配内容网址</a>
</h4>
</div>
<div id="coll_pattern_link_match" class="panel-collapse collapse" aria-expanded="false" style="height: 0px;">
<div class="panel-body">
<div class="form-group">
<label class="control-label">提取网址规则</label>
<div class="input-group">
<textarea class="form-control" name="config[url_rule]" rows="3" data-placeholder-xpath="请输入xpath规则默认获取所有链接" data-placeholder-json="请输入json规则" placeholder="默认获取所有链接并自动保存为[内容]标签以供拼接调用;{$Think.lang.tips_match_url}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="config[url_rule_module]" data-rule-input="config[url_rule]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul data-rule-op="config[url_rule_module]" class="op">
<li data-module="" style="display:block;">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'config[url_rule]\']')">{$Think.lang.sign_wildcard}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_match}" onclick="cpMatch('[name=\'config[url_rule]\']')">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group}" class="blk" onclick="cpMatch('[name=\'config[url_rule]\']',{group:1})">捕获组</a>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block" data-rule-set="config[url_rule_module]">
<span data-module="xpath" style="display:none;">XPATH匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="json" style="display:none;">JSON匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
</p>
</div>
<div class="form-group">
<label class="control-label">拼接成最终网址</label>
<div class="input-group">
<input type="text" class="form-control" name="config[url_merge]" placeholder="默认拼接所有{:cp_sign('match')}标签,{$Think.lang.tips_matchn_url}"/>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="调用规则中的标签" onclick="cpMatchN('[name=\'config[url_rule]\']','[name=\'config[url_merge]\']',{def:1})">{:cp_sign('match','N')}</a>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label">{:cp_sign('match')}添加为字段 <a href="javascript:;" class="glyphicon glyphicon-plus add-link-field" data-val="" title="添加" style="font-size:12px;"></a></label>
<div id="c_p_sign_field_link">
<div class="c-p-sign-field-list"></div>
</div>
<p class="help-block">将“提取网址规则”中的{:cp_sign('match')}标签添加为字段</p>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_link_filter" class="collapsed" aria-expanded="false">结果网址过滤</a>
</h4>
</div>
<div id="coll_pattern_link_filter" class="panel-collapse collapse in" aria-expanded="true">
<div class="panel-body">
<div class="input-group" style="margin-bottom:7px;">
<span class="input-group-addon">必须包含</span>
<input type="text" name="config[url_must]" class="form-control" placeholder="可模糊匹配" />
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="mgr" onclick="cpWildcard('[name=\'config[url_must]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
</div>
</div>
<div class="input-group">
<span class="input-group-addon">不能包含</span>
<input type="text" name="config[url_ban]" class="form-control" placeholder="可模糊匹配" />
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="mgr" onclick="cpWildcard('[name=\'config[url_ban]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-default" style="margin-bottom:0;">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_link_post" class="collapsed" aria-expanded="false">POST模式</a>
</h4>
</div>
<div id="coll_pattern_link_post" class="panel-collapse collapse" aria-expanded="false" style="height: 0px;">
<div class="panel-body">
<div class="form-group">
<label class="control-label">开启POST</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[url_post]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[url_post]" value="0"> </label>
</div>
<p class="help-block">开启后内容页网址中的get参数将以post形式提交</p>
</div>
<div class="form-group">
<label class="control-label">附加参数 <a href="javascript:;" class="glyphicon glyphicon-plus add-url-post" title="添加" style="font-size:12px;"></a></label>
<div class="table-responsive">
<table class="table table-hover c-p-url-posts" style="margin-bottom:0;">
<thead>
<tr>
<th class="col-xs-4">名称</th>
<th class="col-xs-6"></th>
<th class="col-xs-2">删除</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- end coll_pattern_link -->
{include file="cpattern:set_page" _page_type="url" /}
</div>
</div>
@ -380,6 +291,7 @@
<tr>
<th>名称</th>
<th>从页面中提取</th>
<th class="sign" title="区域和网址规则中的{:cp_sign('match')}标签"><span class="sign-th">{:cp_sign('match')}标签</span></th>
<th>操作</th>
</tr>
</thead>
@ -391,7 +303,7 @@
</div>
</div>
{if condition="!empty($collData)"}
{if condition="!empty($collData['id'])"}
<div class="form-group">
<div class="dropdown">
<button class="btn btn-default btn-block dropdown-toggle" type="button" id="dropdownMenuTestSourceUrl" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
@ -399,8 +311,8 @@
<span class="caret"></span>
</button>
<ul class="dropdown-menu" style="width:100%;text-align:center;" aria-labelledby="dropdownMenuTestSourceUrl">
<li><a href="{:url('Cpattern/test?op=source_urls&coll_id='.$collData['id'])}" target="_blank" onclick="windowModal('测试',$(this).attr('href'),{lg:1});return false;">测试抓取内容页网址</a></li>
<li><a href="{:url('Cpattern/test?op=cont_url&coll_id='.$collData['id'])}&test=get_relation_urls" target="_blank" onclick="windowModal('测试',$(this).attr('href'),{lg:1});return false;">测试抓取关联页网址</a></li>
<li><a href="{:url('cpattern_test/source_urls?coll_id='.$collData['id'])}" target="_blank" onclick="windowModal('测试',$(this).attr('href'),{lg:1});return false;">测试抓取内容页网址</a></li>
<li><a href="{:url('cpattern_test/test_url?coll_id='.$collData['id'])}&test=get_relation_urls" target="_blank">测试抓取关联页网址</a></li>
</ul>
</div>
</div>
@ -412,7 +324,7 @@
<div class="h-title">
<label class="control-label">字段列表</label>
<a href="javascript:;" class="glyphicon glyphicon-plus add-field" title="添加"></a>
<a href="javascript:;" onclick="c_pattern.add_default_fields()" style="float:right;font-weight:normal;">添加默认</a>
<a href="javascript:;" class="add-field-default" style="float:right;font-weight:normal;">添加默认</a>
</div>
<div class="table-responsive">
<table class="table table-hover c-p-field-list" style="margin-bottom:0px;">
@ -463,110 +375,29 @@
<label class="control-label">开启分页</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="config[paging][open]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[paging][open]" value="0"> </label>
<label class="radio-inline"><input type="radio" name="config[paging][open]" value="0" checked="checked"> </label>
</div>
</div>
<div id="c_p_paging_open" style="display:none;margin-top:15px;">
<div class="form-group">
<label class="control-label">
分页内容字段
<a href="javascript:;" class="glyphicon glyphicon-plus add-paging-field" title="添加"></a>
</label>
<div id="c_p_paging_fields"></div>
<p class="help-block">只有选中的字段才会在分页中获取到内容</p>
</div>
<div class="form-group">
<label class="control-label">获取分页区域</label>
<div class="input-group">
<textarea name="config[paging][area]" class="form-control" rows="3" data-placeholder-json="请输入json规则默认获取所有字符" data-placeholder-xpath="请输入xpath规则默认获取整个页面" placeholder="默认整个页面,{$Think.lang.tips_match_only}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="config[paging][area_module]" data-rule-input="config[paging][area]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul data-rule-op="config[paging][area_module]" class="op">
<li data-module="" style="display:block;">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'config[paging][area]\']')">{$Think.lang.sign_wildcard}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_match_only}" onclick="cpMatch('[name=\'config[paging][area]\']',{only:1})">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group_only}" class="blk" onclick="cpMatch('[name=\'config[paging][area]\']',{only:1,group:1})">捕获组</a>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block" data-rule-set="config[paging][area_module]">
<span data-module=""><b>{:cp_sign('match')}</b>标签可获取匹配的数据,否则获取完全匹配的数据</span>
<span data-module="xpath" style="display:none;">获取匹配节点的html代码</span>
<span data-module="json" style="display:none;">获取匹配的json字符串</span>
</p>
</div>
<div class="form-group">
<label class="control-label">分页链接规则</label>
<div class="input-group">
<textarea name="config[paging][url_rule]" class="form-control" rows="3" data-placeholder-xpath="请输入xpath规则" data-placeholder-json="请输入json规则" placeholder="必须填写规则,{$Think.lang.tips_match_url}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="config[paging][url_rule_module]" data-rule-input="config[paging][url_rule]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul data-rule-op="config[paging][url_rule_module]" class="op">
<li data-module="" style="display:block;">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'config[paging][url_rule]\']')">{$Think.lang.sign_wildcard}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_match}" onclick="cpMatch('[name=\'config[paging][url_rule]\']')">{:cp_sign('match')}</a>
<a href="javascript:;" title="{$Think.lang.tips_sign_group}" class="blk" onclick="cpMatch('[name=\'config[paging][url_rule]\']',{group:1})">捕获组</a>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block" data-rule-set="config[paging][url_rule_module]">
<span data-module="">规则中无{:cp_sign('match')}标签时,自动将完全匹配的数据保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="xpath" style="display:none;">XPATH匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="json" style="display:none;">JSON匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
</p>
</div>
<div class="form-group">
<label class="control-label">拼接成最终分页链接</label>
<div class="input-group">
<input type="text" class="form-control" name="config[paging][url_merge]" placeholder="默认拼接所有{:cp_sign('match')}标签,{$Think.lang.tips_matchn_url}"/>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="调用规则中的标签" onclick="cpMatchN('[name=\'config[paging][url_rule]\']','[name=\'config[paging][url_merge]\']',{def:1})">{:cp_sign('match','N')}</a>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label">分页网址过滤</label>
<div class="input-group" style="margin-bottom:7px;">
<span class="input-group-addon">必须包含</span>
<input type="text" name="config[paging][url_must]" class="form-control" placeholder="选填,可模糊匹配" />
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="mgr" onclick="cpWildcard('[name=\'config[paging][url_must]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
</div>
</div>
<div class="input-group">
<span class="input-group-addon">不能包含</span>
<input type="text" name="config[paging][url_ban]" class="form-control" placeholder="选填,可模糊匹配" />
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="mgr" onclick="cpWildcard('[name=\'config[paging][url_ban]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label">最大分页数</label>
<input type="number" class="form-control" name="config[paging][max]" value="10">
<p class="help-block">填0表示不限制会自动循环抓取到最后一页为防止出现无限循环的情况最好设置一个数值</p>
</div>
<div class="form-group">
<label class="control-label">
分页内容字段
<a href="javascript:;" class="glyphicon glyphicon-plus add-paging-field" title="添加"></a>
</label>
<div id="c_p_paging_fields"></div>
<p class="help-block">只有选中的字段才会在分页中获取到内容</p>
</div>
{include file="cpattern:set_page" _page_type="paging_url" /}
<div class="form-group">
<label class="control-label">最大分页数</label>
<input type="number" class="form-control" name="config[paging][max]" value="10">
<p class="help-block">填0表示不限制会自动循环抓取到最后一页为防止出现无限循环的情况最好设置一个数值</p>
</div>
</div>
</div>
</div>
</div>
{if condition="!empty($collData)"}
{if condition="!empty($collData['id'])"}
<div class="form-group">
<div class="dropdown">
<button class="btn btn-default btn-block dropdown-toggle" type="button" id="dropdownMenuTestUrl" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
@ -574,8 +405,8 @@
<span class="caret"></span>
</button>
<ul class="dropdown-menu" style="width:100%;text-align:center;" aria-labelledby="dropdownMenuTestUrl">
<li><a href="{:url('Cpattern/test?op=cont_url&coll_id='.$collData['id'])}" target="_blank">测试抓取数据</a></li>
<li><a href="{:url('Cpattern/test?op=match&coll_id='.$collData['id'])}" target="_blank">模拟匹配数据</a></li>
<li><a href="{:url('cpattern_test/test_url?coll_id='.$collData['id'])}" target="_blank">测试抓取数据</a></li>
<li><a href="{:url('cpattern_test/match?coll_id='.$collData['id'])}" target="_blank">模拟匹配数据</a></li>
</ul>
</div>
</div>
@ -585,33 +416,91 @@
<div style="display:none;">
<table>
<tr id="coll_tpl_request_headers">
<td><input type="text" data-name="config[request_headers][custom_names][]" class="form-control" /></td>
<td><input type="text" data-name="config[request_headers][custom_vals][]" class="form-control" /></td>
<td><input type="text" data-name="config[request_headers][custom_names][]" class="form-control" autocomplete="off" /></td>
<td><input type="text" data-name="config[request_headers][custom_vals][]" class="form-control" autocomplete="off" /></td>
<td><a href="javascript:;" class="glyphicon glyphicon-remove delete-request-header"></a></td>
</tr>
<tr id="coll_tpl_url_posts">
<td><input type="text" data-name="config[url_posts][names][]" class="form-control" /></td>
<td><input type="text" data-name="config[url_posts][vals][]" class="form-control" /></td>
<td><a href="javascript:;" class="glyphicon glyphicon-remove delete-url-post"></a></td>
<tr id="coll_tpl_request_headers_img">
<td><input type="text" data-name="config[request_headers][img_names][]" class="form-control" autocomplete="off" /></td>
<td><input type="text" data-name="config[request_headers][img_vals][]" class="form-control" autocomplete="off" /></td>
<td><a href="javascript:;" class="glyphicon glyphicon-remove delete-request-header-img"></a></td>
</tr>
<tr id="coll_tpl_url_web_form">
<td><input type="text" data-name="[url_web][form_names][]" class="form-control" autocomplete="off" /></td>
<td>
<div class="input-group c-p-url-page-signs" data-page-type="" data-input-name="[url_web][form_vals][]">
<input type="text" data-name="[url_web][form_vals][]" class="form-control" autocomplete="off" />
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle btn-page-signs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<div class="dropdown-menu dropdown-menu-right" style="padding:10px;">
<table class="table table-hover">
<thead>
<tr>
<th>页面</th>
<th>区域</th>
<th>网址</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</td>
<td><a href="javascript:;" class="glyphicon glyphicon-remove delete-url-web-form"></a></td>
</tr>
<tr id="coll_tpl_url_web_header">
<td><input type="text" data-name="[url_web][header_names][]" class="form-control" autocomplete="off" /></td>
<td>
<div class="input-group c-p-url-page-signs" data-page-type="" data-input-name="[url_web][header_vals][]">
<input type="text" data-name="[url_web][header_vals][]" class="form-control" autocomplete="off" />
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle btn-page-signs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<div class="dropdown-menu dropdown-menu-right" style="padding:10px;">
<table class="table table-hover">
<thead>
<tr>
<th>页面</th>
<th>区域</th>
<th>网址</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</td>
<td><a href="javascript:;" class="glyphicon glyphicon-remove delete-url-web-header"></a></td>
</tr>
<tr id="coll_tpl_level_url">
<td><span class="level"></span></td>
<td><a href="javascript:;" class="name" data-val=""></a></td>
<td class="sign"><input type="text" class="form-control signs" readonly="true" /></td>
<td>
<input type="hidden" data-name="config[level_urls][]" />
<a href="javascript:;" class="glyphicon glyphicon-arrow-up" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove delete" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-up" title="上移" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down" title="下移" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-copy clone" title="复制" style="font-size:12px;top:0.5px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove delete" title="删除" style="font-size:12px;"></a>
</td>
</tr>
<tr id="coll_tpl_relation_url">
<td><a href="javascript:;" class="name" data-val=""></a></td>
<td class="page"></td>
<td class="sign"><input type="text" class="form-control signs" readonly="true" /></td>
<td>
<input type="hidden" data-name="config[relation_urls][]" />
<a href="javascript:;" class="glyphicon glyphicon-arrow-up" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove delete" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-up" title="上移" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down" title="下移" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-copy clone" title="复制" style="font-size:12px;top:0.5px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove delete" title="删除" style="font-size:12px;"></a>
</td>
</tr>
<tr id="coll_tpl_field">
@ -622,9 +511,10 @@
<input type="hidden" data-name="config[field_list][]" />
<input type="hidden" data-name="config[field_process][]" />
<a href="javascript:;" class="field-process">数据处理</a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-up" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove field-del" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-up" title="上移" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down" title="下移" style="font-size:12px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-copy field-clone" title="复制" style="font-size:12px;top:0.5px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove field-del" title="删除" style="font-size:12px;"></a>
</td>
<td><label class="radio-inline"><input type="radio" data-name="config[field_title]">绑定</label></td>
</tr>
@ -638,10 +528,11 @@
<input type="text" style="display:none;border-radius:2px;border:1px solid #ccc;line-height:16px;margin-left:2px;padding:1px 1px 1px 2px;" />
</div>
<div class="panel-title-ops" style="float:right;">
<a href="javascript:;" class="glyphicon glyphicon-tags" title="标题"></a>&nbsp;
<a href="javascript:;" class="glyphicon glyphicon-arrow-up"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove" onclick="c_pattern.process_op('delete',{obj:this})"></a>
<a href="javascript:;" class="glyphicon glyphicon-tag c-p-process-title" title="标题"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-up" title="上移"></a>
<a href="javascript:;" class="glyphicon glyphicon-arrow-down" title="下移"></a>
<a href="javascript:;" class="glyphicon glyphicon-copy c-p-process-clone" title="复制" style="top:0.5px;"></a>
<a href="javascript:;" class="glyphicon glyphicon-remove c-p-process-del" title="删除"></a>
</div>
</div>
</div>
@ -650,18 +541,18 @@
</div>
</div>
</div>
<div id="coll_tpl_sign_field" class="c-p-sign-field">
<a href="javascript:;" class="field" data-val="" data-source="" title=""></a>
<em class="glyphicon glyphicon-remove-circle delete" data-val=""></em>
</div>
</div>
<link href="__PUBLIC__/static/css/jquery.datetimepicker.css" rel="stylesheet">
<script type="text/javascript" src="__PUBLIC__/static/js/jquery.datetimepicker.js"></script>
<link href="__PUBLIC__/static/css/jquery.datetimepicker.css?{$Think.config.html_v}" rel="stylesheet">
<script type="text/javascript" src="__PUBLIC__/static/js/jquery.datetimepicker.js?{$Think.config.html_v}"></script>
<script type="text/javascript">
var c_pattern=new CollectorPattern('form_coll');
var c_pattern=new CollectorPattern();
c_pattern.init();
{if condition="!empty($collData['config'])"}
c_pattern.load({$collData['config']|json_encode});
{if !empty($collData)}
{if empty($collData['config'])}
c_pattern.load(null);
{else/}
c_pattern.load({$collData['config']|json_encode});
{/if}
{/if}
</script>

View File

@ -0,0 +1,270 @@
{assign name="_tpl_page_type" value="[_page_type]" /}
{php}$_tpl_vars=array('title'=>'页面','is_level_url'=>false,'is_url'=>false,'is_relation_url'=>false,'is_paging_url'=>false);{/php}
{if 'level_url'==$_tpl_page_type}
{php}$_tpl_vars['title']='多级页';$_tpl_vars['id']='c_p_level_url';$_tpl_vars['name']='level_url';$_tpl_vars['is_level_url']=true;{/php}
{elseif 'relation_url'==$_tpl_page_type}
{php}$_tpl_vars['title']='关联页';$_tpl_vars['id']='c_p_relation_url';$_tpl_vars['name']='relation_url';$_tpl_vars['is_relation_url']=true;{/php}
{elseif 'url'==$_tpl_page_type}
{php}$_tpl_vars['title']='内容页';$_tpl_vars['id']='coll_pattern_link';$_tpl_vars['name']='config';$_tpl_vars['is_url']=true;{/php}
{elseif 'paging_url'==$_tpl_page_type}
{php}$_tpl_vars['title']='分页';$_tpl_vars['id']='coll_pattern_paging';$_tpl_vars['name']='config[paging]';$_tpl_vars['is_paging_url']=true;{/php}
{/if}
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#{$_tpl_vars['id']}_area" aria-expanded="false" class="collapsed">从选定区域中提取网址</a>
</h4>
</div>
<div data-module-select="{$_tpl_vars['name']}[area_module]" id="{$_tpl_vars['id']}_area" class="panel-collapse collapse" aria-expanded="false">
<div class="panel-body">
<div class="form-group">
<label class="control-label">获取网址区域</label>
<div class="input-group">
<textarea name="{$_tpl_vars['name']}[area]" class="form-control" rows="3" data-placeholder-json="请输入json规则默认获取所有字符并保存为{:cp_sign('match')}标签以供拼接调用" data-placeholder-xpath="请输入xpath规则默认获取整个页面并保存为{:cp_sign('match')}标签以供拼接调用" placeholder="默认获取整个页面并保存为{:cp_sign('match')}标签以供拼接调用,{$Think.lang.tips_match_area}"></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="{$_tpl_vars['name']}[area_module]" data-module-input="{$_tpl_vars['name']}[area]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul class="op">
<li data-module="" style="display:block;">
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'{$_tpl_vars['name']}[area]\']')">{$Think.lang.sign_wildcard}</a></div>
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_match}" onclick="cpMatch('[name=\'{$_tpl_vars['name']}[area]\']',{zimu:{$_tpl_vars['is_paging_url']?0:1}})">{:cp_sign('match')}</a></div>
<div>
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_group}" onclick="cpMatch('[name=\'{$_tpl_vars['name']}[area]\']',{group:1,zimu:{$_tpl_vars['is_paging_url']?0:1}})">捕获组</a></div>
<div style="display:inline;"><a href="javascript:;" title="提示信息" class="glyphicon glyphicon-info-sign" style="font-size:11px;" onclick="cpRuleTips({$_tpl_vars['is_paging_url']?'':1})"></a></div>
</div>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block">
<span data-module="">规则中无{:cp_sign('match')}标签时,自动将完全匹配的值保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="xpath" style="display:none;">XPATH匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="json" style="display:none;">JSON匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
</p>
</div>
<div class="form-group">
<label class="control-label">拼接成最终区域</label>
<div class="input-group c-p-url-page-signs" data-page-type="{$_tpl_page_type}" data-input-name="{$_tpl_vars['name']}[area_merge]">
<textarea name="{$_tpl_vars['name']}[area_merge]" placeholder="默认拼接区域规则中所有{:cp_sign('match')}标签,{$Think.lang.tips_matchn_area}" class="form-control" rows="2"></textarea>
{if !$_tpl_vars['is_paging_url']}
<div class="input-group-addon">
<a href="javascript:;" role="button" class="dropdown-toggle btn-page-signs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{:cp_sign('match','N')}
<span class="caret"></span>
</a>
<div class="dropdown-menu dropdown-menu-right" style="padding:10px;">
<table class="table table-hover">
<thead>
<tr>
<th>页面</th>
<th>区域</th>
<th>网址</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
{else/}
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="调用规则中的标签" onclick="cpMatchN('[name=\'{$_tpl_vars['name']}[area]\']','[name=\'{$_tpl_vars['name']}[area_merge]\']',{def:1})">{:cp_sign('match','N')}</a>
</div>
{/if}
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#{$_tpl_vars['id']}_url" {if $_tpl_vars['is_relation_url']||$_tpl_vars['is_paging_url']}aria-expanded="true"{else/}aria-expanded="false" class="collapsed"{/if}>匹配{$_tpl_vars['title']}网址</a>
</h4>
</div>
<div data-module-select="{$_tpl_vars['name']}[url_rule_module]" id="{$_tpl_vars['id']}_url" {if $_tpl_vars['is_relation_url']||$_tpl_vars['is_paging_url']}class="panel-collapse collapse in" aria-expanded="true"{else/}class="panel-collapse collapse" aria-expanded="false"{/if}>
<div class="panel-body">
<div class="form-group">
<label class="control-label">提取网址规则</label>
<div class="input-group">
<textarea class="form-control" name="{$_tpl_vars['name']}[url_rule]" rows="3" {if $_tpl_vars['is_relation_url']||$_tpl_vars['is_paging_url']}data-placeholder-xpath="请输入xpath规则" data-placeholder-json="请输入json规则" placeholder="必须填写规则,{$Think.lang.tips_match_url}"{else/}data-placeholder-xpath="请输入xpath规则默认获取所有链接并保存为{:cp_sign('match')}标签以供拼接调用" data-placeholder-json="请输入json规则" placeholder="默认获取所有链接并保存为{:cp_sign('match')}标签以供拼接调用,{$Think.lang.tips_match_url}"{/if}></textarea>
<div class="input-group-addon iga-rt iga-rt1">
<select name="{$_tpl_vars['name']}[url_rule_module]" data-module-input="{$_tpl_vars['name']}[url_rule]" class="slt">
<option value="">正则</option>
<option value="xpath">xpath</option>
<option value="json">json</option>
</select>
<ul class="op">
<li data-module="" style="display:block;">
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" onclick="cpWildcard('[name=\'{$_tpl_vars['name']}[url_rule]\']')">{$Think.lang.sign_wildcard}</a></div>
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_match}" onclick="cpMatch('[name=\'{$_tpl_vars['name']}[url_rule]\']',{zimu:{$_tpl_vars['is_paging_url']?0:1}})">{:cp_sign('match')}</a></div>
<div>
<div style="display:inline;"><a href="javascript:;" title="{$Think.lang.tips_sign_group}" onclick="cpMatch('[name=\'{$_tpl_vars['name']}[url_rule]\']',{group:1,zimu:{$_tpl_vars['is_paging_url']?0:1}})">捕获组</a></div>
<div style="display:inline;"><a href="javascript:;" title="提示信息" class="glyphicon glyphicon-info-sign" style="font-size:11px;" onclick="cpRuleTips({$_tpl_vars['is_paging_url']?'':1})"></a></div>
</div>
</li>
<li data-module="xpath">xpath语法</li>
<li data-module="json">格式 a.b.c<br>通配符 *</li>
</ul>
</div>
</div>
<p class="help-block">
<span data-module="">规则中无{:cp_sign('match')}标签时,自动将完全匹配的值保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="xpath" style="display:none;">XPATH匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
<span data-module="json" style="display:none;">JSON匹配到的值自动保存为{:cp_sign('match')}标签以供拼接调用</span>
</p>
</div>
<div class="form-group">
<label class="control-label">拼接成最终网址</label>
<div class="input-group c-p-url-page-signs" data-page-type="{$_tpl_page_type}" data-input-name="{$_tpl_vars['name']}[url_merge]">
<input type="text" class="form-control" name="{$_tpl_vars['name']}[url_merge]" placeholder="默认拼接网址规则中所有{:cp_sign('match')}标签,{$Think.lang.tips_matchn_url}" autocomplete="off" />
{if !$_tpl_vars['is_paging_url']}
<div class="input-group-addon">
<a href="javascript:;" role="button" class="dropdown-toggle btn-page-signs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{:cp_sign('match','N')}
<span class="caret"></span>
</a>
<div class="dropdown-menu dropdown-menu-right" style="padding:10px;">
<table class="table table-hover">
<thead>
<tr>
<th>页面</th>
<th>区域</th>
<th>网址</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
{else/}
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="调用规则中的标签" onclick="cpMatchN('[name=\'{$_tpl_vars['name']}[url_rule]\']','[name=\'{$_tpl_vars['name']}[url_merge]\']',{def:1})">{:cp_sign('match','N')}</a>
</div>
{/if}
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#{$_tpl_vars['id']}_filter" {if $_tpl_vars['is_relation_url']||$_tpl_vars['is_paging_url']}aria-expanded="false" class="collapsed"{else/}aria-expanded="true"{/if}>结果网址过滤</a>
</h4>
</div>
<div id="{$_tpl_vars['id']}_filter" {if $_tpl_vars['is_relation_url']||$_tpl_vars['is_paging_url']}class="panel-collapse collapse" aria-expanded="false"{else/}class="panel-collapse collapse in" aria-expanded="true"{/if}>
<div class="panel-body">
<div class="form-group">
<div class="input-group" style="margin-bottom:7px;">
<span class="input-group-addon">必须包含</span>
<input type="text" name="{$_tpl_vars['name']}[url_must]" class="form-control" placeholder="选填,可模糊匹配" autocomplete="off" />
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="mgr" onclick="cpWildcard('[name=\'{$_tpl_vars['name']}[url_must]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
</div>
</div>
<div class="input-group">
<span class="input-group-addon">不能包含</span>
<input type="text" name="{$_tpl_vars['name']}[url_ban]" class="form-control" placeholder="选填,可模糊匹配" autocomplete="off" />
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="mgr" onclick="cpWildcard('[name=\'{$_tpl_vars['name']}[url_ban]\']')">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}">正则</span>
</div>
</div>
</div>
</div>
</div>
</div>
{if !$_tpl_vars['is_paging_url']}
<div class="panel panel-default"{if $_tpl_vars['is_url']} style="margin-bottom:0;"{/if}>
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#{$_tpl_vars['id']}_web" aria-expanded="false" class="collapsed">请求网址</a>
</h4>
</div>
<div id="{$_tpl_vars['id']}_web" class="panel-collapse collapse" aria-expanded="false">
<div class="panel-body">
<div class="form-group">
<label class="control-label">自定义请求</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="{$_tpl_vars['name']}[url_web][open]" value="1"></label>
<label class="radio-inline"><input type="radio" name="{$_tpl_vars['name']}[url_web][open]" value="0" checked="checked"></label>
</div>
<p class="help-block">请求网址时使用自定义设置</p>
</div>
<div class="form-group">
<label class="control-label">页面编码</label>
<div class="input-group input-select-custom">
<div class="input-group-btn">
<select name="{$_tpl_vars['name']}[url_web][charset]" class="form-control">
<option value="">默认为采集器设置»网页编码</option>
<option value="utf-8">utf-8</option>
<option value="gbk">gbk</option>
<option value="gb2312">gb2312</option>
<option value="custom">自定义</option>
</select>
</div>
<input type="text" class="form-control" name="{$_tpl_vars['name']}[url_web][charset_custom]">
</div>
</div>
<div class="form-group">
<label>请求方式</label>
<select name="{$_tpl_vars['name']}[url_web][form_method]" class="form-control">
<option value="">GET</option>
<option value="post">POST</option>
</select>
</div>
<div class="form-group">
<label class="control-label">发送数据 <a href="javascript:;" class="glyphicon glyphicon-plus add-url-web-form" title="添加" style="font-size:12px;"></a></label>
<table class="table table-bordered table-hover c-p-url-web-form" style="margin-bottom:0;">
<thead>
<tr>
<td>名称</td>
<td></td>
<td>删除</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="form-group">
<label class="control-label">使用全局请求头</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="{$_tpl_vars['name']}[url_web][header_global]" value="" checked="checked">默认</label>
<label class="radio-inline"><input type="radio" name="{$_tpl_vars['name']}[url_web][header_global]" value="y">强制使用</label>
<label class="radio-inline"><input type="radio" name="{$_tpl_vars['name']}[url_web][header_global]" value="n">强制禁用</label>
</div>
<p class="help-block">默认使用采集器设置»请求头信息»抓取页面中的设置(受全局开启状态影响)</p>
</div>
<div class="form-group">
<label class="control-label">请求头信息 <a href="javascript:;" class="glyphicon glyphicon-plus add-url-web-header" title="添加" style="font-size:12px;"></a></label>
<table class="table table-bordered table-hover c-p-url-web-header" style="margin-bottom:0;">
<thead>
<tr>
<td>名称</td>
<td></td>
<td>删除</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
<p class="help-block">添加新的或者覆盖已有的请求头信息</p>
</div>
</div>
</div>
</div>
{/if}

View File

@ -6,7 +6,8 @@
#form_source .source-params textarea{vertical-align:middle}
</style>
<form id="form_source" method="post" action="{:url('Cpattern/source')}">
<input type="hidden" name="sub" value="1" />
{:html_usertoken()}
<input type="hidden" name="is_submit" value="1" />
<input type="hidden" name="source[type]" value="custom" />
<input type="hidden" name="source[uid]" value="{$source['uid']}" />
<ul class="nav nav-tabs c-p-source-tab">
@ -25,7 +26,7 @@
<div class="input-group" style="margin-bottom:10px;">
<span class="input-group-addon">网址格式</span>
<input type="text" class="form-control" name="source[url]" id="source_url"/>
<div class="input-group-addon" style="background:#fff;"><a href="javascript:;" onclick='cpMatch("#source_url",{only:1})'>{:cp_sign('match')}</a></div>
<div class="input-group-addon" style="background:#fff;"><a href="javascript:;" id="source_url_sign">{:cp_sign('match')}</a></div>
</div>
<div class="input-group-addon" ><span class="glyphicon glyphicon-arrow-up"></span> {:cp_sign('match')} 替换成 <span class="glyphicon glyphicon-arrow-down"></span></div>
<div class="radio form-inline form-group form-group-sm" source-param="num">

View File

@ -1,275 +0,0 @@
<style type="text/css">
#win_json_tree{width:100%;overflow:hidden;}
#win_json_tree ul{list-style:none;margin:0px;padding:0px;padding-left:20px;}
#win_json_tree li{padding:0;margin:0;}
#win_json_tree .tree{cursor:pointer;margin-left:-16px;margin-right:2px;}
#win_json_tree .node{color:#7F007F;}
#win_json_tree .val{}
</style>
<script src="__PUBLIC__/static/js/admin/json_tree.js?{$Think.config.html_v}"></script>
<div id="win_test_cont_url">
<div class="form-group">
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><em class="test-tips" style="font-style:normal">抓取字段</em> <span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="javascript:;" data-test="get_fields" data-title="抓取字段">抓取字段</a></li>
<li><a href="javascript:;" data-test="get_html" data-title="抓取源码">抓取源码</a></li>
<li><a href="javascript:;" data-test="elements" data-title="分析网页">分析网页</a></li>
<li><a href="javascript:;" data-test="get_paging_urls" data-title="抓取分页">抓取分页</a></li>
<li><a href="javascript:;" data-test="get_relation_urls" data-title="抓取关联页">抓取关联页</a></li>
</ul>
</div>
{if condition="!empty($url_post)"}
<div class="input-group-addon" style="color:green;border-right:0;">POST模式</div>
{/if}
<input type="text" class="form-control" name="url" value="{$cont_url}" placeholder="输入内容页网址" />
<div class="input-group-btn"><button type="button" class="btn btn-default test-sub">确定</button></div>
</div>
</div>
{if condition="!empty($input_urls)"}
<div id="win_get_fields_input">
<div class="panel panel-default">
<div class="panel-heading">有字段需要从以下数据源抓取页面,请输入网址</div>
<div class="panel-body">
{if condition="isset($input_urls['source_url'])"}
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">起始页</div>
<input type="text" name="source_url" class="form-control" value="{$input_urls['source_url']}" />
</div>
</div>
{/if}
{if condition="is_array($input_urls['level_url'])"}
{foreach $input_urls['level_url'] as $level_url}
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">多级页:{$level_url['name']}</div>
<input type="text" name="level_{$level_url['level']}" class="form-control" value="{$level_url['url']}" />
</div>
</div>
{/foreach}
{/if}
</div>
</div>
</div>
{/if}
<div class="vals">
</div>
</div>
<script type="text/javascript">
'use strict';//严格模式
//预览
function win_test_view(id){
if($('#'+id).next().attr('id')=='ifm_test_view'){
//折叠
$('#ifm_test_view').remove();
}else{
$('#ifm_test_view').remove();//删除旧的
var html=$('#'+id).val();
html=html.replace(/<script[^<>]*>[\s\S]*?<\/script>/ig,'');//去掉脚本代码
html=html.replace(/<meta[^<>]*charset[^<>]*>/i,'');//去掉编码
var ifm='<iframe id="ifm_test_view" style="width:100%;border:1px solid #ccc;"></iframe>';
$('#'+id).after(ifm);
$('#ifm_test_view').bind('load',function(){
if($("#ifm_test_view").contents().find('body').html().length<=0){
//火狐浏览器需要重新赋值
$("#ifm_test_view").contents().find('body').html(html);
}
var iframeObj = document.getElementById('ifm_test_view');
var height=(iframeObj.Document?iframeObj.Document.body.scrollHeight:iframeObj.contentDocument.body.offsetHeight);
$('#ifm_test_view').attr('height',height+'px');
});
$("#ifm_test_view").contents().find('body').html(html);
}
}
//分析网页
function test_elements(id){
var cont_url=$('#win_test_cont_url input[name="url"]').val();
var url="{:url('Cpattern/browser?coll_id='.$collData['id'].'&url=_url_')}";
url=url.replace('_url_',encodeURIComponent(cont_url));
window.open(url,'_blank');
}
//下拉选择
$('#win_test_cont_url .dropdown-menu a[data-test]').bind('click',function(){
var btnObj=$(this).parents('.dropdown-menu').eq(0).siblings('button.dropdown-toggle').eq(0);
btnObj.attr('data-test',$(this).attr('data-test'));
btnObj.find('.test-tips').text($(this).attr('data-title'));
if($(this).attr('data-test')=='get_fields'){
//显示输入数据源网址
$('#win_get_fields_input').show();
}else{
$('#win_get_fields_input').hide();
}
});
{if condition="!empty($test)"}
$('#win_test_cont_url .dropdown-menu a[data-test="{$test}"]').trigger('click');
{/if}
//测试按钮
$('#win_test_cont_url button.test-sub').bind('click',function(){
var cont_url=$('#win_test_cont_url input[name="url"]').val();
if(!cont_url){
toastr.error('请输入网址');
}else{
$('#win_test_cont_url .vals').html('<img src="'+window.site_config.pub+'/static/images/loading.gif">');
var testOp=$('#win_test_cont_url button.dropdown-toggle').attr('data-test');
testOp=testOp?testOp:'get_fields';//默认获取字段
var url="{:url('Cpattern/test?op=_op_&coll_id='.$collData['id'].'&cont_url=_url_')}";
url=url.replace('_op_',testOp).replace('_url_',encodeURIComponent(cont_url));
if(testOp=='elements'){
test_elements();
$('#win_test_cont_url .vals').html('已过滤所有脚本代码,页面所见即所得!');
}else if(testOp=='get_html'){
//获取源码,防止源代码输出错误
$.ajax({
type:'get',
url:url,
dataType:'html',
success:function(data){
if(htmlIsJson(data)){
//AJAX错误提示
var json=eval('(' + data + ')');
if(json.msg){
//json提示
$('#win_test_cont_url .vals').html(json.msg);
}else{
//json源码
var html='<label>源码:</label><textarea class="form-control" rows="5">'+data
+'</textarea><label style="margin-top:15px;">JSON解析</label><div id="win_json_tree"></div>';
$('#win_test_cont_url .vals').html(html);
//加载json树形
jsonTree.treeId='#win_json_tree';
jsonTree.treeClass='.tree';
jsonTree.load(data);
}
}else{
var eleId=generateUUID();
data=data.replace(/\</g,'&lt;').replace(/\>/g,'&gt;');//编码
var html='<label>源码:</label><a href="javascript:;" onclick="test_elements()">分析网页</a><textarea id="'
+eleId+'" class="form-control" rows="20">'+data+'</textarea>';
$('#win_test_cont_url .vals').html(html);
}
}
});
}else{
if(testOp=='get_fields'){
//附加数据源网址
$('#win_get_fields_input').find('input').each(function(){
url+='&'+$(this).attr('name')+'='+encodeURIComponent($(this).val());
});
//表格标题左右拉伸
window.win_test_table_thead_mousedown=null;//点击初始
var thEle='.table-test-loop thead th';
$('#win_test_cont_url').off('mousedown',thEle).on('mousedown',thEle,function(e){
$(this).css('background','#f1f1f1');
window.win_test_table_thead_mousedown={
table_width:$('#win_test_cont_url .table-test-loop').width(),
th_width:$(this).width(),
page_x:e.pageX
};
$(this).off('mousemove').bind('mousemove',function(e){
var def=window.win_test_table_thead_mousedown;
if(def){
var moveWidth=e.pageX-def.page_x;
$("#win_test_cont_url .table-test-loop").width(def.table_width+moveWidth);
$(this).width(def.th_width+moveWidth);
}
});
$(this).off('mouseout mouseup').bind('mouseout mouseup',function(e){
$(this).css('background','');
window.win_test_table_thead_mousedown=null;//结束
});
});
}
$.ajax({
type:'get',
url:url,
dataType:'json',
success:function(data){
if(data.code==1){
var html='';
if(testOp=='get_paging_urls'){
html='<div class="page-header"><b>成功抓取到分页链接</b></div><ul>';
for(var i in data.data){
html+='<li>'+data.data[i]+'</li>';
}
html+='</ul>';
}else if(testOp=='get_fields'){
if(data.msg){
toastr.success(data.msg);
}
if(data.data.length>1){
//循环数据
html+='<div class="table-responsive"><table class="table table-bordered table-hover table-test-loop"><thead><tr><td></td>';
var fields=data.data[0];//第一条数据
for(var f in fields){
html+='<th>'+f+'</th>';
}
html+='</tr></thead><tbody>';
var curNum=0;
for(var i in data.data){
curNum++;
var vals=data.data[i];//每条数据
html+='<tr><td>'+curNum+'</td>';
for(var f in vals){
if(vals[f]){
html+='<td><input type="text" value="'+(vals[f].replace(/"/g, '&quot;'))+'" /></td>';
}else{
html+='<td></td>';
}
}
html+='</tr>';
}
html+='</tbody>';
}else{
//一条数据
var vals=data.data[0];
for(var f in vals){
var browse='';
var eleId=generateUUID();
if((/<[^<>]*>/).test(vals[f])){
//检测到html代码
browse='<a href="javascript:;" onclick="win_test_view(\''+eleId+'\')">预览</a>';
}
vals[f]=vals[f].replace(/\</g,'&lt;').replace(/\>/g,'&gt;');//编码
html+='<label>'+f+'</label>'+browse+'<textarea id="'+eleId+'" class="form-control">'+vals[f]+'</textarea><br>';
}
}
}else if(testOp=='get_relation_urls'){
html='<div class="page-header"><b>关联页网址</b></div><ul>';
for(var i in data.data){
html+='<li>'+i+''+data.data[i]+'</li>';
}
html+='</ul>';
}
$('#win_test_cont_url .vals').html(html);
}else{
$('#win_test_cont_url .vals').html(data.msg);
}
}
});
}
}
});
//回车测试
$('#win_test_cont_url input[name="url"]').bind('keyup',function(event){
  if(event.keyCode=="13"){
$('#win_test_cont_url button').trigger("click");
  }
});
if($('#win_test_cont_url input[name="url"]').val().length>0){
//有网址自动触发
$('#win_test_cont_url button').trigger("click");
}
</script>

View File

@ -0,0 +1,33 @@
{if condition="!empty($input_urls)"}
<div class="panel panel-default">
<div class="panel-heading">需要从以下页面中抓取数据,请输入网址</div>
<div class="panel-body">
{if condition="isset($input_urls['source_url'])"}
<div class="form-group">
<div class="input-group input-group-sm">
<div class="input-group-addon">起始页</div>
<input type="text" name="source_url" class="form-control" value="{$input_urls['source_url']}" />
</div>
</div>
{/if}
{if condition="is_array($input_urls['level_url'])"}
{foreach $input_urls['level_url'] as $level_url}
<div class="form-group">
<div class="input-group input-group-sm">
<div class="input-group-addon">多级页:{$level_url['name']}</div>
<input type="text" name="level_{$level_url['level']}" class="form-control" value="{$level_url['url']}" />
</div>
</div>
{/foreach}
{/if}
{if condition="isset($input_urls['url'])"}
<div class="form-group">
<div class="input-group input-group-sm">
<div class="input-group-addon">内容页</div>
<input type="text" name="url" class="form-control" value="{$input_urls['url']}" />
</div>
</div>
{/if}
</div>
</div>
{/if}

View File

@ -1,5 +1,6 @@
{extend name="common:main" /}
{block name="cssjs"}
<script type="text/javascript" src="__PUBLIC__/static/js/admin/collector.js?{$Think.config.html_v}"></script>
{/block}
{block name="content"}
<div class="box box-default">

View File

@ -1,52 +1,134 @@
<div id="win_test_match">
<form method="post" action="{:url('Cpattern/test')}">
<form method="post" action="{:url('cpattern_test/match')}">
{:html_usertoken()}
<input type="hidden" name="coll_id" value="{$collData['id']}" />
<input type="hidden" name="op" value="match" />
<div class="form-group">
<label>输入网址或内容</label>
<textarea rows="5" class="form-control" name="content"></textarea>
<p class="help-block">网址必须以http://或https://开头</p>
<label>模拟类型</label>
<select class="form-control" name="input_type">
<option value="content">内容</option>
<option value="url">网址</option>
</select>
</div>
<div id="input_type_content">
<div class="form-group">
<label>输入内容</label>
<textarea rows="5" class="form-control" name="content"></textarea>
</div>
</div>
<div id="input_type_url" style="display:none;">
<div class="form-group">
<label>输入网址</label>
<input type="text" name="url" class="form-control" />
<p class="help-block">网址必须以http://或https://开头</p>
</div>
<div class="form-group">
<label class="control-label">页面编码</label>
<div class="input-group input-select-custom">
<div class="input-group-btn">
<select name="charset" class="form-control">
<option value="">默认为采集器设置»网页编码</option>
<option value="utf-8">utf-8</option>
<option value="gbk">gbk</option>
<option value="gb2312">gb2312</option>
<option value="custom">自定义</option>
</select>
</div>
<input type="text" class="form-control" name="charset_custom">
</div>
</div>
<div class="form-group">
<label class="control-label">请求方式</label>
<select name="form_method" class="form-control">
<option value="">GET</option>
<option value="post">POST</option>
</select>
</div>
<div class="form-group form">
<label class="control-label">发送数据 <a href="javascript:;" class="glyphicon glyphicon-plus add" title="添加" style="font-size:12px;"></a></label>
<table class="table table-bordered table-hover" style="margin-bottom:0;">
<thead>
<tr>
<td>名称</td>
<td></td>
<td>删除</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="form-group">
<label class="control-label">使用全局请求头</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="header_global" value="" checked="checked">默认</label>
<label class="radio-inline"><input type="radio" name="header_global" value="y">强制使用</label>
<label class="radio-inline"><input type="radio" name="header_global" value="n">强制禁用</label>
</div>
<p class="help-block">默认使用采集器设置»请求头信息»抓取页面中的设置(受全局开启状态影响)</p>
</div>
<div class="form-group header">
<label class="control-label">请求头信息 <a href="javascript:;" class="glyphicon glyphicon-plus add" title="添加" style="font-size:12px;"></a></label>
<table class="table table-bordered table-hover" style="margin-bottom:0;">
<thead>
<tr>
<td>名称</td>
<td></td>
<td>删除</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
<p class="help-block">添加新的或者覆盖已有的请求头信息</p>
</div>
</div>
<div class="form-group">
<label>方式</label>
<label>获取方式</label>
<select class="form-control" name="type">
<option value="rule">规则匹配</option>
<option value="rule" checked="checked">规则匹配</option>
<option value="xpath">XPath匹配</option>
<option value="json">JSON提取</option>
</select>
</div>
<div class="form-group">
<label>输入规则</label>
<textarea class="form-control" name="match"></textarea>
<p class="help-block">输入所选方式的规则</p>
<div class="form-group" id="type_rule">
{include file="cpattern:field_rule" _type="rule" _name_pre="" _allow_loop="" /}
</div>
<div class="form-group" id="type_xpath" style="display:none;">
{include file="cpattern:field_rule" _type="xpath" _name_pre="" _allow_loop="" /}
</div>
<div class="form-group" id="type_json" style="display:none;">
{include file="cpattern:field_rule" _type="json" _name_pre="" _allow_loop="" /}
</div>
<div class="form-group">
<button type="submit" class="btn btn-default btn-block">开始测试</button>
</div>
</form>
<div class="form-group test-match-val" style="display:none;">
<label>匹配结果</label>
<textarea rows="3" class="form-control"></textarea>
<div><label>匹配结果</label><a href="javascript:;" class="visualize" style="margin-left:5px;display:none;">预览</a></div>
<textarea id="test_match_val" rows="10" class="form-control"></textarea>
</div>
<table style="display:none">
<tr id="tpl_tr_form">
<td><input type="text" name="form_names[]" class="form-control" /></td>
<td><input type="text" name="form_vals[]" class="form-control" /></td>
<td><a href="javascript:;" class="glyphicon glyphicon-remove delete" style="margin-top:8px;"></a></td>
</tr>
<tr id="tpl_tr_header">
<td><input type="text" name="header_names[]" class="form-control" /></td>
<td><input type="text" name="header_vals[]" class="form-control" /></td>
<td><a href="javascript:;" class="glyphicon glyphicon-remove delete" style="margin-top:8px;"></a></td>
</tr>
</table>
</div>
<script type="text/javascript">
$('#win_test_match form').bind('submit',function(){
$.ajax({
type:'post',
url:$(this).attr('action'),
dataType:'json',
data:$(this).serialize(),
success:function(data){
if(data.code==1){
$('#win_test_match .test-match-val').show().find('textarea').val(data.msg);
}else{
toastr.error(data.msg);
}
}
});
return false;
});
'use strict';//严格模式
$.getScript("__PUBLIC__/static/js/admin/cpattern_test.js?{$Think.config.html_v}", function() {
CpTestMatch();
});
</script>

View File

@ -1,9 +1,15 @@
<style type="text/css">
#test_source_urls .source_url{padding:5px;}
#test_source_urls p{margin:0;}
#test_source_urls ol{padding-left:15px;}
#win_test_source_urls .set-test-num{padding:5px;padding-top:0;display:none;}
#win_test_source_urls .source_url{padding:5px;}
#win_test_source_urls p{margin:0;}
#win_test_source_urls ol{padding-left:15px;}
</style>
<div id="test_source_urls">
<div id="win_test_source_urls">
<div class="set-test-num">
<b>多级页只测试前</b> <input type="number" value="" class="form-control input-sm set-num" style="display:inline;width:40px;height:20px;padding:1px 2px 1px 2px;" /> <b>条数据</b>
<button type="button" class="btn btn-default btn-xs set-num-btn">保存</button>
</div>
{if condition="empty($source_urls)"}
没有起始页网址
{else /}
@ -45,142 +51,14 @@
{/if}
{/if}
</div>
<script type="text/javascript">
'use strict';//严格模式
var max_num=3;//测试时最多显示数量
var url_ajax_requests=new Array();//ajax对象
$(document).ready(function(){
$('#test_source_urls .source_url').each(function(index){
//起始页开始测试
{if condition="!$config['source_is_url']"}
var source_url=$(this).attr('url');
{if condition="!empty($config['level_urls'])"}
//有多级
if(index<max_num){
//测试前几页
get_cont_urls(source_url,$(this),1);
}
{else /}
get_cont_urls(source_url,$(this),0);
{/if}
{/if}
});
//测试
$('#test_source_urls').on('click','.cont_ceshi',function(){
var test_cont_url="{:url('Cpattern/test?op=cont_url&coll_id='.$collData['id'])}&cont_url=_url_";
test_cont_url=test_cont_url.replace('_url_',encodeURIComponent($(this).attr('url')));
var urls={};
$(this).parents('.source_url').each(function(){
var surl=$(this).attr('url');
if(surl){
if($(this).attr('level')){
//是级别
urls['level_'+$(this).attr('level')]=surl;
}else{
//是起始页
urls['source_url']=surl;
}
}
});
if(urls){
//加上多级和起始网址
for(var i in urls){
test_cont_url+='&'+i+'='+encodeURIComponent(urls[i]);
}
}
window.open(test_cont_url,'_blank');
$.getScript("__PUBLIC__/static/js/admin/cpattern_test.js?{$Think.config.html_v}", function() {
var cpTestSourceUrls=new CpTestSourceUrls("{$collData['id']}",{$testNum|intval},{$config['source_is_url']?1:0},{:empty($config['level_urls'])?0:1});
$(document).ready(function(){
cpTestSourceUrls.init();
});
//分析
$('#test_source_urls').on('click','.cont_element',function(){
if((/\beasymode\s*\=/i).test(window.self.location.href)&&window.top){
//简单模式
window.top.postMessage('browser_url:'+$(this).attr('url'),'*');
}else{
var ele_cont_url="{:url('Cpattern/browser?coll_id='.$collData['id'])}&url=_url_";
ele_cont_url=ele_cont_url.replace('_url_',encodeURIComponent($(this).attr('url')));
window.open(ele_cont_url,'_blank');
}
});
//展开收起
$('#test_source_urls').on('click','.cont_urls_num a',function(){
var status=$(this).attr('status');
if(status==1){
$(this).html('[展开]');
$(this).attr('status',0);
$(this).parents('.cont_urls_num').eq(0).siblings('.cont_urls_list').hide();
}else{
$(this).html('[收起]');
$(this).attr('status',1);
$(this).parents('.cont_urls_num').eq(0).siblings('.cont_urls_list').show();
}
});
//获取网址
function get_cont_urls(source_url,curObj,level){
if(source_url){
curObj.children('.cont_urls_list').html('<img src="'+window.site_config.pub+'/static/images/load1.gif">').show();
var url="{:url('Cpattern/test?op=cont_urls&coll_id='.$collData['id'].'&source_url=_url_&level=_level_')}";
url=url.replace('_url_',encodeURIComponent(source_url)).replace('_level_',level);
var url_ajax_request=$.ajax({
type:'get',
url:url,
async:true,
success:function(data){
if(data.code==1){
//内容网址列表
var urls=data.data.urls;
var list='<ul style="list-style-type:'+(level>0?'decimal':'square')+';padding-left:15px;white-space:normal;overflow-x:scroll;">';
if(level>0){
//抓取级别网址
for(var i in urls){
if(i<max_num){
//测试前几页
list+='<li class="source_url" url="'+urls[i]+'" level="'+level+'"><p><b>抓取第'+level+'级页面 “'+data.data.levelName+'”:</b>'+urls[i]+'</p><p class="cont_urls_num"></p><div class="cont_urls_list"></div></li>';
}
}
list+='</ul>';
curObj.children('.cont_urls_list').html(list).show();
curObj.children('.cont_urls_num').html('获取到'+urls.length+'条网址'+(urls.length>max_num?'(只测试前'+max_num+'条)':'')+' <a href="javascript:;" status="1">[收起]</a>');
curObj.children('.cont_urls_list').find('.source_url').each(function(){
var obj=$(this);
get_cont_urls(obj.attr('url'),obj,data.data.nextLevel);//抓取下一级或内容页
});
}else{
//无级别,显示测试网址
for(var i in urls){
list+='<li>[<a href="javascript:;" class="cont_ceshi" url="'+urls[i]+'">测试</a>] '
+'[<a href="javascript:;" class="cont_element" url="'+urls[i]+'">分析</a>] '+urls[i]+'</li>';
}
list+='</ul>';
//没有下一级
curObj.children('.cont_urls_list').html(list).hide();
curObj.children('.cont_urls_num').html('获取到'+urls.length+'条网址 <a href="javascript:;" status="0">[展开]</a>');
}
}else{
//错误信息
curObj.children('.cont_urls_list').html('<span style="color:red">'+data.msg+'</span>').show();
}
},
dataType:'json'
});
window.url_ajax_requests.push(url_ajax_request);
}
}
});
$('#myModal').on('hide.bs.modal', function (e) {
if(window.url_ajax_requests){
//退出时清除所有ajax请求
for(var i in window.url_ajax_requests){
window.url_ajax_requests[i].abort();//终止ajax
}
}
});
});
</script>

View File

@ -1,10 +1,10 @@
{extend name="common:main" /}
{block name="cssjs"}
{/block}
{block name="content"}
<div class="box box-default">
<div class="box-body">
{include file="cpattern:test_cont_url_ajax" /}
</div>
</div>
{extend name="common:main" /}
{block name="cssjs"}
{/block}
{block name="content"}
<div class="box box-default">
<div class="box-body">
{include file="cpattern:test_test_url_ajax" /}
</div>
</div>
{/block}

View File

@ -0,0 +1,43 @@
<style type="text/css">
#win_input_urls>.panel{margin-bottom:10px;}
</style>
<div id="win_test_url">
<div class="form-group">
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><em class="test-tips" style="font-style:normal">抓取字段</em> <span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="javascript:;" data-test="get_fields" data-title="抓取字段">抓取字段</a></li>
<li><a href="javascript:;" data-test="get_signs" data-title="内容标签">内容标签</a></li>
<li><a href="javascript:;" data-test="get_html" data-title="抓取源码">抓取源码</a></li>
<li><a href="javascript:;" data-test="get_elements" data-title="分析网页">分析网页</a></li>
<li><a href="javascript:;" data-test="get_paging_urls" data-title="抓取分页">抓取分页</a></li>
<li><a href="javascript:;" data-test="get_relation_urls" data-title="抓取关联页">抓取关联页</a></li>
</ul>
</div>
<input type="text" class="form-control" name="test_url" value="{$test_url}" placeholder="输入内容页网址" />
<div class="input-group-addon test-page-sources" style="padding:0;border:0;width:110px;display:none;">
<select class="form-control" name="page_source">
<option value="">页面类型</option>
{foreach $pageSources as $k=>$v}
<option value="{$k}"{if $k=='url'} selected="selected"{/if}>{$v}</option>
{/foreach}
</select>
</div>
<div class="input-group-btn"><button type="button" class="btn btn-default test-sub">确定</button></div>
</div>
</div>
<input type="hidden" name="url_params" value="{$urlParams}" />
<div id="win_input_urls" style="display:none;"></div>
<div class="field-vals"></div>
</div>
<script type="text/javascript">
'use strict';//严格模式
$.getScript("__PUBLIC__/static/js/admin/cpattern_test.js?{$Think.config.html_v}", function() {
var cpTestUrl=new CpTestUrl("{$collData['id']}","{$test}");
$(document).ready(function(){
cpTestUrl.init();
});
});
</script>

View File

@ -6,6 +6,7 @@
<div class="box box-default">
<div class="box-body">
<form id="form_app" method="post" ajax-submit="true" action="{:url('Admin/Develop/app')}">
{:html_usertoken()}
{if !empty($appData)}
<input type="hidden" name="edit" value="1" />
<input type="hidden" name="app" value="{$appData['app']}" />

View File

@ -1,4 +1,5 @@
<form id="win_form_pack" method="post" action="{:url('Develop/appAddPack')}">
{:html_usertoken()}
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<label>名称</label>

View File

@ -1,4 +1,5 @@
<form id="win_form_param" method="post" action="{:url('Develop/cmsAddParam')}">
{:html_usertoken()}
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<label>变量名(英文)</label>

View File

@ -6,6 +6,7 @@
<div class="box box-default">
<div class="box-body">
<form id="form_func" method="post" ajax-submit="true" action="{:url('Admin/Develop/func')}">
{:html_usertoken()}
{if !empty($funcClass)}
<input type="hidden" name="edit" value="1" />
<input type="hidden" name="app" value="{$funcClass['app']}" />
@ -18,7 +19,6 @@
<button type="button" class="btn btn-default btn-block dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">插件另存为 <span class="caret"></span></button>
<ul class="dropdown-menu" style="width:100%;text-align:center;background:#f4f4f4;">
<li><a href="{:url('Admin/Develop/export?type=func&app='.$funcClass['app'])}" target="_blank">导出至本地</a></li>
<li><a href="{:url('Admin/Develop/save2store?type=func&app='.$funcClass['app'])}" title="云端存储,保存插件更方便!" onclick="windowModal('保存到云端',$(this).attr('href'));return false;">上传至云端</a></li>
</ul>
</div>
</div>

View File

@ -6,9 +6,10 @@
<div class="box box-default">
<div class="box-body">
<form id="form_cms" method="post" ajax-submit="true" action="{:url('Admin/Develop/releaseCms')}">
{:html_usertoken()}
{if condition="$config['is_edit']"}
{if $is_old_plugin}
<div class="alert alert-error">
<div class="alert alert-danger">
{:lang('release_upgrade')}
</div>
{else/}
@ -21,7 +22,6 @@
<button type="button" class="btn btn-default btn-block dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">插件另存为 <span class="caret"></span></button>
<ul class="dropdown-menu" style="width:100%;text-align:center;background:#f4f4f4;">
<li><a href="{:url('Admin/Develop/export?type=release&app='.$config['app'])}" target="_blank">导出至本地</a></li>
<li><a href="{:url('Admin/Develop/save2store?type=release&app='.$config['app'])}" title="云端存储,保存插件更方便!" onclick="windowModal('保存到云端',$(this).attr('href'));return false;">上传至云端</a></li>
</ul>
</div>
</div>
@ -52,7 +52,7 @@
</div>
</div>
<div class="form-group">
<label>插件功能标识</label>
<label>功能标识</label>
<input type="text" name="identifier" class="form-control">
<p class="help-block">表示该插件的作用,只能输入字母或数字</p>
</div>

View File

@ -1,17 +0,0 @@
{if condition="!empty($pluginData)"}
<script src="__PUBLIC__/static/js/admin/store.js?{$Think.config.html_v}"></script>
<div>
<form id="win_form_save2store" action="https://www.skycaiji.com/client/plugin/upload" method="post" target="myModalIframe">
<input type="hidden" name="plugin" value="{:base64_encode(serialize($pluginData))}" />
</form>
<script type="text/javascript">
$(document).ready(function(){
/*利用iframe+form post提交*/
var formhtml=$('#win_form_save2store').prop("outerHTML")+'<script type="text\/javascript">$("#win_form_save2store").submit()<\/script>';
windowStore('正在上传...','',{addonBody:formhtml});
});
</script>
</div>
{else /}
插件不存在
{/if}

View File

@ -18,11 +18,11 @@
<input type="text" name="username" class="form-control" placeholder="{$Think.lang.find_pwd_username}" />
</div>
</div>
{if condition="$GLOBALS['_sc']['c']['site']['verifycode']"}
{if condition="g_sc_c('site','verifycode')"}
<div class="form-group">
<div class="input-group">
<input type="text" name="verifycode" class="form-control" placeholder="{$Think.lang.verifycode}" />
<div class="input-group-btn"><img src="{:url('Admin/Index/verify')}" class="verify-img" onclick="refreshVerify(this)" /></div>
<div class="input-group-btn"><img src="{:url('Admin/Index/verify')}" class="verify-img" onclick="refreshVerify(this)" onerror="verifyImgError()" /></div>
</div>
</div>
{/if}

Some files were not shown because too many files have changed in this diff Show More