pull/1/head
zorlan 2019-02-19 17:52:13 +08:00
commit fef736b6bb
2869 changed files with 480398 additions and 0 deletions

3
.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
*.js linguist-language=php
*.css linguist-language=php
*.html linguist-language=php

8
.htaccess Normal file
View File

@ -0,0 +1,8 @@
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

1
SkycaijiApp/.htaccess Normal file
View File

@ -0,0 +1 @@
deny from all

View File

@ -0,0 +1,6 @@
<?php
/*兼容v1.x的发布插件*/
namespace Release\Cms;
abstract class BaseCms extends \plugin\release\cms\BaseCms {
}
?>

View File

@ -0,0 +1,6 @@
<?php
/*兼容v1.x的发布插件*/
namespace Release\Diy;
abstract class BaseDiy extends \plugin\release\diy\BaseDiy{
}
?>

View File

@ -0,0 +1,6 @@
<?php
/*兼容v1.x的发布插件*/
namespace Release\Diy;
class CodeDiy extends \plugin\release\diy\CodeDiy{
}
?>

View File

@ -0,0 +1,115 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\behavior;
use skycaiji\admin\controller\BaseController;
class Init{
public function run(){
$curController=strtolower(request()->controller());
if('store'==$curController){
header('Access-Control-Allow-Origin:http://www.skycaiji.com');
header('Access-Control-Allow-Credentials:true');
header('Access-Control-Allow-Methods:POST,GET');
}
/*自动登录*/
$muser=model('User');
$s_userid=session('user_id');
if(empty($s_userid)){
$login_history=cookie('login_history');
if(!empty($login_history)){
$login_history=explode('|', $login_history);
$user=$muser->where('username',$login_history[0])->find();
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']);
}
}
}
$s_userid=session('user_id');
}
if($s_userid>0){
$GLOBALS['user']=$muser->getByUid($s_userid);
if(!empty($GLOBALS['user'])){
$GLOBALS['user']=$GLOBALS['user']->toArray();
$GLOBALS['user']['group']=model('Usergroup')->getById($GLOBALS['user']['groupid']);
if(!empty($GLOBALS['user']['group'])){
$GLOBALS['user']['group']=$GLOBALS['user']['group']->toArray();
}
}
}
/*用户未登录或者不是管理员用户*/
if(empty($GLOBALS['user'])||(empty($GLOBALS['user']['group']['founder'])&&empty($GLOBALS['user']['group']['admin']))){
if(!in_array($curController, array('index','api'))){
$baseContr=new BaseController();
$baseContr->dispatchJump(false,lang('user_error_is_not_admin'),url('Admin/Index/index',null,null,true));
exit();
}
}else{
/*是管理员,进行下列操作*/
if('index'==$curController&&'index'==strtolower(request()->action())){
$baseContr=new BaseController();
$baseContr->success(lang('user_auto_login'),url('Admin/Backstage/index',null,null,true));
}
config('dispatch_error_tmpl','common:error_admin');
config('dispatch_success_tmpl','common:success_admin');
}
/*通用操作,全局变量*/
$mconfig=model('Config');
$latestDate=$mconfig->max('dateline');
$keyConfig='cache_config_all';
$cacheConfig=cache($keyConfig);
$configList=array();
if(empty($cacheConfig)||$cacheConfig['update_time']!=$latestDate){
$configDbList=$mconfig->column('*');
$configDbList=empty($configDbList)?array():$configDbList;
foreach ($configDbList as $configItem){
$configItem=$mconfig->convertData($configItem);
$configList[$configItem['cname']]=$configItem['data'];
}
cache($keyConfig,array('update_time'=>$latestDate,'list'=>$configList));
}else{
$configList=$cacheConfig['list'];
}
$GLOBALS['config']=$configList;
$GLOBALS['clientinfo']=clientinfo();
if(!empty($GLOBALS['clientinfo'])){
$GLOBALS['clientinfo']=base64_encode(json_encode($GLOBALS['clientinfo']));
}
$usertoken=session('usertoken');
if(empty($usertoken)){
$usertoken=rand(1, 9999999).'_'.date('Y-m-d');
$usertoken=md5($usertoken);
session('usertoken',$usertoken);
}
$GLOBALS['usertoken']=$usertoken;
}
}
?>

View File

@ -0,0 +1,92 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
/*采集规则标签*/
function cp_sign($sign,$num=''){
$sign=strtolower($sign);
if($sign=='match'){
return lang('sign_match',array('num'=>$num));
}else{
}
}
/*密码验证*/
function check_verify($verifycode){
if(empty($verifycode)){
return array('msg'=>lang('verifycode_error'),'name'=>'verifycode');
}
$verify = new \think\captcha\Captcha(array('reset'=>false));
if(!$verify->check($verifycode)){
return array('msg'=>lang('verifycode_error'),'name'=>'verifycode');
}
return array('success'=>true);
}
/*获取项目的文件md5列表*/
function program_filemd5_list($path,&$md5FileList){
static $passPaths=array();
if(empty($passPaths)){
$passPaths['data']=realpath(config('root_path').'/data');
$passPaths['runtime']=realpath(config('root_path').'/runtime');
$passPaths=array_filter($passPaths);
}
$fileList=scandir($path);
foreach( $fileList as $file ){
$isPass=false;
$fileName=realpath($path.'/'.$file);
foreach ($passPaths as $passPath){
if($fileName==$passPath||stripos($fileName,$passPath)>0){
$isPass=true;
}
}
if($isPass){
continue;
}
if(is_dir( $fileName ) && '.' != $file && '..' != $file ){
program_filemd5_list( $fileName,$md5FileList );
}elseif(is_file($fileName)){
$root=realpath(config('root_path'));
$curFile=str_replace('\\', '/',str_replace($root, '', $fileName));
$md5FileList[]=array('md5'=>md5_file($fileName),'file'=>$curFile);
}
}
}
/*验证用户token*/
function check_usertoken(){
if($GLOBALS['usertoken']!=input('_usertoken_')){
return false;
}else{
return true;
}
}
/*输出用户token*/
function html_usertoken(){
return '<input type="hidden" name="_usertoken_" value="'.$GLOBALS['usertoken'].'" />';
}
/*判断正在执行采集任务*/
function is_collecting(){
if(defined('IS_COLLECTING')){
return true;
}else{
return false;
}
}
/*移除自动采集》正在采集状态*/
function remove_auto_collecting(){
\skycaiji\admin\model\CacheModel::getInstance()->db()->where('cname','auto_collecting')->delete();
}

View File

@ -0,0 +1,16 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
return array(
'dispatch_success_tmpl' => 'common:success',
'dispatch_error_tmpl' => 'common:error',
);

View File

@ -0,0 +1,77 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
use skycaiji\admin\model\CacheModel;
class Api extends BaseController{
/*任务api发布*/
public function taskAction(){
define('CLOSE_ECHO_MSG', 1);
$taskId=input('id/d',0);
$apiurl=input('apiurl');
$releData=model('Release')->where(array('task_id'=>$taskId))->find();
$releData['config']=unserialize($releData['config']);
if($apiurl!=$releData['config']['api']['url']){
exit('api地址错误');
}
header('Content-type:text/json');
controller('admin/Task','controller')->_collect($taskId);
}
/*执行采集*/
public function collectAction(){
define('IS_COLLECTING', 1);
$mcache=CacheModel::getInstance();
if($mcache->getCache('auto_collecting')){
$this->error('有任务正在自动采集');
}
$mcache->setCache('auto_collecting',1);
register_shutdown_function('remove_auto_collecting');
if(!session('user_id')){
define('CLOSE_ECHO_MSG', true);
}
ignore_user_abort(true);
if($GLOBALS['config']['caiji']['timeout']>0){
set_time_limit(60*$GLOBALS['config']['caiji']['timeout']);
}else{
set_time_limit(0);
}
if(empty($GLOBALS['config']['caiji']['auto'])){
$this->error('请先开启自动采集','Admin/Setting/caiji');
}
$lastCollectTime=cache('last_collect_time');
if($GLOBALS['config']['caiji']['interval']>0){
$waitTime=(60*$GLOBALS['config']['caiji']['interval'])-abs(time()-$lastCollectTime);
if($waitTime>0){
$this->error('再次采集需等待'.(($waitTime<60)?($waitTime.'秒'):(sprintf("%.2f", $waitTime/60).'分钟')),'Admin/Api/collect',null,$waitTime);
}
}
$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('没有可自动采集的任务');
}
$taskList=collection($taskList)->toArray();
cache('last_collect_time',time());
controller('admin/Task','controller')->_collect_batch($taskList);
$this->echo_msg('所有任务执行完毕!','green');
}
}

View File

@ -0,0 +1,151 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
use skycaiji\admin\model\CacheModel;
class Backstage extends BaseController{
public function indexAction(){
$runInfo=array();
$mcollected=model('Collected');
$todayTime=strtotime(date('Y-m-d',time()));
$runInfo['today_success']=$mcollected->where(array('addtime'=>array('GT',$todayTime),'target'=>array('<>','')))->count();
$runInfo['today_error']=$mcollected->where(array('addtime'=>array('GT',$todayTime),'error'=>array('<>','')))->count();
$runInfo['total_success']=$mcollected->where("`target` <> ''")->count();
$runInfo['total_error']=$mcollected->where("`error` <> ''")->count();
$runInfo['task_auto']=model('Task')->where('`auto`=1')->count();
$runInfo['task_other']=model('Task')->where('`auto`=0')->count();
/*服务器信息*/
$serverInfo=array(
'os'=>php_uname('s').' '.php_uname('r'),
'php'=>PHP_VERSION,
'db'=>config('database.type'),
'version'=>$GLOBALS['config']['version']?$GLOBALS['config']['version']:constant("SKYCAIJI_VERSION"),
'server'=>$_SERVER["SERVER_SOFTWARE"],
'upload_max'=>ini_get('upload_max_filesize')
);
if(stripos($serverInfo['db'],'mysql')!==false){
$dbVersion=db()->query('SELECT VERSION() as v;');
$serverInfo['db'].=' '.($dbVersion[0]?$dbVersion[0]['v']:'');
}
$runInfo['auto_status']='良好';
/*设置采集状态*/
if($GLOBALS['config']['caiji']['auto']){
$lastTime=cache('last_collect_time');
$taskAutoCount=model('Task')->where('auto',1)->count();
if($taskAutoCount<=0){
$serverInfo['caiji']='<a href="'.url('Admin/Task/list').'">未设置自动采集任务</a>';
$runInfo['auto_status']='无任务';
}else{
if($lastTime>0){
$runInfo['auto_status']='运行良好';
$serverInfo['caiji']='最近采集:'.date('Y-m-d H:i:s',$lastTime).' &nbsp;';
if($GLOBALS['config']['caiji']['run']=='backstage'){
if(NOW_TIME-$lastTime>60*($GLOBALS['config']['caiji']['interval']+15)){
$serverInfo['caiji'].='<p class="help-block">自动采集似乎停止了,请<a href="'.
url('Admin/Setting/caiji').'">重新保存设置</a>以便激活采集</p>';
$runInfo['auto_status']='停止运行';
}
}
}
$serverInfo['caiji'].='<a href="javascript:;" id="a_collect_now">实时采集</a>';
}
}else{
$runInfo['auto_status']='已停止';
$serverInfo['caiji']='<a href="'.url('Admin/Setting/caiji').'">未开启自动采集</a>';
}
$upgradeDb=false;
if(version_compare(model('Config')->getVersion(),SKYCAIJI_VERSION,'<')){
$upgradeDb=true;
}
$timeout=NOW_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);
$mcacheCont=CacheModel::getInstance('cont_url');
$mcacheCont->db()->where('dateline','<',$timeout)->delete();
$GLOBALS['content_header']='后台管理';
$GLOBALS['breadcrumb']=breadcrumb(array('首页'));
$this->assign('runInfo',$runInfo);
$this->assign('serverInfo',$serverInfo);
$this->assign('upgradeDb',$upgradeDb);
return $this->fetch('backstage/index');
}
/*实时采集*/
public function collectAction(){
remove_auto_collecting();
controller('admin/Api','controller')->collectAction();
}
/*获取推送消息*/
public function adminIndexAction(){
$callback=input('?'.config('var_jsonp_handler'))?input(config('var_jsonp_handler')):config('default_jsonp_handler');
$html=get_html('http://www.skycaiji.com/Store/Client/adminIndex?v='.SKYCAIJI_VERSION.'&'.config('var_jsonp_handler').'='.rawurlencode($callback),null,null,'utf-8');
header('Content-Type:application/json;charset=utf-8');
exit($html);
}
/*生成js语言包文件*/
public function createJsLangAction(){
$langs=array();
$langs['zh-cn']='zh-cn';
foreach($langs as $lk=>$lv){
$module_file=config('app_path').'/admin/lang/'.$lv.'.php';
$module_lang=include $module_file;
$module_lang=is_array($module_lang)?$module_lang:array();
$common_file=config('app_path').'/lang/'.$lv.'.php';
$common_lang=include $common_file;
$common_lang=is_array($common_lang)?$common_lang:array();
$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>";
}
}
/* 排查重复的语言变量 */
public function checkRepeatLangAction() {
$file = config ( 'app_path' ) . '/admin/lang/zh-cn.php';
$txt = file_get_contents ( $file );
$repeatList = array ();
if (preg_match_all ( '/[\'\"](\w+)[\'\"]\s*\=\s*\>\s*/', $txt, $keys )) {
$keys = $keys [1];
foreach ( $keys as $i => $key ) {
if (in_array ( $key, array_slice ( $keys, $i + 1 ) )) {
$repeatList [] = $key;
}
}
}
print_r ( $repeatList );
}
}

View File

@ -0,0 +1,81 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
class BaseController extends \skycaiji\common\controller\BaseController{
/*输出模板防止ajax时乱码*/
public function fetch($template = '', $vars = [], $replace = [], $config = []){
if(request()->isAjax()){
$config=is_array($config)?null:$config;
return view($template, $vars, $replace,$config);
}else{
return parent::fetch($template, $vars, $replace, $config);
}
}
/*输出内容函数*/
private static $echo_msg_head=null;
public function echo_msg($str,$color='red',$echo=true,$end_str=''){
if(defined('CLOSE_ECHO_MSG')){
$echo=false;
}
if($echo){
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数据才能实时显示-->';
}
}
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($allowOutput){
echo str_pad(' ', $outputSize>1050?($outputSize+100):1050);
}
}
echo '<p style="color:'.$color.';">'.$str.'</p>'.$end_str;
ob_flush();
flush();
}
}
/*保留旧的入口*/
public function indexAction(){
if(strtolower(request()->controller())=='base'){
$this->redirect('Admin/Backstage/index');
}
}
}

View File

@ -0,0 +1,120 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
class Collected extends BaseController {
public function listAction(){
$taskName=input('task_name');
$page=input('p/d',1);
$page=max(1,$page);
$mcollected=model('Collected');
$mtask=model('Task');
$cond=array();
$search=array();
$null_task=false;
if(!empty($taskName)){
$search['task_name']=$taskName;
$searchTasks=$mtask->field('`id`,`name`')->where(array('name'=>array('like',"%{$taskName}%")))->column('name','id');
if(!empty($searchTasks)){
$cond['task_id']=array('in',array_keys($searchTasks));
}else{
$null_task=true;
}
}
$search['num']=input('num/d',200);
$search['url']=input('url','','trim');
if(!empty($search['url'])){
$cond['url']=array('like','%'.addslashes($search['url']).'%');
}
$search['release']=input('release');
if(!empty($search['release'])){
$cond['release']=$search['release'];
}
$search['status']=input('status');
if(!empty($search['status'])){
if($search['status']==1){
$cond['target']=array('<>','');
}elseif($search['status']==2){
$cond['error']=array('<>','');
}
}
if(!$null_task){
$count=$mcollected->where($cond)->count();
$limit=$search['num'];
if($count>0){
$dataList=$mcollected->where($cond)->order('id desc')->paginate($limit,false,array('query'=>$search));
$pagenav=$dataList->render();
$this->assign('pagenav',$pagenav);
$dataList=$dataList->all();
$dataList=empty($dataList)?array():$dataList;
$taskIds=array();
foreach ($dataList as $itemK=>$item){
$taskIds[$item['task_id']]=$item['task_id'];
if(preg_match('/^\w+\:\/\//', $item['target'])){
$dataList[$itemK]['target']='<a href="'.$item['target'].'" target="_blank">'.$item['target'].'</a>';
}
}
if(!empty($taskIds)){
$taskList=model('Task')->where(array('id'=>array('in',$taskIds)))->column('name','id');
}
$this->assign('dataList',$dataList);
$this->assign('taskList',$taskList);
}
$GLOBALS['content_header']=lang('collected_list');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Collected/list'),'title'=>lang('collected_list'))));
}
$this->assign('search',$search);
return $this->fetch();
}
/**
* 操作
*/
public function opAction(){
$id=input('id/d',0);
$op=input('op');
$ops=array('item'=>array('delete'),'list'=>array('deleteall'));
if(!in_array($op,$ops['item'])&&!in_array($op,$ops['list'])){
$this->error(lang('invalid_op'));
}
$mcollected=model('Collected');
if(in_array($op,$ops['item'])){
$collectedData=$mcollected->getById($id);
if(empty($collectedData)){
$this->error(lang('empty_data'));
}
}
if($op=='delete'){
$mcollected->where(array('id'=>$id))->delete();
$this->success(lang('delete_success'));
}elseif($op=='deleteall'){
$ids=input('ids/a',0,'intval');
if(is_array($ids)&&count($ids)>0){
$mcollected->where(array('id'=>array('in',$ids)))->delete();
}
$this->success(lang('op_success'),'list');
}
}
}

View File

@ -0,0 +1,182 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
class Collector extends BaseController {
public function indexAction(){
return $this->fetch();
}
public function setAction(){
$taskId=input('task_id/d',0);
$mtask=model('Task');
$mcoll=model('Collector');
$taskData=$mtask->getById($taskId);
if(empty($taskData)){
$this->error(lang('task_error_empty_task'));
}
if(empty($taskData['module'])){
$this->error(lang('task_error_null_module'));
}
if(!in_array($taskData['module'],config('allow_coll_modules'))){
$this->error(lang('coll_error_invalid_module'));
}
$collData=$mcoll->where(array('task_id'=>$taskData['id'],'module'=>$taskData['module']))->find();
if(request()->isPost()){
$effective=input('effective');
if(empty($effective)){
$this->error(lang('coll_error_empty_effective'));
}
$name=trim(input('name'));
$module=trim(input('module'));
$module=strtolower($module);
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);
$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'];
if(empty($collData)){
$collId=$mcoll->add_new($newColl);
}else{
$mcoll->edit_by_id($collId,$newColl);
}
if($collId>0){
$tab_link=trim(input('tab_link'),'#');
$this->success(lang('op_success'),'Collector/set?task_id='.$taskId.($tab_link?'&tab_link='.$tab_link:''));
}else{
$this->error(lang('op_failed'));
}
}else{
if(!empty($collData)){
$collData['config']=unserialize($collData['config']);
}
$GLOBALS['content_header']=lang('coll_set').lang('separator').lang('task_module_'.$taskData['module']);
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Task/edit?id='.$taskData['id']),'title'=>lang('task').lang('separator').$taskData['name']),lang('coll_set')));
$this->assign('collData',$collData);
$this->assign('taskData',$taskData);
return $this->fetch();
}
}
/*列表*/
public function listAction(){
$page=max(1,input('p/d',0));
$module=input('module');
$pageParams=array();
$cond=array();
$taskCond=array();
if(!empty($module)){
$cond=array('module'=>$module);
$pageParams['module']=$module;
}
$mcoll=model('Collector');
$limit=20;
$count=$mcoll->where($cond)->count();
$collList=$mcoll->where($cond)->paginate($limit,false,array('query'=>$pageParams));
$pagenav = $collList->render();
$this->assign('pagenav',$pagenav);
$collList=$collList->all();
$collList=empty($collList)?array():$collList;
if($count>0){
$taskIds=array();
foreach ($collList as $coll){
$taskIds[$coll['task_id']]=$coll['task_id'];
}
if(!empty($taskIds)){
$taskCond['id']=array('in',$taskIds);
$taskNames=model('Task')->where($taskCond)->column('name','id');
$this->assign('taskNames',$taskNames);
}
}
$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);
$mcoll=model('Collector');
$collData=$mcoll->where(array('id'=>$coll_id))->find();
if(empty($collData)){
$this->error(lang('coll_error_empty_coll'));
}
$config=unserialize($collData['config']);
if(empty($config)){
$this->error('规则不存在');
}
$taskData=model('Task')->getById($collData['task_id']);
$name=($collData['name']?$collData['name']:$taskData['name']);
$module=strtolower($collData['module']);
set_time_limit(600);
$collector=array(
'name'=>$name,
'module'=>$module,
'config'=>serialize($config),
);
$txt='/*skycaiji-collector-start*/'.base64_encode(serialize($collector)).'/*skycaiji-collector-end*/';
$name='规则_'.$name;
ob_start();
header("Expires: 0" );
header("Pragma:public" );
header("Cache-Control:must-revalidate,post-check=0,pre-check=0" );
header("Cache-Control:public");
header("Content-Type:application/octet-stream" );
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"');
}else{
header('Content-Disposition: attachment; filename="'.$name.'.skycaiji"');
}
echo $txt;
ob_end_flush();
}
}

View File

@ -0,0 +1,527 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
/*采集器:规则采集*/
class Cpattern extends BaseController {
/**
* 起始页网址
*/
public function sourceAction(){
$is_sub=input('sub');
if(request()->isPost()&&$is_sub){
$source=input('source/a','','trim');
if($source['type']=='custom'){
if(preg_match_all('/^\w+\:\/\/[^\r\n]+/im',$source['urls'],$urls)){
$urls=array_unique($urls[0]);
}else{
$this->error('请输入正确的网址');
}
}elseif($source['type']=='batch'){
if(!preg_match('/^\w+\:\/\/[^\r\n]+$/i',$source['url'])){
$this->error('请输入正确的网址格式');
}
if(stripos($source['url'],cp_sign('match'))===false){
$this->error('请在网址格式中添加 '.cp_sign('match').' 才能批量生成网址!');
}
if(empty($source['param'])){
$this->error('请选择参数类型');
}
$urls=array();
$urlFmt=$source['url'];
if($source['param']=='num'){
$source['param_num_start']=intval($source ['param_num_start']);
$source['param_num_end']=intval($source ['param_num_end']);
$source['param_num_end'] = max ( $source ['param_num_start'], $source ['param_num_end'] );
$source['param_num_inc'] = max ( 1, intval($source ['param_num_inc']));
$source['param_num_desc']=$source['param_num_desc']?1:0;
if($source['param_num_desc']){
for($i=$source['param_num_end'];$i>=$source['param_num_start'];$i--){
$urls[]=str_replace(cp_sign('match'), $source['param_num_start']+($i-$source['param_num_start'])*$source['param_num_inc'], $source['url']);
}
}else{
for($i=$source['param_num_start'];$i<=$source['param_num_end'];$i++){
$urls[]=str_replace(cp_sign('match'), $source['param_num_start']+($i-$source['param_num_start'])*$source['param_num_inc'], $source['url']);
}
}
$urlFmt=str_replace(cp_sign('match'),"{param:num,{$source['param_num_start']}\t{$source['param_num_end']}\t{$source['param_num_inc']}\t{$source['param_num_desc']}}",$urlFmt);
}elseif($source['param']=='letter'){
$letter_start=ord($source['param_letter_start']);
$letter_end=ord($source['param_letter_end']);
$letter_end=max($letter_start,$letter_end);
$source['param_letter_desc']=$source['param_letter_desc']?1:0;
if($source['param_letter_desc']){
for($i=$letter_end;$i>=$letter_start;$i--) {
$urls[]=str_replace(cp_sign('match'), chr($i), $source['url']);
}
}else{
for($i=$letter_start;$i<=$letter_end;$i++) {
$urls[]=str_replace(cp_sign('match'), chr($i), $source['url']);
}
}
$urlFmt=str_replace(cp_sign('match'),"{param:letter,{$source['param_letter_start']}\t{$source['param_letter_end']}\t{$source['param_letter_desc']}}",$urlFmt);
}elseif($source['param']=='custom'){
if(preg_match_all('/[^\r\n]+/', $source['param_custom'],$cusParams)){
$cusParams=array_unique($cusParams[0]);
foreach ($cusParams as $cusParam){
$urls[]=str_replace(cp_sign('match'), $cusParam, $source['url']);
}
$urlFmt=str_replace(cp_sign('match'),"{param:custom,".implode("\t", $cusParams)."}",$urlFmt);
}
}
}elseif($source['type']=='large'){
if(preg_match_all('/^\w+\:\/\/[^\r\n]+/im',$source['large_urls'],$urls)){
$urls=array_unique($urls[0]);
}else{
$this->error('请输入正确的网址');
}
}
if($urls){
$urls=array_values($urls);
$this->success('',null,array('uid'=>$source['uid'],'url'=>$urlFmt,'urls'=>$urls));
}else{
$this->error('未生成网址!');
}
}else{
$url=input('url','','trim');
if($url){
$source['uid']=input('uid','');
if(preg_match('/\{param\:(\w+)\,([^\}]*)\}/i', $url,$param)){
$source['url']= preg_replace('/\{param\:(\w+)\,([^\}]*)\}/i', cp_sign('match'), $url);
$source['type']='batch';
$source['param']=strtolower($param[1]);
$param_val=explode("\t", $param[2]);
if($source['param']=='num'){
$source['param_num_start']=intval($param_val[0]);
$source['param_num_end']=intval($param_val[1]);
$source['param_num_inc']=intval($param_val[2]);
$source['param_num_desc']=intval($param_val[3]);
}elseif($source['param']=='letter'){
$source['param_letter_start']=strtolower($param_val[0]);
$source['param_letter_end']=strtolower($param_val[1]);
$source['param_letter_desc']=intval($param_val[2]);
}elseif($source['param']=='custom'){
$source['param_custom']=implode("\r\n", $param_val);
}
}elseif(preg_match('/[\r\n]/', $url)){
$source['type']='large';
$source['large_urls']=$url;
}else{
$source['type']='custom';
$source['urls']=$url;
}
$this->assign('source',$source);
}
return $this->fetch();
}
}
/**
* 字段
*/
public function fieldAction(){
if(request()->isPost()){
$objid=input('post.objid');
$field=input('post.field/a',null,'trim');
if(empty($field['name'])){
$this->error('请输入字段名称');
}
$this->_check_name($field['name'],'字段名称');
$field['module']=strtolower($field['module']);
switch ($field['module']){
case 'rule':if(empty($field['rule']))$this->error('规则不能为空!');break;
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']);
$field['num_end']=intval($field['num_end']);
$field['num_end'] = max ( $field['num_start'], $field ['num_end'] );
break;
case 'words':if(empty($field['words']))$this->error('固定文字不能为空!');break;
case 'list':if(empty($field['list']))$this->error('随机抽取不能为空!');break;
case 'extract':if(empty($field['extract']))$this->error('请选择字段!');break;
case 'merge':if(empty($field['merge']))$this->error('字段组合不能为空!');break;
}
$modules = array (
'rule' =>array('rule','rule_multi','rule_multi_type','rule_multi_str','rule_merge'),
'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'),
'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'),
'merge' => 'merge'
);
$returnField=array('name'=>$field['name'],'source'=>$field['source'],'module'=>$field['module']);
if(is_array($modules[$field['module']])){
foreach($modules[$field['module']] as $mparam){
$returnField[$mparam]=$field[$mparam];
}
}else{
$returnField[$modules[$field['module']]]=$field[$modules[$field['module']]];
}
$this->success('',null,array('field'=>$returnField,'objid'=>$objid));
}else{
$field=input('field','','url_b64decode');
$objid=input('objid');
$field=$field?json_decode($field,true):array();
$field['time_format']=$field['time_format']?$field['time_format']:'[年]/[月]/[日] [时]:[分]';
$this->assign('field',$field);
$this->assign('objid',$objid);
return $this->fetch();
}
}
/**
* 数据处理
*/
public function processAction(){
$type=input('type');
$this->assign('type',$type);
$op=input('op');
if(empty($type)){
if(empty($op)){
$objid=input('objid');
$process=input('process','','url_b64decode');
$process=$process?json_decode($process,true):'';
$this->assign('objid',$objid);
$this->assign('process',$process);
return $this->fetch();
}elseif($op=='sub'){
$process=input('process/a',null,'trim');
if(empty($process)){
$process='';
}else{
foreach($process as $k=>$v){
if(!empty($v['title'])){
$process[$k]['title']=str_replace(array("'",'"'),'',strip_tags($v['title']));
}
}
}
$objid=input('objid','');
$this->success('',null,array('process'=>$process,'process_json'=>empty($process)?'':json_encode($process),'objid'=>$objid));
}
}elseif('common'==$type){
if(empty($op)){
return $this->fetch();
}elseif($op=='load'){
$process=input('process/a',null,'trim');
$this->assign('process',$process);
return $this->fetch('process_load');
}
}
}
/**
* 内容分页
* 添加分页字段
*/
public function paging_fieldAction(){
if(request()->isPost()){
$objid=input('post.objid');
$pagingField=input('post.paging_field/a',null,'trim');
if(empty($pagingField['field'])){
$this->error('请选择字段');
}
$this->success('',null,array('paging_field'=>$pagingField,'objid'=>$objid));
}else{
$pagingField=input('paging_field','','url_b64decode');
$objid=input('objid');
$pagingField=$pagingField?json_decode($pagingField,true):'';
$this->assign('pagingField',$pagingField);
$this->assign('objid',$objid);
return $this->fetch();
}
}
/*多级网址规则*/
public function level_urlAction(){
if(request()->isPost()){
$objid=input('post.objid');
$level_url=input('post.level_url/a',null,'trim');
if(empty($level_url['name'])){
$this->error('请输入名称');
}
$this->_check_name($level_url['name'],'多级名称');
$this->success('',null,array('level_url'=>$level_url,'objid'=>$objid));
}else{
$level_url=input('level_url','','url_b64decode');
$objid=input('objid');
$level_url=$level_url?json_decode($level_url,true):array();
$this->assign('level_url',$level_url);
$this->assign('objid',$objid);
return $this->fetch();
}
}
/*关联网址规则*/
public function relation_urlAction(){
if(request()->isPost()){
$objid=input('post.objid');
$relation_url=input('post.relation_url/a',null,'trim');
if(empty($relation_url['name'])){
$this->error('请输入名称');
}
$this->_check_name($relation_url['name'],'关联页名称');
if(empty($relation_url['url_rule'])){
$this->error('请输入提取网址规则');
}
$this->success('',null,array('relation_url'=>$relation_url,'objid'=>$objid));
}else{
$relation_url=input('relation_url','','url_b64decode');
$objid=input('objid');
$relation_url=$relation_url?json_decode($relation_url,true):array();
$this->assign('relation_url',$relation_url);
$this->assign('objid',$objid);
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['config']);
if('source_urls'==$op){
$source_urls=array();
foreach ( $eCpattern->config ['source_url'] as $k => $v ) {
if(empty($v)){
continue;
}
$urls = $eCpattern->convert_source_url ( $v );
if (is_array ( $urls )) {
$source_urls = array_merge ( $source_urls, $urls );
} else {
$source_urls [] = $urls;
}
}
$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->get_level_urls($source_url,$curLevel);
$eCpattern->success('',null,array('urls'=>$levelData['urls'],'levelName'=>$levelData['levelName'],'nextLevel'=>$levelData['nextLevel']));
}elseif('cont_url'==$op){
$GLOBALS['content_header']='测试抓取';
$GLOBALS['breadcrumb']=breadcrumb('测试抓取');
$cont_url=input('cont_url','','trim');
$test=input('test');
$url_post=$eCpattern->config['url_post'];
$eCpattern->assign('cont_url',$cont_url);
$eCpattern->assign('url_post',$url_post);
$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){
$val_list=$eCpattern->getFields($cont_url);
if(empty($eCpattern->first_loop_field)){
$val_list=array($val_list);
}
foreach ($val_list as $v_k=>$vals){
foreach ($vals as $k=>$v){
$vals[$k]=$v['value'];
}
$val_list[$v_k]=$vals;
}
$eCpattern->success('',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['content_header']='模拟匹配';
$GLOBALS['breadcrumb']=breadcrumb('模拟匹配');
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), $content);
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){
ob_clean();
header("Content-type:text/html;charset=utf-8");
$cont_url=input('cont_url','','trim');
if(!preg_match('/^\w+\:\/\//',$cont_url)){
$cont_url='http://'.$cont_url;
}
$html=$eCpattern->get_html($cont_url,false,$eCpattern->config['url_post']);
$html=preg_replace('/<script[^<>]*?>[\s\S]*?<\/script>/i', '', $html);
$html=preg_replace('/<meta[^<>]*charset[^<>]*?>/i', '', $html);
$publicUrl=config('root_website').'/public';
$jscss="\r\n<!-- 以下为蓝天采集器代码 -->\r\n".'<script src="%s/jquery/jquery.min.js?%s"></script>'
."\r\n".'<script src="%s/static/js/admin/cpattern_elements.js?%s"></script>'
."\r\n".'<link rel="stylesheet" href="%s/static/css/cpattern_elements.css?%s">';
$jscss=sprintf($jscss,$publicUrl,config('html_v'),$publicUrl,config('html_v'),$publicUrl,config('html_v'));
$html.=$jscss;
exit($html);
}
}
/*名称命名规范*/
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;
}
}
}

View File

@ -0,0 +1,372 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
use plugin;
class Develop extends BaseController {
public static $typeList = array (
'number' => '数字(number)',
'text' => '字符(text)',
'radio' => '开关(radio)',
'textarea' => '文本(textarea)',
'select_coll' => '选择采集字段(select)',
'select_val' => '选择固定值(select)',
'select_func' => '选择函数返回值(select)'
);
public function releaseCmsAction(){
$mapp=model('ReleaseApp');
if(request()->isPost()){
$is_edit=input('edit');
$name=input('name');
if(empty($name)){
$this->error('请输入发布插件名称');
}
if(!$is_edit){
$cms_name=input('cms_name');
$cms_name_custom=input('cms_name_custom');
$identifier=input('identifier');
$copyright=input('copyright');
if(empty($cms_name)){
$this->error('请选择CMS程序');
}elseif($cms_name=='custom'){
if(empty($cms_name_custom)){
$this->error('请输入CMS程序名');
}else{
$cms_name=$cms_name_custom;
}
}
if(!preg_match('/^[a-z][a-z0-9]*$/i', $cms_name)){
$this->error('cms程序名必须由字母或数字组成且首位不能为数字');
}
if(empty($identifier)){
$this->error('请输入插件功能标识');
}elseif(!preg_match('/^[a-z][a-z0-9]*$/i', $identifier)){
$this->error('插件功能标识必须由字母或数字组成且首位不能为数字!');
}
if(empty($copyright)){
$this->error('请输入作者版权');
}elseif(!preg_match('/^[a-z][a-z0-9]*$/i', $copyright)){
$this->error('作者版权必须由字母或数字组成且首位不能为数字!');
}
$appName=ucfirst(strtolower($cms_name)).ucfirst(strtolower($identifier)).ucfirst(strtolower($copyright));
}else{
$appName=ucfirst(input('app'));
}
$params=input('params/a');
if(empty($params)||!is_array($params)){
$this->error('请添加参数');
}
foreach ($params as $k=>$v){
$params[$k]=json_decode(url_b64decode($v),true);
}
$this->create_cms_app(array('name'=>$name,'app'=>$appName), $params,$is_edit);
}else{
$appName=input('app');
$appName=ucfirst($appName);
$config=array();
if($appName){
$cmsData=$mapp->where(array('module'=>'cms','app'=>$appName))->find();
if(!empty($cmsData)){
$config['name']=$cmsData['name'];
$config['app']=$appName;
if(preg_match('/^([A-Z][a-z0-9]*)([A-Z][a-z0-9]*)([A-Z][a-z0-9]*)$/', $appName,$appInfo)){
$config['is_edit']=true;
$config['cms_name']=strtolower($appInfo[1]);
$config['identifier']=strtolower($appInfo[2]);
$config['copyright']=strtolower($appInfo[3]);
$config['app_file']=realpath($mapp->appFileName($appName,'cms'));
}
$config['params']=array();
$cmsClass=null;
$is_old_plugin=false;
try {
if($mapp->appFileExists($appName,'cms')){
$cmsClass=$mapp->appImportClass($appName,'cms');
}elseif($mapp->oldFileExists($appName,'cms')){
$is_old_plugin=true;
$cmsClass=$mapp->oldImportClass($appName,'cms');
}
}catch (\Exception $ex){
$cmsClass=null;
$this->error($ex->getMessage());
}
if(is_array($cmsClass->_params)){
foreach ($cmsClass->_params as $k=>$v){
$param=array(
'key'=>$k,
'require'=>intval($v['require']),
'name'=>$v['name'],
);
if($v['tag']=='select'){
if(is_array($v['option'])){
$param['type']='select_val';
$param['select_val']='';
foreach ($v['option'] as $vk=>$vv){
$param['select_val'].=$vk.'='.$vv."\r\n";
}
}elseif($v['option']=='function:param_option_fields'){
$param['type']='select_coll';
}elseif(preg_match('/^function:(.+)$/', $v['option'],$select_func)){
$param['type']='select_func';
$param['select_func']=$select_func[1];
}
}else{
$param['type']=$v['tag'];
}
$param['type_name']=self::$typeList[$param['type']];
$config['params'][]=$param;
}
}
}
}
$GLOBALS['content_header']='开发CMS发布插件 <small><a href="http://www.skycaiji.com/manual/doc/cms" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>';
$GLOBALS['breadcrumb']=breadcrumb(array('开发工具','开发CMS发布插件'));
$this->assign('config',$config);
$this->assign('is_old_plugin',$is_old_plugin);
return $this->fetch('releaseCms');
}
}
/*添加参数*/
public function cmsAddParamAction(){
if(request()->isPost()){
$param=input('param/a');
$param=array_array_map('trim', $param);
if(empty($param['key'])){
$this->error('请输入变量名');
}
if(!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/',$param['key'])){
$this->error('变量名必须符合php命名规范');
}
if(empty($param['name'])){
$this->error('请输入参数名称');
}
if(empty($param['type'])){
$this->error('请选择参数类型');
}
if($param['type']=='select_func'){
if(!preg_match('/^param_option_[a-zA-Z0-9_]+$/', $param['select_func'])){
$this->error('函数名必须以param_option_开头且符合命名规范');
}
}elseif($param['type']=='select_val'){
if(empty($param['select_val'])){
$this->error('请输入选项值');
}
}
$param['param_json']=json_encode($param);
$param['type_name']=self::$typeList[$param['type']];
$this->success('',null,$param);
}else{
$objid=input('objid');
$param=input('param','','url_b64decode');
$param=$param?json_decode($param,true):'';
$this->assign('objid',$objid);
$this->assign('param',$param);
$this->assign('typeList',self::$typeList);
return $this->fetch('cmsAddParam');
}
}
/*创建cms发布插件*/
public function create_cms_app($appData,$params,$is_edit=false){
if(!preg_match('/^[a-z][a-z0-9]*$/i', $appData['app'])){
$this->error('插件名错误!');
}
$appData['app']=ucfirst($appData['app']);
$mapp=model('ReleaseApp');
$cmsData=$mapp->where(array('module'=>'cms','app'=>$appData['app']))->find();
if(!$is_edit&&!empty($cmsData)){
$this->error('抱歉,已存在'.$appData['app'].'插件');
}
$_params=array();
$newFuncs=array();
$params=empty($params)?array():$params;
foreach ($params as $k=>$v){
$pkey=$v['key'];
$_params[$pkey]=array(
'name' => $v['name'],
'require'=>intval($v['require'])
);
$v['type']=strtolower($v['type']);
if(strpos($v['type'], 'select_')===0){
$_params[$pkey]['tag']='select';
}else{
$_params[$pkey]['tag']=$v['type'];
}
if($v['type']=='select_coll'){
$_params[$pkey]['option']='function:param_option_fields';
}elseif($v['type']=='select_func'){
$_params[$pkey]['option']='function:'.$v['select_func'];
$newFuncs[$v['select_func']]=$v['select_func'];
}elseif($v['type']=='select_val'){
if(preg_match_all('/[^\r\n]+/', $v['select_val'],$select_val)){
$_params[$pkey]['option']=array();
foreach ($select_val[0] as $slv){
if(strpos($slv,'=')!==false){
list($slv_k,$slv_v)=explode('=', $slv);
if(is_null($slv_k)){
$slv_k=$slv_v;
}
$_params[$pkey]['option'][$slv_k]=$slv_v;
}else{
$_params[$pkey]['option'][$slv]=$slv;
}
}
}
}
}
$cmsClass=null;
$is_old_plugin=false;
try {
if($mapp->appFileExists($appData['app'],'cms')){
$cmsClass=$mapp->appImportClass($appData['app'],'cms');
}elseif($mapp->oldFileExists($appData['app'],'cms')){
$is_old_plugin=true;
$cmsClass=$mapp->oldImportClass($appData['app'],'cms');
}
}catch (\Exception $ex){
$cmsClass=null;
$this->error($ex->getMessage());
}
$existsFuncs=array();
if(!empty($cmsClass)){
$existsFuncs=get_class_methods($cmsClass);
}
$_params=var_export($_params,true);
$_params=preg_replace_callback('/^\s*/m', function($matches){
$returnStr="\t";
for($i=0;$i<(strlen($matches[0])/2);$i++){
$returnStr.="\t";
}
return $returnStr;
}, $_params);
$_params=preg_replace('/\s+array\s*\(/i', ' array (', $_params);
$funcPhp='';
foreach ($newFuncs as $v){
if(!in_array($v,$existsFuncs)){
$funcPhp.="\r\n\tpublic function {$v}(){\r\n\t\t/*必须返回键值对数组*/\r\n\t\treturn array();\r\n\t}";
}
}
if(empty($cmsClass)){
$phpCode=<<<EOF
<?php
namespace plugin\\release\\cms;
class {$appData['app']} extends BaseCms{
/*参数*/
public \$_params ={$_params};
{$funcPhp}
/*导入数据*/
public function runImport(\$params){
/*
* -----这里开始写代码-----
* 数据库操作:\$this->db()可参考thinkphp5的数据库操作
* 参数值列表:\$params\$params[变量名] 调用参数的值
*/
/*
* 必须以数组形式返回:
* id必填表示入库返回的自增id或状态
* target可选记录入库的数据位置发布的网址等
* desc可选记录入库的数据位置附加信息
* error可选记录入库失败的错误信息
* 入库的信息可在“已采集数据”中查看
*/
return array('id'=>0,'target'=>'','desc'=>'','error'=>'');
}
}
?>
EOF;
}else{
$phpCode=null;
if($is_old_plugin){
$phpCode=$mapp->oldFileCode($appData['app'],'cms');
$phpCode=preg_replace('/\bthinkphp\s*\d+(\.\d+){0,1}/i', 'thinkphp5', $phpCode);
$phpCode=preg_replace('/\bnamespace\s+Release\\\Cms\;/i', 'namespace plugin\\release\\cms;', $phpCode);
$phpCode=preg_replace('/\bclass\s+(\w+)Cms\s+extends\s+BaseCms\b/i', "class \\1 extends BaseCms", $phpCode);
}else{
$phpCode=file_get_contents($mapp->appFileName($appData['app'],'cms'));
}
$phpCode=preg_replace('/public\s*\$_params\s*\=[\s\S]+?\)\s*;/i', 'public $_params ='.$_params.';', $phpCode);
if(!empty($funcPhp)){
if(preg_match('/namespace[^\r\n]+?\{/', $phpCode)){
$phpCode=preg_replace('/\}\s*\}\s*\?\>/',"\r\n".$funcPhp."\t\r\n}\r\n}\r\n?>",$phpCode);
}else{
$phpCode=preg_replace('/\}\s*\?\>/',"\r\n".$funcPhp."\r\n}\r\n?>",$phpCode);
}
}
}
if(!empty($phpCode)){
$success=$mapp->addCms(array('app'=>$appData['app'],'name'=>$appData['name']),$phpCode);
if($success){
$this->success('创建成功','Develop/releaseCms?app='.$appData['app']);
}else{
$this->error('创建失败');
}
}else{
$this->error('代码错误');
}
}
}

View File

@ -0,0 +1,361 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
use skycaiji\admin\model\User;
use skycaiji\admin\model\CacheModel;
class Index extends BaseController{
public function indexAction(){
return $this->fetch();
}
/*后台运行采集,会无限运行下去*/
public function backstageAction(){
if(empty($GLOBALS['config']['caiji']['auto'])){
$this->error('请先开启自动采集');
}
if(!input('?autorun')){
$this->error('参数错误');
}
$runtime=input('runtime/d');
if(empty($runtime)){
$runtime=time();
cache('caiji_auto_backstage_runtime',$runtime);
}else{
$cahce_runtime=cache('caiji_auto_backstage_runtime');
$cahce_runtime=intval($cahce_runtime);
if($runtime<$cahce_runtime){
$this->error('终止旧进程');
}
}
ignore_user_abort(true);
set_time_limit(0);
$mconfig=new \skycaiji\admin\model\Config();
$caijiConfig=$mconfig->where('cname','caiji')->find();
$caijiConfig=$mconfig->convertData($caijiConfig);
if(empty($caijiConfig['data']['auto'])||$caijiConfig['data']['run']!='backstage'){
$this->error('自动采集已停止');
}
$collectTime1=time();
try{
@get_html(url('Admin/Api/collect',null,false,true));
}catch(\Exception $ex){
}
$collectTime2=time();
$minWaitTime=60;
$waitTime=0;
if($GLOBALS['config']['caiji']['interval']>0){
$waitTime=60*$GLOBALS['config']['caiji']['interval']-($collectTime2-$collectTime1);
}
$waitTime=$waitTime>$minWaitTime?$waitTime:$minWaitTime;
sleep($waitTime);
sleep(10);
if($GLOBALS['config']['caiji']['auto']){
try{
@get_html(url('Admin/Index/backstage',array('autorun'=>1,'runtime'=>$runtime),false,true),null,array('timeout'=>5));
}catch(\Exception $ex){
}
}
exit();
}
/*访问执行采集*/
public function caijiAction(){
@get_html(url('Admin/Api/collect',null,false,true),null,array('timeout'=>1));
$waitTime=$GLOBALS['config']['caiji']['interval']*60;
$waitTime=$waitTime>0?$waitTime:3;
$this->success('正在采集...','Admin/Index/caiji',null,$waitTime);
}
/*任务api发布*/
public function apiTaskAction(){
controller('admin/Api','controller')->taskAction();
}
public function loginAction(){
if(request()->isPost()){
if(!check_usertoken()){
$this->error(lang('usertoken_error'));
}
$mcacheLogin=CacheModel::getInstance('login');
$config_login=$GLOBALS['config']['site']['login'];
$clientIpMd5=md5(request()->ip());
if(!empty($config_login['limit'])){
$ipLoginData=$mcacheLogin->getCache($clientIpMd5,'data');
if((NOW_TIME-$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')));
$pwd=trim(input('post.password'));
if($GLOBALS['config']['site']['verifycode']){
$verifycode=trim(input('post.verifycode'));
$check=check_verify($verifycode);
if(!$check['success']){
$this->error($check['msg']);
}
}
$check=User::right_username($username);
if(!$check['success']){
$this->error($check['msg']);
}
$check=User::right_pwd($pwd);
if(!$check['success']){
$this->error($check['msg']);
}
$muser=new \skycaiji\admin\model\User();
$userData=$muser->where('username',$username)->find();
if(empty($userData)||$userData['password']!=pwd_encrypt($pwd)){
if(!empty($config_login['limit'])){
$ipLoginData=$mcacheLogin->getCache($clientIpMd5,'data');
if(!empty($ipLoginData)){
if((NOW_TIME-$ipLoginData['lastdate'])<($config_login['time']*3600)){
$ipLoginData['failed']++;
}else{
$ipLoginData['lastdate']=NOW_TIME;
$ipLoginData['failed']=1;
}
}else{
$ipLoginData['lastdate']=NOW_TIME;
$ipLoginData['failed']=1;
}
$ipLoginData['ip']=request()->ip();
$mcacheLogin->setCache($clientIpMd5, $ipLoginData);
$this->error(lang('user_error_login')."失败{$config_login['failed']}次将被锁定{$config_login['time']}小时,已失败{$ipLoginData['failed']}");
}
$this->error(lang('user_error_login'));
}
if(input('post.auto')){
cookie('login_history',$username.'|'.md5($username.$userData['password']),array('expire'=>3600*24*15));
}
session('user_id',$userData['uid']);
$serverinfo=input('serverinfo');
if(empty($serverinfo)){
$this->success(lang('user_login_in'),'Admin/Backstage/index');
}else{
$this->success(lang('user_login_in'),null,array('js'=>'window.parent.postMessage("login_success","http://www.skycaiji.com");'));
}
}else{
$this->error(lang('user_error_sublogin'));
}
}else{
return $this->fetch('index');
}
}
/*退出*/
public function logoutAction(){
\think\Cookie::delete('login_history');
unset($GLOBALS['user']);
session('user_id',null);
$this->success(lang('op_success'),'Admin/Index/index');
}
/*验证码*/
public function verifyAction(){
$config=array(
'fontSize'=>30,
'length'=>3,
'fontttf'=>'5.ttf',
'useCurve'=>true,
'useNoise'=>true
);
ob_clean();
$captcha = new \think\captcha\Captcha($config);
return $captcha->entry();
}
/*找回密码*/
public function find_passwordAction(){
$username=trim(input('post.username'));
if(empty($username)){
$username=trim(input('username'));
$username=base64_decode($username);
}
$step=max(1,input('step/d',1));
$stepSname='find_password_step.'.md5($username);
$stepSession=session($stepSname);
$muser=model('User');
if($step>1){
if(strcasecmp(('step'.$step),$stepSession['step'])!==0){
$this->error(lang('find_pwd_error_step'),'Index/find_password');
}
if(empty($stepSession['user'])){
$this->error(lang('find_pwd_error_none_user'));
}
}
if(request()->isPost()){
if(input('post.subForPwd')){
if(empty($username)){
$this->error(lang('find_pwd_error_username'));
}
if($step===1){
if(!check_usertoken()){
$this->error(lang('usertoken_error'));
}
if($GLOBALS['config']['site']['verifycode']){
$verifycode=trim(input('verifycode'));
$check=check_verify($verifycode);
if(!$check['success']){
$this->error($check['msg']);
}
}
/*获取用户信息*/
$username_is_email=false;
$check=\skycaiji\admin\model\User::right_email($username);
if($check['success']){
$username_is_email=true;
}
if($username_is_email){
$emailCount=$muser->where(array('email'=>$username))->count();
if($emailCount<=0){
$this->error(lang('find_pwd_error_none_email'));
}elseif($emailCount>1){
$this->error(lang('find_pwd_error_multiple_emails'));
}else{
$userData=$muser->where(array('email'=>$username))->find();
}
}else{
$userData=$muser->where(array('username'=>$username))->find();
}
if(empty($userData)){
$this->error(lang('find_pwd_error_none_user'));
}
$userData=$userData->toArray();
session($stepSname,array('step'=>'step2','user'=>$userData));
$this->success(lang('redirecting'),'Index/find_password?step=2&username='.rawurlencode(base64_encode($username)));
}elseif($step===2){
$yzm=trim(input('yzm'));
$check=\skycaiji\admin\model\User::right_yzm($username, $yzm);
if(!$check['success']){
$this->error($check['msg']);
}
$stepSession['step']='step3';
session($stepSname,$stepSession);
$this->success(lang('redirecting'),'Index/find_password?step=3&username='.rawurlencode(base64_encode($username)));
}elseif($step===3){
$pwd=trim(input('password'));
$repwd=trim(input('repassword'));
$check=\skycaiji\admin\model\User::right_pwd($pwd);
if(!$check['success']){
$this->error($check['msg']);
}
$check=\skycaiji\admin\model\User::right_repwd($pwd,$repwd);
if(!$check['success']){
$this->error($check['msg']);
}
$muser->save(array('password'=>pwd_encrypt($pwd)),array('username'=>$stepSession['user']['username']));
session($stepSname,null);
$this->success(lang('find_pwd_success'),'Admin/Index/index');
}else{
$this->error(lang('find_pwd_error_step'),'Index/find_password');
}
}else{
$this->error(lang('find_pwd_error_post'));
}
}else{
if($step===2){
$emailStatus=array('success'=>false,'msg'=>'');
if(empty($GLOBALS['config']['email'])){
$emailStatus['msg']=lang('config_error_none_email');
}else{
$waitTime=60;
$waitSname='send_yzm_wait';
$passTime=abs(NOW_TIME-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['config']['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));
$emailStatus['success']=true;
$emailStatus['msg']=lang('find_pwd_sended',array('email'=>preg_replace('/.{2}\@/', '**@', $stepSession['user']['email'])));
}else{
$emailStatus['msg']=lang('find_pwd_email_failed').'<br>'.$mailReturn;
}
}
}
$this->assign('emailStatus',$emailStatus);
}
$this->assign('userData',$stepSession['user']);
$this->assign('username',$username);
$this->assign('step',$step);
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

@ -0,0 +1,196 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
class Mystore extends BaseController {
public function indexAction(){
$this->redirect('Mystore/collect');
}
public function collectAction(){
$mrule=model('Rule');
$type='collect';
$module=input('module');
$page=max(1,input('p/d',0));
$pageParams=array();
$pageParams['type']=$type;
$cond=array('type'=>$type);
if(!empty($module)){
$cond=array('module'=>$module);
$pageParams['module']=$module;
}
$sortBy=input('sort','desc');
$sortBy=($sortBy=='asc')?'asc':'desc';
$orderKey=input('order');
$this->assign('sortBy',$sortBy);
$this->assign('orderKey',$orderKey);
$orderBy=!empty($orderKey)?($orderKey.' '.$sortBy):'id desc';
$limit=20;
$count=$mrule->where($cond)->count();
$ruleList=$mrule->where($cond)->order($orderBy)->paginate($limit,false,array('query'=>$pageParams));
$pagenav = $ruleList->render();
$this->assign('pagenav',$pagenav);
$ruleList=$ruleList->all();
$GLOBALS['content_header']='已下载';
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Mystore/index'),'title'=>'已下载'),lang('rule_'.$type)));
$this->assign('ruleList',$ruleList);
$tpl=input('tpl');
$tpl='rules'.(!empty($tpl)?('_'.$tpl):'');
return $this->fetch($tpl);
}
public function ruleOpAction(){
$id=input('id/d',0);
$op=input('op');
$ops=array('item'=>array('delete'),'list'=>array('deleteall','check_store_update'));
if(!in_array($op,$ops['item'])&&!in_array($op,$ops['list'])){
$this->error(lang('invalid_op'));
}
$mrule=model('Rule');
if($op=='delete'){
$mrule->where(array('id'=>$id))->delete();
$this->success(lang('delete_success'));
}elseif($op=='deleteall'){
$ids=input('ids/a');
if(is_array($ids)&&count($ids)>0){
$mrule->where(array('id'=>array('in',$ids)))->delete();
}
$this->success(lang('op_success'),'Mystore/collect');
}elseif($op=='check_store_update'){
$ids=input('ids/a');
if(!empty($ids)){
$ruleList=model('Rule')->where(array('id'=>array('in',$ids)))->column('*','store_id');
}else{
$ruleList=array();
}
$uptimeList=array();
if(!empty($ruleList)){
$storeIds=implode(',', array_keys($ruleList));
$uptimeList=get_html('http://www.skycaiji.com/Store/Client/collectUpdate?ids='.rawurlencode($storeIds));
$uptimeList=json_decode($uptimeList,true);
}
if(!empty($uptimeList)){
$updateList=array();
foreach ($uptimeList as $storeId=>$storeUptime){
if($storeUptime>0&&$storeUptime>$ruleList[$storeId]['uptime']){
$updateList[]=$ruleList[$storeId]['id'];
}
}
$this->success('',null,$updateList);
}else{
$this->error();
}
}
}
public function releaseAppAction(){
$page=max(1,input('p/d',0));
$pageParams=array();
$cond=array();
$sortBy=input('sort','desc');
$sortBy=($sortBy=='asc')?'asc':'desc';
$orderKey=input('order');
$this->assign('sortBy',$sortBy);
$this->assign('orderKey',$orderKey);
$orderBy=!empty($orderKey)?($orderKey.' '.$sortBy):'id desc';
$mapp=model('ReleaseApp');
$limit=20;
$count=$mapp->where($cond)->count();
$appList=$mapp->where($cond)->order($orderBy)->paginate($limit,false,array('query'=>$pageParams));
$pagenav = $appList->render();
$this->assign('pagenav',$pagenav);
$appList=$appList->all();
$GLOBALS['content_header']='已下载';
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Mystore/index'),'title'=>'已下载'),'发布插件'));
$this->assign('appList',$appList);
return $this->fetch('releaseApp');
}
public function releaseAppOpAction(){
$id=input('id/d',0);
$op=input('op');
$ops=array('item'=>array('delete'),'list'=>array('deleteall','check_store_update'));
if(!in_array($op,$ops['item'])&&!in_array($op,$ops['list'])){
$this->error(lang('invalid_op'));
}
$mapp=model('ReleaseApp');
if($op=='delete'){
$mapp->where(array('id'=>$id))->delete();
$this->success(lang('delete_success'));
}elseif($op=='deleteall'){
$ids=input('ids/a');
if(is_array($ids)&&count($ids)>0){
$mapp->where(array('id'=>array('in',$ids)))->delete();
}
$this->success(lang('op_success'),'Mystore/ReleaseApp');
}elseif($op=='check_store_update'){
$ids=input('ids/a');
$appList=model('ReleaseApp')->where(array('module'=>'cms','id'=>array('in',$ids)))->column('*','app');
$uptimeList=array();
if(!empty($appList)){
$apps=implode(',', array_keys($appList));
$uptimeList=get_html('http://www.skycaiji.com/Store/Client/cmsUpdate?apps='.rawurlencode($apps));
$uptimeList=json_decode($uptimeList,true);
}
if(!empty($uptimeList)){
$updateList=array();
foreach ($uptimeList as $app=>$storeUptime){
if($storeUptime>0&&$storeUptime>$appList[$app]['uptime']){
$updateList[]=$appList[$app]['id'];
}
}
$this->success('',null,$updateList);
}else{
$this->error();
}
}
}
}

View File

@ -0,0 +1,422 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
use skycaiji\admin\model\DbCommon;
class Release extends BaseController{
/*发布设置*/
public function setAction(){
$taskId=input('task_id/d',0);
$releaseId=input('release_id/d',0);
$mtask=model('Task');
$mrele=model('Release');
$taskData=$mtask->getById($taskId);
if(empty($taskData)){
$this->error(lang('task_error_empty_task'));
}
$releData=$mrele->where(array('task_id'=>$taskData['id']))->find();
if(request()->isPost()){
$newData=array('task_id'=>$taskData['id'],'addtime'=>NOW_TIME,'config'=>array());
if($releaseId>0){
$importRele=$mrele->where(array('id'=>$releaseId))->find();
$newData['module']=$importRele['module'];
$newData['config']=$importRele['config'];
}else{
$newData['module']=input('module','','strtolower');
if(empty($newData['module'])){
$this->error(lang('rele_error_null_module'));
}
$releObj=controller('admin/R'.$newData['module'],'event');
$newData['config']=$releObj->setConfig($newData['config']);
$newData['config']=serialize($newData['config']);
}
if(empty($newData['module'])){
$this->error(lang('rele_error_null_module'));
}
if(empty($releData)){
$mrele->allowField(true)->save($newData);
$releId=$mrele->id;
}else{
$releId=$releData['id'];
$mrele->allowField(true)->save($newData,array('id'=>$releData['id']));
}
if($releId>0){
$this->success(lang('op_success'),'Release/set?task_id='.$taskId);
}else{
$this->error(lang('op_failed'));
}
}else{
$GLOBALS['content_header']=lang('rele_set');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Task/edit?id='.$taskData['id']),'title'=>lang('task').lang('separator').$taskData['name']),lang('rele_set')));
$this->assign('taskData',$taskData);
if(!empty($releData)){
$releData['config']=unserialize($releData['config']);
$config=$releData['config'];
$this->assign('config',$config);
$this->assign('releData',$releData);
}
$apiRootUrl=config('root_website');
if(stripos(\think\Request::instance()->root(),'/index.php?s=')!==false){
$apiRootUrl.='/index.php?s=';
}elseif(stripos(\think\Request::instance()->root(),'/index.php')!==false){
$apiRootUrl.='/index.php';
}
$releBase=new \skycaiji\admin\event\ReleaseBase();
$collFields=$releBase->get_coll_fields($taskData['id'],$taskData['module']);
$this->assign('apiRootUrl',$apiRootUrl);
$this->assign('collFields',$collFields);
return $this->fetch();
}
}
/*导入配置*/
public function importAction(){
$page=max(1,input('p/d',0));
$mrele=model('Release');
$mtask=model('Task');
$limit=10;
$cond=array();
$taskCond=array();
$count=$mrele->where($cond)->count();
$releList=$mrele->where($cond)->order('id desc')->paginate($limit);
$pagenav = $releList->render();
$this->assign('pagenav',$pagenav);
$releList=$releList->all();
$releList=empty($releList)?array():$releList;
if($count>0){
$taskIds=array();
foreach ($releList as $rele){
$taskIds[$rele['task_id']]=$rele['task_id'];
}
if(!empty($taskIds)){
$taskCond['id']=array('in',$taskIds);
$taskNames=$mtask->where($taskCond)->column('name','id');
$this->assign('taskNames',$taskNames);
}
}
$this->assign('releList',$releList);
return $this->fetch();
}
/*检测cms信息*/
public function cmsDetectAction(){
$acms=controller('admin/Rcms','event');
$acms->cms_name_list(config('root_path'));
$acms->cms_name_list(config('root_path').'/../');
$prevPath=config('root_path').'/../';
if(is_dir($prevPath)){
$dp=dir($prevPath);
while(($curPath=$dp->read())!=false){
if($curPath!='.'&&$curPath!='..'){
$curPath=$prevPath.$curPath;
if(is_dir($curPath)){
$acms->cms_name_list($curPath);
}
}
}
$dp->close();
}
$nextPath=config('root_path').'/';
if(is_dir($nextPath)){
$dp=dir($nextPath);
while(($curPath=$dp->read())!=false){
if($curPath!='.'&&$curPath!='..'){
$curPath=$nextPath.$curPath;
if(is_dir($curPath)){
$acms->cms_name_list($curPath);
}
}
}
$dp->close();
}
$cmsList=$acms->cms_name_list(null,true);
if(!empty($cmsList)){
$this->success('',null,$cmsList);
}else{
$this->error(lang('rele_error_detect_null'));
}
}
/*
* cms程序绑定数据
* 设置可不先入库进行测试绑定
* */
public function cmsBindAction(){
$cmsSet=input('cms/a');
$taskId=input('task_id/d',0);
$cmsPath=$cmsSet['path'];
if(empty($cmsPath)){
$this->error('cms路径不能为空');
}
$acms=controller('admin/Rcms','event');
$cmsName=$acms->cms_name($cmsPath);
if(empty($cmsName)){
$this->error('未知的cms程序请确保路径存在如需指定CMS程序请在路径结尾加上@CMS程序名例如@discuz');
}
$cmsApp=$cmsSet['app'];
$cmsApps=model('ReleaseApp')->where(array('module'=>'cms','app'=>array('like',addslashes($cmsName).'%')))->order('uptime desc')->column('*');
$cmsApps=is_array($cmsApps)?$cmsApps:array();
if(!empty($cmsApps)){
$cmsApps=array_values($cmsApps);
}
if(!empty($cmsApp)){
$cmsApp=ucfirst($cmsApp);
if(!model('ReleaseApp')->appFileExists($cmsApp,'cms')){
if(model('ReleaseApp')->oldFileExists($cmsApp,'Cms')){
$cmsError=lang('release_upgrade');
}else{
$cmsError='抱歉,插件文件不存在';
}
$this->assign('cmsError',$cmsError);
}else{
try {
$releCms=model('ReleaseApp')->appImportClass($cmsApp,'cms');
$releCms->init($cmsPath,array('task_id'=>$taskId));
$releCms->runBind();
} catch (\Exception $ex) {
$releCms=null;
$this->error($ex->getMessage());
}
$this->assign('releCms',$releCms);
}
}
$this->assign('cmsName',$cmsName);
$this->assign('cmsApps',$cmsApps);
$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['config']);
$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);
}
}
/*读取数据库表*/
public function dbTablesAction(){
$releId=input('id/d',0);
$mrele=model('Release');
$releData=$mrele->where(array('id'=>$releId))->find();
if(empty($releData)){
$this->error(lang('rele_error_empty_rele'));
}
$config=unserialize($releData['config']);
$db_config=controller('admin/Rdb','event')->get_db_config($config['db']);
try{
$mdb=new DbCommon($db_config);
$tables=$mdb->getTables();
}catch(\Exception $ex){
$msg=$this->trans_db_msg($ex->getMessage());
$this->error($msg);
}
$this->assign('tables',$tables);
$html=$this->fetch('dbTables');
$this->success($html->getContent());
}
/*测试连接数据库*/
public function dbConnectAction(){
$op=input('op');
$db=input('db/a','','trim');
$no_check=array('db_pwd');
if('db_names'==$op){
$no_check[]='db_name';
unset($db['name']);
}
$db_config=controller('admin/Rdb','event')->get_db_config($db);
foreach ($db_config as $k=>$v){
if(empty($v)&&!in_array($k,$no_check)){
$this->error(lang('error_null_input',array('str'=>lang('rele_'.$k))));
}
}
$msgError=false;
$msgSuccess=false;
try{
$mdb=new DbCommon($db_config);
if(!$mdb->db()){
$msgError='数据库连接错误';
}else{
if('db_names'==$op){
$dbNames=array();
if($db_config['db_type']=='mysql'){
$dbsData=$mdb->db()->query('show databases');
foreach ($dbsData as $dbDt){
$dbNames[$dbDt['Database']]=$dbDt['Database'];
}
}elseif($db_config['db_type']=='oracle'){
$dbsData=$mdb->db()->query('SELECT * FROM v$database');
foreach ($dbsData as $dbDt){
$dbNames[$dbDt['NAME']]=$dbDt['NAME'];
}
}elseif($db_config['db_type']=='sqlsrv'){
$dbsData=$mdb->db()->query('select * from sysdatabases');
foreach ($dbsData as $dbDt){
$dbNames[$dbDt['name']]=$dbDt['name'];
}
}
if(empty($dbNames)){
$msgError='没有数据库';
}else{
sort($dbNames);
$this->assign('dbNames',$dbNames);
$html=$this->fetch('release/dbNames');
$msgSuccess=$html->getContent();
}
}else{
$dbTables=$mdb->getTables();
$msgSuccess=lang('rele_success_db_ok');
}
}
}catch(\Exception $ex){
$msg=$this->trans_db_msg($ex->getMessage());
$this->error($msg);
}
if($msgError){
$this->error($msgError);
}
if($msgSuccess){
$this->success($msgSuccess);
}
}
/*数据表绑定数据*/
public function dbTableBindAction(){
$releId=input('id/d',0);
$table=input('table');
$tables=explode(',', $table);
$tables=array_filter($tables);
$tables=array_values($tables);
if(empty($table)){
$this->error('请选择表');
}
$mrele=model('Release');
$mtask=model('Task');
$mcoll=model('Collector');
$releData=$mrele->where(array('id'=>$releId))->find();
if(empty($releData)){
$this->error(lang('rele_error_empty_rele'));
}
$config=unserialize($releData['config']);
$adb=controller('admin/Rdb','event');
$db_config=$adb->get_db_config($config['db']);
try {
$mdb=new DbCommon($db_config);
$fields=array();
$field_values=array();
foreach ($tables as $tbName){
$fields[$tbName]=$mdb->getFields($tbName);
if(!empty($config['db_table']['field'][$tbName])){
$tableFields=$config['db_table']['field'][$tbName];
if(!empty($tableFields)){
$issetFields=array();
foreach ($fields[$tbName] as $k=>$v){
if(isset($tableFields[$k])){
$issetFields[$k]=$v;
}
}
$fields[$tbName]=array_merge($issetFields,$fields[$tbName]);
}
$field_values[$tbName]['field']=$tableFields;
$field_values[$tbName]['custom']=$config['db_table']['custom'][$tbName];
}
}
$taskData=$mtask->getById($releData['task_id']);
if(!empty($taskData)){
$collFields=$adb->get_coll_fields($taskData['id'], $taskData['module']);
}
}catch (\Exception $ex){
$dbMsg=$this->trans_db_msg($ex->getMessage());
$this->error($dbMsg);
}
$this->assign('collFields',$collFields);
$this->assign('tables',$tables);
$this->assign('fields',$fields);
$this->assign('field_values',$field_values);
return $this->fetch('dbTableBind');
}
/*翻译数据库错误信息*/
public function trans_db_msg($msg){
$msg=lang('rele_error_db').str_replace('Unknown database', lang('error_unknown_database'), $msg);
return $msg;
}
}

View File

@ -0,0 +1,332 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
class Setting extends BaseController {
/*站点设置*/
public function siteAction(){
$mconfig=model('Config');
if(request()->isPost()){
$config=array();
$config['verifycode']=input('verifycode/d',0);
$config['hidehome']=input('hidehome/d',0);
$config['login']=input('login/a');
if($config['login']['limit']){
if(empty($config['login']['failed'])){
$this->error('请设置失败次数');
}
if(empty($config['login']['time'])){
$this->error('请设置锁定时间');
}
}
$mconfig->setConfig('site',$config);
$this->success(lang('op_success'),'Setting/site');
}else{
$GLOBALS['content_header']=lang('setting_site');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Setting/site'),'title'=>lang('setting_site'))));
$siteConfig=$mconfig->getConfig('site','data');
$this->assign('siteConfig',$siteConfig);
}
return $this->fetch();
}
/*采集设置*/
public function caijiAction(){
$mconfig=model('Config');
if(request()->isPost()){
$config=array();
$config['auto']=input('auto/d',0);
$config['run']=input('run');
$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['real_time']=input('real_time/d',0);
$config['download_img']=input('download_img/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);
if(!empty($config['img_path'])){
$checkImgPath=$mconfig->check_img_path($config['img_path']);
if(!$checkImgPath['success']){
$this->error($checkImgPath['msg']);
}
}
if(!empty($config['img_url'])){
$checkImgUrl=$mconfig->check_img_url($config['img_url']);
if(!$checkImgUrl['success']){
$this->error($checkImgUrl['msg']);
}
}
$mconfig->setConfig('caiji',$config);
if($config['auto']){
remove_auto_collecting();
if($config['run']=='backstage'){
@get_html(url('Admin/Index/backstage',array('autorun'=>1),false,true),null,array('timeout'=>1));
}
}
$this->success(lang('op_success'),'Setting/caiji');
}else{
$GLOBALS['content_header']=lang('setting_caiji');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Setting/caiji'),'title'=>lang('setting_caiji'))));
$caijiConfig=$mconfig->getConfig('caiji','data');
$this->assign('caijiConfig',$caijiConfig);
}
return $this->fetch();
}
/*代理设置*/
public function proxyAction(){
$mconfig=model('Config');
$mproxy=model('Proxyip');
if(request()->isPost()){
$config=array();
$ip_list=input('ip_list','','trim');
$user_list=input('user_list','','trim');
$pwd_list=input('pwd_list','','trim');
$ip_list=empty($ip_list)?null:json_decode($ip_list,true);
$user_list=empty($user_list)?null:json_decode($user_list,true);
$pwd_list=empty($pwd_list)?null:json_decode($pwd_list,true);
$config['open']=input('open/d',0);
$config['failed']=input('failed/d',0);
$config['use']=strtolower(input('use'));
$config['use_num']=input('use_num/d',0);
$config['use_time']=input('use_time/d',0);
if('num'==$config['use']&&$config['use_num']<=0){
$this->error('每个IP使用多少次必须大于0');
}
if('time'==$config['use']&&$config['use_time']<=0){
$this->error('每个IP使用多少分钟必须大于0');
}
if(!empty($ip_list)&&is_array($ip_list)){
$mproxy->where(array('ip'=>array('not in',$ip_list)))->delete();
$ip_list=array_map('trim', $ip_list);
$user_list=array_map('trim', $user_list);
$pwd_list=array_map('trim', $pwd_list);
foreach ($ip_list as $k=>$v){
if(empty($v)){
continue;
}
$newData=array(
'ip'=>$v,
'user'=>$user_list[$k],
'pwd'=>$pwd_list[$k],
'invalid'=>0,
'failed'=>0,
'num'=>0,
'time'=>0,
);
if($mproxy->where(array('ip'=>$newData['ip']))->count()>0){
unset($newData['invalid']);
$mproxy->allowField(true)->save($newData,array('ip'=>$newData['ip']));
}else{
$mproxy->db()->insert($newData,true);
}
}
}else{
$mproxy->where('1=1')->delete();
}
$mconfig->setConfig('proxy',$config);
$this->success(lang('op_success'),'Setting/Proxy');
}else{
$GLOBALS['content_header']='代理设置';
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Setting/Proxy'),'title'=>'代理设置')));
$proxyConfig=$mconfig->getConfig('proxy','data');
$proxyConfig['ip_list']=$mproxy->column('*');
$this->assign('proxyConfig',$proxyConfig);
}
return $this->fetch();
}
/*批量添加代理*/
public function proxyBatchAction(){
if(request()->isPost()){
$ips=input('ips');
$fmt=input('format');
$fmt=str_replace(array('[ip]','[端口]','[用户名]','[密码]')
,array('(?P<ip>(\d+\.)+\d+)','(?P<port>\d+)','(?P<user>[^\s]+)','(?P<pwd>[^\s]+)')
,$fmt);
$ipList=array();
if(preg_match_all('/[^\r\n]+/',$ips,$m_ips)){
foreach ($m_ips[0] as $ip){
if(preg_match('/'.$fmt.'/',$ip,$ipInfo)){
$ipList[]=array(
'ip'=>$ipInfo['ip'].':'.$ipInfo['port'],
'user'=>$ipInfo['user'],
'pwd'=>$ipInfo['pwd'],
);
}
}
}
if(empty($ipList)){
$this->error('没有匹配到数据');
}else{
$this->success('',null,$ipList);
}
}else{
return $this->fetch('proxyBatch');
}
}
/*翻译设置*/
public function translateAction(){
$mconfig=model('Config');
if(request()->isPost()){
$config=array();
$config['open']=input('open/d',0);
$config['api']=input('api','','strtolower');
$config['baidu']=input('baidu/a',null,'trim');
$config['youdao']=input('youdao/a',null,'trim');
if(!empty($config['api'])){
if(empty($config[$config['api']])){
$this->error('请填写api配置');
}
foreach ($config[$config['api']] as $k=>$v){
if(empty($v)){
$this->error('请填写api配置');
}
}
}
$mconfig->setConfig('translate',$config);
$this->success(lang('op_success'),'Setting/translate');
}else{
$GLOBALS['content_header']='翻译设置';
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Setting/translate'),'title'=>'翻译设置')));
$transConfig=$mconfig->getConfig('translate','data');
foreach ($transConfig['baidu'] as $k=>$v){
$transConfig['baidu'][$k]=htmlspecialchars($v,ENT_QUOTES);
}
foreach ($transConfig['youdao'] as $k=>$v){
$transConfig['youdao'][$k]=htmlspecialchars($v,ENT_QUOTES);
}
$this->assign('transConfig',$transConfig);
return $this->fetch();
}
}
/*邮箱设置*/
public function emailAction(){
$is_test=input('is_test/d',0);
$mconfig=model('Config');
if(request()->isPost()){
$config=array();
$config['sender']=input('sender');
$config['email']=input('email');
$config['pwd']=input('pwd');
$config['smtp']=input('smtp');
$config['port']=input('port');
$config['type']=input('type');
if($is_test){
$return=send_mail($config, $config['email'], $config['sender'],lang('set_email_test_subject'),lang('set_email_test_body'));
if($return===true){
$this->success(lang('set_email_test_body'),'');
}else{
$this->error($return,'');
}
}else{
$mconfig->setConfig('email',$config);
$this->success(lang('op_success'),'Setting/email');
}
}else{
$GLOBALS['content_header']=lang('setting_email');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Setting/email'),'title'=>lang('setting_email'))));
$emailConfig=$mconfig->getConfig('email','data');
$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['timeout']=input('timeout/d');
if(!in_array($config['tool'],array('chrome'))){
$config['tool']='';
}
if(empty($config['tool'])){
$this->error('请选择渲染工具','');
}
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']);
try {
$chromeSoket->openHost();
}catch (\Exception $ex){
$this->error($ex->getMessage());
}
}
$this->success(lang('op_success'),'Setting/page_render');
}else{
$GLOBALS['content_header']='页面渲染设置 <small><a href="http://www.skycaiji.com/manual/doc/page_render" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a></small>';
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Setting/page_render'),'title'=>'页面渲染设置')));
$config=$mconfig->getConfig('page_render','data');
$this->assign('config',$config);
if($config['tool']=='chrome'){
$cConfig=$config['chrome'];
$chromeSoket=new \util\ChromeSocket($cConfig['host'],$cConfig['port'],$config['timeout'],$cConfig['filename']);
$toolIsOpen=$chromeSoket->hostIsOpen();
$this->assign('toolIsOpen',$toolIsOpen);
}
return $this->fetch();
}
}
/*清理缓存目录*/
public function cleanAction(){
set_time_limit(1000);
$path=realpath(config('root_path').'/runtime');
clear_dir($path);
$this->success();
}
}

View File

@ -0,0 +1,144 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
class Store extends BaseController {
public function isLoginAction(){
if(empty($GLOBALS['user'])){
$this->dispatchJump(false,lang('user_error_is_not_admin'),url('Admin/Index/index',null,null,true));
}else{
$this->dispatchJump(true);
}
}
public function indexAction(){
$GLOBALS['content_header']=lang('store');
$GLOBALS['breadcrumb']=breadcrumb(array(lang('store')));
return $this->fetch();
}
/*安装规则*/
public function installRuleAction(){
$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'],'name'=>$rule['name'],'module'=>$rule['module'],'uptime'=>($rule['uptime']>0?$rule['uptime']:NOW_TIME),'config'=>$rule['config']);
$ruleData=$mrule->where(array('type'=>$rule['type'],'store_id'=>$store_id))->find();
if(empty($ruleData)){
$newRule['store_id']=$store_id;
$newRule['addtime']=NOW_TIME;
$ruleId=$mrule->insert($newRule);
}else{
$mrule->allowField(true)->save($newRule,array('id'=>$ruleData['id']));
$ruleId=$ruleData['id'];
}
$this->dispatchJump(true,$ruleId);
}else{
$this->dispatchJump(false,'id错误');
}
}
/*规则更新时间*/
public function ruleUpdateAction(){
$storeIds=input('store_ids');
$storeIdList=array('collect'=>array());
foreach (array_keys($storeIdList) as $type){
if(preg_match_all('/\b'.$type.'\_(\d+)/i', $storeIds,$typeIds)){
$storeIdList[$type]=$typeIds[1];
}
}
$uptimeList=array('status'=>1,'data'=>array());
$mrule=model('Rule');
if(!empty($storeIdList)){
foreach ($storeIdList as $type=>$ids){
if(!empty($ids)){
$cond=array();
$cond['type']=$type;
$cond['store_id']=array('in',$ids);
$uptimeList['data'][$type]=$mrule->field('`id`,`type`,`store_id`,`uptime`')->where($cond)->column('uptime','store_id');
}
}
}
return jsonp($uptimeList);
}
/*安装cms发布程序*/
public function installCmsAction(){
$cms=json_decode(base64_decode(input('post.cms')),true);
$cms['code']=base64_decode($cms['code']);
if(empty($cms['app'])){
$this->dispatchJump(false,'插件id错误');
}
if(empty($cms['name'])){
$this->dispatchJump(false,'插件名错误');
}
if(empty($cms['code'])){
$this->dispatchJump(false,'不是可用的程序');
}
if(!empty($cms['tpl'])){
$cms['tpl']=base64_decode($cms['tpl']);
}
model('ReleaseApp')->addCms(array('app'=>$cms['app'],'name'=>$cms['name'],'desc'=>$cms['desc'],'uptime'=>$cms['uptime'])
,$cms['code'],$cms['tpl']);
$this->dispatchJump(true);
}
/*cms发布插件更新时间*/
public function cmsUpdateAction(){
$storeApps=input('store_apps');
if(preg_match_all('/\bcms\_(\w+)/i', $storeApps,$apps)){
$apps=$apps[1];
}
$uptimeList=array('status'=>1,'data'=>array());
if(!empty($apps)){
$cond=array();
$cond['module']='cms';
$cond['app']=array('in',$apps);
$uptimeList['data']=model('ReleaseApp')->where($cond)->column('uptime','app');
}
return jsonp($uptimeList);
}
/*站点验证*/
public function siteCertificationAction(){
$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,'操作错误!');
}
}
}

View File

@ -0,0 +1,688 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
use think\Loader;
class Task extends BaseController {
public function indexAction(){
return $this->fetch();
}
/*任务列表*/
public function listAction(){
$page=input('p/d',1);
$page=max(1,$page);
$show=strtolower(input('show','list'));
if(!in_array($show,array('list','folder','import'))){
$show='list';
}
$mtaskgroup=model('Taskgroup');
$mtask=model('Task');
if($show=='folder'){
$tgSelect=$mtaskgroup->getLevelSelect();
$tgSelect=preg_replace('/<select[^<>]*>/i', "$0<option value=''>".lang('all')."</option>", $tgSelect);
$this->assign('tgSelect',$tgSelect);
}elseif($show=='list'){
$sortBy=input('sort','desc');
$sortBy=($sortBy=='asc')?'asc':'desc';
$orderKey=input('order');
$this->assign('sortBy',$sortBy);
$this->assign('orderKey',$orderKey);
$orderBy=!empty($orderKey)?($orderKey.' '.$sortBy):'sort desc';
$search['tg_id']=input('tg_id');
$search['name']=input('name');
$search['module']=input('module');
$search['show']='list';
$limit=20;
$cond=array();
if(!empty($search['name'])){
$cond['name']=array('like','%'.addslashes($search['name']).'%');
}
if(!empty($search['module'])){
$cond['module']=$search['module'];
}
$this->assign('search',$search);
if(is_numeric($search['tg_id'])){
if($search['tg_id']>0){
$tgData=$mtaskgroup->getById($search['tg_id']);
if(empty($tgData)){
$this->error(lang('task_error_empty_tg'));
}
$subTgList=$mtaskgroup->where(array('parent_id'=>$tgData['id']))->column('name','id');
$subTgList[$tgData['id']]=$tgData['name'];
$cond['tg_id']=array('in',array_keys($subTgList));
$this->assign('tgList',$subTgList);
}else{
$cond['tg_id']=0;
}
$taskList=$mtask->where($cond)->order($orderBy)->paginate($limit,false,array('query'=>$search));
$pagenav=$taskList->render();
$taskList=$taskList->all();
}else{
$taskList=$mtask->where($cond)->order($orderBy)->paginate($limit,false,array('query'=>$search));
$pagenav=$taskList->render();
$taskList=$taskList->all();
if(!empty($taskList)){
$tgIds=array();
foreach($taskList as $task){
$tgIds[$task['tg_id']]=$task['tg_id'];
}
$tkTgList=$mtaskgroup->where(array('id'=>array('in',$tgIds)))->column('name','id');
$this->assign('tgList',$tkTgList);
}
}
$count=$mtask->where($cond)->count();
$this->assign('taskList',$taskList);
$this->assign('pagenav',$pagenav);
$tgSelect=$mtaskgroup->getLevelSelect();
$tgSelect=preg_replace('/<select[^<>]*>/i', "$0<option value=''>".lang('all')."</option>", $tgSelect);
$this->assign('tgSelect',$tgSelect);
}elseif($show=='import'){
$count=$mtask->count();
$limit=20;
$taskList=$mtask->order('sort desc')->paginate($limit,false,array('query'=>array('show'=>$show)));
$pagenav=$taskList->render();
$taskList=$taskList->all();
$this->assign('taskList',$taskList);
$this->assign('pagenav',$pagenav);
}
$showChange=$show=='list'?'folder':'list';
$GLOBALS['content_header']=lang('task_list').' <small><a href="'.url('Task/list?show='.$showChange).'">'.lang('task_change_'.$showChange).'</a></small>';
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list'))));
return $this->fetch('list_'.$show);
}
/*任务列表,打开文件夹*/
public function openListAction(){
$tgid=input('tg_id/d',0);
$mtaskgroup=model('taskgroup');
$mtask=model('Task');
$subTgList=$mtaskgroup->where(array('parent_id'=>$tgid))->order('sort desc')->column('*');
$taskList=$mtask->where(array('tg_id'=>$tgid))->order('sort desc')->column('*');
if(!empty($subTgList)||!empty($taskList)){
foreach ($taskList as $tk=>$tv){
$tv['module']=lang('task_module_'.$tv['module']);
$tv['addtime']=date('Y-m-d',$tv['addtime']);
$tv['caijitime']=$tv['caijitime']>0?date('Y-m-d H:i',$tv['caijitime']):'无';
$taskList[$tk]=$tv;
}
$this->success('',null,array('tgList'=>$subTgList,'taskList'=>$taskList));
}else{
$this->error();
}
}
/**
* 添加任务
*/
public function addAction(){
$mtask=model('Task');
if(request()->isPost()){
$newData=input('param.');
$importTaskId=input('task_id/d',0);
$validate=Loader::validate('Task');
if(!$validate->scene('add')->check($newData)){
$this->error($validate->getError());
}
if(input('?config.img_url')){
$newData['config']['img_url']=input('config.img_url','','trim');
}
$newData['config']=$this->_save_config($newData['config']);
$newData['config']=serialize($newData['config']);
$newData['addtime']=NOW_TIME;
$importColl=null;
$importRele=null;
if($importTaskId>0){
$importTask=$mtask->where('id',$importTaskId)->find();
if(!empty($importTask)){
$importTask=$importTask->toArray();
$importColl=model('Collector')->where(array('task_id'=>$importTask['id'],'module'=>$importTask['module']))->find();
$importRele=model('Release')->where(array('task_id'=>$importTask['id']))->find();
$newData['tg_id']=$newData['tg_id']>0?$newData['tg_id']:$importTask['tg_id'];
$newData['module']=$importTask['module'];
$newData['config']=$importTask['config'];
}
}
$mtask->allowField(true)->save($newData);
$tid=$mtask->id;
if($tid>0){
$taskData=$mtask->getById($tid);
if($importTaskId>0){
if(!empty($importColl)){
$importColl=$importColl->toArray();
$importColl['task_id']=$taskData['id'];
unset($importColl['id']);
model('Collector')->add_new($importColl);
}
if(!empty($importRele)){
$importRele=$importRele->toArray();
$importRele['task_id']=$taskData['id'];
$importRele['addtime']=NOW_TIME;
unset($importRele['id']);
model('Release')->allowField(true)->save($importRele);
}
}
/*导入规则*/
$ruleId=input('rule_id');
if(!empty($taskData)&&!empty($ruleId)){
$this->_import_rule($taskData, $ruleId);
}
$this->success(lang('op_success'),input('referer','','trim')?input('referer','','trim'):('Task/edit?id='.$tid));
}else{
$this->error(lang('op_failed'));
}
}else{
$mtaskgroup=model('Taskgroup');
$tgSelect=$mtaskgroup->getLevelSelect();
$GLOBALS['content_header']=lang('task_add');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list')),lang('task_add')));
$this->assign('tgSelect',$tgSelect);
if(request()->isAjax()){
return view('add_ajax');
}else{
return $this->fetch('add');
}
}
}
/**
* 编辑任务
*/
public function editAction(){
$id=input('id/d',0);
$mtask=model('Task');
$taskData=$mtask->getById($id);
if(empty($id)){
$this->error(lang('task_error_null_id'));
}
if(empty($taskData)){
$this->error(lang('task_error_empty_task'));
}
if(request()->isPost()){
$newData=input('param.');
$validate=Loader::validate('Task');
if(!$validate->scene('edit')->check($newData)){
$this->error($validate->getError());
}
if(input('?config.img_url')){
$newData['config']['img_url']=input('config.img_url','','trim');
}
$newData['config']=$this->_save_config($newData['config']);
$newData['config']=serialize($newData['config']);
if($taskData['name']!=$newData['name']){
if($mtask->where(array('name'=>$newData['name']))->count()>0){
$this->error(lang('task_error_has_name'));
}
}
unset($newData['id']);
if($mtask->allowField(true)->save($newData,array('id'=>intval($taskData['id'])))>=0){
$taskData=$mtask->getById($taskData['id']);
/*导入规则*/
$ruleId=input('rule_id');
if(!empty($taskData)&&!empty($ruleId)){
$this->_import_rule($taskData, $ruleId);
}
$this->success(lang('op_success'),'Task/edit?id='.$taskData['id']);
}else{
$this->error(lang('op_failed'));
}
}else{
$taskData=$taskData->getData();
$taskData['config']=unserialize($taskData['config']);
$taskData['config']=is_array($taskData['config'])?$taskData['config']:array();
$mtaskgroup=model('Taskgroup');
$tgSelect=$mtaskgroup->getLevelSelect();
$GLOBALS['content_header']=lang('task_edit');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Task/list'),'title'=>lang('task_list')),lang('task_edit')));
$this->assign('tgSelect',$tgSelect);
$this->assign('taskData',$taskData);
if(request()->isAjax()){
return view('add_ajax');
}else{
return $this->fetch('add');
}
}
}
/*保持更多设置*/
public function _save_config($config=array()){
$config=is_array($config)?$config:array();
$config['num']=intval($config['num']);
$config['img_path']=trim($config['img_path']);
$config['img_url']=trim($config['img_url']);
if(!empty($config['img_path'])){
$checkImgPath=model('Config')->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']);
if(!$checkImgUrl['success']){
$this->error($checkImgUrl['msg']);
}
}
return $config;
}
/*导入规则*/
public function _import_rule($taskData,$ruleId){
$mtask=model('Task');
$mrule=model('Rule');
$mcoll=model('Collector');
list($ruleType,$ruleId)=explode(':', $ruleId);
$ruleId=intval($ruleId);
$ruleType=strtolower($ruleType);
if(!empty($taskData)){
$name=null;
$module=null;
$config=null;
if('rule'==$ruleType){
$ruleData=$mrule->getById($ruleId);
}elseif('collector'==$ruleType){
$ruleData=$mcoll->getById($ruleId);
}elseif('file'==$ruleType){
$file=$_FILES['rule_file'];
$fileTxt=file_get_contents($file['tmp_name']);
if(preg_match('/\/\*skycaiji-collector-start\*\/(?P<coll>[\s\S]+?)\/\*skycaiji-collector-end\*\//i',$fileTxt,$ruleMatch)){
$ruleData=unserialize(base64_decode(trim($ruleMatch['coll'])));
}
}
if(!empty($ruleData)){
$name=$ruleData['name'];
$module=$ruleData['module'];
$config=$ruleData['config'];
}
$referer=input('referer','','trim')?input('referer','','trim'):url('Task/edit?id='.$taskData['id']);
if(empty($module)||(strcasecmp($module, $taskData['module'])!==0)){
$this->error('导入的规则模块错误',$referer);
}
if(empty($config)){
$this->error('导入的规则为空',$referer);
}
$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);
if(empty($collData)){
$mcoll->add_new($newColl);
}else{
$mcoll->edit_by_id($collData['id'],$newColl);
}
}
}
public function opAction(){
$id=input('id/d',0);
$op=input('op');
$ops=array('item'=>array('delete','auto'),'list'=>array('saveall'));
if(!in_array($op,$ops['item'])&&!in_array($op,$ops['list'])){
$this->error(lang('invalid_op'));
}
$mtask=model('Task');
if(in_array($op,$ops['item'])){
$taskData=$mtask->getById($id);
if(empty($taskData)){
$this->error(lang('empty_data'));
}
}
$this->assign('op',$op);
if($op=='delete'){
$mtask->where(array('id'=>$id))->delete();
model('Collector')->where('task_id',$id)->delete();
model('Release')->where('task_id',$id)->delete();
$this->success(lang('delete_success'));
}elseif($op=='auto'){
$auto = min(1,input('auto/d',0));
$mtask->save(array('auto'=>$auto),array('id'=>$taskData['id']));
$this->success(lang('op_success'));
}elseif($op=='saveall'){
$newsort=input('newsort/a');
if(is_array($newsort)&&count($newsort)>0){
foreach ($newsort as $key=>$val){
$mtask->save(array('sort'=>intval($val)),array('id'=>intval($key)));
}
}
$this->success(lang('op_success'),'Task/list?show='.input('show'));
}
}
/*执行任务采集*/
public function collectAction(){
if(input('?backstage')){
ignore_user_abort(true);
define('CLOSE_ECHO_MSG',true);
}else{
ignore_user_abort(false);
}
$taskId=input('id/d',0);
$this->_collect($taskId);
}
/*批量执行任务采集*/
public function collectBatchAction(){
if(input('?backstage')){
ignore_user_abort(true);
define('CLOSE_ECHO_MSG',true);
}else{
ignore_user_abort(false);
}
$taskIds=input('ids');
if(empty($taskIds)){
$this->echo_msg('没有选中任务');
exit();
}
$taskIds=explode(',', $taskIds);
$taskIds=array_map('intval', $taskIds);
if($GLOBALS['config']['caiji']['timeout']>0){
set_time_limit(60*$GLOBALS['config']['caiji']['timeout']);
}else{
set_time_limit(0);
}
$taskList=model('Task')->where('id','in',$taskIds)->column('*','id');
if(empty($taskList)){
$this->echo_msg('没有任务');
exit();
}
$sortTasks=array();
foreach ($taskIds as $v){
$sortTasks[$v]=$taskList[$v];
}
$taskList=$sortTasks;
unset($sortTasks);
$this->_collect_batch($taskList);
$this->echo_msg('所有任务采集完毕!','green');
}
/*单个任务采集*/
public function _collect($taskId){
static $setted_timeout=null;
if(!isset($setted_timeout)){
if($GLOBALS['config']['caiji']['timeout']>0){
set_time_limit(60*$GLOBALS['config']['caiji']['timeout']);
}else{
set_time_limit(0);
}
$setted_timeout=1;
}
$mtask=model('Task');
$taskData=$mtask->getById($taskId);
if(empty($taskData)){
$this->echo_msg(lang('task_error_empty_task'));
exit();
}
$taskData=$taskData->toArray();
if(empty($taskData['module'])){
$this->echo_msg(lang('task_error_null_module'));
exit();
}
if(!in_array($taskData['module'],config('allow_coll_modules'))){
$this->echo_msg(lang('coll_error_invalid_module'));
exit();
}
$taskData['config']=unserialize($taskData['config']);
model('Task')->loadConfig($taskData['config']);
$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();
}
$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();
}
$releData=$releData->toArray();
$mtask->save(array('caijitime'=>NOW_TIME),array('id'=>$taskData['id']));
$acoll=controller('admin/C'.strtolower($collData['module']),'event');
$acoll->init($collData);
$arele=controller('admin/R'.strtolower($releData['module']),'event');
$arele->init($releData);
$GLOBALS['real_time_release']=&$arele;
if('api'==$releData['module']){
$GLOBALS['config']['caiji']['real_time']=0;
$cacheApiData=$arele->get_cache_fields();
if($cacheApiData!==false){
json($cacheApiData)->send();
exit();
}
}
$all_field_list=array();
$caijiNum=intval($GLOBALS['config']['caiji']['num']);
$taskNum=intval($taskData['config']['num']);
if($taskNum<=0||($caijiNum>0&&$taskNum>$caijiNum)){
$taskNum=$caijiNum;
}
$caijiLimit=false;
if($taskNum>0){
$caijiLimit=true;
}
if($caijiLimit){
while($taskNum>0){
$field_list=$acoll->collect($taskNum);
if($field_list=='completed'){
break;
}elseif(is_array($field_list)&&!empty($field_list)){
$all_field_list=array_merge($all_field_list,$field_list);
$taskNum-=count($field_list);
}
if($taskNum>0){
$this->echo_msg('采集到'.count($field_list).'条数据,还差'.$taskNum.'条','orange');
}
}
}else{
do{
$field_list=$acoll->collect($taskNum);
if(is_array($field_list)&&!empty($field_list)){
$all_field_list=array_merge($all_field_list,$field_list);
}
}while($field_list!='completed');
}
if(empty($all_field_list)){
$this->echo_msg('没有采集到数据','orange');
}else{
$this->echo_msg('采集到'.count($all_field_list).'条数据','green');
if(empty($GLOBALS['config']['caiji']['real_time'])){
$addedNum=$arele->export($all_field_list);
$this->echo_msg('成功发布'.$addedNum.'条数据','green');
}
}
}
/*批量任务采集*/
public function _collect_batch($taskList=array()){
$mtask=model('Task');
$mcoll=model('Collector');
$mrele=model('Release');
$caijiNum=intval($GLOBALS['config']['caiji']['num']);
$caijiLimit=false;
if($caijiNum>0){
$caijiLimit=true;
$this->echo_msg('总共需采集'.$caijiNum.'条数据','black');
}
foreach ($taskList as $taskData){
$mtask->where('id',$taskData['id'])->update(array('caijitime'=>time()));
$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)){
$this->echo_msg('任务:'.$taskData['name'].' 设置不完整','orange');
continue;
}
$collData=$collData->toArray();
$releData=$releData->toArray();
if($releData['module']=='api'){
$this->echo_msg('任务:'.$taskData['name'].'发布方式为API接口跳过执行','orange');
continue;
}
$taskData['config']=unserialize($taskData['config']);
$mtask->loadConfig($taskData['config']);
$acoll='\\skycaiji\\admin\\event\\C'.strtolower($collData['module']);
$acoll=new $acoll();
$acoll->init($collData);
$arele='\\skycaiji\\admin\\event\\R'.strtolower($releData['module']);
$arele=new $arele();
$arele->init($releData);
$GLOBALS['real_time_release']=&$arele;
$this->echo_msg('<div style="background:#efefef;padding:5px;margin:5px 0;text-align:center;">正在执行任务:'.$taskData['name'].'</div>','black');
$all_field_list=array();
$taskNum=intval($taskData['config']['num']);
if($taskNum<=0||($caijiLimit&&$taskNum>$caijiNum)){
$taskNum=$caijiNum;
}
if($taskNum>0){
while($taskNum>0){
$field_list=$acoll->collect($taskNum);
if($field_list=='completed'){
break;
}elseif(is_array($field_list)&&!empty($field_list)){
$all_field_list=array_merge($all_field_list,$field_list);
$taskNum-=count($field_list);
$caijiNum-=count($field_list);
}
}
}else{
do{
$field_list=$acoll->collect($taskNum);
if(is_array($field_list)&&!empty($field_list)){
$all_field_list=array_merge($all_field_list,$field_list);
}
}while($field_list!='completed');
}
if(empty($all_field_list)){
$this->echo_msg('任务:'.$taskData['name'].' 没有采集到数据','orange');
}else{
$this->echo_msg('任务:'.$taskData['name'].' 采集到'.count($all_field_list).'条数据','green');
if(empty($GLOBALS['config']['caiji']['real_time'])){
$addedNum=$arele->export($all_field_list);
$this->echo_msg('成功发布'.$addedNum.'条数据','green');
}
}
$this->echo_msg('<div style="background:#efefef;padding:5px;margin:5px 0;text-align:center;color:green;">任务:'.$taskData['name'].' 执行完毕</div>','green');
if($caijiLimit){
if($caijiNum>0){
$this->echo_msg('还差'.$caijiNum.'条数据','orange');
}else{
break;
}
}
}
}
}

View File

@ -0,0 +1,271 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
use think\Loader;
class Taskgroup extends BaseController {
/**
* 任务分组列表
*/
public function listAction(){
$page=input('p/d',1);
$page=max(1,$page);
$search['parent_id']=input('parent_id/d',0);
$search['name']=input('name');
$mtaskgroup=model('Taskgroup');
$cond=array();
if($search['parent_id']>0){
$cond['parent_id']=$search['parent_id'];
}
if(!empty($search['name'])){
$cond['name']=array('like','%'.addslashes($search['name']).'%');
}
$this->assign('search',$search);
$limit=20;
if($cond){
$count=$mtaskgroup->where($cond)->count();
if($count>0){
$parentList=$mtaskgroup->where($cond)->order('sort desc')->paginate($limit,false,array('query'=>$search));
}
}else{
$cond=array('parent_id'=>0);
$count=$mtaskgroup->where($cond)->count();
if($count>0){
$parentList=$mtaskgroup->where($cond)->order('sort desc')->paginate($limit,false,array('query'=>$search));
$parentIds=array();
foreach ($parentList->all() as $item){
$parentIds[$item['id']]=$item['id'];
}
$subList1=$mtaskgroup->where(array('parent_id'=>array('in',$parentIds)))->order('sort desc')->column('*');
$subList=array();
foreach ($subList1 as $item){
$subList[$item['parent_id']][$item['id']]=$item;
}
unset($subList1);
}
}
if(isset($parentList)){
$pagenav = $parentList->render();
$this->assign('pagenav',$pagenav);
$parentList=$parentList->all();
}else{
$parentList=null;
}
$this->assign('parentList',$parentList);
$this->assign('subList',$subList);
$parentTgList=$mtaskgroup->where(array('parent_id'=>0))->order('sort desc')->column('name','id');
$this->assign('parentTgList',$parentTgList);
$GLOBALS['content_header']=lang('taskgroup_list');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list'))));
return $this->fetch();
}
/**
* 添加任务分组
*/
public function addAction(){
$mtaskgroup=model('Taskgroup');
if(request()->isPost()){
$newData=input('param.');
$validate=Loader::validate('Taskgroup');
if(!$validate->scene('add')->check($newData)){
$this->error($validate->getError());
}
$mtaskgroup->allowField(true)->save($newData);
$tgid=$mtaskgroup->id;
if($tgid>0){
$this->success(lang('op_success'),input('referer','','trim')?input('referer','','trim'):('Taskgroup/edit?id='.$tgid));
}else{
$this->error(lang('op_failed'));
}
}else{
$parentTgList=$mtaskgroup->where(array('parent_id'=>0))->order('sort desc')->column('name','id');
$this->assign('parentTgList',$parentTgList);
$GLOBALS['content_header']=lang('taskgroup_add');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list')),lang('taskgroup_add')));
if(request()->isAjax()){
return view('add_ajax');
}else{
return $this->fetch('add');
}
}
}
/**
* 编辑任务分组
*/
public function editAction(){
$mtaskgroup=model('Taskgroup');
$id=input('id/d',0);
$tgData=$mtaskgroup->getById($id);
if(empty($tgData)){
$this->error(lang('tg_none'));
}
if(request()->isPost()){
$newData=input('param.');
$validate=Loader::validate('Taskgroup');
if(!$validate->scene('edit')->check($newData)){
$this->error($validate->getError());
}
if($tgData['name']!=$newData['name']){
if($mtaskgroup->where(array('name'=>$newData['name']))->count()>0){
$this->error(lang('tg_error_has_name'));
}
}
if($newData['parent_id']>0){
$subCount=$mtaskgroup->where(array('parent_id'=>$tgData['id']))->count();
if($subCount>0){
$this->error(lang('tg_is_parent'));
}
}
if($newData['parent_id']==$tgData['id']){
unset($newData['parent_id']);
}
unset($newData['id']);
$result=$mtaskgroup->allowField(true)->save($newData,array('id'=>intval($tgData['id'])));
if($result>=0){
$this->success(lang('op_success'),'Taskgroup/edit?id='.$tgData['id']);
}else{
$this->error(lang('op_failed'));
}
}else{
$parentTgList=$mtaskgroup->where(array('parent_id'=>0))->order('sort desc')->column('name','id');
$this->assign('parentTgList',$parentTgList);
$this->assign('tgData',$tgData);
$GLOBALS['content_header']=lang('taskgroup_edit');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('Taskgroup/list'),'title'=>lang('taskgroup_list')),lang('taskgroup_edit')));
if(request()->isAjax()){
return view('add_ajax');
}else{
return $this->fetch('add');
}
}
}
/**
* 任务分组操作
*/
public function opAction(){
$id=input('id/d',0);
$op=input('op');
$ops=array('item'=>array('delete','move'),'list'=>array('deleteall','saveall'));
if(!in_array($op,$ops['item'])&&!in_array($op,$ops['list'])){
$this->error(lang('invalid_op'));
}
$mtaskgroup=model('Taskgroup');
if(in_array($op,$ops['item'])){
$tgData=$mtaskgroup->getById($id);
if(empty($tgData)){
$this->error(lang('empty_data'));
}
$this->assign('tgData',$tgData);
}
$this->assign('op',$op);
$mtask=model('Task');
if($op=='delete'){
if($mtaskgroup->where(array('parent_id'=>$tgData['id']))->count()>0){
$this->error(lang('tg_exist_sub'));
}else{
$mtaskgroup->where(array('id'=>$id))->delete();
$mtask->save(array('tg_id'=>0),array('tg_id'=>$id));
$this->success(lang('delete_success'));
}
}elseif($op=='move'){
$parentTgList=$mtaskgroup->where(array('parent_id'=>0))->column('name','id');
if(request()->isPost()){
$parent_id=input('parent_id/d',0);
if($parent_id>0&&$parent_id!=$tgData['parent_id']){
$subCount=$mtaskgroup->where(array('parent_id'=>$tgData['id']))->count();
if($subCount>0){
$this->error(lang('tg_is_parent'));
}
}
if($tgData['id']!=$parent_id){
$mtaskgroup->save(array('parent_id'=>$parent_id),array('id'=>intval($tgData['id'])));
}
$this->success(lang('op_success'),input('referer','','trim'));
}else{
$this->assign('parentTgList',$parentTgList);
return $this->fetch();
}
}elseif($op=='deleteall'){
$ids=input('ids/a');
if(is_array($ids)&&count($ids)>0){
$list=$mtaskgroup->where(array('id'=>array('in',$ids)))->column('*');
$deleteIds=array();
foreach ($list as $item){
$subCount=$mtaskgroup->where(array('parent_id'=>$item['id']))->count();
if($subCount==0){
$deleteIds[$item['id']]=$item['id'];
}else{
$hasSub=true;
}
}
if($deleteIds){
$mtaskgroup->where(array('id'=>array('in',$deleteIds)))->delete();
$mtask->save(array('tg_id'=>0),array('tg_id'=>array('in',$deleteIds)));
}
}
$this->success(lang($hasSub?'tg_deleteall_has_sub':'op_success'));
}elseif($op=='saveall'){
$ids=input('ids/a');
$newsort=input('newsort/a');
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]));
}
$updateSql.='END WHERE `id` IN ('. implode(',',$ids).')';
try{
$mtaskgroup->execute($updateSql);
}catch (\Exception $ex){
$this->error(lang('op_failed'));
}
}
$this->success(lang('op_success'),'list');
}
}
}

View File

@ -0,0 +1,433 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
use skycaiji\admin\model\DbCommon;
class Tool extends BaseController {
/*文件管理*/
public function fileManagerAction(){
$GLOBALS['content_header']='文件管理';
$GLOBALS['breadcrumb']=breadcrumb(array('文件管理'));
return $this->fetch('fileManager');
}
/*elfinder文件管理器*/
public function elfinderAction(){
$op=input('op');
if(empty($op)){
$elfinderUrl=config('root_website').'/vendor/studio-42/elfinder';
$this->assign('elfinderUrl',$elfinderUrl);
return $this->fetch();
}elseif('connect'==$op){
\elFinder::$netDrivers['ftp'] = 'FTP';
$opts = array(
'roots' => array(
array(
'driver' => 'LocalFileSystem',
'path' => config('root_path').'/data',
'URL' => config('root_website').'/data',
'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 (
array (
'pattern' => '/\.php$/i',
'read' => false,
'write' => false,
'hidden' => true,
'locked' => false
)
)
)
)
);
$connector = new \elFinderConnector(new \elFinder($opts));
$connector->run();
}
}
/*日志列表*/
public function logsAction(){
$logPath=realpath(config('root_path').'/runtime/log');
$logList=array();
$paths=scandir($logPath);
foreach ($paths as $path){
if($path!='.'&&$path!='..'){
$pathFiles=scandir($logPath.'/'.$path);
foreach ($pathFiles as $pathFile){
if($pathFile!='.'&&$pathFile!='..'){
$logList[$path][]=array(
'name'=>$pathFile,
'file'=>realpath($logPath.'/'.$path.'/'.$pathFile),
);
}
}
}
}
$GLOBALS['content_header']='错误日志';
$GLOBALS['breadcrumb']=breadcrumb(array('错误日志'));
$this->assign('logList',$logList);
return $this->fetch();
}
/*读取日志*/
public function logAction(){
$file=realpath(input('file'));
$logPath=realpath(config('root_path').'/runtime/log');
if(stripos($file,$logPath)===false){
$this->error('不是日志文件');
}
$log=file_get_contents($file);
exit($log);
}
/*文件校验*/
public function checkfileAction(){
set_time_limit(0);
if(request()->isPost()){
$check_file=file_get_contents(config('app_path').'/install/data/check_file');
$check_file=unserialize($check_file);
if(empty($check_file)){
$this->error('没有获取到校验文件');
}
if(!version_compare($check_file['version'],SKYCAIJI_VERSION,'=')){
$this->error('校验文件版本与程序版本不一致');
}
if(empty($check_file['files'])){
$this->error('没有文件');
}
$new_files=array();
$new_files1=array();
program_filemd5_list(config('root_path'), $new_files1);
foreach ($new_files1 as $k=>$v){
$new_files[md5($v['file'])]=$v;
}
unset($new_files1);
if(empty($new_files)){
$this->error('没有获取到程序文件');
}
$error_files=array();
foreach ($check_file['files'] as $old_file){
$error_file='';
$filenameMd5=md5($old_file['file']);
if(isset($new_files[$filenameMd5])){
if($new_files[$filenameMd5]['file']!=$old_file['file']){
$error_file=$old_file['file'].' 不一致';
}elseif($new_files[$filenameMd5]['md5']!=$old_file['md5']){
$error_file=$old_file['file'].' 已修改';
}
}else{
$error_file=$old_file['file'].' 不存在';
}
if(!empty($error_file)){
$error_files[]=$error_file;
}
}
if(empty($error_files)){
$this->success();
}else{
$this->error('',null,array('files'=>$error_files));
}
}else{
$GLOBALS['content_header']='校验文件';
$GLOBALS['breadcrumb']=breadcrumb(array('校验文件'));
return $this->fetch();
}
}
/*获取索引*/
public function _get_indexes($tb_indexes){
$indexes=array();
if(!empty($tb_indexes)){
foreach ($tb_indexes as $tb_index){
$tb_index=array_change_key_case($tb_index,CASE_LOWER);
if(empty($indexes[$tb_index['key_name']]['type'])){
$index_type=strtolower($tb_index['index_type']);
if(strcasecmp($tb_index['key_name'], 'primary')==0){
$index_type='primary';
}elseif(empty($tb_index['non_unique'])){
$index_type='unique';
}elseif($index_type=='fulltext'){
$index_type='fulltext';
}else{
$index_type='index';
}
}
$indexes[$tb_index['key_name']]['type']=$index_type;
$indexes[$tb_index['key_name']]['field'][]='`'.$tb_index['column_name'].'`'.(empty($tb_index['sub_part'])?'':"({$tb_index['sub_part']})");
}
}
return $indexes;
}
/*数据库校验*/
public function checkdbAction(){
if(request()->isPost()){
set_time_limit(0);
$repair=input('repair/d',0);
$check_db=file_get_contents(config('app_path').'/install/data/check_db');
if(empty($check_db)){
$this->error('没有获取到校验文件');
}
$check_db=unserialize($check_db);
if(empty($check_db)){
$this->error('没有获取到表');
}
if(!version_compare($check_db['version'],$GLOBALS['config']['version'],'=')){
$this->error('校验文件版本与数据库版本不一致');
}
if(empty($check_db['tables'])){
$this->error('没有表');
}
$error_fields=array();
$error_indexes=array();
$table_primary=array();
foreach ($check_db['tables'] as $table=>$fields){
$tb_indexes=$check_db['indexes'][$table];
$table=config('database.prefix').$table;
$null_table=db()->query("show tables like '{$table}';");
$null_table=empty($null_table)?true:false;
$cur_fields=array();
if(!$null_table){
$cur_fields=DbCommon::fieldsInfo($table);
}
foreach ($fields as $field=>$field_set){
if(serialize($field_set)!=serialize($cur_fields[$field])){
$error_fields[$table][$field]=$field_set;
}
if($field_set['primary']){
$table_primary[$table][$field_set['name']]='`'.$field_set['name'].'`';
}
}
$tb_indexes=$this->_get_indexes($tb_indexes);
if(!$null_table){
$cur_indexes=db()->query("SHOW INDEX FROM `{$table}`");
$cur_indexes=$this->_get_indexes($cur_indexes);
foreach ($tb_indexes as $index_name=>$tb_index){
$cur_index=$cur_indexes[$index_name];
if(empty($cur_index)||strcasecmp($tb_index['type'],$cur_index['type'])!=0||strcasecmp(implode(',',$tb_index['field']),implode(',',$cur_index['field']))!=0){
$error_indexes[$table][$index_name]=$tb_index;
}
}
}
}
if(empty($error_fields)&&empty($error_indexes)){
$this->success();
}else{
if(!$repair){
foreach ($error_fields as $tb=>$tb_fields){
foreach ($tb_fields as $k=>$v){
$v['default']=is_null($v['default'])?NULL:$v['default'];
$v['primary']=$v['primary']?'是':'否';
$v['notnull']=$v['notnull']?'是':'否';
$v['autoinc']=$v['autoinc']?'是':'否';
$tb_fields[$k]=$v;
}
$error_fields[$tb]=$tb_fields;
}
foreach ($error_indexes as $tb=>$indexes){
foreach ($indexes as $k=>$v){
$index_field=implode(',', $v['field']);
$index_field=str_replace('`', '', $index_field);
$error_indexes[$tb][$k]['field']=$index_field;
}
}
$this->error('',null,array('fields'=>empty($error_fields)?null:$error_fields,'indexes'=>empty($error_indexes)?null:$error_indexes));
}else{
try {
foreach ($error_fields as $tb=>$tb_fields){
$primarys=$table_primary[$tb];
$hasTable=db()->query("show tables like '{$tb}';");
foreach ($tb_fields as $k=>$v){
if($v['primary']){
$v['notnull']=1;
}
if($v['notnull']){
$v['default']=is_null($v['default'])?'':"DEFAULT '{$v['default']}'";
}else{
$v['default']=is_null($v['default'])?'DEFAULT NULL':"DEFAULT '{$v['default']}'";
}
$v['notnull']=$v['notnull']?'NOT NULL':'null';
$v['autoinc']=$v['autoinc']?'AUTO_INCREMENT':'';
$tb_fields[$k]=$v;
}
if(empty($hasTable)){
$createSql="CREATE TABLE `{$tb}` (";
foreach ($tb_fields as $k=>$v){
$createSql.="`{$v['name']}` {$v['type']} {$v['notnull']} {$v['default']} {$v['autoinc']},\r\n";
}
if(empty($primarys)){
$createSql=rtrim($createSql,',');
}else{
$createSql.='PRIMARY KEY ('.implode(',', $primarys).')';
}
$createSql.=' ) ENGINE=MyISAM DEFAULT CHARSET=utf8';
db()->execute($createSql);
}else{
$cur_fields=db()->getTableFields($tb);
foreach ($tb_fields as $k=>$v){
$alterSql="ALTER TABLE {$tb} ";
if(in_array($v['name'],$cur_fields)){
$alterSql.=' MODIFY ';
}else{
$alterSql.=' ADD ';
}
$alterSql.=" `{$v['name']}` {$v['type']} {$v['notnull']} {$v['default']} {$v['autoinc']}";
if(empty($primarys)&&$v['primary']){
$alterSql.=' PRIMARY KEY';
}
db()->execute($alterSql);
}
if(!empty($primarys)){
db()->execute("alter table {$tb} drop primary key,add primary key(".implode(',', $primarys).')');
}
}
}
foreach ($error_indexes as $tb=>$tb_indexes){
foreach ($tb_indexes as $index_name=>$each_index){
$each_index['type']=strtolower($each_index['type']);
$add_sql=" add ";
$drop_sql="alter table {$tb} drop ";
switch ($each_index['type']){
case 'primary':$add_sql.='primary key';$drop_sql.='primary key';break;
case 'unique':$add_sql.="unique `{$index_name}`";$drop_sql.="index `{$index_name}`";break;
case 'index':$add_sql.="index `{$index_name}`";$drop_sql.="index `{$index_name}`";break;
case 'fulltext':$add_sql.="fulltext `{$index_name}`";$drop_sql.="index `{$index_name}`";break;
default:$add_sql='';$drop_sql='';break;
}
if(!empty($add_sql)){
$add_sql.=" (".implode(',',$each_index['field']).")";
}
if($each_index['type']=='primary'){
try {
if(!empty($drop_sql)&&!empty($add_sql)){
db()->execute($drop_sql.','.$add_sql);
}
}catch (\Exception $ex){
}
}else{
if(!empty($drop_sql)){
try {
db()->execute($drop_sql);
}catch (\Exception $ex){
}
}
if(!empty($add_sql)){
$add_sql="alter table {$tb} ".$add_sql;
try {
db()->execute($add_sql);
}catch (\Exception $ex){
}
}
}
}
}
}catch (\Exception $ex){
$this->error($ex->getMessage());
}
$this->success('修复完毕,请再次校验!');
}
}
}else{
$GLOBALS['content_header']='校验数据库';
$GLOBALS['breadcrumb']=breadcrumb(array('校验数据库'));
return $this->fetch();
}
}
public function json_treeAction(){
if(request()->isPost()){
$url=input('url','','trim');
$json='';
if(!empty($url)){
$json=get_html($url);
}
$this->success('','',array('json'=>$json));
}
$GLOBALS['content_header']='JSON解析';
$GLOBALS['breadcrumb']=breadcrumb(array('JSON解析'));
return $this->fetch();
}
}

View File

@ -0,0 +1,155 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
class Upgrade extends BaseController{
public $oldFilePath='';
public $newFilePath='';
public function __construct(){
parent::__construct();
set_time_limit(3600);
$this->oldFilePath=config('root_path').'/data/program/backup/skycaiji'.$GLOBALS['config']['version'];
$this->newFilePath=config('root_path').'/data/program/upgrade/skycaiji'.$GLOBALS['config']['version'];
}
/*检测更新*/
public function newVersionAction(){
$version=get_html('http://www.skycaiji.com/upgrade/program/version?v='.SKYCAIJI_VERSION,null,null,'utf-8');
$version=json_decode($version,true);
$new_version=trim($version['new_version']);
$cur_version=$GLOBALS['config']['version'];
if(version_compare($new_version,$cur_version)>=1){
$this->success('',null,$version);
}else{
$this->error();
}
}
/*
* 下载的文件完整性检测
* 注意:执行该方法时,旧代码已经编译了,替换文件后还是执行的旧文件代码
* 还要注意thinkphp缓存的问题
* */
public function downCompleteAction(){
$downFileList=$this->_getNewFiles();
$errorFiles=array();
foreach ($downFileList as $file){
$filename=$this->newFilePath.$file['file'];
if(!file_exists($filename)){
$errorFiles[]=$file['file'];
}else{
$filemd5=md5_file($filename);
if($filemd5!=$file['md5']){
$errorFiles[]=$file['file'];
}
}
}
if(!empty($errorFiles)){
$errorFiles=array_unique($errorFiles);
$this->error('',null,$errorFiles);
}else{
foreach ($downFileList as $file){
$content=file_get_contents($this->newFilePath.$file['file']);
write_dir_file(config('root_path').$file['file'],$content);
}
$upgradeDb=new \skycaiji\install\event\UpgradeDb();
$upgradeResult=$upgradeDb->run();
if($upgradeResult['success']){
$this->success();
}else{
$this->error();
}
}
}
/*下载文件*/
public function downFileAction(){
$fileName=input('filename');
$filemd5=input('filemd5');
if(file_exists($this->newFilePath.$fileName)){
if($filemd5==md5_file($this->newFilePath.$fileName)){
$this->success();
}
}
$fileUrl='http://www.skycaiji.com/upgrade/program/getFile?filename='.rawurlencode(base64_encode($fileName));
$result=\Requests::get($fileUrl,array(),array('timeout'=>100));
if(200==$result->status_code){
$newFile=$result->body;
$oldFile=file_get_contents(config('root_path').$fileName);
if(!empty($oldFile)){
write_dir_file($this->oldFilePath.$fileName,$oldFile);
}
write_dir_file($this->newFilePath.$fileName,$newFile);
$newFilemd5=md5_file($this->newFilePath.$fileName);
if($newFilemd5==$filemd5){
$this->success();
}else{
$this->error('文件校验失败:'.$fileName);
}
}else{
$this->error('文件下载失败:'.$fileName);
}
$this->error();
}
/*获取升级、更新的文件*/
public function newFilesAction(){
$downFileList=$this->_getNewFiles();
if(empty($downFileList)){
$this->error();
}else{
$this->success('',null,array('files'=>$downFileList));
}
}
public function _getNewFiles(){
$md5Files=array();
program_filemd5_list(config('root_path'),$md5Files);
$md5FileList=array();
foreach ($md5Files as $k=>$v){
$md5FileList[md5($v['file'])]=$v;
}
unset($md5Files);
$newFileList=get_html('http://www.skycaiji.com/upgrade/program/files',null,array('timeout'=>100),'utf-8');
$newFileList=json_decode($newFileList,true);
$downFileList=array();
foreach ($newFileList as $newFile){
$filenameMd5=md5($newFile['file']);
if(isset($md5FileList[$filenameMd5])){
if($md5FileList[$filenameMd5]['md5']!=$newFile['md5']||$md5FileList[$filenameMd5]['file']!=$newFile['file']){
$downFileList[]=$newFile;
}
}else{
$downFileList[]=$newFile;
}
}
return empty($downFileList)?null:$downFileList;
}
}

View File

@ -0,0 +1,179 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\controller;
class User extends BaseController {
public function listAction(){
$muser=model('User');
$page=input('p/d',1);
$page=max(1,$page);
$limit=20;
$count=$muser->count();
$userList=$muser->order('uid asc')->paginate($limit);
$pagenav = $userList->render();
$this->assign('pagenav',$pagenav);
$userList=$userList->all();
$GLOBALS['content_header']=lang('user_list');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list'))));
$groupList=model('Usergroup')->column('*','id');
$this->assign('userList',$userList);
$this->assign('groupList',$groupList);
return $this->fetch();
}
public function addAction(){
$muser=model('User');
$musergroup=model('Usergroup');
if(request()->isPost()){
if(!check_usertoken()){
$this->error(lang('usertoken_error'));
}
if($GLOBALS['config']['site']['verifycode']){
$verifycode=trim(input('verifycode'));
$check=check_verify($verifycode);
if(!$check['success']){
$this->error($check['msg']);
}
}
$newData=array(
'username'=>input('username'),
'password'=>input('password'),
'repassword'=>input('repassword'),
'email'=>input('email'),
'groupid'=>input('groupid/d',0)
);
$check=$muser->add_check($newData);
if(!$check['success']){
$this->error($check['msg']);
}
$newData['password']=pwd_encrypt($newData['password']);
$newGroup=$musergroup->getById($newData['groupid']);
if($musergroup->user_level_limit($newGroup['level'])){
$this->error('您不能添加“'.$GLOBALS['user']['group']['name'].'”用户组');
}
$newData['regtime']=NOW_TIME;
$muser->allowField(true)->save($newData);
if($muser->uid>0){
$this->success(lang('op_success'),'User/list');
}else{
$this->error(lang('op_failed'));
}
}else{
$subGroupList=$musergroup->get_sub_level($GLOBALS['user']['groupid']);
$GLOBALS['content_header']=lang('user_add');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list')),lang('user_add')));
$this->assign('subGroupList',$subGroupList);
return $this->fetch();
}
}
public function editAction(){
$uid=input('uid/d',0);
if(empty($uid)){
$this->error(lang('user_error_null_uid'));
}
$muser=model('User');
$musergroup=model('Usergroup');
$userData=$muser->getByUid($uid);
if(empty($userData)){
$this->error(lang('user_error_empty_user'));
}
$userData['group']=$musergroup->getById($userData['groupid']);
$isOwner=($GLOBALS['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'));
}
if($GLOBALS['config']['site']['verifycode']){
$verifycode=trim(input('verifycode'));
$check=check_verify($verifycode);
if(!$check['success']){
$this->error($check['msg']);
}
}
$newData=array(
'password'=>input('password'),
'repassword'=>input('repassword'),
'email'=>input('email'),
'groupid'=>input('groupid/d',0)
);
if(empty($newData['password'])){
unset($newData['password']);
unset($newData['repassword']);
}
$check=$muser->edit_check($newData);
if(!$check['success']){
$this->error($check['msg']);
}
if(!empty($newData['password'])){
$newData['password']=pwd_encrypt($newData['password']);
}
$newGroup=$musergroup->getById($newData['groupid']);
if($musergroup->user_level_limit($newGroup['level'])){
$this->error('您不能改为“'.$GLOBALS['user']['group']['name'].'”用户组');
}
if($isOwner||empty($newData['groupid'])){
unset($newData['groupid']);
}
$muser->allowField(true)->save($newData,array('uid'=>$uid));
$this->success(lang('op_success'),'User/list');
}else{
$this->assign('userData',$userData);
$subGroupList=$musergroup->get_sub_level($GLOBALS['user']['groupid']);
$this->assign('subGroupList',$subGroupList);
$this->assign('isOwner',$isOwner);
$GLOBALS['content_header']=lang('user_edit');
$GLOBALS['breadcrumb']=breadcrumb(array(array('url'=>url('User/list'),'title'=>lang('user_list')),lang('user_edit')));
return $this->fetch();
}
}
public function deleteAction(){
$uid=input('uid/d',0);
if(empty($uid)){
$this->error(lang('user_error_null_uid'));
}
$muser=model('User');
$musergroup=model('Usergroup');
$userData=$muser->getByUid($uid);
if(empty($userData)){
$this->error(lang('user_error_empty_user'));
}
if($userData['uid']==$GLOBALS['user']['uid']){
$this->error('不能删除自己');
}
$userData['group']=$musergroup->getById($userData['groupid']);
if($musergroup->user_level_limit($userData['group']['level'])){
$this->error('您不能删除“'.$userData['group']['name'].'”组的用户');
}
$muser->where(array('uid'=>$uid))->delete();
$this->success(lang('op_success'),'User/list');
}
}

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,213 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\event;
abstract class Collector extends \skycaiji\admin\controller\BaseController {
/*防止执行采集时出现错误模板后终止采集*/
public function error($msg = '', $url = null, $data = array(), $wait = 3, array $header = []){
if(is_collecting()){
parent::echo_msg($msg,'red');
return null;
}else{
parent::error($msg,$url,$data,$wait,$header);
}
}
/*采集器的输出内容需要重写,只有正在采集时才输出内容*/
public function echo_msg($str,$color='red',$echo=true,$end_str=''){
if(is_collecting()){
parent::echo_msg($str,$color,$echo,$end_str);
}
}
/**
* 优化设置页面post过来的config
* @param unknown $config
*/
public abstract function setConfig($config);
/**
* 初始化配置
* @param unknown $config
*/
public abstract function init($config);
/**
* 采集数据
* @param unknown $num 采集条数
*/
public abstract function collect($num=10);
/**
* 测试数据
public abstract function test();
*/
/*设置抓取页面间隔*/
public function set_html_interval(){
if(is_collecting()){
if($GLOBALS['config']['caiji']['html_interval']>0){
sleep($GLOBALS['config']['caiji']['html_interval']);
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 unknown $url
* @param unknown $html
* @return Ambigous <NULL, string>
*/
public function match_base_url($url,$html){
if(preg_match('/<base[^<>]*href=[\'\"](?P<base>[^\<\>\"\']*?)[\'\"]/i', $html,$base_url)){
$base_url=$base_url['base'];
}else{
$base_url=preg_replace('/[\#\?][^\/]*$/', '', $url);
if(preg_match('/^\w+\:\/\/([\w\-]+\.){1,}[\w]+\/.+/',$base_url)&&preg_match('/\.[a-z]+$/i', $base_url)){
$base_url=preg_replace('/\/[^\/]*\.[a-z]+$/', '', $base_url);
}
}
$base_url=rtrim($base_url,'/');
return $base_url?$base_url:null;
}
/**
* 匹配域名
* @param unknown $url
* @return Ambigous <NULL, string>
*/
public function match_domain_url($url){
if(preg_match('/^\w+\:\/\/([\w\-]+\.){1,}[\w]+/', $url,$domain_url)){
$domain_url=rtrim($domain_url[0],'/');
}
return $domain_url?$domain_url:null;
}
/**
* 生成完整网址
* @param $url 要填充的网址
* @param $base_url 根目录网址
* @param $domain_url 域名
*/
public function create_complete_url($url,$base_url,$domain_url){
if(preg_match('/^\w+\:\/\//', $url)){
return $url;
}elseif(strpos($url,'//')===0){
$url='https:'.$url;
}elseif(strpos($url,'/')===0){
$url=$domain_url.'/'.ltrim($url,'/');
}elseif(stripos($url,'javascript')===0||stripos($url,'#')===0){
$url='';
}elseif(!preg_match('/^\w+\:\/\//', $url)){
$url=$base_url.'/'.ltrim($url,'/');
}
return $url;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
/*发布设置:本地cms*/
namespace skycaiji\admin\event;
use skycaiji\admin\model\CacheModel;
class Rapi extends Release{
/**
* 设置页面post过来的config
* @param unknown $config
*/
public function setConfig($config){
$api=input('api/a');
$api['url']=trim($api['url'],'\/\\');
$api['cache_time']=intval($api['cache_time']);
$api['hide_fields']=is_array($api['hide_fields'])?$api['hide_fields']:array();
if(empty($api['url'])){
$this->error('请输入api地址');
}
if(!preg_match('/^[a-zA-Z0-9\-\_]+$/i', $api['url'])){
$this->error('api地址只能由字母、数字、下划线组成');
}
$config['api']=$api;
return $config;
}
/*导出数据*/
public function export($collFieldsList,$options=null){
if(!is_array($collFieldsList)){
$collFieldsList=array();
}
$contUrls=array();
foreach ($collFieldsList as $v){
$contUrls[]=md5($v['url']);
}
if(!empty($contUrls)){
$mcacheCont=CacheModel::getInstance('cont_url');
$mcacheCont->db()->where('cname','in',$contUrls)->delete();
}
$this->hide_coll_fields($this->config['api']['hide_fields'],$collFieldsList);
$this->set_cache_fields($collFieldsList);
json($collFieldsList)->send();
exit();
}
/*设置缓存数据*/
public function set_cache_fields($collFieldsList){
if(!empty($this->config['api']['cache_time'])){
$mcache=CacheModel::getInstance('task_api');
if($mcache->expire($this->release['task_id'],$this->config['api']['cache_time']*60)){
$mcache->setCache($this->release['task_id'], $collFieldsList);
}
}
}
/*获取缓存数据*/
public function get_cache_fields(){
if(!empty($this->config['api']['cache_time'])){
$mcache=CacheModel::getInstance('task_api');
if(!$mcache->expire($this->release['task_id'],$this->config['api']['cache_time']*60)){
$data=$mcache->getCache($this->release['task_id'],'data');
return empty($data)?array():$data;
}else{
return false;
}
}else{
return false;
}
}
}
?>

View File

@ -0,0 +1,157 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
/*发布设置:本地cms*/
namespace skycaiji\admin\event;
class Rcms extends Release{
/**
* 设置页面post过来的config
* @param unknown $config
*/
public function setConfig($config){
$config['cms']=input('cms/a');
$config['cms_app']=input('cms_app/a');
if(empty($config['cms']['path'])){
$this->error('cms路径不能为空');
}
if(empty($config['cms']['app'])){
$this->error('cms插件不能为空');
}
if(empty($config['cms']['name'])){
$config['cms']['name']=$this->cms_name($config['cms']['path']);
}
if(!model('ReleaseApp')->appFileExists($config['cms']['app'],'cms')){
if(model('ReleaseApp')->oldFileExists($config['cms']['app'],'Cms')){
$this->error(lang('release_upgrade'));
}else{
$this->error('抱歉,插件文件不存在');
}
}
$releCms=model('ReleaseApp')->appImportClass($config['cms']['app'],'cms');
$releCms->init($config['cms']['path']);
$releCms->runCheck($config['cms_app']);
return $config;
}
/*导出数据*/
public function export($collFieldsList,$options=null){
if(!model('ReleaseApp')->appFileExists($this->config['cms']['app'],'cms')){
if(model('ReleaseApp')->oldFileExists($this->config['cms']['app'],'Cms')){
$this->echo_msg(lang('release_upgrade'));
exit();
}else{
$this->echo_msg('没有cms发布插件'.$this->config['cms']['app']);
exit();
}
}
$releCms=model('ReleaseApp')->appImportClass($this->config['cms']['app'],'cms');
$releCms->init(null,$this->release);
$addedNum=0;
foreach ($collFieldsList as $collFieldsKey=>$collFields){
$return=$releCms->runExport($collFields['fields']);
if($return['id']>0){
$addedNum++;
}
$this->record_collected($collFields['url'],$return,$this->release,$collFields['title']);
unset($collFieldsList[$collFieldsKey]['fields']);
}
return $addedNum;
}
/*获取cms名字*/
public function cms_name($cmsPath){
list($cmsPath,$cmsPathName)=explode('@', $cmsPath);
$cmsPath=realpath($cmsPath);
if(empty($cmsPath)){
return '';
}
static $cmsNames=array();
$md5Path=md5($cmsPath);
if(!isset($cmsNames[$md5Path])){
$cmsName='';
if(!empty($cmsPathName)){
$cmsName=$cmsPathName;
}else{
$cmsFiles=$this->cms_files();
foreach ($cmsFiles as $cms=>$cmsFile){
$cmsFile=realpath($cmsPath.'/'.$cmsFile);
if(!empty($cmsFile)&&file_exists($cmsFile)){
$cmsName=$cms;
break;
}
}
}
$cmsNames[$md5Path]=$cmsName;
}
return $cmsNames[$md5Path];
}
/*获取cms名字列表*/
public function cms_name_list($cmsPath,$return=false){
$cmsPath=realpath($cmsPath);
static $list=array();
if($return){
foreach ($list as $cms=>$files){
$files=array_unique($files);
$files=array_filter($files);
$files=array_values($files);
$list[$cms]=$files;
}
return empty($list)?array():$list;
}
if(!empty($cmsPath)){
$cmsName=$this->cms_name($cmsPath);
if(!empty($cmsName)){
$list[$cmsName][]=$cmsPath;
}
}
}
/*cms文件*/
public function cms_files(){
static $files=array (
'discuz'=>'source/class/discuz/discuz_core.php',
'wordpress'=>'wp-includes/wp-db.php',
'dedecms'=>'include/dedetemplate.class.php',
'empirecms'=>'e/class/EmpireCMS_version.php',
'phpcms'=>'phpcms/base.php',
'destoon'=>'api/oauth/destoon.inc.php',
'ecshop'=>'includes/cls_ecshop.php',
'shopex'=>'plugins/app/shopex_stat/shopex_stat_modifiers.php',
'espcms'=>'adminsoft/include/inc_replace_mailtemplates.php',
'metinfo'=>'config/metinfo.inc.php',
'twcms'=>'twcms/config/config.inc.php',
'zblog'=>'zb_system/function/lib/zblogphp.php',
'phpwind'=>'actions/pweditor/modifyattach.php',
'xiunobbs'=>'xiunophp/xiunophp.php',
'skyuc'=>'includes/modules/integrates/skyuc.php',
'jieqicms'=>'themes/jieqidiv/theme.html',
'hadsky'=>'app/hadskycloudserver/index.php',
'mipcms'=>'app/article/Mipcms.php',
'maccms'=>'application/extra/maccms.php',
);
return $files;
}
}
?>

View File

@ -0,0 +1,230 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
/*发布设置:本地cms*/
namespace skycaiji\admin\event;
use skycaiji\admin\model\DbCommon;
class Rdb extends Release{
protected $db_conn_list=array();
/**
* 设置页面post过来的config
* @param unknown $config
*/
public function setConfig($config){
$db=input('db/a','','trim');
foreach ($db as $k=>$v){
if(empty($v)&&'pwd'!=$k){
$this->error(lang('error_null_input',array('str'=>lang('rele_db_'.$k))));
}
}
$config['db']=$db;
$config['db_table']=input('db_table/a','','trim');
if(is_array($config['db_table'])&&is_array($config['db_table']['field'])){
foreach($config['db_table']['field'] as $tbName=>$tbFields){
if(is_array($tbFields)){
foreach ($tbFields as $tbField=>$fieldVal){
if(empty($fieldVal)){
unset($config['db_table']['field'][$tbName][$tbField]);
unset($config['db_table']['custom'][$tbName][$tbField]);
continue;
}
}
}
}
}
return $config;
}
/*导出数据*/
public function export($collFieldsList,$options=null){
$db_config=$this->get_db_config($this->config['db']);
$db_key=md5(serialize($db_config));
if(empty($this->db_conn_list[$db_key])){
$mdb=new DbCommon($db_config);
$mdb=$mdb->db();
$this->db_conn_list[$db_key]=$mdb;
}else{
$mdb=$this->db_conn_list[$db_key];
}
$addedNum=0;
$dbCharset=strtolower($db_config['db_charset']);
if(empty($dbCharset)||$dbCharset=='utf-8'||$dbCharset=='utf8'){
$dbCharset=null;
}
foreach ($collFieldsList as $collFieldsKey=>$collFields){
$mdb->startTrans();
$contTitle=$collFields['title'];
$contUrl=$collFields['url'];
$collFields=$collFields['fields'];
$tableFields=array();
foreach ($this->config['db_table']['field'] as $tbName=>$tbFields){
foreach ($tbFields as $tbField=>$fieldVal){
if(empty($fieldVal)){
unset($tbFields[$tbField]);
continue;
}
if(strcasecmp('custom:',$fieldVal)==0){
$fieldVal=$this->config['db_table']['custom'][$tbName][$tbField];
}elseif(preg_match('/^field\:(.+)$/ui',$fieldVal,$collField)){
$fieldVal=$this->get_field_val($collFields[$collField[1]]);
$fieldVal=is_null($fieldVal)?'':$fieldVal;
}
if(!empty($dbCharset)){
$fieldVal=$this->utf8_to_charset($dbCharset, $fieldVal);
}
$tbFields[$tbField]=$fieldVal;
}
$tableFields[$tbName]=$tbFields;
}
if(!empty($tableFields)){
if('oracle'==$db_config['db_type']){
$pdoOracle=new \PDO($db_config['db_dsn'], $db_config['db_user'], $db_config['db_pwd'],array());
$pdoOracle->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
$errorMsg=false;
$autoidList=array();
foreach ($tableFields as $table=>$fields){
$table=strtolower($table);
foreach ($fields as $k=>$v){
if(preg_match('/^auto_id\@([^\s]+)$/i', $v,$autoidTbName)){
$autoidTbName=trim($autoidTbName[1]);
$autoidTbName=strtolower($autoidTbName);
$fields[$k]=$autoidList[$autoidTbName];
}
}
try {
if('oracle'==$db_config['db_type']){
$insertSql='insert into '.$table.' ';
$insertKeys=array();
$insertVals=array();
$sequenceName='';
foreach ($fields as $k=>$v){
if(preg_match('/^sequence\@([^\s]+)$/i', $v,$m_sequence)){
$sequenceName=$m_sequence[1];
continue;
}
$insertKeys[]=$k;
$insertVals[]="'".str_replace("'", "''", $v)."'";
}
$insertSql.='('.implode(',', $insertKeys).') values ('.implode(',', $insertVals).')';
if($pdoOracle->exec($insertSql)){
if(!empty($sequenceName)){
$autoId=$pdoOracle->query("select {$sequenceName}.CURRVAL as id FROM DUAL");
if($autoId){
$autoId=$autoId->fetch();
$autoidList[$table]=$autoId[0];
}
}
if(empty($autoidList[$table])){
$autoidList[$table]=1;
}
}else{
$autoidList[$table]=0;
}
}else{
$autoidList[$table]=$mdb->table($table)->insert($fields,false,true);
}
}catch (\Exception $ex){
$errorMsg=$ex->getMessage();
$this->echo_msg($errorMsg);
$errorMsg=!empty($errorMsg)?$errorMsg:($table.'表入库失败');
break;
}
if($autoidList[$table]<=0){
break;
}
}
$returnData=array('id'=>0);
if(!empty($errorMsg)){
$mdb->rollback();
$returnData['error']=$errorMsg;
}else{
$mdb->commit();
reset($autoidList);
list($firstTable,$firstId) = each($autoidList);
$firstId=intval($firstId);
if($firstId>0){
$addedNum++;
$returnData['id']=$firstId;
$returnData['target']="{$db_config['db_type']}:{$db_config['db_name']}@table:{$firstTable}@id:{$firstId}";
}else{
$returnData['error']='数据插入失败';
}
}
$this->record_collected($contUrl,$returnData,$this->release,$contTitle);
}
unset($collFieldsList[$collFieldsKey]['fields']);
}
return $addedNum;
}
/*将发布配置中的数据库参数转换成thinkphp数据库参数*/
public function get_db_config($config_db){
$db_config=array(
'db_type' => strtolower($config_db['type']),
'db_user' => $config_db['user'],
'db_pwd' => $config_db['pwd'],
'db_host' => $config_db['host'],
'db_port' => $config_db['port'],
'db_charset' => $config_db['charset'],
'db_name' => $config_db['name']
);
if(strcasecmp($db_config['db_charset'], 'utf-8')===0){
$db_config['db_charset']='utf8';
}
if('mysqli'==$db_config['db_type']){
$db_config['db_type']='mysql';
}elseif('oracle'==$db_config['db_type']){
$db_config['db_dsn']="oci:host={$db_config['db_host']};dbname={$db_config['db_name']};charset={$db_config['db_charset']}";
}elseif('sqlsrv'==$db_config['db_type']){
$db_config['db_dsn']='sqlsrv:Database='.$db_config['db_name'].';Server='.$db_config['db_host'];
}
return $db_config;
}
}
?>

View File

@ -0,0 +1,120 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
/*发布设置:diy*/
namespace skycaiji\admin\event;
class Rdiy extends Release{
/**
* 设置页面post过来的config
* @param unknown $config
*/
public function setConfig($config){
$diy=input('diy/a','','trim');
if(!in_array($diy['type'],array('app','code'))){
$this->error('类型错误');
}
if($diy['type']=='app'){
$diy['app']=strtolower(trim($diy['app'],'\/\\'));
if(empty($diy['app'])){
$this->error('请输入插件名称');
}
if(in_array($diy['app'], array('base','code'))){
$this->error($diy['app'].'为系统保留名称,不能使用');
}
if(!preg_match('/^[a-z][a-z0-9]+$/i', $diy['app'])){
$this->error('插件名称必须以字母开头且由字母或数字组成');
}
}elseif($diy['type']=='code'){
if(empty($diy['code'])){
$this->error('请输入PHP代码');
}
}
$config['diy']=$diy;
return $config;
}
/*导出数据*/
public function export($collFieldsList,$options=null){
try {
$appName='';
$releDiy='';
if($this->config['diy']['type']=='app'){
$appName=strtolower($this->config['diy']['app']);
}elseif($this->config['diy']['type']=='code'){
$appName='CodeDiy';
}
if(!empty($appName)){
if(model('ReleaseApp')->appFileExists($appName,'diy')){
$releDiy=model('ReleaseApp')->appImportClass($appName,'diy');
$releDiy->init($this->release);
}elseif(model('ReleaseApp')->oldFileExists($appName,'diy')){
$this->echo_msg(lang('release_upgrade'));
exit();
}
}
if(empty($releDiy)){
$this->echo_msg('没有自定义插件:'.$appName);
exit();
}
}catch (\Exception $ex){
$this->echo_msg($ex->getMessage());
exit();
}
$addedNum=0;
foreach ($collFieldsList as $collFieldsKey=>$collFields){
$releDiy->db()->startTrans();
$errorMsg=false;
$contUrl=$collFields['url'];
try {
$return=$releDiy->runExport($contUrl,$collFields['fields']);
if(empty($return)){
continue;
}
}catch (\Exception $ex){
$return=array();
$errorMsg=$ex->getMessage();
$this->echo_msg($ex->getMessage());
break;
}
$return=empty($return)?array('id'=>0):$return;
if(!empty($errorMsg)){
$return['error']=$errorMsg;
}
$returnData=array();
if(!empty($return['error'])){
$releDiy->db()->rollback();
$returnData=array('id'=>0,'error'=>$errorMsg);
}else{
$releDiy->db()->commit();
$returnData=$return;
unset($returnData['error']);
if($returnData['id']>0){
$addedNum++;
}else{
$returnData['error']='数据插入失败';
}
}
$this->record_collected($contUrl,$returnData,$this->release,$collFields['title']);
unset($collFieldsList[$collFieldsKey]['fields']);
}
return $addedNum;
}
}
?>

View File

@ -0,0 +1,42 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\event;
abstract class Release extends ReleaseBase{
public $release;
public $config;
public $task;
/*发布时初始化*/
public function init($release){
if(!is_array($release['config'])){
$release['config']=unserialize($release['config']);
}
$this->release=$release;
$this->config=$release['config'];
$this->task=model('Task')->getById($this->release['task_id']);
if(empty($this->task)){
$this->error(lang('task_error_empty_task'));
}
}
/**
* 优化设置页面post过来的config
* @param unknown $config 页面配置
*/
public abstract function setConfig($config);
/**
* 导出数据
* @param unknown $collFieldsList 采集到的字段数据列表
* @param unknown $options 选项
*/
public abstract function export($collFieldsList,$options=null);
}
?>

View File

@ -0,0 +1,263 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\event;
use skycaiji\admin\model\CacheModel;
class ReleaseBase extends \skycaiji\admin\controller\BaseController{
/*已采集记录*/
public function record_collected($url,$returnData,$release,$title=null,$echo=true){
if($returnData['id']>0){
model('Collected')->insert(array(
'url' => $url,
'urlMd5' => md5 ( $url ),
'titleMd5'=>empty($title)?'':md5($title),
'target' => $returnData['target'],
'desc' => $returnData['desc']?$returnData['desc']:'',
'error'=>'',
'task_id' => $release ['task_id'],
'release' => $release['module'],
'addtime'=>time()
));
if(!empty($returnData['target'])){
$target=$returnData['target'];
if(preg_match('/^http(s){0,1}\:\/\//i',$target)){
$target='<a href="'.$target.'" target="_blank">'.$target.'</a>';
}
$this->echo_msg("成功将<a href='{$url}' target='_blank'>内容</a>发布至:{$target}",'green',$echo);
}else{
$this->echo_msg("成功发布:<a href='{$url}' target='_blank'>{$url}</a>",'green',$echo);
}
}else{
if(!empty($returnData['error'])){
if(model('Collected')->getCountByUrl($url)<=0){
model('Collected')->insert(array(
'url' => $url,
'urlMd5' => md5 ( $url ),
'titleMd5'=>'',
'target' => '',
'desc'=>'',
'error' => $returnData['error'],
'task_id' => $release ['task_id'],
'release' => $release['module'],
'addtime'=>time()
));
}
$this->echo_msg($returnData['error']."<a href='{$url}' target='_blank'>{$url}</a>",'red',$echo);
}
}
static $mcacheCont=null;
if(!isset($mcacheCont)){
$mcacheCont=CacheModel::getInstance('cont_url');
}
$mcacheCont->db()->where('cname',md5($url))->delete();
}
/*获取字段值*/
public function get_field_val($collFieldVal){
if(empty($collFieldVal)){
return '';
}
$val=$collFieldVal['value'];
if(!empty($GLOBALS['config']['caiji']['download_img'])){
if(!empty($collFieldVal['img'])){
if(!is_array($collFieldVal['img'])){
$collFieldVal['img']=array($collFieldVal['img']);
}
$total=count($collFieldVal['img']);
if($total>0){
$this->echo_msg('正在下载图片','black');
}
$curI=0;
foreach ($collFieldVal['img'] as $imgUrl){
$newImgUrl=$this->download_img($imgUrl);
if($newImgUrl!=$imgUrl){
$val=str_replace($imgUrl, $newImgUrl, $val);
}
$curI++;
if($curI<$total){
if(!empty($GLOBALS['config']['caiji']['img_interval'])){
sleep($GLOBALS['config']['caiji']['img_interval']);
}
}
}
}
}
return $val;
}
/*下载图片*/
public function download_img($url){
static $imgPaths=array();
static $imgUrls=array();
$img_path=$GLOBALS['config']['caiji']['img_path'];
$img_url=$GLOBALS['config']['caiji']['img_url'];
if(!isset($imgPaths[$img_path])){
if(empty($img_path)){
$imgPaths[$img_path]=config('root_path').'/data/images/';
}else{
$imgPaths[$img_path]=rtrim($img_path,'\/\\').'/';
}
}
$img_path=$imgPaths[$img_path];
if(!isset($imgUrls[$img_url])){
if(empty($img_url)){
$imgUrls[$img_url]=config('root_website').'/data/images/';
}else{
$imgUrls[$img_url]=rtrim($img_url,'\/\\').'/';
}
}
$img_url=$imgUrls[$img_url];
if(empty($url)){
return '';
}
if(!preg_match('/^\w+\:\/\//',$url)){
return $url;
}
static $imgList=array();
$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';
}
$filename='';
$imgurl='';
$imgname='';
if('url'==$GLOBALS['config']['caiji']['img_name']){
$imgname=substr($key,0,2).'/'.substr($key,-2,2).'/';
}else{
$imgname=date('Y-m-d',NOW_TIME).'/';
}
$imgname.=$key.'.'.$prop;
$filename=$img_path.$imgname;
$imgurl=$img_url.$imgname;
if(!file_exists($filename)){
$mproxy=model('Proxyip');
try {
$options=array();
if(!empty($GLOBALS['config']['caiji']['img_timeout'])){
$options['timeout']=$GLOBALS['config']['caiji']['img_timeout'];
}
if(!empty($GLOBALS['config']['proxy']['open'])){
$proxy_ip=$mproxy->get_usable_ip();
$proxyIp=$mproxy->to_proxy_ip($proxy_ip);
if(!empty($proxyIp)){
$options['proxy']=$proxyIp;
}
}
if(!empty($GLOBALS['config']['caiji']['img_max'])){
$options['max_bytes']=intval($GLOBALS['config']['caiji']['img_max'])*1024*1024;
}
$imgCode=get_html($url,null,$options,'utf-8');
if(!empty($imgCode)){
if(write_dir_file($filename,$imgCode)){
$imgList[$key]=$imgurl;
}
}
}catch (\Exception $ex){
}
}else{
$imgList[$key]=$imgurl;
}
}
return empty($imgList[$key])?$url:$imgList[$key];
}
/*获取采集器字段*/
public function get_coll_fields($taskId,$taskModule){
static $fieldsList=array();
$key=$taskId.'__'.$taskModule;
if(!isset($fieldsList[$key])){
$mcoll=model('Collector');
$collData=$mcoll->where(array('task_id'=>$taskId,'module'=>$taskModule))->find();
if(!empty($collData)){
$collData=$collData->toArray();
$collData['config']=unserialize($collData['config']);
$collFields=array();
if(is_array($collData['config']['field_list'])){
foreach ($collData['config']['field_list'] as $collField){
$collFields[]=$collField['name'];
}
}
$fieldsList[$key]=$collFields;
}
}
return $fieldsList[$key];
}
/*隐藏采集字段(删除字段)*/
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]);
}
}
}
}
/*utf8转换成其他编码*/
public function utf8_to_charset($charset,$val){
static $chars=array('utf-8','utf8','utf8mb4');
if(!in_array(strtolower($charset),$chars)){
if(!empty($val)){
$val=iconv('utf-8',$charset.'//IGNORE',$val);
}
}
return $val;
}
/*任意编码转换成utf8*/
public function auto_convert2utf8($arr){
$arr=array_array_map('auto_convert2utf8',$arr);
return $arr;
}
/*写入文件*/
public function write_file($filename,$data){
return write_dir_file($filename,$data);
}
}
?>

View File

@ -0,0 +1,142 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
/*发布设置:本地cms*/
namespace skycaiji\admin\event;
class Rfile extends Release {
/**
* 设置页面post过来的config
* @param unknown $config
*/
public function setConfig($config){
$file=input('file/a');
$file['path']=trim($file['path'],'\/\\');
$file['hide_fields']=is_array($file['hide_fields'])?$file['hide_fields']:array();
if(empty($file['path'])){
$this->error('请输入文件存放目录');
}
if(!preg_match('/^[a-zA-Z0-9\-\_]+$/i', $file['path'])){
$this->error('目录只能由字母、数字、下划线组成');
}
if(empty($file['type'])){
$this->error('请选择文件格式');
}
$config['file']=$file;
return $config;
}
/*导出数据*/
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->hide_coll_fields($this->config['file']['hide_fields'],$collFieldsList);
$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=$filepath.'/'.$filename;
$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();
}
if(!file_exists($filename)){
write_dir_file( $filename, null);
$newPhpExcel=new \PHPExcel();
$sheet1 = new \PHPExcel_Worksheet($newPhpExcel, 'Sheet1');
$newPhpExcel->addSheet($sheet1);
$newPhpExcel->setActiveSheetIndex(0);
$firstFields=reset($collFieldsList);
$firstFields=array_keys($firstFields['fields']);
foreach ($firstFields as $k=>$v){
$newPhpExcel->getActiveSheet()->setCellValue(chr(65+$k).'1',$v);
}
$newWriter = \PHPExcel_IOFactory::createWriter($newPhpExcel,$excelType);
$newWriter->save($filename);
unset($newWriter);
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){
$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);
}elseif('txt'==$this->config['file']['type']){
$txtLine=0;
if(file_exists($filename)){
$fpTxt=fopen($filename,'r');
while(!feof($fpTxt)) {
if(($fpData=fread($fpTxt,1024*1024*2))!=false){
$txtLine+=substr_count($fpData,"\r\n");
}
}
fclose($fpTxt);
}else{
write_dir_file( $filename, null);
}
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']);
}
}
return $addedNum;
}
}
?>

View File

@ -0,0 +1,301 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
return array(
'admincp'=>'后台',
'sign_wildcard'=>'(*)',
'sign_match'=>'[内容{:num}]',
'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_regular'=>'可使用正则表达式',
'setting'=>'设置',
'setting_site'=>'站点设置',
'set_site_verifycode'=>'开启图片验证码',
'setting_caiji'=>'采集设置',
'set_caiji_auto'=>'开启自动采集',
'set_caiji_run'=>'自动采集运行方式',
'set_caiji_interval'=>'每次采集间隔时间',
'set_caiji_num'=>'每次采集数量',
'set_caiji_timeout'=>'最大执行时间',
'setting_email'=>'邮件发送设置',
'set_email_sender'=>'发件人名称',
'set_email_email'=>'发件人邮箱账号',
'set_email_pwd'=>'发件人邮箱密码',
'set_email_smtp'=>'SMTP服务器',
'set_email_port'=>'SMTP端口',
'set_email_port_tips'=>'TLS一般为25SSL一般为465咨询邮箱服务商获取',
'set_email_type'=>'SMTP端口类型',
'set_email_test_subject'=>'测试发送邮件',
'set_email_test_body'=>'恭喜,发送邮件成功!',
'config_error_none_email'=>'没有邮箱服务器配置,请在后台设置!',
'user'=>'用户',
'user_list'=>'用户列表',
'user_add'=>'添加用户',
'user_edit'=>'编辑用户',
'user_username'=>'用户名',
'user_password'=>'密码',
'user_repassword'=>'确认密码',
'user_newpwd_tips'=>'如果您想修改密码,请在此输入新密码,否则留空',
'user_email'=>'邮箱',
'user_email_tips'=>'用于找回账号密码',
'user_groupid'=>'用户组',
'user_error_edit_not_allow'=>'只有创始人才能编辑他人的账号!',
'user_error_delete_not_allow'=>'只有创始人才能删除账号!',
'user_error_email'=>'邮箱格式错误!',
'user_error_groupid'=>'不是允许的用户组!',
'user_error_del_founder'=>'不能删除创始人账号!',
'user_error_null_uid'=>'UID不能为空',
'user_error_empty_user'=>'用户不存在',
'user_error_login'=>'用户名或密码不正确!',
'user_error_sublogin'=>'登录提交失败',
'user_error_is_not_admin'=>'抱歉,请登录管理员账号!',
'user_login_in'=>'登录中...',
'user_auto_login'=>'正在自动登录...',
'usertoken_error'=>'用户token错误请刷新页面重新获取',
'task'=>'任务',
'task_add'=>'添加任务',
'task_edit'=>'编辑任务',
'task_list'=>'任务列表',
'task_change_list'=>'切换列表模式',
'task_change_folder'=>'切换分组模式',
'task_name'=>'任务名称',
'task_tg'=>'任务分组',
'task_sort'=>'排序',
'task_sort_help'=>'数字越大越靠前',
'task_module'=>'采集模块',
'task_module_'=>'无',
'task_module_pattern'=>'规则采集',
'task_module_keyword'=>'关键词采集',
'task_module_weixin'=>'微信采集',
'task_auto'=>'自动采集',
'task_addtime'=>'添加时间',
'task_caijitime'=>'采集时间',
'task_edit_collector'=>'下一步:编辑采集器',
'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',
'task_error_empty_tg'=>'不存在分组',
'task_error_null_name'=>'请输入名称!',
'task_error_has_name'=>'名称已经存在!',
'task_error_null_module'=>'未设置采集模块',
'taskgroup_add'=>'添加分组',
'taskgroup_edit'=>'编辑分组',
'taskgroup'=>'任务分组',
'taskgroup_list'=>'分组列表',
'taskgroup_name'=>'分组名称',
'taskgroup_sort'=>'排序',
'taskgroup_sort_help'=>'数字越大越靠前',
'taskgroup_parent_id'=>'父分组',
'tg_add_sub'=>'添加子分组',
'tg_move'=>'移动分组',
'tg_exist_sub'=>'存在子分组!',
'tg_none'=>'分组不存在!',
'tg_is_parent'=>'存在子分组,请先清空子分组,才能移动分组!',
'tg_deleteall_has_sub'=>'有子分组的不能删除,需先清空子分组!',
'tg_no_checked'=>'没有选中的记录!',
'tg_error_null_name'=>'请输入名称!',
'tg_error_has_name'=>'名称已经存在!',
'coll_set'=>'采集器设置',
'coll_edit_task'=>'上一步:编辑任务',
'coll_name'=>'采集规则名称',
'coll_error_invalid_module'=>'无效的采集模块',
'coll_error_empty_coll'=>'不存在采集器',
'coll_error_empty_effective'=>'页面脚本不可用,保存失败!',
'field_module_rule'=>'规则匹配',
'field_module_auto'=>'自动获取',
'field_module_xpath'=>'XPath匹配',
'field_module_words'=>'固定文字',
'field_module_num'=>'随机数字',
'field_module_time'=>'时间',
'field_module_list'=>'随机抽取',
'field_module_json'=>'JSON提取',
'field_module_merge'=>'字段组合',
'field_module_extract'=>'字段提取',
'process_module_html'=>'html标签过滤',
'process_module_replace'=>'内容替换',
'process_module_filter'=>'过滤词',
'process_module_translate'=>'翻译',
'process_module_tool'=>'工具箱',
'process_module_batch'=>'批量替换',
'process_module_substr'=>'截取字符串',
'process_module_func'=>'使用函数',
'rele_set'=>'发布设置',
'rele_error_detect_null'=>'没有检测到本地CMS程序您可以手动绑定数据',
'rele_error_empty_rele'=>'发布设置不存在',
'rele_error_null_module'=>'请选择发布方式',
'rele_error_db'=>'数据库错误:',
'rele_error_no_table'=>'该数据库没有表',
'rele_success_db_ok'=>'数据库连接成功',
'rele_module'=>'发布方式',
'rele_module_cms'=>'本地CMS程序',
'rele_module_db'=>'数据库',
'rele_module_api'=>'API接口',
'rele_module_file'=>'文件存储',
'rele_module_diy'=>'自定义插件',
'rele_btn_detect'=>'开始检测',
'rele_cms_path'=>'CMS路径',
'rele_db_type'=>'数据库类型',
'rele_db_host'=>'数据库主机',
'rele_db_name'=>'数据库名称',
'rele_db_charset'=>'数据库编码',
'rele_db_port'=>'数据库端口',
'rele_db_user'=>'数据库用户',
'rele_db_pwd'=>'数据库密码',
'error_unknown_database'=>'未知的数据库',
'error_null_input'=>'请输入{:str}',
'collected'=>'已采集数据',
'collected_list'=>'已采集数据列表',
'COLLECTED_RELE_'=>'无',
'collected_rele_cms'=>'CMS',
'collected_rele_db'=>'数据库',
'collected_rele_file'=>'文件',
'collected_rele_api'=>'API',
'collected_rele_diy'=>'插件',
'verifycode'=>'验证码',
'verifycode_error'=>'验证码错误!',
'find_password'=>'找回密码',
'find_pwd_username'=>'请输入邮箱/用户名',
'find_pwd_yzm'=>'请输入激活码',
'find_pwd_resend'=>'重新发送',
'find_pwd_next_step'=>'下一步',
'find_pwd_pwd'=>'请输入新密码',
'find_pwd_repwd'=>'确认新密码',
'find_pwd_sended'=>'已向邮箱{:email}发送了激活码!',
'find_pwd_email_failed'=>'发送邮件失败,请检查后台发送邮件配置!',
'find_pwd_email_wait'=>'需等待{:seconds}秒才能再次发送',
'find_pwd_email_subject'=>'找回密码 - 蓝天采集器',
'find_pwd_email_body'=>'您的激活码为:{:yzm},有效时间{:minutes}分钟',
'find_pwd_error_username'=>'请输入邮箱/用户名',
'find_pwd_error_step'=>'步骤错误,请重新操作!',
'find_pwd_error_post'=>'表单提交失败',
'find_pwd_error_none_email'=>'邮箱不存在!',
'find_pwd_error_multiple_emails'=>'存在多个用户使用此邮箱,请输入用户名!',
'find_pwd_error_none_user'=>'用户不存在!',
'find_pwd_success'=>'密码修改成功',
'yzm_error_please_send'=>'请发送激活码',
'yzm_error_please_input'=>'请输入激活码',
'yzm_error_timeout'=>'激活码已过期!请重新发送',
'yzm_error_yzm'=>'激活码错误',
'admincp_style'=>'界面',
'admincp_sidebar_mini'=>'菜单最小化',
'admincp_skins'=>'设置皮肤',
'skin_blue'=>'蓝',
'skin_black'=>'黑',
'skin_purple'=>'紫',
'skin_green'=>'绿',
'skin_red'=>'红',
'skin_yellow'=>'黄',
'skin_blue_light'=>'蓝亮',
'skin_black_light'=>'黑亮',
'skin_purple_light'=>'紫亮',
'skin_green_light'=>'绿亮',
'skin_red_light'=>'红亮',
'skin_yellow_light'=>'黄亮',
'store'=>'云平台',
'rule_collect'=>'采集规则',
'empty_data'=>'数据不存在',
'invalid_op'=>'无效的操作!',
'submit'=>'提交',
'search'=>'搜索',
'op_success'=>'操作成功',
'op_failed'=>'操作失败',
'sort'=>'排序',
'select'=>'选择',
'select_all'=>'全选',
'select_first'=>'请选择',
'save'=>'保存',
'op'=>'操作',
'delete'=>'删除',
'deleted'=>'已删除',
'edit'=>'编辑',
'test'=>'测试',
'confirm_delete'=>'确定删除?',
'delete_success'=>'删除成功',
'none'=>'无',
'caiji'=>'采集',
'more'=>'更多',
'yes'=>'是',
'no'=>'否',
'all'=>'全部',
'login'=>'登录',
'logout'=>'退出',
'login_auto'=>'下次自动登录',
'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',
'release_upgrade'=>'插件版本过低,请升级插件 <a href="http://www.skycaiji.com/manual/doc/release_upgrade" target="_blank">升级教程</a>',
);
?>

View File

@ -0,0 +1,19 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
use think\Model;
class BaseModel extends Model {
public function get_table_name(){
return strtolower(config('database.prefix').$this->name);
}
}
?>

View File

@ -0,0 +1,121 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
/**
* 数据缓存模型
* 不继承model类直接调用db防止不同表实例化的静态变量混淆
*/
class CacheModel{
private static $instances;
public $category='';
public $table_name='cache';
protected $cache_list=array();
public function __construct($category=''){
$this->category=$category;
$this->table_name='cache'.($this->category?('_'.$this->category):'');
}
/*获取实例化类*/
public static function getInstance($category=''){
if(!isset(self::$instances[$category])){
self::$instances[$category] = new static($category);
}
return self::$instances[$category];
}
/**
* 获取数据库连接
* @return \think\db\Query
*/
public function db(){
try {
$db=db($this->table_name);
$db->getPk();
}catch (\Exception $ex){
$this->create_table();
$db=db($this->table_name);
}
return $db;
}
public function getCount($cname){
return $this->db()->where('cname',$cname)->count();
}
/**
* 获取缓存
* @param string $cname 缓存名称
* @param string $key 缓存的数据键名
* @return mixed
*/
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;
}
return $key?$cache[$key]:$cache;
}
/**
* 设置缓存
* @param string $cname 缓存名称
* @param string $value 缓存数据
*/
public function setCache($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->db()->insert($data,true);
}
/**
* 缓存是否过期
* @param string $cname 缓存名称
* @param int $timeout 过期时间
* @return boolean
*/
public function expire($cname,$timeout=72000){
$cache=$this->getCache($cname);
if(empty($cache)||abs(NOW_TIME-$cache['dateline']>$timeout)){
return true;
}else{
return false;
}
}
/**
* 创建表
* @return boolean
*/
public function create_table(){
$tname=config('database.prefix').$this->table_name;
$exists=db()->query("show tables like '{$tname}'");
if(empty($exists)){
$table=<<<EOT
CREATE TABLE `{$tname}` (
`cname` varchar(32) NOT NULL,
`ctype` tinyint(3) unsigned NOT NULL,
`dateline` int(10) unsigned NOT NULL,
`data` mediumblob NOT NULL,
PRIMARY KEY (`cname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
EOT;
db()->execute($table);
}
}
}
?>

View File

@ -0,0 +1,87 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
/*采集到的数据库*/
class Collected extends BaseModel{
public function __construct($data=[]){
try {
parent::__construct($data);
$this->getPk();
}catch (\Exception $ex){
$this->create_table();
parent::__construct($data);
}
}
/**
* 获取url的数量
* @param array|string $urls
*/
public function getCountByUrl($urls){
if(is_array($urls)){
$urls=array_map('md5', $urls);
return $this->where('urlMd5','in',$urls)->count();
}else{
return $this->where('urlMd5',md5($urls))->count();
}
}
/*获取标题的数量*/
public function getCountByTitle($title){
if(empty($title)){
return 0;
}
return $this->where('titleMd5',md5($title))->count();
}
public function getUrlByUrl($urls){
if(!is_array($urls)){
$urls=array($urls);
}
$urls=array_map('md5', $urls);
return $this->field('`id`,`url`')->where(array('urlMd5'=>array('in',$urls)))->column('url','id');
}
/**
* 创建表
* @return boolean
*/
public function create_table(){
$tname=$this->get_table_name();
$exists=db()->query("show tables like '{$tname}'");
if(empty($exists)){
$table=<<<EOT
CREATE TABLE `{$tname}` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(1000) NOT NULL DEFAULT '',
`urlMd5` varchar(32) NOT NULL DEFAULT '',
`release` varchar(10) NOT NULL DEFAULT '',
`task_id` int(11) NOT NULL DEFAULT '0',
`target` varchar(1000) NOT NULL DEFAULT '',
`desc` varchar(1000) NOT NULL DEFAULT '',
`error` varchar(1000) NOT NULL DEFAULT '',
`addtime` int(11) NOT NULL DEFAULT '0',
`titleMd5` varchar(32) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `ix_urlmd5` (`urlMd5`),
KEY `ix_taskid` (`task_id`),
KEY `ix_addtime` (`addtime`),
KEY `ix_titlemd5` (`titleMd5`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
EOT;
db()->execute($table);
}
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
class Collector extends BaseModel{
public function add_new($data){
$data['addtime']=NOW_TIME;
$data['uptime']=NOW_TIME;
$this->allowField(true)->save($data);
return $this->id;
}
public function edit_by_id($id,$data){
unset($data['addtime']);
$data['uptime']=NOW_TIME;
$this->allowField(true)->save($data,array('id'=>$id));
}
}
?>

View File

@ -0,0 +1,115 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
class Config extends BaseModel {
protected $pk = 'cname';
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);
}
/*设置版本号*/
public function setVersion($version){
$version=trim(strtoupper($version),'V');
$this->setConfig('version', $version);
}
/*获取数据库的版本*/
public function getVersion(){
$dbVersion=$this->where("`cname`='version'")->find();
if(!empty($dbVersion)){
$dbVersion=$this->convertData($dbVersion);
$dbVersion=$dbVersion['data'];
}
return $dbVersion;
}
/*检查图片路径*/
public function check_img_path($imgPath){
$return=array('success'=>false,'msg'=>'');
if(!empty($imgPath)){
if(!preg_match('/(^\w+\:)|(^[\/\\\])/i', $imgPath)){
$return['msg']='图片目录必须为绝对路径!';
}else{
if(!is_dir($imgPath)){
$return['msg']='图片目录不存在!';
}else{
$imgPath=realpath($imgPath);
$root_path=rtrim(realpath(config('root_path')),'\\\/');
if(preg_match('/^'.addslashes($root_path).'\b/i',$imgPath)){
if(!preg_match('/^'.addslashes($root_path).'[\/\\\]data[\/\\\].+/i', $imgPath)){
$return['msg']='图片保存到本程序中目录必须在data文件夹里';
}else{
$return['success']=true;
}
}else{
$return['success']=true;
}
}
}
}
return $return;
}
/*检查图片网址*/
public function check_img_url($imgUrl){
$return=array('success'=>false,'msg'=>'');
if(!empty($imgUrl)){
if(!preg_match('/^\w+\:\/\//i',$imgUrl)){
$return['msg']='图片链接地址必须以http://或者https://开头';
}else{
$return['success']=true;
}
}
return $return;
}
}
?>

View File

@ -0,0 +1,180 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
use think\Db;
/*动态操作数据库*/
class DbCommon{
public $config=null;
public function __construct($config=array()) {
$this->config=array(
'type'=>strtolower($config['db_type']),
'database'=>$config['db_name'],
'username'=>$config['db_user'],
'password'=>$config['db_pwd'],
'hostname'=>$config['db_host'],
'hostport'=>$config['db_port'],
'charset'=>$config['db_charset'],
'prefix'=>$config['db_prefix'],
'dsn'=>$config['db_dsn'],
'resultset_type'=>'array',
'break_reconnect'=>true,
);
if($this->config['type']=='mysqli'){
$this->config['type']='mysql';
}elseif($this->config['type']=='sqlserver'){
$this->config['type']='sqlsrv';
}
}
/**
* 获取数据库连接
* @param string $table
* @param string $force
* @param string $compatible 兼容的数据库模型
* @return \think\db\Query|NULL
*/
public function db($table='',$force=false,$compatible=false){
if(!empty($this->config)){
$config=$this->config;
if($config['type']=='oracle'){
$config['type']='\think\oracle\Connection';
}
if($compatible){
$db=Db::connect($config, $force);
}else{
$db=Db::connect($config, $force);
}
if($table){
$db=$db->name($table);
}
return $db;
}else{
return null;
}
}
/**
* 获取数据库中的所有表
*/
public function getTables(){
$list=array();
if('oracle'==$this->config['type']){
$tables=$this->db()->query("select table_name from user_tables");
if(!empty($tables)){
foreach ($tables as $table){
$list[$table['TABLE_NAME']]=$table['TABLE_NAME'];
}
}
}else{
$tables=$this->db()->getTables($this->config['database']);
if(!empty($tables)){
foreach ($tables as $table){
$list[$table]=$table;
}
}
}
return $list;
}
/*获取表的所有字段信息*/
public function getFields($tableName=''){
$tb_fields=array();
if(!empty($tableName)){
if('sqlsrv'==$this->config['type']){
list($tableName) = explode(' ', $tableName);
$tableNames = explode('.', $tableName);
$tableName = isset($tableNames[1]) ? $tableNames[1] : $tableNames[0];
$sql = "SELECT column_name, data_type, character_maximum_length, column_default, is_nullable
FROM information_schema.tables AS t
JOIN information_schema.columns AS c
ON t.table_catalog = c.table_catalog
AND t.table_schema = c.table_schema
AND t.table_name = c.table_name
WHERE t.table_name = '$tableName'";
$result = $this->db()->query($sql);
if ($result) {
foreach ($result as $key => $val) {
$val = array_change_key_case($val,CASE_LOWER);
$tb_fields[$val['column_name']] = [
'name' => $val['column_name'],
'type' => $val['data_type'].($val['character_maximum_length']?('('.$val['character_maximum_length'].')'):''),
'notnull' => ('yes' == strtolower($val['is_nullable']))?false:true,
'default' => $val['column_default'],
'primary' => false,
'autoinc' => false,
];
}
}
$sql = "SELECT column_name FROM information_schema.key_column_usage WHERE table_name='{$tableName}'";
$result = $this->db()->query($sql);
if ($result) {
foreach ($result as $key => $val) {
$tb_fields[$val['column_name']]['primary'] = true;
}
}
$sql = "SELECT column_name FROM information_schema.columns WHERE TABLE_NAME='{$tableName}' AND COLUMNPROPERTY(OBJECT_ID('{$tableName}'),COLUMN_NAME,'IsIdentity')=1";
$result = $this->db()->query($sql);
if ($result) {
foreach ($result as $key => $val) {
$tb_fields[$val['column_name']]['autoinc'] = true;
}
}
}else{
$fields=$this->db()->getFields($tableName);
if(!empty($fields)){
foreach ($fields as $k=>$v){
$tb_fields[$k]=array_change_key_case($v,CASE_LOWER);
}
}
}
}
return $tb_fields;
}
/*获取表的字段信息*/
public static function fieldsInfo($tableName){
if(empty($tableName)){
return array();
}
$tableName = '`'.$tableName.'`';
$tbFields=db()->query('SHOW COLUMNS FROM '.$tableName);
$fields=array();
if(!empty($tbFields)){
foreach ($tbFields as $tbField){
$tbField=array_change_key_case($tbField,CASE_LOWER);
$fields[$tbField['field']]=array(
'name' => $tbField['field'],
'type' => $tbField['type'],
'notnull' => (strtolower($tbField['null']) == 'yes')?false:true,
'default' => $tbField['default'],
'primary' => (strtolower($tbField['key']) == 'pri'),
'autoinc' => (strtolower($tbField['extra']) == 'auto_increment'),
);
}
}
return $fields;
}
}
?>

View File

@ -0,0 +1,122 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
class Proxyip extends BaseModel {
public $name='proxy_ip';
public $setting;
public function __construct($data=[]){
parent::__construct($data);
$this->setting=$GLOBALS['config']['proxy'];
}
/*转换成get_html中格式的ip*/
public function to_proxy_ip($proxy_ip){
$proxyIp=null;
if(empty($proxy_ip)||empty($proxy_ip['ip'])){
$proxyIp=null;
}
if(empty($proxy_ip['user'])){
$proxyIp=$proxy_ip['ip'];
}else{
$proxyIp=array(
$proxy_ip['ip'],
$proxy_ip['user'],
$proxy_ip['pwd']
);
}
return $proxyIp;
}
/*获取可用的ip*/
public function get_usable_ip(){
if(!empty($this->setting['open'])){
$cond=array();
$cond['invalid']=0;
if(!empty($this->setting['use'])){
if($this->setting['use']=='num'){
$cond['num']=array('lt',$this->setting['use_num']);
}elseif($this->setting['use']=='time'){
$cond['time']=array(array('eq',0),array('gt',time()-$this->setting['use_time']*60), 'or') ;
}
}else{
$cond['num']=array('lt',1);
}
$proxyipData=$this->where($cond)->find();
if(empty($proxyipData)){
if(!empty($this->setting['use'])){
if($this->setting['use']=='num'){
$this->where('1=1')->update(array('num'=>0));
}elseif($this->setting['use']=='time'){
$this->where('1=1')->update(array('time'=>0));
}
}else{
$this->where('1=1')->update(array('num'=>0));
}
$proxyipData=$this->where($cond)->find();
}
if(!empty($proxyipData)){
$upData=array();
if(!empty($this->setting['use'])){
if($this->setting['use']=='num'){
$upData['num']=$proxyipData['num']+1;
}elseif($this->setting['use']=='time'){
if(empty($proxyipData['time'])){
$upData['time']=time();
}
}
}else{
$upData['num']=$proxyipData['num']+1;
}
$this->allowField(true)->save($upData,array('ip'=>$proxyipData['ip']));
}
return $proxyipData;
}
return null;
}
/*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;
}
$this->allowField(true)->save($upData,array('ip'=>$proxy_ip['ip']));
}
}
?>

View File

@ -0,0 +1,169 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
use think\db\Query;
use think\db\Connection;
/**
* 兼容tp5和tp3.2的数据库操作模型
*/
class QueryCompatible extends Query{
/*重写父类的private属性*/
protected static $event = [];
protected static $readMaster = [];
protected function checkMultiField($field, $logic){
return isset($this->options['multi'][$logic][$field]) && count($this->options['multi'][$logic][$field]) > 1;
}
/*---------------------------*/
public function __construct(Connection $connection = null, $model = null){
parent::__construct($connection,$model);
}
public function where($field, $op = null, $condition = null){
$newSql=$this->_tp3_parse_sql(func_get_args());
if(empty($newSql)){
return parent::where($field,$op,$condition);
}else{
return parent::where($newSql);
}
}
public function query($sql, $bind = [], $master = false, $class = false){
$newSql=$this->_tp3_parse_sql(func_get_args());
if(empty($newSql)){
return parent::query($sql,$bind,$master,$class);
}else{
return parent::query($newSql);
}
}
public function execute($sql, $bind = []){
$newSql=$this->_tp3_parse_sql(func_get_args());
if(empty($newSql)){
return parent::execute($sql,$bind);
}else{
return parent::execute($newSql);
}
}
/**
* tp3的方法必须在这里定义防止与tp5存在的方法冲突
* @see \think\db\Query::__call()
*/
public function __call($method, $args){
switch ($method){
case 'getField':return $this->_tp3_getField($args);break;
case 'add':return $this->_tp3_add($args);break;
case 'addAll':return $this->_tp3_addAll($args);break;
case 'save':return $this->_tp3_save($args);break;
}
}
/*getField($field,$sepa=null)*/
private function _tp3_getField($args){
$field=$args[0];
$sepa=isset($args[1])?$args[1]:null;
if(strpos($field,',')!==false){
if(is_numeric($sepa)&&$sepa>0){
return $this->limit($sepa)->column($field);
}elseif($sepa===false){
$field=explode(',', $field);
return $this->value($field[0]);
}else{
return $this->column($field);
}
}else{
if($sepa===true){
return $this->column($field);
}elseif(is_numeric($sepa)){
$sepa=intval($sepa);
if($sepa>0){
return $this->limit($sepa)->column($field);
}else{
return $this->column($field);
}
}else{
return $this->value($field);
}
}
}
/*add($data='',$options=array(),$replace=false)*/
private function _tp3_add($args){
$data=isset($args[0])?$args[0]:'';
$options=isset($args[1])?$args[1]:array();
$replace=isset($args[2])?$args[2]:false;
if(empty($data)){
$data=array();
}
if(empty($options)){
return $this->insert($data,$replace,true);
}else{
$this->_tp5_exception('add', 'insert');
}
}
/*addAll($dataList,$options=array(),$replace=false)*/
private function _tp3_addAll($args){
$dataList=$args[0];
$options=isset($args[1])?$args[1]:array();
$replace=isset($args[2])?$args[2]:false;
if(empty($options)){
$this->insertAll($dataList,$replace);
return $this->getLastInsID();
}else{
$this->_tp5_exception('addAll', 'insertAll');
}
}
/*save($data='',$options=array())*/
private function _tp3_save($args){
$data=isset($args[0])?$args[0]:'';
$options=isset($args[1])?$args[1]:array();
if(empty($options)){
$options = $this->options;
if(empty($options['where'])){
$this->_tp5_exception('save', 'update');
}
return $this->update($data);
}else{
$this->_tp5_exception('save', 'update');
}
}
/*tp3解析sql语句*/
private function _tp3_parse_sql($args=array()){
$sql=$args[0];
$newSql=null;
if(is_array($args)&&count($args)>1&&is_string($sql)&&strpos($sql,'%')!==false){
array_shift($args);
foreach ($args as $k=>$v){
if(!is_scalar($v)){
$args=null;
break;
}else{
$args[$k]=addslashes($v);
}
}
if(!empty($args)){
$newSql=vsprintf($sql,$args);
if($newSql==$sql){
$newSql=null;
}
}
}
return $newSql;
}
private function _tp5_exception($oldMethod,$newMethod){
throw new \Exception("tp5数据库操作已弃用{$oldMethod}方法,请使用{$newMethod}方法");
exit();
}
}
?>

View File

@ -0,0 +1,32 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
class Release extends BaseModel{
public function getByTaskid($taskId){
static $dataList=array();
if(empty($taskId)){
return null;
}
if(!isset($dataList[$taskId])){
$taskData=$this->where(array('task_id'=>$taskId))->find();
if(!empty($taskData)){
$dataList[$taskId]=$taskData->toArray();
}else{
$dataList[$taskId]=array();
}
}
return $dataList[$taskId];
}
}
?>

View File

@ -0,0 +1,105 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
use think\Loader;
class ReleaseApp extends BaseModel{
protected $tableName='release_app';
public function addCms($cms,$code='',$tpl=''){
if(empty($cms['app'])){
return false;
}
$cms['module']='cms';
$cms['uptime']=$cms['uptime']>0?$cms['uptime']:NOW_TIME;
$cmsData=$this->where(array('module'=>'cms','app'=>$cms['app']))->find();
$success=false;
if(!empty($cmsData)){
$this->allowField(true)->save($cms,array('module'=>'cms','app'=>$cms['app']));
$success=true;
}else{
$cms['addtime']=NOW_TIME;
$this->save($cms);
$cms['id']=$this->id;
$success=$cms['id']>0?true:false;
}
if($success){
$cmsAppPath=config('plugin_path').'/release';
if(!empty($code)){
write_dir_file($cmsAppPath.'/cms/'.ucfirst($cms['app']).'.php', $code);
}
if(!empty($tpl)){
write_dir_file($cmsAppPath.'/view/cms/'.ucfirst($cms['app']).'.html', $tpl);
}
}
return $success;
}
public function appFileName($appName,$model='cms'){
$model=strtolower($model);
$appName=ucfirst($appName);
return config('plugin_path').'/release/'.$model.'/'.$appName.'.php';
}
public function appFileExists($appName,$model='cms'){
$fileName=$this->appFileName($appName,$model);
return file_exists($fileName)?true:false;
}
public function appImportClass($appName,$model='cms'){
$cmsClass='\\plugin\\release\\'.strtolower($model).'\\'.ucfirst($appName);
$cmsClass=new $cmsClass();
return $cmsClass;
}
/*导入v1.x版本发布插件*/
public function oldImportClass($appName,$model='Cms'){
$model=ucfirst($model);
$appName=ucfirst($appName);
$fileName=$this->oldFileName($appName,$model);
$appName=$appName.$model;
if(file_exists($fileName)){
Loader::addNamespace('Release',realpath(APP_PATH.'Release'));
Loader::import($appName,config('app_path').'/Release/'.$model.'/','.class.php');
$oldClass='\\Release\\'.$model.'\\'.$appName;
$oldClass=new $oldClass();
return $oldClass?$oldClass:null;
}else{
return null;
}
}
/*获取v1.x版本发布插件源码*/
public function oldFileCode($appName,$model='Cms'){
$fileName=$this->oldFileName($appName,$model);
if(file_exists($fileName)){
return file_get_contents($fileName);
}else{
return null;
}
}
/*存在v1.x版本插件*/
public function oldFileExists($appName,$model='Cms'){
$fileName=$this->oldFileName($appName,$model);
return file_exists($fileName)?true:false;
}
public function oldFileName($appName,$model='Cms'){
$model=ucfirst($model);
$appName=ucfirst($appName);
return config('app_path').'/Release/'.$model.'/'.$appName.$model.'.class.php';
}
}
?>

View File

@ -0,0 +1,18 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
class Rule extends BaseModel{
}
?>

View File

@ -0,0 +1,57 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
class Task extends BaseModel{
public function loadConfig($config){
if(empty($config)){
$config=array();
}
if(!is_array($config)){
$config=unserialize($config);
}
static $global_config=null;
if(!isset($global_config)){
$global_config=$GLOBALS['config'];
}
if(!empty($global_config['caiji']['download_img'])){
if($config['download_img']=='n'){
$GLOBALS['config']['caiji']['download_img']=0;
}else{
$GLOBALS['config']['caiji']['download_img']=1;
}
}else{
$GLOBALS['config']['caiji']['download_img']=0;
}
if(!empty($global_config['proxy']['open'])){
if($config['proxy']=='n'){
$GLOBALS['config']['proxy']['open']=0;
}else{
$GLOBALS['config']['proxy']['open']=1;
}
}else{
$GLOBALS['config']['proxy']['open']=0;
}
$GLOBALS['config']['caiji']['img_path']=empty($config['img_path'])?$global_config['caiji']['img_path']:$config['img_path'];
$GLOBALS['config']['caiji']['img_url']=empty($config['img_url'])?$global_config['caiji']['img_url']:$config['img_url'];
}
}
?>

View File

@ -0,0 +1,61 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
class Taskgroup extends BaseModel{
/**
* 获取分级分组
*/
public function getLevelList(){
static $list=null;
if(!isset($list)){
$level1List=$this->where('`parent_id`=0')->order('sort desc')->column('*');
$level1Ids=array();
foreach ($level1List as $level1){
$level1Ids[$level1['id']]=$level1['id'];
}
$level2List=array();
$cond=array();
if(!empty($level1Ids)){
$cond['parent_id']=array('in',$level1Ids);
}
$subList=$this->where($cond)->order('sort desc')->column('*');
foreach ($subList as $sub){
$level2List[$sub['parent_id']][$sub['id']]=$sub;
}
$list=array('level1'=>$level1List,'level2'=>$level2List);
}
return $list;
}
/**
* 获取分级分组select代码
*/
public function getLevelSelect($sltName='tg_id'){
$list=$this->getLevelList();
$html='<select name="'.$sltName.'" class="form-control">';
$html.='<option value="0">'.lang('none').'</option>';
foreach($list['level1'] as $tg1){
$html.="<option value='{$tg1['id']}'>{$tg1['name']}</option>";
if(!empty($list['level2'][$tg1['id']])){
foreach ($list['level2'][$tg1['id']] as $tg2){
$html.="<option value='{$tg2['id']}'>-----{$tg2['name']}</option>";
}
}
}
$html.='</select>';
return $html;
}
}
?>

View File

@ -0,0 +1,164 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
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,20}$/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);
}
}
/*用户组*/
public static function right_groupid($groupid,$name='groupid'){
$return=array('name'=>$name);
$count=model('Usergroup')->where('id',$groupid)->count();
if(empty($count)||$count<=0){
$return['msg']=lang('user_error_groupid');
}else{
$return['success']=true;
}
return $return;
}
/**
* 邮件激活码是否正确
* @param unknown $username
* @param unknown $yanzhengma
* @param unknown $name
* @return multitype:string
*/
public static function right_yzm($username,$yanzhengma,$name='yzm'){
$yzmSname='send_yzm.'.md5($username);
$yzmSession=session($yzmSname);
$check=array('name'=>$name);
if(empty($yzmSession)){
$check['msg']=lang('yzm_error_please_send');
}elseif(empty($yanzhengma)){
$check['msg']=lang('yzm_error_please_input');
}elseif(abs(time()-$yzmSession['time'])>config('yzm_expire')){
$check['msg']=lang('yzm_error_timeout');
}elseif(strcasecmp($yanzhengma, $yzmSession['yzm'])!==0){
$check['msg']=lang('yzm_error_yzm');
}else{
$check['success']=true;
}
return $check;
}
/*检测用户名正确且是否存在*/
public function checkUsername($username){
$check=self::right_username($username);
if($check['success']){
if($this->where('username',$username)->count()){
$check['msg']=lang('user_error_has_username');
$check['success']=false;
}
}
return $check;
}
/*添加用户时验证*/
public function add_check($data){
$check=self::right_groupid($data['groupid']);
if(!$check['success']){
return $check;
}
$check=$this->checkUsername($data['username']);
if(!$check['success']){
return $check;
}
$check=self::right_pwd($data['password']);
if(!$check['success']){
return $check;
}
$check=self::right_repwd($data['password'],$data['repassword']);
if(!$check['success']){
return $check;
}
$check=self::right_email($data['email']);
if(!$check['success']){
return $check;
}
return array('success'=>true);
}
/*修改用户时验证*/
public function edit_check($data){
if(!empty($data['groupid'])){
$check=self::right_groupid($data['groupid']);
if(!$check['success']){
return $check;
}
}
if(!empty($data['password'])){
$check=self::right_pwd($data['password']);
if(!$check['success']){
return $check;
}
$check=self::right_repwd($data['password'],$data['repassword']);
if(!$check['success']){
return $check;
}
}
$check=self::right_email($data['email']);
if(!$check['success']){
return $check;
}
return array('success'=>true);
}
}
?>

View File

@ -0,0 +1,33 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\model;
class Usergroup extends BaseModel{
/*获取当前组的下属等级组*/
public function get_sub_level($groupid){
$group=$this->getById($groupid);
if(empty($group)){
return null;
}
return $this->where('level','LT',$group['level'])->column('*');
}
/*等级限制:判断当前用户组等级小于等于传入的等级*/
public function user_level_limit($level){
if($GLOBALS['user']['group']['level']<=$level){
return true;
}else{
return false;
}
}
}
?>

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,38 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
return [
'app_init' => [],
'app_begin' => [],
'module_init' => ['skycaiji\\admin\\behavior\\Init'],
'action_begin' => [],
'view_filter' => [],
'log_write' => [],
'app_end' => [],
];

View File

@ -0,0 +1,30 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\validate;
use think\Validate;
class Task extends Validate{
protected $rule = [
'name'=>'require|unique:task',
];
protected $message = [
'name.require'=>'{%task_error_null_name}',
'name.unique'=>'{%task_error_has_name}',
];
protected $scene = [
'add'=>['name'],
'edit'=>['name'=>'require'],
];
}
?>

View File

@ -0,0 +1,30 @@
<?php
/*
|--------------------------------------------------------------------------
| SkyCaiji (蓝天采集器)
|--------------------------------------------------------------------------
| Copyright (c) 2018 http://www.skycaiji.com All rights reserved.
|--------------------------------------------------------------------------
| 使用协议 http://www.skycaiji.com/licenses
|--------------------------------------------------------------------------
*/
namespace skycaiji\admin\validate;
use think\Validate;
class Taskgroup extends Validate{
protected $rule = [
'name'=>'require|unique:taskgroup',
];
protected $message = [
'name.require'=>'{%task_error_null_name}',
'name.unique'=>'{%task_error_has_name}',
];
protected $scene = [
'add'=>['name'],
'edit'=>['name'=>'require'],
];
}
?>

View File

@ -0,0 +1,120 @@
{extend name="common:main" /}
{block name="cssjs"}
<script src="__PUBLIC__/static/js/admin/index.js?{$Think.config.html_v}"></script>
{/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>
<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>
<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="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>
</div>
</div>
</div>
<div class="box box-default">
<div class="box-body">
<div class="row">
<div class="col-sm-6">
<table class="table table-bordered table-striped" style="margin-bottom:0;">
<tbody>
<tr>
<th style="width:90px;">检测更新</th>
<td>
<div id="upgrade_check"></div>
<textarea id="upgrade_error" rows="5" class="form-control" style="display:none;margin-top:10px;"></textarea>
</td>
</tr>
{if condition="$upgradeDb"}
<tr>
<th>升级数据库</th>
<td><a href="javascript:;" id="upgrade_db">点击升级数据库</a></td>
</tr>
{/if}
<tr>
<th>当前版本</th>
<td>SkyCaiji V{$serverInfo['version']}</td>
</tr>
{if condition="isset($serverInfo['caiji'])"}
<tr>
<th>采集状态</th>
<td>{$serverInfo['caiji']}</td>
</tr>
{/if}
<tr>
<th>社区论坛</th>
<td><a href="http://bbs.skycaiji.com" target="_blank">SkyCaiji交流社区</a></td>
</tr>
<tr>
<th>清除缓存</th>
<td><a href="javascript:;" id="op_clean">清除缓存</a></td>
</tr>
</tbody>
</table>
</div>
<div class="col-sm-6">
<table class="table table-bordered table-striped" style="margin-bottom:0;">
<tbody>
<tr>
<th style="width:90px;">操作系统</th>
<td>{$serverInfo['os']}</td>
</tr>
<tr>
<th>运行环境</th>
<td>{$serverInfo['server']}</td>
</tr>
<tr>
<th>数据库</th>
<td>{$serverInfo['db']}</td>
</tr>
<tr>
<th>PHP版本</th>
<td>{$serverInfo['php']}</td>
</tr>
<tr>
<th>上传限制</th>
<td>{$serverInfo['upload_max']}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div id="skycaiji_admin_index">
</div>
{/block}

View File

@ -0,0 +1,110 @@
{extend name="common:main" /}
{block name="cssjs"}
<script type="text/javascript" src="__PUBLIC__/static/js/admin/collected.js?{$Think.config.html_v}"></script>
{/block}
{block name="content"}
<div class="box">
<div class="box-body">
<div class="alert alert-warning alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
已采集网址可防止重复采集,如无必要,请勿删除!
</div>
<form id="form_list" method="post" ajax-submit="true" action="{:url('Collected/op')}">
<div class="table-responsive">
<table id="list_table" class="table table-bordered table-hover datatable">
<thead>
<tr>
<th width="60" class="chk">{$Think.lang.select}</th>
<th class="url">源网址</th>
<th>已发布至</th>
<th>发布方式</th>
<th>任务名</th>
<th>添加时间</th>
<th>{$Think.lang.op}</th>
</tr>
</thead>
<tbody>
{foreach name="dataList" item="item"}
<tr>
<td class="chk"><input type="checkbox" name="ids[]" value="{$item['id']}" /></td>
<td class="url"><a href="{$item['url']}" target="_blank">{$item['url']}</a></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><a href="{:url('Admin/Task/edit?id='.$item['task_id'])}" target="_blank">{$taskList[$item['task_id']]}</a></td>
<td>{:date('Y-m-d H:i:s',$item['addtime'])}</td>
<td><a href="javascript:;" url="{:url('Collected/op?op=delete&id='.$item['id'])}" class="delete">删除</a></td>
</tr>
{/foreach}
</tbody>
<tfoot>
<tr>
<td class="chk"><label><input type="checkbox" id="chkall" onclick="checkall(this,'ids[]')" />全部</label></td>
<td colspan="4">
<button type="button" class="btn btn btn-danger" id="deleteall">{$Think.lang.delete}</button>
</td>
</tr>
{if condition="!empty($pagenav)"}
<tr>
<td colspan="5">{$pagenav}</td>
</tr>
{/if}
</tfoot>
</table>
</div>
</form>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
<div class="list-footer">
<form id="form_search" method="post" action="{:url('Collected/list')}" class="form-inline">
<div class="form-group form-group-sm">
<label>每页显示</label>
<select name="num" class="form-control">
<option value="50">50</option>
<option value="100">100</option>
<option value="200">200</option>
<option value="500">500</option>
<option value="1000">1000</option>
</select>
</div>
<div class="form-group form-group-sm">
<label>发布方式</label>
<select name="release" class="form-control">
<option value="">全部</option>
{foreach name="Think.config.release_modules" item="rele_module"}
<option value="{$rele_module}">{:lang('collected_rele_'.$rele_module)}</option>
{/foreach}
</select>
</div>
<div class="form-group form-group-sm">
<label>网址</label>
<input type="text" name="url" class="form-control" value="{$search['url']}" placeholder="模糊搜索,默认全部">
</div>
<div class="form-group form-group-sm">
<label>任务名</label>
<input type="text" name="task_name" class="form-control" value="{$search['task_name']}" placeholder="模糊搜索,默认全部">
</div>
<div class="form-group form-group-sm">
<select name="status" class="form-control">
<option value="">全部</option>
<option value="1">发布成功</option>
<option value="2">发布失败</option>
</select>
</div>
<button type="submit" class="btn btn-default btn-sm">{$Think.lang.search}</button>
</form>
</div>
<script type="text/javascript">
$('#form_search select[name="num"]').val("{$search['num']|intval}");
$('#form_search select[name="release"]').val("{$search['release']}");
$('#form_search select[name="status"]').val("{$search['status']}");
collectedClass.init_list();
</script>
{/block}

View File

@ -0,0 +1,31 @@
{if condition="!empty($collList)"}
<div id="window_colls">
<ul class="row" id="coll_list">
{foreach name="collList" item="coll"}
<li class="col-xs-6" style="padding:0;">
<a href="javascript:;" data-id="{$coll['id']}">
{if condition="!empty($taskNames[$coll['task_id']])"}
任务规则:{$taskNames[$coll['task_id']]}
{else /}
采集器:{$coll['name']}
{/if}
</a>
</li>
{/foreach}
</ul>
{$pagenav}
<script type="text/javascript">
$('#window_colls #coll_list li a').bind('click',function(){
var id=$(this).attr('data-id');
var name=$(this).text();
import_rule('collector:'+id,name);
});
$('#window_colls .pagination a').bind('click',function(){
windowModal('导入规则',$(this).attr('href'));
return false;
});
</script>
</div>
{else /}
没有规则,请进入<a href="{:url('Store/index')}">云平台</a>下载
{/if}

View File

@ -0,0 +1,17 @@
{if condition="!empty($collData)"}
<script src="__PUBLIC__/static/js/admin/store.js?{$Think.config.html_v}"></script>
<div>
<form id="win_form_save2store" action="http://www.skycaiji.com/store/client/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

@ -0,0 +1,23 @@
{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"}
<form id="form_coll" class="form-item" method="post" ajax-submit="true" role="form" action="{:url('Collector/set')}">
<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="" />
{if condition="$taskData['module']=='pattern'"}
{include file="cpattern:set" /}
{elseif condition="$taskData['module']=='weixin'" /}
{/if}
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">{$Think.lang.save}</button>
</div>
{if condition="$taskData"}
{include file="task:stepsbar" /}
{/if}
</form>
{/block}

View File

@ -0,0 +1,6 @@
{if condition="$GLOBALS['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

@ -0,0 +1,45 @@
{php}
$_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:footer_public" /}

View File

@ -0,0 +1,46 @@
{php}
$_WP['title']=$msg;
{/php}
{extend name="common:main" /}
{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>
{/block}

View File

@ -0,0 +1,3 @@
<div class="control-sidebar-bg"></div>
</div>
{include file="common:footer_public" /}

View File

@ -0,0 +1,3 @@
{include file="common:browser_is_old" /}
</body>
</html>

View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<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>
<!-- Bootstrap 3.3.7 -->
<link rel="stylesheet" href="__PUBLIC__/bootstrap/css/bootstrap.min.css?{$Think.config.html_v}">
<!-- Font Awesome -->
<link rel="stylesheet" href="__PUBLIC__/addon/font-awesome/css/font-awesome.min.css?{$Think.config.html_v}">
<!-- Ionicons -->
<link rel="stylesheet" href="__PUBLIC__/addon/Ionicons/css/ionicons.min.css?{$Think.config.html_v}">
<!-- Theme style -->
<link rel="stylesheet" href="__PUBLIC__/adminlte/dist/css/AdminLTE.min.css?{$Think.config.html_v}">
<link rel="stylesheet" href="__PUBLIC__/adminlte/dist/css/skins/_all-skins.min.css?{$Think.config.html_v}">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="__PUBLIC__/addon/adminlte/html5shiv.min.js?{$Think.config.html_v}"></script>
<script src="__PUBLIC__/addon/adminlte/respond.min.js?{$Think.config.html_v}"></script>
<![endif]-->
<!-- Google Font -->
<!-- <link rel="stylesheet" href="__PUBLIC__/addon/adminlte/google-font.css?{$Think.config.html_v}"> -->
<!-- jQuery -->
<script src="__PUBLIC__/jquery/jquery.min.js?{$Think.config.html_v}"></script>
<!-- else -->
<script type="text/javascript" src="__PUBLIC__/static/js/base64.min.js?{$Think.config.html_v}"></script>
<link href="__PUBLIC__/static/css/toastr.css?{$Think.config.html_v}" rel="stylesheet" type="text/css">
<script src="__PUBLIC__/static/js/toastr.js?{$Think.config.html_v}"></script>
<!-- jQuery UI 1.11.4 -->
<script src="__PUBLIC__/addon/adminlte/jquery-ui.min.js?{$Think.config.html_v}"></script>
<!-- Bootstrap 3.3.7 -->
<script src="__PUBLIC__/bootstrap/js/bootstrap.min.js?{$Think.config.html_v}"></script>
<!-- FastClick -->
<script src="__PUBLIC__/addon/adminlte/fastclick.js?{$Think.config.html_v}"></script>
<!-- AdminLTE App -->
<script src="__PUBLIC__/adminlte/dist/js/adminlte.min.js?{$Think.config.html_v}"></script>
<script src="__PUBLIC__/static/js/bootbox.min.js?{$Think.config.html_v}"></script>
<!-- custom -->
<script src="__PUBLIC__/static/js/common.js?{$Think.config.html_v}"></script>
<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['clientinfo']}"};</script>

View File

@ -0,0 +1,176 @@
{include file="common:header_public" /}
{block name="cssjs"}{/block}
</head>
<body class="skin-blue" data-spy="scroll" data-target="#scrollspy">
<script type="text/javascript">admincpInit();</script>
<div class="wrapper">
<header class="main-header">
<a href="{:url('Admin/Backstage/index')}" class="logo">
蓝天采集器
</a>
<nav class="navbar navbar-static-top" role="navigation">
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
<span class="sr-only"> </span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<span class="glyphicon glyphicon-user"></span>
<span>{$GLOBALS['user']['username']}</span>
</a>
<ul class="dropdown-menu">
<li><a href="{:url('User/edit?uid='.$GLOBALS['user']['uid'])}">{$Think.lang.user_edit}</a></li>
<li><a href="{:url('Admin/Index/logout')}">{$Think.lang.logout}</a></li>
</ul>
</li>
</ul>
</div>
</nav>
</header>
{php}$curMenu=array(strtolower(request()->controller())=>' menu-open cur-menu');{/php}
<aside class="main-sidebar">
<section class="sidebar">
<ul class="sidebar-menu" data-widget="tree">
<li class="treeview{$curMenu['setting']}">
<a href="#">
<i class="fa fa-cog"></i> <span>{$Think.lang.setting}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<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/email')}"><i class="fa fa-circle-o"></i> {$Think.lang.setting_email}</a></li>
</ul>
</li>
<li class="treeview{$curMenu['task']}{$curMenu['taskgroup']}{$curMenu['collector']}{$curMenu['release']}">
<a href="#">
<i class="fa fa-tasks"></i> <span>{$Think.lang.task}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><a href="{:url('Admin/Task/list')}"><i class="fa fa-circle-o"></i> {$Think.lang.task_list}</a></li>
<li><a href="{:url('Admin/Task/add')}"><i class="fa fa-circle-o"></i> {$Think.lang.task_add}</a></li>
<li class="treeview">
<a href="#"><i class="fa fa-circle-o"></i> {$Think.lang.taskgroup}
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu" style="display:none;">
<li><a href="{:url('Taskgroup/list')}"><i class="fa fa-circle-o"></i> {$Think.lang.taskgroup_list}</a></li>
<li><a href="{:url('Taskgroup/add')}"><i class="fa fa-circle-o"></i> {$Think.lang.taskgroup_add}</a></li>
</ul>
</li>
</ul>
</li>
<li class="treeview{$curMenu['store']}{$curMenu['mystore']}">
<a href="#">
<i class="fa fa-cloud"></i> <span>云端</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><a href="{:url('Admin/Store/index')}"><i class="fa fa-circle-o"></i> 云平台</a></li>
<li class="treeview menu-open">
<a href="#"><i class="fa fa-circle-o"></i> 已下载
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu" style="display:block;">
<li><a href="{:url('Admin/Mystore/Collect')}"><i class="fa fa-circle-o"></i> 采集规则</a></li>
<li><a href="{:url('Admin/Mystore/ReleaseApp')}"><i class="fa fa-circle-o"></i> 发布插件</a></li>
</ul>
</li>
</ul>
</li>
<li class="treeview{$curMenu['collected']}">
<a href="#">
<i class="fa fa-database"></i> <span>{$Think.lang.collected}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><a href="{:url('Admin/Collected/list')}"><i class="fa fa-circle-o"></i> {$Think.lang.collected_list}</a></li>
</ul>
</li>
<li class="treeview{$curMenu['user']}">
<a href="#">
<i class="fa fa-user"></i> <span>{$Think.lang.user}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><a href="{:url('Admin/User/list')}"><i class="fa fa-circle-o"></i> {$Think.lang.user_list}</a></li>
</ul>
</li>
<li class="treeview{$curMenu['develop']}{$curMenu['tool']}">
<a href="#">
<i class="fa fa-wrench"></i> <span>工具&amp;开发</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li><a href="{:url('Admin/Develop/releaseCms')}"><i class="fa fa-circle-o"></i> CMS发布插件</a></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/logs')}"><i class="fa fa-circle-o"></i> 错误日志</a></li>
<li class="treeview">
<a href="#"><i class="fa fa-circle-o"></i> 校验
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu" style="display:none;">
<li><a href="{:url('Admin/Tool/checkfile')}"><i class="fa fa-circle-o"></i> 文件</a></li>
<li><a href="{:url('Admin/Tool/checkdb')}"><i class="fa fa-circle-o"></i> 数据库</a></li>
</ul>
</li>
</ul>
</li>
<li class="treeview">
<a href="#">
<i class="fa fa-dashboard"></i> <span>{$Think.lang.admincp_style}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu treeview-config">
<li>
<div class="checkbox"><label><input id="chk_sidebar_mini" type="checkbox"> {$Think.lang.admincp_sidebar_mini}</label></div>
</li>
<li>
<div>{$Think.lang.admincp_skins}</div>
<div id="sidebar_skins"></div>
</li>
</ul>
</li>
</ul>
</section>
</aside>
<div class="content-wrapper">
<section class="content-header">
<h1>{$GLOBALS['content_header']}</h1>
<ol class="breadcrumb">
<li><a href="{:url('Admin/Backstage/index')}"><i class="fa fa-dashboard"></i> {$Think.lang.admincp}</a></li>
{$GLOBALS['breadcrumb']}
</ol>
</section>
<section class="content">
{block name="content"}
{/block}
</section>
</div>
{include file="common:footer" /}

View File

@ -0,0 +1,9 @@
{include file="common:header_public" /}
{block name="cssjs"}{/block}
</head>
<body>
<div class="container-fluid">
{block name="content"}
{/block}
</div>
{include file="common:footer_public" /}

View File

@ -0,0 +1,45 @@
{php}
$_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:footer_public" /}

View File

@ -0,0 +1,46 @@
{php}
$_WP['title']=$msg;
{/php}
{extend name="common:main" /}
{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>
{/block}

View File

@ -0,0 +1,262 @@
<form id="form_field" method="post" action="{:url('Cpattern/field')}">
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<div class="input-group">
<span class="input-group-addon" style="background:#f4f4f4;">字段名称</span>
<input type="text" name="field[name]" class="form-control" />
<div class="input-group-btn c-p-field-source" title="选择数据源">
<select name="field[source]" class="form-control slt-field-source">
<optgroup label="选择数据源">
<option value="">默认页</option>
<option value="source_url">起始页</option>
</optgroup>
</select>
</div>
</div>
</div>
<div class="form-group">
<div class="input-group" style="margin-bottom:10px;">
<span class="input-group-addon" style="background:#f4f4f4;">获取方式</span>
<select name="field[module]" class="form-control">
<option value="rule">{$Think.lang.field_module_rule}</option>
<option value="xpath">{$Think.lang.field_module_xpath}</option>
<option value="json">{$Think.lang.field_module_json}</option>
<option value="auto">{$Think.lang.field_module_auto}</option>
<optgroup label="数据生成">
<option value="words">{$Think.lang.field_module_words}</option>
<option value="num">{$Think.lang.field_module_num}</option>
<option value="time">{$Think.lang.field_module_time}</option>
<option value="list">{$Think.lang.field_module_list}</option>
</optgroup>
<optgroup label="字段">
<option value="extract">字段提取内容</option>
<option value="merge">{$Think.lang.field_module_merge}</option>
</optgroup>
</select>
</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>
</div>
<div class="c-p-field-module" module="auto" style="display:none;">
<div class="form-group" style="text-align:center;">
<p>自动提取页面中的内容:</p>
<label class="radio-inline">
<input type="radio" name="field[auto]" value="title">标题
</label>
<label class="radio-inline">
<input type="radio" name="field[auto]" value="content">正文
</label>
<label class="radio-inline">
<input type="radio" name="field[auto]" value="keywords">keywords
</label>
<label class="radio-inline">
<input type="radio" name="field[auto]" value="description">description
</label>
<label class="radio-inline">
<input type="radio" name="field[auto]" value="url">页面网址
</label>
</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>
</div>
<div class="c-p-field-module" module="words" style="display:none;">
<textarea name="field[words]" class="form-control" rows="3">{$field['words']}</textarea>
</div>
<div class="c-p-field-module" module="num" style="display:none;">
<div class="input-group col-sm-8" style="margin:0 auto;">
<div class="input-group-addon">范围</div>
<input type="number" name="field[num_start]" class="form-control" value="{$field['num_start']?intval($field['num_start']):1}" />
<div class="input-group-addon"></div>
<input type="number" name="field[num_end]" class="form-control" value="{$field['num_end']?intval($field['num_end']):100}" />
</div>
</div>
<div class="c-p-field-module" module="time" style="display:none;">
<div class="input-group" style="margin-bottom:7px;">
<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:;">[]</a> &nbsp; <a href="javascript:;">[]</a> &nbsp; <a href="javascript:;">[]</a> &nbsp;
<a href="javascript:;">[]</a> &nbsp; <a href="javascript:;">[]</a> &nbsp; <a href="javascript:;">[]</a>
</p>
<div class="input-group">
<div class="input-group-addon">范围随机</div>
<input type="text" name="field[time_start]" class="form-control" placeholder="默认当前时间" />
<div class="input-group-addon"></div>
<input type="text" name="field[time_end]" class="form-control" placeholder="默认当前时间" />
<div class="input-group-btn"><button type="button" class="btn btn-default" onclick="$(this).parent().siblings('input:text').val('');">清空</button></div>
</div>
<div class="checkbox"><label><input type="checkbox" name="field[time_stamp]" value="1" {$field['time_stamp']?'checked="checked"':''}> 转换成时间戳</label></div>
</div>
<div class="c-p-field-module" module="list" style="display:none;">
<textarea name="field[list]" class="form-control" rows="3">{$field['list']}</textarea>
<p class="help-block">一行一条数据,从列表中随机抽取</p>
</div>
<div class="c-p-field-module" module="merge" style="display:none;">
<textarea name="field[merge]" class="form-control" rows="3">{$field['merge']}</textarea>
<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">
<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>
</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>
<select name="field[extract]" class="form-control">
<option value="">请选择</option>
</select>
</div>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">提取内容</div>
<select name="field[extract_module]" class="form-control">
<option value="">请选择</option>
<option value="cover">第一张图片</option>
<option value="phone">电话</option>
<option value="email">邮箱</option>
<option value="rule">规则匹配</option>
<option value="xpath">xpath匹配</option>
<option value="json">json提取</option>
</select>
</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>
</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;">
</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>
</div>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>
</div>
</form>
<script type="text/javascript">
{if condition="$field"}
c_pattern.field_op('init',{field:{$field|json_encode}});
{else /}
c_pattern.field_op('init');
{/if}
</script>

View File

@ -0,0 +1,98 @@
<form id="form_level_url" method="post" action="{:url('Cpattern/level_url')}">
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<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>
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>
</div>
</form>
<script type="text/javascript">
{if condition="$level_url"}
c_pattern.level_url_op('init',{level_url:{$level_url|json_encode}});
{else /}
c_pattern.level_url_op('init');
{/if}
</script>

View File

@ -0,0 +1,27 @@
<form id="form_paging_field" method="post" action="{:url('Cpattern/paging_field')}">
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">选择字段</span>
<select class="form-control" name="paging_field[field]">
</select>
</div>
</div>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">分页分隔符</span>
<input type="text" name="paging_field[delimiter]" class="form-control" placeholder="选填,内容多页之间插入字符" />
</div>
</div>
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>
</div>
</form>
<script type="text/javascript">
{if condition="$pagingField"}
c_pattern.paging_field_op('init',{paging_field:{$pagingField|json_encode}});
{else /}
c_pattern.paging_field_op('init');
{/if}
</script>

View File

@ -0,0 +1,45 @@
<div id="window_process">
<div class="form-group">
<div class="input-group">
<span class="input-group-addon">处理方式</span>
<select name="process[module]" class="form-control">
<option value="">请选择</option>
<option value="html">{$Think.lang.process_module_html}</option>
<option value="replace">{$Think.lang.process_module_replace}</option>
<option value="batch">{$Think.lang.process_module_batch}</option>
<option value="filter">{$Think.lang.process_module_filter}</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>
</select>
<span class="input-group-btn">
<button class="btn btn-default process-add" type="button">添加</button>
</span>
</div>
</div>
{include file="cpattern:process_module" /}
{if condition="empty($type)"}
<form id="form_process" method="post" action="{:url('Cpattern/process?op=sub')}" style="display:none;">
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<div class="panel-group c-p-process-accordion">
</div>
</div>
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>
</div>
</form>
{/if}
</div>
<script type="text/javascript">
{if condition="empty($type)"}
{if condition="!empty($process)"}
c_pattern.process_op('init',{process:{$process|json_encode}});
{else /}
c_pattern.process_op('init');
{/if}
{elseif condition="$type eq 'common'" /}
c_pattern.process_op('init',{formObj:'#coll_pattern_process'});
{/if}
</script>

View File

@ -0,0 +1,8 @@
<div id="c_p_process_load">
{include file="cpattern:process_module" /}
</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}});
{/if}
</script>

View File

@ -0,0 +1,158 @@
<!-- 数据处理模块 -->
<div style="display:none;">
<div class="c-p-process-module" module="html">
<section>
<ul class="nav nav-tabs">
<li class="active"><a href="#p_m_html_allow" data-toggle="tab">保留标签</a></li>
<li><a href="#p_m_html_filter" data-toggle="tab">过滤标签</a></li>
</ul>
<div class="tab-content" style="padding-top:10px;">
<div class="tab-pane fade in active" id="p_m_html_allow">
<div class="form-group">
<input type="text" data-process="html:html_allow" class="form-control" value="p,br,img" />
<div class="p-m-html-tags" module-html="html_allow">
<a href="javascript:;"><span>img</span>图片</a>
<a href="javascript:;"><span>a</span>超链接</a>
<a href="javascript:;"><span>p</span>段落</a>
<a href="javascript:;"><span>br</span>换行</a>
</div>
</div>
</div>
<div class="tab-pane fade" id="p_m_html_filter">
<div class="form-group">
<input type="text" data-process="html:html_filter" class="form-control" value="" />
<div class="p-m-html-tags" module-html="html_filter">
<a href="javascript:;"><span>all</span>全部标签</a>
<a href="javascript:;"><span>a</span>超链接</a>
<a href="javascript:;"><span>img</span>图片</a>
<a href="javascript:;"><span>div</span></a>
<a href="javascript:;"><span>p</span>段落</a>
<a href="javascript:;"><span>br</span>换行</a>
<a href="javascript:;"><span>form</span>表单</a>
<a href="javascript:;"><span>iframe</span>框架</a>
<a href="javascript:;"><span>object</span>对象</a>
<a href="javascript:;"><span>script</span>脚本</a>
<a href="javascript:;"><span>style</span>样式</a>
<a href="javascript:;"><span>link</span>外部样式</a>
</div>
</div>
</div>
</div>
<p>其它标签可直接输入,用空格或逗号分隔</p>
</section>
</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>
<div class="input-group-addon iga-rt">
<a href="javascript:;" title="{$Think.lang.tips_sign_wildcard}" class="blk sign-wildcard">{$Think.lang.sign_wildcard}</a>
<span title="{$Think.lang.tips_regular}" class="blk">正则</span>
</div>
</div>
<p style="margin:5px 0;">替换成</p>
<div class="form-group">
<textarea data-process="replace:replace_to" rows="3" class="form-control"></textarea>
</div>
</div>
<div class="c-p-process-module" module="filter">
<div class="form-group">
<label>一行一个过滤词</label>
<textarea data-process="filter:filter_list" rows="3" class="form-control"></textarea>
</div>
<div class="form-group">
<label>过滤词替换成</label>
<input type="text" data-process="filter:filter_replace" class="form-control" value="" />
</div>
<div class="checkbox"><label><input type="checkbox" data-process="filter:filter_pass" value="1" /> 检测到过滤词将该字段值设为空</label></div>
</div>
<div class="c-p-process-module" module="translate">
<div class="form-group">
<div class="input-group">
<select data-process="translate:translate_from" class="form-control">
<option value="">--源语言--</option>
<option value="zh">中文</option>
<option value="en">英语</option>
<option value="fra">法语</option>
<option value="jp">日语</option>
<option value="kor">韩语</option>
<option value="de">德语</option>
<option value="ru">俄语</option>
<option value="spa">西班牙语</option>
<option value="pt">葡萄牙语</option>
<option value="it">意大利语</option>
<option value="ara">阿拉伯语</option>
<option value="cht">繁体中文</option>
</select>
<span class="input-group-addon">翻译为</span>
<select data-process="translate:translate_to" class="form-control">
<option value="">--目标语言--</option>
<option value="zh">中文</option>
<option value="en">英语</option>
<option value="fra">法语</option>
<option value="jp">日语</option>
<option value="kor">韩语</option>
<option value="de">德语</option>
<option value="ru">俄语</option>
<option value="spa">西班牙语</option>
<option value="pt">葡萄牙语</option>
<option value="it">意大利语</option>
<option value="ara">阿拉伯语</option>
<option value="cht">繁体中文</option>
</select>
</div>
</div>
<p class="help-block">不支持自动识别,必须指定源语言和目标语言</p>
</div>
<div class="c-p-process-module" module="tool">
<div class="checkbox">
<label><input type="checkbox" data-process="tool:tool_list" value="trim" />去除前后空格</label>
&nbsp; <label><input type="checkbox" data-process="tool:tool_list" value="format" />清除文本格式去除html元素的style、width、height等</label>
&nbsp; <label><input type="checkbox" data-process="tool:tool_list" value="is_img" />内容是图片链接</label>
</div>
</div>
<div class="c-p-process-module" module="batch">
<div class="form-group">
<label>批量替换</label>
<textarea data-process="batch:batch_list" rows="3" class="form-control"></textarea>
<p class="help-block">一行一对替换词,用“=”分隔例如aa=bb即将“aa”替换成“bb”</p>
</div>
</div>
<div class="c-p-process-module" module="substr">
<div class="form-group">
<label>截取长度</label>
<input type="number" data-process="substr:substr_len" class="form-control" />
</div>
<div class="form-group">
<label>结尾字符</label>
<input type="text" data-process="substr:substr_end" class="form-control" />
</div>
</div>
<div class="c-p-process-module" module="func">
<div class="form-group">
<label>PHP函数名</label>
<select data-process="func:func_name" class="form-control">
<option value="">--请选择--</option>
{foreach $Think.config.allow_process_func as $k=>$v}
<option value="{$k}">{$v}</option>
{/foreach}
{if is_array($Think.config.EXTEND_PROCESS_FUNC)}
{foreach $Think.config.EXTEND_PROCESS_FUNC as $k=>$v}
<option value="{$k}">{$v}</option>
{/foreach}
{/if}
</select>
</div>
<div class="form-group">
<label>传入参数</label>
<textarea data-process="func:func_param" rows="2" class="form-control" placeholder="默认###传入当前字段的值"></textarea>
<p class="help-block">
一行一个值,使用###表示当前字段的值,请按函数传参,否则运行出错!<a href="javascript:;" onclick="$(this).siblings('span').show();">扩展函数</a>
<span style="display:none;">
<br>
出于安全考虑,如需扩展函数,请在根目录/data/config.php中添加配置
'EXTEND_PROCESS_FUNC'=>array('PHP函数名'=>'描述')
</span>
</p>
</div>
</div>
</div>

View File

@ -0,0 +1,58 @@
<form id="form_relation_url" method="post" action="{:url('Cpattern/relation_url')}">
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<label class="control-label">关联页名称</label>
<input type="text" class="form-control" name="relation_url[name]" placeholder=""/>
</div>
<div class="form-group">
<label class="control-label">从页面中提取</label>
<select name="relation_url[page]" class="form-control">
<option value="">默认内容页</option>
</select>
</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>
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>
</div>
</form>
<script type="text/javascript">
{if condition="$relation_url"}
c_pattern.relation_url_op('init',{relation_url:{$relation_url|json_encode}});
{else /}
c_pattern.relation_url_op('init');
{/if}
</script>

View File

@ -0,0 +1,582 @@
<ul id="coll_tab" class="nav nav-tabs coll-tab">
<li class="active"><a href="#coll_pattern_coll" data-toggle="tab">采集器设置</a></li>
<li><a href="#coll_pattern_source" data-toggle="tab">起始页网址</a></li>
<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">
<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/save2store?coll_id='.$collData['id'])}" title="云端存储,下载规则更方便!" onclick="windowModal('保存到云端',$(this).attr('href'));return false;">上传至云端</a></li>
<li><a href="{:url('Collector/export?coll_id='.$collData['id'])}" target="_blank">导出至本地</a></li>
</ul>
</li>
{/if}
</ul>
<div id="coll_tab_content" class="tab-content" style="margin-top:-1px">
<div class="tab-pane fade in active" id="coll_pattern_coll">
<div class="panel panel-default">
<div class="panel-body">
<div class="form-group">
<label class="control-label">{$Think.lang.coll_name}</label>
<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;">
</div>
<div class="form-group">
<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>
</div>
<p class="help-block">需先配置<a href="{:url('Setting/page_render')}">页面渲染</a>可自动加载ajax内容</p>
</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>
</div>
<p class="help-block">将所有页面源码中的相对地址转换成绝对地址包含超链接、图片、JS链接等</p>
</div>
<div class="form-group">
<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>
</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[url_repeat]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[url_repeat]" value="0"> </label>
</div>
<p class="help-block">默认将已采集网址排重过滤,选择“是”允许重复采集</p>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_request_headers" aria-expanded="false">请求头信息</a>
</h4>
</div>
<div id="coll_pattern_request_headers" 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"> </label>
</div>
</div>
<div id="c_p_request_headers_open" style="display:none;">
<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="h-title">
<label class="control-label">自定义</label>
<a href="javascript:;" class="glyphicon glyphicon-plus add-request-header" title="添加"></a>
</div>
<div class="form-group">
<div class="table-responsive">
<table class="table table-hover c-p-request-headers">
<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>
</div>
</div>
<div class="tab-pane fade" id="coll_pattern_source">
<div class="panel panel-default">
<div class="panel-body">
<div class="form-group">
<label class="control-label">起始网址</label>
<a href="javascript:;" class="glyphicon glyphicon-plus" title="添加"></a>
<a href="javascript:;" class="glyphicon glyphicon-trash" title="清空"></a>
</div>
<div class="c-p-source-urls">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" autocomplete="off" name="config[source_url][]">
<div class="input-group-addon brl_0"><a href="javascript:;" class="glyphicon glyphicon-edit"></a></div>
<div class="input-group-addon brl_0"><a href="javascript:;" class="glyphicon glyphicon-remove"></a></div>
<div class="input-group-addon"><a href="javascript:;" class="glyphicon glyphicon-arrow-up"></a> <a href="javascript:;" class="glyphicon glyphicon-arrow-down"></a></div>
</div>
</div>
</div>
</div>
<div class="panel-footer" style="padding-top:5px;padding-bottom:5px;">
<div class="checkbox">
<label>
<input type="checkbox" name="config[source_is_url]" value="1"> 设置为内容页网址(不选则为列表页)
</label>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="coll_pattern_link">
<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>
</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>
<a href="javascript:;" class="glyphicon glyphicon-plus add-level-url" title="添加"></a>
</div>
<div class="table-responsive">
<table id="c_p_level_urls" class="table table-bordered table-hover">
<thead>
<tr>
<th>级别</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="panel panel-default" id="panel_coll_pattern_cont_url">
<div class="panel-heading">
<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>
</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">
<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="添加"></a></label>
<div class="table-responsive">
<table class="table table-hover c-p-url-posts">
<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 -->
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_relation_url" aria-expanded="false">关联页网址获取</a>
</h4>
</div>
<div id="coll_pattern_relation_url" class="panel-collapse collapse">
<div class="panel-body">
<div class="h-title">
<span class="is-loading"></span>
<label class="control-label">关联页规则</label>
<a href="javascript:;" class="glyphicon glyphicon-plus add-relation-url" title="添加"></a>
</div>
<div class="table-responsive">
<table id="c_p_relation_urls" class="table table-bordered table-hover">
<thead>
<tr>
<th>名称</th>
<th>从页面中提取</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
{if condition="!empty($collData)"}
<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">
测试(需先保存设置)
<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=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>
</ul>
</div>
</div>
{/if}
</div>
<div class="tab-pane fade" id="coll_pattern_field">
<div class="panel panel-default">
<div class="panel-body">
<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>
</div>
<div class="table-responsive">
<table class="table table-bordered table-hover c-p-field-list" style="margin-bottom:10px;">
<thead>
<tr>
<th>字段</th>
<th>数据源</th>
<th>获取方式</th>
<th>操作</th>
<th title="把字段作为标题进行排重,默认无">
<label class="radio-inline"><input type="radio" name="config[field_title]" value=""><b>标题排重</b></label>
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<p id="c_p_field_loop_tips" class="help-block" style="margin-bottom:0px;display:none;">开启循环入库后,将以第一个循环字段的数量为准,后面的循环字段会映射第一个循环字段的索引并自动获取相应位置的值入库,非循环字段则以当前值入库;如开启了分页,分页内容也会循环入库</p>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_process" aria-expanded="false">数据处理(通用)</a>
</h4>
</div>
<div id="coll_pattern_process" class="panel-collapse collapse">
<div class="panel-body">
<div class="h-title">
<label class="control-label">通用数据处理</label>
<a href="javascript:;" class="glyphicon glyphicon-plus add-process" title="添加"></a>
</div>
<div class="panel-group c-p-process-accordion">
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#coll_pattern_paging" aria-expanded="false">内容分页</a>
</h4>
</div>
<div id="coll_pattern_paging" 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[paging][open]" value="1"> </label>
<label class="radio-inline"><input type="radio" name="config[paging][open]" value="0"> </label>
</div>
</div>
<div id="c_p_paging_open" style="display:none;">
<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>
</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>
</div>
</div>
</div>
{if condition="!empty($collData)"}
<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">
测试(需先保存设置)
<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" onclick="windowModal('测试抓取',$(this).attr('href'),{lg:1});return false;">测试抓取数据</a></li>
<li><a href="{:url('Cpattern/test?op=match&coll_id='.$collData['id'])}" target="_blank" onclick="windowModal('模拟匹配',$(this).attr('href'),{lg:1});return false;">模拟匹配数据</a></li>
</ul>
</div>
</div>
{/if}
</div>
</div>
<link href="__PUBLIC__/static/css/jquery.datetimepicker.css" rel="stylesheet">
<script type="text/javascript" src="__PUBLIC__/static/js/jquery.datetimepicker.js"></script>
<script type="text/javascript">
var c_pattern=new CollectorPattern('form_coll');
c_pattern.init();
{if condition="!empty($collData['config'])"}
c_pattern.load({$collData['config']|json_encode});
{/if}
</script>

View File

@ -0,0 +1,84 @@
<style type="text/css">
#form_source .radio{border:1px solid #eee;padding:10px;}
#form_source .radio:hover{background:#efefef;}
#form_source .source-params{display:inline;}
#form_source .source-params *{display:inline;}
#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" />
<input type="hidden" name="source[type]" value="custom" />
<input type="hidden" name="source[uid]" value="{$source['uid']}" />
<ul class="nav nav-tabs">
<li class="active"><a href="#tab_custom" data-toggle="tab" source-type="custom">手工指定</a></li>
<li class=""><a href="#tab_batch" data-toggle="tab" source-type="batch">批量生成</a></li>
<li class=""><a href="#tab_large" data-toggle="tab" source-type="large">大量网址</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane fade in active" id="tab_custom" style="padding:10px 0;">
<p>一行一条列表页网址(http://或https://开头)</p>
<textarea name="source[urls]" class="form-control" rows="5"></textarea>
</div>
<div class="tab-pane fade" id="tab_batch" style="padding:10px 0;">
<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>
<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">
<label>
<input type="radio" name="source[param]" value="num" />
数字
</label>
<div class="source-params">
<input name="source[param_num_start]" type="number" value="1" class="form-control" style="width:70px;">
<input name="source[param_num_end]" type="number" value="5" class="form-control" style="width:70px;">
递增数 <input name="source[param_num_inc]" type="number" value="1" class="form-control" style="width:70px;">
<label><input type="checkbox" name="source[param_num_desc]" value="1"> 倒序</label>
</div>
</div>
<div class="radio form-inline form-group form-group-sm" source-param="letter">
<label>
<input type="radio" name="source[param]" value="letter" />
字母
</label>
<div class="source-params">
<input name="source[param_letter_start]" type="text" value="a" class="form-control" style="width:50px;">
<input name="source[param_letter_end]" type="text" value="z" class="form-control" style="width:50px;">
<label><input type="checkbox" name="source[param_letter_desc]" value="1"> 倒序</label>
</div>
</div>
<div class="radio form-inline form-group form-group-sm" source-param="custom">
<label>
<input type="radio" name="source[param]" value="custom" />
自定义
</label>
<div class="source-params">
<textarea class="form-control" style="width:auto;" name="source[param_custom]" rows="3"></textarea>
一行一个
</div>
</div>
<div class="form-group form-group-sm">
<button type="button" class="btn btn-default btn-block" onclick="c_pattern.source_op('add_sub',{'preview':1})">预览</button>
</div>
<textarea class="form-control disabled" rows="5" id="source_preview" readonly="readonly"></textarea>
</div>
<div class="tab-pane fade" id="tab_large" style="padding:10px 0;">
<p>大量网址,一行一条(http://或https://开头)</p>
<textarea name="source[large_urls]" class="form-control" rows="5"></textarea>
</div>
</div>
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block" onclick="return c_pattern.source_op('add_sub');">提交</button>
</div>
</form>
<script type="text/javascript">
{if condition="$source"}
c_pattern.source_op('init',{source:{$source|json_encode}});
{else /}
c_pattern.source_op('init');
{/if}
</script>

View File

@ -0,0 +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>
{/block}

View File

@ -0,0 +1,151 @@
<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 style="font-style:normal">抓取字段</em> <span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="javascript:;" data-test="get_fields">抓取字段</a></li>
<li><a href="javascript:;" data-test="get_html">抓取源码</a></li>
<li><a href="javascript:;" data-test="elements">分析元素</a></li>
<li><a href="javascript:;" data-test="get_paging_urls">抓取分页</a></li>
<li><a href="javascript:;" data-test="get_relation_urls">抓取关联页</a></li>
</ul>
</div>
{if condition="!empty($url_post)"}
<div class="input-group-addon" style="color:green;">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>
<div class="vals">
</div>
</div>
<script type="text/javascript">
function win_test_view(id){
$('#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/test?op=_op_&coll_id='.$collData['id'].'&cont_url=_url_')}";
url=url.replace('_op_','elements').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('em').eq(0).text($(this).text());
});
{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('页面效果所见即所得点击元素可获取xpath值');
}else if(testOp=='get_html'){
//获取源码,防止源代码输出错误
$.ajax({
type:'get',
url:url,
dataType:'html',
success:function(data){
if(htmlIsJson(data)){
//AJAX错误提示
data=eval('(' + data + ')');
$('#win_test_cont_url .vals').html(data.msg);
}else{
var eleId=generateUUID();
data=data.replace(/\</g,'&lt;').replace(/\>/g,'&gt;');//编码
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{
$.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'){
for(var i in data.data){
if(data.data.length>1){
html+='<div class="panel panel-default"><div class="panel-heading"><h4 class="panel-title"><a data-toggle="collapse" aria-expanded="false">'
+'第'+(parseInt(i)+1)+'条数据</a></h4></div><div class="panel-collapse collapse in"><div class="panel-body">';
}
var vals=data.data[i];//每条数据
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>';
}
html+='<label>'+f+'</label>'+browse+'<textarea id="'+eleId+'" class="form-control">'+vals[f]+'</textarea><br>';
}
if(data.data.length>1){
html+='</div></div></div>';
}
}
}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);
}
}
});
}
}
});
if($('#win_test_cont_url input[name="url"]').val().length>0){
//有网址自动触发
$('#win_test_cont_url button').trigger("click");
}
</script>

View File

@ -0,0 +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_match_ajax" /}
</div>
</div>
{/block}

View File

@ -0,0 +1,52 @@
<div id="win_test_match">
<form method="post" action="{:url('Cpattern/test')}">
<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>
</div>
<div class="form-group">
<label>方式</label>
<select class="form-control" name="type">
<option value="rule">规则匹配</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>
<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>
</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;
});
</script>

View File

@ -0,0 +1,120 @@
<style type="text/css">
#test_source_urls .source_url{padding:5px;}
#test_source_urls p{margin:0;}
</style>
<div id="test_source_urls">
{if condition="empty($source_urls)"}
没有起始页网址
{else /}
{foreach name="source_urls" item="source_url"}
<div class="source_url" url="{$source_url}">
<p><b>抓取起始页面:</b>{$source_url}</p>
<p class="cont_urls_num"></p>
<div class="cont_urls_list">
</div>
</div>
{/foreach}
{/if}
</div>
<script type="text/javascript">
'use strict';//严格模式
var max_num=5;//测试时最多显示数量
var url_ajax_requests=new Array();//ajax对象
$(document).ready(function(){
$('#test_source_urls .source_url').each(function(index){
//起始页开始测试
var obj=$(this);
var source_url=$(this).attr('url');
{if condition="!empty($config['level_urls'])"}
//有多级
if(index<max_num){
//测试前几页
get_cont_urls(source_url,obj,1);
}
{else /}
get_cont_urls(source_url,obj,0);
{/if}
});
//展开收起
$('#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).parent().siblings('.cont_urls_list').hide();
}else{
$(this).html('[收起]');
$(this).attr('status',1);
$(this).parent().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]+'"><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{
//无级别,显示测试网址
var test_cont_url="{:url('Cpattern/test?op=cont_url&coll_id='.$collData['id'])}&cont_url=_url_";
var ele_cont_url="{:url('Cpattern/test?op=elements&coll_id='.$collData['id'])}&cont_url=_url_";
for(var i in urls){
list+='<li>[<a href="'+(test_cont_url.replace('_url_',encodeURIComponent(urls[i])))+'" target="_test_cont">测试</a>] '
+'[<a href="'+(ele_cont_url.replace('_url_',encodeURIComponent(urls[i])))+'" target="_test_cont">元素</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

@ -0,0 +1,55 @@
<form id="win_form_param" method="post" action="{:url('Develop/cmsAddParam')}">
<input type="hidden" name="objid" value="{$objid}" />
<div class="form-group">
<label>变量名(英文)</label>
<input type="text" name="param[key]" class="form-control" autocomplete="off" />
<p class="help-block">变量名在代码中调用必须符合php的变量命名规范</p>
</div>
<div class="form-group">
<label>必填</label>
<div class="input-group">
<label class="radio-inline"><input type="radio" name="param[require]" value="1"></label>
<label class="radio-inline"><input type="radio" name="param[require]" value="0"></label>
</div>
</div>
<div class="form-group">
<label>参数名称(中文)</label>
<input type="text" name="param[name]" class="form-control" autocomplete="off" />
<p class="help-block">在前端页面中显示,供用户操作</p>
</div>
<div class="form-group">
<label>参数类型</label>
<select name="param[type]" class="form-control">
<option value="">请选择</option>
{foreach name="typeList" item="tval" key="tkey"}
<option value="{$tkey}">{$tval}</option>
{/foreach}
</select>
<p class="help-block">在前端页面中显示,供用户操作</p>
</div>
<div class="form-group param-type-select" data-select="select_val" style="display:none;">
<label>选项值</label>
<textarea class="form-control" name="param[select_val]" rows="3" placeholder=""></textarea>
<p class="help-block">
一行一个,直接输入值或键值对形式输入<br/>例如:<br/>
a=好评<br/>
b=中评<br/>
c=差评<br/>
</p>
</div>
<div class="form-group param-type-select" data-select="select_func" style="display:none;">
<label>函数名</label>
<input type="text" name="param[select_func]" class="form-control" />
<p class="help-block">函数名必须以“param_option_”开头</p>
</div>
<div class="form-group form-group-sm">
<button type="submit" class="btn btn-primary btn-block">确定</button>
</div>
</form>
<script type="text/javascript">
developClass.init_cms_param();
{if condition="!empty($param)"}
developClass.load_cms_param({$param|json_encode});
{/if}
</script>

View File

@ -0,0 +1,87 @@
{extend name="common:main" /}
{block name="cssjs"}
<script type="text/javascript" src="__PUBLIC__/static/js/admin/develop.js?{$Think.config.html_v}"></script>
{/block}
{block name="content"}
<div class="box box-default">
<div class="box-body">
<form id="form_cms" method="post" ajax-submit="true" action="{:url('Admin/Develop/releaseCms')}">
{if condition="$config['is_edit']"}
{if $is_old_plugin}
<div class="alert alert-error">
{:lang('release_upgrade')}
</div>
{else/}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
请在 {$config['app_file']} 文件中编辑代码
</div>
{/if}
<input type="hidden" name="edit" value="1" />
<input type="hidden" name="app" value="{$config['app']}" />
{/if}
<div class="form-group">
<label>插件名称</label>
<input type="text" name="name" class="form-control">
<p class="help-block">精简描述该插件</p>
</div>
<div class="form-group">
<label>CMS程序</label>
<select name="cms_name" class="form-control">
<option value="">请选择</option>
<option value="wordpress">wordpress</option>
<option value="discuz">discuz</option>
<option value="dedecms">dedecms</option>
<option value="phpcms">phpcms</option>
<option value="empirecms">帝国CMS</option>
<option value="custom">自定义</option>
</select>
<div id="cms_name_custom" style="display:none;">
<input type="text" name="cms_name_custom" class="form-control">
<p class="help-block">自定义时请输入CMS程序的英文全称</p>
</div>
</div>
<div class="form-group">
<label>插件功能标识</label>
<input type="text" name="identifier" class="form-control">
<p class="help-block">表示该插件的作用,只能输入字母或数字</p>
</div>
<div class="form-group">
<label>作者版权</label>
<input type="text" name="copyright" class="form-control">
<p class="help-block">版权归属能有效区分他人开发的插件,只能输入字母或数字</p>
</div>
<div class="form-group">
<div class="h-title">
<label class="control-label">参数</label>
<a href="javascript:;" id="add_param" class="glyphicon glyphicon-plus" title="添加"></a>
</div>
</div>
<div class="form-group">
<div class="table-responsive">
<table class="table table-hover" id="param_list" style="margin-bottom:0;">
<thead>
<tr>
<th class="col-xs-2">变量名(英文)</th>
<th class="col-xs-2">必填</th>
<th class="col-xs-2">参数名(中文)</th>
<th class="col-xs-2">参数类型</th>
<th class="col-xs-2">删除</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">{$Think.lang.save}</button>
</div>
</form>
</div>
</div>
<script type="text/javascript">
developClass.release_cms({$config|json_encode});
</script>
{/block}

View File

@ -0,0 +1,84 @@
{include file="common:header_public" /}
</head>
<body class="hold-transition login-page">
<div class="login-box">
<div class="login-logo">
<a href="{:url('Admin/index/index')}">蓝天采集器</a>
</div>
<div class="login-box-body">
<p class="login-box-msg">{$Think.lang.find_password}</p>
<form action="{:url('Admin/index/find_password')}" ajax-submit="true" method="post">
{:html_usertoken()}
<input type="hidden" name="subForPwd" value="1" />
<input type="hidden" name="step" value="{$step}" />
{if condition="$step elt 1"}
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="text" name="username" class="form-control" placeholder="{$Think.lang.find_pwd_username}" />
</div>
</div>
{if condition="$GLOBALS['config']['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>
</div>
{/if}
<div class="form-group">
<button class="btn btn-info btn-block" type="submit">{$Think.lang.find_pwd_next_step}</button>
</div>
{elseif condition="$step eq 2"/}
<input type="hidden" name="username" value="{$username}" />
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="text" name="username1" value="{$username}" class="form-control" disabled="disabled" />
<span class="input-group-addon"><a href="javascript:window.location.reload()">{$Think.lang.find_pwd_resend}</a></span>
</div>
</div>
<div class="alert alert-{$emailStatus['success']?'success':'warning'}" role="alert">{$emailStatus['msg']}</div>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-certificate"></span></span>
<input type="text" name="yzm" class="form-control" placeholder="{$Think.lang.find_pwd_yzm}" />
</div>
</div>
<div class="form-group">
<button class="btn btn-info btn-block" type="submit">{$Think.lang.find_pwd_next_step}</button>
</div>
{if condition="!$emailStatus['success']"}
<div class="alert alert-success">
手动修改:在数据库{:config('database.prefix')}user表中将username为“{$username}”的password值改为“{:pwd_encrypt('skycaiji123')}
即密码为“skycaiji123”再登录后台修改密码
</div>
{/if}
{elseif condition="$step eq 3"/}
<input type="hidden" name="username" value="{$username}" />
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="text" value="{$userData['username']}" class="form-control" disabled="disabled" />
</div>
</div>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-asterisk"></span></span>
<input type="password" name="password" class="form-control" placeholder="{$Think.lang.find_pwd_pwd}" />
</div>
</div>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-repeat"></span></span>
<input type="password" name="repassword" class="form-control" placeholder="{$Think.lang.find_pwd_repwd}" />
</div>
</div>
<div class="form-group">
<button class="btn btn-info btn-block" type="submit">{$Think.lang.submit}</button>
</div>
{/if}
</form>
</div>
</div>
{include file="common:footer_public" /}

View File

@ -0,0 +1,47 @@
{include file="common:header_public" /}
</head>
<body class="hold-transition login-page">
<div class="login-box">
<div class="login-logo">
<a href="{:url('Admin/index/index')}">蓝天采集器</a>
</div>
<div class="login-box-body">
<p class="login-box-msg"><a href="http://www.skycaiji.com">SkyCaiji</a> V{:constant('SKYCAIJI_VERSION')} 后台管理</p>
<form action="{:url('Admin/index/login')}" ajax-submit="true" method="post">
{:html_usertoken()}
<input type="hidden" name="sublogin" value="1" />
{if condition="input('?serverinfo')"}
<input type="hidden" name="serverinfo" value="1" />
{/if}
<div class="form-group has-feedback">
<input type="text" name="username" class="form-control" placeholder="{$Think.lang.user_username}">
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="password" name="password" class="form-control" placeholder="{$Think.lang.user_password}">
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
{if condition="$GLOBALS['config']['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>
</div>
{/if}
<div class="input-group-lg">
<div style="float:left;">
<div class="checkbox" style="margin:0 0 15px 0;"><label><input name="auto" type="checkbox" checked="checked"> {$Think.lang.login_auto}</label></div>
</div>
<div style="float:right;">
<a href="{:url('Admin/Index/find_password')}">{$Think.lang.find_password}</a>
</div>
</div>
<div class="from-group" style="clear:both;">
<button type="submit" class="btn btn-primary btn-block">{$Think.lang.login}</button>
</div>
</form>
</div>
</div>
{include file="common:footer_public" /}

View File

@ -0,0 +1,19 @@
{extend name="common:main" /}
{block name="cssjs"}
<script src="__PUBLIC__/static/js/admin/store.js?{$Think.config.html_v}"></script>
{/block}
{block name="content"}
<div class="box">
<div class="box-body">
{if condition="!empty($collectRules)"}
<div class="page-header"><span class="glyphicon glyphicon-th-list"></span> <a href="{:url('Mystore/collect')}">采集规则</a><i class="ph-more"><a href="{:url('Mystore/collect')}">更多 &gt;</a></i></div>
{foreach name="collectRules" item="rule"}
<div class="col-xs-6 col-sm-4"><a href="http://www.skycaiji.com/collect/rule/detail?id={$rule['store_id']}" class="store-detail">{$rule['name']}</a></div>
{/foreach}
{/if}
</div>
</div>
<script type="text/javascript">
storeClass.init_my();
</script>
{/block}

View File

@ -0,0 +1,68 @@
{extend name="common:main" /}
{block name="cssjs"}
<script src="__PUBLIC__/static/js/admin/store.js?{$Think.config.html_v}"></script>
<script src="__PUBLIC__/static/js/admin/mystore.js?{$Think.config.html_v}"></script>
{/block}
{block name="content"}
{php}$orderClass=array($orderKey=>'_'.$sortBy);$orderSort=array($orderKey=>($sortBy=='asc'?'升序':'倒序'));{/php}
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li><a href="{:url('Mystore/Collect')}">采集规则</a></li>
<li class="active"><a href="{:url('Mystore/ReleaseApp')}">发布插件</a></li>
<li class="nav-check-update"><a href="javascript:;" onclick="check_releaseapp_update()">检测更新</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active">
<div class="table-responsive">
<form id="form_list" method="post" ajax-submit="true" action="{:url('Mystore/releaseAppOp')}">
<table id="list_table" class="table table-bordered table-hover datatable">
<thead>
<tr>
<th class="chk">{$Think.lang.select}</th>
<th class="sorting{$orderClass['name']}" data-order="name" title="名称{$orderSort['name']}">名称</th>
<th class="sorting{$orderClass['app']}" data-order="app" title="app{$orderSort['app']}">APP</th>
<th>模块</th>
<th class="sorting{$orderClass['addtime']}" data-order="addtime" title="添加时间{$orderSort['addtime']}">添加时间</th>
<th class="sorting{$orderClass['uptime']}" data-order="uptime" title="更新时间{$orderSort['uptime']}">更新时间</th>
<th>详细</th>
<th>{$Think.lang.op}</th>
</tr>
</thead>
<tbody>
{foreach name="appList" item="app"}
<tr data-app-id="{$app['id']}">
<td class="chk"><input type="checkbox" name="ids[]" value="{$app['id']}" /></td>
<td><a href="http://www.skycaiji.com/release/cms/detail?app={$app['app']}" class="store-detail">{$app['name']}</a></td>
<td>{$app['app']}</td>
<td>{$app['module']}</td>
<td>{:date('Y-m-d H:i',$app['addtime'])}</td>
<td>{:date('Y-m-d H:i',$app['uptime'])}</td>
<td class="store-info"><a href="http://www.skycaiji.com/release/cms/detail?app={$app['app']}" class="store-detail">详细</a></td>
<td><a href="{:url('Develop/releaseCms?app='.$app['app'])}">开发</a> &nbsp; <a href="javascript:;" url="{:url('Mystore/releaseAppOp?op=delete&id='.$app['id'])}" class="delete">删除</a></td>
</tr>
{/foreach}
</tbody>
<tfoot>
<tr>
<td class="chk"><label><input type="checkbox" id="chkall" onclick="checkall(this,'ids[]')" />全部</label></td>
<td colspan="7">
<button type="button" class="btn btn btn-danger" id="deleteall">{$Think.lang.delete}</button>
&nbsp;<a href="{:url('Develop/releaseCms')}" class="btn btn btn-success">开发一个</a>
</td>
</tr>
{if condition="!empty($pagenav)"}
<tr>
<td colspan="5">{$pagenav}</td>
</tr>
{/if}
</tfoot>
</table>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
init_releaseapp();
</script>
{/block}

View File

@ -0,0 +1,63 @@
{extend name="common:main" /}
{block name="cssjs"}
<script src="__PUBLIC__/static/js/admin/store.js?{$Think.config.html_v}"></script>
<script src="__PUBLIC__/static/js/admin/mystore.js?{$Think.config.html_v}"></script>
{/block}
{block name="content"}
{php}$orderClass=array($orderKey=>'_'.$sortBy);$orderSort=array($orderKey=>($sortBy=='asc'?'升序':'倒序'));{/php}
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="active"><a href="{:url('Mystore/Collect')}">采集规则</a></li>
<li><a href="{:url('Mystore/ReleaseApp')}">发布插件</a></li>
<li class="nav-check-update"><a href="javascript:;" onclick="check_rules_update()">检测更新</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active">
<div class="table-responsive">
<form id="form_list" method="post" ajax-submit="true" action="{:url('Mystore/ruleOp')}">
<table id="list_table" class="table table-bordered table-hover datatable">
<thead>
<tr>
<th class="chk">{$Think.lang.select}</th>
<th class="sorting{$orderClass['name']}" data-order="name" title="名称{$orderSort['name']}">名称</th>
<th class="sorting{$orderClass['addtime']}" data-order="addtime" title="添加时间{$orderSort['addtime']}">添加时间</th>
<th class="sorting{$orderClass['uptime']}" data-order="uptime" title="更新时间{$orderSort['uptime']}">更新时间</th>
<th>详细</th>
<th>{$Think.lang.op}</th>
</tr>
</thead>
<tbody>
{foreach name="ruleList" item="rule"}
<tr data-rule-id="{$rule['id']}">
<td class="chk"><input type="checkbox" name="ids[]" value="{$rule['id']}" /></td>
<td><a href="http://www.skycaiji.com/collect/rule/detail?id={$rule['store_id']}" class="store-detail">{$rule['name']}</a></td>
<td>{:date('Y-m-d H:i',$rule['addtime'])}</td>
<td>{:date('Y-m-d H:i',$rule['uptime'])}</td>
<td class="store-info"><a href="http://www.skycaiji.com/collect/rule/detail?id={$rule['store_id']}" class="store-detail">详细</a></td>
<td><a href="javascript:;" url="{:url('Mystore/ruleOp?op=delete&id='.$rule['id'])}" class="delete">删除</a></td>
</tr>
{/foreach}
</tbody>
<tfoot>
<tr>
<td class="chk"><label><input type="checkbox" id="chkall" onclick="checkall(this,'ids[]')" />全部</label></td>
<td colspan="5">
<button type="button" class="btn btn btn-danger" id="deleteall">{$Think.lang.delete}</button>
</td>
</tr>
{if condition="!empty($pagenav)"}
<tr>
<td colspan="5">{$pagenav}</td>
</tr>
{/if}
</tfoot>
</table>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
init_rules();
</script>
{/block}

View File

@ -0,0 +1,23 @@
{if condition="!empty($ruleList)"}
<div id="window_rules">
<ul class="row" id="rule_list">
{foreach name="ruleList" item="rule"}
<li class="col-xs-6" style="padding:0;"><a href="javascript:;" data-id="{$rule['id']}">{$rule['name']}</a></li>
{/foreach}
</ul>
{$pagenav}
<script type="text/javascript">
$('#window_rules #rule_list li a').bind('click',function(){
var id=$(this).attr('data-id');
var name=$(this).text();
import_rule('rule:'+id,name);
});
$('#window_rules .pagination a').bind('click',function(){
windowModal('导入规则',$(this).attr('href'));
return false;
});
</script>
</div>
{else /}
您没有规则,请进入<a href="{:url('Store/index')}">云平台</a>下载
{/if}

View File

@ -0,0 +1,25 @@
{if condition="!empty($cmsApps)"}
{php}$sltedCmsApp=array($cmsApp=>' selected="selected"');{/php}
<div class="form-group">
<div class="input-group">
<label class="input-group-addon"><b>CMS插件</b></label>
<select name="cms[app]" class="form-control">
<option value="">请选择</option>
{foreach name="cmsApps" item="cmsAppV"}
<option value="{$cmsAppV['app']}"{$sltedCmsApp[$cmsAppV['app']]}>{$cmsAppV['name']}</option>
{/foreach}
</select>
</div>
</div>
{if condition="!empty($releCms)"}
<div class="box box-primary">
<div class="box-body">
{php}echo $releCms->tplBind();{/php}
</div>
</div>
{else /}
{$cmsError}
{/if}
{else /}
没有“{$cmsName}”相关的发布插件,在<a href="http://www.skycaiji.com/store/cms?q={$cmsName|rawurlencode}" onclick="windowStore('CMS发布插件',$(this).attr('href'));return false;">云平台</a>中查找
{/if}

View File

@ -0,0 +1,17 @@
<div class="input-group" id="win_db_names">
<select class="form-control">
<option value="">请选择</option>
{foreach name="dbNames" item="dbName"}
<option value="{$dbName}">{$dbName}</option>
{/foreach}
</select>
<div class="input-group-btn">
<button class="btn btn-default" type="button">确定</button>
</div>
</div>
<script type="text/javascript">
$('#win_db_names button').bind('click',function(){
$(releaseClass.formid).find('[name="db[name]"]').val($('#win_db_names select').val());//赋值
$('#myModal').modal('hide');//隐藏
});
</script>

View File

@ -0,0 +1,74 @@
{foreach name="tables" item="table"}
<div class="panel panel-default" style="margin-bottom:10px;">
<div class="panel-heading">
<div class="panel-title">
<a data-toggle="collapse" href="#db_table_name_{$table}" class="collapsed" data-parent="#db_table_bind_list">{$table}表绑定数据</a>
<div style="float:right;font-size:14px;">
<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"></a>
</div>
</div>
</div>
<div id="db_table_name_{$table}" class="panel-collapse collapse in">
<div class="panel-body table-responsive table-db-table-bind">
<table class="table table-hover">
<thead>
<tr>
<th>数据库字段</th>
<th>类型</th>
<th>绑定数据</th>
</tr>
</thead>
<tbody>
{foreach name="fields[$table]" item="field"}
<tr>
<td>
{$field['name']}
</td>
<td>
{$field['type']}
{$field['primary']?' &nbsp; 主键':''}
{$field['autoinc']?' &nbsp; 自增':''}
</td>
<td>
<select name="db_table[field][{$table}][{$field['name']}]" class="form-control">
<option value="">不选择</option>
{foreach name="collFields" item="collField"}
<option value="field:{$collField}">采集字段:{$collField}</option>
{/foreach}
<option value="custom:">自定义内容</option>
</select>
<input class="form-control" style="display:none;" name="db_table[custom][{$table}][{$field['name']}]" />
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
</div>
{/foreach}
{if condition="!empty($field_values)"}
<div id="db_table_bind_values">
<script type="text/javascript">
(function(){
//载入表数据
var field_values={$field_values|json_encode};
if(field_values){
for(var table in field_values){
for(var field in field_values[table]['field']){
$(releaseClass.formid).find('[name="db_table[field]['+table+']['+field+']"]').val(field_values[table]['field'][field]).trigger('change');
}
for(var field in field_values[table]['custom']){
$(releaseClass.formid).find('[name="db_table[custom]['+table+']['+field+']"]').val(field_values[table]['custom'][field]).trigger('change');
}
}
}
})();
$(document).ready(function(){
$('#db_table_bind_values').remove();//删除元素,否则不能上下换位
});
</script>
</div>
{/if}

View File

@ -0,0 +1,8 @@
<span class="input-group-btn"><button class="btn btn-default" type="button" onclick="window.location.reload()">重载</button></span>
<select class="form-control">
<option value="">请选择</option>
{foreach name="tables" item="table"}
<option value="{$table}">{$table}</option>
{/foreach}
</select>
<span class="input-group-btn"><button class="btn btn-default btn-db-table-bind" type="button">绑定数据</button></span>

View File

@ -0,0 +1,6 @@
{extend name="common:main" /}
{block name="cssjs"}
{/block}
{block name="content"}
<a href="">检测CMS程序</a>
{/block}

View File

@ -0,0 +1,31 @@
{if condition="!empty($releList)"}
<div id="window_reles">
<ul class="row" id="rele_list">
{foreach name="releList" item="rele"}
<li class="col-xs-6" style="padding:0;">
<a href="javascript:;" data-id="{$rele['id']}">
{if condition="!empty($taskNames[$rele['task_id']])"}
任务:{$taskNames[$rele['task_id']]}
{else /}
发布:{$rele['name']}
{/if}
</a>
</li>
{/foreach}
</ul>
{$pagenav}
<script type="text/javascript">
$('#window_reles #rele_list li a').bind('click',function(){
var id=$(this).attr('data-id');
var name=$(this).text();
releaseClass.import(id,name);
});
$('#window_reles .pagination a').bind('click',function(){
windowModal('导入规则',$(this).attr('href'));
return false;
});
</script>
</div>
{else /}
没有发布设置
{/if}

View File

@ -0,0 +1,338 @@
{extend name="common:main" /}
{block name="cssjs"}
<script type="text/javascript" src="__PUBLIC__/static/js/admin/release.js?{$Think.config.html_v}"></script>
{/block}
{block name="content"}
<form id="form_rele" class="form-item" method="post" ajax-submit="true" action="{:url('Release/set')}">
<input type="hidden" name="task_id" value="{$taskData['id']}" />
<input type="hidden" name="release_id" value="" />
<div class="form-group">
<div class="input-group">
<label class="input-group-addon">{$Think.lang.rele_module}</label>
<select name="module" class="form-control">
<option value="">{$Think.lang.select_first}</option>
{foreach name="Think.config.release_modules" item="rele_module"}
<option value="{$rele_module}">{:lang('rele_module_'.$rele_module)}</option>
{/foreach}
</select>
<div class="input-group-btn"><button class="btn btn-default" type="button" id="btn_import_release">导入配置</button></div>
</div>
</div>
<div class="rele-module" id="rele_module_cms" module="cms" style="display:none;">
<ul id="cms_tab" class="nav nav-tabs">
<li class="active"><a href="#cms_tab_detect" data-toggle="tab">检测CMS程序</a></li>
<li><a href="#cms_tab_bind" data-toggle="tab">数据绑定</a></li>
<li style="float:right"><a href="{:url('Develop/releaseCms')}">开发插件</a></li>
</ul>
<div id="cms_tab_content" class="tab-content" style="margin-top:-1px">
<div class="tab-pane fade in active" id="cms_tab_detect">
<div class="panel panel-default">
<div class="panel-body">
<div class="form-group">
<button type="button" class="btn btn-default btn-cms-detect">{$Think.lang.rele_btn_detect}</button>
</div>
<div class="form-group" id="cms_list"></div>
</div>
</div>
</div>
<div class="tab-pane fade" id="cms_tab_bind">
<div class="panel panel-default">
<div class="panel-body">
<div class="form-group" id="cms_info">
<div class="input-group">
<div class="input-group-addon">
<a href="javascript:;" onclick="modal('CMS路径',$(this).text());" class="glyphicon glyphicon-info-sign" style="width:16px;overflow:hidden;">
注意是CMS程序在硬盘中的路径并非网址URL蓝天采集器所在路径为{:config('root_path')}
</a>
<b>{$Think.lang.rele_cms_path}</b>
</div>
<input type="text" name="cms[path]" class="form-control" value="{$config['cms']['path']}" />
<span class="input-group-btn"><button class="btn btn-default btn-cms-bind" type="button">开始绑定</button></span>
</div>
</div>
<div class="form-group" id="cms_bind">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="rele-module" module="db" style="display:none;">
<ul id="db_tab" class="nav nav-tabs">
<li class="active"><a href="#db_tab_config" data-toggle="tab">数据库配置</a></li>
<li><a href="#db_tab_table" data-toggle="tab">数据表</a></li>
</ul>
<div id="db_tab_content" class="tab-content" style="margin-top:-1px">
<div class="tab-pane fade in active" id="db_tab_config">
<div class="panel panel-default">
<div class="panel-body">
<div class="form-group">
<label>{$Think.lang.rele_db_type}</label>
<select name="db[type]" class="form-control">
<option value="mysql">mysql</option>
<option value="oracle">oracle</option>
<option value="sqlsrv">sql server</option>
</select>
</div>
<div class="form-group">
<label>{$Think.lang.rele_db_host}</label>
<input name="db[host]" class="form-control" value="{$config['db']['host']?$config['db']['host']:'localhost'}">
</div>
<div class="form-group">
<label>{$Think.lang.rele_db_port}</label>
<input name="db[port]" class="form-control" value="{$config['db']['port']?$config['db']['port']:3306}">
</div>
<div class="form-group">
<label>{$Think.lang.rele_db_charset}</label>
<input name="db[charset]" class="form-control" value="{$config['db']['charset']}">
</div>
<div class="form-group">
<label>{$Think.lang.rele_db_name}</label>
<div class="input-group">
<input name="db[name]" class="form-control" value="{$config['db']['name']}">
<div class="input-group-btn"><button type="button" class="btn btn-default btn-db-names">选择数据库</button></div>
</div>
</div>
<div class="form-group">
<label>{$Think.lang.rele_db_user}</label>
<input name="db[user]" class="form-control" value="{$config['db']['user']}">
</div>
<div class="form-group">
<label>{$Think.lang.rele_db_pwd}</label>
<input type="password" name="db[pwd]" class="form-control" value="{$config['db']['pwd']}">
</div>
<div class="form-group">
<button type="button" class="btn btn-default btn-db-connect">测试连接到数据库</button>
<div class="rele-db-error"></div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="db_tab_table">
<div class="panel panel-default">
<div class="panel-body">
{if condition="empty($releData['config']['db'])"}
请先保存“数据库配置”
{else /}
<div class="form-group">
<div class="input-group db-table-list">
</div>
<div class="db-table-binding" style="margin-top:15px;"></div>
</div>
<div class="form-group">
<div class="panel-group" id="db_table_bind_list"></div>
{if condition="$releData['config']['db']['type'] eq 'oracle'"}
<p class="help-block">Oracel表的自增主键需绑定序列号才能获取自增值自增字段选择“自定义内容”输入“sequence@序列号”例如“sequence@seq_123”</p>
{/if}
<p class="help-block">如需获取表的自增主键值选择“自定义内容”输入“auto_id@表名”例如“auto_id@table123”注意表是按顺序插入数据前面的表不能获取后面表的自增主键值</p>
</div>
{/if}
</div>
</div>
</div>
</div>
</div>
<div class="rele-module" id="rele_module_file" module="file" style="display:none;">
<div class="box box-default">
<div class="box-body">
<div class="form-group">
<label>文件存放目录</label>
<div class="input-group">
<div class="input-group-addon">{:config('root_path')}\data\</div>
<input type="text" class="form-control" name="file[path]" />
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-file-rand-path">随机目录</button>
</div>
</div>
<p class="help-block">请务必输入一个复杂的目录以防止他人破解目录下载数据!</p>
</div>
<div class="form-group">
<label>文件格式</label>
<div class="row">
<div class="col-sm-4" style="padding-top:7px;">
<label class="radio-inline">
<input type="radio" name="file[type]" value="xlsx"> Excel2007(.xlsx格式)
</label>
</div>
<div class="col-sm-4" style="padding-top:7px;">
<label class="radio-inline">
<input type="radio" name="file[type]" value="xls"> Excel2003(.xls格式)
</label>
</div>
<div class="col-sm-4">
<div class="input-group">
<div class="input-group-addon" style="border:0;padding-left:0;">
<label class="radio-inline">
<input type="radio" name="file[type]" value="txt"> txt文本字段分隔符
</label>
</div>
<input type="text" class="form-control" name="file[txt_implode]" placeholder="默认制表符" />
</div>
</div>
</div>
</div>
{if !empty($collFields)}
<div class="form-group">
<label>隐藏采集字段</label>
<div>
{foreach $collFields as $v}
<label class="checkbox-inline"><input type="checkbox" name="file[hide_fields][]" value="{$v}" />{$v}</label>
{/foreach}
</div>
<p class="help-block">勾选的字段不写入文件</p>
</div>
{/if}
</div>
</div>
</div>
<div class="rele-module" id="rele_module_api" module="api" style="display:none;">
<div class="box box-default">
<div class="box-body">
<div class="form-group">
<label>api地址</label>
<div class="input-group">
<div class="input-group-addon">{:config('root_website')}/api_task/{$releData['task_id']}/</div>
<input type="text" class="form-control" name="api[url]" />
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-api-rand-url">随机字符串</button>
</div>
</div>
<p class="help-block">
请务必输入一个复杂的字符串以防止他人破解api下载数据
<br />
{if condition="!empty($releData['config']['api']['url'])"}
API网址<a href="{$apiRootUrl}/api_task/{$releData['task_id']}/{$releData['config']['api']['url']}" target="_blank">{$apiRootUrl}/api_task/{$releData['task_id']}/{$releData['config']['api']['url']}</a>
{/if}
</p>
</div>
<div class="form-group">
<label>数据缓存时间(分钟)</label>
<input type="number" class="form-control" name="api[cache_time]" />
<p class="help-block">留空或0表示实时抓取</p>
</div>
{if !empty($collFields)}
<div class="form-group">
<label>隐藏采集字段</label>
<div>
{foreach $collFields as $v}
<label class="checkbox-inline"><input type="checkbox" name="api[hide_fields][]" value="{$v}" />{$v}</label>
{/foreach}
</div>
<p class="help-block">勾选的字段不显示,默认显示所有字段</p>
</div>
{/if}
</div>
</div>
</div>
<div class="rele-module" id="rele_module_diy" module="diy" style="display:none;">
<input type="hidden" name="diy[type]" value="app">
<ul id="diy_tab" class="nav nav-tabs">
<li class="active"><a href="#diy_tab_app" data-toggle="tab" data-type="app">使用插件</a></li>
<li><a href="#diy_tab_code" data-toggle="tab" data-type="code">使用代码</a></li>
</ul>
<div id="diy_tab_content" class="tab-content" style="margin-top:-1px">
<div class="tab-pane fade in active" id="diy_tab_app">
<div class="panel panel-default">
<div class="panel-body">
<div class="form-group">
<label>插件名</label>
<input type="text" class="form-control" name="diy[app]" />
<p class="help-block">
自定义插件适用于任何网站的数据发布或开发其他发布功能<br>
请在网站根目录/plugin/release/diy目录中创建<b></b>插件可参考目录中的Demo.php文件
</p>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="diy_tab_code">
<div class="panel panel-default">
<div class="panel-body">
{if condition="!config('OPEN_DIY_CODE')"}
出于安全考虑,如需开启该功能,请在根目录配置文件"data/config.php"中添加设置
<b>'OPEN_DIY_CODE'=>TRUE</b>
{else /}
<div class="form-group">
<div class="table-responsive">
<table>
<thead>
<tr>
<th>数据库类型</th>
<th>服务器</th>
<th>库名称</th>
<th>用户名</th>
<th>密码</th>
<th>端口</th>
<th>表前缀</th>
<th>编码</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<select name="diy[db_type]" class="form-control">
<option value="mysql">mysql/mysqli</option>
<option value="sqlserver">mssql/sqlsrv</option>
<option value="oracle">oracle</option>
<option value="mongo">mongo</option>
<option value="sqlite">sqlite</option>
<option value="ibase">ibase</option>
<option value="pgsql">pgsql</option>
<option value="PDO">PDO</option>
</select>
</td>
<td><input type="text" name="diy[db_host]" value="localhost" class="form-control" /></td>
<td><input type="text" name="diy[db_name]" class="form-control" /></td>
<td><input type="text" name="diy[db_user]" class="form-control" /></td>
<td><input type="text" name="diy[db_pwd]" class="form-control" /></td>
<td><input type="text" name="diy[db_port]" value="3306" class="form-control" /></td>
<td><input type="text" name="diy[db_prefix]" class="form-control" /></td>
<td><input type="text" name="diy[db_charset]" value="utf8" class="form-control" /></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<label>PHP代码</label>
<textarea name="diy[code]" class="form-control" rows="5"></textarea>
<div class="help-block">
可用变量:$fields = 采集到的字段数据列表,$url = 采集的页面网址,$this->db() = 数据库操作, 可参考thinkphp5的数据库操作
<br>获取字段值必须使用 $this->get_field_val($field);方法(可处理图片本地化等),否则使用$field['value']调用字段原始值
<p style="border-top:dashed 1px #ccc;padding-top:10px;margin-top:10px;">
必须以数组形式返回:
<br>* id必填表示入库返回的自增id或状态
<br>target可选记录入库的数据位置发布的网址等
<br>desc可选记录入库的数据位置附加信息
<br>error可选入库的错误信息
<br>return array('id'=>0,'target'=>'','desc'=>'','error'=>'');
</p>
入库的信息可在“已采集数据”中查看
</div>
</div>
{/if}
</div>
</div>
</div>
</div>
</div>
{if condition="!empty($releData['config'])"}
<a href="{:url('Release/test?id='.$releData['id'])}" target="_blank" onclick="windowIframe('测试',$(this).attr('href'),{lg:1});return false;" class="btn btn-default btn-block" style="margin-bottom:10px;">测试发布(需先保存设置)</a>
{/if}
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">{$Think.lang.save}</button>
</div>
</form>
{if condition="$taskData"}
{include file="task:stepsbar" /}
{/if}
<script type="text/javascript">
var releaseClass=new ReleaseClass('form_rele',{$releData["id"]|intval});
releaseClass.init();
{if condition="!empty($releData)"}
releaseClass.load({$releData|json_encode});
{/if}
</script>
{/block}

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