[李景山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
- [李景山php]thinkphp核心源码注释|functions.php
- [李景山php]thinkphp核心源码注释|View.class.php
- [李景山php]thinkphp核心源码注释|Think.class.php
- [李景山php]thinkphp核心源码注释|Template.class.php
- [李景山php]thinkphp核心源码注释|Storage.class.php
- [李景山php]thinkphp核心源码注释|Route.class.php
- [李景山php]thinkphp核心源码注释|Model.class.php
- [李景山php]thinkphp核心源码注释|Log.class.php
- [李景山php]thinkphp核心源码注释|Hook.class.php
- [李景山php]thinkphp核心源码注释|DB.class.php
- [李景山php]thinkphp核心源码注释|Controller.class.php
- [李景山php]thinkphp核心源码注释|Cache.class.php
- [李景山php]thinkphp核心源码注释|Build.class.php
- [李景山php]thinkphp核心源码注释|App.class.php
- [李景山php]thinkphp核心源码注释|Disaptcher.class.php
- [李景山php]thinkphp核心源码注释|Taglib.class.php
- [李景山php]thinkphp核心源码注释|Cx.class.php
- [李景山php]thinkphp核心源码注释|Html.class.php
- c#treeview点击节点闪烁
- Angular.js学习之一下载和搭建hello world实例
- BZOJ 2525: [Poi2011]Dynamite
- git笔记
- 【代码笔记】iOS-由身份证号码返回性别
- [李景山php]thinkphp核心源码注释|functions.php
- ubuntu tar 命令
- .Net WebApi接口调试之Swagger集成详解
- ionic登录
- APUE 2-17 确定文件描述符个数
- ViewPagerIndicator使用流程记录
- 使用sqluldr2实现将Oracle数据无落地快速导入Greenplum数据库
- mongodb mysql数据互相导入
- Akka入门