百搜论坛欢迎您的加入!
adimg adimg
 
昨日:篇  今日:篇   总帖:篇   会员:
今日:0    总帖:89
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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'   => '&laquo;',        'next'   => '&raquo;',        '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天前
admin
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天前
admin
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天前
admin
1100
AUTH权限管理的原理最简单的auth权限管理的4张数据表如下图每一个功能对应的一个url路径,规则表其实就是记录url路径,通过url来实现权限管理权限验证时机分类前置验证所谓前置认证,就是当前可访问的页面内部元素在显示前就进行权限验证。例如:游客访问网页时,看不到某个功能菜单,但管理员能看到等。前置验证用户体验好,但性能差点后置认证所谓后置认证,这个就简单,就是每个功能访问时先进行权限验证。例如,在页面上点击‘添加栏目’按钮,先进行验证,通过才执行添加栏目功能代码。后置验证用户体验差,但性能好权限验证代码实现位置在用户成功登陆后台后,后台所有菜单、导航、按钮的操作就必须进行权限验证但后台首页、欢迎页、用户退出等功能可无需权限验证,根据具体项目需求来订AUTH权限管理与RBAC权限管理的区别相同点:都是基于角色的权限管理不同点:数据表的设计不同,导致AUTH更灵活、权限管理更细腻权限模块设计推荐教程:《TP5》以上就是THINKPHP中的AUTH权限管理介绍的详细内容
0 0 1409天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
admin
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天前
快速发帖 高级模式
联系站长 友链申请桂ICP备19000949号-1     桂ICP备19000949号-1
您的IP:3.144.86.138,2024-05-03 00:58:08,Processed in 0.35983 second(s).
免责声明: 本网不承担任何由内容提供商提供的信息所引起的争议和法律责任。
Powered by HadSky 7.12.9
免责声明
1、本站资源,均来自网络,版权归原作者,所有资源和文章仅限用于学习和研究目的 。
2、不得用于商业或非法用途,否则,一切责任由该用户承担 !
如果觉得本文还不错请点个赞或者打赏点轻币哦~
拒绝伸手党,拿走请回复,尊重楼主,尊重你我他~

侵权删除请致信 E-Mail:207882320@qq.com