1303
前些天有朋友问到了一个联表的聚合查询问题,想到此问题可能很多新手处理都比较棘手,现在特意分享出来。我们有两个数据表:bus表:user表:需求:统计每个人上车数量如何实现呢?第一步:联表这种场景肯定需要两个数据表联表,我们先不考虑统计,我们先进行两个数据表联表。1$data=Db::name('user')->alias('a')->join('bus b','a.user_id=b.user_id')->select()->toArray();alias是别名,join是联表的数据表,并且有联表条件a.user_id=b.user_id,这样我们就能够获取到两个数据表联表的数据了。第二步:聚合查询在做聚合查询前,我们先看下官方手册的教程。因为我们最终是要获取统计的数量,所以我们首先确定用count()方法,所以我们修改查询语句:1$data=Db::name('user')->alias('a')->field('count(b.user_id) AS c'')->join('bus b','a.user_id=b.user_id')->select()->toArray();这其中c,是别名。我们需要根据user_id这个字段进行聚合查询,是根据这个字段统计的,所以我们肯定是group(user_id),也就是按照user_id这个字段进行分组。我们继续修改查询语句:1$data=Db::name('user')->alias('a')->field('count(b.user_id) AS c')->join('bus b','a.user_id=b.user_id')->group('a.user_id')->select()->toArray();这样我们就实现了我们的最终查询结果。第三点:注意情况在上面的查询语句中,如果mysql是5.7版本,那么需要格外注意。比如在mysql5.7中在field中添加a.*,就会报错:12$data=Db::name('user')->alias('a')->field('a.*,count(b.user_id) AS c')->join('bus b','a.user_id=b.user_id')->group('a.user_id')->select()->toArray();[object Object]为什么会有这样的错误呢?MYSQL5.7为了更好的性能,对sql_mode的限制。ONLY_FULL_GROUP_BY: 对于GROUP BY聚合操作的时候,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中,这也就是报错所在。我们可以修改mysql配置:修改/etc/my.cnf,将sql_mode=中的only_full_group_by给删掉这样一个联表的聚合查询就实现了,我们遇到这个问题的时候,不要心急,根据最终的需求,一步步的拆分一步步的实现。以上就是从实例讲解ThinkPHP6联表聚合查询的详细内容
0
0 1409天前
1118
thinkphp导入Excel的方法介绍:开发思路1、先把Excel文件上传到服务器2、获取服务器Excel文件内容3、写入数据库一、上传Excel文件,使用PHP里自带的上传方法 “\Think\Upload();”,可以很方便的实现。为此我整理下使用这个方法的最简单方式1234567891011121314151617181920212223/** * TODO 上传文件方法 * @param $fileid form表单file的name值 * @param $dir 上传到uploads目录的$dir文件夹里 * @param int $maxsize 最大上传限制,默认1024000 byte * @param array $exts 允许上传文件类型 默认array('gif','jpg','jpeg','bmp','png') * @return array 返回array,失败status=0 成功status=1,filepath=newspost/2014-9-9/a.jpg */function uploadfile($fileid,$dir,$maxsize=5242880,$exts=array('gif','jpg','jpeg','bmp','png'),$maxwidth=430){ $upload = new \Think\Upload();// 实例化上传类 $upload->maxSize = $maxsize;// 设置附件上传大小,单位字节(微信图片限制1M $upload->exts = $exts;// 设置附件上传类型 $upload->rootPath = './uploads/'; // 设置附件上传根目录 $upload->savePath = $dir.'/'; // 设置附件上传(子)目录 // 上传文件 $info = $upload->upload(); if(!$info) {// 上传错误提示错误信息 return array(status=>0,msg=>$upload->getError()); }else{// 上传成功 return array(status=>1,msg=>'上传成功',filepath=>$info[$fileid]['savepath'].$info[$fileid]['savename']); }}这里默认上传到ThinkPHP入口文件index.php所在的文件夹uploads,此方法返回一个数据,状态status=1时为成功,也建议大家在写功能模块时或做封装时,整个系统的在架构初期应该有约定,在必要的情况下返回值用数组形式,成功返回1return array(status=>1,data=>....,info=>.....)失败时可以返回1array(status->0,info=>'可以说明出错的原因',....)这样用统一的方式有利于规范开发,团队协作时看代码时可以提高效率,减少思维运转,说远了,上传的方法调用方式如下:123456789//excel 文件 if(!empty($_FILES['xls']['name'])){ $upload=uploadfile('xls','tempxls',5242880,array('xls','xlsx')); if($upload['status']){ $path=$upload['filepath']; }else{ $this->error($upload['msg']); } }二、获取Excel数据1、首先需要引入PHPExcel的类库1require_once 'module/PHPExcel/Classes/PHPExcel/IOFactory.php';2、获取Excel第0张表即(Sheet1)1234//获取excel文件$objPHPExcel = \PHPExcel_IOFactory::load("uploads/$path");$objPHPExcel->setActiveSheetIndex(0);$sheet0=$objPHPExcel->getSheet(0);3、获取行数,并把数据读取出来$data数组1234567891011$rowCount=$sheet0->getHighestRow();//excel行数 $data=array(); for ($i = 2; $i <= $rowCount; $i++){ $item['name']=$this->getExcelValue($sheet0,'A'.$i); $item['sex']=$this->getExcelValue($sheet0,'B'.$i); $item['contact']=$this->getExcelValue($sheet0,'C'.$i); $item['remark']=$this->getExcelValue($sheet0,'D'.$i); $item['addtime']=$this->getExcelValue($sheet0,'E'.$i); $data[]=$item; }三、最后保存到数据123456789101112$success=0; $error=0; $sum=count($data); foreach($data as $k=>$v){ if(M('temp_area3')->data($v)->add()){ $success++; }else { $error++; } } echo "总{$sum}条,成功{$success}条,失败{$error}条。";推荐教程:《TP5》以上就是thinkphp中使用PHPExcel导入Excel的方法的详细内容
0
0 1409天前
1110
WorkermanWorkerman是一款纯PHP开发的开源高性能的PHP socket 服务器框架。被广泛的用于手机app、手游服务端、网络游戏服务器、聊天室服务器、硬件通讯服务器、智能家居、车联网、物联网等领域的开发。 支持TCP长连接,支持Websocket、HTTP等协议,支持自定义协议。基于workerman开发者可以更专注于业务逻辑开发,不必再为PHP Socket底层开发而烦恼。安装首先通过 composer 安装1composer require topthink/think-worker使用使用Workerman作为HttpServer在命令行启动服务端1php think worker然后就可以通过浏览器直接访问当前应用1http://localhost:2346linux下面可以支持下面指令1php think worker [start|stop|reload|restart|status]workerman的参数可以在应用配置目录下的worker.php里面配置。由于onWorkerStart运行的时候没有HTTP_HOST,因此最好在应用配置文件中设置app_hostSocketServer在命令行启动服务端(需要2.0.5+版本)1php think worker:server默认会在0.0.0.0:2345开启一个websocket服务。如果需要自定义参数,可以在config/worker_server.php中进行配置,包括:配置参数描述protocol协议host监听地址port监听端口socket完整的socket地址并且支持workerman所有的参数(包括全局静态参数)。也支持使用闭包方式定义相关事件回调。12345678return [ 'socket' => 'http://127.0.0.1:8000', 'name' => 'thinkphp', 'count' => 4, 'onMessage' => function($connection, $data) { $connection->send(json_encode($data)); },];也支持使用自定义类作为Worker服务入口文件类。例如,我们可以创建一个服务类(必须要继承 think\worker\Server),然后设置属性和添加回调方法1234567891011<?phpnamespace app\http;use think\worker\Server;class Worker extends Server{ protected $socket = 'http://0.0.0.0:2346'; public function onMessage($connection,$data) { $connection->send(json_encode($data)); }}支持workerman所有的回调方法定义(回调方法必须是public类型)然后在worker_server.php中增加配置参数:123return [ 'worker_class' => 'app\http\Worker',];定义该参数后,其它配置参数均不再有效。在命令行启动服务端1php think worker:server然后在浏览器里面访问1http://localhost:2346如果在Linux下面,同样支持reload|restart|stop|status 操作1php think worker:server reload推荐教程:《ThinkPHP》《PHP教程》《Workerman教程》以上就是ThinkPHP6 Workerman 基本使用的详细内容
0
0 1409天前
1158
图片上传功能应该是个极为普遍的,在此参考了 ThinkPHP 框架中的集成方法整理了一下 FTP图片的上传功能,这样方便在后台操作时,把有关的图片直接上传到线上的图片服务器,避免大流量访问的图片加载缓慢,降低网站的访问压力。1、前端设计这里主要为了测试功能的实现,使用最简单的设计,既方便参考又有利于后期的功能扩展。如下附 upload.html主要代码,着重注意红框圈出的代码,其中 css样式比较简单,需要的可以参考后面的源代码。2、后台控制器设计config.class.php 主要代码如下所示,其中设计的表“conf”在此只需用两个字段就好——'tag','value',可以使用简单的varchar类型12345678910111213141516171819202122public function upload(){ if (IS_POST){ foreach ($_FILES as $key => $value){ $img = handleImg($key); $furl = C('REMOTE_ROOT').$img; if ($img){ ftp_upload($furl,$img); $saveData['value'] = $img; M('conf') ->where("tag = '".$key."'") ->save($saveData); } } $this->success('FTP 测试完成',U('Config/upload'),2); }else{ $imgUrl = M('conf') ->where("tag = 'upImg'") ->getField('value'); $this->assign('imgUrl',$imgUrl); $this->display(); }}3、配置数据在公共配置文件中,进行如下常量的数据配置,参考代码如下,注意配置FTP 账号及密码的正确性,此处安全起见只是举例。1234567891011121314//ftp(外网服务器)上传文件相关参数'FTP_SEVER' => 'http://img.52zhenmi.com', //此地址,作为图片读取的位置 请上线前仔细确认'FTP_HOST' => 'img.52zhenmi.com','WEB_SEVER' => 'http://img.52zhenmi.com','WEB_M_SERVER' => 'http://www.52zhenmi.com/m', 'FTP_NAME' => 'fexxxi',//ftp帐户'FTP_PWD' => '1qxxxxxxw',//ftp密码'FTP_PORT' => '21',//ftp端口,默认为21'FTP_PASV' => true,//是否开启被动模式,true开启,默认不开启'FTP_SSL' => false,//ssl连接,默认不开启'FTP_TIMEOUT' => 60,//超时时间,默认60,单位 s'REMOTE_ROOT' => '/',//图片服务器根目录4、引入文件以我的代码为例,在此引用了两个文件,其中的 FTP.class.php 放在了 '/Library/Think' 目录下;Upload.class.php 放在了'/Library/Org/Net'目录下,可根据自己的使用习惯自行调整目录,只要保证实例化路径时没问题就可。5、公共函数添加注意添加上文步骤2中使用到的公共函数。12345678910111213/** * 图片上传的公共处理方法 * @param string $fileName 图片上传的name * @return string 图片的存储路径 */function handleImg($fileName){ if($_FILES[$fileName]['tmp_name'] != ""){ $img = $_FILES[$fileName]; $imgUrl = __ROOT__."/public"; $upload = new \Org\Net\Upload($img, $imgUrl); return $upload->main(); }}FTP上传文件函数123456789101112131415function ftp_upload($remotefile,$localfile){ $ftp = new \Think\Ftp(); $data['server'] = C('FTP_HOST'); $data['username'] = C('FTP_NAME');//ftp帐户 $data['password'] = C('FTP_PWD');//ftp密码 $data['port'] = C('FTP_PORT');//ftp端口,默认为21 $data['pasv'] = C('FTP_PASV');//是否开启被动模式,true开启,默认不开启 $data['ssl'] = C('FTP_SSL');//ssl连接,默认不开启 $data['timeout'] = C('FTP_TIMEOUT');//超时时间,默认60,单位 s $info = $ftp->start($data); if($info){ if($ftp->put($remotefile,$localfile)){} } $ftp->close();}6、操作截图7、提示对于这份参考代码,涉及到的公共方法 handleImg()会先将需要上传的图片传到当前操作的网站根目录,之后又会通过 ftp_upload()将图片传到对应的图片FTP服务器,从实现步骤上看第一步多余,主要是开发过程中的测试服务器不符合FTP账号要求,同时又要方便线上内容修改的及时更新。推荐教程:《TP5》以上就是thinkphp中使用ftp上传图片的详细内容
0
0 1409天前
1153
1.解压"tp5"压缩包到"thinkphp_5.0.24_with_extend\"(E);2.把解压好的"tp5文件夹"—>改名"demo(可以起其它的名字)"->把demo文件夹拷贝到WWW目录;3.在浏览器中输入"http://127.0.0.1/demo/public"—>查看tp5是否可以使用;4.创建或导入一个数据库(我是导入的);5.在application文件夹中—>创建admin文件夹—>在admin文件夹中—>分别创建controller、model、view文件夹—>在controller文件夹中—>创建Login.php;D:\phpStudy\WWW\demo\application\admin\controller\Login.php内容12345678910111213141516171819202122232425262728293031<?phpnamespace app\admin\controller;use think\Controller;use app\admin\model\Login as Log;class Login extends Controller{ public function index() { // $linkres= \think\Db::name('link')->paginate(3); // $this->assign('linkres',$linkres); if(request()->isPost()){ $login=new Log; $status=$login->login(input('username'),input('password')); if($status==1){ return $this->success('登录成功,正在跳转!','Index/index'); }elseif($status==2){ return $this->error('账号或者密码错误!'); }else{ return $this->error('用户不存在!'); } } return $this->fetch('login'); } public function logout(){ session(null); return $this->success('退出成功!',url('index')); } }6.在model文件夹中—>创建Login.php文件D:\phpStudy\WWW\demo\application\admin\model\Login.php内容:123456789101112131415161718192021<?phpnamespace app\admin\model;use think\Model;class Login extends Model{ public function login($username,$password){ $admin= \think\Db::name('admin')->where('username','=',$username)->find(); if($admin){ if($admin['password']==md5($password)){ \think\Session::set('id',$admin['id']); \think\Session::set('username',$admin['username']); return 1; }else{ return 2; } }else{ return 3; } }}7.在view文件夹中—>创建Login文件夹—>在Login文件夹中—>创建login.html文件D:\phpStudy\WWW\demo\application\admin\view\Login\login.html内容:1234567891011121314151617181920212223242526272829303132<!doctype html><html><head> <meta charset="UTF-8"> <title>后台登录</title> <link href="__PUBLIC__/static/admin/css/admin_login.css" rel="stylesheet" type="text/css" /></head><body><div class="admin_login_wrap"> <h1>后台管理</h1> <div class="adming_login_border"> <div class="admin_input"> <form action="" method="post"> <ul class="admin_items"> <li> <label for="user">用户名:</label> <input type="text" name="username" value="admin" id="user" size="35" class="admin_input_style" /> </li> <li> <label for="pwd">密码:</label> <input type="password" name="password" value="admin" id="pwd" size="35" class="admin_input_style" /> </li> <li> <input type="submit" tabindex="3" value="提交" class="btn btn-primary" /> </li> </ul> </form> </div> </div></div></body></html>8.D:\phpStudy\WWW\demo\application\config.php12// 应用调试模式 'app_debug' => false,修改成:1'app_debug' => true,就能看到Bug了!模板文件不存在:D:\phpStudy\WWW\demo\public/../application/admin\view\login\login.htmlview下的login文件名不对!!!*在controller和model下Login.php要大写Login,在view下login.html要小写login!SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: NO)出现Bug是没有链接数据库的D:\phpStudy\WWW\demo\application\database.php填写内容12345678910111213141516171819202122232425return [ // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => '127.0.0.1', // 数据库名 'database' => 'youme', //你创建或导入的数据库名 // 用户名 'username' => 'root', // 密码 'password' => '****', // 端口 'hostport' => '', // 连接dsn 'dsn' => '', // 数据库连接参数 'params' => [], // 数据库编码默认采用utf8 'charset' => 'utf8', // 数据库表前缀 'prefix' => 'ym_', // 你创建或导入数据库表名的前缀 ***************************************************************************************** SQLSTATE[42S02]: Base table or view not found: 1146 Table 'youhe.admin' doesn't exist(Bug)D:\phpStudy\WWW\demo\application\admin\model\Login.php12345678910111213141516171819202122232425<?phpnamespace app\admin\model;use think\Model;class Login extends Model{ public function login($username,$password){// $admin= \think\Db::name('admin')->where('username','=',$username)->find(); $user= \think\Db::name('user')->where('username','=',$username)->find();// if($admin){ if($user){// if($admin['password']==md5($password)){ if($user['password']==$password){// \think\Session::set('id',$admin['id']); \think\Session::set('id',$user['id']);// \think\Session::set('username',$admin['username']); \think\Session::set('username',$user['username']); return 1; }else{ return 2; } }else{ return 3; } }}推荐教程:《TP5》以上就是thinkphp5实现后台登录界面的方法的详细内容
0
0 1409天前
1065
下面由thinkphp开发教程栏目给大家解析 ThinkPHP 的命名空间,希望对需要的朋友有所帮助!大家都知道由于PHP语法里不支持函数重载机制,如果一个应用里有两个同名的方法,怎么办呢?在Yii 框架为了避免名字重复引起问题,全部的类前边都有 C 字样,而在ThinkPHP里就引入了命名空间这个概念。a) 命名空间是虚拟的定义空间,不是真实存在目录b) 命名空间的分隔符都是反斜杠 \c) 非限定名称:getName() 获得与其最近的命名空间的getName()d) 限定名称:beijinggetName() 相对方式通过最近的命名空间定位beijinggetName():如下面的实例,他会认为在当前目录下的beijinggetName(),因此会找dalianbeijinggetName()。此时,因为找不到就会报错了!!e) 完全限定名称: beijinggetName() 直接在指定的命名空间获得具体元素f) 命名空间针对:函数、类名、常量三者其作用,在命名空间里边把这三种统称为元素操作实例如下:相关推荐:《TP5》以上就是解析 ThinkPHP 的命名空间的详细内容
0
0 1409天前
1125
THINKPHP的cron计划任务的实现,利用THINKPHP自带的cli,加上数据库执行记录(记录任务的报错,成功)。在服务器cron定时任务在网站目录(不是网站根目录)执行php cron.php,网站根目录为Public。写一个cli的入口文件cli.php123456789101112<?phpdefine('MODE_NAME', 'cli');// 检测PHP环境if(version_compare(PHP_VERSION,'5.3.0','<')) die('require PHP > 5.3.0 !'); define('APP_DEBUG', true); // 定义应用目录define('APP_PATH', __DIR__ . '/Application/'); // 引入ThinkPHP入口文件require __DIR__ . '/ThinkPHP/ThinkPHP.php';写一个执行文件cron.php12define('AUTO_CRON', true);include __DIR__ . '/cli.php';数据库设计123456789101112131415161718DROP TABLE IF EXISTS `cron`;CREATE TABLE IF NOT EXISTS `cron` ( `cron_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `expression` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `class` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `method` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `type` varchar(30) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `status` varchar(30) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `run_at` timestamp NULL DEFAULT NULL, `ms` int(10) unsigned NOT NULL DEFAULT '0', `error` text COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`cron_id`), KEY `name` (`name`,`created_at`), KEY `cron_status_index` (`status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;配置文件1234567891011<?phpreturn array( 'version' => '1.0.0', 'beastalkd' => array( 'process_untreated_queue' => array( 'expression' => '* * * * *', 'class' => 'Statistics\Model\PheanstalkModel', 'method' => 'processUntreatedQueue' ) ));执行文件 init.php/写个hook程序执行init.php12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182<?phpuse Think\Log, Think\Db, Cron\Model\Cron;$Model = new \Think\Model();$Has = !$Model->query("SHOW TABLES LIKE 'cron'")?false:true; if(defined("AUTO_CRON") && $Has){ class CronCommand { protected $_initializedJobs; protected $_jobs; protected $_now; public function __construct() { $this->_now = strtotime(date('Y-n-j H:i')); import("Cron.Common.Cron.tdcron_entry",'','.php'); import("Cron.Common.Cron.tdcron",'','.php'); } /** * 这里是放要执行的代码 */ public function fire() { restore_error_handler(); restore_exception_handler(); $this->_initializedJobs = array(); $jobs = M('cron')->where("status = 'initialized'")->select(); /** * @var $cron Cron * 已存在 cron */ if($jobs) { $cron = new Cron(); foreach ($jobs as $data) { $cron->setData($data)->isNew(false); $this->_initializedJobs[$data['name']] = $cron; } } /** * 新 cron */ foreach ($this->getCronJobs() as $name => $cronJob) { if (isset($cronJob['expression'])) { $expression = $cronJob['expression']; } else { Log::write('Cron expression is required for cron job "' . $name . '"',Log::WARN); continue; } if ($this->_now != tdCron::getNextOccurrence($expression, $this->_now)) continue; $cronJob['name'] = $name; $cron = isset($this->_initializedJobs[$name]) ? $this->_initializedJobs[$name] : $this->_initializedJobs[$name] = new Cron(); $cron->initialize($cronJob); } /* @var $cron Cron 处理*/ foreach ($this->_initializedJobs as $cron) { $cron->run(); } } /** * Get All Defined Cron Jobs * 获取配置 * @return array */ public function getCronJobs() { if ($this->_jobs === null) { $this->_jobs = C('beastalkd'); } return $this->_jobs; } } $command = new CronCommand(); $command->fire();}cron 模型12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788<?phpnamespace Cron\Model;use Common\Model;use Think\Log; /** * Class Cron * @method string getClass() * @method string getMethod() * @method string getName() * @method string getType() * @package Cron\Model */class Cron extends Model{ const STATUS_COMPLETED = 'completed'; const STATUS_FAILED = 'failed'; const STATUS_INITIALIZED = 'initialized'; const STATUS_RUNNING = 'running'; protected $name = 'cron'; protected $tableName = 'cron'; protected $pk = 'cron_id'; protected $_originalData = array(); /** * 保存配置信息CLASS */ protected static $_cron_classes = array(); /** * @param $class * @return mixed 获取配置的 CLASS */ public function getSingleton($class) { isset(static::$_cron_classes[$class]) or static::$_cron_classes[$class] = new $class; return static::$_cron_classes[$class]; } /** * @param $cronJob * @return $this * 初始化 任务状态 */ public function initialize($cronJob) { foreach ($cronJob as $k => $v) { $this->setData($k, $v); } $now = date('Y-m-d H:i:s'); $this->setData('status',self::STATUS_INITIALIZED)->setData('created_at',$now)->setData('updated_at',$now)->save(); return $this; } /** * @return $this run 命令 */ public function run() { $this->setData('run_at',date('Y-m-d H:i:s'))->setData('status',self::STATUS_RUNNING)->save(); Timer::start(); try { $class = $this->getData('class'); $method = $this->getData('method'); if (!class_exists($class)) throw new \Exception(sprintf('Class "%s" not found!', $class)); if (!method_exists($class, $method)) throw new \Exception(sprintf('Method "%s::%s()" not found!', $class, $method)); $callback = array($this->getSingleton($class), $method); //new CLASS 使用操作方法 // 执行配置里的 Statistics\Model\PheanstalkModel类 的 processUntreatedQueue 操作 call_user_func($callback); Timer::stop(); $this->setData('ms',round(Timer::diff() * 1000))->setData('status',self::STATUS_COMPLETED)->save(); } catch (\Exception $e) { Timer::stop(); $this->setData('ms',round(Timer::diff() * 1000)) ->setData('status',self::STATUS_FAILED) ->setData('error',$e->getMessage() . "\nParams:\n" . var_export($this->getDbFields(), true))->save(); Log::write($e->getMessage() . "\n" . $e->getTraceAsString(),Log::ERR); } return $this; } }Common\Model 模型12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394<?php namespace Common; use Think\Model as ThinkModel; /** * Class Model * @package Common * * @property \Think\Db\Driver\Mysql $db DB instance */abstract class Model extends ThinkModel { protected $_isNew = true; protected $_jsonFields = array(); protected $_originalData = array(); protected function _after_find(&$result, $options) { foreach ($this->_jsonFields as $field) { is_string($_data = fnGet($result, $field)) and $result[$field] = json_decode($_data, true); } $this->_originalData = $result; $this->_isNew = !$result; parent::_after_find($result, $options); } protected function _after_save($result) { } protected function _before_find() { $this->_originalData = array(); } protected function _facade($data) { foreach ($this->_jsonFields as $field) { is_array($_data = fnGet($data, $field)) and $data[$field] = json_encode($_data); } return parent::_facade($data); } public function find($options = array()) { $this->_before_find(); return parent::find($options); } public function getData($key = null) { return $key === null ? $this->data : $this->__get($key); } public function getOptions() { return $this->options; } public function getOriginalData($key = null) { return $key === null ? $this->_originalData : fnGet($this->_originalData, $key); } /** * Get or set isNew flag * * @param bool $flag * * @return bool */ public function isNew($flag = null) { if ($flag !== null) $this->_isNew = (bool)$flag; return $this->_isNew; } public function save($data = '', $options = array()) { if ($this->_isNew) { $oldData = $this->data; $result = $this->add($data, $options); $this->data = $oldData; if ($result && $this->pk && is_string($this->pk)) { $this->setData($this->pk, $result); } $this->_isNew = false; } else { $oldData = $this->data; $result = parent::save($data, $options); $this->data = $oldData; } $this->_after_save($result); return $result; } public function setData($key, $value = null) { is_array($key) ? $this->data = $key : $this->data[$key] = $value; return $this; }}Timer.class.php1234567891011121314151617181920212223242526<?phpnamespace Cron\Model;class Timer{ protected static $_start = array(0, 0); protected static $_stop = array(0, 0); public static function diff($start = null, $stop = null) { $start and self::start($start); $stop and self::stop($stop); return (self::$_stop[0] - self::$_start[0]) + (self::$_stop[1] - self::$_start[1]); } public static function start($microtime = null) { $microtime or $microtime = microtime(); self::$_start = explode(' ', $microtime); } public static function stop($microtime = null) { $microtime or $microtime = microtime(); self::$_stop = explode(' ', $microtime); }}tdcron.php123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334<?php define('IDX_MINUTE', 0);define('IDX_HOUR', 1);define('IDX_DAY', 2);define('IDX_MONTH', 3);define('IDX_WEEKDAY', 4);define('IDX_YEAR', 5); /* * tdCron v0.0.1 beta - CRON-Parser for PHP * * Copyright (c) 2010 Christian Land / tagdocs.de * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * @author Christian Land <devel@tagdocs.de> * @package tdCron * @copyright Copyright (c) 2010, Christian Land / tagdocs.de * @version v0.0.1 beta */ class tdCron{ /** * Parsed cron-expressions cache. * @var mixed */ static private $pcron = array(); /** * getNextOccurrence() uses a cron-expression to calculate the time and date at which a cronjob * should be executed the next time. If a reference-time is passed, the next time and date * after that time is calculated. * * @access public * @param string $expression cron-expression to use * @param int $timestamp optional reference-time * @return int * @throws Exception */ static public function getNextOccurrence($expression, $timestamp = null) { try { // Convert timestamp to array $next = self::getTimestamp($timestamp); // Calculate date/time $next_time = self::calculateDateTime($expression, $next); } catch (Exception $e) { throw $e; } // return calculated time return $next_time; } /** * getLastOccurrence() does pretty much the same as getNextOccurrence(). The only difference * is, that it doesn't calculate the next but the last time a cronjob should have been executed. * * @access public * @param string $expression cron-expression to use * @param int $timestamp optional reference-time * @return int * @throws Exception */ static public function getLastOccurrence($expression, $timestamp = null) { try { // Convert timestamp to array $last = self::getTimestamp($timestamp); // Calculate date/time $last_time = self::calculateDateTime($expression, $last, false); } catch (Exception $e) { throw $e; } // return calculated time return $last_time; } /** * calculateDateTime() is the function where all the magic happens :-) * * It calculates the time and date at which the next/last call of a cronjob is/was due. * * @access private * @param mixed $expression cron-expression * @param mixed $rtime reference-time * @param bool $next true = nextOccurence, false = lastOccurence * @return int * @throws Exception */ static private function calculateDateTime($expression, $rtime, $next = true) { // Initialize vars $calc_date = true; // Parse cron-expression (if neccessary) $cron = self::getExpression($expression, !$next); // OK, lets see if the day/month/weekday of the reference-date exist in our // $cron-array. if (!in_array($rtime[IDX_DAY], $cron[IDX_DAY]) || !in_array($rtime[IDX_MONTH], $cron[IDX_MONTH]) || !in_array($rtime[IDX_WEEKDAY], $cron[IDX_WEEKDAY])) { // OK, things are easy. The day/month/weekday of the reference time // can't be found in the $cron-array. This means that no matter what // happens, we WILL end up at at a different date than that of our // reference-time. And in this case, the lastOccurrence will ALWAYS // happen at the latest possible time of the day and the nextOccurrence // at the earliest possible time. // // In both cases, the time can be found in the first elements of the // hour/minute cron-arrays. $rtime[IDX_HOUR] = reset($cron[IDX_HOUR]); $rtime[IDX_MINUTE] = reset($cron[IDX_MINUTE]); } else { // OK, things are getting a little bit more complicated... $nhour = self::findValue($rtime[IDX_HOUR], $cron[IDX_HOUR], $next); // Meh. Such a cruel world. Something has gone awry. Lets see HOW awry it went. if ($nhour === false) { // Ah, the hour-part went wrong. Thats easy. Wrong hour means that no // matter what we do we'll end up at a different date. Thus we can use // some simple operations to make things look pretty ;-) // // As alreasy mentioned before -> different date means earliest/latest // time: $rtime[IDX_HOUR] = reset($cron[IDX_HOUR]); $rtime[IDX_MINUTE] = reset($cron[IDX_MINUTE]); // Now all we have to do is add/subtract a day to get a new reference time // to use later to find the right date. The following line probably looks // a little odd but thats the easiest way of adding/substracting a day without // screwing up the date. Just trust me on that one ;-) $rtime = explode(',', strftime('%M,%H,%d,%m,%w,%Y', mktime($rtime[IDX_HOUR], $rtime[IDX_MINUTE], 0, $rtime[IDX_MONTH], $rtime[IDX_DAY], $rtime[IDX_YEAR]) + ((($next) ? 1 : -1) * 86400))); } else { // OK, there is a higher/lower hour available. Check the minutes-part. $nminute = self::findValue($rtime[IDX_MINUTE], $cron[IDX_MINUTE], $next); if ($nminute === false) { // No matching minute-value found... lets see what happens if we substract/add an hour $nhour = self::findValue($rtime[IDX_HOUR] + (($next) ? 1 : -1), $cron[IDX_HOUR], $next); if ($nhour === false) { // No more hours available... add/substract a day... you know what happens ;-) $nminute = reset($cron[IDX_MINUTE]); $nhour = reset($cron[IDX_HOUR]); $rtime = explode(',', strftime('%M,%H,%d,%m,%w,%Y', mktime($nhour, $nminute, 0, $rtime[IDX_MONTH], $rtime[IDX_DAY], $rtime[IDX_YEAR]) + ((($next) ? 1 : -1) * 86400))); } else { // OK, there was another hour. Set the right minutes-value $rtime[IDX_HOUR] = $nhour; $rtime[IDX_MINUTE] = (($next) ? reset($cron[IDX_MINUTE]) : end($cron[IDX_MINUTE])); $calc_date = false; } } else { // OK, there is a matching minute... reset minutes if hour has changed if ($nhour <> $rtime[IDX_HOUR]) { $nminute = reset($cron[IDX_MINUTE]); } // Set time $rtime[IDX_HOUR] = $nhour; $rtime[IDX_MINUTE] = $nminute; $calc_date = false; } } } // If we have to calculate the date... we'll do so if ($calc_date) { if (in_array($rtime[IDX_DAY], $cron[IDX_DAY]) && in_array($rtime[IDX_MONTH], $cron[IDX_MONTH]) && in_array($rtime[IDX_WEEKDAY], $cron[IDX_WEEKDAY])) { return mktime($rtime[1], $rtime[0], 0, $rtime[3], $rtime[2], $rtime[5]); } else { // OK, some searching necessary... $cdate = mktime(0, 0, 0, $rtime[IDX_MONTH], $rtime[IDX_DAY], $rtime[IDX_YEAR]); // OK, these three nested loops are responsible for finding the date... // // The class has 2 limitations/bugs right now: // // -> it doesn't work for dates in 2036 or later! // -> it will most likely fail if you search for a Feburary, 29th with a given weekday // (this does happen because the class only searches in the next/last 10 years! And // while it usually takes less than 10 years for a "normal" date to iterate through // all weekdays, it can take 20+ years for Feb, 29th to iterate through all weekdays! for ($nyear = $rtime[IDX_YEAR]; (($next) ? ($nyear <= $rtime[IDX_YEAR] + 10) : ($nyear >= $rtime[IDX_YEAR] - 10)); $nyear = $nyear + (($next) ? 1 : -1)) { foreach ($cron[IDX_MONTH] as $nmonth) { foreach ($cron[IDX_DAY] as $nday) { if (checkdate($nmonth, $nday, $nyear)) { $ndate = mktime(0, 0, 1, $nmonth, $nday, $nyear); if (($next) ? ($ndate >= $cdate) : ($ndate <= $cdate)) { $dow = date('w', $ndate); // The date is "OK" - lets see if the weekday matches, too... if (in_array($dow, $cron[IDX_WEEKDAY])) { // WIN! :-) We found a valid date... $rtime = explode(',', strftime('%M,%H,%d,%m,%w,%Y', mktime($rtime[IDX_HOUR], $rtime[IDX_MINUTE], 0, $nmonth, $nday, $nyear))); return mktime($rtime[1], $rtime[0], 0, $rtime[3], $rtime[2], $rtime[5]); } } } } } } } throw new Exception('Failed to find date, No matching date found in a 10 years range!', 10004); } return mktime($rtime[1], $rtime[0], 0, $rtime[3], $rtime[2], $rtime[5]); } /** * getTimestamp() converts an unix-timestamp to an array. The returned array contains the following values: * * [0] -> minute * [1] -> hour * [2] -> day * [3] -> month * [4] -> weekday * [5] -> year * * The array is used by various functions. * * @access private * @param int $timestamp If none is given, the current time is used * @return mixed */ static private function getTimestamp($timestamp = null) { if (is_null($timestamp)) { $arr = explode(',', strftime('%M,%H,%d,%m,%w,%Y', time())); } else { $arr = explode(',', strftime('%M,%H,%d,%m,%w,%Y', $timestamp)); } // Remove leading zeros (or we'll get in trouble ;-) foreach ($arr as $key => $value) { $arr[$key] = (int)ltrim($value, '0'); } return $arr; } /** * findValue() checks if the given value exists in an array. If it does not exist, the next * higher/lower value is returned (depending on $next). If no higher/lower value exists, * false is returned. * * @access public * @param int $value * @param mixed $data * @param bool $next * @return mixed */ static private function findValue($value, $data, $next = true) { if (in_array($value, $data)) { return (int)$value; } else { if (($next) ? ($value <= end($data)) : ($value >= end($data))) { foreach ($data as $curval) { if (($next) ? ($value <= (int)$curval) : ($curval <= $value)) { return (int)$curval; } } } } return false; } /** * getExpression() returns a parsed cron-expression. Parsed cron-expressions are cached to reduce * unneccessary calls of the parser. * * @access public * @param string $expression * @param bool $reverse * @return mixed * @throws Exception */ static private function getExpression($expression, $reverse = false) { // First of all we cleanup the expression and remove all duplicate tabs/spaces/etc. // For example "* * * * *" would be converted to "* * * * *", etc. $expression = preg_replace('/(\s+)/', ' ', strtolower(trim($expression))); // Lets see if we've already parsed that expression if (!isset(self::$pcron[$expression])) { // Nope - parse it! try { self::$pcron[$expression] = tdCronEntry::parse($expression); self::$pcron['reverse'][$expression] = self::arrayReverse(self::$pcron[$expression]); } catch (Exception $e) { throw $e; } } return ($reverse ? self::$pcron['reverse'][$expression] : self::$pcron[$expression]); } /** * arrayReverse() reverses all sub-arrays of our cron array. The reversed values are used for calculations * that are run when getLastOccurence() is called. * * @access public * @param mixed $cron * @return mixed */ static private function arrayReverse($cron) { foreach ($cron as $key => $value) { $cron[$key] = array_reverse($value); } return $cron; }}tdcron_entry.php123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258<?php /** * tinyCronEntry is part of tdCron. Its a class to parse Cron-Expressions like "1-45 1,2,3 1-30/5 January,February Mon,Tue" * and convert it to an easily useable format. * * The parser is quite powerful and understands pretty much everything you will ever find in a Cron-Expression. * * A Cron-Expression consists of 5 segments: * * <pre> * .---------------- minute (0 - 59) * | .------------- hour (0 - 23) * | | .---------- day of month (1 - 31) * | | | .------- month (1 - 12) * | | | | .----- day of week (0 - 6) * | | | | | * * * * * * * </pre> * * Each segment can contain values, ranges and intervals. A range is always written as "value1-value2" and * intervals as "value1/value2". * * Of course each segment can contain multiple values seperated by commas. * * Some valid examples: * * <pre> * 1,2,3,4,5 * 1-5 * 10-20/* * Jan,Feb,Oct * Monday-Friday * 1-10,15,20,40-50/2 * </pre> * * The current version of the parser understands all weekdays and month names in german and english! * * Usually you won't need to call this class directly. * * Copyright (c) 2010 Christian Land / tagdocs.de * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * @author Christian Land <devel@tagdocs.de> * @package tinyCron * @subpackage tinyCronEntry * @copyright Copyright (c) 2010, Christian Land / tagdocs.de * @version v0.0.1 beta */class tdCronEntry{ /** * The parsed cron-expression. * @var mixed */ static private $cron = array(); /** * Ranges. * @var mixed */ static private $ranges = array( IDX_MINUTE => array('min' => 0, 'max' => 59), // Minutes IDX_HOUR => array('min' => 0, 'max' => 23), // Hours IDX_DAY => array('min' => 1, 'max' => 31), // Days IDX_MONTH => array('min' => 1, 'max' => 12), // Months IDX_WEEKDAY => array('min' => 0, 'max' => 7) // Weekdays ); /** * Named intervals. * @var mixed */ static private $intervals = array( '@yearly' => '0 0 1 1 *', '@annually' => '0 0 1 1 *', '@monthly' => '0 0 1 * *', '@weekly' => '0 0 * * 0', '@midnight' => '0 0 * * *', '@daily' => '0 0 * * *', '@hourly' => '0 * * * *' ); /** * Possible keywords for months/weekdays. * @var mixed */ static private $keywords = array( IDX_MONTH => array( '/(january|januar|jan)/i' => 1, '/(february|februar|feb)/i' => 2, '/(march|maerz|m?rz|mar|mae|m?r)/i' => 3, '/(april|apr)/i' => 4, '/(may|mai)/i' => 5, '/(june|juni|jun)/i' => 6, '/(july|juli|jul)/i' => 7, '/(august|aug)/i' => 8, '/(september|sep)/i' => 9, '/(october|oktober|okt|oct)/i' => 10, '/(november|nov)/i' => 11, '/(december|dezember|dec|dez)/i' => 12 ), IDX_WEEKDAY => array( '/(sunday|sonntag|sun|son|su|so)/i' => 0, '/(monday|montag|mon|mo)/i' => 1, '/(tuesday|dienstag|die|tue|tu|di)/i' => 2, '/(wednesdays|mittwoch|mit|wed|we|mi)/i' => 3, '/(thursday|donnerstag|don|thu|th|do)/i' => 4, '/(friday|freitag|fre|fri|fr)/i' => 5, '/(saturday|samstag|sam|sat|sa)/i' => 6 ) ); /** * parseExpression() analyses crontab-expressions like "* * 1,2,3 * mon,tue" and returns an array * containing all values. If it can't be parsed, an exception is thrown. * * @access public * @param string $expression The cron-expression to parse. * @return mixed * @throws Exception */ static public function parse($expression) { $dummy = array(); // Convert named expressions if neccessary if (substr($expression, 0, 1) == '@') { $expression = strtr($expression, self::$intervals); if (substr($expression, 0, 1) == '@') { // Oops... unknown named interval!?!! throw new Exception('Unknown named interval [' . $expression . ']', 10000); } } // Next basic check... do we have 5 segments? $cron = explode(' ', $expression); if (count($cron) <> 5) { // No... we haven't... throw new Exception('Wrong number of segments in expression. Expected: 5, Found: ' . count($cron), 10001); } else { // Yup, 5 segments... lets see if we can work with them foreach ($cron as $idx => $segment) { try { $dummy[$idx] = self::expandSegment($idx, $segment); } catch (Exception $e) { throw $e; } } } return $dummy; } /** * expandSegment() analyses a single segment * * @access public * @param $idx * @param $segment * @return array * @throws Exception */ static private function expandSegment($idx, $segment) { // Store original segment for later use $osegment = $segment; // Replace months/weekdays like "January", "February", etc. with numbers if (isset(self::$keywords[$idx])) { $segment = preg_replace(array_keys(self::$keywords[$idx]), array_values(self::$keywords[$idx]), $segment); } // Replace wildcards if (substr($segment, 0, 1) == '*') { $segment = preg_replace('/^\*(\/\d+)?$/i', self::$ranges[$idx]['min'] . '-' . self::$ranges[$idx]['max'] . '$1', $segment); } // Make sure that nothing unparsed is left :) $dummy = preg_replace('/[0-9\-\/\,]/', '', $segment); if (!empty($dummy)) { // Ohoh.... thats not good :-) throw new Exception('Failed to parse segment: ' . $osegment, 10002); } // At this point our string should be OK - lets convert it to an array $result = array(); $atoms = explode(',', $segment); foreach ($atoms as $curatom) { $result = array_merge($result, self::parseAtom($curatom)); } // Get rid of duplicates and sort the array $result = array_unique($result); sort($result); // Check for invalid values if ($idx == IDX_WEEKDAY) { if (end($result) == 7) { if (reset($result) <> 0) { array_unshift($result, 0); } array_pop($result); } } foreach ($result as $key => $value) { if (($value < self::$ranges[$idx]['min']) || ($value > self::$ranges[$idx]['max'])) { throw new Exception('Failed to parse segment, invalid value [' . $value . ']: ' . $osegment, 10003); } } return $result; } /** * parseAtom() analyses a single segment * * @access public * @param string $atom The segment to parse * @return array */ static private function parseAtom($atom) { $expanded = array(); if (preg_match('/^(\d+)-(\d+)(\/(\d+))?/i', $atom, $matches)) { $low = $matches[1]; $high = $matches[2]; if ($low > $high) { list($low, $high) = array($high, $low); } $step = isset($matches[4]) ? $matches[4] : 1; for ($i = $low; $i <= $high; $i += $step) { $expanded[] = (int)$i; } } else { $expanded[] = (int)$atom; } $expanded2 = array_unique($expanded); return $expanded; }}推荐教程:《TP5》以上就是THINKPHP的cron任务实现的详细内容
0
0 1409天前
1315
ThinkPHP提供了自带的错误提示页面,但是并不美观,提示信息显示如下:我们如果想要更换提示页面应该怎么做呢?以ThinkPHP3.2为例:在应用配置文件(应用文件目录/Common/Conf/config.php)中添加:1234/* 错误页面模板 */'TMPL_ACTION_ERROR' => 'Public/dispatch_jump.html', // 默认错误跳转对应的模板文件''TMPL_ACTION_SUCCESS' => 'Public/dispatch_jump.html', // 默认成功跳转对应的模板文件'//'TMPL_EXCEPTION_FILE' => 'Public/exception.html',// 异常页面的模板文件然后我是在项目公共文件(项目目录/Public)中新建了dispatch_jump.html,模板内容如下:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970<!DOCTYPE html><html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>跳转提示</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style type="text/css"> *{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased} body{padding:70px 0;background:#edf1f4;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333} a{outline:0;color:#3498db;text-decoration:none;cursor:pointer} .system-message{margin:20px 5%;padding:40px 20px;background:#fff;box-shadow:1px 1px 1px hsla(0,0%,39%,.1);text-align:center} .system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:40px} .system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400} .system-message .jump{font-size:14px} .system-message .jump a{color:#333} .system-message p{font-size:9pt;line-height:20px} .system-message .btn{display:inline-block;margin-right:10px;width:138px;height:2pc;border:1px solid #44a0e8;border-radius:30px;color:#44a0e8;text-align:center;font-size:1pc;line-height:2pc;margin-bottom:5px;} .success .btn{border-color:#69bf4e;color:#69bf4e} .error .btn{border-color:#ff8992;color:#ff8992} .info .btn{border-color:#3498db;color:#3498db} .copyright p{width:100%;color:#919191;text-align:center;font-size:10px} .system-message .btn-grey{border-color:#bbb;color:#bbb} .clearfix:after{clear:both;display:block;visibility:hidden;height:0;content:"."} @media (max-width:768px){body {padding:20px 0;}} @media (max-width:480px){.system-message h1{font-size:30px;}} </style> </head> <body> <div class="system-message error"> <?php if(isset($message)){ ?> <div class="image"> <img src="http://cdn.demo.fastadmin.net/assets/img/success.svg" alt="" width="150" /> </div> <h1> <?php echo $message; }else{ ?> <div class="image"> <img src="http://cdn.demo.fastadmin.net/assets/img/error.svg" alt="" width="150" /> </div> <h1> <?php echo $error; }?></h1> <p class="jump"> 页面将在 <span id="wait"><?php echo($waitSecond); ?></span><!-- <span id="wait">3</span> -->秒后自动<a id="href" href="<?php echo($jumpUrl); ?>">跳转</a> </p> <p class="clearfix"> <a href="javascript:history.go(-1);" class="btn btn-grey">返回上一步</a> <a href="<?php echo($jumpUrl); ?>" class="btn btn-primary">立即跳转</a> </p> </div> <script type="text/javascript"> (function () { var wait = document.getElementById('wait'), href = document.getElementById('href').href; var interval = setInterval(function () { var time = --wait.innerHTML; if (time <= 0) { location.href = href; clearInterval(interval); } }, 1000); })(); </script> </body></html>效果如下:推荐教程:《TP5》以上就是ThinkPHP中自定义错误、成功、异常提示页面的方法的详细内容
0
0 1409天前
1040
ThinkPHP支持两种构造方法: __construct和_initialize(ThinkPHP内置的构造方法)。修改用户控制器类文件UserController.class.php 如下:1、__construct构造方法修改中间控制器类CommonController.class.php 如下:说明:empty() 5.5 版本之后支持表达式,否则会报如下错误:运行结果如下:中间控制器必须先构造父类,才能使用父类的方法,修改代码如下:运行结果:2、_initialize构造方法,如下:通过_initialize构造方法同样可以实现上述效果,无需构造父类,查看基类控制器代码如下:通过Controller.class.php中的架构函数可以看出,只要存在 _initialize方法,就会直接调用来初始化控制器,因此ThinkPHP内置的构造方法无需再构造父类。推荐教程:《TP5》以上就是thinkphp登录限制时__construct和_initialize的区别介绍的详细内容
0
0 1409天前
1389
需求多加一个类似phpmyadmin一样的每页显示条数 查了好久都没找到看到thinkphp 分页类 是html拼接的 很low 但是方便了我修改 新增需求在原生分页类基础上 新定义了一个num变量show方法返回的时候 thinkphp拼接html的地方 新加了一段选择条数的代码123456789return "<ul class='am-pagination am-pagination-right'>{$page_str}</ul> <div class='am-dropdown am-dropdown-up' data-am-dropdown> <button class='am-btn am-btn-primary am-dropdown-toggle' data-am-dropdown-toggle>显示条数 <span class='am-icon-caret-up'></span></button> <ul class='am-dropdown-content'> <li><a href='".$this->urlNum(10,1)."'>10</a></li> <li><a href='".$this->urlNum(30,1)."'>30</a></li> <li><a href='".$this->urlNum(50,1)."'>50</a></li> </ul> </div>";然后新加的urlNum方法是这样:1234private function urlNum($num,$page){ $str = str_replace(urlencode('[PAGE]'), $page, $this->url); return str_replace(urlencode('[NUM]'), $num, $str);}开始的时候由于page这个变量 thinkphp会先变一个转码的 后面才替换而且page=1的时候 url里是不显示的 但是还有这个参数导致num这个变量老是搞得url 很不稳定 经常叠加后面只有做了一个小牺牲(选定每页显示条数的时候 url page即使为1 也会加上)不过这并没有什么影响整个代码分页类 就是这样:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163<?php// +----------------------------------------------------------------------// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]// +----------------------------------------------------------------------// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.// +----------------------------------------------------------------------// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )// +----------------------------------------------------------------------// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>// +----------------------------------------------------------------------namespace Think; class Page{ public $firstRow; // 起始行数 public $listRows; // 列表每页显示行数 public $parameter; // 分页跳转时要带的参数 public $totalRows; // 总行数 public $totalPages; // 分页总页面数 public $rollPage = 11;// 分页栏每页显示的页数 public $lastSuffix = true; // 最后一页是否显示总页数 private $p = 'p'; //分页参数名 private $num = 'num'; //分页参数名 private $url = ''; //当前链接URL private $nowPage = 1; // 分页显示定制 private $config = array( 'header' => '<span class="rows">共 %TOTAL_ROW% 条记录</span>', 'prev' => '«', 'next' => '»', 'first' => '1...', 'last' => '...%TOTAL_PAGE%', 'theme' => '%HEADER% %FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%', ); /** * 架构函数 * @param array $totalRows 总的记录数 * @param array $listRows 每页显示记录数 * @param array $parameter 分页跳转的参数 */ public function __construct($totalRows, $listRows=20, $parameter = array()) { C('VAR_PAGE') && $this->p = C('VAR_PAGE'); //设置分页参数名称 /* 基础设置 */ $this->totalRows = $totalRows; //设置总记录数 $this->listRows = $listRows; //设置每页显示行数 $this->parameter = empty($parameter) ? $_GET : $parameter; $this->nowPage = empty($_GET[$this->p]) ? 1 : intval($_GET[$this->p]); $this->nowPage = $this->nowPage>0 ? $this->nowPage : 1; $this->firstRow = $this->listRows * ($this->nowPage - 1); } /** * 定制分页链接设置 * @param string $name 设置名称 * @param string $value 设置值 */ public function setConfig($name,$value) { if(isset($this->config[$name])) { $this->config[$name] = $value; } } /** * 生成链接URL * @param integer $page 页码 * @return string */ private function url($page){ // return str_replace(urlencode('[PAGE]'), $page, $this->url); $num = $_GET['num'] ? $_GET['num'] : '10'; $str = str_replace(urlencode('[NUM]'), $num, $this->url); return str_replace(urlencode('[PAGE]'), $page, $str); } private function urlNum($num,$page){ $str = str_replace(urlencode('[PAGE]'), $page, $this->url); return str_replace(urlencode('[NUM]'), $num, $str); } /** * 组装分页链接 * @return string */ public function show() { if(0 == $this->totalRows) return ''; /* 生成URL */ // echo $this->num;die; $this->parameter[$this->p] = '[PAGE]'; // $num = empty($_GET['num']) ? '20' : ''; $this->parameter[$this->num] = '[NUM]'; $this->url = U(ACTION_NAME, $this->parameter); /* 计算分页信息 */ $this->totalPages = ceil($this->totalRows / $this->listRows); //总页数 if(!empty($this->totalPages) && $this->nowPage > $this->totalPages) { $this->nowPage = $this->totalPages; } /* 计算分页临时变量 */ $now_cool_page = $this->rollPage/2; $now_cool_page_ceil = ceil($now_cool_page); $this->lastSuffix && $this->config['last'] = $this->totalPages; //上一页 $up_row = $this->nowPage - 1; $up_page = $up_row > 0 ? '<li><a class="prev" href="' . $this->url($up_row) . '">' . $this->config['prev'] . '</a></li>' : ''; //下一页 $down_row = $this->nowPage + 1; $down_page = ($down_row <= $this->totalPages) ? '<li><a class="next" href="' . $this->url($down_row) . '">' . $this->config['next'] . '</a></li>' : ''; //第一页 $the_first = ''; if($this->totalPages > $this->rollPage && ($this->nowPage - $now_cool_page) >= 1){ $the_first = '<li><a class="first" href="' . $this->url(1) . '">' . $this->config['first'] . '</a></li>'; } //最后一页 $the_end = ''; if($this->totalPages > $this->rollPage && ($this->nowPage + $now_cool_page) < $this->totalPages){ $the_end = '<li><a class="end" href="' . $this->url($this->totalPages) . '">' . $this->config['last'] . '</a></li>'; } //数字连接 $link_page = ""; for($i = 1; $i <= $this->rollPage; $i++){ if(($this->nowPage - $now_cool_page) <= 0 ){ $page = $i; }elseif(($this->nowPage + $now_cool_page - 1) >= $this->totalPages){ $page = $this->totalPages - $this->rollPage + $i; }else{ $page = $this->nowPage - $now_cool_page_ceil + $i; } if($page > 0 && $page != $this->nowPage){ if($page <= $this->totalPages){ $link_page .= '<li><a class="num" href="' . $this->url($page) . '">' . $page . '</a></li>'; }else{ break; } }else{ if($page > 0 && $this->totalPages != 1){ $link_page .= '<li class="am-active"><a href="#">' . $page . '</a></li>'; } } } //替换分页内容 $page_str = str_replace( array('%HEADER%', '%NOW_PAGE%', '%UP_PAGE%', '%DOWN_PAGE%', '%FIRST%', '%LINK_PAGE%', '%END%', '%TOTAL_ROW%', '%TOTAL_PAGE%'), array($this->config['header'], $this->nowPage, $up_page, $down_page, $the_first, $link_page, $the_end, $this->totalRows, $this->totalPages), $this->config['theme']); return "<ul class='am-pagination am-pagination-right'>{$page_str}</ul> <div class='am-dropdown am-dropdown-up' data-am-dropdown> <button class='am-btn am-btn-primary am-dropdown-toggle' data-am-dropdown-toggle>显示条数 <span class='am-icon-caret-up'></span></button> <ul class='am-dropdown-content'> <li><a href='".$this->urlNum(10,1)."'>10</a></li> <li><a href='".$this->urlNum(30,1)."'>30</a></li> <li><a href='".$this->urlNum(50,1)."'>50</a></li> </ul> </div>"; }}效果如下:推荐教程:《TP5》以上就是thinkphp增加每页显示条数的方法的详细内容
0
0 1409天前
1027
大家都知道在thinkphp里面,我们是通过在控制器里面给模板分配变量,然后在模板里面通过标签的方式来获取变量,假设有一个变量为$name,那么我们在模板里面就应该是通过。{$name}的方式来获取变量值,在这里问题就出来了,假设我们的这个模板里面还有其他的JS,CSS,比如我在模板里面还有这样一段JS代码如下:123456789101112131415<script type="text/javascript"> Var str=6; If(str>=6){ Alert('test'); }else{ Alert(''); } </script>如果模板里面有上述一段这样一段JS代码的话,那thinkphp解析模板的时候就会报错,因为在这段JS里面也出现了{}定界符,thinkphp就会认为{}里面的也是一个模板标签,然后去解析它,但它其实只是一段JS代码,所以就报错了。当我们碰到这种情况应该怎么处理呢?下面我们就来看一下thinkphp中修改定界符的方法:在thinkphp里面很多修改系统默认东西的操作都是通过配置文件来实现的,修改标签定界符也是通过在配置文件里面来指定的,我们来看一下具体应该怎么做,在config.php里面增加如下代码:1234567891011<?php return array( 'TMPL_L_DELIM'=>'<{', 'TMPL_R_DELIM'=>'}>', ); ?>通过上述代码我们也可以看出,标签定界符已经改成了<{}>,也就是说如果我们现在在控制器里面分配一个变量$this->assign(‘name’,$name),这个时候我们在模板里面就应该这样写了<{$name}>,这样就不会和JS或者CSS冲突了。推荐教程:《TP5》以上就是thinkphp中修改模板标签定界符的方法的详细内容
0
0 1409天前
1143
使用的是ThinkPHP自带的Authority权限类!ThinkPHP版本是3.1.3的我要实现的是根据模块名分配权限,当然,这个可以扩展到操作名。假如我有这些模块文件:那么 think_auth_rule表的内容差不多应该是这样的:比如,我的登录用户的uid=7.think_auth_group_access 表中有 uid=9 ,group=6;think_auth_group 表中有 id=6,title="宇宙管理员",rules="4,5,8";那么,我只要再模块文件CommAction.class.php中,添加:1234567891011121314151617class CommAction extends Action{ public function __construct(){ parent::__construct(); $this->assign('waitSecond',2); $this->checkRight(); } private function checkRight(){ import('ORG.Util.Authority'); $auth=new Authority(); $r = $auth->getAuth(MODULE_NAME,session('S_USER_ID')); if(!$r){ $this->error('没有权限!'); } }}然后,再让其它的模块文件继承这个文件,比如,ActivityAction.class.php:12345<?phpclass activityAction extends CommAction{//操作方法}?>就这样,当我访问think_auth_rules中id是4,5,8模块的时候,就可以正常访问;如果访问id是10,11,12,13的模块,就会跳转到失败,提示没有权限的页面了~现在我用这个权限类遇到的问题是:think_auth_rule表中的内容需要我手动去添加,这块是属性开发的,如果能自动生成就好了。推荐教程:《TP5》以上就是thinkphp中的模块权限分配的详细内容
0
0 1409天前
1100
AUTH权限管理的原理最简单的auth权限管理的4张数据表如下图每一个功能对应的一个url路径,规则表其实就是记录url路径,通过url来实现权限管理权限验证时机分类前置验证所谓前置认证,就是当前可访问的页面内部元素在显示前就进行权限验证。例如:游客访问网页时,看不到某个功能菜单,但管理员能看到等。前置验证用户体验好,但性能差点后置认证所谓后置认证,这个就简单,就是每个功能访问时先进行权限验证。例如,在页面上点击‘添加栏目’按钮,先进行验证,通过才执行添加栏目功能代码。后置验证用户体验差,但性能好权限验证代码实现位置在用户成功登陆后台后,后台所有菜单、导航、按钮的操作就必须进行权限验证但后台首页、欢迎页、用户退出等功能可无需权限验证,根据具体项目需求来订AUTH权限管理与RBAC权限管理的区别相同点:都是基于角色的权限管理不同点:数据表的设计不同,导致AUTH更灵活、权限管理更细腻权限模块设计推荐教程:《TP5》以上就是THINKPHP中的AUTH权限管理介绍的详细内容
0
0 1409天前
1095
PHP-Casbin 是一个强大的、高效的开源访问控制框架,它支持基于各种访问控制模型的权限管理。Think-Casbin 是一个专为ThinkPHP5.1定制的Casbin的扩展包,使开发者更便捷的在thinkphp项目中使用Casbin。安装创建thinkphp项目(如果没有):1composer create-project topthink/think=5.1.* tp5在ThinkPHP项目里,安装Think-Casbin扩展:1composer require casbin/think-adapter发布资源:1php think casbin:publish这将自动创建model配置文件config/casbin-basic-model.conf,和Casbin的配置文件config/casbin.php。数据迁移:由于Think-Casbin默认将Casbin的策略(Policy)存储在数据库中,所以需要初始化数据库表信息。执行前,请确保数据库连接信息配置正确,如需单独修改Casbin的数据库连接信息或表名,可以修改config/casbin.php里的配置。1php think casbin:migrate这将会自动创建Casbin的策略(Policy)表casbin_rule。中间件ThinkPHP 从 5.1.6+ 版本开始,正式引入中间件的支持。可以通过命令行指令快速生成中间件1php think make:middleware Authorization这个指令会 application/http/middleware 目录下面生成一个 Authorization 中间件。在中间件中,获取当前用户名、URI、请求方法,通过 Casbin 验证权限:1234567891011121314151617181920212223242526272829<?php namespace app\http\middleware; use Casbin;use think\facade\Session; class Authorization{ public function handle($request, \Closure $next) { // 当前登录用户名,这里以session为例 // $user = Session::get('user_name') ?: 'test_user'; $user = Session::get('user_name'); $url = $request->url(); $action = $request->method(); if (!$user){ return response()->data('Unauthenticated.')->code(401); } if (!Casbin::enforce($user, $url, $action)) { return response()->data('Unauthorized.')->code(403); } return $next($request); }}Casbin Model配置config\casbin-basic-model.conf 配置文件:1234567891011[request_definition]r = sub, obj, act [policy_definition]p = sub, obj, act [policy_effect]e = some(where (p.eft == allow)) [matchers]m = r.sub == p.sub && keyMatch2(r.obj, p.obj) && r.act == p.act验证在执行授权之前,先在数据库 casbin_rule 表中添加一些默认的策略:添加路由及其中间件:1234567891011Route::group('users', function () { Route::get('', function () { return 'Users data.'; }); Route::get('/:id', function ($id) { return 'User: '.$id; }); })->middleware(\app\http\middleware\Authorization::class);先登录用户保存用户名到 SESSION ,可以访问 /users、/users/1 验证一下权限。推荐教程:《TP5》以上就是thinkphp中使用Casbin作为权限控制中间件的详细内容
0
0 1409天前
1126
thinkPHP的数据库迁移工具:topthink/think-migration一:安装topthink/think-migration这里注意你安装topthink/think-migration时需要注意你的thinkPHP版本,这里我的thinkPHP版本为5.1,所以可以安装topthink/think-migration的2.0版本,无法安装3.0版本,选择你适合的版本进行安装1composer require topthink/think-migration=2.0.*安装完成之后在命令行执行:1php think如下表示migrate安装成功二:使用topthink/think-migration实现数据库迁移1:创建迁移类在命令行执行1php think migrate:create CreateUser执行完成之后我们就和在./database/migrateions目录下创建一个migrate迁移文件2:实现数据库迁移[1]:migrate代码说明:在migrate中有三个方法up:在migrate:run时执行(前提是文件中不存在change方法)down:在migrate:rollback时执行(前提是文件中不存在change方法)change:migrate:run 和migrate:rollback时执行 (如果存在该方法 则不会去执行up 与down)一般情况下我一般将migrate文件中的change方法删除,up方法专门放置新增和更新表的操作,down方法放置删除表和删除字段操作(1)新增表:12345678// create the table$table = $this->table('user', ['id' => 'user_id', 'comment' => '用户表', 'engine' => 'MyISAM', '']);$table->addColumn('user_name', 'string', ['limit' => 15, 'default' => '', 'comment' => '用户名']) ->addColumn('password', 'string', ['limit' => 15, 'default' => '', 'comment' => '密码',]) ->addColumn('status', 'boolean', ['limit' => 1, 'default' => 0, 'comment' => '状态']) ->addIndex(['user_name'], ['unique' => true])//为user_name创建索引并设置唯一(唯一索引) ->addTimestamps()//默认生成create_time和update_time两个字段 ->create();(2)更新表:123$this->table('user') ->addColumn('test', 'string', ['limit' => 15, 'default' => '', 'comment' => '测试'])//在user表中增加一个test字段 ->update();(3)删除表:1$this->table('user')->drop();(4)删除字段123$this->table('user') ->removeColumn('test')//删除user表中的test字段 ->save();[2]:migrate命令:migrate常用的命令有三个,分别为:123php think migrate:create CreateUser #创建一个迁移类php think migrate:run #执行迁移php think migrate:rollback #迁移回滚推荐教程:《TP5》以上就是thinkPHP使用migrate迁移数据库的详细内容
0
0 1409天前
1158
模型定义一.定义模型1. 定义一个与数据库相匹配的模型12class User extends Model{}2. 模型会自动对应数据表,模型类的命名规则是除去表前缀(例如:tp_)的数据表名称,采用驼峰法命名,并且首字母大写,例如:tp_user(表名) => User(模型名)tp_user_type(表名) => UserType(模型名)3. 如果担心模型的名称和PHP关键字冲突,可以启用类后缀功能,只需要在应用配置文件app.php中设置:12// 开启应用类库后缀'class_suffix' => true,4. 设置完毕后,所有的控制器名与类名都要加上Controller与Model,例如:Class UserModelClass UserController二.模型设置1. 默认主键是id,如果想设置其他主键,类似于uid:1protected $pk = 'uid';2. 在控制器调用模型的时候,如果控制器类名与模型名重复,可以设置别名:use app\test\model\User as UserModel;3. 在模型定义中也可以在模型中设置其他表名:1protected $table = 'tp_other';4. 模型同控制器一样也支持初始化,这里必须设置static静态方法,具体如下:1234protected static function init(){ //初始化内容 }三.模型操作1.模型操作与数据库操作一致,但是模型操作不需要指定表名,例如:数据库操作:1Db::name('user')->all ();模型操作:1User:all();2. 模型操作与数据库操作返回的结果类型不同,数据库操作返回的结果是一个(二维)数组[ [ ] ],而模型操作返回的结果是一个结果集[ { } ]。推荐教程:《TP5》以上就是thinkphp模型定义的详细内容
0
0 1409天前
1198
thinkphp模块改名,如何做。例如,We模块改为You模块步骤如下:We模块:(大小写敏感)1.修改Controller和model的 namespace为You2.替换所有的We\链接为 You\3.替换所有的We/链接为 You/4.替换所有的We@为You@5.替换所有we/ 为 You/6.替换所有we\为You\推荐教程:《TP5》以上就是thinkphp模块改名的方法的详细内容
0
0 1409天前
1081
Thinkphp5.1使用Smarty模板引擎习惯了使用smarty的小伙伴,如果不想修改已有的模板代码,可以直接使用composer安装Smarty库,修改模板配置文件就可以直接使用smarty模板了think-smartyThinkPHP5.1Smarty 引擎驱动安装方法使用composer安装模版引擎方法: composer require emmetltd/think-smartyThinkPHP5.1 配置template.php文件中参数1234567891011121314151617181920212223return [// 模板引擎类型 支持 php think 支持扩展'type' => 'Smarty',// 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法'auto_rule' => 1,// 模板路径'view_path' => '',// 模板后缀'view_suffix' => 'html',// 模板文件名分隔符'view_depr' => '_', //DIRECTORY_SEPARATOR,// 模板引擎普通标签开始标记'tpl_begin' => '<{',// 模板引擎普通标签结束标记'tpl_end' => '}>',// 标签库标签开始标记'taglib_begin' => '{',// 标签库标签结束标记'taglib_end' => '}','view_replace_str' => [ //字符替换部分'/Upfiles/'=>'http://www.emmetltd.com/Uploads/',],];那么在控制器 index/index::index 中 return view();时会加载模板 index/view/index_index.html推荐教程:《TP5》以上就是thinkphp5.1使用Smarty模板引擎的详细内容
0
0 1409天前
1030
在config.php中添加'allow_module_ip' => ['admin' => '*'], // 设置某些ip可以访问指定模块['admin' => '*'] 所有ip都可以访问admin模块,['admin' => ['127.0.0.1','192.168.1.100']] 仅这两个ip可以访问admin模块最好加在这个位置123456// 禁止访问模块'deny_module_list' => ['common'],// 设置某些ip可以访问指定模块'allow_module_ip' => ['admin' => '*'],// 默认控制器名'default_controller' => 'Index',需要修改框架代码thinkphp/library/think/App.php代码位置如下123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051public static function module($result, $config, $convert = null) { if (is_string($result)) { $result = explode('/', $result); } $request = Request::instance(); if ($config['app_multi_module']) { // 多模块部署 $module = strip_tags(strtolower($result[0] ?: $config['default_module'])); $bind = Route::getBind('module'); $available = false; if ($bind) { // 绑定模块 list($bindModule) = explode('/', $bind); if (empty($result[0])) { $module = $bindModule; $available = true; } elseif ($module == $bindModule) { $available = true; } } elseif (!in_array($module, $config['deny_module_list']) && is_dir(APP_PATH . $module)) { $available = true; } //region 设置了限制ip访问模块, 如:'allow_module_ip' => ['admin'=>['127.0.0.1']] if (isset($config['allow_module_ip']) && isset($config['allow_module_ip'][$module])) { $allowIps = $config['allow_module_ip'][$module]; if (!in_array($_SERVER['REMOTE_ADDR'], $allowIps) && $allowIps != '*') { $available = false; } } //end region // 模块初始化 if ($module && $available) { // 初始化模块 $request->module($module); $config = self::init($module); // 模块请求缓存检查 $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']); } else { throw new HttpException(404, 'module not exists:' . $module); } } else { // 单一模块部署 $module = ''; $request->module($module); } // ......}推荐教程:《TP5》以上就是thinkphp5配置指定ip访问模块的详细内容
0
0 1409天前
1096
ThinkPHP执行调用存储过程怎么添加日志1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253//PHP代码部分/** * [LogAdd 操作日志] * @param [string] $userid [用户的ID] * @param [string] $type [类型] * @param [string] $controller_name [当前控制器的中文名称] * @param [string] $function_name [当前方法的中文名称] */function LogAdd($userid,$type,$controller_name,$function_name){ //组合数据 $data['userid'] = $userid;//当前操作的用户 $data['type'] = $type;//当前操作的类型 $data['url'] = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];//当前操作的URL地址 $data['controller'] = CONTROLLER_NAME;//当前控制器的名称 $data['controller_name'] = $controller_name;//当前控制器的中文名称 $data['function'] = ACTION_NAME;//当前方法的名称 $data['function_name'] = $function_name;//当前方法的中文名称 $data['ip'] = getClientIP();//IP地址 $data['create_time'] = date('Y-m-d H:i:s',time());//登录时间 //表名 $data_fun = 't_sys_logs_'.date('Y',time()); //执行原生SQL $Model = M(); $results = $Model->query('show tables');//打开库 //组装为一维数组进行判断 foreach($results as $k=>$v){ $data_table_show[] = $v['tables_in_dbwxapplite']; } //先判断是否存在表 if(in_array(strtolower($data_fun), $data_table_show)){ //存在表直接添加日志 $loginLog = M($data_fun)->add($data); if($loginLog != false){ $res = ['status' => '1','result' => '写入成功','data' => $loginLog]; }else{ $res = ['status' => '0','result' => '写入失败','data' => $loginLog]; } }else{ //不存在表,先调用存储过程,在执行添加日志 $code = $Model->query("call spCreateTableSysLogs(".date('Y',time()).")"); if($code){ //存储过程成功则添加数据 $loginLog = M($data_fun)->add($data); if($loginLog != false){ $res = ['status' => '1','result' => '写入成功','data' => $loginLog]; }else{ $res = ['status' => '0','result' => '写入失败','data' => $loginLog]; } }else{ //失败 $res = ['status' => '0','result' => '存储过程调用失败','data' => $loginLog]; } } return $res;}12345678910111213//mysql脚本数据库部分-- ------------------------------ Table structure for t_sys_logs_2017-- ----------------------------DROP TABLE IF EXISTS `t_sys_logs_2017`;CREATE TABLE `t_sys_logs_2017` ( `logid` int(11) NOT NULL AUTO_INCREMENT COMMENT '日志ID', `userid` varchar(32) NOT NULL DEFAULT '0' COMMENT '创建人ID', `type` varchar(8) NOT NULL COMMENT '日志操作类型,如:登录;注销;退出;修改密码;创建报名', `url` varchar(100) NOT NULL DEFAULT 'www' COMMENT '当前操作的URL', `controller` varchar(30) NOT NULL DEFAULT '控制器的名称' COMMENT '当前控制器的名称', `controller_name` varchar(30) NOT NULL DEFAULT '控制器的中文名称' COMMENT '当前控制器的中文名称', `function` varchar(30) NOT NULL DEFAULT '方法的名称' COMMENT '当前方法的名称', `function_name` varchar(30) NOT NULL DEFAULT '方法的中文名称' COMMENT '当前方法的中文名称', `ip` varchar(30) NOT NULL DEFAULT '255.255.255.255' COMMENT '当前操作客户端IP', `create_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间', `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`logid`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表';以上就是ThinkPHP执行调用存储过程怎么添加日志的详细内容
0
0 1409天前