// +---------------------------------------------------------------------- /** * Think 系统函数库 */ /** * 获取和设置配置参数 支持批量定义 * @param string|array $name 配置变量 * @param mixed $value 配置值 * @param mixed $default 默认值 * @return mixed */ function C($name=null, $value=null,$default=null) { static $_config = array(); // 无参数时获取所有 if (empty($name)) { return $_config; } // 优先执行设置获取或赋值 if (is_string($name)) { if (!strpos($name, '.')) { $name = strtoupper($name); if (is_null($value)) return isset($_config[$name]) ? $_config[$name] : $default; $_config[$name] = $value; return null; } // 二维数组设置和获取支持 $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; } // 批量设置 if (is_array($name)){ $_config = array_merge($_config, array_change_key_case($name,CASE_UPPER)); return null; } return null; // 避免非法参数 } /** * 加载配置文件 支持格式转换 仅支持一级配置 * @param string $file 配置文件名 * @param string $parse 配置解析方法 有些格式需要用户自己解析 * @return array */ 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': return (array)simplexml_load_file($file); case '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); } } /** * 抛出异常处理 * @param string $msg 异常消息 * @param integer $code 异常代码 默认为0 * @throws Think\Exception * @return void */ function E($msg, $code=0) { throw new Think\Exception($msg, $code); } /** * 记录和统计时间(微秒)和内存使用情况 * 使用方法: * * G('begin'); // 记录开始标记位 * // ... 区间运行代码 * G('end'); // 记录结束标签位 * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位 * echo G('begin','end','m'); // 统计区间内存使用情况 * 如果end标记位没有定义,则会自动以当前作为标记位 * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效 * * @param string $start 开始标签 * @param string $end 结束标签 * @param integer|string $dec 小数位或者m * @return mixed */ function G($start,$end='',$dec=4) { static $_info = array(); static $_mem = array(); if(is_float($end)) { // 记录时间 $_info[$start] = $end; }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); } }else{ // 记录时间和内存使用 $_info[$start] = microtime(TRUE); if(MEMORY_LIMIT_ON) $_mem[$start] = memory_get_usage(); } return null; } /** * 获取和设置语言定义(不区分大小写) * @param string|array $name 语言变量 * @param mixed $value 语言值或者变量 * @return mixed */ function L($name=null, $value=null) { static $_lang = array(); // 空参数返回所有定义 if (empty($name)) return $_lang; // 判断语言获取(或设置) // 若不存在,直接返回全大写$name 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)) $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER)); return null; } /** * 添加和获取页面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 */ function compile($filename) { $content = php_strip_whitespace($filename); $content = trim(substr($content, 5)); // 替换预编译指令 $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.'}'; } /** * 获取模版文件 格式 资源://模块@主题/控制器/操作 * @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'); } /** * 获取输入参数 支持过滤和默认值 * 使用方法: * * I('id',0); 获取id参数 自动判断get或者post * I('post.name','','htmlspecialchars'); 获取$_POST['name'] * I('get.'); 获取$_GET * * @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')){ // 默认强制转换为字符串 $type = 's'; } if(strpos($name,'.')) { // 指定参数来源 list($method,$name) = explode('.',$name,2); }else{ // 默认为自动判断 $method = 'param'; } 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; 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; case 'path' : $input = array(); if(!empty($_SERVER['PATH_INFO'])){ $depr = C('URL_PATHINFO_DEPR'); $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; } 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); // 参数过滤 } } }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; } } }else{ // 变量默认值 $data = isset($default)?$default:null; } is_array($data) && array_walk_recursive($data,'think_filter'); return $data; } 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; } /** * 设置和获取统计数据 * 使用方法: * * N('db',1); // 记录数据库操作次数 * N('read',1); // 记录读取次数 * echo N('db'); // 获取当前页面数据库的所有操作次数 * echo N('read'); // 获取当前页面读取次数 * * @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; } if (empty($step)){ return $_num[$key]; }else{ $_num[$key] = $_num[$key] + (int)$step; } if(false !== $save){ // 保存结果 S('N_'.$key,$_num[$key],$save); } return null; } /** * 字符串命名风格转换 * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 * @param string $name 字符串 * @param integer $type 转换类型 * @return string */ function parse_name($name, $type=0) { if ($type) { return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function($match){return strtoupper($match[1]);}, $name)); } else { return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); } } /** * 优化的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 */ function 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; } /** * 导入所需的类库 同java的Import 本函数有缓存功能 * @param string $class 类库命名空间字符串 * @param string $baseUrl 起始路径 * @param string $ext 导入的文件扩展名 * @return boolean */ 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) != '/') $baseUrl .= '/'; $classfile = $baseUrl . $class . $ext; if (!class_exists(basename($class),false)) { // 如果类不存在 则导入类库文件 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); } /** * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的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); } /** * 实例化模型类 格式 [资源://][模块/]模型 * @param string $name 资源地址 * @param string $layer 模型层名称 * @return Think\Model */ function D($name='',$layer='') { if(empty($name)) return new Think\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; } function DM($name='', $tablePrefix='tab_',$connection='') { return M($name, $tablePrefix,$connection); } /** * 实例化一个没有模型文件的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'; } $guid = (is_array($connection)?implode('',$connection):$connection).$tablePrefix . $name . '_' . $class; if (!isset($_model[$guid])) $_model[$guid] = new $class($name,$tablePrefix,$connection); return $_model[$guid]; } /** * 实例化模型,判断是否是子站,如果是,自动接入子站 * * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User * @param string $tablePrefix 表前缀 * @param boolean $is_subsiteTable 是否强制使用子站 * @return Think\Model */ function SM($name='', $tablePrefix='sys_',$is_subsiteTable=false) { if(empty($name)){ if(IS_SUBSITE){ return M($name, $tablePrefix,SUBSITE_DB); } }else{ $tableName = strtolower($tablePrefix.unCamelize($name)); if(is_subsiteTable($tableName) || $is_subsiteTable){ return M($name, $tablePrefix,SUBSITE_DB); } } return M($name, $tablePrefix); } /** * 解析资源地址并导入类库文件 * 例如 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 = ''; } 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; } /** * 用于实例化访问控制器 * @param string $name 控制器名 * @param string $path 控制器命名空间(路径) * @return Think\Controller|false */ function controller($name,$path=''){ $layer = C('DEFAULT_C_LAYER'); if(!C('APP_USE_NAMESPACE')){ $class = parse_name($name, 1).$layer; import(MODULE_NAME.'/'.$layer.'/'.$class); }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; } } /** * 实例化多层控制器 格式:[资源://][模块/]控制器 * @param string $name 资源地址 * @param string $layer 控制层名称 * @param integer $level 控制器层次 * @return Think\Controller|false */ function A($name,$layer='',$level=0) { static $_action = array(); $layer = $layer? : C('DEFAULT_C_LAYER'); $level = $level? : ($layer == C('DEFAULT_C_LAYER')?C('CONTROLLER_LEVEL'):1); if(isset($_action[$name.$layer])) return $_action[$name.$layer]; $class = parse_res_name($name,$layer,$level); if(class_exists($class)) { $action = new $class(); $_action[$name.$layer] = $action; return $action; }else { return false; } } /** * 远程调用控制器的操作方法 URL 参数格式 [资源://][模块/]控制器/操作 * @param string $url 调用地址 * @param string|array $vars 调用参数 支持字符串和数组 * @param string $layer 要调用的控制层名称 * @return mixed */ function R($url,$vars=array(),$layer='') { $info = pathinfo($url); $action = $info['basename']; $module = $info['dirname']; $class = A($module,$layer); 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; } } /** * 处理标签扩展 * @param string $tag 标签名称 * @param mixed $params 传入参数 * @return void */ function tag($tag, &$params=NULL) { \Think\Hook::listen($tag,$params); } /** * 执行某个行为 * @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); } /** * 去除代码中的空白和注释 * @param string $content 代码内容 * @return string */ function strip_whitespace($content) { $stripStr = ''; //分析php源码 $tokens = token_get_all($content); $last_space = false; for ($i = 0, $j = count($tokens); $i < $j; $i++) { 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 .= "<<'; } else { $output = $label . print_r($var, true); } } else { ob_start(); var_dump($var); $output = ob_get_clean(); if (!extension_loaded('xdebug')) { $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output); $output = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'; } } if ($echo) { echo($output); return null; }else return $output; } /** * 设置当前页面的布局 * @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); } } /** * URL组装 支持不同URL模式 * @param string $url URL表达式,格式:'[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...' * @param string|array $vars 传入的参数,支持数组和字符串 * @param string|boolean $suffix 伪静态后缀,默认为true表示获取配置值 * @param boolean $domain 是否显示域名 * @return string */ function U($url='',$vars='',$suffix=true,$domain=false) { // 解析URL $info = parse_url($url); $url = !empty($info['path'])?$info['path']:ACTION_NAME; if(isset($info['fragment'])) { // 解析锚点 $anchor = $info['fragment']; 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); } // 解析子域名 if(isset($host)) { $domain = $host.(strpos($host,'.')?'':strstr($_SERVER['HTTP_HOST'],'.')); }elseif($domain===true){ $domain = $_SERVER['HTTP_HOST']; if(C('APP_SUB_DOMAIN_DEPLOY') ) { // 开启子域名部署 $domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.'); // '子域名'=>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'); $urlCase = C('URL_CASE_INSENSITIVE'); 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'); $varController = C('VAR_CONTROLLER'); $varAction = C('VAR_ACTION'); $var[$varAction] = !empty($path)?array_pop($path):ACTION_NAME; $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')) { if($controller = array_search(strtolower($var[$varController]),$maps)){ $var[$varController] = $controller; } } if($urlCase) { $var[$varController] = parse_name($var[$varController]); } $module = ''; if(!empty($path)) { $var[$varModule] = implode($depr,$path); }else{ if(C('MULTI_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; } /** * 渲染输出Widget * @param string $name Widget名称 * @param array $data 传入的参数 * @return void */ function W($name, $data=array()) { return R($name,$data,'Widget'); } /** * 判断是否SSL协议 * @return boolean */ 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 = ""; if ($time != 0) $str .= $msg; exit($str); } } /** * 缓存管理 * @param mixed $name 缓存名称,如果为数组表示进行缓存设置 * @param mixed $value 缓存值 * @param mixed $options 缓存参数 * @return mixed */ function S($name,$value='',$options=null) { static $cache = ''; if(is_array($options)){ // 缓存操作的同时初始化 $type = isset($options['type'])?$options['type']:''; $cache = Think\Cache::getInstance($type,$options); }elseif(is_array($name)) { // 缓存初始化 $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); } } /** * 快速文件数据读取和保存 针对简单类型数据 字符串、数组 * @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'; 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])) return $_cache[$name]; if (Think\Storage::has($filename,'F')){ $value = unserialize(Think\Storage::read($filename,'F')); $_cache[$name] = $value; } else { $value = false; } return $value; } /** * 根据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); } /** * 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 .= "<{$root}{$attr}>"; $xml .= data_to_xml($data, $item, $id); $xml .= ""; 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 .= ""; } return $xml; } /** * session管理函数 * @param string|array $name session名称 如果为数组则表示进行session设置 * @param mixed $value session值 * @return mixed */ function session($name='',$value='') { $prefix = C('SESSION_PREFIX'); if(is_array($name)) { // session初始化 在session_start 之前调用 if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']); if(C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])){ session_id($_REQUEST[C('VAR_SESSION_ID')]); }elseif(isset($name['id'])) { session_id($name['id']); } if('common' == APP_MODE){ // 其它模式可能不支持 ini_set('session.auto_start', 0); } if(isset($name['name'])) session_name($name['name']); if(isset($name['path'])) session_save_path($name['path']); if(isset($name['domain'])) ini_set('session.cookie_domain', $name['domain']); if (C('SESSION_COOKIE_PATH')) { ini_set('session.cookie_path', C('SESSION_COOKIE_PATH')); } if(isset($name['expire'])) { ini_set('session.gc_maxlifetime', $name['expire']); ini_set('session.cookie_lifetime', 99999999); } 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'); $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(); }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]); } }elseif(is_null($name)){ // 清空session 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; } /** * 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); $config = array_merge($config, array_change_key_case($option)); } if(!empty($config['httponly'])){ 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; } /** * 加载动态扩展文件 * @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)); } } } } /** * 获取客户端IP地址 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @param boolean $adv 是否进行高级模式获取(有可能被伪装) * @return mixed */ function get_client_ip($type = 0, $adv=true) { $type = $type ? 1 : 0; static $ip = NULL; if ($ip !== NULL) return $ip[$type]; if($adv){ if (isset($_SERVER['HTTP_X_HWWAF_REAL_IP'])) { $ip = $_SERVER['HTTP_X_HWWAF_REAL_IP']; } elseif (isset($_SERVER['HTTP_X_REAL_IP'])) { $ip = $_SERVER['HTTP_X_REAL_IP']; } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $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 = $long ? array($ip, $long) : array('0.0.0.0', 0); return $ip[$type]; } /** * 发送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)); }