[李景山php]thinkphp核心源码注释|functions.php

来源:互联网 发布:淘宝宝贝型号怎么设置 编辑:程序博客网 时间:2024/05/22 00:29
<?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: liu21st <liu21st@gmail.com>// +----------------------------------------------------------------------/** * Think 系统函数库 */// 同学们,上节课,我们已经 完成了 thinkphp 各种预定义变量的 定义// 重点可以分成以下几点:// 第一:对于 需要 web 加载的 也就是项目文档 thinkphp 采取的 dirname 的方式进行的组合跟加载// 其特点是 ////// 这样的斜杠// 对于 需要引入的文件 也就是 thinkphp 核心框架部分 其加载方式 采取了 __DIR__的方式进行加载// 其特点是 \\\\ 这样的反斜杠// ps 当然这些都是基于 window 下的方向, 也就分成了 两个 路径的 始祖 app_PATH  跟 think_PATH// 第二:我们可以进行记录的事情是// 作为一个框架程序,需要有能力记录 该脚本执行的 时间 跟 内存的消耗,所以 就毫不犹豫的开启了 mirctime 跟 memory_get_usage// 此刻作为 时间 跟 内存的起点。// 第三:值得我们注意的地方是:// 使用了 const 跟 define 定义了 系统常量,但是 感觉就是,必须一成不变的,用了 const// 就代表这个,彻底就固化死了,define 是可以让用户 在创建 自己的 app 中 进行修改的。 在系统进行定义之前,会判读是否定义,// const 是没有 办法重新定义的// 总结 基本没什么区别,这两个, 唯一就是用法啊,编译上的一个区别!// 第四:对 系统预定义变量[GPC] 跟 文本 数据流// 基本上可以说是进行 非转义处理 么有 addsalshe 之类的// 第五:判读了 php 跟 web服务器 的 通信方式 cgi// 判读了操作系统// 判读 了 是否 脱离服务器运行 的命令行工具// 第六: 针对于 ROOT 跟 _FILE_ 文件的定义 不统一,重新进行了多平台定义,增强了平台的可以移植性。// 总之:就是 规范了定义 以及其 跨平台特性!// 接下来我们讲针对与 functions.php 这些 公共函数 为大家进行讲解 20151205/** * 实例化多层控制器 格式:[资源://][模块/]控制器 * @param string $name 资源地址 * @param string $layer 控制层名称 * @param integer $level 控制器层次 * @return Think\Controller|false */// 此函数 进行 多层控制器实例化 功能 方便其内部调用,在写 app 应用的时候比较少用。function A($name,$layer='',$level=0) {    static $_action = array();// 此处定义静态化 存储数组 为其实现 单列实例化模式    $layer  =   $layer? : C('DEFAULT_C_LAYER'); //'DEFAULT_C_LAYER'       =>  'Controller', // 默认的控制器层名称    $level  =   $level? : ($layer == C('DEFAULT_C_LAYER')?C('CONTROLLER_LEVEL'):1); //    'CONTROLLER_LEVEL'      =>  1,    if(isset($_action[$name.$layer]))// 根据传入的控制器 以及其对应的层级 默认:Controller 1 层级 返回        return $_action[$name.$layer];    $class  =   parse_res_name($name,$layer,$level); // 根据其传入的控制器 名称 层级 类名 获取对应的 class 名称    if(class_exists($class)) { // 如果说 根据上述的生成 class 名称 如果存在 就进行实例化        $action             =   new $class(); // 实例化        $_action[$name.$layer]     =   $action;// 存放 实例化对象到静态数组中        return $action;// 返回实例化 情况    }else {        return false;    }    // 例如: $name = 'admin'  结果就是 $class  = AdminController.class.php 文件 下的 AdiminController 类。}// 总结: 其实这个,就是根据你传入的 $name 返回 不同的 实例化对象。$name 可以存在的选项为:// A('[项目://][分组/]模块','控制器层名称')   目前感觉这个level 基本上用不到。// 等待拯救// 好的,同学们我们今天继续,昨天了解A函数,其实就是一个 根据不同参数去实例化不同 控制器类的 一个功能函数// 注意 A函数中 加入了一个 把不同输入参数 转换的 对应类的名称跟位置// 接下来我们来看一下 B 函数的功能/** * 执行某个行为 * @param string $name 行为名称 * @param string $tag 标签名称(行为类无需传入) * @param Mixed $params 传入的参数 * @return void */function B($name, $tag='',&$params=NULL) {    if(''==$tag){        $name   .=  'Behavior';    }    return \Think\Hook::exec($name,$tag,$params);}// 从字面意义上来说,这个是个 执行某个行为的函数,// 如果 没有对应的 标签,也就是 默认的行为就是 找到钩子函数进行执行// 另外注意一点 就是其 $params 其实是一个 引入传值,并不是一个 普通的复制传值,这样,可以无需返回就改变了传入的参数。// 根据其 钩子函数的 特殊情况,一般其配置在 Addons 下面// 默认是 $name Behavior 联合// 默认的执行函数是run// 文件位置 "Addons\\{$name}\\{$name}Addon";// $class   =  $name.'Behavior';// $tag    =   'run';// return $addon->$tag($params);// 总结,其实B函数,就是执行插件【内部/外部】的两种,引入插件的开始位置。执行开始函数。// return $class->run(参数);// 下面继续我们的学习,这个C函数,是一个非常常用的函数,如果说AB我们可以一般的略过,这个就要我们仔细研究一下啦///** * 获取和设置配置参数 支持批量定义 * @param string|array $name 配置变量 * @param mixed $value 配置值 * @param mixed $default 默认值 * @return mixed */function C($name=null, $value=null,$default=null) {    // 定义 初始化容器 ,仅能一次初始化的    static $_config = array();// 经典的静态全局变量注册,执行单一流程时有效,其实,对于多页面不同加载的话,效果不明显。是一个可以优化的地方。    // 无参数时获取所有  情况1    if (empty($name)) { // 这个是一个大招,也就是,当调用 C()的时候,注意,内部为空的时候, 就把你全家的都返回出去了。        return $_config;    }    // 优先执行设置获取或赋值 情况 2    if (is_string($name)) {  // 如果 是个字符串,也不下面数组的形式        if (!strpos($name, '.')) { // 此处可以记作 2.1 如果 没有 连接符号,这个我觉得有点多次一举了,但是 是为了兼容数组的保存形式。老刘啊,你真的不容易啊。            $name = strtoupper($name); // 不关什么 字母,统统大写,这个其实是兼容的一个好的处理方式,同学们可以借鉴哦!            if (is_null($value)) // 这里其实 是可以分的 此处记作2.1.1                return isset($_config[$name]) ? $_config[$name] : $default; // 此处的三元,真的很高明, 可以分成 2.1.1.1 跟 2.1.1.2            $_config[$name] = $value; // 此处记作 2.1.2 你懂了吗            return null; //这些是各种中条件细分            // 总结就是 C('name','zhangsan'); 就是赋值 name 为张三            // 如果 $name = C('name') 就是读取 name的赋值,如果刚刚执行过上面的语句的话            // 那么 $name 就是 张三了        }        // 二维数组设置和获取支持        $name = explode('.', $name); // 这里仅仅是添加了 二维数组的支持 这里有个问题,就是 二维数组的 子元素没有变成大写        $name[0]   =  strtoupper($name[0]);        if (is_null($value))            return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : $default;        $_config[$name[0]][$name[1]] = $value;        return null;    }    // 批量设置  情况3  直接合并数据了 其实并不很常用,原因是容易搞晕,对于我这种小智商的人,就算了,不过,偶尔会用一下。    if (is_array($name)){        $_config = array_merge($_config, array_change_key_case($name,CASE_UPPER));        return null;    }    // 其它 情况    return null; // 避免非法参数}// 好的,感谢同学们,我们下节课继续!// 其实上节课程中我们讲到C函数,这里有一思路,就函数尽量不要收到配置文件的限制,// 我们今天继续D函数,这个函数在 thinkphp的使用中,是贯穿始终的。// 这个是一个 实例化 Model 类的 函数/** * 实例化模型类 格式 [资源://][模块/]模型 * @param string $name 资源地址 * @param string $layer 模型层名称 * @return Think\Model */function D($name='',$layer='') {    if(empty($name)) return new Think\Model; // 如果输入参数为空,直接返回默认的 Model    static $_model  =   array();    // 否则就可以建立 静态 实例化仓库    $layer          =   $layer? : C('DEFAULT_M_LAYER'); // 这里进行默认层的确认,就是    if(isset($_model[$name.$layer]))    // 同样的道理 存在就返回,其实就是单列的应用思想        return $_model[$name.$layer];    $class          =   parse_res_name($name,$layer); //通过解析 获取到对应的 类名 这个函数 是包含导入文件功能的,牛叉吧    if(class_exists($class)) {  // 如果存在 就直接加载 并且实例化        $model      =   new $class(basename($name));    }elseif(false === strpos($name,'/')){ // 如果说没有找到类文件 也就是没有找到类        // 自动加载公共模块下面的模型        if(!C('APP_USE_NAMESPACE')){ // 就去 公共模型下面寻找, 如果没有指定公共模型            import('Common/'.$layer.'/'.$class); // 默认公共模型存放位置        }else{            $class      =   '\\Common\\'.$layer.'\\'.$name.$layer;// 实在不行就去实例化 默认的类了        }        $model      =   class_exists($class)? new $class($name) : new Think\Model($name);    }else { // 否则的日志记录错误 实例化一个基础的类 给 返回回去        Think\Log::record('D方法实例化没找到模型类'.$class,Think\Log::NOTICE);        $model      =   new Think\Model(basename($name));    }    $_model[$name.$layer]  =  $model; // 存入历史记录    return $model;// 返回当期实例化的类  3中方式进行的实例化}// 抛出异常 基本上就是个封装了 直接转的  但是在他的核心代码里面 也没什么东西了。// 仅仅是 继承了 php 默认的异常类/** * 抛出异常处理 * @param string $msg 异常消息 * @param integer $code 异常代码 默认为0 * @throws Think\Exception * @return void */function E($msg, $code=0) {    throw new Think\Exception($msg, $code);}//  这个是一通过文件进行快速 数据 保存跟读取操作的事情。/** * 快速文件数据读取和保存 针对简单类型数据 字符串、数组 * @param string $name 缓存名称 * @param mixed $value 缓存值 * @param string $path 缓存路径 * @return mixed */function F($name, $value='', $path=DATA_PATH) {    static $_cache  =   array(); // 老一套啊,看起来用的很顺手啊,    $filename       =   $path . $name . '.php'; // 文件目录,也很简单。 直接使用的php 文件    if ('' !== $value) { // 如果有数值        if (is_null($value)) { // 如果存在的数值为空的话            // 删除缓存            if(false !== strpos($name,'*')){ // 如果保存的对象中中存在 * 号,错误                return false; // TODO            }else{                unset($_cache[$name]);// 删除数据缓存                return Think\Storage::unlink($filename,'F'); // 删除数据文件            }        } else {            Think\Storage::put($filename,serialize($value),'F'); // 用序列化的方式 写入文件            // 缓存数据            $_cache[$name]  =   $value; // 并且写入缓存            return null;        }    }    // 获取缓存数据    if (isset($_cache[$name])) // 跟其 通用 C 很像啊 ,        return $_cache[$name];    if (Think\Storage::has($filename,'F')){ // 读取 存在的文件        $value      =   unserialize(Think\Storage::read($filename,'F'));        $_cache[$name]  =   $value; // 返回数据    } else {        $value          =   false;    }    return $value; //返回数据}// 就是一个缓存数据的读取,跟 file 相比 差得多了// 好的, 各位同学,继续// 这里给大家提示一点,框架中的 叫做 functions.php 应用中的叫做 function.php// 大家 明白我此刻说的应用里面的位置吗?// 如果作为一个函数的注释来说,该函简洁明了/** * 记录和统计时间(微秒)和内存使用情况 * 使用方法: * <code> * G('begin'); // 记录开始标记位 * // ... 区间运行代码 * G('end'); // 记录结束标签位 * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位  时间 用数字 * echo G('begin','end','m'); // 统计区间内存使用情况  内存用m表示 * 如果end标记位没有定义,则会自动以当前作为标记位 * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效 * </code> * @param string $start 开始标签 * @param string $end 结束标签 * @param integer|string $dec 小数位或者m * @return mixed */// 这里不得不说 thinkphp 的创始人,特别喜欢干的一个事情,就是,根据输入参数的不同实现不同的意义// 如 C 函数 F 函数,都是 ,如果仅仅输入 单一参数 表示读取数字, 2 个参数表示 设定数值,3 个参数一般多加了默认值// number_format — 以千位分隔符方式格式化一个数字// $nombre_format_francais = number_format($number, 2, ',', ' ');function G($start,$end='',$dec=4) {    static $_info       =   array(); // 这个是时间仓库    static $_mem        =   array(); // 这个是内存仓库    if(is_float($end)) { // 记录时间  如果传值如此 G('start',2342353234.453); 就是个记录 跟上面的风格保持一致        // 有 小数 传入 就是 结束        $_info[$start]  =   $end; // 或者 如果传值如此 G('start',microtime(TRUE));    }elseif(!empty($end)){ // 统计时间和内存使用  也就是其默认的优先级 是 时间        // 有 非数字 结尾 就是 返回 差值        if(!isset($_info[$end])) $_info[$end]       =  microtime(TRUE);        if(MEMORY_LIMIT_ON && $dec=='m'){ // 如果开启了内存记录 并且明确是内存的记录            if(!isset($_mem[$end])) $_mem[$end]     =  memory_get_usage(); // 获取内存记录            return number_format(($_mem[$end]-$_mem[$start])/1024); // 获取返回的格式化数值        }else{            return number_format(($_info[$end]-$_info[$start]),$dec); // 返回格式化的位数 默认4位小数        }    }else{ // 记录时间和内存使用        // 单独的话,就是同步记录 内存 跟时间的 标志位。        $_info[$start]  =  microtime(TRUE);        if(MEMORY_LIMIT_ON) $_mem[$start]           =  memory_get_usage();    }    return null;}// 无 H 函数// 今日上午面试,就到这里了,感谢!//  嗯,昨天有点匆忙,其实这个G就是一个记录时间 跟内存的函数,都过第二,第三个参数的属性//  进行区分 是记录的时间还是 其它什么的 ,但是不管怎么得瑟,都是 同时记录的时间 给内存//  通过时间跟内存的记录可以 从一个角度来反映出php 程序运行的性能// 接下来是我们强大的I输入过滤函数,支持默认值/** * 获取输入参数 支持过滤和默认值 * 使用方法: * <code> * I('id',0); 获取id参数 自动判断get或者post // 嗯,你举例的这几个,确实很常用 * I('post.name','','htmlspecialchars'); 获取$_POST['name'] * I('get.'); 获取$_GET * </code> * @param string $name 变量的名称 支持指定类型 * @param mixed $default 不存在的时候默认值 * @param mixed $filter 参数过滤方法 * @param mixed $datas 要获取的额外数据源 * @return mixed */function I($name,$default='',$filter=null,$datas=null) {    // 第一步:指定仓库    static $_PUT   =   null;  // 默认单数据仓库    // 第二步:判定输入类型    if(strpos($name,'/')){ // 指定修饰符        list($name,$type)    =   explode('/',$name,2);    }elseif(C('VAR_AUTO_STRING')){ // 默认强制转换为字符串        // // 输入变量是否自动强制转换为字符串 如果开启则数组变量需要手动传入变量修饰符获取变量        // 其实上面的 这个默认是false        $type   =   's';    }    // 第三步:数据源获取    // 第三步:第一小步骤:就是分解数据源    // 在一般的程序中,上面这两个是用不到的,也就是 指定 数据类型, 默认都没有指定。    if(strpos($name,'.')) { // 指定参数来源        list($method,$name) =   explode('.',$name,2);    }else{ // 默认为自动判断        $method =   'param';    }    // 第三步:第二小步骤:关联数据源    // 指定数据源,常用的就是 get post 了    switch(strtolower($method)) { // 其实这个用的很经典 比较之前 先 小写        case 'get'     :            $input =& $_GET; // 取地址 用的也不错,很有想法            break;        case 'post'    :            $input =& $_POST;            break;        case 'put'     :            if(is_null($_PUT)){                parse_str(file_get_contents('php://input'), $_PUT);            }            $input =$_PUT;/*读取POST数据不能用于multipart/form-data类型php://input VS $HTTP_RAW_POST_DATA读取POST数据 */            break;        case 'param'   :// 其实这个最不科学了,为了兼容懒人编程,            switch($_SERVER['REQUEST_METHOD']) {                case 'POST':                    $input  =  $_POST;                    break;                case 'PUT':                    if(is_null($_PUT)){                        parse_str(file_get_contents('php://input'), $_PUT);                    }                    $input =$_PUT;                    break;                default:                    $input  =  $_GET;            }            break;        // 常用的三种输入 获取方式 GET POST PUT        case 'path'    : // 居然还有路径获取,我调用中从来没用过            $input  =   array();            if(!empty($_SERVER['PATH_INFO'])){                $depr   =   C('URL_PATHINFO_DEPR');// 路径分隔符                //'URL_PATHINFO_DEPR'     =>  '/',  // PATHINFO模式下,各参数之间的分割符号                $input  =   explode($depr,trim($_SERVER['PATH_INFO'],$depr));            }            break;        case 'request' :            $input =& $_REQUEST;            break;        case 'session' :            $input =& $_SESSION;            break;        case 'cookie'  :            $input =& $_COOKIE;            break;        case 'server'  :            $input =& $_SERVER;            break;        case 'globals' :            $input =& $GLOBALS;            break;        case 'data'    :            $input =& $datas;            break;        default:            return null;    }    // 第四步:明确获取变量    // 4.1 获取全部数值    if(''==$name) { // 获取全部变量        $data       =   $input;        // 用过滤函数继续过滤        $filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');        if($filters) {            if(is_string($filters)){                $filters    =   explode(',',$filters);            }            foreach($filters as $filter){                $data   =   array_map_recursive($filter,$data); // 参数过滤            }        }        // 4.2  获取 指定数值    }elseif(isset($input[$name])) { // 取值操作 如果明确一个 取值        $data       =   $input[$name]; // 数据获取完成        // 开始执行过滤        $filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');        // 存在过滤器 开始过滤        if($filters) {            if(is_string($filters)){                if(0 === strpos($filters,'/')){                    if(1 !== preg_match($filters,(string)$data)){ // 过滤器支持正则                        // 支持正则验证                        return   isset($default) ? $default : null;                    }                }else{                    $filters    =   explode(',',$filters);                }            }elseif(is_int($filters)){                $filters    =   array($filters);            }            // 进行数组过滤            if(is_array($filters)){                foreach($filters as $filter){                    if(function_exists($filter)) {                        $data   =   is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤                    }else{                        $data   =   filter_var($data,is_int($filter) ? $filter : filter_id($filter));                        if(false === $data) {                            return   isset($default) ? $default : null;                        }                    }                }            }        }        // 对输出数据类型进行指定 默认 字符串        if(!empty($type)){            switch(strtolower($type)){                case 'a':   // 数组                    $data =(array)$data;                    break;                case 'd':   // 数字                    $data =(int)$data;                    break;                case 'f':   // 浮点                    $data =(float)$data;                    break;                case 'b':   // 布尔                    $data =(boolean)$data;                    break;                case 's':   // 字符串                default:                    $data   =   (string)$data;            }        }        //4.3 获取 默认的 数值了    }else{ // 变量默认值        $data       =    isset($default)?$default:null;    }    // 最后在返回数据之前,在进行处理了,就是 如果是数组,就 执行 默认的过滤函数    is_array($data) && array_walk_recursive($data,'think_filter');    return $data;}// 总结,其实经过上述函数的分析大致可以这样学习的地方:// 第一:按步骤进行分支 代码书写 类似于 第一步: 1.1 1.2 第二步: 2.1 2.2 这样// 第二:依然贯穿了其传统,通过 参数 调整其输出的特色 就是各种参数的样式进行不同的兼容// 第三:就是 各种过滤函数的方便 搭配。真心不错!// 我看好你哦,哈哈!// 无 J函数// 无 K函数// 遇到 这个 L 函数 一般情况下就是 做的 语言配置。/** * 获取和设置语言定义(不区分大小写) * @param string|array $name 语言变量 * @param mixed $value 语言值或者变量 * @return mixed */function L($name=null, $value=null) {    static $_lang = array();// 老步调,定义仓库    // 空参数返回所有定义    // 三种方式    // 第一种方式:为空    if (empty($name)) // 老步调: 无输入 返回全部        return $_lang;    // 判断语言获取(或设置)    // 若不存在,直接返回全大写$name    // 如果 字符串    // 第二种方式:字符串  然后在细分  空 数组 默认 记住这里的return 其实是个神器    if (is_string($name)) { // 如果是字符串        $name   =   strtoupper($name); // 第一步:统统转换成为大写        if (is_null($value)){ // 判读 是 设置 还是读取            return isset($_lang[$name]) ? $_lang[$name] : $name; // 有定义返回定义,没有定义,直接返回        }elseif(is_array($value)){ // 如果是数组            // 支持变量            $replace = array_keys($value); //返回包含数组中所有键名的一个新数组:            foreach($replace as &$v){ // 好复杂,这一节没看懂,嘿嘿 能看懂的在楼下回复哈!感谢                $v = '{$'.$v.'}';            }            return str_replace($replace,$value,isset($_lang[$name]) ? $_lang[$name] : $name);        }        $_lang[$name] = $value; // 语言定义  否则就进行定义        return null;    }    // 批量定义    // 第三种方式:数组    if (is_array($name)) // 批量 定义 array_change_key_case() 函数将数组的所有的键都转换为大写字母或小写字母。默认大写        $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER));    return null;}// 特别常用的 一款 函数 不过 我稍后会  推荐D函数  但是任何函数,都有自己的 特点/** * 实例化一个没有模型文件的Model * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User * @param string $tablePrefix 表前缀 * @param mixed $connection 数据库连接信息 * @return Think\Model *///function M($name='', $tablePrefix='',$connection='') {    static $_model  = array();// 一成不变的仓库    if(strpos($name,':')) { // 可以组合其 代码 然后 拼接成为 类,跟 类名        list($class,$name)    =  explode(':',$name);    }else{        $class      =   'Think\\Model'; // 否则的话,执行 默认的 Model 类 实例化    }    // 这个相当于做了一个唯一值    $guid           =   (is_array($connection)?implode('',$connection):$connection).$tablePrefix . $name . '_' . $class;    if (!isset($_model[$guid])) // 单列  单列        $_model[$guid] = new $class($name,$tablePrefix,$connection); // 实例化保存后的单列    return $_model[$guid]; // 这个不多说了,就这样了。}/** * 设置和获取统计数据 * 使用方法: * <code> * N('db',1); // 记录数据库操作次数 * N('read',1); // 记录读取次数 * echo N('db'); // 获取当前页面数据库的所有操作次数 * echo N('read'); // 获取当前页面读取次数 * </code> * @param string $key 标识位置 * @param integer $step 步进值 * @param boolean $save 是否保存结果 * @return mixed */function N($key, $step=0,$save=false) {    static $_num    = array(); // 仓库    if (!isset($_num[$key])) { // 如果说没有设置 当前值        $_num[$key] = (false !== $save)? S('N_'.$key) :  0; // 如果设置了存储 就在S 函数中,读取处理,否则就0了    }    if (empty($step)){ // 如果没有步进设置        return $_num[$key];    }else{ // 否则 按照步进 的方式前进        $_num[$key] = $_num[$key] + (int)$step;    }    if(false !== $save){ // 保存结果  其实 这个是通过 缓存  读取 函数的。        S('N_'.$key,$_num[$key],$save);    }    return null;}// 无 O函数// 无 P函数// 无 Q函数// 今日到此结束,讲述了 L M N 函数 语言包 M 实例化 可以 指定实例化类 跟 连接的数据库 N 记录步骤// 不好意思,糊涂了,昨天没有更新,今天也才更新/** * 远程调用控制器的操作方法 URL 参数格式 [资源://][模块/]控制器/操作 * @param string $url 调用地址 * @param string|array $vars 调用参数 支持字符串和数组 * @param string $layer 要调用的控制层名称 * @return mixed */// 把查询字符串解析到变量中// parse_str() 函数把查询字符串解析到变量中。// 注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。/**parse_str("name=Bill&age=60");echo $name."<br>";echo $age; *parse_str("name=Bill&age=60",$myArray);print_r($myArray); */// print_r(pathinfo("/testweb/test.txt"));// pathinfo() 返回一个关联数组包含有 path 的信息。/**Array([dirname] => /testweb[basename] => test.txt[extension] => txt) * [dirname][basename][extension] *//**Class ClassA{function bc($b, $c) {$bc = $b + $c;echo $bc;}}call_user_func_array(array('ClassA','bc'), array("111", "222"));//显示 333 */function R($url,$vars=array(),$layer='') {    $info   =   pathinfo($url); // 解析路径    $action =   $info['basename'];  // 获取文件名    $module =   $info['dirname'];   // 获取 文件路径    $class  =   A($module,$layer); // 获取实际 class 实例化  多了一层级的 关系  如Widget    if($class){ // 如果存在 类        if(is_string($vars)) { // 如果有变量 传入            parse_str($vars,$vars); // 解析传入参数到数组        }        return call_user_func_array(array(&$class,$action.C('ACTION_SUFFIX')),$vars); //    }else{        return false;    }}// 总结,其实 这个R 就是 一个call_user_func_array 的升级版本,通过 url 直接进行处理。// 还有一个半小时 今天结束。继续今天的学习// 这个函数 其实也是个很牛叉的函数 ,好像可以 用F函数,让我们对比一下吧,看看 这两个鬼有什么区别。/** * 缓存管理 * @param mixed $name 缓存名称,如果为数组表示进行缓存设置 * @param mixed $value 缓存值 * @param mixed $options 缓存参数 * @return mixed */function S($name,$value='',$options=null) {    static $cache   =   ''; // 仓库 仓库 仓库 又是仓库    //第一步:初始化    if(is_array($options)){ // 如果缓存 参数 其实有点乱 type 可以放到任何一个位置        // 缓存操作的同时初始化 其实就是 就是个 初始化 的过程        $type       =   isset($options['type'])?$options['type']:'';        $cache      =   Think\Cache::getInstance($type,$options);    }elseif(is_array($name)) { // 缓存初始化 // 如果缓存 参数 其实有点乱 type 可以放到任何一个位置        $type       =   isset($name['type'])?$name['type']:'';        $cache      =   Think\Cache::getInstance($type,$name);        return $cache;    }elseif(empty($cache)) { // 自动初始化 还没有的话        $cache      =   Think\Cache::getInstance();  //初始化    }    // 根据对数据 进行 设计    if(''=== $value){ // 获取缓存        return $cache->get($name); // 获取数据    }elseif(is_null($value)) { // 删除缓存        return $cache->rm($name); // 删除数据    }else { // 缓存数据        if(is_array($options)) {            $expire     =   isset($options['expire'])?$options['expire']:NULL;        }else{            $expire     =   is_numeric($options)?$options:NULL;        }        return $cache->set($name, $value, $expire); // 保存数据    }}// 总结,其实这个 就是 干什么的呢,关键点是那个 class 类函数// 其实那个 函数 也没什么了// 今天学一个新的东西,就是 写 模版引擎/** * 获取模版文件 格式 资源://模块@主题/控制器/操作 * @param string $template 模版资源地址 * @param string $layer 视图层(目录)名称 * @return string */function T($template='',$layer=''){    // 解析模版资源地址  第一步:    if(false === strpos($template,'://')){        $template   =   'http://'.str_replace(':', '/',$template);    }    $info   =   parse_url($template); // 第二步:解析到自己的 数组里面    $file   =   $info['host'].(isset($info['path'])?$info['path']:'');    $module =   isset($info['user'])?$info['user'].'/':MODULE_NAME.'/'; // 扩展用户名    $extend =   $info['scheme']; // 扩展 文件扩展名    $layer  =   $layer?$layer:C('DEFAULT_V_LAYER'); // 层次    // 获取当前主题的模版路径    $auto   =   C('AUTOLOAD_NAMESPACE');    if($auto && isset($auto[$extend])){ // 扩展资源        $baseUrl    =   $auto[$extend].$module.$layer.'/';    }elseif(C('VIEW_PATH')){        // 改变模块视图目录        $baseUrl    =   C('VIEW_PATH');    }elseif(defined('TMPL_PATH')){        // 指定全局视图目录        $baseUrl    =   TMPL_PATH.$module;    }else{        $baseUrl    =   APP_PATH.$module.$layer.'/';    }    // 获取主题    $theme  =   substr_count($file,'/')<2 ? C('DEFAULT_THEME') : '';    // 分析模板文件规则    $depr   =   C('TMPL_FILE_DEPR');    if('' == $file) {        // 如果模板文件名为空 按照默认规则定位        $file = CONTROLLER_NAME . $depr . ACTION_NAME;    }elseif(false === strpos($file, '/')){        $file = CONTROLLER_NAME . $depr . $file;    }elseif('/' != $depr){        $file   =   substr_count($file,'/')>1 ? substr_replace($file,$depr,strrpos($file,'/'),1) : str_replace('/', $depr, $file);    }    return $baseUrl.($theme?$theme.'/':'').$file.C('TMPL_TEMPLATE_SUFFIX');}// 总结,其实,这货 就是返回了一个 真实的网址路径而已啦// 今天是这个新东西,组装产品/** * URL组装 支持不同URL模式 * @param string $url URL表达式,格式:'[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...' * @param string|array $vars 传入的参数,支持数组和字符串 * @param string|boolean $suffix 伪静态后缀,默认为true表示获取配置值 * @param boolean $domain 是否显示域名 * @return string * 本函数不是用来验证给定 URL 的合法性的,只是将其分解为下面列出的部分。不完整的 URL 也被接受,parse_url() 会尝试尽量正确地将其解析。 * Array([scheme] => http[host] => hostname[user] => username[pass] => password[path] => /path[query] => arg=value   在问号 ? 之后[fragment] => anchor  在散列符号 # 之后) * $url = 'http://username:password@hostname/path?arg=value#anchor'; */function U($url='',$vars='',$suffix=true,$domain=false) {    // 解析URL 其实这里传入的 url 不是 正常地址上人的 url 他重新做了组合,个人觉得不是很科学    $info   =  parse_url($url); // 解析参数  这里的解析方式 跟正常的还不太一样// 情况 1//    $url = 'Home/Index/index#zhangsan@www.maizi.net?name=lisi&age=32';//    var_dump(parse_url($url));//array (size=2)//'path' => string 'Home/Index/index' (length=16)//  'fragment' => string 'zhangsan@www.maizi.net?name=lisi&age=32' (length=39)    // 情况2//    $url = 'Home/Index/index@www.maizi.net?name=lisi&age=32';//    var_dump(parse_url($url));//    array (size=2)//  'path' => string 'Home/Index/index@www.maizi.net' (length=30)//  'query' => string 'name=lisi&age=32' (length=16)    $url    =  !empty($info['path'])?$info['path']:ACTION_NAME; // 如果解析到了路径,就用解析的路径,否则就用action_name    if(isset($info['fragment'])) { // 解析锚点  就是 网页中 跳转到网站固定位置的 标记        $anchor =   $info['fragment']; // 其实这种是全的  '[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...'        if(false !== strpos($anchor,'?')) { // 解析参数  如果锚点 后面还有跟随的参数            list($anchor,$info['query']) = explode('?',$anchor,2);        }        if(false !== strpos($anchor,'@')) { // 解析域名  如果锚点后,还有@ 域名            list($anchor,$host)    =   explode('@',$anchor, 2);        }    }elseif(false !== strpos($url,'@')) { // 解析域名 把用户名密码 跟 域名拆分        list($url,$host)    =   explode('@',$info['path'], 2);        // '[模块/控制器/操作@域名]?参数1=值1&参数2=值2...' 这种是不全的    }    // 解析子域名  host 就是域名了    if(isset($host)) { // 不是二级域名吗  其实一般情况下是没有这个东西的        // 其实这个用法 很奇怪  一般情况下,就是 $domain = $host  这里可以能是跟随参数的        $domain = $host.(strpos($host,'.')?'':strstr($_SERVER['HTTP_HOST'],'.'));    }elseif($domain===true){ //如果显示域名 如果有添加,这里就不是 true boolen类型才可以哈        $domain = $_SERVER['HTTP_HOST']; // 显示 主机名 域名        if(C('APP_SUB_DOMAIN_DEPLOY') ) { // 开启子域名部署  默认是没有开启            $domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.'); // 默认给他缓存了 www.你的域名啦 本地的就不管了            // '子域名'=>array('模块[/控制器]');  找到子域名的 匹配规则 实际上,可能用不到哈            foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) {// 处理 子域名规则                $rule   =   is_array($rule)?$rule[0]:$rule;                if(false === strpos($key,'*') && 0=== strpos($url,$rule)) {                    $domain = $key.strstr($domain,'.'); // 生成对应子域名                    $url    =  substr_replace($url,'',0,strlen($rule));                    break;                }            }        }    }    // 解析参数 解析 参数,这个是 后面传入的参数    if(is_string($vars)) { // aaa=1&bbb=2 转换成数组        parse_str($vars,$vars);    }elseif(!is_array($vars)){        $vars = array();    }    // 合并参数    if(isset($info['query'])) { // 解析地址里面参数 合并到vars        parse_str($info['query'],$params);        $vars = array_merge($params,$vars);    }    // 这里总结一下,其实就量大步骤,第一步 拆分    // 第二步:组装    // URL组装    $depr       =   C('URL_PATHINFO_DEPR'); //'/', // PATHINFO模式下,各参数之间的分割符号    $urlCase    =   C('URL_CASE_INSENSITIVE'); //// 默认false 表示URL区分大小写 true则表示不区分大小写    // 如果有 url 地址    if($url) {        if(0=== strpos($url,'/')) {// 定义路由  如果是跟目录            $route      =   true;            $url        =   substr($url,1); // 去掉第一个 斜杠            if('/' != $depr) { // 换成系统的 指定的间隔符号                $url    =   str_replace('/',$depr,$url);            }        }else{ // 也就是, 不是根目录的情况下            if('/' != $depr) { // 安全替换                $url    =   str_replace('/',$depr,$url);            }            // 解析模块、控制器和操作            $url        =   trim($url,$depr); // 删除两端的 间隔符号            $path       =   explode($depr,$url); // 解析路径            $var        =   array();            $varModule      =   C('VAR_MODULE'); // 'VAR_MODULE'            =>  'm',     // 默认模块获取变量            $varController  =   C('VAR_CONTROLLER'); //'VAR_CONTROLLER'        =>  'c',    // 默认控制器获取变量            $varAction      =   C('VAR_ACTION'); // 'VAR_ACTION'            =>  'a',    // 默认操作获取变量            $var[$varAction]       =   !empty($path)?array_pop($path):ACTION_NAME; // 通过这种方式 解析出 action            $var[$varController]   =   !empty($path)?array_pop($path):CONTROLLER_NAME;// 同上 解析出            if($maps = C('URL_ACTION_MAP')) { // 定义路由规则 默认是没有的, 所以说,这里是不执行的                if(isset($maps[strtolower($var[$varController])])) {                    $maps    =   $maps[strtolower($var[$varController])];                    if($action = array_search(strtolower($var[$varAction]),$maps)){                        $var[$varAction] = $action;                    }                }            }            if($maps = C('URL_CONTROLLER_MAP')) { // 同上//                $a=array("a"=>"red","b"=>"green","c"=>"blue");//                echo array_search("red",$a);                if($controller = array_search(strtolower($var[$varController]),$maps)){                    $var[$varController] = $controller;                }            }            if($urlCase) { // 是否区分大小写 默认是true 代表不区分                $var[$varController]   =   parse_name($var[$varController]); // 都转换成统一的格式            }            $module =   ''; // 初始化 为空            if(!empty($path)) { // 如果路径不为空                $var[$varModule]    =   implode($depr,$path);            }else{                if(C('MULTI_MODULE')) { // 如果开启多模块 // 是否允许多模块 如果为false 则必须设置 DEFAULT_MODULE                    if(MODULE_NAME != C('DEFAULT_MODULE') || !C('MODULE_ALLOW_LIST')){                        $var[$varModule]=   MODULE_NAME;                    }                }            }            if($maps = C('URL_MODULE_MAP')) { // 如果这里也设置路由 同上                if($_module = array_search(strtolower($var[$varModule]),$maps)){                    $var[$varModule] = $_module;                }            }            if(isset($var[$varModule])){ // 同上                $module =   $var[$varModule];                unset($var[$varModule]);            }        }    }    // 其实这里才开始 真正的组合 分两种方式    // 域名    //    if(C('URL_MODEL') == 0) { // 普通模式URL转换        $url        =   __APP__.'?'.C('VAR_MODULE')."={$module}&".http_build_query(array_reverse($var));        if($urlCase){ // 全部转化小写            $url    =   strtolower($url);        }        if(!empty($vars)) { // 如果参数不为空 加入参数            $vars   =   http_build_query($vars);            $url   .=   '&'.$vars;        }    }else{ // PATHINFO模式或者兼容URL模式        if(isset($route)) {// 如果开启了 路由            $url    =   __APP__.'/'.rtrim($url,$depr);        }else{            $module =   (defined('BIND_MODULE') && BIND_MODULE==$module )? '' : $module;            $url    =   __APP__.'/'.($module?$module.MODULE_PATHINFO_DEPR:'').implode($depr,array_reverse($var));        }        if($urlCase){ // 转换            $url    =   strtolower($url);        }        if(!empty($vars)) { // 添加参数 另外的一种解析方式而已            foreach ($vars as $var => $val){                if('' !== trim($val))   $url .= $depr . $var . $depr . urlencode($val);            }        }        if($suffix) {// 如果定义了 文件后缀            $suffix   =  $suffix===true?C('URL_HTML_SUFFIX'):$suffix;            if($pos = strpos($suffix, '|')){                $suffix = substr($suffix, 0, $pos);            }            if($suffix && '/' != substr($url,-1)){                $url  .=  '.'.ltrim($suffix,'.');            }        }    }    if(isset($anchor)){ // 如果有锚点 组合上        $url  .= '#'.$anchor;    }    if($domain) { // 组合上域名        $url   =  (is_ssl()?'https://':'http://').$domain.$url;    }    return $url;}// 无 V函数// 总结:// 指导 parse_url 是对 url 地址进行解析的函数// 其实我觉得这个函数他复杂了,就是对不同输入的 url 方式解析成为自己的方式// 常用的是 U('Home/Index/index',array('name'=>'lijingshan','age'=>'12'));// 默认的情况下 不会用域名 跟 锚点的,不过这两个还是不错的,哈哈,就是解析起来,不复杂,但是,组合的时候,那个路由规则有点费劲。// 好的,今天我们继续// 这个函数,其实就是个封装/** * 渲染输出Widget * @param string $name Widget名称 * @param array $data 传入的参数 * @return void */function W($name, $data=array()) {    return R($name,$data,'Widget');}// 无 X函数// 无 Y函数// 无 Z函数// 26 字母 函数写完了,// A 函数中调用的 函数/** * 解析资源地址并导入类库文件 * 例如 module/controller addon://module/behavior * @param string $name 资源地址 格式:[扩展://][模块/]资源名 * @param string $layer 分层名称 * @param integer $level 控制器层次 * @return string */function parse_res_name($name,$layer,$level=1){    // 解析扩展资源    if(strpos($name,'://')) {// 指定扩展资源        list($extend,$name)  =   explode('://',$name);// 解析扩展资源    }else{        $extend  =   '';    }    // 解析普通模块    // echo substr_count("I love Shanghai. Shanghai is the biggest city in china.","Shanghai");    // 计算 "Shanghai" 在字符串中出现的次数:    // 默认第一个 模块    if(strpos($name,'/') && substr_count($name, '/')>=$level){ // 指定模块        list($module,$name) =  explode('/',$name,2);    }else{        $module =   defined('MODULE_NAME') ? MODULE_NAME : '' ;    }    // 解析资源    $array  =   explode('/',$name);    if(!C('APP_USE_NAMESPACE')){ // 关闭应用 类库的命名空间处理        $class  =   parse_name($name, 1);        import($module.'/'.$layer.'/'.$class.$layer);// 导入对应文件即可    }else{        $class  =   $module.'\\'.$layer;        foreach($array as $name){            $class  .=   '\\'.parse_name($name, 1);        }        // 导入资源类库        if($extend){ // 扩展资源            $class      =   $extend.'\\'.$class;        }    }    return $class.$layer; // 返回资源}// 今日结束// 首先我们先回顾一下,上一节的东西, W parse_res_name// 这里 我们可以 简单 看出 W 其实就是 规定了 Widget 的 一个指定的扩展// parse_res_name  这里要看出的关键点 就是 parse  很明细是个解析, 那么针对解析的函数来说,明确输入 形式 跟输出形式很重要// 好的,开启我们今天的学习/** * 加载配置文件 支持格式转换 仅支持一级配置 * @param string $file 配置文件名 * @param string $parse 配置解析方法 有些格式需要用户自己解析 * @return array */// 如果是 .ini 配置文件,就解析 配置文件//parse_ini_file() 函数解析一个配置文件,并以数组的形式返回其中的设置//      test.ini//      [names]//      me = Robert//      you = Peter////      [urls]//      first = "http://www.example.com"//      second = "http://www.w3school.com.cn"//          php 代码//        print_r(parse_ini_file("test.ini"));//          输出//          Array//          (//              [me] => Robert//          [you] => Peter//          [first] => http://www.example.com//          [second] => http://www.w3school.com.cn//          )//          print_r(parse_ini_file("test.ini",true));//          Array//          (//              [names] => Array//              (//                  [me] => Robert//                    [you] => Peter//                    )//                  [urls] => Array//                          (//                              [first] => http://www.example.com//                    [second] => http://www.w3school.com.cn//                    )//                  )// 从字面意思上不难理解 这个是加载配置文件的意思// php 文件 直接包含到内存里面// 通过不同的文件类型  不同的加载 方式function load_config($file,$parse=CONF_PARSE){    $ext  = pathinfo($file,PATHINFO_EXTENSION); // 此处的意思,仅仅返回其扩展名 简单点说 也就是 什么类型的文件    switch($ext){        case 'php':            return include $file;        case 'ini':            return parse_ini_file($file);        case 'yaml':            // 一种新的数据格式            return yaml_parse_file($file);        case 'xml':            // 解析 xml            return (array)simplexml_load_file($file);        case 'json':            // 解析 json            return json_decode(file_get_contents($file), true);        default:            // 默认的话,使用 自己配置的专用解析 函数  那如果是这样的话,就不用这个 函数 得瑟了            // 否则 报错            if(function_exists($parse)){                return $parse($file);            }else{                E(L('_NOT_SUPPORT_').':'.$ext);            }    }}/** * 解析yaml文件返回一个数组 * @param string $file 配置文件名 * @return array */// 下面的这种定义很经典if (!function_exists('yaml_parse_file')) {    function yaml_parse_file($file) {        vendor('spyc.Spyc');// 快速 导入第三方框架 处理这个问题        return Spyc::YAMLLoad($file);    }}// 今日结束,感谢大家// 今日我们开始,这个 ,又一个 封存的函数 飘过...../** * 添加和获取页面Trace记录 * @param string $value 变量 * @param string $label 标签 * @param string $level 日志级别 * @param boolean $record 是否记录日志 * @return void|array */function trace($value='[think]',$label='',$level='DEBUG',$record=false) {    return Think\Think::trace($value,$label,$level,$record);}/** * 编译文件 * @param string $filename 文件名 * @return string */// 这里进行文件 编译 php_strip_whitespace — 返回删除注释和空格后的PHP源码function compile($filename) {    $content    =   php_strip_whitespace($filename); // php_strip_whitespace — 返回删除注释和空格后的PHP源码    $content    =   trim(substr($content, 5)); // 删除 开始 的 <?php 标签 删除 两端的空格    // 替换预编译指令  正则替换 如 //[RUNTIME](.*?)//[/RUNTIME\]   变成 ''    $content    =   preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content);    if(0===strpos($content,'namespace')){// 如果存在命名空间 就        $content    =   preg_replace('/namespace\s(.*?);/','namespace \\1{',$content,1);    }else{        // 否则 就直接 使用        $content    =   'namespace {'.$content;    }    // 判读是否存在结束 符号,有的话,就    if ('?>' == substr($content, -2))        $content    = substr($content, 0, -2);    return $content.'}';}// 总结 经过运行后// 第一:其输入参数 $filename = '1.php';// 1.php 的源码如下// 第二:  <?php//          //[RUNTIME]张三//[/RUNTIME\]//          echo 123;// 第三:得到的结果:namespace {echo 123; }// 周六函数解析:// 首先从字面以上来说,这个肯定就是个 数组遍历函数// 从recursive  发现其实好像这个是个递归的函数// 从输入参数的定义可以看出 两个参数 分别是 过滤函数 跟 输入的数据// 也就是可以支持多维数组function array_map_recursive($filter, $data) {    $result = array(); // 建立临时的返回仓库    foreach ($data as $key => $val) { //遍历数组        $result[$key] = is_array($val)         ? array_map_recursive($filter, $val) // 如果是数组递归处理         : call_user_func($filter, $val); // 如果非数组 调用  过滤函数处理    }    return $result;// 返回处理结果 }// 周日函数补充/** * 字符串命名风格转换 * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 * @param string $name 字符串 * @param integer $type 转换类型 * @return string */// 字符串命名 风格转换function parse_name($name, $type=0) {    if ($type) { //如果是java 风格        // 这句话的意思 就是 把所有 带有 下划线  去掉下划线,然后首字母大写  $match[0] = '_jingshan'  $match[1] = ]jingshan'        return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function($match){return strtoupper($match[1]);}, $name));    } else {        // \0 全部的大写字母 都改成下划线 并且 加上原来的字母        // 第一步:Jingshan==>_Jingshan        // 第二步:删除去多于的字符        // 第三步:转换成为i小写字母        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));    }}// 总结:// C 风格字符串//echo parse_name('zhangsan_jingshanLisi');//zhangsan_jingshan_lisi// Java 风格字符串//echo parse_name('zhangsan_jingshanLisi',1);//ZhangsanJingshanLisi// 周一代码/** * 优化的require_once * @param string $filename 文件地址 * @return boolean */function require_cache($filename) {    static $_importFiles = array(); // 久违了, 数据仓库    if (!isset($_importFiles[$filename])) { //如果乜嘢包含文件        if (file_exists_case($filename)) { // 如果文件都存在            require $filename;// 包含文件            $_importFiles[$filename] = true; //确认 已经包含        } else {            $_importFiles[$filename] = false; // 标志位        }    }    return $_importFiles[$filename]; // 返回文件}/** * 区分大小写的文件存在判断 * @param string $filename 文件地址 * @return boolean */// 首先进行 文件的判断// realpath — 返回规范化的绝对路径名// D:\WWW\www.maizi.net\1.css// 如果使用 realpath('1.css') 显示 为 上面的这个// basename 解析后的代码 就变成了 1.cssfunction file_exists_case($filename) {    if (is_file($filename)) {        if (IS_WIN && APP_DEBUG) {            if (basename(realpath($filename)) != basename($filename))                return false;        }        return true;    }    return false;}// 总结:其知识点是这样的,就是 上面的 重点,一个是 realpath 获取文件的 盘符之下的绝对路径// basename 获取 文件名// 这个是 thinkphp 里面自己最常用的 导入 手法/** * 导入所需的类库 同java的Import 本函数有缓存功能 * @param string $class 类库命名空间字符串 * @param string $baseUrl 起始路径 * @param string $ext 导入的文件扩展名 * @return boolean *///$find = array("Hello","world");//$replace = array("B",'s');//$arr = array("Hello","world","!");//print_r(str_replace($find,$replace,$arr));//Array ( [0] => B [1] => s [2] => ! )function import($class, $baseUrl = '', $ext=EXT) {    static $_file = array(); // 作为导入 数据的 思路,或者仓库来讲,都有这样的一个思路 就是静态仓库    $class = str_replace(array('.', '#'), array('/', '.'), $class);    // 上面采用的相对不是很常用的 数组替换    if (isset($_file[$class . $baseUrl]))        return true; // 如果文件已经加载了,就返回真    else        $_file[$class . $baseUrl] = true; // 否则进行加载动作,进行加载标志位的 修改    $class_strut     = explode('/', $class); // 拆分数组    if (empty($baseUrl)) {// 如果没有 跟目录 也就是基础目录        // 当默认目录 为空的情况下,会进行不同情况下的一个加载        // 就是各种模式下的一个加载        if ('@' == $class_strut[0] || MODULE_NAME == $class_strut[0]) {            //加载当前模块的类库            $baseUrl = MODULE_PATH;            $class   = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);        }elseif ('Common' == $class_strut[0]) {            //加载公共模块的类库            $baseUrl = COMMON_PATH;            $class   = substr($class, 7);        }elseif (in_array($class_strut[0],array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$class_strut[0])) {            // 系统类库包和第三方类库包            $baseUrl = LIB_PATH;        }else { // 加载其他模块的类库            $baseUrl = APP_PATH;        }    }    if (substr($baseUrl, -1) != '/') // -1 代表倒序  判读如果 基础目录没有这个,        $baseUrl    .= '/'; // 就添加上这个    $classfile       = $baseUrl . $class . $ext;    if (!class_exists(basename($class),false)) { // 如果类不存在 base        // print_r(basename('Think/Util/Aay')) ; 结果为 Aay        // 如果类不存在 则导入类库文件        return require_cache($classfile);    }    return null;}// 总结,其实上面也没什么,就是个,加载类文件,针对于不同的类的输入参数,进行不同的加载而已// 今日 的另外一种导入方式/** * 基于命名空间方式导入函数库 * load('@.Util.Array') * @param string $name 函数库命名空间字符串 * @param string $baseUrl 起始路径 * @param string $ext 导入的文件扩展名 * @return void */function load($name, $baseUrl='', $ext='.php') {    $name = str_replace(array('.', '#'), array('/', '.'), $name);    // 规则演化    if (empty($baseUrl)) {        // 不同输入参数的 不同输出        if (0 === strpos($name, '@/')) {//加载当前模块函数库            $baseUrl    =   MODULE_PATH.'Common/';            $name       =   substr($name, 2);        } else { //加载其他模块函数库            $array      =   explode('/', $name);            $baseUrl    =   APP_PATH . array_shift($array).'/Common/';            $name       =   implode('/',$array);        }    }    // 不为空,就清空 然后在添加    if (substr($baseUrl, -1) != '/')        $baseUrl       .= '/';    require_cache($baseUrl . $name . $ext); // 用升级版 替换包含文件}// 总结,这个函数 相对于 import 简直就是弱爆了,太容易了。这个让我想起来javascript 里面的 call// 貌似很强大,然没感觉有什么鸟用//24 日/** * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面 * @param string $class 类库 * @param string $baseUrl 基础目录 * @param string $ext 类库后缀 * @return boolean */// 又是一个变种function vendor($class, $baseUrl = '', $ext='.php') {    if (empty($baseUrl))        $baseUrl = VENDOR_PATH;    return import($class, $baseUrl, $ext);}// 总结,其实,今日我是昏迷的,我26日,重新补上了,这个,感谢大家的支持// 这里也没什么特殊的了,其实,就是一个 修改地址// 25 日/** * 用于实例化访问控制器 * @param string $name 控制器名 * @param string $path 控制器命名空间(路径) * @return Think\Controller|false */function controller($name,$path=''){    $layer  =   C('DEFAULT_C_LAYER'); // 这个显然是记不住的,但是, 我搜索了一下,默认是 controller    if(!C('APP_USE_NAMESPACE')){ // 如果没有定义 用户默认的 控制器 // 自动加载的应用类库层 关闭APP_USE_NAMESPACE后有效        $class  =   parse_name($name, 1).$layer;// 这个 找到对应的类名        import(MODULE_NAME.'/'.$layer.'/'.$class); // 找到对应的 controller 控制器名称    }else{        // 也就是 个人设置的起到效果了        $class  =   ( $path ? basename(ADDON_PATH).'\\'.$path : MODULE_NAME ).'\\'.$layer;        $array  =   explode('/',$name);        foreach($array as $name){            $class  .=   '\\'.parse_name($name, 1);        }        $class .=   $layer; // 不知道上面怎么折腾的,反正最后就是返回 类名,感谢!    }    if(class_exists($class)) {        return new $class(); // 返回实例化的 类    }else {        return false;    }}// 总结 :没什么特殊的,这个我见多了,就是,换一个名字,实例化了,两中方式下的 控制器类// 然后,成功了呢,就返回,否则,就是 不行。// 26 日/** * 处理标签扩展 * @param string $tag 标签名称 * @param mixed $params 传入参数 * @return void */function tag($tag, &$params=NULL) {    \Think\Hook::listen($tag,$params);}// 总结:我能默默的说,这个,我能飘过吗,其实还是有个知识点的,// 第一:命名空间的 根目录浏览// 静态函数的调用// 这个是一个 重点 的提升中/** * 去除代码中的空白和注释 * @param string $content 代码内容 * @return string */function strip_whitespace($content) {    $stripStr   = ''; // 这个,估计是返回的 数据仓库,没有特殊的原理    //分析php源码    $tokens     = token_get_all($content);    // token_get_all() 解析提供的 source 源码字符,然后使用 Zend 引擎的语法分析器获取源码中的 PHP 语言的解析器代号    // 这个表示 没怎么看懂    // 不是没有看明白函数的意思,是不明白这个用他干什么呢?    $last_space = false; // 最后一个 不容易啊    // 明白了,上面是个解析啊    for ($i = 0, $j = count($tokens); $i < $j; $i++) { // 这个 for 用的牛叉,很少这样用,不过,真心不错        if (is_string($tokens[$i])) {            $last_space = false;            $stripStr  .= $tokens[$i];        } else {            switch ($tokens[$i][0]) {                //过滤各种PHP注释                case T_COMMENT:                case T_DOC_COMMENT:                    break;                //过滤空格                case T_WHITESPACE:                    if (!$last_space) {                        $stripStr  .= ' ';                        $last_space = true;                    }                    break;                case T_START_HEREDOC:                    $stripStr .= "<<<THINK\n";                    break;                case T_END_HEREDOC:                    $stripStr .= "THINK;\n";                    for($k = $i+1; $k < $j; $k++) {                        if(is_string($tokens[$k]) && $tokens[$k] == ';') {                            $i = $k;                            break;                        } else if($tokens[$k][0] == T_CLOSE_TAG) {                            break;                        }                    }                    break;                default:                    $last_space = false;                    $stripStr  .= $tokens[$i][1];            }        }    }    return $stripStr;}// 总结,就是,各种过滤呗,感谢/***array (size=5)0 =>array (size=3)0 => int 3681 => string '<?php ' (length=6)2 => int 11 =>array (size=3)0 => int 3161 => string 'echo' (length=4)2 => int 12 => string ';' (length=1)3 =>array (size=3)0 => int 3711 => string ' ' (length=1)2 => int 14 =>array (size=3)0 => int 3701 => string '?>' (length=2)2 => int 1 */// 27 日/** * 自定义异常处理 * @param string $msg 异常消息 * @param string $type 异常类型 默认为Think\Exception * @param integer $code 异常代码 默认为0 * @return void */// 建议使用 自定义异常类进行处理function throw_exception($msg, $type='Think\\Exception', $code=0) {    // 记录 异常类的方式    Think\Log::record('建议使用E方法替代throw_exception',Think\Log::NOTICE);    if (class_exists($type, false)) // 指定的存在的话,就这么执行        throw new $type($msg, $code);    else        Think\Think::halt($msg);        // 异常类型不存在则输出错误信息字串    // 核心框架中的 重新封装了 各种异常处理}// 总结:就是个打包的过程,然 没什么实质上的意义,但是,这样方便的错误的管理// 这个是 跟 var_dump() 有的一拼的属性, 其实这个 经常用了// 来今天我们来看看他的真面貌/** * 浏览器友好的变量输出 * @param mixed $var 变量 * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串 * @param string $label 标签 默认为空 * @param boolean $strict 是否严谨 默认为true * @return void|string */// 其实我们常用的参数里面,基本上就只有一个参数function dump($var, $echo=true, $label=null, $strict=true) {    $label = ($label === null) ? '' : rtrim($label) . ' '; // 对标签替换我为空,经典的写法。    // 真心不错,我个人很喜欢    // 这种写法,证明 了作者,不仅仅是停留在了 函数 三元运算符的形式上,跟深入掌握理解并且灵活运用了该运算符。    if (!$strict) { // 很明显,从字面意思上可以看出是非严格算法        if (ini_get('html_errors')) {// 如果 php.ini 设置了 html_errors            // 是否在出错信息中使用HTML标记。 当前默认为打开状态            $output = print_r($var, true); // 格式化输出 注意,这里是不直接输出的,而是整理成为输出的字符串的样式。            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';        } else {            // 否则 执行此格式化输出            $output = $label . print_r($var, true);        }    } else {// 否则先输出到缓存        ob_start();        var_dump($var);        $output = ob_get_clean();        if (!extension_loaded('xdebug')) { // 查看是否加载 xdebug            $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';        }    }    if ($echo) { // 如果是普通的 echo 默认是这个,就输出就可以了 不需要返回        echo($output);        return null;    }else // 否则返回        return $output;}// 总结:默认严谨输出,其实,就是 在print_r 的基础上,加个了pre 格式化而已// 并且 区分了,输出,跟返回,默认是输出。就ok 了,其它的没了// 今日播报/** * 设置当前页面的布局 * @param string|false $layout 布局名称 为false的时候表示关闭布局 * @return void */function layout($layout) {// 这个是一个布局的函数,其实我没怎么搞懂,不,准确的说,我不怎么用这个函数    if(false !== $layout) {// 绝对的恒不等判定,看来要求,很严格啊        // 开启布局        C('LAYOUT_ON',true);// 配置其 开启布局        if(is_string($layout)) { // 设置新的布局模板            C('LAYOUT_NAME',$layout); // 进行布局 分析        }    }else{// 临时关闭布局        C('LAYOUT_ON',false);    }}// 总结:就是各种变量的配置// 然在实际使用过程中,我更喜欢 exttions 继承的方式// 可能是代码写多了的原因吧/** * 判断是否SSL协议 * @return boolean */// 谁能告诉我什么是ssl协议// SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。// 百科上这么说的// SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。// HTTPS(Hypertext Transfer Protocol Secure)安全超文本传输协议function is_ssl() {    if(isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))){        return true;    }elseif(isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'] )) {        return true;    }    return false;}// 总结:就是看看传送的协议是否是安全的而已了// 重新定向的代码发送/** * URL重定向 * @param string $url 重定向的URL地址 * @param integer $time 重定向的等待时间(秒) * @param string $msg 重定向前的提示信息 * @return void */function redirect($url, $time=0, $msg='') {    //多行URL地址支持    $url        = str_replace(array("\n", "\r"), '', $url);    if (empty($msg))        $msg    = "系统将在{$time}秒之后自动跳转到{$url}!";    if (!headers_sent()) {        // redirect        if (0 === $time) {// 立即跳转            header('Location: ' . $url);        } else { // 刷新跳转            header("refresh:{$time};url={$url}");            echo($msg);        }        exit();    } else { // 另外的一种跳转方式        $str    = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";        if ($time != 0)            $str .= $msg;        exit($str);    }}// 总结:进行了多种不同情况的一个跳转 没发送就用头跳转 发送了,就用 meta 跳转//headers_sent() 函数检查 HTTP 标头是否已被发送以及在哪里被发送。//如果报头已发送,则返回 true,否则返回 false。// 今日继续/** * 根据PHP各种类型变量生成唯一标识号 * @param mixed $mix 变量 * @return string */// 这个其实就是变量的 选择性加密 增强了我的加密判断function to_guid_string($mix) {    if (is_object($mix)) {        return spl_object_hash($mix);    } elseif (is_resource($mix)) {        $mix = get_resource_type($mix) . strval($mix);    } else {        $mix = serialize($mix);    }    return md5($mix);}/** * $c = mysql_connect();echo get_resource_type($c)."\n";// 打印:mysql link$fp = fopen("foo","w");echo get_resource_type($fp)."\n";// 打印:file$doc = new_xmldoc("1.0");echo get_resource_type($doc->doc)."\n";// 打印:domxml document */// strval 将变量转成字符串类型。// 总结:就是个不同的加密,嘿嘿// 今日继续 30 日// 这个其实 是一个补充的编码类型/** * XML编码 * @param mixed $data 数据 * @param string $root 根节点名 * @param string $item 数字索引的子节点名 * @param string $attr 根节点属性 * @param string $id   数字索引子节点key转换的属性名 * @param string $encoding 数据编码 * @return string */function xml_encode($data, $root='think', $item='item', $attr='', $id='id', $encoding='utf-8') {    if(is_array($attr)){ // 判读是否是数组        $_attr = array();        foreach ($attr as $key => $value) {            $_attr[] = "{$key}=\"{$value}\"";        } // 将数组进行转存        $attr = implode(' ', $_attr); // 空格 变成其 字符串    }    // 上面就是重新规整一下数组。    $attr   = trim($attr); // 清楚两端多于空格    $attr   = empty($attr) ? '' : " {$attr}"; // 为空为 : 否则为数据    $xml    = "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>";    $xml   .= "<{$root}{$attr}>";    $xml   .= data_to_xml($data, $item, $id); // 又是一内核函数    $xml   .= "</{$root}>";    return $xml;}// 总结:就是 转换形式。/** * 数据XML编码 * @param mixed  $data 数据 * @param string $item 数字索引时的节点名称 * @param string $id   数字索引key转换为的属性名 * @return string */function data_to_xml($data, $item='item', $id='id') {    $xml = $attr = '';    foreach ($data as $key => $val) {        if(is_numeric($key)){            $id && $attr = " {$id}=\"{$key}\"";            $key  = $item;        }        $xml    .=  "<{$key}{$attr}>";        $xml    .=  (is_array($val) || is_object($val)) ? data_to_xml($val, $item, $id) : $val;        $xml    .=  "</{$key}>";    }    return $xml;}// 这个是 对上面的一个 补充,处理其内部编码。// 我最不喜欢这个了‘// 今日继续  31日/** * session管理函数 * @param string|array $name session名称 如果为数组则表示进行session设置 * @param mixed $value session值 * @return mixed */// 这个 太重要了// 两个参数,一个是/** * php的session是可以程序恢复的,这个和java不太一样。session的恢复机制可以实现多个应用程序session的共享,因为php的session都是以文件形式或者数据库存储的。首先是session_id的获取是通过session_id()函数获取,这个值可以进行传递。 */function session($name='',$value='') {    $prefix   =  C('SESSION_PREFIX'); // 设置session 前缀:    if(is_array($name)) { // session初始化 在session_start 之前调用        // 如果是数组,可能意味着,批量化 赋值        if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']);        // 如果在传入的数组重新定义了 prefix  修改默认其前缀配置        if(C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])){            session_id($_REQUEST[C('VAR_SESSION_ID')]);            // 获取 session_id        }elseif(isset($name['id'])) {            session_id($name['id']); // 如果在 数组中设置了ID 那么就有了        }        if('common' == APP_MODE){ // 其它模式可能不支持            ini_set('session.auto_start', 0);// 禁止其自动启动        }        // 处理 session 名字        if(isset($name['name']))            session_name($name['name']);        // 处理 session 路径        if(isset($name['path']))            session_save_path($name['path']);        // 处理 session 域名        if(isset($name['domain']))          ini_set('session.cookie_domain', $name['domain']);        // 处理其生成中秋        if(isset($name['expire']))          {            ini_set('session.gc_maxlifetime',   $name['expire']);            ini_set('session.cookie_lifetime',  $name['expire']);        }        // PHP中的session有效期默认是1440秒(24分钟)【weiweiok 注:php5里默认的是180分】,也就是说,客户端超过24分钟没有刷新,当前session就会失效。很明显,这是不能满足需要的。        if(isset($name['use_trans_sid']))   ini_set('session.use_trans_sid', $name['use_trans_sid']?1:0);// 设置这个        if(isset($name['use_cookies']))     ini_set('session.use_cookies', $name['use_cookies']?1:0);// 设置这个        if(isset($name['cache_limiter']))   session_cache_limiter($name['cache_limiter']);// 设置这个        if(isset($name['cache_expire']))    session_cache_expire($name['cache_expire']);// 设置这个        if(isset($name['type']))            C('SESSION_TYPE',$name['type']);// 设置这个        if(C('SESSION_TYPE')) { // 读取session驱动            $type   =   C('SESSION_TYPE');// 获取不同的session 驱动            $class  =   strpos($type,'\\')? $type : 'Think\\Session\\Driver\\'. ucwords(strtolower($type));            $hander =   new $class();            session_set_save_handler(                array(&$hander,"open"),                 array(&$hander,"close"),                 array(&$hander,"read"),                 array(&$hander,"write"),                 array(&$hander,"destroy"),                 array(&$hander,"gc"));         }        // 启动session        if(C('SESSION_AUTO_START'))  session_start();// 开启session        // 如果是数组的话,这个配置项就多多了    }elseif('' === $value){ // 如果没有数值 默认就是读取        if(''===$name){            // 获取全部的session            return $prefix ? $_SESSION[$prefix] : $_SESSION; // 读取全部        }elseif(0===strpos($name,'[')) { // session 操作 // 特殊操作            if('[pause]'==$name){ // 暂停session                session_write_close();            }elseif('[start]'==$name){ // 启动session                session_start();            }elseif('[destroy]'==$name){ // 销毁session                $_SESSION =  array(); // 各种销毁啊                session_unset(); // 各种销毁啊                session_destroy(); // 各种销毁啊            }elseif('[regenerate]'==$name){ // 重新生成id                session_regenerate_id();            }        }elseif(0===strpos($name,'?')){ // 检查session 如果有 ?的话            $name   =  substr($name,1); //删掉问号            if(strpos($name,'.')){ // 支持数组                list($name1,$name2) =   explode('.',$name); // 分析其代码                return $prefix?isset($_SESSION[$prefix][$name1][$name2]):isset($_SESSION[$name1][$name2]);            }else{                return $prefix?isset($_SESSION[$prefix][$name]):isset($_SESSION[$name]);            }            // 返回其 数组 如 company.nanme $_SESSION[$prefix][company][nanme]        }elseif(is_null($name)){ // 清空session // 如果传入的参数 为null            // 清空            if($prefix) {                unset($_SESSION[$prefix]);            }else{                $_SESSION = array();            }        }elseif($prefix){ // 获取session 跟上面的很相近            if(strpos($name,'.')){                list($name1,$name2) =   explode('.',$name);                return isset($_SESSION[$prefix][$name1][$name2])?$_SESSION[$prefix][$name1][$name2]:null;              }else{                return isset($_SESSION[$prefix][$name])?$_SESSION[$prefix][$name]:null;                            }                    }else{// 默认返回二维数组            if(strpos($name,'.')){                list($name1,$name2) =   explode('.',$name);                return isset($_SESSION[$name1][$name2])?$_SESSION[$name1][$name2]:null;              }else{                return isset($_SESSION[$name])?$_SESSION[$name]:null;            }                    }    }elseif(is_null($value)){ // 删除session        if(strpos($name,'.')){ // 二维数组删除            list($name1,$name2) =   explode('.',$name);            if($prefix){                unset($_SESSION[$prefix][$name1][$name2]);            }else{                unset($_SESSION[$name1][$name2]);            }        }else{ // 普通删除            if($prefix){                unset($_SESSION[$prefix][$name]);            }else{                unset($_SESSION[$name]);            }        }    }else{ // 设置session        if(strpos($name,'.')){ // 设置            list($name1,$name2) =   explode('.',$name);            if($prefix){                $_SESSION[$prefix][$name1][$name2]   =  $value;            }else{                $_SESSION[$name1][$name2]  =  $value;            }        }else{// 设置            if($prefix){                $_SESSION[$prefix][$name]   =  $value;            }else{                $_SESSION[$name]  =  $value;            }        }    }    return null;}// 总结:这个真的很重要:// 然发现没有使用起来感觉那么高大上// 唯一的惊奇的地方,就是 其 数组参数,可以完全设置各种参数。// 16 年 1号,嘿嘿,跨年了/** * Cookie 设置、获取、删除 * @param string $name cookie名称 * @param mixed $value cookie值 * @param mixed $option cookie参数 * @return mixed */function cookie($name='', $value='', $option=null) {    // 默认设置    $config = array(        'prefix'    =>  C('COOKIE_PREFIX'), // cookie 名称前缀        'expire'    =>  C('COOKIE_EXPIRE'), // cookie 保存时间        'path'      =>  C('COOKIE_PATH'), // cookie 保存路径        'domain'    =>  C('COOKIE_DOMAIN'), // cookie 有效域名        'secure'    =>  C('COOKIE_SECURE'), //  cookie 启用安全传输        'httponly'  =>  C('COOKIE_HTTPONLY'), // httponly设置    ); // 各种设置    // 参数设置(会覆盖黙认设置)    if (!is_null($option)) { // 非默认值,就开启        if (is_numeric($option))// 数字,直接就是过期时间            $option = array('expire' => $option);        elseif (is_string($option)) // 字符串,解析字符串            parse_str($option, $option);        // parse_str("name=Bill&age=60");        $config     = array_merge($config, array_change_key_case($option));// 合并设置    }    if(!empty($config['httponly'])){ // 默认仅仅支持 http 其的顾管        ini_set("session.cookie_httponly", 1);    }    // 清除指定前缀的所有cookie    if (is_null($name)) { // 清空全部        if (empty($_COOKIE))            return null;        // 要删除的cookie前缀,不指定则删除config设置的指定前缀        $prefix = empty($value) ? $config['prefix'] : $value; // 前缀        if (!empty($prefix)) {// 如果前缀为空字符串将不作处理直接返回            foreach ($_COOKIE as $key => $val) {                if (0 === stripos($key, $prefix)) {                    setcookie($key, '', time() - 3600, $config['path'], $config['domain'],$config['secure'],$config['httponly']);                    unset($_COOKIE[$key]);                }            }        }        return null;    }elseif('' === $name){        // 获取全部的cookie        return $_COOKIE;    }    $name = $config['prefix'] . str_replace('.', '_', $name); // 二维数组 变成字符串    if ('' === $value) {        if(isset($_COOKIE[$name])){            $value =    $_COOKIE[$name];            if(0===strpos($value,'think:')){                $value  =   substr($value,6);                return array_map('urldecode',json_decode(MAGIC_QUOTES_GPC?stripslashes($value):$value,true));            }else{                return $value;            }        }else{            return null;        }    } else { // 删除数值        if (is_null($value)) {            setcookie($name, '', time() - 3600, $config['path'], $config['domain'],$config['secure'],$config['httponly']);            unset($_COOKIE[$name]); // 删除指定cookie        } else {            // 设置cookie            if(is_array($value)){                $value  = 'think:'.json_encode(array_map('urlencode',$value));            }            $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0;            setcookie($name, $value, $expire, $config['path'], $config['domain'],$config['secure'],$config['httponly']);            $_COOKIE[$name] = $value;        }    }    return null;}// 总结:发现也没什么用 关键函数还是这个setcookie// 16 年 2号/** * 加载动态扩展文件 * @var string $path 文件路径 * @return void */function load_ext_file($path) {    // 加载自定义外部文件    if($files = C('LOAD_EXT_FILE')) { // 批量加载外部文件 ,指定路径下的外部文件        $files      =  explode(',',$files);        foreach ($files as $file){            $file   = $path.'Common/'.$file.'.php';            if(is_file($file)) include $file;        }    }    // 加载自定义的动态配置文件    if($configs = C('LOAD_EXT_CONFIG')) {// 加载配置文件 也是文件,不是配置选项        if(is_string($configs)) $configs =  explode(',',$configs);        foreach ($configs as $key=>$config){            $file   = is_file($config)? $config : $path.'Conf/'.$config.CONF_EXT;            if(is_file($file)) { // 并且动态加载到配置的选项                is_numeric($key)?C(load_config($file)):C($key,load_config($file));            }        }    }}// 总结,没什么的,就是个批量加载文件,或者配置选项而已了。// 16年 3号/** * 获取客户端IP地址 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @param boolean $adv 是否进行高级模式获取(有可能被伪装)  * @return mixed */function get_client_ip($type = 0,$adv=false) {    $type       =  $type ? 1 : 0; // 个人感觉这个写的太无良了,毛用没有啊,不够处理了个 函数的强制转换数值    static $ip  =   NULL; // 默认返回IP地址 非 IPV4数字    if ($ip !== NULL) return $ip[$type];// 如果已经有了,就直接返回    if($adv){ // 是否高级默认,默认非高级模式,去掉伪装        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {            // 不同形势下的IP 获得            $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);            $pos    =   array_search('unknown',$arr);            if(false !== $pos) unset($arr[$pos]);            $ip     =   trim($arr[0]);        }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {            $ip     =   $_SERVER['HTTP_CLIENT_IP'];        }elseif (isset($_SERVER['REMOTE_ADDR'])) {            $ip     =   $_SERVER['REMOTE_ADDR'];        }    }elseif (isset($_SERVER['REMOTE_ADDR'])) { // 不检测伪装        $ip     =   $_SERVER['REMOTE_ADDR'];    }    // IP地址合法验证    $long = sprintf("%u",ip2long($ip));// 检测是否合格IP    $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0); // 合格就返回获取的数据,否则是0    return $ip[$type];}// 总结,其实这个函数没有那么神秘,就是返回,并且自己同时处理好了 ip 跟数字,需要就个返回那个// ip 转数字的函数 是ip2long/** * 发送HTTP状态 * @param integer $code 状态码 * @return void */// 发送状态码function send_http_status($code) {    static $_status = array(            // Informational 1xx            100 => 'Continue',            101 => 'Switching Protocols',            // Success 2xx            200 => 'OK',            201 => 'Created',            202 => 'Accepted',            203 => 'Non-Authoritative Information',            204 => 'No Content',            205 => 'Reset Content',            206 => 'Partial Content',            // Redirection 3xx            300 => 'Multiple Choices',            301 => 'Moved Permanently',            302 => 'Moved Temporarily ',  // 1.1            303 => 'See Other',            304 => 'Not Modified',            305 => 'Use Proxy',            // 306 is deprecated but reserved            307 => 'Temporary Redirect',            // Client Error 4xx            400 => 'Bad Request',            401 => 'Unauthorized',            402 => 'Payment Required',            403 => 'Forbidden',            404 => 'Not Found',            405 => 'Method Not Allowed',            406 => 'Not Acceptable',            407 => 'Proxy Authentication Required',            408 => 'Request Timeout',            409 => 'Conflict',            410 => 'Gone',            411 => 'Length Required',            412 => 'Precondition Failed',            413 => 'Request Entity Too Large',            414 => 'Request-URI Too Long',            415 => 'Unsupported Media Type',            416 => 'Requested Range Not Satisfiable',            417 => 'Expectation Failed',            // Server Error 5xx            500 => 'Internal Server Error',            501 => 'Not Implemented',            502 => 'Bad Gateway',            503 => 'Service Unavailable',            504 => 'Gateway Timeout',            505 => 'HTTP Version Not Supported',            509 => 'Bandwidth Limit Exceeded'    );    if(isset($_status[$code])) { // 两种模式下发送        header('HTTP/1.1 '.$code.' '.$_status[$code]);        // 确保FastCGI模式下正常        header('Status:'.$code.' '.$_status[$code]);    }}// 查询过滤function think_filter(&$value){    // TODO 其他安全过滤    // 过滤查询特殊字符    if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){        $value .= ' ';// 如果匹配了,加一个空格,感觉什么用的没有呢    }}// 不区分大小写的in_array实现// 直接转换为小写,就不用区分大小写了function in_array_case($value,$array){    return in_array(strtolower($value),array_map('strtolower',$array));}
0 0
原创粉丝点击