|
|
<?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 系统函数库
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* 获取和设置配置参数 支持批量定义
|
|
|
* @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);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 记录和统计时间(微秒)和内存使用情况
|
|
|
* 使用方法:
|
|
|
* <code>
|
|
|
* G('begin'); // 记录开始标记位
|
|
|
* // ... 区间运行代码
|
|
|
* G('end'); // 记录结束标签位
|
|
|
* echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位
|
|
|
* echo G('begin','end','m'); // 统计区间内存使用情况
|
|
|
* 如果end标记位没有定义,则会自动以当前作为标记位
|
|
|
* 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效
|
|
|
* </code>
|
|
|
* @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');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取输入参数 支持过滤和默认值
|
|
|
* 使用方法:
|
|
|
* <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')){ // 默认强制转换为字符串
|
|
|
$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;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 设置和获取统计数据
|
|
|
* 使用方法:
|
|
|
* <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;
|
|
|
}
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 实例化一个没有模型文件的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];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 解析资源地址并导入类库文件
|
|
|
* 例如 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 .= "<<<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;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 自定义异常处理
|
|
|
* @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); // 异常类型不存在则输出错误信息字串
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 浏览器友好的变量输出
|
|
|
* @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')) {
|
|
|
$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')) {
|
|
|
$output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
|
|
|
$output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
|
|
|
}
|
|
|
}
|
|
|
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 = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
|
|
|
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 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;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 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(isset($name['expire'])) {
|
|
|
ini_set('session.gc_maxlifetime', $name['expire']);
|
|
|
ini_set('session.cookie_lifetime', $name['expire']);
|
|
|
}
|
|
|
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=false) {
|
|
|
$type = $type ? 1 : 0;
|
|
|
static $ip = NULL;
|
|
|
if ($ip !== NULL) return $ip[$type];
|
|
|
if($adv){
|
|
|
if (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));
|
|
|
}
|