diff --git a/ThinkPHP/Common/common.php b/ThinkPHP/Common/common.php new file mode 100644 index 0000000..770bbc6 --- /dev/null +++ b/ThinkPHP/Common/common.php @@ -0,0 +1,757 @@ + +// +---------------------------------------------------------------------- + +/** + * Think 基础函数库 + * @category Think + * @package Common + * @author liu21st + */ + +/** + * 获取模版文件 格式 项目://分组@主题/模块/操作 + * @param string $name 模版资源地址 + * @param string $layer 视图层(目录)名称 + * @return string + */ +function T($template='',$layer=''){ + if(is_file($template)) { + return $template; + } + // 解析模版资源地址 + if(false === strpos($template,'://')){ + $template = APP_NAME.'://'.str_replace(':', '/',$template); + } + $info = parse_url($template); + $file = $info['host'].(isset($info['path'])?$info['path']:''); + $group = isset($info['user'])?$info['user'].'/':(defined('GROUP_NAME')?GROUP_NAME.'/':''); + $app = $info['scheme']; + $layer = $layer?$layer:C('DEFAULT_V_LAYER'); + + // 获取当前主题的模版路径 + if(($list = C('EXTEND_GROUP_LIST')) && isset($list[$app])){ // 扩展分组 + $baseUrl = $list[$app].'/'.$group.$layer.'/'; + }elseif(1==C('APP_GROUP_MODE')){ // 独立分组模式 + $baseUrl = dirname(BASE_LIB_PATH).'/'.$group.$layer.'/'; + }else{ + $baseUrl = TMPL_PATH.$group; + } + + // 分析模板文件规则 + if('' == $file) { + // 如果模板文件名为空 按照默认规则定位 + $file = MODULE_NAME . C('TMPL_FILE_DEPR') . ACTION_NAME; + }elseif(false === strpos($file, '/')){ + $file = MODULE_NAME . C('TMPL_FILE_DEPR') . $file; + } + return $baseUrl.$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 参数过滤方法 + * @return mixed + */ +function I($name,$default='',$filter=null) { + 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' : parse_str(file_get_contents('php://input'), $input);break; + case 'param' : + switch($_SERVER['REQUEST_METHOD']) { + case 'POST': + $input = $_POST; + break; + case 'PUT': + parse_str(file_get_contents('php://input'), $input); + break; + default: + $input = $_GET; + } + if(C('VAR_URL_PARAMS') && isset($_GET[C('VAR_URL_PARAMS')])){ + $input = array_merge($input,$_GET[C('VAR_URL_PARAMS')]); + } + 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; + default: + return NULL; + } + // 全局过滤 + // array_walk_recursive($input,'filter_exp'); + if(C('VAR_FILTERS')) { + $_filters = explode(',',C('VAR_FILTERS')); + foreach($_filters as $_filter){ + // 全局参数过滤 + array_walk_recursive($input,$_filter); + } + } + if(empty($name)) { // 获取全部变量 + $data = $input; + $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); + if($filters) { + $filters = explode(',',$filters); + foreach($filters as $filter){ + $data = array_map($filter,$data); // 参数过滤 + } + } + }elseif(isset($input[$name])) { // 取值操作 + $data = $input[$name]; + $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); + if($filters) { + $filters = explode(',',$filters); + foreach($filters as $filter){ + if(function_exists($filter)) { + $data = is_array($data)?array_map($filter,$data):$filter($data); // 参数过滤 + }else{ + $data = filter_var($data,is_int($filter)?$filter:filter_id($filter)); + if(false === $data) { + return isset($default)?$default:NULL; + } + } + } + } + }else{ // 变量默认值 + $data = isset($default)?$default:NULL; + } + return $data; +} + +/** + * 记录和统计时间(微秒)和内存使用情况 + * 使用方法: + * + * 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(); + } +} + +/** + * 设置和获取统计数据 + * 使用方法: + * + * N('db',1); // 记录数据库操作次数 + * N('read',1); // 记录读取次数 + * echo N('db'); // 获取当前页面数据库的所有操作次数 + * echo N('read'); // 获取当前页面读取次数 + * + * @param string $key 标识位置 + * @param integer $step 步进值 + * @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); + } +} + +/** + * 字符串命名风格转换 + * 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("/_([a-zA-Z])/e", "strtoupper('\\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 array $array 文件数组 + * @param boolean $return 加载成功后是否返回 + * @return boolean + */ +function require_array($array,$return=false){ + foreach ($array as $file){ + if (require_cache($file) && $return) return true; + } + if($return) return false; +} + +/** + * 区分大小写的文件存在判断 + * @param string $filename 文件地址 + * @return boolean + */ +function file_exists_case($filename) { + if (is_file($filename)) { + if (IS_WIN && C('APP_FILE_CASE')) { + 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='.class.php') { + static $_file = array(); + $class = str_replace(array('.', '#'), array('/', '.'), $class); + if ('' === $baseUrl && false === strpos($class, '/')) { + // 检查别名导入 + return alias_import($class); + } + if (isset($_file[$class . $baseUrl])) + return true; + else + $_file[$class . $baseUrl] = true; + $class_strut = explode('/', $class); + if (empty($baseUrl)) { + $libPath = defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH; + if ('@' == $class_strut[0] || APP_NAME == $class_strut[0]) { + //加载当前项目应用类库 + $baseUrl = dirname($libPath); + $class = substr_replace($class, basename($libPath).'/', 0, strlen($class_strut[0]) + 1); + }elseif ('think' == strtolower($class_strut[0])){ // think 官方基类库 + $baseUrl = CORE_PATH; + $class = substr($class,6); + }elseif (in_array(strtolower($class_strut[0]), array('org', 'com'))) { + // org 第三方公共类库 com 企业公共类库 + $baseUrl = LIBRARY_PATH; + }else { // 加载其他项目应用类库 + $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1); + $baseUrl = APP_PATH . '../' . $class_strut[0] . '/'.basename($libPath).'/'; + } + } + if (substr($baseUrl, -1) != '/') + $baseUrl .= '/'; + $classfile = $baseUrl . $class . $ext; + if (!class_exists(basename($class),false)) { + // 如果类不存在 则导入类库文件 + return require_cache($classfile); + } +} + +/** + * 基于命名空间方式导入函数库 + * 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 = COMMON_PATH; + $name = substr($name, 2); + } else { + //加载ThinkPHP 系统函数库 + $baseUrl = EXTEND_PATH . 'Function/'; + } + } + 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|array $alias 类库别名 + * @param string $classfile 对应类库 + * @return boolean + */ +function alias_import($alias, $classfile='') { + static $_alias = array(); + if (is_string($alias)) { + if(isset($_alias[$alias])) { + return require_cache($_alias[$alias]); + }elseif ('' !== $classfile) { + // 定义别名导入 + $_alias[$alias] = $classfile; + return; + } + }elseif (is_array($alias)) { + $_alias = array_merge($_alias,$alias); + return; + } + return false; +} + +/** + * D函数用于实例化Model 格式 项目://分组/模块 + * @param string $name Model资源地址 + * @param string $layer 业务层名称 + * @return Model + */ +function D($name='',$layer='') { + if(empty($name)) return new Model; + static $_model = array(); + $layer = $layer?$layer:C('DEFAULT_M_LAYER'); + if(strpos($name,'://')) {// 指定项目 + list($app) = explode('://',$name); + $name = str_replace('://','/'.$layer.'/',$name); + }else{ + $app = C('DEFAULT_APP'); + $name = $app.'/'.$layer.'/'.$name; + } + if(isset($_model[$name])) return $_model[$name]; + $path = explode('/',$name); + if($list = C('EXTEND_GROUP_LIST') && isset($list[$app])){ // 扩展分组 + $baseUrl = $list[$app]; + import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); + }elseif(count($path)>3 && 1 == C('APP_GROUP_MODE')) { // 独立分组 + $baseUrl = $path[0]== '@' ? dirname(BASE_LIB_PATH) : APP_PATH.'../'.$path[0].'/'.C('APP_GROUP_PATH').'/'; + import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); + }else{ + import($name.$layer); + } + $class = basename($name.$layer); + if(class_exists($class)) { + $model = new $class(basename($name)); + }else { + $model = new Model(basename($name)); + } + $_model[$name] = $model; + return $model; +} + +/** + * M函数用于实例化一个没有模型文件的Model + * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User + * @param string $tablePrefix 表前缀 + * @param mixed $connection 数据库连接信息 + * @return Model + */ +function M($name='', $tablePrefix='',$connection='') { + static $_model = array(); + if(strpos($name,':')) { + list($class,$name) = explode(':',$name); + }else{ + $class = 'Model'; + } + $guid = $tablePrefix . $name . '_' . $class; + if (!isset($_model[$guid])) + $_model[$guid] = new $class($name,$tablePrefix,$connection); + return $_model[$guid]; +} + +/** + * A函数用于实例化Action 格式:[项目://][分组/]模块 + * @param string $name Action资源地址 + * @param string $layer 控制层名称 + * @param boolean $common 是否公共目录 + * @return Action|false + */ +function A($name,$layer='',$common=false) { + static $_action = array(); + $layer = $layer?$layer:C('DEFAULT_C_LAYER'); + if(strpos($name,'://')) {// 指定项目 + list($app) = explode('://',$name); + $name = str_replace('://','/'.$layer.'/',$name); + }else{ + $app = '@'; + $name = '@/'.$layer.'/'.$name; + } + if(isset($_action[$name])) return $_action[$name]; + $path = explode('/',$name); + if($list = C('EXTEND_GROUP_LIST') && isset($list[$app])){ // 扩展分组 + $baseUrl = $list[$app]; + import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); + }elseif(count($path)>3 && 1 == C('APP_GROUP_MODE')) { // 独立分组 + $baseUrl = $path[0]== '@' ? dirname(BASE_LIB_PATH) : APP_PATH.'../'.$path[0].'/'.C('APP_GROUP_PATH').'/'; + import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); + }elseif($common) { // 加载公共类库目录 + import(str_replace('@/','',$name).$layer,LIB_PATH); + }else{ + import($name.$layer); + } + $class = basename($name.$layer); + if(class_exists($class,false)) { + $action = new $class(); + $_action[$name] = $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|array $name 语言变量 + * @param string $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; + $_lang[$name] = $value; // 语言定义 + return; + } + // 批量定义 + if (is_array($name)) + $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER)); + return; +} + +/** + * 获取和设置配置参数 支持批量定义 + * @param string|array $name 配置变量 + * @param mixed $value 配置值 + * @return mixed + */ +function C($name=null, $value=null) { + static $_config = array(); + // 无参数时获取所有 + if (empty($name)) { + if(!empty($value) && $array = S('c_'.$value)) { + $_config = array_merge($_config, array_change_key_case($array)); + } + return $_config; + } + // 优先执行设置获取或赋值 + if (is_string($name)) { + if (!strpos($name, '.')) { + $name = strtolower($name); + if (is_null($value)) + return isset($_config[$name]) ? $_config[$name] : null; + $_config[$name] = $value; + return; + } + // 二维数组设置和获取支持 + $name = explode('.', $name); + $name[0] = strtolower($name[0]); + if (is_null($value)) + return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null; + $_config[$name[0]][$name[1]] = $value; + return; + } + // 批量设置 + if (is_array($name)){ + $_config = array_merge($_config, array_change_key_case($name)); + if(!empty($value)) {// 保存配置值 + S('c_'.$value,$_config); + } + return; + } + return null; // 避免非法参数 +} + +/** + * 处理标签扩展 + * @param string $tag 标签名称 + * @param mixed $params 传入参数 + * @return mixed + */ +function tag($tag, &$params=NULL) { + // 系统标签扩展 + $extends = C('extends.' . $tag); + // 应用标签扩展 + $tags = C('tags.' . $tag); + if (!empty($tags)) { + if(empty($tags['_overlay']) && !empty($extends)) { // 合并扩展 + $tags = array_unique(array_merge($extends,$tags)); + }elseif(isset($tags['_overlay'])){ // 通过设置 '_overlay'=>1 覆盖系统标签 + unset($tags['_overlay']); + } + }elseif(!empty($extends)) { + $tags = $extends; + } + if($tags) { + if(APP_DEBUG) { + G($tag.'Start'); + trace('[ '.$tag.' ] --START--','','INFO'); + } + // 执行扩展 + foreach ($tags as $key=>$name) { + if(!is_int($key)) { // 指定行为类的完整路径 用于模式扩展 + $name = $key; + } + B($name, $params); + } + if(APP_DEBUG) { // 记录行为的执行日志 + trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO'); + } + }else{ // 未执行任何行为 返回false + return false; + } +} + +/** + * 动态添加行为扩展到某个标签 + * @param string $tag 标签名称 + * @param string $behavior 行为名称 + * @param string $path 行为路径 + * @return void + */ +function add_tag_behavior($tag,$behavior,$path='') { + $array = C('tags.'.$tag); + if(!$array) { + $array = array(); + } + if($path) { + $array[$behavior] = $path; + }else{ + $array[] = $behavior; + } + C('tags.'.$tag,$array); +} + +/** + * 执行某个行为 + * @param string $name 行为名称 + * @param Mixed $params 传入的参数 + * @return void + */ +function B($name, &$params=NULL) { + if(strpos($name,'/')){ + list($name,$method) = explode('/',$name); + }else{ + $method = 'run'; + } + $class = $name.'Behavior'; + if(APP_DEBUG) { + G('behaviorStart'); + } + $behavior = new $class(); + $behavior->$method($params); + if(APP_DEBUG) { // 记录行为的执行日志 + G('behaviorEnd'); + trace($name.' Behavior ::'.$method.' [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO'); + } +} + +/** + * 去除代码中的空白和注释 + * @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 .= "<<' == substr($content, -2)) + $content = substr($content, 0, -2); + return $content; +} + +// 根据数组生成常量定义 +function array_define($array,$check=true) { + $content = "\n"; + foreach ($array as $key => $val) { + $key = strtoupper($key); + if($check) $content .= 'defined(\'' . $key . '\') or '; + if (is_int($val) || is_float($val)) { + $content .= "define('" . $key . "'," . $val . ');'; + } elseif (is_bool($val)) { + $val = ($val) ? 'true' : 'false'; + $content .= "define('" . $key . "'," . $val . ');'; + } elseif (is_string($val)) { + $content .= "define('" . $key . "','" . addslashes($val) . "');"; + } + $content .= "\n"; + } + return $content; +} +//[/RUNTIME] + +/** + * 添加和获取页面Trace记录 + * @param string $value 变量 + * @param string $label 标签 + * @param string $level 日志级别 + * @param boolean $record 是否记录日志 + * @return void + */ +function trace($value='[think]',$label='',$level='DEBUG',$record=false) { + static $_trace = array(); + if('[think]' === $value){ // 获取trace信息 + return $_trace; + }else{ + $info = ($label?$label.':':'').print_r($value,true); + if('ERR' == $level && C('TRACE_EXCEPTION')) {// 抛出异常 + throw_exception($info); + } + $level = strtoupper($level); + if(!isset($_trace[$level])) { + $_trace[$level] = array(); + } + $_trace[$level][] = $info; + if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE') || $record) { + Log::record($info,$level,$record); + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Common/functions.php b/ThinkPHP/Common/functions.php new file mode 100644 index 0000000..009fdfc --- /dev/null +++ b/ThinkPHP/Common/functions.php @@ -0,0 +1,813 @@ + +// +---------------------------------------------------------------------- + +/** + * Think 标准模式公共函数库 + * @category Think + * @package Common + * @author liu21st + */ + +/** + * 错误输出 + * @param mixed $error 错误 + * @return void + */ +function halt($error) { + $e = array(); + if (APP_DEBUG) { + //调试模式下输出错误信息 + if (!is_array($error)) { + $trace = debug_backtrace(); + $e['message'] = $error; + $e['file'] = $trace[0]['file']; + $e['line'] = $trace[0]['line']; + ob_start(); + debug_print_backtrace(); + $e['trace'] = ob_get_clean(); + } else { + $e = $error; + } + } else { + //否则定向到错误页面 + $error_page = C('ERROR_PAGE'); + if (!empty($error_page)) { + redirect($error_page); + } else { + if (C('SHOW_ERROR_MSG')) + $e['message'] = is_array($error) ? $error['message'] : $error; + else + $e['message'] = C('ERROR_MESSAGE'); + } + } + // 包含异常页面模板 + include C('TMPL_EXCEPTION_FILE'); + exit; +} + +/** + * 自定义异常处理 + * @param string $msg 异常消息 + * @param string $type 异常类型 默认为ThinkException + * @param integer $code 异常代码 默认为0 + * @return void + */ +function throw_exception($msg, $type='ThinkException', $code=0) { + if (class_exists($type, false)) + throw new $type($msg, $code); + else + 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 = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'; + } 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; +} + +/** + * 404处理 + * 调试模式会抛异常 + * 部署模式下面传入url参数可以指定跳转页面,否则发送404信息 + * @param string $msg 提示信息 + * @param string $url 跳转URL地址 + * @return void + */ +function _404($msg='',$url='') { + APP_DEBUG && throw_exception($msg); + if($msg && C('LOG_EXCEPTION_RECORD')) Log::write($msg); + if(empty($url) && C('URL_404_REDIRECT')) { + $url = C('URL_404_REDIRECT'); + } + if($url) { + redirect($url); + }else{ + send_http_status(404); + exit; + } +} + +/** + * 设置当前页面的布局 + * @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 $suffix 伪静态后缀,默认为true表示获取配置值 + * @param boolean $redirect 是否跳转,如果设置为true则表示跳转到该URL地址 + * @param boolean $domain 是否显示域名 + * @return string + */ +function U($url='',$vars='',$suffix=true,$redirect=false,$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) { + if(false === strpos($key,'*') && 0=== strpos($url,$rule[0])) { + $domain = $key.strstr($domain,'.'); // 生成对应子域名 + $url = substr_replace($url,'',0,strlen($rule[0])); + 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'); + 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(); + $var[C('VAR_ACTION')] = !empty($path)?array_pop($path):ACTION_NAME; + $var[C('VAR_MODULE')] = !empty($path)?array_pop($path):MODULE_NAME; + if($maps = C('URL_ACTION_MAP')) { + if(isset($maps[strtolower($var[C('VAR_MODULE')])])) { + $maps = $maps[strtolower($var[C('VAR_MODULE')])]; + if($action = array_search(strtolower($var[C('VAR_ACTION')]),$maps)){ + $var[C('VAR_ACTION')] = $action; + } + } + } + if($maps = C('URL_MODULE_MAP')) { + if($module = array_search(strtolower($var[C('VAR_MODULE')]),$maps)){ + $var[C('VAR_MODULE')] = $module; + } + } + if(C('URL_CASE_INSENSITIVE')) { + $var[C('VAR_MODULE')] = parse_name($var[C('VAR_MODULE')]); + } + if(!C('APP_SUB_DOMAIN_DEPLOY') && C('APP_GROUP_LIST')) { + if(!empty($path)) { + $group = array_pop($path); + $var[C('VAR_GROUP')] = $group; + }else{ + if(GROUP_NAME != C('DEFAULT_GROUP')) { + $var[C('VAR_GROUP')]= GROUP_NAME; + } + } + if(C('URL_CASE_INSENSITIVE') && isset($var[C('VAR_GROUP')])) { + $var[C('VAR_GROUP')] = strtolower($var[C('VAR_GROUP')]); + } + } + } + } + + if(C('URL_MODEL') == 0) { // 普通模式URL转换 + $url = __APP__.'?'.http_build_query(array_reverse($var)); + if(!empty($vars)) { + $vars = urldecode(http_build_query($vars)); + $url .= '&'.$vars; + } + }else{ // PATHINFO模式或者兼容URL模式 + if(isset($route)) { + $url = __APP__.'/'.rtrim($url,$depr); + }else{ + $url = __APP__.'/'.implode($depr,array_reverse($var)); + } + 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; + } + if($redirect) // 直接跳转URL + redirect($url); + else + return $url; +} + +/** + * 渲染输出Widget + * @param string $name Widget名称 + * @param array $data 传入的参数 + * @param boolean $return 是否返回内容 + * @param string $path Widget所在路径 + * @return void + */ +function W($name, $data=array(), $return=false,$path='') { + $class = $name . 'Widget'; + $path = empty($path) ? BASE_LIB_PATH : $path; + require_cache($path . 'Widget/' . $class . '.class.php'); + if (!class_exists($class)) + throw_exception(L('_CLASS_NOT_EXIST_') . ':' . $class); + $widget = Think::instance($class); + $content = $widget->render($data); + if ($return) + return $content; + else + echo $content; +} + +/** + * 过滤器方法 引用传值 + * @param string $name 过滤器名称 + * @param string $content 要过滤的内容 + * @return void + */ +function filter($name, &$content) { + $class = $name . 'Filter'; + require_cache(BASE_LIB_PATH . 'Filter/' . $class . '.class.php'); + $filter = new $class(); + $content = $filter->run($content); +} + +/** + * 判断是否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) && empty($cache)){ + // 缓存操作的同时初始化 + $type = isset($options['type'])?$options['type']:''; + $cache = Cache::getInstance($type,$options); + }elseif(is_array($name)) { // 缓存初始化 + $type = isset($name['type'])?$name['type']:''; + $cache = Cache::getInstance($type,$name); + return $cache; + }elseif(empty($cache)) { // 自动初始化 + $cache = 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); + } +} +// S方法的别名 已经废除 不再建议使用 +function cache($name,$value='',$options=null){ + return S($name,$value,$options); +} + +/** + * 快速文件数据读取和保存 针对简单类型数据 字符串、数组 + * @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)) { + // 删除缓存 + return false !== strpos($name,'*')?array_map("unlink", glob($filename)):unlink($filename); + } else { + // 缓存数据 + $dir = dirname($filename); + // 目录不存在则创建 + if (!is_dir($dir)) + mkdir($dir,0755,true); + $_cache[$name] = $value; + return file_put_contents($filename, strip_whitespace("")); + } + } + if (isset($_cache[$name])) + return $_cache[$name]; + // 获取缓存数据 + if (is_file($filename)) { + $value = include $filename; + $_cache[$name] = $value; + } else { + $value = false; + } + return $value; +} + +/** + * 取得对象实例 支持调用类的静态方法 + * @param string $name 类名 + * @param string $method 方法名,如果为空则返回实例化对象 + * @param array $args 调用参数 + * @return object + */ +function get_instance_of($name, $method='', $args=array()) { + static $_instance = array(); + $identify = empty($args) ? $name . $method : $name . $method . to_guid_string($args); + if (!isset($_instance[$identify])) { + if (class_exists($name)) { + $o = new $name(); + if (method_exists($o, $method)) { + if (!empty($args)) { + $_instance[$identify] = call_user_func_array(array(&$o, $method), $args); + } else { + $_instance[$identify] = $o->$method(); + } + } + else + $_instance[$identify] = $o; + } + else + halt(L('_CLASS_NOT_EXIST_') . ':' . $name); + } + return $_instance[$identify]; +} + +/** + * 根据PHP各种类型变量生成唯一标识号 + * @param mixed $mix 变量 + * @return string + */ +function to_guid_string($mix) { + if (is_object($mix) && function_exists('spl_object_hash')) { + 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']); + } + 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']); + 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驱动 + $class = 'Session'. ucwords(strtolower(C('SESSION_TYPE'))); + // 检查驱动类 + if(require_cache(EXTEND_PATH.'Driver/Session/'.$class.'.class.php')) { + $hander = new $class(); + $hander->execute(); + }else { + // 类没有定义 + throw_exception(L('_CLASS_NOT_EXIST_').': ' . $class); + } + } + // 启动session + if(C('SESSION_AUTO_START')) session_start(); + }elseif('' === $value){ + if(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($prefix){ + unset($_SESSION[$prefix][$name]); + }else{ + unset($_SESSION[$name]); + } + }else{ // 设置session + if($prefix){ + if (!is_array($_SESSION[$prefix])) { + $_SESSION[$prefix] = array(); + } + $_SESSION[$prefix][$name] = $value; + }else{ + $_SESSION[$name] = $value; + } + } +} + +/** + * Cookie 设置、获取、删除 + * @param string $name cookie名称 + * @param mixed $value cookie值 + * @param mixed $options 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 有效域名 + ); + // 参数设置(会覆盖黙认设置) + 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)); + } + // 清除指定前缀的所有cookie + if (is_null($name)) { + if (empty($_COOKIE)) + return; + // 要删除的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']); + unset($_COOKIE[$key]); + } + } + } + return; + } + $name = $config['prefix'] . $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']); + 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']); + $_COOKIE[$name] = $value; + } + } +} + +/** + * 加载动态扩展文件 + * @return void + */ +function load_ext_file() { + // 加载自定义外部文件 + if(C('LOAD_EXT_FILE')) { + $files = explode(',',C('LOAD_EXT_FILE')); + foreach ($files as $file){ + $file = COMMON_PATH.$file.'.php'; + if(is_file($file)) include $file; + } + } + // 加载自定义的动态配置文件 + if(C('LOAD_EXT_CONFIG')) { + $configs = C('LOAD_EXT_CONFIG'); + if(is_string($configs)) $configs = explode(',',$configs); + foreach ($configs as $key=>$config){ + $file = CONF_PATH.$config.'.php'; + if(is_file($file)) { + is_numeric($key)?C(include $file):C($key,include $file); + } + } + } +} + +/** + * 获取客户端IP地址 + * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 + * @return mixed + */ +function get_client_ip($type = 0) { + $type = $type ? 1 : 0; + static $ip = NULL; + if ($ip !== NULL) return $ip[$type]; + 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']; + } + // 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 filter_exp(&$value){ + if (in_array(strtolower($value),array('exp','or'))){ + $value .= ' '; + } +} diff --git a/ThinkPHP/Common/runtime.php b/ThinkPHP/Common/runtime.php new file mode 100644 index 0000000..06dbb1a --- /dev/null +++ b/ThinkPHP/Common/runtime.php @@ -0,0 +1,242 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 运行时文件 编译后不再加载 + * @category Think + * @package Common + * @author liu21st + */ +defined('THINK_PATH') or exit(); +if(version_compare(PHP_VERSION,'5.2.0','<')) die('require PHP > 5.2.0 !'); + +// 版本信息 +define('THINK_VERSION', '3.1.3'); + +// 系统信息 +if(version_compare(PHP_VERSION,'5.4.0','<')) { + ini_set('magic_quotes_runtime',0); + define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()?True:False); +}else{ + define('MAGIC_QUOTES_GPC',false); +} +define('IS_CGI',substr(PHP_SAPI, 0,3)=='cgi' ? 1 : 0 ); +define('IS_WIN',strstr(PHP_OS, 'WIN') ? 1 : 0 ); +define('IS_CLI',PHP_SAPI=='cli'? 1 : 0); + +// 项目名称 +defined('APP_NAME') or define('APP_NAME', basename(dirname($_SERVER['SCRIPT_FILENAME']))); + +if(!IS_CLI) { + // 当前文件名 + if(!defined('_PHP_FILE_')) { + if(IS_CGI) { + //CGI/FASTCGI模式下 + $_temp = explode('.php',$_SERVER['PHP_SELF']); + define('_PHP_FILE_', rtrim(str_replace($_SERVER['HTTP_HOST'],'',$_temp[0].'.php'),'/')); + }else { + define('_PHP_FILE_', rtrim($_SERVER['SCRIPT_NAME'],'/')); + } + } + if(!defined('__ROOT__')) { + // 网站URL根目录 + if( strtoupper(APP_NAME) == strtoupper(basename(dirname(_PHP_FILE_))) ) { + $_root = dirname(dirname(_PHP_FILE_)); + }else { + $_root = dirname(_PHP_FILE_); + } + define('__ROOT__', (($_root=='/' || $_root=='\\')?'':$_root)); + } + + //支持的URL模式 + define('URL_COMMON', 0); //普通模式 + define('URL_PATHINFO', 1); //PATHINFO模式 + define('URL_REWRITE', 2); //REWRITE模式 + define('URL_COMPAT', 3); // 兼容模式 +} + +// 路径设置 可在入口文件中重新定义 所有路径常量都必须以/ 结尾 +defined('CORE_PATH') or define('CORE_PATH', THINK_PATH.'Lib/'); // 系统核心类库目录 +defined('EXTEND_PATH') or define('EXTEND_PATH', THINK_PATH.'Extend/'); // 系统扩展目录 +defined('MODE_PATH') or define('MODE_PATH', EXTEND_PATH.'Mode/'); // 模式扩展目录 +defined('ENGINE_PATH') or define('ENGINE_PATH', EXTEND_PATH.'Engine/'); // 引擎扩展目录 +defined('VENDOR_PATH') or define('VENDOR_PATH', EXTEND_PATH.'Vendor/'); // 第三方类库目录 +defined('LIBRARY_PATH') or define('LIBRARY_PATH', EXTEND_PATH.'Library/'); // 扩展类库目录 +defined('COMMON_PATH') or define('COMMON_PATH', APP_PATH.'Common/'); // 项目公共目录 +defined('LIB_PATH') or define('LIB_PATH', APP_PATH.'Lib/'); // 项目类库目录 +defined('CONF_PATH') or define('CONF_PATH', APP_PATH.'Conf/'); // 项目配置目录 +defined('LANG_PATH') or define('LANG_PATH', APP_PATH.'Lang/'); // 项目语言包目录 +defined('TMPL_PATH') or define('TMPL_PATH', APP_PATH.'Tpl/'); // 项目模板目录 +defined('HTML_PATH') or define('HTML_PATH', APP_PATH.'Html/'); // 项目静态目录 +defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH.'Logs/'); // 项目日志目录 +defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH.'Temp/'); // 项目缓存目录 +defined('DATA_PATH') or define('DATA_PATH', RUNTIME_PATH.'Data/'); // 项目数据目录 +defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH.'Cache/'); // 项目模板缓存目录 + +// 为了方便导入第三方类库 设置Vendor目录到include_path +set_include_path(get_include_path() . PATH_SEPARATOR . VENDOR_PATH); + +// 加载运行时所需要的文件 并负责自动目录生成 +function load_runtime_file() { + // 加载系统基础函数库 + require THINK_PATH.'Common/common.php'; + // 读取核心文件列表 + $list = array( + CORE_PATH.'Core/Think.class.php', + CORE_PATH.'Core/ThinkException.class.php', // 异常处理类 + CORE_PATH.'Core/Behavior.class.php', + ); + // 加载模式文件列表 + foreach ($list as $key=>$file){ + if(is_file($file)) require_cache($file); + } + // 加载系统类库别名定义 + alias_import(include THINK_PATH.'Conf/alias.php'); + + // 检查项目目录结构 如果不存在则自动创建 + if(!is_dir(LIB_PATH)) { + // 创建项目目录结构 + build_app_dir(); + }elseif(!is_dir(CACHE_PATH)){ + // 检查缓存目录 + check_runtime(); + }elseif(APP_DEBUG){ + // 调试模式切换删除编译缓存 + if(is_file(RUNTIME_FILE)) unlink(RUNTIME_FILE); + } +} + +// 检查缓存目录(Runtime) 如果不存在则自动创建 +function check_runtime() { + if(!is_dir(RUNTIME_PATH)) { + mkdir(RUNTIME_PATH); + }elseif(!is_writeable(RUNTIME_PATH)) { + header('Content-Type:text/html; charset=utf-8'); + exit('目录 [ '.RUNTIME_PATH.' ] 不可写!'); + } + mkdir(CACHE_PATH); // 模板缓存目录 + if(!is_dir(LOG_PATH)) mkdir(LOG_PATH); // 日志目录 + if(!is_dir(TEMP_PATH)) mkdir(TEMP_PATH); // 数据缓存目录 + if(!is_dir(DATA_PATH)) mkdir(DATA_PATH); // 数据文件目录 + return true; +} + +// 创建编译缓存 +function build_runtime_cache($append='') { + // 生成编译文件 + $defs = get_defined_constants(TRUE); + $content = '$GLOBALS[\'_beginTime\'] = microtime(TRUE);'; + if(defined('RUNTIME_DEF_FILE')) { // 编译后的常量文件外部引入 + file_put_contents(RUNTIME_DEF_FILE,'$item){ + foreach ($item as $key=>$name) { + $content .= is_int($key)?compile(CORE_PATH.'Behavior/'.$name.'Behavior.class.php'):compile($name); + } + } + return $content; +} + +// 创建项目目录结构 +function build_app_dir() { + // 没有创建项目目录的话自动创建 + if(!is_dir(APP_PATH)) mkdir(APP_PATH,0755,true); + if(is_writeable(APP_PATH)) { + $dirs = array( + LIB_PATH, + RUNTIME_PATH, + CONF_PATH, + COMMON_PATH, + LANG_PATH, + CACHE_PATH, + TMPL_PATH, + TMPL_PATH.C('DEFAULT_THEME').'/', + LOG_PATH, + TEMP_PATH, + DATA_PATH, + LIB_PATH.'Model/', + LIB_PATH.'Action/', + LIB_PATH.'Behavior/', + LIB_PATH.'Widget/', + ); + foreach ($dirs as $dir){ + if(!is_dir($dir)) mkdir($dir,0755,true); + } + // 写入目录安全文件 + build_dir_secure($dirs); + // 写入初始配置文件 + if(!is_file(CONF_PATH.'config.php')) + file_put_contents(CONF_PATH.'config.php',"'配置值'\n);\n?>"); + // 写入测试Action + if(!is_file(LIB_PATH.'Action/IndexAction.class.php')) + build_first_action(); + }else{ + header('Content-Type:text/html; charset=utf-8'); + exit('项目目录不可写,目录无法自动生成!
请使用项目生成器或者手动生成项目目录~'); + } +} + +// 创建测试Action +function build_first_action() { + $content = file_get_contents(THINK_PATH.'Tpl/default_index.tpl'); + file_put_contents(LIB_PATH.'Action/IndexAction.class.php',$content); +} + +// 生成目录安全文件 +function build_dir_secure($dirs=array()) { + // 目录安全写入 + if(defined('BUILD_DIR_SECURE') && BUILD_DIR_SECURE) { + defined('DIR_SECURE_FILENAME') or define('DIR_SECURE_FILENAME', 'index.html'); + defined('DIR_SECURE_CONTENT') or define('DIR_SECURE_CONTENT', ' '); + // 自动写入目录安全文件 + $content = DIR_SECURE_CONTENT; + $files = explode(',', DIR_SECURE_FILENAME); + foreach ($files as $filename){ + foreach ($dirs as $dir) + file_put_contents($dir.$filename,$content); + } + } +} + +// 加载运行时所需文件 +load_runtime_file(); +// 记录加载文件时间 +G('loadTime'); +// 执行入口 +Think::Start(); \ No newline at end of file diff --git a/ThinkPHP/Conf/alias.php b/ThinkPHP/Conf/alias.php new file mode 100644 index 0000000..466b34f --- /dev/null +++ b/ThinkPHP/Conf/alias.php @@ -0,0 +1,23 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +// 系统别名定义文件 +return array( + 'Model' => CORE_PATH.'Core/Model.class.php', + 'Db' => CORE_PATH.'Core/Db.class.php', + 'Log' => CORE_PATH.'Core/Log.class.php', + 'ThinkTemplate' => CORE_PATH.'Template/ThinkTemplate.class.php', + 'TagLib' => CORE_PATH.'Template/TagLib.class.php', + 'Cache' => CORE_PATH.'Core/Cache.class.php', + 'Widget' => CORE_PATH.'Core/Widget.class.php', + 'TagLibCx' => CORE_PATH.'Driver/TagLib/TagLibCx.class.php', +); \ No newline at end of file diff --git a/ThinkPHP/Conf/convention.php b/ThinkPHP/Conf/convention.php new file mode 100644 index 0000000..f2a4d23 --- /dev/null +++ b/ThinkPHP/Conf/convention.php @@ -0,0 +1,145 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP惯例配置文件 + * 该文件请不要修改,如果要覆盖惯例配置的值,可在项目配置文件中设定和惯例不符的配置项 + * 配置名称大小写任意,系统会统一转换成小写 + * 所有配置参数都可以在生效前动态改变 + * @category Think + * @package Common + * @author liu21st + * @version $Id: convention.php 3088 2012-07-29 09:12:19Z luofei614@gmail.com $ + */ +defined('THINK_PATH') or exit(); +return array( + /* 项目设定 */ + 'APP_STATUS' => 'debug', // 应用调试模式状态 调试模式开启后有效 默认为debug 可扩展 并自动加载对应的配置文件 + 'APP_FILE_CASE' => false, // 是否检查文件的大小写 对Windows平台有效 + 'APP_AUTOLOAD_PATH' => '',// 自动加载机制的自动搜索路径,注意搜索顺序 + 'APP_TAGS_ON' => true, // 系统标签扩展开关 + 'APP_SUB_DOMAIN_DEPLOY' => false, // 是否开启子域名部署 + 'APP_SUB_DOMAIN_RULES' => array(), // 子域名部署规则 + 'APP_SUB_DOMAIN_DENY' => array(), // 子域名禁用列表 + 'APP_GROUP_LIST' => '', // 项目分组设定,多个组之间用逗号分隔,例如'Home,Admin' + 'APP_GROUP_MODE' => 0, // 分组模式 0 普通分组 1 独立分组 + 'APP_GROUP_PATH' => 'Modules', // 分组目录 独立分组模式下面有效 + 'ACTION_SUFFIX' => '', // 操作方法后缀 + + /* Cookie设置 */ + 'COOKIE_EXPIRE' => 0, // Coodie有效期 + 'COOKIE_DOMAIN' => '', // Cookie有效域名 + 'COOKIE_PATH' => '/', // Cookie路径 + 'COOKIE_PREFIX' => '', // Cookie前缀 避免冲突 + + /* 默认设定 */ + 'DEFAULT_M_LAYER' => 'Model', // 默认的模型层名称 + 'DEFAULT_C_LAYER' => 'Action', // 默认的控制器层名称 + 'DEFAULT_V_LAYER' => 'Tpl', // 默认的视图层名称 + 'DEFAULT_APP' => '@', // 默认项目名称,@表示当前项目 + 'DEFAULT_LANG' => 'zh-cn', // 默认语言 + 'DEFAULT_THEME' => '', // 默认模板主题名称 + 'DEFAULT_GROUP' => 'Home', // 默认分组 + 'DEFAULT_MODULE' => 'Index', // 默认模块名称 + 'DEFAULT_ACTION' => 'index', // 默认操作名称 + 'DEFAULT_CHARSET' => 'utf-8', // 默认输出编码 + 'DEFAULT_TIMEZONE' => 'PRC', // 默认时区 + 'DEFAULT_AJAX_RETURN' => 'JSON', // 默认AJAX 数据返回格式,可选JSON XML ... + 'DEFAULT_JSONP_HANDLER' => 'jsonpReturn', // 默认JSONP格式返回的处理方法 + 'DEFAULT_FILTER' => 'htmlspecialchars', // 默认参数过滤方法 用于 $this->_get('变量名');$this->_post('变量名')... + + /* 数据库设置 */ + 'DB_TYPE' => 'mysql', // 数据库类型 + 'DB_HOST' => 'localhost', // 服务器地址 + 'DB_NAME' => '', // 数据库名 + 'DB_USER' => 'root', // 用户名 + 'DB_PWD' => '', // 密码 + 'DB_PORT' => '', // 端口 + 'DB_PREFIX' => 'think_', // 数据库表前缀 + 'DB_FIELDTYPE_CHECK' => false, // 是否进行字段类型检查 + 'DB_FIELDS_CACHE' => true, // 启用字段缓存 + 'DB_CHARSET' => 'utf8', // 数据库编码默认采用utf8 + 'DB_DEPLOY_TYPE' => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'DB_RW_SEPARATE' => false, // 数据库读写是否分离 主从式有效 + 'DB_MASTER_NUM' => 1, // 读写分离后 主服务器数量 + 'DB_SLAVE_NO' => '', // 指定从服务器序号 + 'DB_SQL_BUILD_CACHE' => false, // 数据库查询的SQL创建缓存 + 'DB_SQL_BUILD_QUEUE' => 'file', // SQL缓存队列的缓存方式 支持 file xcache和apc + 'DB_SQL_BUILD_LENGTH' => 20, // SQL缓存的队列长度 + 'DB_SQL_LOG' => false, // SQL执行日志记录 + + /* 数据缓存设置 */ + 'DATA_CACHE_TIME' => 0, // 数据缓存有效期 0表示永久缓存 + 'DATA_CACHE_COMPRESS' => false, // 数据缓存是否压缩缓存 + 'DATA_CACHE_CHECK' => false, // 数据缓存是否校验缓存 + 'DATA_CACHE_PREFIX' => '', // 缓存前缀 + 'DATA_CACHE_TYPE' => 'File', // 数据缓存类型,支持:File|Db|Apc|Memcache|Shmop|Sqlite|Xcache|Apachenote|Eaccelerator + 'DATA_CACHE_PATH' => TEMP_PATH,// 缓存路径设置 (仅对File方式缓存有效) + 'DATA_CACHE_SUBDIR' => false, // 使用子目录缓存 (自动根据缓存标识的哈希创建子目录) + 'DATA_PATH_LEVEL' => 1, // 子目录缓存级别 + + /* 错误设置 */ + 'ERROR_MESSAGE' => '页面错误!请稍后再试~',//错误显示信息,非调试模式有效 + 'ERROR_PAGE' => '', // 错误定向页面 + 'SHOW_ERROR_MSG' => false, // 显示错误信息 + 'TRACE_EXCEPTION' => false, // TRACE错误信息是否抛异常 针对trace方法 + + /* 日志设置 */ + 'LOG_RECORD' => false, // 默认不记录日志 + 'LOG_TYPE' => 3, // 日志记录类型 0 系统 1 邮件 3 文件 4 SAPI 默认为文件方式 + 'LOG_DEST' => '', // 日志记录目标 + 'LOG_EXTRA' => '', // 日志记录额外信息 + 'LOG_LEVEL' => 'EMERG,ALERT,CRIT,ERR',// 允许记录的日志级别 + 'LOG_FILE_SIZE' => 2097152, // 日志文件大小限制 + 'LOG_EXCEPTION_RECORD' => false, // 是否记录异常信息日志 + + /* SESSION设置 */ + 'SESSION_AUTO_START' => true, // 是否自动开启Session + 'SESSION_OPTIONS' => array(), // session 配置数组 支持type name id path expire domain 等参数 + 'SESSION_TYPE' => '', // session hander类型 默认无需设置 除非扩展了session hander驱动 + 'SESSION_PREFIX' => '', // session 前缀 + //'VAR_SESSION_ID' => 'session_id', //sessionID的提交变量 + + /* 模板引擎设置 */ + 'TMPL_CONTENT_TYPE' => 'text/html', // 默认模板输出类型 + 'TMPL_ACTION_ERROR' => THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认错误跳转对应的模板文件 + 'TMPL_ACTION_SUCCESS' => THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认成功跳转对应的模板文件 + 'TMPL_EXCEPTION_FILE' => THINK_PATH.'Tpl/think_exception.tpl',// 异常页面的模板文件 + 'TMPL_DETECT_THEME' => false, // 自动侦测模板主题 + 'TMPL_TEMPLATE_SUFFIX' => '.html', // 默认模板文件后缀 + 'TMPL_FILE_DEPR' => '/', //模板文件MODULE_NAME与ACTION_NAME之间的分割符 + + /* URL设置 */ + 'URL_CASE_INSENSITIVE' => false, // 默认false 表示URL区分大小写 true则表示不区分大小写 + 'URL_MODEL' => 1, // URL访问模式,可选参数0、1、2、3,代表以下四种模式: + // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE 模式); 3 (兼容模式) 默认为PATHINFO 模式,提供最好的用户体验和SEO支持 + 'URL_PATHINFO_DEPR' => '/', // PATHINFO模式下,各参数之间的分割符号 + 'URL_PATHINFO_FETCH' => 'ORIG_PATH_INFO,REDIRECT_PATH_INFO,REDIRECT_URL', // 用于兼容判断PATH_INFO 参数的SERVER替代变量列表 + 'URL_HTML_SUFFIX' => 'html', // URL伪静态后缀设置 + 'URL_DENY_SUFFIX' => 'ico|png|gif|jpg', // URL禁止访问的后缀设置 + 'URL_PARAMS_BIND' => true, // URL变量绑定到Action方法参数 + 'URL_404_REDIRECT' => '', // 404 跳转页面 部署模式有效 + + /* 系统变量名称设置 */ + 'VAR_GROUP' => 'g', // 默认分组获取变量 + 'VAR_MODULE' => 'm', // 默认模块获取变量 + 'VAR_ACTION' => 'a', // 默认操作获取变量 + 'VAR_AJAX_SUBMIT' => 'ajax', // 默认的AJAX提交变量 + 'VAR_JSONP_HANDLER' => 'callback', + 'VAR_PATHINFO' => 's', // PATHINFO 兼容模式获取变量例如 ?s=/module/action/id/1 后面的参数取决于URL_PATHINFO_DEPR + 'VAR_URL_PARAMS' => '_URL_', // PATHINFO URL参数变量 + 'VAR_TEMPLATE' => 't', // 默认模板切换变量 + 'VAR_FILTERS' => 'filter_exp', // 全局系统变量的默认过滤方法 多个用逗号分割 + + 'OUTPUT_ENCODE' => false, // 页面压缩输出 + 'HTTP_CACHE_CONTROL' => 'private', // 网页缓存控制 + +); \ No newline at end of file diff --git a/ThinkPHP/Conf/debug.php b/ThinkPHP/Conf/debug.php new file mode 100644 index 0000000..c4b8a5c --- /dev/null +++ b/ThinkPHP/Conf/debug.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 默认的调试模式配置文件 + * 如果项目有定义自己的调试模式配置文件,本文件无效 + * @category Think + * @package Common + * @author liu21st + * @version $Id: debug.php 3071 2012-07-15 07:59:23Z liu21st@gmail.com $ + */ +defined('THINK_PATH') or exit(); +// 调试模式下面默认设置 可以在项目配置目录下重新定义 debug.php 覆盖 +return array( + 'LOG_RECORD' => true, // 进行日志记录 + 'LOG_EXCEPTION_RECORD' => true, // 是否记录异常信息日志 + 'LOG_LEVEL' => 'EMERG,ALERT,CRIT,ERR,WARN,NOTIC,INFO,DEBUG,SQL', // 允许记录的日志级别 + 'DB_FIELDS_CACHE' => false, // 字段缓存信息 + 'DB_SQL_LOG' => true, // 记录SQL信息 + 'APP_FILE_CASE' => true, // 是否检查文件的大小写 对Windows平台有效 + 'TMPL_CACHE_ON' => false, // 是否开启模板编译缓存,设为false则每次都会重新编译 + 'TMPL_STRIP_SPACE' => false, // 是否去除模板文件里面的html空格与换行 + 'SHOW_ERROR_MSG' => true, // 显示错误信息 +); \ No newline at end of file diff --git a/ThinkPHP/Conf/tags.php b/ThinkPHP/Conf/tags.php new file mode 100644 index 0000000..92ddfd4 --- /dev/null +++ b/ThinkPHP/Conf/tags.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- + +// 系统默认的核心行为扩展列表文件 +return array( + 'app_init' => array( + ), + 'app_begin' => array( + 'ReadHtmlCache', // 读取静态缓存 + ), + 'route_check' => array( + 'CheckRoute', // 路由检测 + ), + 'app_end' => array(), + 'path_info' => array(), + 'action_begin' => array(), + 'action_end' => array(), + 'view_begin' => array(), + 'view_parse' => array( + 'ParseTemplate', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 + ), + 'view_filter' => array( + 'ContentReplace', // 模板输出替换 + 'TokenBuild', // 表单令牌 + 'WriteHtmlCache', // 写入静态缓存 + 'ShowRuntime', // 运行时间显示 + ), + 'view_end' => array( + 'ShowPageTrace', // 页面Trace显示 + ), +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Action/RestAction.class.php b/ThinkPHP/Extend/Action/RestAction.class.php new file mode 100644 index 0000000..d22826a --- /dev/null +++ b/ThinkPHP/Extend/Action/RestAction.class.php @@ -0,0 +1,323 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * ThinkPHP Restful 控制器扩展 + * @category Extend + * @package Extend + * @subpackage Action + * @author liu21st + */ +abstract class RestAction { + + // 当前Action名称 + private $name = ''; + // 视图实例 + protected $view = null; + protected $_method = ''; // 当前请求类型 + protected $_type = ''; // 当前资源类型 + // 输出类型 + protected $_types = array(); + + /** + * 架构函数 取得模板对象实例 + * @access public + */ + public function __construct() { + //实例化视图类 + $this->view = Think::instance('View'); + + if(!defined('__EXT__')) define('__EXT__',''); + + // 资源类型检测 + if(''==__EXT__) { // 自动检测资源类型 + $this->_type = $this->getAcceptType(); + }elseif(false === stripos(C('REST_CONTENT_TYPE_LIST'),__EXT__)) { + // 资源类型非法 则用默认资源类型访问 + $this->_type = C('REST_DEFAULT_TYPE'); + }else{ + // 检测实际资源类型 + if($this->getAcceptType() == __EXT__) { + $this->_type = __EXT__; + }else{ + $this->_type = C('REST_DEFAULT_TYPE'); + } + } + + // 请求方式检测 + $method = strtolower($_SERVER['REQUEST_METHOD']); + if(false === stripos(C('REST_METHOD_LIST'),$method)) { + // 请求方式非法 则用默认请求方法 + $method = C('REST_DEFAULT_METHOD'); + } + $this->_method = $method; + // 允许输出的资源类型 + $this->_types = C('REST_OUTPUT_TYPE'); + + //控制器初始化 + if(method_exists($this,'_initialize')) + $this->_initialize(); + } + + /** + * 获取当前Action名称 + * @access protected + */ + protected function getActionName() { + if(empty($this->name)) { + // 获取Action名称 + $this->name = substr(get_class($this),0,-6); + } + return $this->name; + } + + /** + * 是否AJAX请求 + * @access protected + * @return boolean + */ + protected function isAjax() { + if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) ) { + if('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) + return true; + } + if(!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) + // 判断Ajax方式提交 + return true; + return false; + } + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $args 参数 + * @return mixed + */ + public function __call($method,$args) { + if( 0 === strcasecmp($method,ACTION_NAME)) { + if(method_exists($this,$method.'_'.$this->_method.'_'.$this->_type)) { // RESTFul方法支持 + $fun = $method.'_'.$this->_method.'_'.$this->_type; + $this->$fun(); + }elseif($this->_method == C('REST_DEFAULT_METHOD') && method_exists($this,$method.'_'.$this->_type) ){ + $fun = $method.'_'.$this->_type; + $this->$fun(); + }elseif($this->_type == C('REST_DEFAULT_TYPE') && method_exists($this,$method.'_'.$this->_method) ){ + $fun = $method.'_'.$this->_method; + $this->$fun(); + }elseif(method_exists($this,'_empty')) { + // 如果定义了_empty操作 则调用 + $this->_empty($method,$args); + }elseif(file_exists_case(C('TMPL_FILE_NAME'))){ + // 检查是否存在默认模版 如果有直接输出模版 + $this->display(); + }else{ + // 抛出异常 + throw_exception(L('_ERROR_ACTION_').ACTION_NAME); + } + }else{ + switch(strtolower($method)) { + // 获取变量 支持过滤和默认值 调用方式 $this->_post($key,$filter,$default); + case '_get': $input =& $_GET;break; + case '_post':$input =& $_POST;break; + case '_put': + case '_delete':parse_str(file_get_contents('php://input'), $input);break; + case '_request': $input =& $_REQUEST;break; + case '_session': $input =& $_SESSION;break; + case '_cookie': $input =& $_COOKIE;break; + case '_server': $input =& $_SERVER;break; + default: + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + } + if(isset($input[$args[0]])) { // 取值操作 + $data = $input[$args[0]]; + $fun = $args[1]?$args[1]:C('DEFAULT_FILTER'); + $data = $fun($data); // 参数过滤 + }else{ // 变量默认值 + $data = isset($args[2])?$args[2]:NULL; + } + return $data; + } + } + + /** + * 模板显示 + * 调用内置的模板引擎显示方法, + * @access protected + * @param string $templateFile 指定要调用的模板文件 + * 默认为空 由系统自动定位模板文件 + * @param string $charset 输出编码 + * @param string $contentType 输出类型 + * @return void + */ + protected function display($templateFile='',$charset='',$contentType='') { + $this->view->display($templateFile,$charset,$contentType); + } + + /** + * 模板变量赋值 + * @access protected + * @param mixed $name 要显示的模板变量 + * @param mixed $value 变量的值 + * @return void + */ + protected function assign($name,$value='') { + $this->view->assign($name,$value); + } + + public function __set($name,$value) { + $this->view->assign($name,$value); + } + + /** + * 设置页面输出的CONTENT_TYPE和编码 + * @access public + * @param string $type content_type 类型对应的扩展名 + * @param string $charset 页面输出编码 + * @return void + */ + public function setContentType($type, $charset=''){ + if(headers_sent()) return; + if(empty($charset)) $charset = C('DEFAULT_CHARSET'); + $type = strtolower($type); + if(isset($this->_types[$type])) //过滤content_type + header('Content-Type: '.$this->_types[$type].'; charset='.$charset); + } + + /** + * 输出返回数据 + * @access protected + * @param mixed $data 要返回的数据 + * @param String $type 返回类型 JSON XML + * @param integer $code HTTP状态 + * @return void + */ + protected function response($data,$type='',$code=200) { + // 保存日志 + if(C('LOG_RECORD')) Log::save(); + $this->sendHttpStatus($code); + exit($this->encodeData($data,strtolower($type))); + } + + /** + * 编码数据 + * @access protected + * @param mixed $data 要返回的数据 + * @param String $type 返回类型 JSON XML + * @return void + */ + protected function encodeData($data,$type='') { + if(empty($data)) return ''; + if('json' == $type) { + // 返回JSON数据格式到客户端 包含状态信息 + $data = json_encode($data); + }elseif('xml' == $type){ + // 返回xml格式数据 + $data = xml_encode($data); + }elseif('php'==$type){ + $data = serialize($data); + }// 默认直接输出 + $this->setContentType($type); + header('Content-Length: ' . strlen($data)); + return $data; + } + + // 发送Http状态信息 + protected function sendHttpStatus($status) { + 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]); + } + } + /** + * 获取当前请求的Accept头信息 + * @return string + */ + protected function getAcceptType(){ + $type = array( + 'html' => 'text/html,application/xhtml+xml,*/*', + 'xml' => 'application/xml,text/xml,application/x-xml', + 'json' => 'application/json,text/x-json,application/jsonrequest,text/json', + 'js' => 'text/javascript,application/javascript,application/x-javascript', + 'css' => 'text/css', + 'rss' => 'application/rss+xml', + 'yaml' => 'application/x-yaml,text/yaml', + 'atom' => 'application/atom+xml', + 'pdf' => 'application/pdf', + 'text' => 'text/plain', + 'png' => 'image/png', + 'jpg' => 'image/jpg,image/jpeg,image/pjpeg', + 'gif' => 'image/gif', + 'csv' => 'text/csv' + ); + + foreach($type as $key=>$val){ + $array = explode(',',$val); + foreach($array as $k=>$v){ + if(stristr($_SERVER['HTTP_ACCEPT'], $v)) { + return $key; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Behavior/AgentCheckBehavior.class.php b/ThinkPHP/Extend/Behavior/AgentCheckBehavior.class.php new file mode 100644 index 0000000..59f374c --- /dev/null +++ b/ThinkPHP/Extend/Behavior/AgentCheckBehavior.class.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 行为扩展:代理检测 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class AgentCheckBehavior extends Behavior { + protected $options = array( + 'LIMIT_PROXY_VISIT'=>true, + ); + public function run(&$params) { + // 代理访问检测 + if(C('LIMIT_PROXY_VISIT') && ($_SERVER['HTTP_X_FORWARDED_FOR'] || $_SERVER['HTTP_VIA'] || $_SERVER['HTTP_PROXY_CONNECTION'] || $_SERVER['HTTP_USER_AGENT_VIA'])) { + // 禁止代理访问 + exit('Access Denied'); + } + } +} +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Behavior/BrowserCheckBehavior.class.php b/ThinkPHP/Extend/Behavior/BrowserCheckBehavior.class.php new file mode 100644 index 0000000..0d5dee3 --- /dev/null +++ b/ThinkPHP/Extend/Behavior/BrowserCheckBehavior.class.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 浏览器防刷新检测 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class BrowserCheckBehavior extends Behavior { + protected $options = array( + // 浏览器防刷新的时间间隔(秒) + 'LIMIT_REFLESH_TIMES' => 10, + ); + + public function run(&$params) { + if($_SERVER['REQUEST_METHOD'] == 'GET') { + // 启用页面防刷新机制 + $guid = md5($_SERVER['PHP_SELF']); + // 检查页面刷新间隔 + if(cookie('_last_visit_time_'.$guid) && cookie('_last_visit_time_'.$guid)>time()-C('LIMIT_REFLESH_TIMES')) { + // 页面刷新读取浏览器缓存 + header('HTTP/1.1 304 Not Modified'); + exit; + }else{ + // 缓存当前地址访问时间 + cookie('_last_visit_time_'.$guid, $_SERVER['REQUEST_TIME']); + //header('Last-Modified:'.(date('D,d M Y H:i:s',$_SERVER['REQUEST_TIME']-C('LIMIT_REFLESH_TIMES'))).' GMT'); + } + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Behavior/CheckActionRouteBehavior.class.php b/ThinkPHP/Extend/Behavior/CheckActionRouteBehavior.class.php new file mode 100644 index 0000000..8946369 --- /dev/null +++ b/ThinkPHP/Extend/Behavior/CheckActionRouteBehavior.class.php @@ -0,0 +1,199 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:操作路由检测 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class CheckActionRouteBehavior extends Behavior { + + // 行为扩展的执行入口必须是run + public function run(&$config){ + // 优先检测是否存在PATH_INFO + $regx = trim($_SERVER['PATH_INFO'],'/'); + if(empty($regx)) return ; + // 路由定义文件优先于config中的配置定义 + // 路由处理 + $routes = $config['routes']; + if(!empty($routes)) { + $depr = C('URL_PATHINFO_DEPR'); + // 分隔符替换 确保路由定义使用统一的分隔符 + $regx = str_replace($depr,'/',$regx); + $regx = substr_replace($regx,'',0,strlen(__URL__)); + foreach ($routes as $rule=>$route){ + if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由 + return C('ACTION_NAME',$this->parseRegex($matches,$route,$regx)); + }else{ // 规则路由 + $len1 = substr_count($regx,'/'); + $len2 = substr_count($rule,'/'); + if($len1>=$len2) { + if('$' == substr($rule,-1,1)) {// 完整匹配 + if($len1 != $len2) { + continue; + }else{ + $rule = substr($rule,0,-1); + } + } + $match = $this->checkUrlMatch($regx,$rule); + if($match) return C('ACTION_NAME',$this->parseRule($rule,$route,$regx)); + } + } + } + } + } + + // 检测URL和规则路由是否匹配 + private function checkUrlMatch($regx,$rule) { + $m1 = explode('/',$regx); + $m2 = explode('/',$rule); + $match = true; // 是否匹配 + foreach ($m2 as $key=>$val){ + if(':' == substr($val,0,1)) {// 动态变量 + if(strpos($val,'\\')) { + $type = substr($val,-1); + if('d'==$type && !is_numeric($m1[$key])) { + $match = false; + break; + } + }elseif(strpos($val,'^')){ + $array = explode('|',substr(strstr($val,'^'),1)); + if(in_array($m1[$key],$array)) { + $match = false; + break; + } + } + }elseif(0 !== strcasecmp($val,$m1[$key])){ + $match = false; + break; + } + } + return $match; + } + + // 解析规范的路由地址 + // 地址格式 操作?参数1=值1&参数2=值2... + private function parseUrl($url) { + $var = array(); + if(false !== strpos($url,'?')) { // 操作?参数1=值1&参数2=值2... + $info = parse_url($url); + $path = $info['path']; + parse_str($info['query'],$var); + }else{ // 操作 + $path = $url; + } + $var[C('VAR_ACTION')] = $path; + return $var; + } + + // 解析规则路由 + // '路由规则'=>'操作?额外参数1=值1&额外参数2=值2...' + // '路由规则'=>array('操作','额外参数1=值1&额外参数2=值2...') + // '路由规则'=>'外部地址' + // '路由规则'=>array('外部地址','重定向代码') + // 路由规则中 :开头 表示动态变量 + // 外部地址中可以用动态变量 采用 :1 :2 的方式 + // 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'), + // 'new/:id'=>array('/new.php?id=:1',301), 重定向 + private function parseRule($rule,$route,$regx) { + // 获取路由地址规则 + $url = is_array($route)?$route[0]:$route; + // 获取URL地址中的参数 + $paths = explode('/',$regx); + // 解析路由规则 + $matches = array(); + $rule = explode('/',$rule); + foreach ($rule as $item){ + if(0===strpos($item,':')) { // 动态变量获取 + if($pos = strpos($item,'^') ) { + $var = substr($item,1,$pos-1); + }elseif(strpos($item,'\\')){ + $var = substr($item,1,-2); + }else{ + $var = substr($item,1); + } + $matches[$var] = array_shift($paths); + }else{ // 过滤URL中的静态变量 + array_shift($paths); + } + } + if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 + if(strpos($url,':')) { // 传递动态参数 + $values = array_values($matches); + $url = preg_replace('/:(\d+)/e','$values[\\1-1]',$url); + } + header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); + exit; + }else{ + // 解析路由地址 + $var = $this->parseUrl($url); + // 解析路由地址里面的动态参数 + $values = array_values($matches); + foreach ($var as $key=>$val){ + if(0===strpos($val,':')) { + $var[$key] = $values[substr($val,1)-1]; + } + } + $var = array_merge($matches,$var); + // 解析剩余的URL参数 + if($paths) { + preg_replace('@(\w+)\/([^\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', implode('/',$paths)); + } + // 解析路由自动传人参数 + if(is_array($route) && isset($route[1])) { + parse_str($route[1],$params); + $var = array_merge($var,$params); + } + $action = $var[C('VAR_ACTION')]; + unset($var[C('VAR_ACTION')]); + $_GET = array_merge($var,$_GET); + return $action; + } + } + + // 解析正则路由 + // '路由正则'=>'[分组/模块/操作]?参数1=值1&参数2=值2...' + // '路由正则'=>array('[分组/模块/操作]?参数1=值1&参数2=值2...','额外参数1=值1&额外参数2=值2...') + // '路由正则'=>'外部地址' + // '路由正则'=>array('外部地址','重定向代码') + // 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式 + // '/new\/(\d+)\/(\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'), + // '/new\/(\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), 重定向 + private function parseRegex($matches,$route,$regx) { + // 获取路由地址规则 + $url = is_array($route)?$route[0]:$route; + $url = preg_replace('/:(\d+)/e','$matches[\\1]',$url); + if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 + header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); + exit; + }else{ + // 解析路由地址 + $var = $this->parseUrl($url); + // 解析剩余的URL参数 + $regx = substr_replace($regx,'',0,strlen($matches[0])); + if($regx) { + preg_replace('@(\w+)\/([^,\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', $regx); + } + // 解析路由自动传人参数 + if(is_array($route) && isset($route[1])) { + parse_str($route[1],$params); + $var = array_merge($var,$params); + } + $action = $var[C('VAR_ACTION')]; + unset($var[C('VAR_ACTION')]); + $_GET = array_merge($var,$_GET); + } + return $action; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Behavior/CheckLangBehavior.class.php b/ThinkPHP/Extend/Behavior/CheckLangBehavior.class.php new file mode 100644 index 0000000..7386363 --- /dev/null +++ b/ThinkPHP/Extend/Behavior/CheckLangBehavior.class.php @@ -0,0 +1,87 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 语言检测 并自动加载语言包 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class CheckLangBehavior extends Behavior { + // 行为参数定义(默认值) 可在项目配置中覆盖 + protected $options = array( + 'LANG_SWITCH_ON' => false, // 默认关闭语言包功能 + 'LANG_AUTO_DETECT' => true, // 自动侦测语言 开启多语言功能后有效 + 'LANG_LIST' => 'zh-cn', // 允许切换的语言列表 用逗号分隔 + 'VAR_LANGUAGE' => 'l', // 默认语言切换变量 + ); + + // 行为扩展的执行入口必须是run + public function run(&$params){ + // 开启静态缓存 + $this->checkLanguage(); + } + + /** + * 语言检查 + * 检查浏览器支持语言,并自动加载语言包 + * @access private + * @return void + */ + private function checkLanguage() { + // 不开启语言包功能,仅仅加载框架语言文件直接返回 + if (!C('LANG_SWITCH_ON')){ + return; + } + $langSet = C('DEFAULT_LANG'); + // 启用了语言包功能 + // 根据是否启用自动侦测设置获取语言选择 + if (C('LANG_AUTO_DETECT')){ + if(isset($_GET[C('VAR_LANGUAGE')])){ + $langSet = $_GET[C('VAR_LANGUAGE')];// url中设置了语言变量 + cookie('think_language',$langSet,3600); + }elseif(cookie('think_language')){// 获取上次用户的选择 + $langSet = cookie('think_language'); + }elseif(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){// 自动侦测浏览器语言 + preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches); + $langSet = $matches[1]; + cookie('think_language',$langSet,3600); + } + if(false === stripos(C('LANG_LIST'),$langSet)) { // 非法语言参数 + $langSet = C('DEFAULT_LANG'); + } + } + // 定义当前语言 + define('LANG_SET',strtolower($langSet)); + + $group = ''; + $path = (defined('GROUP_NAME') && C('APP_GROUP_MODE')==1) ? BASE_LIB_PATH.'Lang/'.LANG_SET.'/' : LANG_PATH.LANG_SET.'/'; + // 读取项目公共语言包 + if(is_file(LANG_PATH.LANG_SET.'/common.php')) + L(include LANG_PATH.LANG_SET.'/common.php'); + // 读取分组公共语言包 + if(defined('GROUP_NAME')){ + if(C('APP_GROUP_MODE')==1){ // 独立分组 + $file = $path.'common.php'; + }else{ // 普通分组 + $file = $path.GROUP_NAME.'.php'; + $group = GROUP_NAME.C('TMPL_FILE_DEPR'); + } + if(is_file($file)) + L(include $file); + } + // 读取当前模块语言包 + if (is_file($path.$group.strtolower(MODULE_NAME).'.php')) + L(include $path.$group.strtolower(MODULE_NAME).'.php'); + } +} diff --git a/ThinkPHP/Extend/Behavior/CronRunBehavior.class.php b/ThinkPHP/Extend/Behavior/CronRunBehavior.class.php new file mode 100644 index 0000000..4627ab4 --- /dev/null +++ b/ThinkPHP/Extend/Behavior/CronRunBehavior.class.php @@ -0,0 +1,72 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 自动执行任务 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class CronRunBehavior extends Behavior { + protected $options = array( + 'CRON_MAX_TIME' => 60, // 单个任务最大执行时间 + ); + public function run(&$params) { + // 锁定自动执行 + $lockfile = RUNTIME_PATH.'cron.lock'; + if(is_writable($lockfile) && filemtime($lockfile) > $_SERVER['REQUEST_TIME'] - C('CRON_MAX_TIME')) { + return ; + } else { + touch($lockfile); + } + set_time_limit(1000); + ignore_user_abort(true); + + // 载入cron配置文件 + // 格式 return array( + // 'cronname'=>array('filename',intervals,nextruntime),... + // ); + if(is_file(RUNTIME_PATH.'~crons.php')) { + $crons = include RUNTIME_PATH.'~crons.php'; + }elseif(is_file(CONF_PATH.'crons.php')){ + $crons = include CONF_PATH.'crons.php'; + } + if(isset($crons) && is_array($crons)) { + $update = false; + $log = array(); + foreach ($crons as $key=>$cron){ + if(empty($cron[2]) || $_SERVER['REQUEST_TIME']>=$cron[2]) { + // 到达时间 执行cron文件 + G('cronStart'); + include LIB_PATH.'Cron/'.$cron[0].'.php'; + $_useTime = G('cronStart','cronEnd', 6); + // 更新cron记录 + $cron[2] = $_SERVER['REQUEST_TIME']+$cron[1]; + $crons[$key] = $cron; + $log[] = "Cron:$key Runat ".date('Y-m-d H:i:s')." Use $_useTime s\n"; + $update = true; + } + } + if($update) { + // 记录Cron执行日志 + Log::write(implode('',$log)); + // 更新cron文件 + $content = ""; + file_put_contents(RUNTIME_PATH.'~crons.php',$content); + } + } + // 解除锁定 + unlink($lockfile); + return ; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Behavior/FireShowPageTraceBehavior.class.php b/ThinkPHP/Extend/Behavior/FireShowPageTraceBehavior.class.php new file mode 100644 index 0000000..78363d9 --- /dev/null +++ b/ThinkPHP/Extend/Behavior/FireShowPageTraceBehavior.class.php @@ -0,0 +1,2093 @@ + +// +---------------------------------------------------------------------- +// $Id$ + +/** + +------------------------------------------------------------------------------ + * 将Trace信息输出到火狐的firebug,从而不影响ajax效果和页面的布局。 + +------------------------------------------------------------------------------ + * 使用前,你需要先在火狐浏览器上安装firebug和firePHP两个插件。 + * 定义项目的tags.php文件, + * + * array( + * 'FireShowPageTrace' + * ) + * ); + * + * 再将此文件放到项目的Behavior文件夹中即可 + * 如果trace信息没有正常输出,请查看您的日志。 + * firePHP,是通过http headers和firebug通讯的,所以要保证在输出trace信息之前不能有 + * headers输出,你可以在入口文件第一行加入代码 ob_start(); 或者配置output_buffering + * + */ + +defined('THINK_PATH') or exit(); +/** + +------------------------------------------------------------------------------ + * 系统行为扩展 页面Trace显示输出 + +------------------------------------------------------------------------------ + */ +class FireShowPageTraceBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'FIRE_SHOW_PAGE_TRACE'=> true, // 显示页面Trace信息 + 'TRACE_PAGE_TABS'=> array('BASE'=>'基本','FILE'=>'文件','INFO'=>'流程','ERR|NOTIC'=>'错误','SQL'=>'SQL','DEBUG'=>'调试') + ); + + // 行为扩展的执行入口必须是run + public function run(&$params){ + if(C('FIRE_SHOW_PAGE_TRACE')) $this->showTrace(); + } + + /** + +---------------------------------------------------------- + * 显示页面Trace信息 + +---------------------------------------------------------- + * @access private + +---------------------------------------------------------- + */ + private function showTrace() { + // 系统默认显示信息 + $files = get_included_files(); + $info = array(); + foreach ($files as $key=>$file){ + $info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )'; + } + $trace = array(); + $base = array( + '请求信息'=> date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__, + '运行时间'=> $this->showTime(), + '内存开销'=> MEMORY_LIMIT_ON?number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024,2).' kb':'不支持', + '查询信息'=> N('db_query').' queries '.N('db_write').' writes ', + '文件加载'=> count(get_included_files()), + '缓存信息'=> N('cache_read').' gets '.N('cache_write').' writes ', + '配置加载'=> count(c()), + '会话信息'=> 'SESSION_ID='.session_id(), + ); + // 读取项目定义的Trace文件 + $traceFile = CONF_PATH.'trace.php'; + if(is_file($traceFile)) { + $base = array_merge($base,include $traceFile); + } + $debug = trace(); + $tabs = C('TRACE_PAGE_TABS'); + foreach ($tabs as $name=>$title){ + switch(strtoupper($name)) { + case 'BASE':// 基本信息 + $trace[$title] = $base; + break; + case 'FILE': // 文件信息 + $trace[$title] = $info; + break; + default:// 调试信息 + if(strpos($name,'|')) {// 多组信息 + $array = explode('|',$name); + $result = array(); + foreach($array as $name){ + $result += isset($debug[$name])?$debug[$name]:array(); + } + $trace[$title] = $result; + }else{ + $trace[$title] = isset($debug[$name])?$debug[$name]:''; + } + } + } + foreach ($trace as $key=>$val){ + if(!is_array($val) && empty($val)) + $val=array(); + if(is_array($val)){ + $fire=array( + array('','') + ); + foreach($val as $k=>$v){ + $fire[]=array($k,$v); + } + fb(array($key,$fire),FirePHP::TABLE); + }else{ + fb($val,$key); + } + } + unset($files,$info,$log,$base); + } + + /** + +---------------------------------------------------------- + * 获取运行时间 + +---------------------------------------------------------- + */ + private function showTime() { + // 显示运行时间 + G('beginTime',$GLOBALS['_beginTime']); + G('viewEndTime'); + // 显示详细运行时间 + return G('beginTime','viewEndTime').'s ( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )'; + } + +} + + +function fb() +{ + $instance = FirePHP::getInstance(true); + + $args = func_get_args(); + return call_user_func_array(array($instance,'fb'),$args); +} + + +class FB +{ + /** + * Enable and disable logging to Firebug + * + * @see FirePHP->setEnabled() + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public static function setEnabled($Enabled) + { + $instance = FirePHP::getInstance(true); + $instance->setEnabled($Enabled); + } + + /** + * Check if logging is enabled + * + * @see FirePHP->getEnabled() + * @return boolean TRUE if enabled + */ + public static function getEnabled() + { + $instance = FirePHP::getInstance(true); + return $instance->getEnabled(); + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @see FirePHP->setObjectFilter() + * @param string $Class The class name of the object + * @param array $Filter An array or members to exclude + * @return void + */ + public static function setObjectFilter($Class, $Filter) + { + $instance = FirePHP::getInstance(true); + $instance->setObjectFilter($Class, $Filter); + } + + /** + * Set some options for the library + * + * @see FirePHP->setOptions() + * @param array $Options The options to be set + * @return void + */ + public static function setOptions($Options) + { + $instance = FirePHP::getInstance(true); + $instance->setOptions($Options); + } + + /** + * Get options for the library + * + * @see FirePHP->getOptions() + * @return array The options + */ + public static function getOptions() + { + $instance = FirePHP::getInstance(true); + return $instance->getOptions(); + } + + /** + * Log object to firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object + * @return true + * @throws Exception + */ + public static function send() + { + $instance = FirePHP::getInstance(true); + $args = func_get_args(); + return call_user_func_array(array($instance,'fb'),$args); + } + + /** + * Start a group for following messages + * + * Options: + * Collapsed: [true|false] + * Color: [#RRGGBB|ColorName] + * + * @param string $Name + * @param array $Options OPTIONAL Instructions on how to log the group + * @return true + */ + public static function group($Name, $Options=null) + { + $instance = FirePHP::getInstance(true); + return $instance->group($Name, $Options); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public static function groupEnd() + { + return self::send(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function log($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::LOG); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function info($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::INFO); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function warn($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::WARN); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function error($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::ERROR); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public static function dump($Key, $Variable) + { + return self::send($Variable, $Key, FirePHP::DUMP); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public static function trace($Label) + { + return self::send($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public static function table($Label, $Table) + { + return self::send($Table, $Label, FirePHP::TABLE); + } + +} + +if (!defined('E_STRICT')) { + define('E_STRICT', 2048); +} +if (!defined('E_RECOVERABLE_ERROR')) { + define('E_RECOVERABLE_ERROR', 4096); +} +if (!defined('E_DEPRECATED')) { + define('E_DEPRECATED', 8192); +} +if (!defined('E_USER_DEPRECATED')) { + define('E_USER_DEPRECATED', 16384); +} + +/** + * Sends the given data to the FirePHP Firefox Extension. + * The data can be displayed in the Firebug Console or in the + * "Server" request tab. + * + * For more information see: http://www.firephp.org/ + * + * @copyright Copyright (C) 2007-2009 Christoph Dorn + * @author Christoph Dorn + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHPCore + */ +class FirePHP { + + /** + * FirePHP version + * + * @var string + */ + const VERSION = '0.3'; // @pinf replace '0.3' with '%%package.version%%' + + /** + * Firebug LOG level + * + * Logs a message to firebug console. + * + * @var string + */ + const LOG = 'LOG'; + + /** + * Firebug INFO level + * + * Logs a message to firebug console and displays an info icon before the message. + * + * @var string + */ + const INFO = 'INFO'; + + /** + * Firebug WARN level + * + * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. + * + * @var string + */ + const WARN = 'WARN'; + + /** + * Firebug ERROR level + * + * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. + * + * @var string + */ + const ERROR = 'ERROR'; + + /** + * Dumps a variable to firebug's server panel + * + * @var string + */ + const DUMP = 'DUMP'; + + /** + * Displays a stack trace in firebug console + * + * @var string + */ + const TRACE = 'TRACE'; + + /** + * Displays an exception in firebug console + * + * Increments the firebug error count. + * + * @var string + */ + const EXCEPTION = 'EXCEPTION'; + + /** + * Displays an table in firebug console + * + * @var string + */ + const TABLE = 'TABLE'; + + /** + * Starts a group in firebug console + * + * @var string + */ + const GROUP_START = 'GROUP_START'; + + /** + * Ends a group in firebug console + * + * @var string + */ + const GROUP_END = 'GROUP_END'; + + /** + * Singleton instance of FirePHP + * + * @var FirePHP + */ + protected static $instance = null; + + /** + * Flag whether we are logging from within the exception handler + * + * @var boolean + */ + protected $inExceptionHandler = false; + + /** + * Flag whether to throw PHP errors that have been converted to ErrorExceptions + * + * @var boolean + */ + protected $throwErrorExceptions = true; + + /** + * Flag whether to convert PHP assertion errors to Exceptions + * + * @var boolean + */ + protected $convertAssertionErrorsToExceptions = true; + + /** + * Flag whether to throw PHP assertion errors that have been converted to Exceptions + * + * @var boolean + */ + protected $throwAssertionExceptions = false; + + /** + * Wildfire protocol message index + * + * @var int + */ + protected $messageIndex = 1; + + /** + * Options for the library + * + * @var array + */ + protected $options = array('maxDepth' => 10, + 'maxObjectDepth' => 5, + 'maxArrayDepth' => 5, + 'useNativeJsonEncode' => true, + 'includeLineNumbers' => true); + + /** + * Filters used to exclude object members when encoding + * + * @var array + */ + protected $objectFilters = array( + 'firephp' => array('objectStack', 'instance', 'json_objectStack'), + 'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack') + ); + + /** + * A stack of objects used to detect recursion during object encoding + * + * @var object + */ + protected $objectStack = array(); + + /** + * Flag to enable/disable logging + * + * @var boolean + */ + protected $enabled = true; + + /** + * The insight console to log to if applicable + * + * @var object + */ + protected $logToInsightConsole = null; + + /** + * When the object gets serialized only include specific object members. + * + * @return array + */ + public function __sleep() + { + return array('options','objectFilters','enabled'); + } + + /** + * Gets singleton instance of FirePHP + * + * @param boolean $AutoCreate + * @return FirePHP + */ + public static function getInstance($AutoCreate = false) + { + if ($AutoCreate===true && !self::$instance) { + self::init(); + } + return self::$instance; + } + + /** + * Creates FirePHP object and stores it for singleton access + * + * @return FirePHP + */ + public static function init() + { + return self::setInstance(new self()); + } + + /** + * Set the instance of the FirePHP singleton + * + * @param FirePHP $instance The FirePHP object instance + * @return FirePHP + */ + public static function setInstance($instance) + { + return self::$instance = $instance; + } + + /** + * Set an Insight console to direct all logging calls to + * + * @param object $console The console object to log to + * @return void + */ + public function setLogToInsightConsole($console) + { + if(is_string($console)) { + if(get_class($this)!='FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) { + throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!'); + } + $this->logToInsightConsole = $this->to('request')->console($console); + } else { + $this->logToInsightConsole = $console; + } + } + + /** + * Enable and disable logging to Firebug + * + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public function setEnabled($Enabled) + { + $this->enabled = $Enabled; + } + + /** + * Check if logging is enabled + * + * @return boolean TRUE if enabled + */ + public function getEnabled() + { + return $this->enabled; + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @param string $Class The class name of the object + * @param array $Filter An array of members to exclude + * @return void + */ + public function setObjectFilter($Class, $Filter) + { + $this->objectFilters[strtolower($Class)] = $Filter; + } + + /** + * Set some options for the library + * + * Options: + * - maxDepth: The maximum depth to traverse (default: 10) + * - maxObjectDepth: The maximum depth to traverse objects (default: 5) + * - maxArrayDepth: The maximum depth to traverse arrays (default: 5) + * - useNativeJsonEncode: If true will use json_encode() (default: true) + * - includeLineNumbers: If true will include line numbers and filenames (default: true) + * + * @param array $Options The options to be set + * @return void + */ + public function setOptions($Options) + { + $this->options = array_merge($this->options,$Options); + } + + /** + * Get options from the library + * + * @return array The currently set options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Set an option for the library + * + * @param string $Name + * @param mixed $Value + * @throws Exception + * @return void + */ + public function setOption($Name, $Value) + { + if (!isset($this->options[$Name])) { + throw $this->newException('Unknown option: ' . $Name); + } + $this->options[$Name] = $Value; + } + + /** + * Get an option from the library + * + * @param string $Name + * @throws Exception + * @return mixed + */ + public function getOption($Name) + { + if (!isset($this->options[$Name])) { + throw $this->newException('Unknown option: ' . $Name); + } + return $this->options[$Name]; + } + + /** + * Register FirePHP as your error handler + * + * Will throw exceptions for each php error. + * + * @return mixed Returns a string containing the previously defined error handler (if any) + */ + public function registerErrorHandler($throwErrorExceptions = false) + { + //NOTE: The following errors will not be caught by this error handler: + // E_ERROR, E_PARSE, E_CORE_ERROR, + // E_CORE_WARNING, E_COMPILE_ERROR, + // E_COMPILE_WARNING, E_STRICT + + $this->throwErrorExceptions = $throwErrorExceptions; + + return set_error_handler(array($this,'errorHandler')); + } + + /** + * FirePHP's error handler + * + * Throws exception for each php error that will occur. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * @param array $errcontext + */ + public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) + { + // Don't throw exception if error reporting is switched off + if (error_reporting() == 0) { + return; + } + // Only throw exceptions for errors we are asking for + if (error_reporting() & $errno) { + + $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline); + if ($this->throwErrorExceptions) { + throw $exception; + } else { + $this->fb($exception); + } + } + } + + /** + * Register FirePHP as your exception handler + * + * @return mixed Returns the name of the previously defined exception handler, + * or NULL on error. + * If no previous handler was defined, NULL is also returned. + */ + public function registerExceptionHandler() + { + return set_exception_handler(array($this,'exceptionHandler')); + } + + /** + * FirePHP's exception handler + * + * Logs all exceptions to your firebug console and then stops the script. + * + * @param Exception $Exception + * @throws Exception + */ + function exceptionHandler($Exception) + { + + $this->inExceptionHandler = true; + + header('HTTP/1.1 500 Internal Server Error'); + + try { + $this->fb($Exception); + } catch (Exception $e) { + echo 'We had an exception: ' . $e; + } + $this->inExceptionHandler = false; + } + + /** + * Register FirePHP driver as your assert callback + * + * @param boolean $convertAssertionErrorsToExceptions + * @param boolean $throwAssertionExceptions + * @return mixed Returns the original setting or FALSE on errors + */ + public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false) + { + $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions; + $this->throwAssertionExceptions = $throwAssertionExceptions; + + if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) { + throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!'); + } + + return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler')); + } + + /** + * FirePHP's assertion handler + * + * Logs all assertions to your firebug console and then stops the script. + * + * @param string $file File source of assertion + * @param int $line Line source of assertion + * @param mixed $code Assertion code + */ + public function assertionHandler($file, $line, $code) + { + if ($this->convertAssertionErrorsToExceptions) { + + $exception = new ErrorException('Assertion Failed - Code[ '.$code.' ]', 0, null, $file, $line); + + if ($this->throwAssertionExceptions) { + throw $exception; + } else { + $this->fb($exception); + } + + } else { + $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File'=>$file,'Line'=>$line)); + } + } + + /** + * Start a group for following messages. + * + * Options: + * Collapsed: [true|false] + * Color: [#RRGGBB|ColorName] + * + * @param string $Name + * @param array $Options OPTIONAL Instructions on how to log the group + * @return true + * @throws Exception + */ + public function group($Name, $Options = null) + { + + if (!$Name) { + throw $this->newException('You must specify a label for the group!'); + } + + if ($Options) { + if (!is_array($Options)) { + throw $this->newException('Options must be defined as an array!'); + } + if (array_key_exists('Collapsed', $Options)) { + $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false'; + } + } + + return $this->fb(null, $Name, FirePHP::GROUP_START, $Options); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public function groupEnd() + { + return $this->fb(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function log($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::LOG, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function info($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::INFO, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function warn($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::WARN, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function error($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::ERROR, $Options); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public function dump($Key, $Variable, $Options = array()) + { + if (!is_string($Key)) { + throw $this->newException('Key passed to dump() is not a string'); + } + if (strlen($Key)>100) { + throw $this->newException('Key passed to dump() is longer than 100 characters'); + } + if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $Key, $m)) { + throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]'); + } + return $this->fb($Variable, $Key, FirePHP::DUMP, $Options); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public function trace($Label) + { + return $this->fb($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public function table($Label, $Table, $Options = array()) + { + return $this->fb($Table, $Label, FirePHP::TABLE, $Options); + } + + /** + * Insight API wrapper + * + * @see Insight_Helper::to() + */ + public static function to() + { + $instance = self::getInstance(); + if (!method_exists($instance, "_to")) { + throw new Exception("FirePHP::to() implementation not loaded"); + } + $args = func_get_args(); + return call_user_func_array(array($instance, '_to'), $args); + } + + /** + * Insight API wrapper + * + * @see Insight_Helper::plugin() + */ + public static function plugin() + { + $instance = self::getInstance(); + if (!method_exists($instance, "_plugin")) { + throw new Exception("FirePHP::plugin() implementation not loaded"); + } + $args = func_get_args(); + return call_user_func_array(array($instance, '_plugin'), $args); + } + + /** + * Check if FirePHP is installed on client + * + * @return boolean + */ + public function detectClientExtension() + { + // Check if FirePHP is installed on client via User-Agent header + if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si',$this->getUserAgent(),$m) && + version_compare($m[1][0],'0.0.6','>=')) { + return true; + } else + // Check if FirePHP is installed on client via X-FirePHP-Version header + if (@preg_match_all('/^([\.\d]*)$/si',$this->getRequestHeader("X-FirePHP-Version"),$m) && + version_compare($m[1][0],'0.0.6','>=')) { + return true; + } + return false; + } + + /** + * Log varible to Firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object The variable to be logged + * @return true Return TRUE if message was added to headers, FALSE otherwise + * @throws Exception + */ + public function fb($Object) + { + if($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) { + if(!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message + $this->_logUpgradeClientMessage(); + } + } + + static $insightGroupStack = array(); + + if (!$this->getEnabled()) { + return false; + } + + if ($this->headersSent($filename, $linenum)) { + // If we are logging from within the exception handler we cannot throw another exception + if ($this->inExceptionHandler) { + // Simply echo the error out to the page + echo '
FirePHP ERROR: Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.
'; + } else { + throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.'); + } + } + + $Type = null; + $Label = null; + $Options = array(); + + if (func_num_args()==1) { + } else + if (func_num_args()==2) { + switch(func_get_arg(1)) { + case self::LOG: + case self::INFO: + case self::WARN: + case self::ERROR: + case self::DUMP: + case self::TRACE: + case self::EXCEPTION: + case self::TABLE: + case self::GROUP_START: + case self::GROUP_END: + $Type = func_get_arg(1); + break; + default: + $Label = func_get_arg(1); + break; + } + } else + if (func_num_args()==3) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + } else + if (func_num_args()==4) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + $Options = func_get_arg(3); + } else { + throw $this->newException('Wrong number of arguments to fb() function!'); + } + + if($this->logToInsightConsole!==null && (get_class($this)=='FirePHP_Insight' || is_subclass_of($this, 'FirePHP_Insight'))) { + $msg = $this->logToInsightConsole; + if ($Object instanceof Exception) { + $Type = self::EXCEPTION; + } + if($Label && $Type!=self::TABLE && $Type!=self::GROUP_START) { + $msg = $msg->label($Label); + } + switch($Type) { + case self::DUMP: + case self::LOG: + return $msg->log($Object); + case self::INFO: + return $msg->info($Object); + case self::WARN: + return $msg->warn($Object); + case self::ERROR: + return $msg->error($Object); + case self::TRACE: + return $msg->trace($Object); + case self::EXCEPTION: + return $this->plugin('engine')->handleException($Object, $msg); + case self::TABLE: + if (isset($Object[0]) && !is_string($Object[0]) && $Label) { + $Object = array($Label, $Object); + } + return $msg->table($Object[0], array_slice($Object[1],1), $Object[1][0]); + case self::GROUP_START: + $insightGroupStack[] = $msg->group(md5($Label))->open(); + return $msg->log($Label); + case self::GROUP_END: + if(count($insightGroupStack)==0) { + throw new Error('Too many groupEnd() as opposed to group() calls!'); + } + $group = array_pop($insightGroupStack); + return $group->close(); + default: + return $msg->log($Object); + } + } + + if (!$this->detectClientExtension()) { + return false; + } + + $meta = array(); + $skipFinalObjectEncode = false; + + if ($Object instanceof Exception) { + + $meta['file'] = $this->_escapeTraceFile($Object->getFile()); + $meta['line'] = $Object->getLine(); + + $trace = $Object->getTrace(); + if ($Object instanceof ErrorException + && isset($trace[0]['function']) + && $trace[0]['function']=='errorHandler' + && isset($trace[0]['class']) + && $trace[0]['class']=='FirePHP') { + + $severity = false; + switch($Object->getSeverity()) { + case E_WARNING: $severity = 'E_WARNING'; break; + case E_NOTICE: $severity = 'E_NOTICE'; break; + case E_USER_ERROR: $severity = 'E_USER_ERROR'; break; + case E_USER_WARNING: $severity = 'E_USER_WARNING'; break; + case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break; + case E_STRICT: $severity = 'E_STRICT'; break; + case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break; + case E_DEPRECATED: $severity = 'E_DEPRECATED'; break; + case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break; + } + + $Object = array('Class'=>get_class($Object), + 'Message'=>$severity.': '.$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'trigger', + 'Trace'=>$this->_escapeTrace(array_splice($trace,2))); + $skipFinalObjectEncode = true; + } else { + $Object = array('Class'=>get_class($Object), + 'Message'=>$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'throw', + 'Trace'=>$this->_escapeTrace($trace)); + $skipFinalObjectEncode = true; + } + $Type = self::EXCEPTION; + + } else + if ($Type==self::TRACE) { + + $trace = debug_backtrace(); + if (!$trace) return false; + for( $i=0 ; $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if (isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if ($trace[$i]['function']=='fb' + || $trace[$i]['function']=='trace' + || $trace[$i]['function']=='send') { + + $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'', + 'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'', + 'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'', + 'Message'=>$trace[$i]['args'][0], + 'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'', + 'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'', + 'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'', + 'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1))); + + $skipFinalObjectEncode = true; + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + + } else + if ($Type==self::TABLE) { + + if (isset($Object[0]) && is_string($Object[0])) { + $Object[1] = $this->encodeTable($Object[1]); + } else { + $Object = $this->encodeTable($Object); + } + + $skipFinalObjectEncode = true; + + } else + if ($Type==self::GROUP_START) { + + if (!$Label) { + throw $this->newException('You must specify a label for the group!'); + } + + } else { + if ($Type===null) { + $Type = self::LOG; + } + } + + if ($this->options['includeLineNumbers']) { + if (!isset($meta['file']) || !isset($meta['line'])) { + + $trace = debug_backtrace(); + for( $i=0 ; $trace && $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if (isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if (isset($trace[$i]['file']) + && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip FB::fb() */ + } else { + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + } + } else { + unset($meta['file']); + unset($meta['line']); + } + + $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); + $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION); + + $structure_index = 1; + if ($Type==self::DUMP) { + $structure_index = 2; + $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); + } else { + $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); + } + + if ($Type==self::DUMP) { + $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}'; + } else { + $msg_meta = $Options; + $msg_meta['Type'] = $Type; + if ($Label!==null) { + $msg_meta['Label'] = $Label; + } + if (isset($meta['file']) && !isset($msg_meta['File'])) { + $msg_meta['File'] = $meta['file']; + } + if (isset($meta['line']) && !isset($msg_meta['Line'])) { + $msg_meta['Line'] = $meta['line']; + } + $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']'; + } + + $parts = explode("\n",chunk_split($msg, 5000, "\n")); + + for( $i=0 ; $i2) { + // Message needs to be split into multiple parts + $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + (($i==0)?strlen($msg):'') + . '|' . $part . '|' + . (($isetHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + strlen($part) . '|' . $part . '|'); + } + + $this->messageIndex++; + + if ($this->messageIndex > 99999) { + throw $this->newException('Maximum number (99,999) of messages reached!'); + } + } + } + + $this->setHeader('X-Wf-1-Index',$this->messageIndex-1); + + return true; + } + + /** + * Standardizes path for windows systems. + * + * @param string $Path + * @return string + */ + protected function _standardizePath($Path) + { + return preg_replace('/\\\\+/','/',$Path); + } + + /** + * Escape trace path for windows systems + * + * @param array $Trace + * @return array + */ + protected function _escapeTrace($Trace) + { + if (!$Trace) return $Trace; + for( $i=0 ; $i_escapeTraceFile($Trace[$i]['file']); + } + if (isset($Trace[$i]['args'])) { + $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']); + } + } + return $Trace; + } + + /** + * Escape file information of trace for windows systems + * + * @param string $File + * @return string + */ + protected function _escapeTraceFile($File) + { + /* Check if we have a windows filepath */ + if (strpos($File,'\\')) { + /* First strip down to single \ */ + + $file = preg_replace('/\\\\+/','\\',$File); + + return $file; + } + return $File; + } + + /** + * Check if headers have already been sent + * + * @param string $Filename + * @param integer $Linenum + */ + protected function headersSent(&$Filename, &$Linenum) + { + return headers_sent($Filename, $Linenum); + } + + /** + * Send header + * + * @param string $Name + * @param string $Value + */ + protected function setHeader($Name, $Value) + { + return header($Name.': '.$Value); + } + + /** + * Get user agent + * + * @return string|false + */ + protected function getUserAgent() + { + if (!isset($_SERVER['HTTP_USER_AGENT'])) return false; + return $_SERVER['HTTP_USER_AGENT']; + } + + /** + * Get all request headers + * + * @return array + */ + public static function getAllRequestHeaders() { + static $_cached_headers = false; + if($_cached_headers!==false) { + return $_cached_headers; + } + $headers = array(); + if(function_exists('getallheaders')) { + foreach( getallheaders() as $name => $value ) { + $headers[strtolower($name)] = $value; + } + } else { + foreach($_SERVER as $name => $value) { + if(substr($name, 0, 5) == 'HTTP_') { + $headers[strtolower(str_replace(' ', '-', str_replace('_', ' ', substr($name, 5))))] = $value; + } + } + } + return $_cached_headers = $headers; + } + + /** + * Get a request header + * + * @return string|false + */ + protected function getRequestHeader($Name) + { + $headers = self::getAllRequestHeaders(); + if (isset($headers[strtolower($Name)])) { + return $headers[strtolower($Name)]; + } + return false; + } + + /** + * Returns a new exception + * + * @param string $Message + * @return Exception + */ + protected function newException($Message) + { + return new Exception($Message); + } + + /** + * Encode an object into a JSON string + * + * Uses PHP's jeson_encode() if available + * + * @param object $Object The object to be encoded + * @return string The JSON string + */ + public function jsonEncode($Object, $skipObjectEncode = false) + { + if (!$skipObjectEncode) { + $Object = $this->encodeObject($Object); + } + + if (function_exists('json_encode') + && $this->options['useNativeJsonEncode']!=false) { + + return json_encode($Object); + } else { + return $this->json_encode($Object); + } + } + + /** + * Encodes a table by encoding each row and column with encodeObject() + * + * @param array $Table The table to be encoded + * @return array + */ + protected function encodeTable($Table) + { + + if (!$Table) return $Table; + + $new_table = array(); + foreach($Table as $row) { + + if (is_array($row)) { + $new_row = array(); + + foreach($row as $item) { + $new_row[] = $this->encodeObject($item); + } + + $new_table[] = $new_row; + } + } + + return $new_table; + } + + /** + * Encodes an object including members with + * protected and private visibility + * + * @param Object $Object The object to be encoded + * @param int $Depth The current traversal depth + * @return array All members of the object + */ + protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1, $MaxDepth = 1) + { + if ($MaxDepth > $this->options['maxDepth']) { + return '** Max Depth ('.$this->options['maxDepth'].') **'; + } + + $return = array(); + + if (is_resource($Object)) { + + return '** '.(string)$Object.' **'; + + } else + if (is_object($Object)) { + + if ($ObjectDepth > $this->options['maxObjectDepth']) { + return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **'; + } + + foreach ($this->objectStack as $refVal) { + if ($refVal === $Object) { + return '** Recursion ('.get_class($Object).') **'; + } + } + array_push($this->objectStack, $Object); + + $return['__className'] = $class = get_class($Object); + $class_lower = strtolower($class); + + $reflectionClass = new ReflectionClass($class); + $properties = array(); + foreach( $reflectionClass->getProperties() as $property) { + $properties[$property->getName()] = $property; + } + + $members = (array)$Object; + + foreach( $properties as $plain_name => $property ) { + + $name = $raw_name = $plain_name; + if ($property->isStatic()) { + $name = 'static:'.$name; + } + if ($property->isPublic()) { + $name = 'public:'.$name; + } else + if ($property->isPrivate()) { + $name = 'private:'.$name; + $raw_name = "\0".$class."\0".$raw_name; + } else + if ($property->isProtected()) { + $name = 'protected:'.$name; + $raw_name = "\0".'*'."\0".$raw_name; + } + + if (!(isset($this->objectFilters[$class_lower]) + && is_array($this->objectFilters[$class_lower]) + && in_array($plain_name,$this->objectFilters[$class_lower]))) { + + if (array_key_exists($raw_name,$members) + && !$property->isStatic()) { + + $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1, $MaxDepth + 1); + + } else { + if (method_exists($property,'setAccessible')) { + $property->setAccessible(true); + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); + } else + if ($property->isPublic()) { + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); + } else { + $return[$name] = '** Need PHP 5.3 to get value **'; + } + } + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + + // Include all members that are not defined in the class + // but exist in the object + foreach( $members as $raw_name => $value ) { + + $name = $raw_name; + + if ($name{0} == "\0") { + $parts = explode("\0", $name); + $name = $parts[2]; + } + + $plain_name = $name; + + if (!isset($properties[$name])) { + $name = 'undeclared:'.$name; + + if (!(isset($this->objectFilters[$class_lower]) + && is_array($this->objectFilters[$class_lower]) + && in_array($plain_name,$this->objectFilters[$class_lower]))) { + + $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1, $MaxDepth + 1); + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + } + + array_pop($this->objectStack); + + } elseif (is_array($Object)) { + + if ($ArrayDepth > $this->options['maxArrayDepth']) { + return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **'; + } + + foreach ($Object as $key => $val) { + + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($key=='GLOBALS' + && is_array($val) + && array_key_exists('GLOBALS',$val)) { + $val['GLOBALS'] = '** Recursion (GLOBALS) **'; + } + + $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1, $MaxDepth + 1); + } + } else { + if (self::is_utf8($Object)) { + return $Object; + } else { + return utf8_encode($Object); + } + } + return $return; + } + + /** + * Returns true if $string is valid UTF-8 and false otherwise. + * + * @param mixed $str String to be tested + * @return boolean + */ + protected static function is_utf8($str) + { + if(function_exists('mb_detect_encoding')) { + return (mb_detect_encoding($str) == 'UTF-8'); + } + $c=0; $b=0; + $bits=0; + $len=strlen($str); + for($i=0; $i<$len; $i++){ + $c=ord($str[$i]); + if ($c > 128){ + if (($c >= 254)) return false; + elseif ($c >= 252) $bits=6; + elseif ($c >= 248) $bits=5; + elseif ($c >= 240) $bits=4; + elseif ($c >= 224) $bits=3; + elseif ($c >= 192) $bits=2; + else return false; + if (($i+$bits) > $len) return false; + while($bits > 1){ + $i++; + $b=ord($str[$i]); + if ($b < 128 || $b > 191) return false; + $bits--; + } + } + } + return true; + } + + /** + * Converts to and from JSON format. + * + * JSON (JavaScript Object Notation) is a lightweight data-interchange + * format. It is easy for humans to read and write. It is easy for machines + * to parse and generate. It is based on a subset of the JavaScript + * Programming Language, Standard ECMA-262 3rd Edition - December 1999. + * This feature can also be found in Python. JSON is a text format that is + * completely language independent but uses conventions that are familiar + * to programmers of the C-family of languages, including C, C++, C#, Java, + * JavaScript, Perl, TCL, and many others. These properties make JSON an + * ideal data-interchange language. + * + * This package provides a simple encoder and decoder for JSON notation. It + * is intended for use with client-side Javascript applications that make + * use of HTTPRequest to perform server communication functions - data can + * be encoded into JSON notation for use in a client-side javascript, or + * decoded from incoming Javascript requests. JSON format is native to + * Javascript, and can be directly eval()'ed with no further parsing + * overhead + * + * All strings should be in ASCII or UTF-8 format! + * + * LICENSE: Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: Redistributions of source code must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @category + * @package Services_JSON + * @author Michal Migurski + * @author Matt Knapp + * @author Brett Stimmerman + * @author Christoph Dorn + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + + + /** + * Keep a list of objects as we descend into the array so we can detect recursion. + */ + private $json_objectStack = array(); + + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + private function json_utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + private function json_encode($var) + { + + if (is_object($var)) { + if (in_array($var,$this->json_objectStack)) { + return '"** Recursion **"'; + } + } + + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($var), + array_values($var)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if ($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + $this->json_objectStack[] = $var; + + // treat it like a regular array + $elements = array_map(array($this, 'json_encode'), $var); + + array_pop($this->json_objectStack); + + foreach($elements as $element) { + if ($element instanceof Exception) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = self::encodeObject($var); + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($vars), + array_values($vars)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if ($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return null; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + private function json_name_value($name, $value) + { + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($name=='GLOBALS' + && is_array($value) + && array_key_exists('GLOBALS',$value)) { + $value['GLOBALS'] = '** Recursion **'; + } + + $encoded_value = $this->json_encode($value); + + if ($encoded_value instanceof Exception) { + return $encoded_value; + } + + return $this->json_encode(strval($name)) . ':' . $encoded_value; + } + + /** + * @deprecated + */ + public function setProcessorUrl($URL) + { + trigger_error("The FirePHP::setProcessorUrl() method is no longer supported", E_USER_DEPRECATED); + } + + /** + * @deprecated + */ + public function setRendererUrl($URL) + { + trigger_error("The FirePHP::setRendererUrl() method is no longer supported", E_USER_DEPRECATED); + } +} diff --git a/ThinkPHP/Extend/Behavior/RobotCheckBehavior.class.php b/ThinkPHP/Extend/Behavior/RobotCheckBehavior.class.php new file mode 100644 index 0000000..f1600c2 --- /dev/null +++ b/ThinkPHP/Extend/Behavior/RobotCheckBehavior.class.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 机器人检测 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class RobotCheckBehavior extends Behavior { + protected $options = array( + 'LIMIT_ROBOT_VISIT' => true, // 禁止机器人访问 + ); + public function run(&$params) { + // 机器人访问检测 + if(C('LIMIT_ROBOT_VISIT') && self::isRobot()) { + // 禁止机器人访问 + exit('Access Denied'); + } + } + + static private function isRobot() { + static $_robot = null; + if(is_null($_robot)) { + $spiders = 'Bot|Crawl|Spider|slurp|sohu-search|lycos|robozilla'; + $browsers = 'MSIE|Netscape|Opera|Konqueror|Mozilla'; + if(preg_match("/($browsers)/", $_SERVER['HTTP_USER_AGENT'])) { + $_robot = false ; + } elseif(preg_match("/($spiders)/", $_SERVER['HTTP_USER_AGENT'])) { + $_robot = true; + } else { + $_robot = false; + } + } + return $_robot; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Behavior/UpgradeNoticeBehavior.class.php b/ThinkPHP/Extend/Behavior/UpgradeNoticeBehavior.class.php new file mode 100644 index 0000000..ee10f19 --- /dev/null +++ b/ThinkPHP/Extend/Behavior/UpgradeNoticeBehavior.class.php @@ -0,0 +1,127 @@ + +// +---------------------------------------------------------------------- +defined('THINK_PATH') or exit(); +/** + * 升级短信通知, 如果有ThinkPHP新版升级,或者重要的更新,会发送短信通知你。 + * 需要使用SAE的短信服务。请先找一个SAE的应用开通短信服务。 + * 使用步骤如下: + * 1,在项目的Conf目录下建立tags.php配置文件,内容如下: + * + * array('UpgradeNotice') + * ); + * + * + * 2,将此文件放在项目的Lib/Behavior文件夹下。 + *注:在SAE上面使用时,以上两步可以省略 + * 3,在config.php中配置: + * 'UPGRADE_NOTICE_ON'=>true,//开启短信升级提醒功能 + * 'UPGRADE_NOTICE_AKEY'=>'your akey',//SAE应用的AKEY,如果在SAE上使用可以不填 + * 'UPGRADE_NOTICE_SKEY'=>'your skey',//SAE应用的SKEY,如果在SAE上使用可以不填 + *'UPGRADE_NOTICE_MOBILE'=>'136456789',//接受短信的手机号 + *'UPGRADE_NOTICE_CHECK_INTERVAL' => 604800,//检测频率,单位秒,默认是一周 + *'UPGRADE_CURRENT_VERSION'=>'0',//升级后的版本号,会在短信中告诉你填写什么 + *UPGRADE_NOTICE_DEBUG=>true, //调试默认,如果为true,UPGRADE_NOTICE_CHECK_INTERVAL配置不起作用,每次都会进行版本检查,此时用于调试,调试完毕后请设置次配置为false + * + */ + +class UpgradeNoticeBehavior extends Behavior { + // 行为参数定义(默认值) 可在项目配置中覆盖 + protected $options = array( + 'UPGRADE_NOTICE_ON' => false, // 是否开启升级提醒 + 'UPGRADE_NOTICE_DEBUG'=>false, + 'UPGRADE_NOTICE_QUEUE'=>'',//队列名称, 在SAE平台上设置 + 'UPGRADE_NOTICE_AKEY' => '', //SAE应用的AKEY + 'UPGRADE_NOTICE_SKEY' => '', //SAE应用的SKEY + 'UPGRADE_NOTICE_MOBILE' => '', //接受短信的手机号 + 'UPGRADE_CURRENT_VERSION'=>'0', + 'UPGRADE_NOTICE_CHECK_INTERVAL' => 604800, //检测频率,单位秒,默认是一周 + ); + protected $header_ = ''; + protected $httpCode_; + protected $httpDesc_; + protected $accesskey_; + protected $secretkey_; + public function run(&$params) { + if (C('UPGRADE_NOTICE_ON') && (!S('think_upgrade_interval') || C('UPGRADE_NOTICE_DEBUG'))) { + if(IS_SAE && C('UPGRADE_NOTICE_QUEUE') && !isset($_POST['think_upgrade_queque'])){ + $queue=new SaeTaskQueue(C('UPGRADE_NOTICE_QUEUE')); + $queue->addTask('http://'.$_SERVER['HTTP_HOST'].__APP__,'think_upgrade_queque=1'); + if(!$queue->push()){ + trace('升级提醒队列执行失败,错误原因:'.$queue->errmsg(), '升级通知出错', 'NOTIC', true); + } + return ; + } + $akey = C('UPGRADE_NOTICE_AKEY'); + $skey = C('UPGRADE_NOTICE_SKEY'); + $this->accesskey_ = $akey ? $akey : (defined('SAE_ACCESSKEY') ? SAE_ACCESSKEY : ''); + $this->secretkey_ = $skey ? $skey : (defined('SAE_SECRETKEY') ? SAE_SECRETKEY : ''); + $current_version = C('UPGRADE_CURRENT_VERSION'); + //读取接口 + $info = $this->send('http://sinaclouds.sinaapp.com/thinkapi/upgrade.php?v=' . $current_version); + if ($info['version'] != $current_version) { + if($this->send_sms($info['msg'])) trace($info['msg'], '升级通知成功', 'NOTIC', true); //发送升级短信 + } + S('think_upgrade_interval', true, C('UPGRADE_NOTICE_CHECK_INTERVAL')); + } + } + private function send_sms($msg) { + $timestamp=time(); + $url = 'http://inno.smsinter.sina.com.cn/sae_sms_service/sendsms.php'; //发送短信的接口地址 + $content = "FetchUrl" . $url . "TimeStamp" . $timestamp . "AccessKey" . $this->accesskey_; + $signature = (base64_encode(hash_hmac('sha256', $content, $this->secretkey_, true))); + $headers = array( + "FetchUrl: $url", + "AccessKey: ".$this->accesskey_, + "TimeStamp: " . $timestamp, + "Signature: $signature" + ); + $data = array( + 'mobile' => C('UPGRADE_NOTICE_MOBILE') , + 'msg' => $msg, + 'encoding' => 'UTF-8' + ); + if(!$ret = $this->send('http://g.apibus.io', $data, $headers)){ + return false; + } + if (isset($ret['ApiBusError'])) { + trace('errno:' . $ret['ApiBusError']['errcode'] . ',errmsg:' . $ret['ApiBusError']['errdesc'], '升级通知出错', 'NOTIC', true); + + return false; + } + + return true; + } + private function send($url, $params = array() , $headers = array()) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + if (!empty($params)) { + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $params); + } + if (!empty($headers)) curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $txt = curl_exec($ch); + if (curl_errno($ch)) { + trace(curl_error($ch) , '升级通知出错', 'NOTIC', true); + + return false; + } + curl_close($ch); + $ret = json_decode($txt, true); + if (!$ret) { + trace('接口[' . $url . ']返回格式不正确', '升级通知出错', 'NOTIC', true); + + return false; + } + + return $ret; + } +} diff --git a/ThinkPHP/Extend/Driver/Cache/CacheApachenote.class.php b/ThinkPHP/Extend/Driver/Cache/CacheApachenote.class.php new file mode 100644 index 0000000..dc930de --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheApachenote.class.php @@ -0,0 +1,127 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Apachenote缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver + * @author liu21st + */ +class CacheApachenote extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if(!empty($options)) { + $this->options = $options; + } + if(empty($options)) { + $options = array ( + 'host' => '127.0.0.1', + 'port' => 1042, + 'timeout' => 10, + ); + } + $this->options = $options; + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->handler = null; + $this->open(); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + $this->open(); + $name = $this->options['prefix'].$name; + $s = 'F' . pack('N', strlen($name)) . $name; + fwrite($this->handler, $s); + + for ($data = ''; !feof($this->handler);) { + $data .= fread($this->handler, 4096); + } + N('cache_read',1); + $this->close(); + return $data === '' ? '' : unserialize($data); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @return boolen + */ + public function set($name, $value) { + N('cache_write',1); + $this->open(); + $value = serialize($value); + $name = $this->options['prefix'].$name; + $s = 'S' . pack('NN', strlen($name), strlen($value)) . $name . $value; + + fwrite($this->handler, $s); + $ret = fgets($this->handler); + $this->close(); + if($ret === "OK\n") { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + $this->open(); + $name = $this->options['prefix'].$name; + $s = 'D' . pack('N', strlen($name)) . $name; + fwrite($this->handler, $s); + $ret = fgets($this->handler); + $this->close(); + return $ret === "OK\n"; + } + + /** + * 关闭缓存 + * @access private + */ + private function close() { + fclose($this->handler); + $this->handler = false; + } + + /** + * 打开缓存 + * @access private + */ + private function open() { + if (!is_resource($this->handler)) { + $this->handler = fsockopen($this->options['host'], $this->options['port'], $_, $_, $this->options['timeout']); + } + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Cache/CacheApc.class.php b/ThinkPHP/Extend/Driver/Cache/CacheApc.class.php new file mode 100644 index 0000000..6538bae --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheApc.class.php @@ -0,0 +1,89 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Apc缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheApc extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if(!function_exists('apc_cache_info')) { + throw_exception(L('_NOT_SUPPERT_').':Apc'); + } + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + return apc_fetch($this->options['prefix'].$name); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + if($result = apc_store($name, $value, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + } + return $result; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return apc_delete($this->options['prefix'].$name); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return apc_clear_cache(); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Cache/CacheDb.class.php b/ThinkPHP/Extend/Driver/Cache/CacheDb.class.php new file mode 100644 index 0000000..f9b685b --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheDb.class.php @@ -0,0 +1,142 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 数据库方式缓存驱动 + * CREATE TABLE think_cache ( + * cachekey varchar(255) NOT NULL, + * expire int(11) NOT NULL, + * data blob, + * datacrc int(32), + * UNIQUE KEY `cachekey` (`cachekey`) + * ); + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheDb extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if(empty($options)) { + $options = array ( + 'table' => C('DATA_CACHE_TABLE'), + ); + } + $this->options = $options; + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + import('Db'); + $this->handler = DB::getInstance(); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + $name = $this->options['prefix'].addslashes($name); + N('cache_read',1); + $result = $this->handler->query('SELECT `data`,`datacrc` FROM `'.$this->options['table'].'` WHERE `cachekey`=\''.$name.'\' AND (`expire` =0 OR `expire`>'.time().') LIMIT 0,1'); + if(false !== $result ) { + $result = $result[0]; + if(C('DATA_CACHE_CHECK')) {//开启数据校验 + if($result['datacrc'] != md5($result['data'])) {//校验错误 + return false; + } + } + $content = $result['data']; + if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //启用数据压缩 + $content = gzuncompress($content); + } + $content = unserialize($content); + return $content; + } + else { + return false; + } + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value,$expire=null) { + $data = serialize($value); + $name = $this->options['prefix'].addslashes($name); + N('cache_write',1); + if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //数据压缩 + $data = gzcompress($data,3); + } + if(C('DATA_CACHE_CHECK')) {//开启数据校验 + $crc = md5($data); + }else { + $crc = ''; + } + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $expire = ($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存 + $result = $this->handler->query('select `cachekey` from `'.$this->options['table'].'` where `cachekey`=\''.$name.'\' limit 0,1'); + if(!empty($result) ) { + //更新记录 + $result = $this->handler->execute('UPDATE '.$this->options['table'].' SET data=\''.$data.'\' ,datacrc=\''.$crc.'\',expire='.$expire.' WHERE `cachekey`=\''.$name.'\''); + }else { + //新增记录 + $result = $this->handler->execute('INSERT INTO '.$this->options['table'].' (`cachekey`,`data`,`datacrc`,`expire`) VALUES (\''.$name.'\',\''.$data.'\',\''.$crc.'\','.$expire.')'); + } + if($result) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + }else { + return false; + } + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + $name = $this->options['prefix'].addslashes($name); + return $this->handler->execute('DELETE FROM `'.$this->options['table'].'` WHERE `cachekey`=\''.$name.'\''); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return $this->handler->execute('TRUNCATE TABLE `'.$this->options['table'].'`'); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Cache/CacheEaccelerator.class.php b/ThinkPHP/Extend/Driver/Cache/CacheEaccelerator.class.php new file mode 100644 index 0000000..98a9db3 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheEaccelerator.class.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Eaccelerator缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheEaccelerator extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + return eaccelerator_get($this->options['prefix'].$name); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + eaccelerator_lock($name); + if(eaccelerator_put($name, $value, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return eaccelerator_rm($this->options['prefix'].$name); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Cache/CacheMemcache.class.php b/ThinkPHP/Extend/Driver/Cache/CacheMemcache.class.php new file mode 100644 index 0000000..114d434 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheMemcache.class.php @@ -0,0 +1,106 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Memcache缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheMemcache extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + function __construct($options=array()) { + if ( !extension_loaded('memcache') ) { + throw_exception(L('_NOT_SUPPERT_').':memcache'); + } + + $options = array_merge(array ( + 'host' => C('MEMCACHE_HOST') ? C('MEMCACHE_HOST') : '127.0.0.1', + 'port' => C('MEMCACHE_PORT') ? C('MEMCACHE_PORT') : 11211, + 'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false, + 'persistent' => false, + ),$options); + + $this->options = $options; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $func = $options['persistent'] ? 'pconnect' : 'connect'; + $this->handler = new Memcache; + $options['timeout'] === false ? + $this->handler->$func($options['host'], $options['port']) : + $this->handler->$func($options['host'], $options['port'], $options['timeout']); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + return $this->handler->get($this->options['prefix'].$name); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + if($this->handler->set($name, $value, 0, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name, $ttl = false) { + $name = $this->options['prefix'].$name; + return $ttl === false ? + $this->handler->delete($name) : + $this->handler->delete($name, $ttl); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return $this->handler->flush(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Cache/CacheRedis.class.php b/ThinkPHP/Extend/Driver/Cache/CacheRedis.class.php new file mode 100644 index 0000000..1c7ff52 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheRedis.class.php @@ -0,0 +1,111 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); + +/** + * Redis缓存驱动 + * 要求安装phpredis扩展:https://github.com/nicolasff/phpredis + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author 尘缘 <130775@qq.com> + */ +class CacheRedis extends Cache { + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !extension_loaded('redis') ) { + throw_exception(L('_NOT_SUPPERT_').':redis'); + } + if(empty($options)) { + $options = array ( + 'host' => C('REDIS_HOST') ? C('REDIS_HOST') : '127.0.0.1', + 'port' => C('REDIS_PORT') ? C('REDIS_PORT') : 6379, + 'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false, + 'persistent' => false, + ); + } + $this->options = $options; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $func = $options['persistent'] ? 'pconnect' : 'connect'; + $this->handler = new Redis; + $options['timeout'] === false ? + $this->handler->$func($options['host'], $options['port']) : + $this->handler->$func($options['host'], $options['port'], $options['timeout']); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + $value = $this->handler->get($this->options['prefix'].$name); + $jsonData = json_decode( $value, true ); + return ($jsonData === NULL) ? $value : $jsonData; //检测是否为JSON数据 true 返回JSON解析数组, false返回源数据 + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + //对数组/对象数据进行缓存处理,保证数据完整性 + $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value; + if(is_int($expire)) { + $result = $this->handler->setex($name, $expire, $value); + }else{ + $result = $this->handler->set($name, $value); + } + if($result && $this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return $result; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return $this->handler->delete($this->options['prefix'].$name); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return $this->handler->flushDB(); + } + +} diff --git a/ThinkPHP/Extend/Driver/Cache/CacheShmop.class.php b/ThinkPHP/Extend/Driver/Cache/CacheShmop.class.php new file mode 100644 index 0000000..2c33d18 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheShmop.class.php @@ -0,0 +1,189 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Shmop缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheShmop extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !extension_loaded('shmop') ) { + throw_exception(L('_NOT_SUPPERT_').':shmop'); + } + if(!empty($options)){ + $options = array( + 'size' => C('SHARE_MEM_SIZE'), + 'temp' => TEMP_PATH, + 'project' => 's', + 'length' => 0, + ); + } + $this->options = $options; + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->handler = $this->_ftok($this->options['project']); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name = false) { + N('cache_read',1); + $id = shmop_open($this->handler, 'c', 0600, 0); + if ($id !== false) { + $ret = unserialize(shmop_read($id, 0, shmop_size($id))); + shmop_close($id); + + if ($name === false) { + return $ret; + } + $name = $this->options['prefix'].$name; + if(isset($ret[$name])) { + $content = $ret[$name]; + if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //启用数据压缩 + $content = gzuncompress($content); + } + return $content; + }else { + return null; + } + }else { + return false; + } + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @return boolen + */ + public function set($name, $value) { + N('cache_write',1); + $lh = $this->_lock(); + $val = $this->get(); + if (!is_array($val)) $val = array(); + if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //数据压缩 + $value = gzcompress($value,3); + } + $name = $this->options['prefix'].$name; + $val[$name] = $value; + $val = serialize($val); + if($this->_write($val, $lh)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + $lh = $this->_lock(); + $val = $this->get(); + if (!is_array($val)) $val = array(); + $name = $this->options['prefix'].$name; + unset($val[$name]); + $val = serialize($val); + return $this->_write($val, $lh); + } + + /** + * 生成IPC key + * @access private + * @param string $project 项目标识名 + * @return integer + */ + private function _ftok($project) { + if (function_exists('ftok')) return ftok(__FILE__, $project); + if(strtoupper(PHP_OS) == 'WINNT'){ + $s = stat(__FILE__); + return sprintf("%u", (($s['ino'] & 0xffff) | (($s['dev'] & 0xff) << 16) | + (($project & 0xff) << 24))); + }else { + $filename = __FILE__ . (string) $project; + for($key = array(); sizeof($key) < strlen($filename); $key[] = ord(substr($filename, sizeof($key), 1))); + return dechex(array_sum($key)); + } + } + + /** + * 写入操作 + * @access private + * @param string $name 缓存变量名 + * @return integer|boolen + */ + private function _write(&$val, &$lh) { + $id = shmop_open($this->handler, 'c', 0600, $this->options['size']); + if ($id) { + $ret = shmop_write($id, $val, 0) == strlen($val); + shmop_close($id); + $this->_unlock($lh); + return $ret; + } + $this->_unlock($lh); + return false; + } + + /** + * 共享锁定 + * @access private + * @param string $name 缓存变量名 + * @return boolen + */ + private function _lock() { + if (function_exists('sem_get')) { + $fp = sem_get($this->handler, 1, 0600, 1); + sem_acquire ($fp); + } else { + $fp = fopen($this->options['temp'].$this->options['prefix'].md5($this->handler), 'w'); + flock($fp, LOCK_EX); + } + return $fp; + } + + /** + * 解除共享锁定 + * @access private + * @param string $name 缓存变量名 + * @return boolen + */ + private function _unlock(&$fp) { + if (function_exists('sem_release')) { + sem_release($fp); + } else { + fclose($fp); + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Cache/CacheSqlite.class.php b/ThinkPHP/Extend/Driver/Cache/CacheSqlite.class.php new file mode 100644 index 0000000..97ed9ce --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheSqlite.class.php @@ -0,0 +1,122 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Sqlite缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheSqlite extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !extension_loaded('sqlite') ) { + throw_exception(L('_NOT_SUPPERT_').':sqlite'); + } + if(empty($options)) { + $options = array ( + 'db' => ':memory:', + 'table' => 'sharedmemory', + ); + } + $this->options = $options; + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + + $func = $this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open'; + $this->handler = $func($this->options['db']); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + $name = $this->options['prefix'].sqlite_escape_string($name); + $sql = 'SELECT value FROM '.$this->options['table'].' WHERE var=\''.$name.'\' AND (expire=0 OR expire >'.time().') LIMIT 1'; + $result = sqlite_query($this->handler, $sql); + if (sqlite_num_rows($result)) { + $content = sqlite_fetch_single($result); + if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //启用数据压缩 + $content = gzuncompress($content); + } + return unserialize($content); + } + return false; + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value,$expire=null) { + N('cache_write',1); + $name = $this->options['prefix'].sqlite_escape_string($name); + $value = sqlite_escape_string(serialize($value)); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $expire = ($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存 + if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //数据压缩 + $value = gzcompress($value,3); + } + $sql = 'REPLACE INTO '.$this->options['table'].' (var, value,expire) VALUES (\''.$name.'\', \''.$value.'\', \''.$expire.'\')'; + if(sqlite_query($this->handler, $sql)){ + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + $name = $this->options['prefix'].sqlite_escape_string($name); + $sql = 'DELETE FROM '.$this->options['table'].' WHERE var=\''.$name.'\''; + sqlite_query($this->handler, $sql); + return true; + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + $sql = 'DELETE FROM '.$this->options['table']; + sqlite_query($this->handler, $sql); + return ; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Cache/CacheWincache.class.php b/ThinkPHP/Extend/Driver/Cache/CacheWincache.class.php new file mode 100644 index 0000000..cd9e7f7 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheWincache.class.php @@ -0,0 +1,82 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Wincache缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheWincache extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !function_exists('wincache_ucache_info') ) { + throw_exception(L('_NOT_SUPPERT_').':WinCache'); + } + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + $name = $this->options['prefix'].$name; + return wincache_ucache_exists($name)? wincache_ucache_get($name) : false; + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value,$expire=null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + if(wincache_ucache_set($name, $value, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return wincache_ucache_delete($this->options['prefix'].$name); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Cache/CacheXcache.class.php b/ThinkPHP/Extend/Driver/Cache/CacheXcache.class.php new file mode 100644 index 0000000..2011675 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Cache/CacheXcache.class.php @@ -0,0 +1,84 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Xcache缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheXcache extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !function_exists('xcache_info') ) { + throw_exception(L('_NOT_SUPPERT_').':Xcache'); + } + $this->options['expire'] = isset($options['expire'])?$options['expire']:C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])?$options['prefix']:C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])?$options['length']:0; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + $name = $this->options['prefix'].$name; + if (xcache_isset($name)) { + return xcache_get($name); + } + return false; + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value,$expire=null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire'] ; + } + $name = $this->options['prefix'].$name; + if(xcache_set($name, $value, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return xcache_unset($this->options['prefix'].$name); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Db/DbIbase.class.php b/ThinkPHP/Extend/Driver/Db/DbIbase.class.php new file mode 100644 index 0000000..0c7863e --- /dev/null +++ b/ThinkPHP/Extend/Driver/Db/DbIbase.class.php @@ -0,0 +1,338 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Firebird数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author 剑雷 + */ +class DbIbase extends Db{ + + protected $selectSql = 'SELECT %LIMIT% %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%'; + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config='') { + if ( !extension_loaded('interbase') ) { + throw_exception(L('_NOT_SUPPERT_').':Interbase or Firebird'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'ibase_pconnect':'ibase_connect'; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?"/{$config['hostport']}":''); + $this->linkID[$linkNum] = $conn($host.':'.$config['database'], $config['username'], $config['password'],C('DB_CHARSET'),0,3); + if ( !$this->linkID[$linkNum]) { + throw_exception(ibase_errmsg()); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + ibase_free_result($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = ibase_query($this->_linkID, $str); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = ibase_query($this->_linkID, $str) ; + $this->debug(); + if ( false === $result) { + $this->error(); + return false; + } else { + $this->numRows = ibase_affected_rows($this->_linkID); + $this->lastInsID =0; + return $this->numRows; + } + } + + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + ibase_trans( IBASE_DEFAULT, $this->_linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = ibase_commit($this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result =ibase_rollback($this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * BLOB字段解密函数 Firebird特有 + * @access public + * @param $blob 待解密的BLOB + * @return 二进制数据 + */ + public function BlobDecode($blob) { + $maxblobsize = 262144; + $blob_data = ibase_blob_info($this->_linkID, $blob ); + $blobid = ibase_blob_open($this->_linkID, $blob ); + if( $blob_data[0] > $maxblobsize ) { + $realblob = ibase_blob_get($blobid, $maxblobsize); + while($string = ibase_blob_get($blobid, 8192)){ + $realblob .= $string; + } + } else { + $realblob = ibase_blob_get($blobid, $blob_data[0]); + } + ibase_blob_close( $blobid ); + return( $realblob ); + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + while ( $row = ibase_fetch_assoc($this->queryID)) { + $result[] = $row; + } + //剑雷 2007.12.30 自动解密BLOB字段 + //取BLOB字段清单 + $bloblist = array(); + $fieldCount = ibase_num_fields($this->queryID); + for ($i = 0; $i < $fieldCount; $i++) { + $col_info = ibase_field_info($this->queryID, $i); + if ($col_info['type']=='BLOB') { + $bloblist[]=trim($col_info['name']); + } + } + //如果有BLOB字段,就进行解密处理 + if (!empty($bloblist)) { + $i=0; + foreach ($result as $row) { + foreach($bloblist as $field) { + if (!empty($row[$field])) $result[$i][$field]=$this->BlobDecode($row[$field]); + } + $i++; + } + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query('SELECT RDB$FIELD_NAME AS FIELD, RDB$DEFAULT_VALUE AS DEFAULT1, RDB$NULL_FLAG AS NULL1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME=UPPER(\''.$tableName.'\') ORDER By RDB$FIELD_POSITION'); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[trim($val['FIELD'])] = array( + 'name' => trim($val['FIELD']), + 'type' => '', + 'notnull' => (bool) ($val['NULL1'] ==1), // 1表示不为Null + 'default' => $val['DEFAULT1'], + 'primary' => false, + 'autoinc' => false, + ); + } + } + //剑雷 取表字段类型 + $sql='select first 1 * from '. $tableName; + $rs_temp = ibase_query ($this->_linkID, $sql); + $fieldCount = ibase_num_fields($rs_temp); + + for ($i = 0; $i < $fieldCount; $i++) + { + $col_info = ibase_field_info($rs_temp, $i); + $info[trim($col_info['name'])]['type']=$col_info['type']; + } + ibase_free_result ($rs_temp); + + //剑雷 取表的主键 + $sql='select b.rdb$field_name as FIELD_NAME from rdb$relation_constraints a join rdb$index_segments b +on a.rdb$index_name=b.rdb$index_name +where a.rdb$constraint_type=\'PRIMARY KEY\' and a.rdb$relation_name=UPPER(\''.$tableName.'\')'; + $rs_temp = ibase_query ($this->_linkID, $sql); + while ($row=ibase_fetch_object($rs_temp)) { + $info[trim($row->FIELD_NAME)]['primary']=True; + } + ibase_free_result ($rs_temp); + + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + $sql='SELECT DISTINCT RDB$RELATION_NAME FROM RDB$RELATION_FIELDS WHERE RDB$SYSTEM_FLAG=0'; + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = trim(current($val)); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if ($this->_linkID){ + ibase_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = ibase_errcode().':'.ibase_errmsg(); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + return str_replace("'", "''", $str); + } + + /** + * limit + * @access public + * @param $limit limit表达式 + * @return string + */ + public function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + $limit = explode(',',$limit); + if(count($limit)>1) { + $limitStr = ' FIRST '.($limit[1]-$limit[0]).' SKIP '.$limit[0].' '; + }else{ + $limitStr = ' FIRST '.$limit[0].' '; + } + } + return $limitStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Db/DbMongo.class.php b/ThinkPHP/Extend/Driver/Db/DbMongo.class.php new file mode 100644 index 0000000..9674dd2 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Db/DbMongo.class.php @@ -0,0 +1,756 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Mongo数据库驱动 必须配合MongoModel使用 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +class DbMongo extends Db{ + + protected $_mongo = null; // MongoDb Object + protected $_collection = null; // MongoCollection Object + protected $_dbName = ''; // dbName + protected $_collectionName = ''; // collectionName + protected $_cursor = null; // MongoCursor Object + protected $comparison = array('neq'=>'ne','ne'=>'ne','gt'=>'gt','egt'=>'gte','gte'=>'gte','lt'=>'lt','elt'=>'lte','lte'=>'lte','in'=>'in','not in'=>'nin','nin'=>'nin'); + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !class_exists('mongoClient') ) { + throw_exception(L('_NOT_SUPPERT_').':mongoClient'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $host = 'mongodb://'.($config['username']?"{$config['username']}":'').($config['password']?":{$config['password']}@":'').$config['hostname'].($config['hostport']?":{$config['hostport']}":'').'/'.($config['database']?"{$config['database']}":''); + try{ + $this->linkID[$linkNum] = new mongoClient( $host,$config['params']); + }catch (MongoConnectionException $e){ + throw_exception($e->getmessage()); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 切换当前操作的Db和Collection + * @access public + * @param string $collection collection + * @param string $db db + * @param boolean $master 是否主服务器 + * @return void + */ + public function switchCollection($collection,$db='',$master=true){ + // 当前没有连接 则首先进行数据库连接 + if ( !$this->_linkID ) $this->initConnect($master); + try{ + if(!empty($db)) { // 传人Db则切换数据库 + // 当前MongoDb对象 + $this->_dbName = $db; + $this->_mongo = $this->_linkID->selectDb($db); + } + // 当前MongoCollection对象 + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.getCollection('.$collection.')'; + } + if($this->_collectionName != $collection) { + N('db_read',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->_collection = $this->_mongo->selectCollection($collection); + $this->debug(); + $this->_collectionName = $collection; // 记录当前Collection名称 + } + }catch (MongoException $e){ + throw_exception($e->getMessage()); + } + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->_cursor = null; + } + + /** + * 执行命令 + * @access public + * @param array $command 指令 + * @return array + */ + public function command($command=array()) { + N('db_write',1); + $this->queryStr = 'command:'.json_encode($command); + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_mongo->command($command); + $this->debug(); + if(!$result['ok']) { + throw_exception($result['errmsg']); + } + return $result; + } + + /** + * 执行语句 + * @access public + * @param string $code sql指令 + * @param array $args 参数 + * @return mixed + */ + public function execute($code,$args=array()) { + N('db_write',1); + $this->queryStr = 'execute:'.$code; + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_mongo->execute($code,$args); + $this->debug(); + if($result['ok']) { + return $result['retval']; + }else{ + throw_exception($result['errmsg']); + } + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if($this->_linkID) { + $this->_linkID->close(); + $this->_linkID = null; + $this->_mongo = null; + $this->_collection = null; + $this->_cursor = null; + } + } + + /** + * 数据库错误信息 + * @access public + * @return string + */ + public function error() { + $this->error = $this->_mongo->lastError(); + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insert($data,$options=array(),$replace=false) { + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $this->model = $options['model']; + N('db_write',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.insert('; + $this->queryStr .= $data?json_encode($data):'{}'; + $this->queryStr .= ')'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $replace? $this->_collection->save($data): $this->_collection->insert($data); + $this->debug(); + if($result) { + $_id = $data['_id']; + if(is_object($_id)) { + $_id = $_id->__toString(); + } + $this->lastInsID = $_id; + } + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 插入多条记录 + * @access public + * @param array $dataList 数据 + * @param array $options 参数表达式 + * @return bool + */ + public function insertAll($dataList,$options=array()) { + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $this->model = $options['model']; + N('db_write',1); + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->batchInsert($dataList); + $this->debug(); + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 生成下一条记录ID 用于自增非MongoId主键 + * @access public + * @param string $pk 主键名 + * @return integer + */ + public function mongo_next_id($pk) { + N('db_read',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find({},{'.$pk.':1}).sort({'.$pk.':-1}).limit(1)'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->find(array(),array($pk=>1))->sort(array($pk=>-1))->limit(1); + $this->debug(); + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + $data = $result->getNext(); + return isset($data[$pk])?$data[$pk]+1:1; + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return bool + */ + public function update($data,$options) { + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $this->model = $options['model']; + N('db_write',1); + $query = $this->parseWhere($options['where']); + $set = $this->parseSet($data); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.update('; + $this->queryStr .= $query?json_encode($query):'{}'; + $this->queryStr .= ','.json_encode($set).')'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + if(isset($options['limit']) && $options['limit'] == 1) { + $multiple = array("multiple" => false); + }else{ + $multiple = array("multiple" => true); + } + $result = $this->_collection->update($query,$set,$multiple); + $this->debug(); + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $query = $this->parseWhere($options['where']); + $this->model = $options['model']; + N('db_write',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove('.json_encode($query).')'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->remove($query); + $this->debug(); + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 清空记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function clear($options=array()){ + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $this->model = $options['model']; + N('db_write',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove({})'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->drop(); + $this->debug(); + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return iterator + */ + public function select($options=array()) { + if(isset($options['table'])) { + $this->switchCollection($options['table'],'',false); + } + $cache = isset($options['cache'])?$options['cache']:false; + if($cache) { // 查询缓存检测 + $key = is_string($cache['key'])?$cache['key']:md5(serialize($options)); + $value = S($key,'','',$cache['type']); + if(false !== $value) { + return $value; + } + } + $this->model = $options['model']; + N('db_query',1); + $query = $this->parseWhere($options['where']); + $field = $this->parseField($options['field']); + try{ + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find('; + $this->queryStr .= $query? json_encode($query):'{}'; + $this->queryStr .= $field? ','.json_encode($field):''; + $this->queryStr .= ')'; + } + // 记录开始执行时间 + G('queryStartTime'); + $_cursor = $this->_collection->find($query,$field); + if($options['order']) { + $order = $this->parseOrder($options['order']); + if(C('DB_SQL_LOG')) { + $this->queryStr .= '.sort('.json_encode($order).')'; + } + $_cursor = $_cursor->sort($order); + } + if(isset($options['page'])) { // 根据页数计算limit + if(strpos($options['page'],',')) { + list($page,$length) = explode(',',$options['page']); + }else{ + $page = $options['page']; + } + $page = $page?$page:1; + $length = isset($length)?$length:(is_numeric($options['limit'])?$options['limit']:20); + $offset = $length*((int)$page-1); + $options['limit'] = $offset.','.$length; + } + if(isset($options['limit'])) { + list($offset,$length) = $this->parseLimit($options['limit']); + if(!empty($offset)) { + if(C('DB_SQL_LOG')) { + $this->queryStr .= '.skip('.intval($offset).')'; + } + $_cursor = $_cursor->skip(intval($offset)); + } + if(C('DB_SQL_LOG')) { + $this->queryStr .= '.limit('.intval($length).')'; + } + $_cursor = $_cursor->limit(intval($length)); + } + $this->debug(); + $this->_cursor = $_cursor; + $resultSet = iterator_to_array($_cursor); + if($cache && $resultSet ) { // 查询缓存写入 + S($key,$resultSet,$cache['expire'],$cache['type']); + } + return $resultSet; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 查找某个记录 + * @access public + * @param array $options 表达式 + * @return array + */ + public function find($options=array()){ + if(isset($options['table'])) { + $this->switchCollection($options['table'],'',false); + } + $cache = isset($options['cache'])?$options['cache']:false; + if($cache) { // 查询缓存检测 + $key = is_string($cache['key'])?$cache['key']:md5(serialize($options)); + $value = S($key,'','',$cache['type']); + if(false !== $value) { + return $value; + } + } + $this->model = $options['model']; + N('db_query',1); + $query = $this->parseWhere($options['where']); + $fields = $this->parseField($options['field']); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.findOne('; + $this->queryStr .= $query?json_encode($query):'{}'; + $this->queryStr .= $fields?','.json_encode($fields):''; + $this->queryStr .= ')'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->findOne($query,$fields); + $this->debug(); + if($cache && $result ) { // 查询缓存写入 + S($key,$result,$cache['expire'],$cache['type']); + } + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 统计记录数 + * @access public + * @param array $options 表达式 + * @return iterator + */ + public function count($options=array()){ + if(isset($options['table'])) { + $this->switchCollection($options['table'],'',false); + } + $this->model = $options['model']; + N('db_query',1); + $query = $this->parseWhere($options['where']); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName; + $this->queryStr .= $query?'.find('.json_encode($query).')':''; + $this->queryStr .= '.count()'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $count = $this->_collection->count($query); + $this->debug(); + return $count; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + public function group($keys,$initial,$reduce,$options=array()){ + $this->_collection->group($keys,$initial,$reduce,$options); + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($collection=''){ + if(!empty($collection) && $collection != $this->_collectionName) { + $this->switchCollection($collection,'',false); + } + N('db_query',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.findOne()'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->findOne(); + $this->debug(); + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + if($result) { // 存在数据则分析字段 + $info = array(); + foreach ($result as $key=>$val){ + $info[$key] = array( + 'name'=>$key, + 'type'=>getType($val), + ); + } + return $info; + } + // 暂时没有数据 返回false + return false; + } + + /** + * 取得当前数据库的collection信息 + * @access public + */ + public function getTables(){ + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.getCollenctionNames()'; + } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $list = $this->_mongo->listCollections(); + $this->debug(); + $info = array(); + foreach ($list as $collection){ + $info[] = $collection->getName(); + } + return $info; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + $result = array(); + foreach ($data as $key=>$val){ + if(is_array($val)) { + switch($val[0]) { + case 'inc': + $result['$inc'][$key] = (int)$val[1]; + break; + case 'set': + case 'unset': + case 'push': + case 'pushall': + case 'addtoset': + case 'pop': + case 'pull': + case 'pullall': + $result['$'.$val[0]][$key] = $val[1]; + break; + default: + $result['$set'][$key] = $val; + } + }else{ + $result['$set'][$key] = $val; + } + } + return $result; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return array + */ + protected function parseOrder($order) { + if(is_string($order)) { + $array = explode(',',$order); + $order = array(); + foreach ($array as $key=>$val){ + $arr = explode(' ',trim($val)); + if(isset($arr[1])) { + $arr[1] = $arr[1]=='asc'?1:-1; + }else{ + $arr[1] = 1; + } + $order[$arr[0]] = $arr[1]; + } + } + return $order; + } + + /** + * limit分析 + * @access protected + * @param mixed $limit + * @return array + */ + protected function parseLimit($limit) { + if(strpos($limit,',')) { + $array = explode(',',$limit); + }else{ + $array = array(0,$limit); + } + return $array; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return array + */ + public function parseField($fields){ + if(empty($fields)) { + $fields = array(); + } + if(is_string($fields)) { + $fields = explode(',',$fields); + } + return $fields; + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return array + */ + public function parseWhere($where){ + $query = array(); + foreach ($where as $key=>$val){ + if('_id' != $key && 0===strpos($key,'_')) { + // 解析特殊条件表达式 + $query = $this->parseThinkWhere($key,$val); + }else{ + // 查询字段的安全过滤 + if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){ + throw_exception(L('_ERROR_QUERY_').':'.$key); + } + $key = trim($key); + if(strpos($key,'|')) { + $array = explode('|',$key); + $str = array(); + foreach ($array as $k){ + $str[] = $this->parseWhereItem($k,$val); + } + $query['$or'] = $str; + }elseif(strpos($key,'&')){ + $array = explode('&',$key); + $str = array(); + foreach ($array as $k){ + $str[] = $this->parseWhereItem($k,$val); + } + $query = array_merge($query,$str); + }else{ + $str = $this->parseWhereItem($key,$val); + $query = array_merge($query,$str); + } + } + } + return $query; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $query = array(); + switch($key) { + case '_query': // 字符串模式查询条件 + parse_str($val,$query); + if(isset($query['_logic']) && strtolower($query['_logic']) == 'or' ) { + unset($query['_logic']); + $query['$or'] = $query; + } + break; + case '_string':// MongoCode查询 + $query['$where'] = new MongoCode($val); + break; + } + return $query; + } + + /** + * where子单元分析 + * @access protected + * @param string $key + * @param mixed $val + * @return array + */ + protected function parseWhereItem($key,$val) { + $query = array(); + if(is_array($val)) { + if(is_string($val[0])) { + $con = strtolower($val[0]); + if(in_array($con,array('neq','ne','gt','egt','gte','lt','lte','elt'))) { // 比较运算 + $k = '$'.$this->comparison[$con]; + $query[$key] = array($k=>$val[1]); + }elseif('like'== $con){ // 模糊查询 采用正则方式 + $query[$key] = new MongoRegex("/".$val[1]."/"); + }elseif('mod'==$con){ // mod 查询 + $query[$key] = array('$mod'=>$val[1]); + }elseif('regex'==$con){ // 正则查询 + $query[$key] = new MongoRegex($val[1]); + }elseif(in_array($con,array('in','nin','not in'))){ // IN NIN 运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $k = '$'.$this->comparison[$con]; + $query[$key] = array($k=>$data); + }elseif('all'==$con){ // 满足所有指定条件 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $query[$key] = array('$all'=>$data); + }elseif('between'==$con){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $query[$key] = array('$gte'=>$data[0],'$lte'=>$data[1]); + }elseif('not between'==$con){ + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $query[$key] = array('$lt'=>$data[0],'$gt'=>$data[1]); + }elseif('exp'==$con){ // 表达式查询 + $query['$where'] = new MongoCode($val[1]); + }elseif('exists'==$con){ // 字段是否存在 + $query[$key] =array('$exists'=>(bool)$val[1]); + }elseif('size'==$con){ // 限制属性大小 + $query[$key] =array('$size'=>intval($val[1])); + }elseif('type'==$con){ // 限制字段类型 1 浮点型 2 字符型 3 对象或者MongoDBRef 5 MongoBinData 7 MongoId 8 布尔型 9 MongoDate 10 NULL 15 MongoCode 16 32位整型 17 MongoTimestamp 18 MongoInt64 如果是数组的话判断元素的类型 + $query[$key] =array('$type'=>intval($val[1])); + }else{ + $query[$key] = $val; + } + return $query; + } + } + $query[$key] = $val; + return $query; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Db/DbMssql.class.php b/ThinkPHP/Extend/Driver/Db/DbMssql.class.php new file mode 100644 index 0000000..72505af --- /dev/null +++ b/ThinkPHP/Extend/Driver/Db/DbMssql.class.php @@ -0,0 +1,334 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * MSsql数据库驱动 要求sqlserver2005 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +class DbMssql extends Db{ + protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%'; + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !function_exists('mssql_connect') ) { + throw_exception(L('_NOT_SUPPERT_').':mssql'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'mssql_pconnect':'mssql_connect'; + // 处理不带端口号的socket连接情况 + $sepr = IS_WIN ? ',' : ':'; + $host = $config['hostname'].($config['hostport']?$sepr."{$config['hostport']}":''); + $this->linkID[$linkNum] = $conn( $host, $config['username'], $config['password']); + if ( !$this->linkID[$linkNum] ) throw_exception("Couldn't connect to SQL Server on $host"); + if ( !empty($config['database']) && !mssql_select_db($config['database'], $this->linkID[$linkNum]) ) { + throw_exception("Couldn't open database '".$config['database']); + } + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mssql_free_result($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mssql_query($str, $this->_linkID); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = mssql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = mssql_query($str, $this->_linkID); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + $this->numRows = mssql_rows_affected($this->_linkID); + $this->lastInsID = $this->mssql_insert_id(); + return $this->numRows; + } + } + + /** + * 用于获取最后插入的ID + * @access public + * @return integer + */ + public function mssql_insert_id() { + $query = "SELECT @@IDENTITY as last_insert_id"; + $result = mssql_query($query, $this->_linkID); + list($last_insert_id) = mssql_fetch_row($result); + mssql_free_result($result); + return $last_insert_id; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mssql_query('BEGIN TRAN', $this->_linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = mssql_query('COMMIT TRAN', $this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = mssql_query('ROLLBACK TRAN', $this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mssql_fetch_assoc($this->queryID)) + $result[] = $row; + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query("SELECT column_name, data_type, column_default, is_nullable + FROM information_schema.tables AS t + JOIN information_schema.columns AS c + ON t.table_catalog = c.table_catalog + AND t.table_schema = c.table_schema + AND t.table_name = c.table_name + WHERE t.table_name = '$tableName'"); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['column_name']] = array( + 'name' => $val['column_name'], + 'type' => $val['data_type'], + 'notnull' => (bool) ($val['is_nullable'] === ''), // not null is empty, null is yes + 'default' => $val['column_default'], + 'primary' => false, + 'autoinc' => false, + ); + } + } + return $info; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + $result = $this->query("SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_TYPE = 'BASE TABLE' + "); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + return !empty($order)? ' ORDER BY '.$order:' ORDER BY rand()'; + } + + /** + * limit + * @access public + * @return string + */ + public function parseLimit($limit) { + if(empty($limit)) return ''; + $limit = explode(',',$limit); + if(count($limit)>1) + $limitStr = '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')'; + else + $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"; + return 'WHERE '.$limitStr; + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $this->model = $options['model']; + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $this->model = $options['model']; + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql); + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if ($this->_linkID){ + mssql_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mssql_get_last_message(); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Db/DbOracle.class.php b/ThinkPHP/Extend/Driver/Db/DbOracle.class.php new file mode 100644 index 0000000..f9a3fa5 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Db/DbOracle.class.php @@ -0,0 +1,337 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Oracle数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author ZhangXuehun + */ +class DbOracle extends Db{ + + private $mode = OCI_COMMIT_ON_SUCCESS; + private $table = ''; + protected $selectSql = 'SELECT * FROM (SELECT thinkphp.*, rownum AS numrow FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%) thinkphp ) %LIMIT%%COMMENT%'; + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + putenv("NLS_LANG=AMERICAN_AMERICA.UTF8"); + if ( !extension_loaded('oci8') ) { + throw_exception(L('_NOT_SUPPERT_').'oracle'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'oci_pconnect':'oci_new_connect'; + $this->linkID[$linkNum] = $conn($config['username'], $config['password'],$config['database']);//modify by wyfeng at 2008.12.19 + + if (!$this->linkID[$linkNum]){ + $this->error(false); + } + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + oci_free_statement($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //更改事务模式 + $this->mode = OCI_COMMIT_ON_SUCCESS; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = oci_parse($this->_linkID,$str); + $this->debug(); + if (false === oci_execute($this->queryID, $this->mode)) { + $this->error(); + return false; + } else { + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + // 判断新增操作 + $flag = false; + if(preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $this->queryStr, $match)) { + $this->table = C("DB_SEQUENCE_PREFIX") .str_ireplace(C("DB_PREFIX"), "", $match[2]); + $flag = (boolean)$this->query("SELECT * FROM user_sequences WHERE sequence_name='" . strtoupper($this->table) . "'"); + }//modify by wyfeng at 2009.08.28 + + //更改事务模式 + $this->mode = OCI_COMMIT_ON_SUCCESS; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $stmt = oci_parse($this->_linkID,$str); + $this->debug(); + if (false === oci_execute($stmt)) { + $this->error(); + return false; + } else { + $this->numRows = oci_num_rows($stmt); + $this->lastInsID = $flag?$this->insertLastId():0;//modify by wyfeng at 2009.08.28 + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + $this->mode = OCI_DEFAULT; + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit(){ + if ($this->transTimes > 0) { + $result = oci_commit($this->_linkID); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback(){ + if ($this->transTimes > 0) { + $result = oci_rollback($this->_linkID); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + $this->numRows = oci_fetch_all($this->queryID, $result, 0, -1, OCI_FETCHSTATEMENT_BY_ROW); + //add by wyfeng at 2008-12-23 强制将字段名转换为小写,以配合Model类函数如count等 + if(C("DB_CASE_LOWER")) { + foreach($result as $k=>$v) { + $result[$k] = array_change_key_case($result[$k], CASE_LOWER); + } + } + return $result; + } + + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query("select a.column_name,data_type,decode(nullable,'Y',0,1) notnull,data_default,decode(a.column_name,b.column_name,1,0) pk " + ."from user_tab_columns a,(select column_name from user_constraints c,user_cons_columns col " + ."where c.constraint_name=col.constraint_name and c.constraint_type='P'and c.table_name='".strtoupper($tableName) + ."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)"); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[strtolower($val['column_name'])] = array( + 'name' => strtolower($val['column_name']), + 'type' => strtolower($val['data_type']), + 'notnull' => $val['notnull'], + 'default' => $val['data_default'], + 'primary' => $val['pk'], + 'autoinc' => $val['pk'], + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息(暂时实现取得用户表信息) + * @access public + */ + public function getTables($dbName='') { + $result = $this->query("select table_name from user_tables"); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if($this->_linkID){ + oci_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error($result = true) { + if($result){ + $error = oci_error($this->queryID); + }elseif(!$this->_linkID){ + $error = oci_error(); + }else{ + $error = oci_error($this->_linkID); + } + if('' != $this->queryStr){ + $error['message'] .= "\n [ SQL语句 ] : ".$this->queryStr; + } + $result? trace($error['message'],'','ERR'):throw_exception($error['message'],'',$error['code']); + $this->error = $error['message']; + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + return str_ireplace("'", "''", $str); + } + + /** + * 获取最后插入id ,仅适用于采用序列+触发器结合生成ID的方式 + * 在config.php中指定 + 'DB_TRIGGER_PREFIX' => 'tr_', + 'DB_SEQUENCE_PREFIX' => 'ts_', + * eg:表 tb_user + 相对tb_user的序列为: + -- Create sequence + create sequence TS_USER + minvalue 1 + maxvalue 999999999999999999999999999 + start with 1 + increment by 1 + nocache; + 相对tb_user,ts_user的触发器为: + create or replace trigger TR_USER + before insert on "TB_USER" + for each row + begin + select "TS_USER".nextval into :NEW.ID from dual; + end; + * @access public + * @return integer + */ + public function insertLastId() { + if(empty($this->table)) { + return 0; + } + $sequenceName = $this->table; + $vo = $this->query("SELECT {$sequenceName}.currval currval FROM dual"); + return $vo?$vo[0]["currval"]:0; + } + + /** + * limit + * @access public + * @return string + */ + public function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + $limit = explode(',',$limit); + if(count($limit)>1) + $limitStr = "(numrow>" . $limit[0] . ") AND (numrow<=" . ($limit[0]+$limit[1]) . ")"; + else + $limitStr = "(numrow>0 AND numrow<=".$limit[0].")"; + } + return $limitStr?' WHERE '.$limitStr:''; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Db/DbPdo.class.php b/ThinkPHP/Extend/Driver/Db/DbPdo.class.php new file mode 100644 index 0000000..dfa06f7 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Db/DbPdo.class.php @@ -0,0 +1,476 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * PDO数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +class DbPdo extends Db{ + + protected $PDOStatement = null; + private $table = ''; + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !class_exists('PDO') ) { + throw_exception(L('_NOT_SUPPERT_').':PDO'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + if($this->pconnect) { + $config['params'][PDO::ATTR_PERSISTENT] = true; + } + //$config['params'][PDO::ATTR_CASE] = C("DB_CASE_LOWER")?PDO::CASE_LOWER:PDO::CASE_UPPER; + try{ + $this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$config['params']); + }catch (PDOException $e) { + throw_exception($e->getMessage()); + } + // 因为PDO的连接切换可能导致数据库类型不同,因此重新获取下当前的数据库类型 + $this->dbType = $this->_getDsnType($config['dsn']); + if(in_array($this->dbType,array('MSSQL','ORACLE','IBASE','OCI'))) { + // 由于PDO对于以上的数据库支持不够完美,所以屏蔽了 如果仍然希望使用PDO 可以注释下面一行代码 + throw_exception('由于目前PDO暂时不能完美支持'.$this->dbType.' 请使用官方的'.$this->dbType.'驱动'); + } + $this->linkID[$linkNum]->exec('SET NAMES '.C('DB_CHARSET')); + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->PDOStatement = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @param array $bind 参数绑定 + * @return mixed + */ + public function query($str,$bind=array()) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + if(!empty($bind)){ + $this->queryStr .= '[ '.print_r($bind,true).' ]'; + } + //释放前次的查询结果 + if ( !empty($this->PDOStatement) ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) + throw_exception($this->error()); + $result = $this->PDOStatement->execute($bind); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @param array $bind 参数绑定 + * @return integer + */ + public function execute($str,$bind=array()) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + if(!empty($bind)){ + $this->queryStr .= '[ '.print_r($bind,true).' ]'; + } + $flag = false; + if($this->dbType == 'OCI') + { + if(preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $this->queryStr, $match)) { + $this->table = C("DB_SEQUENCE_PREFIX").str_ireplace(C("DB_PREFIX"), "", $match[2]); + $flag = (boolean)$this->query("SELECT * FROM user_sequences WHERE sequence_name='" . strtoupper($this->table) . "'"); + } + }//modify by wyfeng at 2009.08.28 + //释放前次的查询结果 + if ( !empty($this->PDOStatement) ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) { + throw_exception($this->error()); + } + $result = $this->PDOStatement->execute($bind); + $this->debug(); + if ( false === $result) { + $this->error(); + return false; + } else { + $this->numRows = $this->PDOStatement->rowCount(); + if($flag || preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) { + $this->lastInsID = $this->getLastInsertId(); + } + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + $this->_linkID->beginTransaction(); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = $this->_linkID->commit(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = $this->_linkID->rollback(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC); + $this->numRows = count( $result ); + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $this->initConnect(true); + if(C('DB_DESCRIBE_TABLE_SQL')) { + // 定义特殊的字段查询SQL + $sql = str_replace('%table%',$tableName,C('DB_DESCRIBE_TABLE_SQL')); + }else{ + switch($this->dbType) { + case 'MSSQL': + case 'SQLSRV': + $sql = "SELECT column_name as 'Name', data_type as 'Type', column_default as 'Default', is_nullable as 'Null' + FROM information_schema.tables AS t + JOIN information_schema.columns AS c + ON t.table_catalog = c.table_catalog + AND t.table_schema = c.table_schema + AND t.table_name = c.table_name + WHERE t.table_name = '$tableName'"; + break; + case 'SQLITE': + $sql = 'PRAGMA table_info ('.$tableName.') '; + break; + case 'ORACLE': + case 'OCI': + $sql = "SELECT a.column_name \"Name\",data_type \"Type\",decode(nullable,'Y',0,1) notnull,data_default \"Default\",decode(a.column_name,b.column_name,1,0) \"pk\" " + ."FROM user_tab_columns a,(SELECT column_name FROM user_constraints c,user_cons_columns col " + ."WHERE c.constraint_name=col.constraint_name AND c.constraint_type='P' and c.table_name='".strtoupper($tableName) + ."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)"; + break; + case 'PGSQL': + $sql = 'select fields_name as "Name",fields_type as "Type",fields_not_null as "Null",fields_key_name as "Key",fields_default as "Default",fields_default as "Extra" from table_msg('.$tableName.');'; + break; + case 'IBASE': + break; + case 'MYSQL': + default: + $sql = 'DESCRIBE '.$tableName;//备注: 驱动类不只针对mysql,不能加`` + } + } + $result = $this->query($sql); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $val = array_change_key_case($val); + $val['name'] = isset($val['name'])?$val['name']:""; + $val['type'] = isset($val['type'])?$val['type']:""; + $name = isset($val['field'])?$val['field']:$val['name']; + $info[$name] = array( + 'name' => $name , + 'type' => $val['type'], + 'notnull' => (bool)(((isset($val['null'])) && ($val['null'] === '')) || ((isset($val['notnull'])) && ($val['notnull'] === ''))), // not null is empty, null is yes + 'default' => isset($val['default'])? $val['default'] :(isset($val['dflt_value'])?$val['dflt_value']:""), + 'primary' => isset($val['key'])?strtolower($val['key']) == 'pri':(isset($val['pk'])?$val['pk']:false), + 'autoinc' => isset($val['extra'])?strtolower($val['extra']) == 'auto_increment':(isset($val['key'])?$val['key']:false), + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + if(C('DB_FETCH_TABLES_SQL')) { + // 定义特殊的表查询SQL + $sql = str_replace('%db%',$dbName,C('DB_FETCH_TABLES_SQL')); + }else{ + switch($this->dbType) { + case 'ORACLE': + case 'OCI': + $sql = 'SELECT table_name FROM user_tables'; + break; + case 'MSSQL': + case 'SQLSRV': + $sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'"; + break; + case 'PGSQL': + $sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'"; + break; + case 'IBASE': + // 暂时不支持 + throw_exception(L('_NOT_SUPPORT_DB_').':IBASE'); + break; + case 'SQLITE': + $sql = "SELECT name FROM sqlite_master WHERE type='table' " + . "UNION ALL SELECT name FROM sqlite_temp_master " + . "WHERE type='table' ORDER BY name"; + break; + case 'MYSQL': + default: + if(!empty($dbName)) { + $sql = 'SHOW TABLES FROM '.$dbName; + }else{ + $sql = 'SHOW TABLES '; + } + } + } + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + switch($this->dbType){ + case 'PGSQL': + case 'SQLITE': + $limit = explode(',',$limit); + if(count($limit)>1) { + $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' '; + }else{ + $limitStr .= ' LIMIT '.$limit[0].' '; + } + break; + case 'MSSQL': + case 'SQLSRV': + break; + case 'IBASE': + // 暂时不支持 + break; + case 'ORACLE': + case 'OCI': + break; + case 'MYSQL': + default: + $limitStr .= ' LIMIT '.$limit.' '; + } + } + return $limitStr; + } + + /** + * 字段和表名处理 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + if($this->dbType=='MYSQL'){ + $key = trim($key); + if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { + $key = '`'.$key.'`'; + } + return $key; + }else{ + return parent::parseKey($key); + } + + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + if($this->PDOStatement) { + $error = $this->PDOStatement->errorInfo(); + $this->error = $error[1].':'.$error[2]; + }else{ + $this->error = ''; + } + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + switch($this->dbType) { + case 'PGSQL': + case 'MSSQL': + case 'SQLSRV': + case 'MYSQL': + return addslashes($str); + case 'IBASE': + case 'SQLITE': + case 'ORACLE': + case 'OCI': + return str_ireplace("'", "''", $str); + } + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = strpos($value,':') === 0 ? $this->escapeString($value) : '\''.$this->escapeString($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escapeString($value[1]); + }elseif(is_array($value)) { + $value = array_map(array($this, 'parseValue'),$value); + }elseif(is_bool($value)){ + $value = $value ? '1' : '0'; + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * 获取最后插入id + * @access public + * @return integer + */ + public function getLastInsertId() { + switch($this->dbType) { + case 'PGSQL': + case 'SQLITE': + case 'MSSQL': + case 'SQLSRV': + case 'IBASE': + case 'MYSQL': + return $this->_linkID->lastInsertId(); + case 'ORACLE': + case 'OCI': + $sequenceName = $this->table; + $vo = $this->query("SELECT {$sequenceName}.currval currval FROM dual"); + return $vo?$vo[0]["currval"]:0; + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Db/DbPgsql.class.php b/ThinkPHP/Extend/Driver/Db/DbPgsql.class.php new file mode 100644 index 0000000..6f6f2d2 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Db/DbPgsql.class.php @@ -0,0 +1,300 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Pgsql数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +class DbPgsql extends Db{ + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config='') { + if ( !extension_loaded('pgsql') ) { + throw_exception(L('_NOT_SUPPERT_').':pgsql'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'pg_pconnect':'pg_connect'; + $this->linkID[$linkNum] = $conn('host='.$config['hostname'].' port='.$config['hostport'].' dbname='.$config['database'].' user='.$config['username'].' password='.$config['password']); + if (0 !== pg_connection_status($this->linkID[$linkNum])){ + throw_exception($this->error(false)); + } + //设置编码 + pg_set_client_encoding($this->linkID[$linkNum], C('DB_CHARSET')); + //$pgInfo = pg_version($this->linkID[$linkNum]); + //$dbVersion = $pgInfo['server']; + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + pg_free_result($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = pg_query($this->_linkID,$str); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = pg_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = pg_query($this->_linkID,$str); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + $this->numRows = pg_affected_rows($result); + $this->lastInsID = $this->last_insert_id(); + return $this->numRows; + } + } + + /** + * 用于获取最后插入的ID + * @access public + * @return integer + */ + public function last_insert_id() { + $query = "SELECT LASTVAL() AS insert_id"; + $result = pg_query($this->_linkID,$query); + list($last_insert_id) = pg_fetch_array($result,null,PGSQL_ASSOC); + pg_free_result($result); + return $last_insert_id; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + pg_exec($this->_linkID,'begin;'); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = pg_exec($this->_linkID,'end;'); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = pg_exec($this->_linkID,'abort;'); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = pg_fetch_all($this->queryID); + pg_result_seek($this->queryID,0); + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query("select a.attname as \"Field\", + t.typname as \"Type\", + a.attnotnull as \"Null\", + i.indisprimary as \"Key\", + d.adsrc as \"Default\" + from pg_class c + inner join pg_attribute a on a.attrelid = c.oid + inner join pg_type t on a.atttypid = t.oid + left join pg_attrdef d on a.attrelid=d.adrelid and d.adnum=a.attnum + left join pg_index i on a.attnum=ANY(i.indkey) and c.oid = i.indrelid + where (c.relname='{$tableName}' or c.relname = lower('{$tableName}')) AND a.attnum > 0 + order by a.attnum asc;"); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] == 't'?1:0), // 't' is 'not null' + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 't'), + 'autoinc' => (strtolower($val['Default']) == "nextval('{$tableName}_id_seq'::regclass)"), + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + $result = $this->query("select tablename as Tables_in_test from pg_tables where schemaname ='public'"); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if($this->_linkID){ + pg_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error($result = true) { + $this->error = $result?pg_result_error($this->queryID): pg_last_error($this->_linkID); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + return pg_escape_string($str); + } + + /** + * limit + * @access public + * @return string + */ + public function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + $limit = explode(',',$limit); + if(count($limit)>1) { + $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' '; + }else{ + $limitStr .= ' LIMIT '.$limit[0].' '; + } + } + return $limitStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Db/DbSqlite.class.php b/ThinkPHP/Extend/Driver/Db/DbSqlite.class.php new file mode 100644 index 0000000..d367712 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Db/DbSqlite.class.php @@ -0,0 +1,285 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Sqlite数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +class DbSqlite extends Db { + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config='') { + if ( !extension_loaded('sqlite') ) { + throw_exception(L('_NOT_SUPPERT_').':sqlite'); + } + if(!empty($config)) { + if(!isset($config['mode'])) { + $config['mode'] = 0666; + } + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'sqlite_popen':'sqlite_open'; + $this->linkID[$linkNum] = $conn($config['database'],$config['mode']); + if ( !$this->linkID[$linkNum]) { + throw_exception(sqlite_error_string()); + } + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = sqlite_query($this->_linkID,$str); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = sqlite_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = sqlite_exec($this->_linkID,$str); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + $this->numRows = sqlite_changes($this->_linkID); + $this->lastInsID = sqlite_last_insert_rowid($this->_linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + sqlite_query($this->_linkID,'BEGIN TRANSACTION'); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = sqlite_query($this->_linkID,'COMMIT TRANSACTION'); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = sqlite_query($this->_linkID,'ROLLBACK TRANSACTION'); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows >0) { + for($i=0;$i<$this->numRows ;$i++ ){ + // 返回数组集 + $result[$i] = sqlite_fetch_array($this->queryID,SQLITE_ASSOC); + } + sqlite_seek($this->queryID,0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query('PRAGMA table_info( '.$tableName.' )'); + $info = array(); + if($result){ + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + $result = $this->query("SELECT name FROM sqlite_master WHERE type='table' " + . "UNION ALL SELECT name FROM sqlite_temp_master " + . "WHERE type='table' ORDER BY name"); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if ($this->_linkID){ + sqlite_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $code = sqlite_last_error($this->_linkID); + $this->error = $code.':'.sqlite_error_string($code); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + return sqlite_escape_string($str); + } + + /** + * limit + * @access public + * @return string + */ + public function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + $limit = explode(',',$limit); + if(count($limit)>1) { + $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' '; + }else{ + $limitStr .= ' LIMIT '.$limit[0].' '; + } + } + return $limitStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Db/DbSqlsrv.class.php b/ThinkPHP/Extend/Driver/Db/DbSqlsrv.class.php new file mode 100644 index 0000000..8859a43 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Db/DbSqlsrv.class.php @@ -0,0 +1,352 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Sqlsrv数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +class DbSqlsrv extends Db{ + protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%'; + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config='') { + if ( !function_exists('sqlsrv_connect') ) { + throw_exception(L('_NOT_SUPPERT_').':sqlsrv'); + } + if(!empty($config)) { + $this->config = $config; + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $host = $config['hostname'].($config['hostport']?",{$config['hostport']}":''); + $connectInfo = array('Database'=>$config['database'],'UID'=>$config['username'],'PWD'=>$config['password'],'CharacterSet' => C('DEFAULT_CHARSET')); + $this->linkID[$linkNum] = sqlsrv_connect( $host, $connectInfo); + if ( !$this->linkID[$linkNum] ) $this->error(false); + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + sqlsrv_free_stmt($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @param array $bind 参数绑定 + * @return mixed + */ + public function query($str,$bind=array()) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $str = str_replace(array_keys($bind),'?',$str); + $bind = array_values($bind); + $this->queryStr = $str; + $this->queryID = sqlsrv_query($this->_linkID,$str,$bind, array( "Scrollable" => SQLSRV_CURSOR_KEYSET)); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = sqlsrv_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @param array $bind 参数绑定 + * @return integer + */ + public function execute($str,$bind=array()) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $str = str_replace(array_keys($bind),'?',$str); + $bind = array_values($bind); + $this->queryStr = $str; + $this->queryID= sqlsrv_query($this->_linkID,$str,$bind); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = sqlsrv_rows_affected($this->queryID); + $this->lastInsID = $this->mssql_insert_id(); + return $this->numRows; + } + } + + /** + * 用于获取最后插入的ID + * @access public + * @return integer + */ + public function mssql_insert_id() { + $query = "SELECT @@IDENTITY as last_insert_id"; + $result = sqlsrv_query($this->_linkID,$query); + list($last_insert_id) = sqlsrv_fetch_array($result); + sqlsrv_free_stmt($result); + return $last_insert_id; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + sqlsrv_begin_transaction($this->_linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = sqlsrv_commit($this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = sqlsrv_rollback($this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = sqlsrv_fetch_array($this->queryID,SQLSRV_FETCH_ASSOC)) + $result[] = $row; + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query(" + SELECT column_name,data_type,column_default,is_nullable + FROM information_schema.tables AS t + JOIN information_schema.columns AS c + ON t.table_catalog = c.table_catalog + AND t.table_schema = c.table_schema + AND t.table_name = c.table_name + WHERE t.table_name = '{$tableName}'"); + $pk = $this->query("SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME='{$tableName}'"); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['column_name']] = array( + 'name' => $val['column_name'], + 'type' => $val['data_type'], + 'notnull' => (bool) ($val['is_nullable'] === ''), // not null is empty, null is yes + 'default' => $val['column_default'], + 'primary' => $val['column_name'] == $pk[0]['COLUMN_NAME'], + 'autoinc' => false, + ); + } + } + return $info; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + $result = $this->query("SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_TYPE = 'BASE TABLE' + "); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + return !empty($order)? ' ORDER BY '.$order:' ORDER BY rand()'; + } + + /** + * 字段名分析 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + $key = trim($key); + if(!preg_match('/[,\'\"\*\(\)\[.\s]/',$key)) { + $key = '['.$key.']'; + } + return $key; + } + + /** + * limit + * @access public + * @param mixed $limit + * @return string + */ + public function parseLimit($limit) { + if(empty($limit)) return ''; + $limit = explode(',',$limit); + if(count($limit)>1) + $limitStr = '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')'; + else + $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"; + return 'WHERE '.$limitStr; + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $this->model = $options['model']; + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $this->model = $options['model']; + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if ($this->_linkID){ + sqlsrv_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error($result = true) { + $errors = sqlsrv_errors(); + $this->error = ''; + foreach( $errors as $error ) { + $this->error .= $error['code'].':'.$error['message']; + } + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + $result? trace($this->error,'','ERR'):throw_exception($this->error); + return $this->error; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Session/SessionDb.class.php b/ThinkPHP/Extend/Driver/Session/SessionDb.class.php new file mode 100644 index 0000000..51aee82 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Session/SessionDb.class.php @@ -0,0 +1,189 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 数据库方式Session驱动 + * CREATE TABLE think_session ( + * session_id varchar(255) NOT NULL, + * session_expire int(11) NOT NULL, + * session_data blob, + * UNIQUE KEY `session_id` (`session_id`) + * ); + * @category Extend + * @package Extend + * @subpackage Driver.Session + * @author liu21st + */ +class SessionDb { + + /** + * Session有效时间 + */ + protected $lifeTime = ''; + + /** + * session保存的数据库名 + */ + protected $sessionTable = ''; + + /** + * 数据库句柄 + */ + protected $hander = array(); + + /** + * 打开Session + * @access public + * @param string $savePath + * @param mixed $sessName + */ + public function open($savePath, $sessName) { + $this->lifeTime = C('SESSION_EXPIRE')?C('SESSION_EXPIRE'):ini_get('session.gc_maxlifetime'); + $this->sessionTable = C('SESSION_TABLE')?C('SESSION_TABLE'):C("DB_PREFIX")."session"; + //分布式数据库 + $host = explode(',',C('DB_HOST')); + $port = explode(',',C('DB_PORT')); + $name = explode(',',C('DB_NAME')); + $user = explode(',',C('DB_USER')); + $pwd = explode(',',C('DB_PWD')); + if(1 == C('DB_DEPLOY_TYPE')){ + //读写分离 + if(C('DB_RW_SEPARATE')){ + $w = floor(mt_rand(0,C('DB_MASTER_NUM')-1)); + if(is_numeric(C('DB_SLAVE_NO'))){//指定服务器读 + $r = C('DB_SLAVE_NO'); + }else{ + $r = floor(mt_rand(C('DB_MASTER_NUM'),count($host)-1)); + } + //主数据库链接 + $hander = mysql_connect( + $host[$w].(isset($port[$w])?':'.$port[$w]:':'.$port[0]), + isset($user[$w])?$user[$w]:$user[0], + isset($pwd[$w])?$pwd[$w]:$pwd[0] + ); + $dbSel = mysql_select_db( + isset($name[$w])?$name[$w]:$name[0] + ,$hander); + if(!$hander || !$dbSel) + return false; + $this->hander[0] = $hander; + //从数据库链接 + $hander = mysql_connect( + $host[$r].(isset($port[$r])?':'.$port[$r]:':'.$port[0]), + isset($user[$r])?$user[$r]:$user[0], + isset($pwd[$r])?$pwd[$r]:$pwd[0] + ); + $dbSel = mysql_select_db( + isset($name[$r])?$name[$r]:$name[0] + ,$hander); + if(!$hander || !$dbSel) + return false; + $this->hander[1] = $hander; + return true; + } + } + //从数据库链接 + $r = floor(mt_rand(0,count($host)-1)); + $hander = mysql_connect( + $host[$r].(isset($port[$r])?':'.$port[$r]:':'.$port[0]), + isset($user[$r])?$user[$r]:$user[0], + isset($pwd[$r])?$pwd[$r]:$pwd[0] + ); + $dbSel = mysql_select_db( + isset($name[$r])?$name[$r]:$name[0] + ,$hander); + if(!$hander || !$dbSel) + return false; + $this->hander = $hander; + return true; + } + + /** + * 关闭Session + * @access public + */ + public function close() { + if(is_array($this->hander)){ + $this->gc($this->lifeTime); + return (mysql_close($this->hander[0]) && mysql_close($this->hander[1])); + } + $this->gc($this->lifeTime); + return mysql_close($this->hander); + } + + /** + * 读取Session + * @access public + * @param string $sessID + */ + public function read($sessID) { + $hander = is_array($this->hander)?$this->hander[1]:$this->hander; + $res = mysql_query("SELECT session_data AS data FROM ".$this->sessionTable." WHERE session_id = '$sessID' AND session_expire >".time(),$hander); + if($res) { + $row = mysql_fetch_assoc($res); + return $row['data']; + } + return ""; + } + + /** + * 写入Session + * @access public + * @param string $sessID + * @param String $sessData + */ + public function write($sessID,$sessData) { + $hander = is_array($this->hander)?$this->hander[0]:$this->hander; + $expire = time() + $this->lifeTime; + mysql_query("REPLACE INTO ".$this->sessionTable." ( session_id, session_expire, session_data) VALUES( '$sessID', '$expire', '$sessData')",$hander); + if(mysql_affected_rows($hander)) + return true; + return false; + } + + /** + * 删除Session + * @access public + * @param string $sessID + */ + public function destroy($sessID) { + $hander = is_array($this->hander)?$this->hander[0]:$this->hander; + mysql_query("DELETE FROM ".$this->sessionTable." WHERE session_id = '$sessID'",$hander); + if(mysql_affected_rows($hander)) + return true; + return false; + } + + /** + * Session 垃圾回收 + * @access public + * @param string $sessMaxLifeTime + */ + public function gc($sessMaxLifeTime) { + $hander = is_array($this->hander)?$this->hander[0]:$this->hander; + mysql_query("DELETE FROM ".$this->sessionTable." WHERE session_expire < ".time(),$hander); + return mysql_affected_rows($hander); + } + + /** + * 打开Session + * @access public + */ + public function execute() { + session_set_save_handler(array(&$this,"open"), + array(&$this,"close"), + array(&$this,"read"), + array(&$this,"write"), + array(&$this,"destroy"), + array(&$this,"gc")); + } +} diff --git a/ThinkPHP/Extend/Driver/TagLib/TagLibHtml.class.php b/ThinkPHP/Extend/Driver/TagLib/TagLibHtml.class.php new file mode 100644 index 0000000..e67543f --- /dev/null +++ b/ThinkPHP/Extend/Driver/TagLib/TagLibHtml.class.php @@ -0,0 +1,530 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Html标签库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Taglib + * @author liu21st + */ +class TagLibHtml extends TagLib{ + // 标签定义 + protected $tags = array( + // 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次 + 'editor' => array('attr'=>'id,name,style,width,height,type','close'=>1), + 'select' => array('attr'=>'name,options,values,output,multiple,id,size,first,change,selected,dblclick','close'=>0), + 'grid' => array('attr'=>'id,pk,style,action,actionlist,show,datasource','close'=>0), + 'list' => array('attr'=>'id,pk,style,action,actionlist,show,datasource,checkbox','close'=>0), + 'imagebtn' => array('attr'=>'id,name,value,type,style,click','close'=>0), + 'checkbox' => array('attr'=>'name,checkboxes,checked,separator','close'=>0), + 'radio' => array('attr'=>'name,radios,checked,separator','close'=>0) + ); + + /** + * editor标签解析 插入可视化编辑器 + * 格式: {$vo.remark} + * @access public + * @param string $attr 标签属性 + * @return string|void + */ + public function _editor($attr,$content) { + $tag = $this->parseXmlAttr($attr,'editor'); + $id = !empty($tag['id'])?$tag['id']: '_editor'; + $name = $tag['name']; + $style = !empty($tag['style'])?$tag['style']:''; + $width = !empty($tag['width'])?$tag['width']: '100%'; + $height = !empty($tag['height'])?$tag['height'] :'320px'; + // $content = $tag['content']; + $type = $tag['type'] ; + switch(strtoupper($type)) { + case 'FCKEDITOR': + $parseStr = ' '; + break; + case 'FCKMINI': + $parseStr = ' '; + break; + case 'EWEBEDITOR': + $parseStr = ""; + break; + case 'NETEASE': + $parseStr = ''; + break; + case 'UBB': + $parseStr = '
'; + break; + case 'KINDEDITOR': + $parseStr = ''; + break; + default : + $parseStr = ''; + } + + return $parseStr; + } + + /** + * imageBtn标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @return string|void + */ + public function _imageBtn($attr) { + $tag = $this->parseXmlAttr($attr,'imageBtn'); + $name = $tag['name']; //名称 + $value = $tag['value']; //文字 + $id = isset($tag['id'])?$tag['id']:''; //ID + $style = isset($tag['style'])?$tag['style']:''; //样式名 + $click = isset($tag['click'])?$tag['click']:''; //点击 + $type = empty($tag['type'])?'button':$tag['type']; //按钮类型 + + if(!empty($name)) { + $parseStr = '
'; + }else { + $parseStr = '
'; + } + + return $parseStr; + } + + /** + * imageLink标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @return string|void + */ + public function _imgLink($attr) { + $tag = $this->parseXmlAttr($attr,'imgLink'); + $name = $tag['name']; //名称 + $alt = $tag['alt']; //文字 + $id = $tag['id']; //ID + $style = $tag['style']; //样式名 + $click = $tag['click']; //点击 + $type = $tag['type']; //点击 + if(empty($type)) { + $type = 'button'; + } + $parseStr = ''; + + return $parseStr; + } + + /** + * select标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @return string|void + */ + public function _select($attr) { + $tag = $this->parseXmlAttr($attr,'select'); + $name = $tag['name']; + $options = $tag['options']; + $values = $tag['values']; + $output = $tag['output']; + $multiple = $tag['multiple']; + $id = $tag['id']; + $size = $tag['size']; + $first = $tag['first']; + $selected = $tag['selected']; + $style = $tag['style']; + $ondblclick = $tag['dblclick']; + $onchange = $tag['change']; + + if(!empty($multiple)) { + $parseStr = ''; + } + if(!empty($first)) { + $parseStr .= ''; + } + if(!empty($options)) { + $parseStr .= '$val) { ?>'; + if(!empty($selected)) { + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + }else { + $parseStr .= ''; + } + $parseStr .= ''; + }else if(!empty($values)) { + $parseStr .= ''; + if(!empty($selected)) { + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + }else { + $parseStr .= ''; + } + $parseStr .= ''; + } + $parseStr .= ''; + return $parseStr; + } + + /** + * checkbox标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @return string|void + */ + public function _checkbox($attr) { + $tag = $this->parseXmlAttr($attr,'checkbox'); + $name = $tag['name']; + $checkboxes = $tag['checkboxes']; + $checked = $tag['checked']; + $separator = $tag['separator']; + $checkboxes = $this->tpl->get($checkboxes); + $checked = $this->tpl->get($checked)?$this->tpl->get($checked):$checked; + $parseStr = ''; + foreach($checkboxes as $key=>$val) { + if($checked == $key || in_array($key,$checked) ) { + $parseStr .= ''.$val.$separator; + }else { + $parseStr .= ''.$val.$separator; + } + } + return $parseStr; + } + + /** + * radio标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @return string|void + */ + public function _radio($attr) { + $tag = $this->parseXmlAttr($attr,'radio'); + $name = $tag['name']; + $radios = $tag['radios']; + $checked = $tag['checked']; + $separator = $tag['separator']; + $radios = $this->tpl->get($radios); + $checked = $this->tpl->get($checked)?$this->tpl->get($checked):$checked; + $parseStr = ''; + foreach($radios as $key=>$val) { + if($checked == $key ) { + $parseStr .= ''.$val.$separator; + }else { + $parseStr .= ''.$val.$separator; + } + + } + return $parseStr; + } + + /** + * list标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @return string + */ + public function _grid($attr) { + $tag = $this->parseXmlAttr($attr,'grid'); + $id = $tag['id']; //表格ID + $datasource = $tag['datasource']; //列表显示的数据源VoList名称 + $pk = empty($tag['pk'])?'id':$tag['pk'];//主键名,默认为id + $style = $tag['style']; //样式名 + $name = !empty($tag['name'])?$tag['name']:'vo'; //Vo对象名 + $action = !empty($tag['action'])?$tag['action']:false; //是否显示功能操作 + $key = !empty($tag['key'])?true:false; + if(isset($tag['actionlist'])) { + $actionlist = explode(',',trim($tag['actionlist'])); //指定功能列表 + } + + if(substr($tag['show'],0,1)=='$') { + $show = $this->tpl->get(substr($tag['show'],1)); + }else { + $show = $tag['show']; + } + $show = explode(',',$show); //列表显示字段列表 + + //计算表格的列数 + $colNum = count($show); + if(!empty($action)) $colNum++; + if(!empty($key)) $colNum++; + + //显示开始 + $parseStr = "\n"; + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + //列表需要显示的字段 + $fields = array(); + foreach($show as $val) { + $fields[] = explode(':',$val); + } + + if(!empty($key)) { + $parseStr .= ''; + } + foreach($fields as $field) {//显示指定的字段 + $property = explode('|',$field[0]); + $showname = explode('|',$field[1]); + if(isset($showname[1])) { + $parseStr .= ''; + } + if(!empty($action)) {//如果指定显示操作功能列 + $parseStr .= ''; + } + $parseStr .= ''; + $parseStr .= ''; //支持鼠标移动单元行颜色变化 具体方法在js中定义 + + if(!empty($key)) { + $parseStr .= ''; + } + foreach($fields as $field) { + //显示定义的列表字段 + $parseStr .= ''; + + } + if(!empty($action)) {//显示功能操作 + if(!empty($actionlist[0])) {//显示指定的功能项 + $parseStr .= ''; + } + } + $parseStr .= '
No'; + }else { + $parseStr .= ''; + } + $parseStr .= $showname[0].'操作
{$i}'; + if(!empty($field[2])) { + // 支持列表字段链接功能 具体方法由JS函数实现 + $href = explode('|',$field[2]); + if(count($href)>1) { + //指定链接传的字段值 + // 支持多个字段传递 + $array = explode('^',$href[1]); + if(count($array)>1) { + foreach ($array as $a){ + $temp[] = '\'{$'.$name.'.'.$a.'|addslashes}\''; + } + $parseStr .= ''; + }else{ + $parseStr .= ''; + } + }else { + //如果没有指定默认传编号值 + $parseStr .= ''; + } + } + if(strpos($field[0],'^')) { + $property = explode('^',$field[0]); + foreach ($property as $p){ + $unit = explode('|',$p); + if(count($unit)>1) { + $parseStr .= '{$'.$name.'.'.$unit[0].'|'.$unit[1].'} '; + }else { + $parseStr .= '{$'.$name.'.'.$p.'} '; + } + } + }else{ + $property = explode('|',$field[0]); + if(count($property)>1) { + $parseStr .= '{$'.$name.'.'.$property[0].'|'.$property[1].'}'; + }else { + $parseStr .= '{$'.$name.'.'.$field[0].'}'; + } + } + if(!empty($field[2])) { + $parseStr .= ''; + } + $parseStr .= ''; + foreach($actionlist as $val) { + if(strpos($val,':')) { + $a = explode(':',$val); + if(count($a)>2) { + $parseStr .= ''.$a[1].' '; + }else { + $parseStr .= ''.$a[1].' '; + } + }else{ + $array = explode('|',$val); + if(count($array)>2) { + $parseStr .= ' '.$array[2].' '; + }else{ + $parseStr .= ' {$'.$name.'.'.$val.'} '; + } + } + } + $parseStr .= '
'; + $parseStr .= "\n\n"; + return $parseStr; + } + + /** + * list标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @return string + */ + public function _list($attr) { + $tag = $this->parseXmlAttr($attr,'list'); + $id = $tag['id']; //表格ID + $datasource = $tag['datasource']; //列表显示的数据源VoList名称 + $pk = empty($tag['pk'])?'id':$tag['pk'];//主键名,默认为id + $style = $tag['style']; //样式名 + $name = !empty($tag['name'])?$tag['name']:'vo'; //Vo对象名 + $action = $tag['action']=='true'?true:false; //是否显示功能操作 + $key = !empty($tag['key'])?true:false; + $sort = $tag['sort']=='false'?false:true; + $checkbox = $tag['checkbox']; //是否显示Checkbox + if(isset($tag['actionlist'])) { + $actionlist = explode(',',trim($tag['actionlist'])); //指定功能列表 + } + + if(substr($tag['show'],0,1)=='$') { + $show = $this->tpl->get(substr($tag['show'],1)); + }else { + $show = $tag['show']; + } + $show = explode(',',$show); //列表显示字段列表 + + //计算表格的列数 + $colNum = count($show); + if(!empty($checkbox)) $colNum++; + if(!empty($action)) $colNum++; + if(!empty($key)) $colNum++; + + //显示开始 + $parseStr = "\n"; + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + //列表需要显示的字段 + $fields = array(); + foreach($show as $val) { + $fields[] = explode(':',$val); + } + if(!empty($checkbox) && 'true'==strtolower($checkbox)) {//如果指定需要显示checkbox列 + $parseStr .=''; + } + if(!empty($key)) { + $parseStr .= ''; + } + foreach($fields as $field) {//显示指定的字段 + $property = explode('|',$field[0]); + $showname = explode('|',$field[1]); + if(isset($showname[1])) { + $parseStr .= ''; + }else{ + $parseStr .= $showname[0].''; + } + + } + if(!empty($action)) {//如果指定显示操作功能列 + $parseStr .= ''; + } + + $parseStr .= ''; + $parseStr .= ''; + } + if(!empty($key)) { + $parseStr .= ''; + } + foreach($fields as $field) { + //显示定义的列表字段 + $parseStr .= ''; + + } + if(!empty($action)) {//显示功能操作 + if(!empty($actionlist[0])) {//显示指定的功能项 + $parseStr .= ''; + } + } + $parseStr .= '
No'; + }else { + $parseStr .= ''; + } + $showname[2] = isset($showname[2])?$showname[2]:$showname[0]; + if($sort) { + $parseStr .= ''.$showname[0].'操作
{$i}'; + if(!empty($field[2])) { + // 支持列表字段链接功能 具体方法由JS函数实现 + $href = explode('|',$field[2]); + if(count($href)>1) { + //指定链接传的字段值 + // 支持多个字段传递 + $array = explode('^',$href[1]); + if(count($array)>1) { + foreach ($array as $a){ + $temp[] = '\'{$'.$name.'.'.$a.'|addslashes}\''; + } + $parseStr .= ''; + }else{ + $parseStr .= ''; + } + }else { + //如果没有指定默认传编号值 + $parseStr .= ''; + } + } + if(strpos($field[0],'^')) { + $property = explode('^',$field[0]); + foreach ($property as $p){ + $unit = explode('|',$p); + if(count($unit)>1) { + $parseStr .= '{$'.$name.'.'.$unit[0].'|'.$unit[1].'} '; + }else { + $parseStr .= '{$'.$name.'.'.$p.'} '; + } + } + }else{ + $property = explode('|',$field[0]); + if(count($property)>1) { + $parseStr .= '{$'.$name.'.'.$property[0].'|'.$property[1].'}'; + }else { + $parseStr .= '{$'.$name.'.'.$field[0].'}'; + } + } + if(!empty($field[2])) { + $parseStr .= ''; + } + $parseStr .= ''; + foreach($actionlist as $val) { + if(strpos($val,':')) { + $a = explode(':',$val); + if(count($a)>2) { + $parseStr .= ''.$a[1].' '; + }else { + $parseStr .= ''.$a[1].' '; + } + }else{ + $array = explode('|',$val); + if(count($array)>2) { + $parseStr .= ' '.$array[2].' '; + }else{ + $parseStr .= ' {$'.$name.'.'.$val.'} '; + } + } + } + $parseStr .= '
'; + $parseStr .= "\n\n"; + return $parseStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Template/TemplateEase.class.php b/ThinkPHP/Extend/Driver/Template/TemplateEase.class.php new file mode 100644 index 0000000..91f214b --- /dev/null +++ b/ThinkPHP/Extend/Driver/Template/TemplateEase.class.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * EaseTemplate模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author liu21st + */ +class TemplateEase { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile = substr($templateFile,strlen(THEME_PATH),-5); + $CacheDir = substr(CACHE_PATH,0,-1); + $TemplateDir = substr(THEME_PATH,0,-1); + vendor('EaseTemplate.template#ease'); + $config = array( + 'CacheDir' => $CacheDir, + 'TemplateDir' => $TemplateDir, + 'TplType' => 'html' + ); + if(C('TMPL_ENGINE_CONFIG')) { + $config = array_merge($config,C('TMPL_ENGINE_CONFIG')); + } + $tpl = new EaseTemplate($config); + $tpl->set_var($var); + $tpl->set_file($templateFile); + $tpl->p(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Template/TemplateLite.class.php b/ThinkPHP/Extend/Driver/Template/TemplateLite.class.php new file mode 100644 index 0000000..8d7961f --- /dev/null +++ b/ThinkPHP/Extend/Driver/Template/TemplateLite.class.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * TemplateLite模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author liu21st + */ +class TemplateLite { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + vendor("TemplateLite.class#template"); + $templateFile = substr($templateFile,strlen(THEME_PATH)); + $tpl = new Template_Lite(); + $tpl->template_dir = THEME_PATH; + $tpl->compile_dir = CACHE_PATH ; + $tpl->cache_dir = TEMP_PATH ; + if(C('TMPL_ENGINE_CONFIG')) { + $config = C('TMPL_ENGINE_CONFIG'); + foreach ($config as $key=>$val){ + $tpl->{$key} = $val; + } + } + $tpl->assign($var); + $tpl->display($templateFile); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Template/TemplateMobile.class.php b/ThinkPHP/Extend/Driver/Template/TemplateMobile.class.php new file mode 100644 index 0000000..0b09a64 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Template/TemplateMobile.class.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * MobileTemplate模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author luofei614 + */ +class TemplateMobile { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile=substr($templateFile,strlen(THEME_PATH)); + $var['_think_template_path']=$templateFile; + exit(json_encode($var)); + } +} diff --git a/ThinkPHP/Extend/Driver/Template/TemplateSmart.class.php b/ThinkPHP/Extend/Driver/Template/TemplateSmart.class.php new file mode 100644 index 0000000..119e419 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Template/TemplateSmart.class.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Smart模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author liu21st + */ +class TemplateSmart { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile = substr($templateFile,strlen(THEME_PATH)); + vendor('SmartTemplate.class#smarttemplate'); + $tpl = new SmartTemplate($templateFile); + $tpl->caching = C('TMPL_CACHE_ON'); + $tpl->template_dir = THEME_PATH; + $tpl->compile_dir = CACHE_PATH ; + $tpl->cache_dir = TEMP_PATH ; + if(C('TMPL_ENGINE_CONFIG')) { + $config = C('TMPL_ENGINE_CONFIG'); + foreach ($config as $key=>$val){ + $tpl->{$key} = $val; + } + } + $tpl->assign($var); + $tpl->output(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Driver/Template/TemplateSmarty.class.php b/ThinkPHP/Extend/Driver/Template/TemplateSmarty.class.php new file mode 100644 index 0000000..9ed7736 --- /dev/null +++ b/ThinkPHP/Extend/Driver/Template/TemplateSmarty.class.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Smarty模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author liu21st + */ +class TemplateSmarty { + + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile = substr($templateFile,strlen(THEME_PATH)); + vendor('Smarty.Smarty#class'); + $tpl = new Smarty(); + $tpl->caching = C('TMPL_CACHE_ON'); + $tpl->template_dir = THEME_PATH; + $tpl->compile_dir = CACHE_PATH ; + $tpl->cache_dir = TEMP_PATH ; + if(C('TMPL_ENGINE_CONFIG')) { + $config = C('TMPL_ENGINE_CONFIG'); + foreach ($config as $key=>$val){ + $tpl->{$key} = $val; + } + } + $tpl->assign($var); + $tpl->display($templateFile); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Function/extend.php b/ThinkPHP/Extend/Function/extend.php new file mode 100644 index 0000000..318d836 --- /dev/null +++ b/ThinkPHP/Extend/Function/extend.php @@ -0,0 +1,488 @@ + +// +---------------------------------------------------------------------- + +/** + * Think扩展函数库 需要手动加载后调用或者放入项目函数库 + * @category Extend + * @package Extend + * @subpackage Function + * @author liu21st + */ + +/** + * 字符串截取,支持中文和其他编码 + * @static + * @access public + * @param string $str 需要转换的字符串 + * @param string $start 开始位置 + * @param string $length 截取长度 + * @param string $charset 编码格式 + * @param string $suffix 截断显示字符 + * @return string + */ +function msubstr($str, $start=0, $length, $charset="utf-8", $suffix=true) { + if(function_exists("mb_substr")) + $slice = mb_substr($str, $start, $length, $charset); + elseif(function_exists('iconv_substr')) { + $slice = iconv_substr($str,$start,$length,$charset); + if(false === $slice) { + $slice = ''; + } + }else{ + $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/"; + $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/"; + $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/"; + $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/"; + preg_match_all($re[$charset], $str, $match); + $slice = join("",array_slice($match[0], $start, $length)); + } + return $suffix ? $slice.'...' : $slice; +} + +/** + * 产生随机字串,可用来自动生成密码 默认长度6位 字母和数字混合 + * @param string $len 长度 + * @param string $type 字串类型 + * 0 字母 1 数字 其它 混合 + * @param string $addChars 额外字符 + * @return string + */ +function rand_string($len=6,$type='',$addChars='') { + $str =''; + switch($type) { + case 0: + $chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.$addChars; + break; + case 1: + $chars= str_repeat('0123456789',3); + break; + case 2: + $chars='ABCDEFGHIJKLMNOPQRSTUVWXYZ'.$addChars; + break; + case 3: + $chars='abcdefghijklmnopqrstuvwxyz'.$addChars; + break; + case 4: + $chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借".$addChars; + break; + default : + // 默认去掉了容易混淆的字符oOLl和数字01,要添加请使用addChars参数 + $chars='ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789'.$addChars; + break; + } + if($len>10 ) {//位数过长重复字符串一定次数 + $chars= $type==1? str_repeat($chars,$len) : str_repeat($chars,5); + } + if($type!=4) { + $chars = str_shuffle($chars); + $str = substr($chars,0,$len); + }else{ + // 中文随机字 + for($i=0;$i<$len;$i++){ + $str.= msubstr($chars, floor(mt_rand(0,mb_strlen($chars,'utf-8')-1)),1); + } + } + return $str; +} + +/** + * 获取登录验证码 默认为4位数字 + * @param string $fmode 文件名 + * @return string + */ +function build_verify ($length=4,$mode=1) { + return rand_string($length,$mode); +} + +/** + * 字节格式化 把字节数格式为 B K M G T 描述的大小 + * @return string + */ +function byte_format($size, $dec=2) { + $a = array("B", "KB", "MB", "GB", "TB", "PB"); + $pos = 0; + while ($size >= 1024) { + $size /= 1024; + $pos++; + } + return round($size,$dec)." ".$a[$pos]; +} + +/** + * 检查字符串是否是UTF8编码 + * @param string $string 字符串 + * @return Boolean + */ +function is_utf8($string) { + return preg_match('%^(?: + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )*$%xs', $string); +} +/** + * 代码加亮 + * @param String $str 要高亮显示的字符串 或者 文件名 + * @param Boolean $show 是否输出 + * @return String + */ +function highlight_code($str,$show=false) { + if(file_exists($str)) { + $str = file_get_contents($str); + } + $str = stripslashes(trim($str)); + // The highlight string function encodes and highlights + // brackets so we need them to start raw + $str = str_replace(array('<', '>'), array('<', '>'), $str); + + // Replace any existing PHP tags to temporary markers so they don't accidentally + // break the string out of PHP, and thus, thwart the highlighting. + + $str = str_replace(array('<?php', '?>', '\\'), array('phptagopen', 'phptagclose', 'backslashtmp'), $str); + + // The highlight_string function requires that the text be surrounded + // by PHP tags. Since we don't know if A) the submitted text has PHP tags, + // or B) whether the PHP tags enclose the entire string, we will add our + // own PHP tags around the string along with some markers to make replacement easier later + + $str = ''; // '), array(''), $str); + $str = preg_replace('#color="(.*?)"#', 'style="color: \\1"', $str); + } + + // Remove our artificially added PHP + $str = preg_replace("#\.+?//tempstart\
\#is", "\n", $str); + $str = preg_replace("#\.+?//tempstart\
#is", "\n", $str); + $str = preg_replace("#//tempend.+#is", "
\n", $str); + + // Replace our markers back to PHP tags. + $str = str_replace(array('phptagopen', 'phptagclose', 'backslashtmp'), array('<?php', '?>', '\\'), $str); //", rtrim(ltrim($str,''),'')); + $result = '
    '; + foreach($line as $key=>$val) { + $result .= '
  1. '.$val.'
  2. '; + } + $result .= '
'; + $result = str_replace("\n", "", $result); + if( $show!== false) { + echo($result); + }else { + return $result; + } +} + +//输出安全的html +function h($text, $tags = null) { + $text = trim($text); + //完全过滤注释 + $text = preg_replace('//','',$text); + //完全过滤动态代码 + $text = preg_replace('/<\?|\?'.'>/','',$text); + //完全过滤js + $text = preg_replace('//','',$text); + + $text = str_replace('[','[',$text); + $text = str_replace(']',']',$text); + $text = str_replace('|','|',$text); + //过滤换行符 + $text = preg_replace('/\r?\n/','',$text); + //br + $text = preg_replace('//i','[br]',$text); + $text = preg_replace('//i','[br]',$text); + $text = preg_replace('/(\[br\]\s*){10,}/i','[br]',$text); + //过滤危险的属性,如:过滤on事件lang js + while(preg_match('/(<[^><]+)( lang|on|action|background|codebase|dynsrc|lowsrc)[^><]+/i',$text,$mat)){ + $text=str_replace($mat[0],$mat[1],$text); + } + while(preg_match('/(<[^><]+)(window\.|javascript:|js:|about:|file:|document\.|vbs:|cookie)([^><]*)/i',$text,$mat)){ + $text=str_replace($mat[0],$mat[1].$mat[3],$text); + } + if(empty($tags)) { + $tags = 'table|td|th|tr|i|b|u|strong|img|p|br|div|strong|em|ul|ol|li|dl|dd|dt|a'; + } + //允许的HTML标签 + $text = preg_replace('/<('.$tags.')( [^><\[\]]*)>/i','[\1\2]',$text); + $text = preg_replace('/<\/('.$tags.')>/Ui','[/\1]',$text); + //过滤多余html + $text = preg_replace('/<\/?(html|head|meta|link|base|basefont|body|bgsound|title|style|script|form|iframe|frame|frameset|applet|id|ilayer|layer|name|script|style|xml)[^><]*>/i','',$text); + //过滤合法的html标签 + while(preg_match('/<([a-z]+)[^><\[\]]*>[^><]*<\/\1>/i',$text,$mat)){ + $text=str_replace($mat[0],str_replace('>',']',str_replace('<','[',$mat[0])),$text); + } + //转换引号 + while(preg_match('/(\[[^\[\]]*=\s*)(\"|\')([^\2=\[\]]+)\2([^\[\]]*\])/i',$text,$mat)){ + $text=str_replace($mat[0],$mat[1].'|'.$mat[3].'|'.$mat[4],$text); + } + //过滤错误的单个引号 + while(preg_match('/\[[^\[\]]*(\"|\')[^\[\]]*\]/i',$text,$mat)){ + $text=str_replace($mat[0],str_replace($mat[1],'',$mat[0]),$text); + } + //转换其它所有不合法的 < > + $text = str_replace('<','<',$text); + $text = str_replace('>','>',$text); + $text = str_replace('"','"',$text); + //反转换 + $text = str_replace('[','<',$text); + $text = str_replace(']','>',$text); + $text = str_replace('|','"',$text); + //过滤多余空格 + $text = str_replace(' ',' ',$text); + return $text; +} + +function ubb($Text) { + $Text=trim($Text); + //$Text=htmlspecialchars($Text); + $Text=preg_replace("/\\t/is"," ",$Text); + $Text=preg_replace("/\[h1\](.+?)\[\/h1\]/is","

\\1

",$Text); + $Text=preg_replace("/\[h2\](.+?)\[\/h2\]/is","

\\1

",$Text); + $Text=preg_replace("/\[h3\](.+?)\[\/h3\]/is","

\\1

",$Text); + $Text=preg_replace("/\[h4\](.+?)\[\/h4\]/is","

\\1

",$Text); + $Text=preg_replace("/\[h5\](.+?)\[\/h5\]/is","
\\1
",$Text); + $Text=preg_replace("/\[h6\](.+?)\[\/h6\]/is","
\\1
",$Text); + $Text=preg_replace("/\[separator\]/is","",$Text); + $Text=preg_replace("/\[center\](.+?)\[\/center\]/is","
\\1
",$Text); + $Text=preg_replace("/\[url=http:\/\/([^\[]*)\](.+?)\[\/url\]/is","\\2",$Text); + $Text=preg_replace("/\[url=([^\[]*)\](.+?)\[\/url\]/is","\\2",$Text); + $Text=preg_replace("/\[url\]http:\/\/([^\[]*)\[\/url\]/is","\\1",$Text); + $Text=preg_replace("/\[url\]([^\[]*)\[\/url\]/is","\\1",$Text); + $Text=preg_replace("/\[img\](.+?)\[\/img\]/is","",$Text); + $Text=preg_replace("/\[color=(.+?)\](.+?)\[\/color\]/is","\\2",$Text); + $Text=preg_replace("/\[size=(.+?)\](.+?)\[\/size\]/is","\\2",$Text); + $Text=preg_replace("/\[sup\](.+?)\[\/sup\]/is","\\1",$Text); + $Text=preg_replace("/\[sub\](.+?)\[\/sub\]/is","\\1",$Text); + $Text=preg_replace("/\[pre\](.+?)\[\/pre\]/is","
\\1
",$Text); + $Text=preg_replace("/\[email\](.+?)\[\/email\]/is","\\1",$Text); + $Text=preg_replace("/\[colorTxt\](.+?)\[\/colorTxt\]/eis","color_txt('\\1')",$Text); + $Text=preg_replace("/\[emot\](.+?)\[\/emot\]/eis","emot('\\1')",$Text); + $Text=preg_replace("/\[i\](.+?)\[\/i\]/is","\\1",$Text); + $Text=preg_replace("/\[u\](.+?)\[\/u\]/is","\\1",$Text); + $Text=preg_replace("/\[b\](.+?)\[\/b\]/is","\\1",$Text); + $Text=preg_replace("/\[quote\](.+?)\[\/quote\]/is","
引用:
\\1
", $Text); + $Text=preg_replace("/\[code\](.+?)\[\/code\]/eis","highlight_code('\\1')", $Text); + $Text=preg_replace("/\[php\](.+?)\[\/php\]/eis","highlight_code('\\1')", $Text); + $Text=preg_replace("/\[sig\](.+?)\[\/sig\]/is","
\\1
", $Text); + $Text=preg_replace("/\\n/is","
",$Text); + return $Text; +} + +// 随机生成一组字符串 +function build_count_rand ($number,$length=4,$mode=1) { + if($mode==1 && $length + // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs + $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val); + + // straight replacements, the user should never need these since they're normal characters + // this prevents like + $search = 'abcdefghijklmnopqrstuvwxyz'; + $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $search .= '1234567890!@#$%^&*()'; + $search .= '~`";:?+/={}[]-_|\'\\'; + for ($i = 0; $i < strlen($search); $i++) { + // ;? matches the ;, which is optional + // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars + + // @ @ search for the hex values + $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ; + // @ @ 0{0,7} matches '0' zero to seven times + $val = preg_replace('/(�{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ; + } + + // now the only remaining whitespace attacks are \t, \n, and \r + $ra1 = array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base'); + $ra2 = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload'); + $ra = array_merge($ra1, $ra2); + + $found = true; // keep replacing as long as the previous round replaced something + while ($found == true) { + $val_before = $val; + for ($i = 0; $i < sizeof($ra); $i++) { + $pattern = '/'; + for ($j = 0; $j < strlen($ra[$i]); $j++) { + if ($j > 0) { + $pattern .= '('; + $pattern .= '(&#[xX]0{0,8}([9ab]);)'; + $pattern .= '|'; + $pattern .= '|(�{0,8}([9|10|13]);)'; + $pattern .= ')*'; + } + $pattern .= $ra[$i][$j]; + } + $pattern .= '/i'; + $replacement = substr($ra[$i], 0, 2).''.substr($ra[$i], 2); // add in <> to nerf the tag + $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags + if ($val_before == $val) { + // no replacements were made, so exit the loop + $found = false; + } + } + } + return $val; +} + +/** + * 把返回的数据集转换成Tree + * @access public + * @param array $list 要转换的数据集 + * @param string $pid parent标记字段 + * @param string $level level标记字段 + * @return array + */ +function list_to_tree($list, $pk='id',$pid = 'pid',$child = '_child',$root=0) { + // 创建Tree + $tree = array(); + if(is_array($list)) { + // 创建基于主键的数组引用 + $refer = array(); + foreach ($list as $key => $data) { + $refer[$data[$pk]] =& $list[$key]; + } + foreach ($list as $key => $data) { + // 判断是否存在parent + $parentId = $data[$pid]; + if ($root == $parentId) { + $tree[] =& $list[$key]; + }else{ + if (isset($refer[$parentId])) { + $parent =& $refer[$parentId]; + $parent[$child][] =& $list[$key]; + } + } + } + } + return $tree; +} + +/** + * 对查询结果集进行排序 + * @access public + * @param array $list 查询结果 + * @param string $field 排序的字段名 + * @param array $sortby 排序类型 + * asc正向排序 desc逆向排序 nat自然排序 + * @return array + */ +function list_sort_by($list,$field, $sortby='asc') { + if(is_array($list)){ + $refer = $resultSet = array(); + foreach ($list as $i => $data) + $refer[$i] = &$data[$field]; + switch ($sortby) { + case 'asc': // 正向排序 + asort($refer); + break; + case 'desc':// 逆向排序 + arsort($refer); + break; + case 'nat': // 自然排序 + natcasesort($refer); + break; + } + foreach ( $refer as $key=> $val) + $resultSet[] = &$list[$key]; + return $resultSet; + } + return false; +} + +/** + * 在数据列表中搜索 + * @access public + * @param array $list 数据列表 + * @param mixed $condition 查询条件 + * 支持 array('name'=>$value) 或者 name=$value + * @return array + */ +function list_search($list,$condition) { + if(is_string($condition)) + parse_str($condition,$condition); + // 返回的结果集合 + $resultSet = array(); + foreach ($list as $key=>$data){ + $find = false; + foreach ($condition as $field=>$value){ + if(isset($data[$field])) { + if(0 === strpos($value,'/')) { + $find = preg_match($value,$data[$field]); + }elseif($data[$field]==$value){ + $find = true; + } + } + } + if($find) + $resultSet[] = &$list[$key]; + } + return $resultSet; +} + +// 自动转换字符集 支持数组转换 +function auto_charset($fContents, $from='gbk', $to='utf-8') { + $from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from; + $to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to; + if (strtoupper($from) === strtoupper($to) || empty($fContents) || (is_scalar($fContents) && !is_string($fContents))) { + //如果编码相同或者非字符串标量则不转换 + return $fContents; + } + if (is_string($fContents)) { + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($fContents, $to, $from); + } elseif (function_exists('iconv')) { + return iconv($from, $to, $fContents); + } else { + return $fContents; + } + } elseif (is_array($fContents)) { + foreach ($fContents as $key => $val) { + $_key = auto_charset($key, $from, $to); + $fContents[$_key] = auto_charset($val, $from, $to); + if ($key != $_key) + unset($fContents[$key]); + } + return $fContents; + } + else { + return $fContents; + } +} diff --git a/ThinkPHP/Extend/Library/ORG/Crypt/Base64.class.php b/ThinkPHP/Extend/Library/ORG/Crypt/Base64.class.php new file mode 100644 index 0000000..d6832e7 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Crypt/Base64.class.php @@ -0,0 +1,71 @@ + +// +---------------------------------------------------------------------- + +/** + * Base64 加密实现类 + * @category ORG + * @package ORG + * @subpackage Crypt + * @author liu21st + */ +class Base64 { + + /** + * 加密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function encrypt($data,$key) { + $key = md5($key); + $data = base64_encode($data); + $x=0; + $len = strlen($data); + $l = strlen($key); + for ($i=0;$i< $len;$i++) { + if ($x== $l) $x=0; + $char .=substr($key,$x,1); + $x++; + } + for ($i=0;$i< $len;$i++) { + $str .=chr(ord(substr($data,$i,1))+(ord(substr($char,$i,1)))%256); + } + return $str; + } + + /** + * 解密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($data,$key) { + $key = md5($key); + $x=0; + $len = strlen($data); + $l = strlen($key); + for ($i=0;$i< $len;$i++) { + if ($x== $l) $x=0; + $char .=substr($key,$x,1); + $x++; + } + for ($i=0;$i< $len;$i++) { + if (ord(substr($data,$i,1)) +// +---------------------------------------------------------------------- + +/** + * Crypt 加密实现类 + * @category ORG + * @package ORG + * @subpackage Crypt + * @author liu21st + */ +class Crypt { + + /** + * 加密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + function encrypt($str,$key,$toBase64=false){ + $r = md5($key); + $c=0; + $v = ""; + $len = strlen($str); + $l = strlen($r); + for ($i=0;$i<$len;$i++){ + if ($c== $l) $c=0; + $v.= substr($r,$c,1) . + (substr($str,$i,1) ^ substr($r,$c,1)); + $c++; + } + if($toBase64) { + return base64_encode(self::ed($v,$key)); + }else { + return self::ed($v,$key); + } + + } + + /** + * 解密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + function decrypt($str,$key,$toBase64=false) { + if($toBase64) { + $str = self::ed(base64_decode($str),$key); + }else { + $str = self::ed($str,$key); + } + $v = ""; + $len = strlen($str); + for ($i=0;$i<$len;$i++){ + $md5 = substr($str,$i,1); + $i++; + $v.= (substr($str,$i,1) ^ $md5); + } + return $v; + } + + + function ed($str,$key) { + $r = md5($key); + $c=0; + $v = ""; + $len = strlen($str); + $l = strlen($r); + for ($i=0;$i<$len;$i++) { + if ($c==$l) $c=0; + $v.= substr($str,$i,1) ^ substr($r,$c,1); + $c++; + } + return $v; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Crypt/Des.class.php b/ThinkPHP/Extend/Library/ORG/Crypt/Des.class.php new file mode 100644 index 0000000..5d174a5 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Crypt/Des.class.php @@ -0,0 +1,240 @@ + +// +---------------------------------------------------------------------- + +/** + * Des 加密实现类 + * Converted from JavaScript to PHP by Jim Gibbs, June 2004 Paul Tero, July 2001 + * Optimised for performance with large blocks by Michael Hayworth, November 2001 + * http://www.netdealing.com + * @category ORG + * @package ORG + * @subpackage Crypt + * @author liu21st + */ + +class Des { + + /** + * 加密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + function encrypt($str, $key) { + if ($str == "") { + return ""; + } + return self::_des($key,$str,1); + } + + /** + * 解密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + function decrypt($str, $key) { + if ($str == "") { + return ""; + } + return self::_des($key,$str,0); + } + + /** + * Des算法 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + function _des($key, $message, $encrypt, $mode=0, $iv=null) { + //declaring this locally speeds things up a bit + $spfunction1 = array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004); + $spfunction2 = array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000); + $spfunction3 = array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200); + $spfunction4 = array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080); + $spfunction5 = array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100); + $spfunction6 = array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010); + $spfunction7 = array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002); + $spfunction8 = array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000); + $masks = array (4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0); + + //create the 16 or 48 subkeys we will need + $keys = self::_createKeys ($key); + $m=0; + $len = strlen($message); + $chunk = 0; + //set up the loops for single and triple des + $iterations = ((count($keys) == 32) ? 3 : 9); //single or triple des + if ($iterations == 3) {$looping = (($encrypt) ? array (0, 32, 2) : array (30, -2, -2));} + else {$looping = (($encrypt) ? array (0, 32, 2, 62, 30, -2, 64, 96, 2) : array (94, 62, -2, 32, 64, 2, 30, -2, -2));} + + $message .= (chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0)); //pad the message out with null bytes + //store the result here + $result = ""; + $tempresult = ""; + + if ($mode == 1) { //CBC mode + $cbcleft = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++}); + $cbcright = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++}); + $m=0; + } + + //loop through each 64 bit chunk of the message + while ($m < $len) { + $left = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++}); + $right = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++}); + + //for Cipher Block Chaining mode, xor the message with the previous result + if ($mode == 1) {if ($encrypt) {$left ^= $cbcleft; $right ^= $cbcright;} else {$cbcleft2 = $cbcleft; $cbcright2 = $cbcright; $cbcleft = $left; $cbcright = $right;}} + + //first each 64 but chunk of the message must be permuted according to IP + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; $right ^= $temp; $left ^= ($temp << 16); + $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; $left ^= $temp; $right ^= ($temp << 2); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + + $left = (($left << 1) | ($left >> 31 & $masks[31])); + $right = (($right << 1) | ($right >> 31 & $masks[31])); + + //do this either 1 or 3 times for each chunk of the message + for ($j=0; $j<$iterations; $j+=3) { + $endloop = $looping[$j+1]; + $loopinc = $looping[$j+2]; + //now go through and perform the encryption or decryption + for ($i=$looping[$j]; $i!=$endloop; $i+=$loopinc) { //for efficiency + $right1 = $right ^ $keys[$i]; + $right2 = (($right >> 4 & $masks[4]) | ($right << 28)) ^ $keys[$i+1]; + //the result is attained by passing these bytes through the S selection functions + $temp = $left; + $left = $right; + $right = $temp ^ ($spfunction2[($right1 >> 24 & $masks[24]) & 0x3f] | $spfunction4[($right1 >> 16 & $masks[16]) & 0x3f] + | $spfunction6[($right1 >> 8 & $masks[8]) & 0x3f] | $spfunction8[$right1 & 0x3f] + | $spfunction1[($right2 >> 24 & $masks[24]) & 0x3f] | $spfunction3[($right2 >> 16 & $masks[16]) & 0x3f] + | $spfunction5[($right2 >> 8 & $masks[8]) & 0x3f] | $spfunction7[$right2 & 0x3f]); + } + $temp = $left; $left = $right; $right = $temp; //unreverse left and right + } //for either 1 or 3 iterations + + //move then each one bit to the right + $left = (($left >> 1 & $masks[1]) | ($left << 31)); + $right = (($right >> 1 & $masks[1]) | ($right << 31)); + + //now perform IP-1, which is IP in the opposite direction + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; $left ^= $temp; $right ^= ($temp << 2); + $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; $right ^= $temp; $left ^= ($temp << 16); + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + + //for Cipher Block Chaining mode, xor the message with the previous result + if ($mode == 1) {if ($encrypt) {$cbcleft = $left; $cbcright = $right;} else {$left ^= $cbcleft2; $right ^= $cbcright2;}} + $tempresult .= (chr($left>>24 & $masks[24]) . chr(($left>>16 & $masks[16]) & 0xff) . chr(($left>>8 & $masks[8]) & 0xff) . chr($left & 0xff) . chr($right>>24 & $masks[24]) . chr(($right>>16 & $masks[16]) & 0xff) . chr(($right>>8 & $masks[8]) & 0xff) . chr($right & 0xff)); + + $chunk += 8; + if ($chunk == 512) {$result .= $tempresult; $tempresult = ""; $chunk = 0;} + } //for every 8 characters, or 64 bits in the message + + //return the result as an array + return ($result . $tempresult); + } //end of des + + /** + * createKeys + * this takes as input a 64 bit key (even though only 56 bits are used) + * as an array of 2 integers, and returns 16 48 bit keys + * @access static + * @param string $key 加密key + * @return string + */ + function _createKeys ($key) { + //declaring this locally speeds things up a bit + $pc2bytes0 = array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204); + $pc2bytes1 = array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101); + $pc2bytes2 = array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808); + $pc2bytes3 = array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000); + $pc2bytes4 = array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010); + $pc2bytes5 = array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420); + $pc2bytes6 = array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002); + $pc2bytes7 = array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800); + $pc2bytes8 = array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002); + $pc2bytes9 = array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408); + $pc2bytes10 = array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020); + $pc2bytes11 = array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200); + $pc2bytes12 = array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010); + $pc2bytes13 = array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105); + $masks = array (4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0); + + //how many iterations (1 for des, 3 for triple des) + $iterations = ((strlen($key) >= 24) ? 3 : 1); + //stores the return keys + $keys = array (); // size = 32 * iterations but you don't specify this in php + //now define the left shifts which need to be done + $shifts = array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0); + //other variables + $m=0; + $n=0; + + for ($j=0; $j<$iterations; $j++) { //either 1 or 3 iterations + $left = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++}); + $right = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++}); + + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; $left ^= $temp; $right ^= ($temp << -16); + $temp = (($left >> 2 & $masks[2]) ^ $right) & 0x33333333; $right ^= $temp; $left ^= ($temp << 2); + $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; $left ^= $temp; $right ^= ($temp << -16); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + + //the right side needs to be shifted and to get the last four bits of the left side + $temp = ($left << 8) | (($right >> 20 & $masks[20]) & 0x000000f0); + //left needs to be put upside down + $left = ($right << 24) | (($right << 8) & 0xff0000) | (($right >> 8 & $masks[8]) & 0xff00) | (($right >> 24 & $masks[24]) & 0xf0); + $right = $temp; + + //now go through and perform these shifts on the left and right keys + for ($i=0; $i < count($shifts); $i++) { + //shift the keys either one or two bits to the left + if ($shifts[$i] > 0) { + $left = (($left << 2) | ($left >> 26 & $masks[26])); + $right = (($right << 2) | ($right >> 26 & $masks[26])); + } else { + $left = (($left << 1) | ($left >> 27 & $masks[27])); + $right = (($right << 1) | ($right >> 27 & $masks[27])); + } + $left = $left & -0xf; + $right = $right & -0xf; + + //now apply PC-2, in such a way that E is easier when encrypting or decrypting + //this conversion will look like PC-2 except only the last 6 bits of each byte are used + //rather than 48 consecutive bits and the order of lines will be according to + //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7 + $lefttemp = $pc2bytes0[$left >> 28 & $masks[28]] | $pc2bytes1[($left >> 24 & $masks[24]) & 0xf] + | $pc2bytes2[($left >> 20 & $masks[20]) & 0xf] | $pc2bytes3[($left >> 16 & $masks[16]) & 0xf] + | $pc2bytes4[($left >> 12 & $masks[12]) & 0xf] | $pc2bytes5[($left >> 8 & $masks[8]) & 0xf] + | $pc2bytes6[($left >> 4 & $masks[4]) & 0xf]; + $righttemp = $pc2bytes7[$right >> 28 & $masks[28]] | $pc2bytes8[($right >> 24 & $masks[24]) & 0xf] + | $pc2bytes9[($right >> 20 & $masks[20]) & 0xf] | $pc2bytes10[($right >> 16 & $masks[16]) & 0xf] + | $pc2bytes11[($right >> 12 & $masks[12]) & 0xf] | $pc2bytes12[($right >> 8 & $masks[8]) & 0xf] + | $pc2bytes13[($right >> 4 & $masks[4]) & 0xf]; + $temp = (($righttemp >> 16 & $masks[16]) ^ $lefttemp) & 0x0000ffff; + $keys[$n++] = $lefttemp ^ $temp; $keys[$n++] = $righttemp ^ ($temp << 16); + } + } //for each iterations + //return the keys we've created + return $keys; + } //end of des_createKeys + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Crypt/Hmac.class.php b/ThinkPHP/Extend/Library/ORG/Crypt/Hmac.class.php new file mode 100644 index 0000000..6bc398b --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Crypt/Hmac.class.php @@ -0,0 +1,70 @@ + +// +---------------------------------------------------------------------- + +/** + * HMAC 加密实现类 + * @category ORG + * @package ORG + * @subpackage Crypt + * @author cevin + */ +class Hmac { + + /** + * SHA1加密 + * @access static + * @param string $key 加密key + * @param string $str 字符串 + * @return string + */ + public static function sha1($key,$str) { + $blocksize=64; + $hashfunc='sha1'; + if (strlen($key)>$blocksize) + $key=pack('H*', $hashfunc($key)); + $key=str_pad($key,$blocksize,chr(0x00)); + $ipad=str_repeat(chr(0x36),$blocksize); + $opad=str_repeat(chr(0x5c),$blocksize); + $hmac = pack( + 'H*',$hashfunc( + ($key^$opad).pack( + 'H*',$hashfunc( + ($key^$ipad).$str + ) + ) + ) + ); + return $hmac; + } + + /** + * MD5加密 + * @access static + * @param string $key 加密key + * @param string $str 字符串 + * @return string + */ + public static function md5($key, $str) { + $b = 64; + if (strlen($key) > $b) { + $key = pack("H*",md5($key)); + } + + $key = str_pad($key, $b, chr(0x00)); + $ipad = str_pad('', $b, chr(0x36)); + $opad = str_pad('', $b, chr(0x5c)); + $k_ipad = $key ^ $ipad ; + $k_opad = $key ^ $opad; + + return md5($k_opad . pack("H*",md5($k_ipad . $str))); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Crypt/Rsa.class.php b/ThinkPHP/Extend/Library/ORG/Crypt/Rsa.class.php new file mode 100644 index 0000000..dcb6f3d --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Crypt/Rsa.class.php @@ -0,0 +1,184 @@ + +// +---------------------------------------------------------------------- +define("BCCOMP_LARGER", 1); +/** + * Rsa 加密实现类 + * @category ORG + * @package ORG + * @subpackage Crypt + * @author liu21st + */ +class Rsa { + + /** + * 加密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function encrypt($message, $public_key, $modulus, $keylength) { + $padded = self::add_PKCS1_padding($message, true, $keylength / 8); + $number = self::binary_to_number($padded); + $encrypted = self::pow_mod($number, $public_key, $modulus); + $result = self::number_to_binary($encrypted, $keylength / 8); + return $result; + } + + /** + * 解密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($message, $private_key, $modulus, $keylength) { + $number = self::binary_to_number($message); + $decrypted = self::pow_mod($number, $private_key, $modulus); + $result = self::number_to_binary($decrypted, $keylength / 8); + + return self::remove_PKCS1_padding($result, $keylength / 8); + } + + function sign($message, $private_key, $modulus, $keylength) { + $padded = self::add_PKCS1_padding($message, false, $keylength / 8); + $number = self::binary_to_number($padded); + $signed = self::pow_mod($number, $private_key, $modulus); + $result = self::number_to_binary($signed, $keylength / 8); + return $result; + } + + function verify($message, $public_key, $modulus, $keylength) { + return decrypt($message, $public_key, $modulus, $keylength); + } + + function pow_mod($p, $q, $r) { + // Extract powers of 2 from $q + $factors = array(); + $div = $q; + $power_of_two = 0; + while(bccomp($div, "0") == BCCOMP_LARGER) + { + $rem = bcmod($div, 2); + $div = bcdiv($div, 2); + + if($rem) array_push($factors, $power_of_two); + $power_of_two++; + } + // Calculate partial results for each factor, using each partial result as a + // starting point for the next. This depends of the factors of two being + // generated in increasing order. + $partial_results = array(); + $part_res = $p; + $idx = 0; + foreach($factors as $factor) + { + while($idx < $factor) + { + $part_res = bcpow($part_res, "2"); + $part_res = bcmod($part_res, $r); + + $idx++; + } + array_push($partial_results, $part_res); + } + // Calculate final result + $result = "1"; + foreach($partial_results as $part_res) + { + $result = bcmul($result, $part_res); + $result = bcmod($result, $r); + } + return $result; + } + + //-- + // Function to add padding to a decrypted string + // We need to know if this is a private or a public key operation [4] + //-- + function add_PKCS1_padding($data, $isPublicKey, $blocksize) { + $pad_length = $blocksize - 3 - strlen($data); + + if($isPublicKey) + { + $block_type = "\x02"; + + $padding = ""; + for($i = 0; $i < $pad_length; $i++) + { + $rnd = mt_rand(1, 255); + $padding .= chr($rnd); + } + } + else + { + $block_type = "\x01"; + $padding = str_repeat("\xFF", $pad_length); + } + return "\x00" . $block_type . $padding . "\x00" . $data; + } + + //-- + // Remove padding from a decrypted string + // See [4] for more details. + //-- + function remove_PKCS1_padding($data, $blocksize) { + assert(strlen($data) == $blocksize); + $data = substr($data, 1); + + // We cannot deal with block type 0 + if($data{0} == '\0') + die("Block type 0 not implemented."); + + // Then the block type must be 1 or 2 + assert(($data{0} == "\x01") || ($data{0} == "\x02")); + + // Remove the padding + $offset = strpos($data, "\0", 1); + return substr($data, $offset + 1); + } + + //-- + // Convert binary data to a decimal number + //-- + function binary_to_number($data) { + $base = "256"; + $radix = "1"; + $result = "0"; + + for($i = strlen($data) - 1; $i >= 0; $i--) + { + $digit = ord($data{$i}); + $part_res = bcmul($digit, $radix); + $result = bcadd($result, $part_res); + $radix = bcmul($radix, $base); + } + return $result; + } + + //-- + // Convert a number back into binary form + //-- + function number_to_binary($number, $blocksize) { + $base = "256"; + $result = ""; + $div = $number; + while($div > 0) + { + $mod = bcmod($div, $base); + $div = bcdiv($div, $base); + + $result = chr($mod) . $result; + } + return str_pad($result, $blocksize, "\x00", STR_PAD_LEFT); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Crypt/Xxtea.class.php b/ThinkPHP/Extend/Library/ORG/Crypt/Xxtea.class.php new file mode 100644 index 0000000..8d7f4bc --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Crypt/Xxtea.class.php @@ -0,0 +1,119 @@ + +// +---------------------------------------------------------------------- + +/** + * Xxtea 加密实现类 + * @category ORG + * @package ORG + * @subpackage Crypt + * @author liu21st + */ +class Xxtea { + + /** + * 加密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function encrypt($str, $key) { + if ($str == "") { + return ""; + } + $v = self::str2long($str, true); + $k = self::str2long($key, false); + $n = count($v) - 1; + + $z = $v[$n]; + $y = $v[0]; + $delta = 0x9E3779B9; + $q = floor(6 + 52 / ($n + 1)); + $sum = 0; + while (0 < $q--) { + $sum = self::int32($sum + $delta); + $e = $sum >> 2 & 3; + for ($p = 0; $p < $n; $p++) { + $y = $v[$p + 1]; + $mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $z = $v[$p] = self::int32($v[$p] + $mx); + } + $y = $v[0]; + $mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $z = $v[$n] = self::int32($v[$n] + $mx); + } + return self::long2str($v, false); + } + + /** + * 解密字符串 + * @access static + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($str, $key) { + if ($str == "") { + return ""; + } + $v = self::str2long($str, false); + $k = self::str2long($key, false); + $n = count($v) - 1; + + $z = $v[$n]; + $y = $v[0]; + $delta = 0x9E3779B9; + $q = floor(6 + 52 / ($n + 1)); + $sum = self::int32($q * $delta); + while ($sum != 0) { + $e = $sum >> 2 & 3; + for ($p = $n; $p > 0; $p--) { + $z = $v[$p - 1]; + $mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $y = $v[$p] = self::int32($v[$p] - $mx); + } + $z = $v[$n]; + $mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $y = $v[0] = self::int32($v[0] - $mx); + $sum = self::int32($sum - $delta); + } + return self::long2str($v, true); + } + + private static function long2str($v, $w) { + $len = count($v); + $s = array(); + for ($i = 0; $i < $len; $i++) { + $s[$i] = pack("V", $v[$i]); + } + if ($w) { + return substr(join('', $s), 0, $v[$len - 1]); + }else{ + return join('', $s); + } + } + + private static function str2long($s, $w) { + $v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3)); + $v = array_values($v); + if ($w) { + $v[count($v)] = strlen($s); + } + return $v; + } + + private static function int32($n) { + while ($n >= 2147483648) $n -= 4294967296; + while ($n <= -2147483649) $n += 4294967296; + return (int)$n; + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Net/Http.class.php b/ThinkPHP/Extend/Library/ORG/Net/Http.class.php new file mode 100644 index 0000000..ef037e8 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Net/Http.class.php @@ -0,0 +1,509 @@ + +// +---------------------------------------------------------------------- + +/** + * Http 工具类 + * 提供一系列的Http方法 + * @category ORG + * @package ORG + * @subpackage Net + * @author liu21st + */ +class Http { + + /** + * 采集远程文件 + * @access public + * @param string $remote 远程文件名 + * @param string $local 本地保存文件名 + * @return mixed + */ + static public function curlDownload($remote,$local) { + $cp = curl_init($remote); + $fp = fopen($local,"w"); + curl_setopt($cp, CURLOPT_FILE, $fp); + curl_setopt($cp, CURLOPT_HEADER, 0); + curl_exec($cp); + curl_close($cp); + fclose($fp); + } + + /** + * 使用 fsockopen 通过 HTTP 协议直接访问(采集)远程文件 + * 如果主机或服务器没有开启 CURL 扩展可考虑使用 + * fsockopen 比 CURL 稍慢,但性能稳定 + * @static + * @access public + * @param string $url 远程URL + * @param array $conf 其他配置信息 + * int limit 分段读取字符个数 + * string post post的内容,字符串或数组,key=value&形式 + * string cookie 携带cookie访问,该参数是cookie内容 + * string ip 如果该参数传入,$url将不被使用,ip访问优先 + * int timeout 采集超时时间 + * bool block 是否阻塞访问,默认为true + * @return mixed + */ + static public function fsockopenDownload($url, $conf = array()) { + $return = ''; + if(!is_array($conf)) return $return; + + $matches = parse_url($url); + !isset($matches['host']) && $matches['host'] = ''; + !isset($matches['path']) && $matches['path'] = ''; + !isset($matches['query']) && $matches['query'] = ''; + !isset($matches['port']) && $matches['port'] = ''; + $host = $matches['host']; + $path = $matches['path'] ? $matches['path'].($matches['query'] ? '?'.$matches['query'] : '') : '/'; + $port = !empty($matches['port']) ? $matches['port'] : 80; + + $conf_arr = array( + 'limit' => 0, + 'post' => '', + 'cookie' => '', + 'ip' => '', + 'timeout' => 15, + 'block' => TRUE, + ); + + foreach (array_merge($conf_arr, $conf) as $k=>$v) ${$k} = $v; + + if($post) { + if(is_array($post)) + { + $post = http_build_query($post); + } + $out = "POST $path HTTP/1.0\r\n"; + $out .= "Accept: */*\r\n"; + //$out .= "Referer: $boardurl\r\n"; + $out .= "Accept-Language: zh-cn\r\n"; + $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n"; + $out .= "Host: $host\r\n"; + $out .= 'Content-Length: '.strlen($post)."\r\n"; + $out .= "Connection: Close\r\n"; + $out .= "Cache-Control: no-cache\r\n"; + $out .= "Cookie: $cookie\r\n\r\n"; + $out .= $post; + } else { + $out = "GET $path HTTP/1.0\r\n"; + $out .= "Accept: */*\r\n"; + //$out .= "Referer: $boardurl\r\n"; + $out .= "Accept-Language: zh-cn\r\n"; + $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n"; + $out .= "Host: $host\r\n"; + $out .= "Connection: Close\r\n"; + $out .= "Cookie: $cookie\r\n\r\n"; + } + $fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout); + if(!$fp) { + return ''; + } else { + stream_set_blocking($fp, $block); + stream_set_timeout($fp, $timeout); + @fwrite($fp, $out); + $status = stream_get_meta_data($fp); + if(!$status['timed_out']) { + while (!feof($fp)) { + if(($header = @fgets($fp)) && ($header == "\r\n" || $header == "\n")) { + break; + } + } + + $stop = false; + while(!feof($fp) && !$stop) { + $data = fread($fp, ($limit == 0 || $limit > 8192 ? 8192 : $limit)); + $return .= $data; + if($limit) { + $limit -= strlen($data); + $stop = $limit <= 0; + } + } + } + @fclose($fp); + return $return; + } + } + + /** + * 下载文件 + * 可以指定下载显示的文件名,并自动发送相应的Header信息 + * 如果指定了content参数,则下载该参数的内容 + * @static + * @access public + * @param string $filename 下载文件名 + * @param string $showname 下载显示的文件名 + * @param string $content 下载的内容 + * @param integer $expire 下载内容浏览器缓存时间 + * @return void + */ + static public function download ($filename, $showname='',$content='',$expire=180) { + if(is_file($filename)) { + $length = filesize($filename); + }elseif(is_file(UPLOAD_PATH.$filename)) { + $filename = UPLOAD_PATH.$filename; + $length = filesize($filename); + }elseif($content != '') { + $length = strlen($content); + }else { + throw_exception($filename.L('下载文件不存在!')); + } + if(empty($showname)) { + $showname = $filename; + } + $showname = basename($showname); + if(!empty($filename)) { + $type = mime_content_type($filename); + }else{ + $type = "application/octet-stream"; + } + //发送Http Header信息 开始下载 + header("Pragma: public"); + header("Cache-control: max-age=".$expire); + //header('Cache-Control: no-store, no-cache, must-revalidate'); + header("Expires: " . gmdate("D, d M Y H:i:s",time()+$expire) . "GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s",time()) . "GMT"); + header("Content-Disposition: attachment; filename=".$showname); + header("Content-Length: ".$length); + header("Content-type: ".$type); + header('Content-Encoding: none'); + header("Content-Transfer-Encoding: binary" ); + if($content == '' ) { + readfile($filename); + }else { + echo($content); + } + exit(); + } + + /** + * 显示HTTP Header 信息 + * @return string + */ + static function getHeaderInfo($header='',$echo=true) { + ob_start(); + $headers = getallheaders(); + if(!empty($header)) { + $info = $headers[$header]; + echo($header.':'.$info."\n"); ; + }else { + foreach($headers as $key=>$val) { + echo("$key:$val\n"); + } + } + $output = ob_get_clean(); + if ($echo) { + echo (nl2br($output)); + }else { + return $output; + } + + } + + /** + * HTTP Protocol defined status codes + * @param int $num + */ + static function sendHttpStatus($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 => 'Found', // 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]); + } + } +}//类定义结束 +if( !function_exists ('mime_content_type')) { + /** + * 获取文件的mime_content类型 + * @return string + */ + function mime_content_type($filename) { + static $contentType = array( + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'asc' => 'application/pgp', //changed by skwashd - was text/plain + 'asf' => 'video/x-ms-asf', + 'asx' => 'video/x-ms-asf', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'bcpio' => 'application/x-bcpio', + 'bin' => 'application/octet-stream', + 'bmp' => 'image/bmp', + 'c' => 'text/plain', // or 'text/x-csrc', //added by skwashd + 'cc' => 'text/plain', // or 'text/x-c++src', //added by skwashd + 'cs' => 'text/plain', //added by skwashd - for C# src + 'cpp' => 'text/x-c++src', //added by skwashd + 'cxx' => 'text/x-c++src', //added by skwashd + 'cdf' => 'application/x-netcdf', + 'class' => 'application/octet-stream',//secure but application/java-class is correct + 'com' => 'application/octet-stream',//added by skwashd + 'cpio' => 'application/x-cpio', + 'cpt' => 'application/mac-compactpro', + 'csh' => 'application/x-csh', + 'css' => 'text/css', + 'csv' => 'text/comma-separated-values',//added by skwashd + 'dcr' => 'application/x-director', + 'diff' => 'text/diff', + 'dir' => 'application/x-director', + 'dll' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'doc' => 'application/msword', + 'dot' => 'application/msword',//added by skwashd + 'dvi' => 'application/x-dvi', + 'dxr' => 'application/x-director', + 'eps' => 'application/postscript', + 'etx' => 'text/x-setext', + 'exe' => 'application/octet-stream', + 'ez' => 'application/andrew-inset', + 'gif' => 'image/gif', + 'gtar' => 'application/x-gtar', + 'gz' => 'application/x-gzip', + 'h' => 'text/plain', // or 'text/x-chdr',//added by skwashd + 'h++' => 'text/plain', // or 'text/x-c++hdr', //added by skwashd + 'hh' => 'text/plain', // or 'text/x-c++hdr', //added by skwashd + 'hpp' => 'text/plain', // or 'text/x-c++hdr', //added by skwashd + 'hxx' => 'text/plain', // or 'text/x-c++hdr', //added by skwashd + 'hdf' => 'application/x-hdf', + 'hqx' => 'application/mac-binhex40', + 'htm' => 'text/html', + 'html' => 'text/html', + 'ice' => 'x-conference/x-cooltalk', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'iges' => 'model/iges', + 'igs' => 'model/iges', + 'jar' => 'application/x-jar', //added by skwashd - alternative mime type + 'java' => 'text/x-java-source', //added by skwashd + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'js' => 'application/x-javascript', + 'kar' => 'audio/midi', + 'latex' => 'application/x-latex', + 'lha' => 'application/octet-stream', + 'log' => 'text/plain', + 'lzh' => 'application/octet-stream', + 'm3u' => 'audio/x-mpegurl', + 'man' => 'application/x-troff-man', + 'me' => 'application/x-troff-me', + 'mesh' => 'model/mesh', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mif' => 'application/vnd.mif', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpga' => 'audio/mpeg', + 'ms' => 'application/x-troff-ms', + 'msh' => 'model/mesh', + 'mxu' => 'video/vnd.mpegurl', + 'nc' => 'application/x-netcdf', + 'oda' => 'application/oda', + 'patch' => 'text/diff', + 'pbm' => 'image/x-portable-bitmap', + 'pdb' => 'chemical/x-pdb', + 'pdf' => 'application/pdf', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp',//added by skwashd + 'php' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php3', + 'pl' => 'application/x-perl', + 'pm' => 'application/x-perl', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'po' => 'text/plain', + 'ppm' => 'image/x-portable-pixmap', + 'ppt' => 'application/vnd.ms-powerpoint', + 'ps' => 'application/postscript', + 'qt' => 'video/quicktime', + 'ra' => 'audio/x-realaudio', + 'rar' => 'application/octet-stream', + 'ram' => 'audio/x-pn-realaudio', + 'ras' => 'image/x-cmu-raster', + 'rgb' => 'image/x-rgb', + 'rm' => 'audio/x-pn-realaudio', + 'roff' => 'application/x-troff', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'rtf' => 'text/rtf', + 'rtx' => 'text/richtext', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shtml' => 'text/html', + 'silo' => 'model/mesh', + 'sit' => 'application/x-stuffit', + 'skd' => 'application/x-koan', + 'skm' => 'application/x-koan', + 'skp' => 'application/x-koan', + 'skt' => 'application/x-koan', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'snd' => 'audio/basic', + 'so' => 'application/octet-stream', + 'spl' => 'application/x-futuresplash', + 'src' => 'application/x-wais-source', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'swf' => 'application/x-shockwave-flash', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'application/x-troff', + 'tar' => 'application/x-tar', + 'tcl' => 'application/x-tcl', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'tgz' => 'application/x-gtar', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tr' => 'application/x-troff', + 'tsv' => 'text/tab-separated-values', + 'txt' => 'text/plain', + 'ustar' => 'application/x-ustar', + 'vbs' => 'text/plain', //added by skwashd - for obvious reasons + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcs' => 'text/calendar', + 'vfb' => 'text/calendar', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-ms-wmz', + 'wrl' => 'model/vrml', + 'wvx' => 'video/x-ms-wvx', + 'xbm' => 'image/x-xbitmap', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xls' => 'application/vnd.ms-excel', + 'xlt' => 'application/vnd.ms-excel', + 'xml' => 'application/xml', + 'xpm' => 'image/x-xpixmap', + 'xsl' => 'text/xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'z' => 'application/x-compress', + 'zip' => 'application/zip', + ); + $type = strtolower(substr(strrchr($filename, '.'),1)); + if(isset($contentType[$type])) { + $mime = $contentType[$type]; + }else { + $mime = 'application/octet-stream'; + } + return $mime; + } +} + +if(!function_exists('image_type_to_extension')){ + function image_type_to_extension($imagetype) { + if(empty($imagetype)) return false; + switch($imagetype) { + case IMAGETYPE_GIF : return '.gif'; + case IMAGETYPE_JPEG : return '.jpg'; + case IMAGETYPE_PNG : return '.png'; + case IMAGETYPE_SWF : return '.swf'; + case IMAGETYPE_PSD : return '.psd'; + case IMAGETYPE_BMP : return '.bmp'; + case IMAGETYPE_TIFF_II : return '.tiff'; + case IMAGETYPE_TIFF_MM : return '.tiff'; + case IMAGETYPE_JPC : return '.jpc'; + case IMAGETYPE_JP2 : return '.jp2'; + case IMAGETYPE_JPX : return '.jpf'; + case IMAGETYPE_JB2 : return '.jb2'; + case IMAGETYPE_SWC : return '.swc'; + case IMAGETYPE_IFF : return '.aiff'; + case IMAGETYPE_WBMP : return '.wbmp'; + case IMAGETYPE_XBM : return '.xbm'; + default : return false; + } + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Net/IpLocation.class.php b/ThinkPHP/Extend/Library/ORG/Net/IpLocation.class.php new file mode 100644 index 0000000..b4bf649 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Net/IpLocation.class.php @@ -0,0 +1,236 @@ + +// +---------------------------------------------------------------------- + +/** + * IP 地理位置查询类 修改自 CoolCode.CN + * 由于使用UTF8编码 如果使用纯真IP地址库的话 需要对返回结果进行编码转换 + * @category ORG + * @package ORG + * @subpackage Net + * @author liu21st + */ +class IpLocation { + /** + * QQWry.Dat文件指针 + * + * @var resource + */ + private $fp; + + /** + * 第一条IP记录的偏移地址 + * + * @var int + */ + private $firstip; + + /** + * 最后一条IP记录的偏移地址 + * + * @var int + */ + private $lastip; + + /** + * IP记录的总条数(不包含版本信息记录) + * + * @var int + */ + private $totalip; + + /** + * 构造函数,打开 QQWry.Dat 文件并初始化类中的信息 + * + * @param string $filename + * @return IpLocation + */ + public function __construct($filename = "UTFWry.dat") { + $this->fp = 0; + if (($this->fp = fopen(dirname(__FILE__).'/'.$filename, 'rb')) !== false) { + $this->firstip = $this->getlong(); + $this->lastip = $this->getlong(); + $this->totalip = ($this->lastip - $this->firstip) / 7; + } + } + + /** + * 返回读取的长整型数 + * + * @access private + * @return int + */ + private function getlong() { + //将读取的little-endian编码的4个字节转化为长整型数 + $result = unpack('Vlong', fread($this->fp, 4)); + return $result['long']; + } + + /** + * 返回读取的3个字节的长整型数 + * + * @access private + * @return int + */ + private function getlong3() { + //将读取的little-endian编码的3个字节转化为长整型数 + $result = unpack('Vlong', fread($this->fp, 3).chr(0)); + return $result['long']; + } + + /** + * 返回压缩后可进行比较的IP地址 + * + * @access private + * @param string $ip + * @return string + */ + private function packip($ip) { + // 将IP地址转化为长整型数,如果在PHP5中,IP地址错误,则返回False, + // 这时intval将Flase转化为整数-1,之后压缩成big-endian编码的字符串 + return pack('N', intval(ip2long($ip))); + } + + /** + * 返回读取的字符串 + * + * @access private + * @param string $data + * @return string + */ + private function getstring($data = "") { + $char = fread($this->fp, 1); + while (ord($char) > 0) { // 字符串按照C格式保存,以\0结束 + $data .= $char; // 将读取的字符连接到给定字符串之后 + $char = fread($this->fp, 1); + } + return $data; + } + + /** + * 返回地区信息 + * + * @access private + * @return string + */ + private function getarea() { + $byte = fread($this->fp, 1); // 标志字节 + switch (ord($byte)) { + case 0: // 没有区域信息 + $area = ""; + break; + case 1: + case 2: // 标志字节为1或2,表示区域信息被重定向 + fseek($this->fp, $this->getlong3()); + $area = $this->getstring(); + break; + default: // 否则,表示区域信息没有被重定向 + $area = $this->getstring($byte); + break; + } + return $area; + } + + /** + * 根据所给 IP 地址或域名返回所在地区信息 + * + * @access public + * @param string $ip + * @return array + */ + public function getlocation($ip='') { + if (!$this->fp) return null; // 如果数据文件没有被正确打开,则直接返回空 + if(empty($ip)) $ip = get_client_ip(); + $location['ip'] = gethostbyname($ip); // 将输入的域名转化为IP地址 + $ip = $this->packip($location['ip']); // 将输入的IP地址转化为可比较的IP地址 + // 不合法的IP地址会被转化为255.255.255.255 + // 对分搜索 + $l = 0; // 搜索的下边界 + $u = $this->totalip; // 搜索的上边界 + $findip = $this->lastip; // 如果没有找到就返回最后一条IP记录(QQWry.Dat的版本信息) + while ($l <= $u) { // 当上边界小于下边界时,查找失败 + $i = floor(($l + $u) / 2); // 计算近似中间记录 + fseek($this->fp, $this->firstip + $i * 7); + $beginip = strrev(fread($this->fp, 4)); // 获取中间记录的开始IP地址 + // strrev函数在这里的作用是将little-endian的压缩IP地址转化为big-endian的格式 + // 以便用于比较,后面相同。 + if ($ip < $beginip) { // 用户的IP小于中间记录的开始IP地址时 + $u = $i - 1; // 将搜索的上边界修改为中间记录减一 + } + else { + fseek($this->fp, $this->getlong3()); + $endip = strrev(fread($this->fp, 4)); // 获取中间记录的结束IP地址 + if ($ip > $endip) { // 用户的IP大于中间记录的结束IP地址时 + $l = $i + 1; // 将搜索的下边界修改为中间记录加一 + } + else { // 用户的IP在中间记录的IP范围内时 + $findip = $this->firstip + $i * 7; + break; // 则表示找到结果,退出循环 + } + } + } + + //获取查找到的IP地理位置信息 + fseek($this->fp, $findip); + $location['beginip'] = long2ip($this->getlong()); // 用户IP所在范围的开始地址 + $offset = $this->getlong3(); + fseek($this->fp, $offset); + $location['endip'] = long2ip($this->getlong()); // 用户IP所在范围的结束地址 + $byte = fread($this->fp, 1); // 标志字节 + switch (ord($byte)) { + case 1: // 标志字节为1,表示国家和区域信息都被同时重定向 + $countryOffset = $this->getlong3(); // 重定向地址 + fseek($this->fp, $countryOffset); + $byte = fread($this->fp, 1); // 标志字节 + switch (ord($byte)) { + case 2: // 标志字节为2,表示国家信息又被重定向 + fseek($this->fp, $this->getlong3()); + $location['country'] = $this->getstring(); + fseek($this->fp, $countryOffset + 4); + $location['area'] = $this->getarea(); + break; + default: // 否则,表示国家信息没有被重定向 + $location['country'] = $this->getstring($byte); + $location['area'] = $this->getarea(); + break; + } + break; + case 2: // 标志字节为2,表示国家信息被重定向 + fseek($this->fp, $this->getlong3()); + $location['country'] = $this->getstring(); + fseek($this->fp, $offset + 8); + $location['area'] = $this->getarea(); + break; + default: // 否则,表示国家信息没有被重定向 + $location['country'] = $this->getstring($byte); + $location['area'] = $this->getarea(); + break; + } + if (trim($location['country']) == 'CZ88.NET') { // CZ88.NET表示没有有效信息 + $location['country'] = '未知'; + } + if (trim($location['area']) == 'CZ88.NET') { + $location['area'] = ''; + } + return $location; + } + + /** + * 析构函数,用于在页面执行结束后自动关闭打开的文件。 + * + */ + public function __destruct() { + if ($this->fp) { + fclose($this->fp); + } + $this->fp = 0; + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Net/UploadFile.class.php b/ThinkPHP/Extend/Library/ORG/Net/UploadFile.class.php new file mode 100644 index 0000000..7e69e79 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Net/UploadFile.class.php @@ -0,0 +1,529 @@ + +// +---------------------------------------------------------------------- + +/** + * 文件上传类 + * @category ORG + * @package ORG + * @subpackage Net + * @author liu21st + */ +class UploadFile {//类定义开始 + + private $config = array( + 'maxSize' => -1, // 上传文件的最大值 + 'supportMulti' => true, // 是否支持多文件上传 + 'allowExts' => array(), // 允许上传的文件后缀 留空不作后缀检查 + 'allowTypes' => array(), // 允许上传的文件类型 留空不做检查 + 'thumb' => false, // 使用对上传图片进行缩略图处理 + 'imageClassPath' => 'ORG.Util.Image', // 图库类包路径 + 'thumbMaxWidth' => '',// 缩略图最大宽度 + 'thumbMaxHeight' => '',// 缩略图最大高度 + 'thumbPrefix' => 'thumb_',// 缩略图前缀 + 'thumbSuffix' => '', + 'thumbPath' => '',// 缩略图保存路径 + 'thumbFile' => '',// 缩略图文件名 + 'thumbExt' => '',// 缩略图扩展名 + 'thumbRemoveOrigin' => false,// 是否移除原图 + 'thumbType' => 1, // 缩略图生成方式 1 按设置大小截取 0 按原图等比例缩略 + 'zipImages' => false,// 压缩图片文件上传 + 'autoSub' => false,// 启用子目录保存文件 + 'subType' => 'hash',// 子目录创建方式 可以使用hash date custom + 'subDir' => '', // 子目录名称 subType为custom方式后有效 + 'dateFormat' => 'Ymd', + 'hashLevel' => 1, // hash的目录层次 + 'savePath' => '',// 上传文件保存路径 + 'autoCheck' => true, // 是否自动检查附件 + 'uploadReplace' => false,// 存在同名是否覆盖 + 'saveRule' => 'uniqid',// 上传文件命名规则 + 'hashType' => 'md5_file',// 上传文件Hash规则函数名 + ); + + // 错误信息 + private $error = ''; + // 上传成功的文件信息 + private $uploadFileInfo ; + + public function __get($name){ + if(isset($this->config[$name])) { + return $this->config[$name]; + } + return null; + } + + public function __set($name,$value){ + if(isset($this->config[$name])) { + $this->config[$name] = $value; + } + } + + public function __isset($name){ + return isset($this->config[$name]); + } + + /** + * 架构函数 + * @access public + * @param array $config 上传参数 + */ + public function __construct($config=array()) { + if(is_array($config)) { + $this->config = array_merge($this->config,$config); + } + } + + /** + * 上传一个文件 + * @access public + * @param mixed $name 数据 + * @param string $value 数据表名 + * @return string + */ + private function save($file) { + $filename = $file['savepath'].$file['savename']; + if(!$this->uploadReplace && is_file($filename)) { + // 不覆盖同名文件 + $this->error = '文件已经存在!'.$filename; + return false; + } + // 如果是图像文件 检测文件格式 + if( in_array(strtolower($file['extension']),array('gif','jpg','jpeg','bmp','png','swf'))) { + $info = getimagesize($file['tmp_name']); + if(false === $info || ('gif' == strtolower($file['extension']) && empty($info['bits']))){ + $this->error = '非法图像文件'; + return false; + } + } + if(!move_uploaded_file($file['tmp_name'], $this->autoCharset($filename,'utf-8','gbk'))) { + $this->error = '文件上传保存错误!'; + return false; + } + if($this->thumb && in_array(strtolower($file['extension']),array('gif','jpg','jpeg','bmp','png'))) { + $image = getimagesize($filename); + if(false !== $image) { + //是图像文件生成缩略图 + $thumbWidth = explode(',',$this->thumbMaxWidth); + $thumbHeight = explode(',',$this->thumbMaxHeight); + $thumbPrefix = explode(',',$this->thumbPrefix); + $thumbSuffix = explode(',',$this->thumbSuffix); + $thumbFile = explode(',',$this->thumbFile); + $thumbPath = $this->thumbPath?$this->thumbPath:dirname($filename).'/'; + $thumbExt = $this->thumbExt ? $this->thumbExt : $file['extension']; //自定义缩略图扩展名 + // 生成图像缩略图 + import($this->imageClassPath); + for($i=0,$len=count($thumbWidth); $i<$len; $i++) { + if(!empty($thumbFile[$i])) { + $thumbname = $thumbFile[$i]; + }else{ + $prefix = isset($thumbPrefix[$i])?$thumbPrefix[$i]:$thumbPrefix[0]; + $suffix = isset($thumbSuffix[$i])?$thumbSuffix[$i]:$thumbSuffix[0]; + $thumbname = $prefix.basename($filename,'.'.$file['extension']).$suffix; + } + if(1 == $this->thumbType){ + Image::thumb2($filename,$thumbPath.$thumbname.'.'.$thumbExt,'',$thumbWidth[$i],$thumbHeight[$i],true); + }else{ + Image::thumb($filename,$thumbPath.$thumbname.'.'.$thumbExt,'',$thumbWidth[$i],$thumbHeight[$i],true); + } + + } + if($this->thumbRemoveOrigin) { + // 生成缩略图之后删除原图 + unlink($filename); + } + } + } + if($this->zipImags) { + // TODO 对图片压缩包在线解压 + + } + return true; + } + + /** + * 上传所有文件 + * @access public + * @param string $savePath 上传文件保存路径 + * @return string + */ + public function upload($savePath ='') { + //如果不指定保存文件名,则由系统默认 + if(empty($savePath)) + $savePath = $this->savePath; + // 检查上传目录 + if(!is_dir($savePath)) { + // 检查目录是否编码后的 + if(is_dir(base64_decode($savePath))) { + $savePath = base64_decode($savePath); + }else{ + // 尝试创建目录 + if(!mkdir($savePath)){ + $this->error = '上传目录'.$savePath.'不存在'; + return false; + } + } + }else { + if(!is_writeable($savePath)) { + $this->error = '上传目录'.$savePath.'不可写'; + return false; + } + } + $fileInfo = array(); + $isUpload = false; + + // 获取上传的文件信息 + // 对$_FILES数组信息处理 + $files = $this->dealFiles($_FILES); + foreach($files as $key => $file) { + //过滤无效的上传 + if(!empty($file['name'])) { + //登记上传文件的扩展信息 + if(!isset($file['key'])) $file['key'] = $key; + $file['extension'] = $this->getExt($file['name']); + $file['savepath'] = $savePath; + $file['savename'] = $this->getSaveName($file); + + // 自动检查附件 + if($this->autoCheck) { + if(!$this->check($file)) + return false; + } + + //保存上传文件 + if(!$this->save($file)) return false; + if(function_exists($this->hashType)) { + $fun = $this->hashType; + $file['hash'] = $fun($this->autoCharset($file['savepath'].$file['savename'],'utf-8','gbk')); + } + //上传成功后保存文件信息,供其他地方调用 + unset($file['tmp_name'],$file['error']); + $fileInfo[] = $file; + $isUpload = true; + } + } + if($isUpload) { + $this->uploadFileInfo = $fileInfo; + return true; + }else { + $this->error = '没有选择上传文件'; + return false; + } + } + + /** + * 上传单个上传字段中的文件 支持多附件 + * @access public + * @param array $file 上传文件信息 + * @param string $savePath 上传文件保存路径 + * @return string + */ + public function uploadOne($file,$savePath=''){ + //如果不指定保存文件名,则由系统默认 + if(empty($savePath)) + $savePath = $this->savePath; + // 检查上传目录 + if(!is_dir($savePath)) { + // 尝试创建目录 + if(!mkdir($savePath,0777,true)){ + $this->error = '上传目录'.$savePath.'不存在'; + return false; + } + }else { + if(!is_writeable($savePath)) { + $this->error = '上传目录'.$savePath.'不可写'; + return false; + } + } + //过滤无效的上传 + if(!empty($file['name'])) { + $fileArray = array(); + if(is_array($file['name'])) { + $keys = array_keys($file); + $count = count($file['name']); + for ($i=0; $i<$count; $i++) { + foreach ($keys as $key) + $fileArray[$i][$key] = $file[$key][$i]; + } + }else{ + $fileArray[] = $file; + } + $info = array(); + foreach ($fileArray as $key=>$file){ + //登记上传文件的扩展信息 + $file['extension'] = $this->getExt($file['name']); + $file['savepath'] = $savePath; + $file['savename'] = $this->getSaveName($file); + // 自动检查附件 + if($this->autoCheck) { + if(!$this->check($file)) + return false; + } + //保存上传文件 + if(!$this->save($file)) return false; + if(function_exists($this->hashType)) { + $fun = $this->hashType; + $file['hash'] = $fun($this->autoCharset($file['savepath'].$file['savename'],'utf-8','gbk')); + } + unset($file['tmp_name'],$file['error']); + $info[] = $file; + } + // 返回上传的文件信息 + return $info; + }else { + $this->error = '没有选择上传文件'; + return false; + } + } + + /** + * 转换上传文件数组变量为正确的方式 + * @access private + * @param array $files 上传的文件变量 + * @return array + */ + private function dealFiles($files) { + $fileArray = array(); + $n = 0; + foreach ($files as $key=>$file){ + if(is_array($file['name'])) { + $keys = array_keys($file); + $count = count($file['name']); + for ($i=0; $i<$count; $i++) { + $fileArray[$n]['key'] = $key; + foreach ($keys as $_key){ + $fileArray[$n][$_key] = $file[$_key][$i]; + } + $n++; + } + }else{ + $fileArray[$key] = $file; + } + } + return $fileArray; + } + + /** + * 获取错误代码信息 + * @access public + * @param string $errorNo 错误号码 + * @return void + */ + protected function error($errorNo) { + switch($errorNo) { + case 1: + $this->error = '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值'; + break; + case 2: + $this->error = '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值'; + break; + case 3: + $this->error = '文件只有部分被上传'; + break; + case 4: + $this->error = '没有文件被上传'; + break; + case 6: + $this->error = '找不到临时文件夹'; + break; + case 7: + $this->error = '文件写入失败'; + break; + default: + $this->error = '未知上传错误!'; + } + return ; + } + + /** + * 根据上传文件命名规则取得保存文件名 + * @access private + * @param string $filename 数据 + * @return string + */ + private function getSaveName($filename) { + $rule = $this->saveRule; + if(empty($rule)) {//没有定义命名规则,则保持文件名不变 + $saveName = $filename['name']; + }else { + if(function_exists($rule)) { + //使用函数生成一个唯一文件标识号 + $saveName = $rule().".".$filename['extension']; + }else { + //使用给定的文件名作为标识号 + $saveName = $rule.".".$filename['extension']; + } + } + if($this->autoSub) { + // 使用子目录保存文件 + $filename['savename'] = $saveName; + $saveName = $this->getSubName($filename).$saveName; + } + return $saveName; + } + + /** + * 获取子目录的名称 + * @access private + * @param array $file 上传的文件信息 + * @return string + */ + private function getSubName($file) { + switch($this->subType) { + case 'custom': + $dir = $this->subDir; + break; + case 'date': + $dir = date($this->dateFormat,time()).'/'; + break; + case 'hash': + default: + $name = md5($file['savename']); + $dir = ''; + for($i=0;$i<$this->hashLevel;$i++) { + $dir .= $name{$i}.'/'; + } + break; + } + if(!is_dir($file['savepath'].$dir)) { + mkdir($file['savepath'].$dir,0777,true); + } + return $dir; + } + + /** + * 检查上传的文件 + * @access private + * @param array $file 文件信息 + * @return boolean + */ + private function check($file) { + if($file['error']!== 0) { + //文件上传失败 + //捕获错误代码 + $this->error($file['error']); + return false; + } + //文件上传成功,进行自定义规则检查 + //检查文件大小 + if(!$this->checkSize($file['size'])) { + $this->error = '上传文件大小不符!'; + return false; + } + + //检查文件Mime类型 + if(!$this->checkType($file['type'])) { + $this->error = '上传文件MIME类型不允许!'; + return false; + } + //检查文件类型 + if(!$this->checkExt($file['extension'])) { + $this->error ='上传文件类型不允许'; + return false; + } + + //检查是否合法上传 + if(!$this->checkUpload($file['tmp_name'])) { + $this->error = '非法上传文件!'; + return false; + } + return true; + } + + // 自动转换字符集 支持数组转换 + private function autoCharset($fContents, $from='gbk', $to='utf-8') { + $from = strtoupper($from) == 'UTF8' ? 'utf-8' : $from; + $to = strtoupper($to) == 'UTF8' ? 'utf-8' : $to; + if (strtoupper($from) === strtoupper($to) || empty($fContents) || (is_scalar($fContents) && !is_string($fContents))) { + //如果编码相同或者非字符串标量则不转换 + return $fContents; + } + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($fContents, $to, $from); + } elseif (function_exists('iconv')) { + return iconv($from, $to, $fContents); + } else { + return $fContents; + } + } + + /** + * 检查上传的文件类型是否合法 + * @access private + * @param string $type 数据 + * @return boolean + */ + private function checkType($type) { + if(!empty($this->allowTypes)) + return in_array(strtolower($type),$this->allowTypes); + return true; + } + + + /** + * 检查上传的文件后缀是否合法 + * @access private + * @param string $ext 后缀名 + * @return boolean + */ + private function checkExt($ext) { + if(!empty($this->allowExts)) + return in_array(strtolower($ext),$this->allowExts,true); + return true; + } + + /** + * 检查文件大小是否合法 + * @access private + * @param integer $size 数据 + * @return boolean + */ + private function checkSize($size) { + return !($size > $this->maxSize) || (-1 == $this->maxSize); + } + + /** + * 检查文件是否非法提交 + * @access private + * @param string $filename 文件名 + * @return boolean + */ + private function checkUpload($filename) { + return is_uploaded_file($filename); + } + + /** + * 取得上传文件的后缀 + * @access private + * @param string $filename 文件名 + * @return boolean + */ + private function getExt($filename) { + $pathinfo = pathinfo($filename); + return $pathinfo['extension']; + } + + /** + * 取得上传文件的信息 + * @access public + * @return array + */ + public function getUploadFileInfo() { + return $this->uploadFileInfo; + } + + /** + * 取得最后一次错误信息 + * @access public + * @return string + */ + public function getErrorMsg() { + return $this->error; + } +} diff --git a/ThinkPHP/Extend/Library/ORG/Util/ArrayList.class.php b/ThinkPHP/Extend/Library/ORG/Util/ArrayList.class.php new file mode 100644 index 0000000..9f0cbb9 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/ArrayList.class.php @@ -0,0 +1,240 @@ + +// +---------------------------------------------------------------------- + +/** + * ArrayList实现类 + * @category Think + * @package Think + * @subpackage Util + * @author liu21st + */ +class ArrayList implements IteratorAggregate { + + /** + * 集合元素 + * @var array + * @access protected + */ + protected $_elements = array(); + + /** + * 架构函数 + * @access public + * @param string $elements 初始化数组元素 + */ + public function __construct($elements = array()) { + if (!empty($elements)) { + $this->_elements = $elements; + } + } + + /** + * 若要获得迭代因子,通过getIterator方法实现 + * @access public + * @return ArrayObject + */ + public function getIterator() { + return new ArrayObject($this->_elements); + } + + /** + * 增加元素 + * @access public + * @param mixed $element 要添加的元素 + * @return boolen + */ + public function add($element) { + return (array_push($this->_elements, $element)) ? true : false; + } + + // + public function unshift($element) { + return (array_unshift($this->_elements,$element))?true : false; + } + + // + public function pop() { + return array_pop($this->_elements); + } + + /** + * 增加元素列表 + * @access public + * @param ArrayList $list 元素列表 + * @return boolen + */ + public function addAll($list) { + $before = $this->size(); + foreach( $list as $element) { + $this->add($element); + } + $after = $this->size(); + return ($before < $after); + } + + /** + * 清除所有元素 + * @access public + */ + public function clear() { + $this->_elements = array(); + } + + /** + * 是否包含某个元素 + * @access public + * @param mixed $element 查找元素 + * @return string + */ + public function contains($element) { + return (array_search($element, $this->_elements) !== false ); + } + + /** + * 根据索引取得元素 + * @access public + * @param integer $index 索引 + * @return mixed + */ + public function get($index) { + return $this->_elements[$index]; + } + + /** + * 查找匹配元素,并返回第一个元素所在位置 + * 注意 可能存在0的索引位置 因此要用===False来判断查找失败 + * @access public + * @param mixed $element 查找元素 + * @return integer + */ + public function indexOf($element) { + return array_search($element, $this->_elements); + } + + /** + * 判断元素是否为空 + * @access public + * @return boolen + */ + public function isEmpty() { + return empty($this->_elements); + } + + /** + * 最后一个匹配的元素位置 + * @access public + * @param mixed $element 查找元素 + * @return integer + */ + public function lastIndexOf($element) { + for ($i = (count($this->_elements) - 1); $i > 0; $i--) { + if ($element == $this->get($i)) { return $i; } + } + } + + public function toJson() { + return json_encode($this->_elements); + } + + /** + * 根据索引移除元素 + * 返回被移除的元素 + * @access public + * @param integer $index 索引 + * @return mixed + */ + public function remove($index) { + $element = $this->get($index); + if (!is_null($element)) { array_splice($this->_elements, $index, 1); } + return $element; + } + + /** + * 移出一定范围的数组列表 + * @access public + * @param integer $offset 开始移除位置 + * @param integer $length 移除长度 + */ + public function removeRange($offset , $length) { + array_splice($this->_elements, $offset , $length); + } + + /** + * 移出重复的值 + * @access public + */ + public function unique() { + $this->_elements = array_unique($this->_elements); + } + + /** + * 取出一定范围的数组列表 + * @access public + * @param integer $offset 开始位置 + * @param integer $length 长度 + */ + public function range($offset,$length=null) { + return array_slice($this->_elements,$offset,$length); + } + + /** + * 设置列表元素 + * 返回修改之前的值 + * @access public + * @param integer $index 索引 + * @param mixed $element 元素 + * @return mixed + */ + public function set($index, $element) { + $previous = $this->get($index); + $this->_elements[$index] = $element; + return $previous; + } + + /** + * 获取列表长度 + * @access public + * @return integer + */ + public function size() { + return count($this->_elements); + } + + /** + * 转换成数组 + * @access public + * @return array + */ + public function toArray() { + return $this->_elements; + } + + // 列表排序 + public function ksort() { + ksort($this->_elements); + } + + // 列表排序 + public function asort() { + asort($this->_elements); + } + + // 逆向排序 + public function rsort() { + rsort($this->_elements); + } + + // 自然排序 + public function natsort() { + natsort($this->_elements); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Auth.class.php b/ThinkPHP/Extend/Library/ORG/Util/Auth.class.php new file mode 100644 index 0000000..a4b8ad5 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Auth.class.php @@ -0,0 +1,186 @@ +  +// +---------------------------------------------------------------------- +/** + * 权限认证类 + * 功能特性: + * 1,是对规则进行认证,不是对节点进行认证。用户可以把节点当作规则名称实现对节点进行认证。 + * $auth=new Auth(); $auth->check('规则名称','用户id') + * 2,可以同时对多条规则进行认证,并设置多条规则的关系(or或者and) + * $auth=new Auth(); $auth->check('规则1,规则2','用户id','and') + * 第三个参数为and时表示,用户需要同时具有规则1和规则2的权限。 当第三个参数为or时,表示用户值需要具备其中一个条件即可。默认为or + * 3,一个用户可以属于多个用户组(think_auth_group_access表 定义了用户所属用户组)。我们需要设置每个用户组拥有哪些规则(think_auth_group 定义了用户组权限) + * + * 4,支持规则表达式。 + * 在think_auth_rule 表中定义一条规则时,如果type为1, condition字段就可以定义规则表达式。 如定义{score}>5 and {score}<100 表示用户的分数在5-100之间时这条规则才会通过。 + * @category ORG + * @package ORG + * @subpackage Util + * @author luofei614 + */ + +//数据库 +/* +-- ---------------------------- +-- think_auth_rule,规则表, +-- id:主键,name:规则唯一标识, title:规则中文名称 status 状态:为1正常,为0禁用,condition:规则表达式,为空表示存在就验证,不为空表示按照条件验证 +-- ---------------------------- + DROP TABLE IF EXISTS `think_auth_rule`; +CREATE TABLE `think_auth_rule` ( + `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `name` char(80) NOT NULL DEFAULT '', + `title` char(20) NOT NULL DEFAULT '', + `status` tinyint(1) NOT NULL DEFAULT '1', + `condition` char(100) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- ---------------------------- +-- think_auth_group 用户组表, +-- id:主键, title:用户组中文名称, rules:用户组拥有的规则id, 多个规则","隔开,status 状态:为1正常,为0禁用 +-- ---------------------------- + DROP TABLE IF EXISTS `think_auth_group`; +CREATE TABLE `think_auth_group` ( + `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `title` char(100) NOT NULL DEFAULT '', + `status` tinyint(1) NOT NULL DEFAULT '1', + `rules` char(80) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- ---------------------------- +-- think_auth_group_access 用户组明细表 +-- uid:用户id,group_id:用户组id +-- ---------------------------- +DROP TABLE IF EXISTS `think_auth_group_access`; +CREATE TABLE `think_auth_group_access` ( + `uid` mediumint(8) unsigned NOT NULL, + `group_id` mediumint(8) unsigned NOT NULL, + UNIQUE KEY `uid_group_id` (`uid`,`group_id`), + KEY `uid` (`uid`), + KEY `group_id` (`group_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + */ + +class Auth{ + + //默认配置 + protected $_config = array( + 'AUTH_ON' => true, //认证开关 + 'AUTH_TYPE' => 1, // 认证方式,1为时时认证;2为登录认证。 + 'AUTH_GROUP' => 'think_auth_group', //用户组数据表名 + 'AUTH_GROUP_ACCESS' => 'think_auth_group_access', //用户组明细表 + 'AUTH_RULE' => 'think_auth_rule', //权限规则表 + 'AUTH_USER' => 'think_members'//用户信息表 + ); + + public function __construct() { + if (C('AUTH_CONFIG')) { + //可设置配置项 AUTH_CONFIG, 此配置项为数组。 + $this->_config = array_merge($this->_config, C('AUTH_CONFIG')); + } + } + + //获得权限$name 可以是字符串或数组或逗号分割, uid为 认证的用户id, $or 是否为or关系,为true是, name为数组,只要数组中有一个条件通过则通过,如果为false需要全部条件通过。 + public function check($name, $uid, $relation='or') { + if (!$this->_config['AUTH_ON']) + return true; + $authList = $this->getAuthList($uid); + if (is_string($name)) { + if (strpos($name, ',') !== false) { + $name = explode(',', $name); + } else { + $name = array($name); + } + } + $list = array(); //有权限的name + foreach ($authList as $val) { + if (in_array($val, $name)) + $list[] = $val; + } + if ($relation=='or' and !empty($list)) { + return true; + } + $diff = array_diff($name, $list); + if ($relation=='and' and empty($diff)) { + return true; + } + return false; + } + + //获得用户组,外部也可以调用 + public function getGroups($uid) { + static $groups = array(); + if (isset($groups[$uid])) + return $groups[$uid]; + $user_groups = M()->table($this->_config['AUTH_GROUP_ACCESS'] . ' a')->where("a.uid='$uid' and g.status='1'")->join($this->_config['AUTH_GROUP']." g on a.group_id=g.id")->select(); + $groups[$uid]=$user_groups?$user_groups:array(); + return $groups[$uid]; + } + + //获得权限列表 + protected function getAuthList($uid) { + static $_authList = array(); + if (isset($_authList[$uid])) { + return $_authList[$uid]; + } + if(isset($_SESSION['_AUTH_LIST_'.$uid])){ + return $_SESSION['_AUTH_LIST_'.$uid]; + } + //读取用户所属用户组 + $groups = $this->getGroups($uid); + $ids = array(); + foreach ($groups as $g) { + $ids = array_merge($ids, explode(',', trim($g['rules'], ','))); + } + $ids = array_unique($ids); + if (empty($ids)) { + $_authList[$uid] = array(); + return array(); + } + //读取用户组所有权限规则 + $map=array( + 'id'=>array('in',$ids), + 'status'=>1 + ); + $rules = M()->table($this->_config['AUTH_RULE'])->where($map)->select(); + //循环规则,判断结果。 + $authList = array(); + foreach ($rules as $r) { + if (!empty($r['condition'])) { + //条件验证 + $user = $this->getUserInfo($uid); + $command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $r['condition']); + //dump($command);//debug + @(eval('$condition=(' . $command . ');')); + if ($condition) { + $authList[] = $r['name']; + } + } else { + //存在就通过 + $authList[] = $r['name']; + } + } + $_authList[$uid] = $authList; + if($this->_config['AUTH_TYPE']==2){ + //session结果 + $_SESSION['_AUTH_LIST_'.$uid]=$authList; + } + return $authList; + } + //获得用户资料,根据自己的情况读取数据库 + protected function getUserInfo($uid) { + static $userinfo=array(); + if(!isset($userinfo[$uid])){ + $userinfo[$uid]=M()->table($this->_config['AUTH_USER'])->find($uid); + } + return $userinfo[$uid]; + } + +} diff --git a/ThinkPHP/Extend/Library/ORG/Util/CodeSwitch.class.php b/ThinkPHP/Extend/Library/ORG/Util/CodeSwitch.class.php new file mode 100644 index 0000000..39e37e0 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/CodeSwitch.class.php @@ -0,0 +1,200 @@ + +// +---------------------------------------------------------------------- + +class CodeSwitch { + // 错误信息 + static private $error = array(); + // 提示信息 + static private $info = array(); + // 记录错误 + static private function error($msg) { + self::$error[] = $msg; + } + // 记录信息 + static private function info($info) { + self::$info[] = $info; + } + /** + * 编码转换函数,对整个文件进行编码转换 + * 支持以下转换 + * GB2312、UTF-8 WITH BOM转换为UTF-8 + * UTF-8、UTF-8 WITH BOM转换为GB2312 + * @access public + * @param string $filename 文件名 + * @param string $out_charset 转换后的文件编码,与iconv使用的参数一致 + * @return void + */ + static function DetectAndSwitch($filename,$out_charset) { + $fpr = fopen($filename,"r"); + $char1 = fread($fpr,1); + $char2 = fread($fpr,1); + $char3 = fread($fpr,1); + + $originEncoding = ""; + + if($char1==chr(239) && $char2==chr(187) && $char3==chr(191))//UTF-8 WITH BOM + $originEncoding = "UTF-8 WITH BOM"; + elseif($char1==chr(255) && $char2==chr(254))//UNICODE LE + { + self::error("不支持从UNICODE LE转换到UTF-8或GB编码"); + fclose($fpr); + return; + }elseif($char1==chr(254) && $char2==chr(255)){//UNICODE BE + self::error("不支持从UNICODE BE转换到UTF-8或GB编码"); + fclose($fpr); + return; + }else{//没有文件头,可能是GB或UTF-8 + if(rewind($fpr)===false){//回到文件开始部分,准备逐字节读取判断编码 + self::error($filename."文件指针后移失败"); + fclose($fpr); + return; + } + + while(!feof($fpr)){ + $char = fread($fpr,1); + //对于英文,GB和UTF-8都是单字节的ASCII码小于128的值 + if(ord($char)<128) + continue; + + //对于汉字GB编码第一个字节是110*****第二个字节是10******(有特例,比如联字) + //UTF-8编码第一个字节是1110****第二个字节是10******第三个字节是10****** + //按位与出来结果要跟上面非星号相同,所以应该先判断UTF-8 + //因为使用GB的掩码按位与,UTF-8的111得出来的也是110,所以要先判断UTF-8 + if((ord($char)&224)==224) { + //第一个字节判断通过 + $char = fread($fpr,1); + if((ord($char)&128)==128) { + //第二个字节判断通过 + $char = fread($fpr,1); + if((ord($char)&128)==128) { + $originEncoding = "UTF-8"; + break; + } + } + } + if((ord($char)&192)==192) { + //第一个字节判断通过 + $char = fread($fpr,1); + if((ord($char)&128)==128) { + //第二个字节判断通过 + $originEncoding = "GB2312"; + break; + } + } + } + } + + if(strtoupper($out_charset)==$originEncoding) { + self::info("文件".$filename."转码检查完成,原始文件编码".$originEncoding); + fclose($fpr); + }else { + //文件需要转码 + $originContent = ""; + + if($originEncoding == "UTF-8 WITH BOM") { + //跳过三个字节,把后面的内容复制一遍得到utf-8的内容 + fseek($fpr,3); + $originContent = fread($fpr,filesize($filename)-3); + fclose($fpr); + }elseif(rewind($fpr)!=false){//不管是UTF-8还是GB2312,回到文件开始部分,读取内容 + $originContent = fread($fpr,filesize($filename)); + fclose($fpr); + }else{ + self::error("文件编码不正确或指针后移失败"); + fclose($fpr); + return; + } + + //转码并保存文件 + $content = iconv(str_replace(" WITH BOM","",$originEncoding),strtoupper($out_charset),$originContent); + $fpw = fopen($filename,"w"); + fwrite($fpw,$content); + fclose($fpw); + + if($originEncoding!="") + self::info("对文件".$filename."转码完成,原始文件编码".$originEncoding.",转换后文件编码".strtoupper($out_charset)); + elseif($originEncoding=="") + self::info("文件".$filename."中没有出现中文,但是可以断定不是带BOM的UTF-8编码,没有进行编码转换,不影响使用"); + } + } + + /** + * 目录遍历函数 + * @access public + * @param string $path 要遍历的目录名 + * @param string $mode 遍历模式,一般取FILES,这样只返回带路径的文件名 + * @param array $file_types 文件后缀过滤数组 + * @param int $maxdepth 遍历深度,-1表示遍历到最底层 + * @return void + */ + static function searchdir($path,$mode = "FULL",$file_types = array(".html",".php"),$maxdepth = -1,$d = 0) { + if(substr($path,strlen($path)-1) != '/') + $path .= '/'; + $dirlist = array(); + if($mode != "FILES") + $dirlist[] = $path; + if($handle = @opendir($path)) { + while(false !== ($file = readdir($handle))) + { + if($file != '.' && $file != '..') + { + $file = $path.$file ; + if(!is_dir($file)) + { + if($mode != "DIRS") + { + $extension = ""; + $extpos = strrpos($file, '.'); + if($extpos!==false) + $extension = substr($file,$extpos,strlen($file)-$extpos); + $extension=strtolower($extension); + if(in_array($extension, $file_types)) + $dirlist[] = $file; + } + } + elseif($d >= 0 && ($d < $maxdepth || $maxdepth < 0)) + { + $result = self::searchdir($file.'/',$mode,$file_types,$maxdepth,$d + 1) ; + $dirlist = array_merge($dirlist,$result); + } + } + } + closedir ( $handle ) ; + } + if($d == 0) + natcasesort($dirlist); + + return($dirlist) ; + } + + /** + * 对整个项目目录中的PHP和HTML文件行进编码转换 + * @access public + * @param string $app 要遍历的项目路径 + * @param string $mode 遍历模式,一般取FILES,这样只返回带路径的文件名 + * @param array $file_types 文件后缀过滤数组 + * @return void + */ + static function CodingSwitch($app = "./",$charset='UTF-8',$mode = "FILES",$file_types = array(".html",".php")) { + self::info("注意: 程序使用的文件编码检测算法可能对某些特殊字符不适用"); + $filearr = self::searchdir($app,$mode,$file_types); + foreach($filearr as $file) + self::DetectAndSwitch($file,$charset); + } + + static public function getError() { + return self::$error; + } + + static public function getInfo() { + return self::$info; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Cookie.class.php b/ThinkPHP/Extend/Library/ORG/Util/Cookie.class.php new file mode 100644 index 0000000..db60f1a --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Cookie.class.php @@ -0,0 +1,64 @@ + +// +---------------------------------------------------------------------- +// $Id: Cookie.class.php 2702 2012-02-02 12:35:01Z liu21st $ + +/** + +------------------------------------------------------------------------------ + * Cookie管理类 + +------------------------------------------------------------------------------ + * @category Think + * @package Think + * @subpackage Util + * @author liu21st + * @version $Id: Cookie.class.php 2702 2012-02-02 12:35:01Z liu21st $ + +------------------------------------------------------------------------------ + */ +class Cookie { + // 判断Cookie是否存在 + static function is_set($name) { + return isset($_COOKIE[C('COOKIE_PREFIX').$name]); + } + + // 获取某个Cookie值 + static function get($name) { + $value = $_COOKIE[C('COOKIE_PREFIX').$name]; + $value = unserialize(base64_decode($value)); + return $value; + } + + // 设置某个Cookie值 + static function set($name,$value,$expire='',$path='',$domain='') { + if($expire=='') { + $expire = C('COOKIE_EXPIRE'); + } + if(empty($path)) { + $path = C('COOKIE_PATH'); + } + if(empty($domain)) { + $domain = C('COOKIE_DOMAIN'); + } + $expire = !empty($expire)? time()+$expire : 0; + $value = base64_encode(serialize($value)); + setcookie(C('COOKIE_PREFIX').$name, $value,$expire,$path,$domain); + $_COOKIE[C('COOKIE_PREFIX').$name] = $value; + } + + // 删除某个Cookie值 + static function delete($name) { + Cookie::set($name,'',-3600); + unset($_COOKIE[C('COOKIE_PREFIX').$name]); + } + + // 清空Cookie值 + static function clear() { + unset($_COOKIE); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Date.class.php b/ThinkPHP/Extend/Library/ORG/Util/Date.class.php new file mode 100644 index 0000000..d9dfeb2 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Date.class.php @@ -0,0 +1,569 @@ + +// +---------------------------------------------------------------------- + + +/** + * 日期时间操作类 + * @category ORG + * @package ORG + * @subpackage Date + * @author liu21st + * @version $Id: Date.class.php 2662 2012-01-26 06:32:50Z liu21st $ + */ +class Date { + + /** + * 日期的时间戳 + * @var integer + * @access protected + */ + protected $date; + + /** + * 时区 + * @var integer + * @access protected + */ + protected $timezone; + + /** + * 年 + * @var integer + * @access protected + */ + protected $year; + + /** + * 月 + * @var integer + * @access protected + */ + protected $month; + + /** + * 日 + * @var integer + * @access protected + */ + protected $day; + + /** + * 时 + * @var integer + * @access protected + */ + protected $hour; + + /** + * 分 + * @var integer + * @access protected + */ + protected $minute; + + /** + * 秒 + * @var integer + * @access protected + */ + protected $second; + + /** + * 星期的数字表示 + * @var integer + * @access protected + */ + protected $weekday; + + /** + * 星期的完整表示 + * @var string + * @access protected + */ + protected $cWeekday; + + /** + * 一年中的天数 0-365 + * @var integer + * @access protected + */ + protected $yDay; + + /** + * 月份的完整表示 + * @var string + * @access protected + */ + protected $cMonth; + + /** + * 日期CDATE表示 + * @var string + * @access protected + */ + protected $CDATE; + + /** + * 日期的YMD表示 + * @var string + * @access protected + */ + protected $YMD; + + /** + * 时间的输出表示 + * @var string + * @access protected + */ + protected $CTIME; + + // 星期的输出 + protected $Week = array("日","一","二","三","四","五","六"); + + /** + * 架构函数 + * 创建一个Date对象 + * @param mixed $date 日期 + * @static + * @access public + */ + public function __construct($date='') { + //分析日期 + $this->date = $this->parse($date); + $this->setDate($this->date); + } + + /** + * 日期分析 + * 返回时间戳 + * @static + * @access public + * @param mixed $date 日期 + * @return string + */ + public function parse($date) { + if (is_string($date)) { + if (($date == "") || strtotime($date) == -1) { + //为空默认取得当前时间戳 + $tmpdate = time(); + } else { + //把字符串转换成UNIX时间戳 + $tmpdate = strtotime($date); + } + } elseif (is_null($date)) { + //为空默认取得当前时间戳 + $tmpdate = time(); + + } elseif (is_numeric($date)) { + //数字格式直接转换为时间戳 + $tmpdate = $date; + + } else { + if (get_class($date) == "Date") { + //如果是Date对象 + $tmpdate = $date->date; + } else { + //默认取当前时间戳 + $tmpdate = time(); + } + } + return $tmpdate; + } + + /** + * 验证日期数据是否有效 + * @access public + * @param mixed $date 日期数据 + * @return string + */ + public function valid($date) { + + } + + /** + * 日期参数设置 + * @static + * @access public + * @param integer $date 日期时间戳 + * @return void + */ + public function setDate($date) { + $dateArray = getdate($date); + $this->date = $dateArray[0]; //时间戳 + $this->second = $dateArray["seconds"]; //秒 + $this->minute = $dateArray["minutes"]; //分 + $this->hour = $dateArray["hours"]; //时 + $this->day = $dateArray["mday"]; //日 + $this->month = $dateArray["mon"]; //月 + $this->year = $dateArray["year"]; //年 + + $this->weekday = $dateArray["wday"]; //星期 0~6 + $this->cWeekday = '星期'.$this->Week[$this->weekday];//$dateArray["weekday"]; //星期完整表示 + $this->yDay = $dateArray["yday"]; //一年中的天数 0-365 + $this->cMonth = $dateArray["month"]; //月份的完整表示 + + $this->CDATE = $this->format("%Y-%m-%d");//日期表示 + $this->YMD = $this->format("%Y%m%d"); //简单日期 + $this->CTIME = $this->format("%H:%M:%S");//时间表示 + + return ; + } + + /** + * 日期格式化 + * 默认返回 1970-01-01 11:30:45 格式 + * @access public + * @param string $format 格式化参数 + * @return string + */ + public function format($format = "%Y-%m-%d %H:%M:%S") { + return strftime($format, $this->date); + } + + /** + * 是否为闰年 + * @static + * @access public + * @return string + */ + public function isLeapYear($year='') { + if(empty($year)) { + $year = $this->year; + } + return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0)); + } + + /** + * 计算日期差 + * + * w - weeks + * d - days + * h - hours + * m - minutes + * s - seconds + * @static + * @access public + * @param mixed $date 要比较的日期 + * @param string $elaps 比较跨度 + * @return integer + */ + public function dateDiff($date, $elaps = "d") { + $__DAYS_PER_WEEK__ = (7); + $__DAYS_PER_MONTH__ = (30); + $__DAYS_PER_YEAR__ = (365); + $__HOURS_IN_A_DAY__ = (24); + $__MINUTES_IN_A_DAY__ = (1440); + $__SECONDS_IN_A_DAY__ = (86400); + //计算天数差 + $__DAYSELAPS = ($this->parse($date) - $this->date) / $__SECONDS_IN_A_DAY__ ; + switch ($elaps) { + case "y"://转换成年 + $__DAYSELAPS = $__DAYSELAPS / $__DAYS_PER_YEAR__; + break; + case "M"://转换成月 + $__DAYSELAPS = $__DAYSELAPS / $__DAYS_PER_MONTH__; + break; + case "w"://转换成星期 + $__DAYSELAPS = $__DAYSELAPS / $__DAYS_PER_WEEK__; + break; + case "h"://转换成小时 + $__DAYSELAPS = $__DAYSELAPS * $__HOURS_IN_A_DAY__; + break; + case "m"://转换成分钟 + $__DAYSELAPS = $__DAYSELAPS * $__MINUTES_IN_A_DAY__; + break; + case "s"://转换成秒 + $__DAYSELAPS = $__DAYSELAPS * $__SECONDS_IN_A_DAY__; + break; + } + return $__DAYSELAPS; + } + + /** + * 人性化的计算日期差 + * @static + * @access public + * @param mixed $time 要比较的时间 + * @param mixed $precision 返回的精度 + * @return string + */ + public function timeDiff( $time ,$precision=false) { + if(!is_numeric($precision) && !is_bool($precision)) { + static $_diff = array('y'=>'年','M'=>'个月','d'=>'天','w'=>'周','s'=>'秒','h'=>'小时','m'=>'分钟'); + return ceil($this->dateDiff($time,$precision)).$_diff[$precision].'前'; + } + $diff = abs($this->parse($time) - $this->date); + static $chunks = array(array(31536000,'年'),array(2592000,'个月'),array(604800,'周'),array(86400,'天'),array(3600 ,'小时'),array(60,'分钟'),array(1,'秒')); + $count =0; + $since = ''; + for($i=0;$i=$chunks[$i][0]) { + $num = floor($diff/$chunks[$i][0]); + $since .= sprintf('%d'.$chunks[$i][1],$num); + $diff = (int)($diff-$chunks[$i][0]*$num); + $count++; + if(!$precision || $count>=$precision) { + break; + } + } + } + return $since.'前'; + } + + /** + * 返回周的某一天 返回Date对象 + * @access public + * @return Date + */ + public function getDayOfWeek($n){ + $week = array(0=>'sunday',1=>'monday',2=>'tuesday',3=>'wednesday',4=>'thursday',5=>'friday',6=>'saturday'); + return (new Date($week[$n])); + } + + /** + * 计算周的第一天 返回Date对象 + * @access public + * @return Date + */ + public function firstDayOfWeek() { + return $this->getDayOfWeek(1); + } + + /** + * 计算月份的第一天 返回Date对象 + * @access public + * @return Date + */ + public function firstDayOfMonth() { + return (new Date(mktime(0, 0, 0,$this->month,1,$this->year ))); + } + + /** + * 计算年份的第一天 返回Date对象 + * @access public + * @return Date + */ + public function firstDayOfYear() { + return (new Date(mktime(0, 0, 0, 1, 1, $this->year))); + } + + /** + * 计算周的最后一天 返回Date对象 + * @access public + * @return Date + */ + public function lastDayOfWeek() { + return $this->getDayOfWeek(0); + } + + /** + * 计算月份的最后一天 返回Date对象 + * @access public + * @return Date + */ + public function lastDayOfMonth() { + return (new Date(mktime(0, 0, 0, $this->month + 1, 0, $this->year ))); + } + + /** + * 计算年份的最后一天 返回Date对象 + * @access public + * @return Date + */ + public function lastDayOfYear() { + return (new Date(mktime(0, 0, 0, 1, 0, $this->year + 1))); + } + + /** + * 计算月份的最大天数 + * @access public + * @return integer + */ + public function maxDayOfMonth() { + $result = $this->dateDiff(strtotime($this->dateAdd(1,'m')),'d'); + return $result; + } + + /** + * 取得指定间隔日期 + * + * yyyy - 年 + * q - 季度 + * m - 月 + * y - day of year + * d - 日 + * w - 周 + * ww - week of year + * h - 小时 + * n - 分钟 + * s - 秒 + * @access public + * @param integer $number 间隔数目 + * @param string $interval 比较类型 + * @return Date + */ + public function dateAdd($number = 0, $interval = "d") { + $hours = $this->hour; + $minutes = $this->minute; + $seconds = $this->second; + $month = $this->month; + $day = $this->day; + $year = $this->year; + + switch ($interval) { + case "yyyy": + //---Add $number to year + $year += $number; + break; + + case "q": + //---Add $number to quarter + $month += ($number*3); + break; + + case "m": + //---Add $number to month + $month += $number; + break; + + case "y": + case "d": + case "w": + //---Add $number to day of year, day, day of week + $day += $number; + break; + + case "ww": + //---Add $number to week + $day += ($number*7); + break; + + case "h": + //---Add $number to hours + $hours += $number; + break; + + case "n": + //---Add $number to minutes + $minutes += $number; + break; + + case "s": + //---Add $number to seconds + $seconds += $number; + break; + } + + return (new Date(mktime($hours, + $minutes, + $seconds, + $month, + $day, + $year))); + + } + + /** + * 日期数字转中文 + * 用于日和月、周 + * @static + * @access public + * @param integer $number 日期数字 + * @return string + */ + public function numberToCh($number) { + $number = intval($number); + $array = array('一','二','三','四','五','六','七','八','九','十'); + $str = ''; + if($number ==0) { $str .= "十" ;} + if($number < 10){ + $str .= $array[$number-1] ; + } + elseif($number < 20 ){ + $str .= "十".$array[$number-11]; + } + elseif($number < 30 ){ + $str .= "二十".$array[$number-21]; + } + else{ + $str .= "三十".$array[$number-31]; + } + return $str; + } + + /** + * 年份数字转中文 + * @static + * @access public + * @param integer $yearStr 年份数字 + * @param boolean $flag 是否显示公元 + * @return string + */ + public function yearToCh( $yearStr ,$flag=false ) { + $array = array('零','一','二','三','四','五','六','七','八','九'); + $str = $flag? '公元' : ''; + for($i=0;$i<4;$i++){ + $str .= $array[substr($yearStr,$i,1)]; + } + return $str; + } + + /** + * 判断日期 所属 干支 生肖 星座 + * type 参数:XZ 星座 GZ 干支 SX 生肖 + * + * @static + * @access public + * @param string $type 获取信息类型 + * @return string + */ + public function magicInfo($type) { + $result = ''; + $m = $this->month; + $y = $this->year; + $d = $this->day; + + switch ($type) { + case 'XZ'://星座 + $XZDict = array('摩羯','宝瓶','双鱼','白羊','金牛','双子','巨蟹','狮子','处女','天秤','天蝎','射手'); + $Zone = array(1222,122,222,321,421,522,622,722,822,922,1022,1122,1222); + if((100*$m+$d)>=$Zone[0]||(100*$m+$d)<$Zone[1]) + $i=0; + else + for($i=1;$i<12;$i++){ + if((100*$m+$d)>=$Zone[$i]&&(100*$m+$d)<$Zone[$i+1]) + break; + } + $result = $XZDict[$i].'座'; + break; + + case 'GZ'://干支 + $GZDict = array( + array('甲','乙','丙','丁','戊','己','庚','辛','壬','癸'), + array('子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥') + ); + $i= $y -1900+36 ; + $result = $GZDict[0][$i%10].$GZDict[1][$i%12]; + break; + + case 'SX'://生肖 + $SXDict = array('鼠','牛','虎','兔','龙','蛇','马','羊','猴','鸡','狗','猪'); + $result = $SXDict[($y-4)%12]; + break; + + } + return $result; + } + + public function __toString() { + return $this->format(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Debug.class.php b/ThinkPHP/Extend/Library/ORG/Util/Debug.class.php new file mode 100644 index 0000000..803b15b --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Debug.class.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- + +/** + * 系统调试类 + * @category Think + * @package Think + * @subpackage Util + * @author liu21st + */ +class Debug { + + static private $marker = array(); + /** + * 标记调试位 + * @access public + * @param string $name 要标记的位置名称 + * @return void + */ + static public function mark($name) { + self::$marker['time'][$name] = microtime(TRUE); + if(MEMORY_LIMIT_ON) { + self::$marker['mem'][$name] = memory_get_usage(); + self::$marker['peak'][$name] = function_exists('memory_get_peak_usage')?memory_get_peak_usage(): self::$marker['mem'][$name]; + } + } + + /** + * 区间使用时间查看 + * @access public + * @param string $start 开始标记的名称 + * @param string $end 结束标记的名称 + * @param integer $decimals 时间的小数位 + * @return integer + */ + static public function useTime($start,$end,$decimals = 6) { + if ( ! isset(self::$marker['time'][$start])) + return ''; + if ( ! isset(self::$marker['time'][$end])) + self::$marker['time'][$end] = microtime(TRUE); + return number_format(self::$marker['time'][$end] - self::$marker['time'][$start], $decimals); + } + + /** + * 区间使用内存查看 + * @access public + * @param string $start 开始标记的名称 + * @param string $end 结束标记的名称 + * @return integer + */ + static public function useMemory($start,$end) { + if(!MEMORY_LIMIT_ON) + return ''; + if ( ! isset(self::$marker['mem'][$start])) + return ''; + if ( ! isset(self::$marker['mem'][$end])) + self::$marker['mem'][$end] = memory_get_usage(); + return number_format((self::$marker['mem'][$end] - self::$marker['mem'][$start])/1024); + } + + /** + * 区间使用内存峰值查看 + * @access public + * @param string $start 开始标记的名称 + * @param string $end 结束标记的名称 + * @return integer + */ + static function getMemPeak($start,$end) { + if(!MEMORY_LIMIT_ON) + return ''; + if ( ! isset(self::$marker['peak'][$start])) + return ''; + if ( ! isset(self::$marker['peak'][$end])) + self::$marker['peak'][$end] = function_exists('memory_get_peak_usage')?memory_get_peak_usage(): memory_get_usage(); + return number_format(max(self::$marker['peak'][$start],self::$marker['peak'][$end])/1024); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/HtmlExtractor.class.php b/ThinkPHP/Extend/Library/ORG/Util/HtmlExtractor.class.php new file mode 100644 index 0000000..89ec0b0 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/HtmlExtractor.class.php @@ -0,0 +1,222 @@ +标签 + * 3 含有
标签 + * 减分项 1 含有li标签 + * 2 不包含任何标点符号 + * 3 含有关键词javascript + * 4 不包含任何中文的,直接删除 + * 5 有
  • text($html); + * 其中$html是某个网页的HTML代码,$str是返回的正文,正文编码是utf-8的 + */ +class HtmlExtractor { + + /* + * 取得汉字的个数(目前不太精确) + */ + function chineseCount($str){ + $count = preg_match_all("/[\xB0-\xF7][\xA1-\xFE]/",$str,$ff); + return $count; + } + + /* + * 判断一段文字是否是UTF-8,如果不是,那么要转成UTF-8 + */ + function getutf8($str){ + if(!$this->is_utf8(substr(strip_tags($str),0,500))){ + $str = $this->auto_charset($str,"gbk","utf-8"); + } + return $str; + } + + function is_utf8($string) + { + if(preg_match("/^([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}/",$string) == true || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}$/",$string) == true || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){2,}/",$string) == true){ + return true; + }else{ + return false; + } + } + + /* + * 自动转换字符集,支持数组和字符串 + */ + function auto_charset($fContents,$from,$to){ + $from = strtoupper($from)=='UTF8'? 'utf-8':$from; + $to = strtoupper($to)=='UTF8'? 'utf-8':$to; + if( strtoupper($from) === strtoupper($to) || empty($fContents) || (is_scalar($fContents) && !is_string($fContents)) ){ + //如果编码相同或者非字符串标量则不转换 + return $fContents; + } + if(is_string($fContents) ) { + if(function_exists('mb_convert_encoding')){ + return mb_convert_encoding ($fContents, $to, $from); + }elseif(function_exists('iconv')){ + return iconv($from,$to,$fContents); + }else{ + return $fContents; + } + } + elseif(is_array($fContents)){ + foreach ( $fContents as $key => $val ) { + $_key = $this->auto_charset($key,$from,$to); + $fContents[$_key] = $this->auto_charset($val,$from,$to); + if($key != $_key ) + unset($fContents[$key]); + } + return $fContents; + } + else{ + return $fContents; + } + } + + /* + * 进行正文提取动作 + */ + function text($str){ + $str = $this->clear($str); + $str = $this->getutf8($str); + $divList = $this->divList($str); + $content = array(); + foreach($divList[0] as $k=>$v){ + //首先判断,如果这个内容块的汉字数量站总数量的一半还多,那么就直接保留 + //还要判断,是不是一个A标签把整个内容都扩上 + if($this->chineseCount($v)/(strlen($v)/3) >= 0.4 && $this->checkHref($v)){ + array_push($content,strip_tags($v,"


    ")); + }else if($this->makeScore($v) >= 3){ + //然后根据分数判断,如果大于3分的,保留 + array_push($content,strip_tags($v,"


    ")); + }else{ + //这些就是排除的内容了 + } + } + return implode("",$content); + } + + /* + * 判断是不是一个A标签把整个内容都扩上 + * 判断方法:把A标签和它的内容都去掉后,看是否还含有中文 + */ + private function checkHref($str){ + if(!preg_match("']*?>(.*)'si",$str)){ + //如果不包含A标签,那不用管了,99%是正文 + return true; + } + $clear_str = preg_replace("']*?>(.*)'si","",$str); + if($this->chineseCount($clear_str)){ + return true; + }else{ + return false; + } + } + + function makeScore($str){ + $score = 0; + //标点分数 + $score += $this->score1($str); + //判断含有P标签 + $score += $this->score2($str); + //判断是否含有br标签 + $score += $this->score3($str); + //判断是否含有li标签 + $score -= $this->score4($str); + //判断是否不包含任何标点符号 + $score -= $this->score5($str); + //判断javascript关键字 + $score -= $this->score6($str); + //判断

  • score7($str); + return $score; + } + + /* + * 判断是否有标点符号 + */ + private function score1($str){ + //取得标点符号的个数 + $count = preg_match_all("/(,|。|!|(|)|“|”|;|《|》|、)/si",$str,$out); + if($count){ + return $count * 2; + }else{ + return 0; + } + } + + /* + * 判断是否含有P标签 + */ + private function score2($str){ + $count = preg_match_all("']*?>.*?

    'si",$str,$out); + return $count * 2; + } + + /* + * 判断是否含有BR标签 + */ + private function score3($str){ + $count = preg_match_all("'
    'si",$str,$out) + preg_match_all("'
    'si",$str,$out); + return $count * 2; + } + + /* + * 判断是否含有li标签 + */ + private function score4($str){ + //有多少,减多少分 * 2 + $count = preg_match_all("']*?>.*?
  • 'si",$str,$out); + return $count * 2; + } + + /* + * 判断是否不包含任何标点符号 + */ + private function score5($str){ + if(!preg_match_all("/(,|。|!|(|)|“|”|;|《|》|、|【|】)/si",$str,$out)){ + return 2; + }else{ + return 0; + } + } + + /* + * 判断是否包含javascript关键字,有几个,减几分 + */ + private function score6($str){ + $count = preg_match_all("'javascript'si",$str,$out); + return $count; + } + + /* + * 判断
  • ]*?>.*?]*?>.*?'si","",$str); + $str = preg_replace("']*?>.*?'si","",$str); + $str = preg_replace("''si","",$str); + return $str; + } + + /* + * 取得内容块 + */ + private function divList($str){ + preg_match_all("'<[^a][^>]*?>.*?]*?>'si",$str,$divlist); + return $divlist; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Image.class.php b/ThinkPHP/Extend/Library/ORG/Util/Image.class.php new file mode 100644 index 0000000..f342b23 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Image.class.php @@ -0,0 +1,560 @@ + +// +---------------------------------------------------------------------- + +/** + * 图像操作类库 + * @category ORG + * @package ORG + * @subpackage Util + * @author liu21st + */ +class Image { + + /** + * 取得图像信息 + * @static + * @access public + * @param string $image 图像文件名 + * @return mixed + */ + + static function getImageInfo($img) { + $imageInfo = getimagesize($img); + if ($imageInfo !== false) { + $imageType = strtolower(substr(image_type_to_extension($imageInfo[2]), 1)); + $imageSize = filesize($img); + $info = array( + "width" => $imageInfo[0], + "height" => $imageInfo[1], + "type" => $imageType, + "size" => $imageSize, + "mime" => $imageInfo['mime'] + ); + return $info; + } else { + return false; + } + } + + /** + * 为图片添加水印 + * @static public + * @param string $source 原文件名 + * @param string $water 水印图片 + * @param string $$savename 添加水印后的图片名 + * @param string $alpha 水印的透明度 + * @return void + */ + static public function water($source, $water, $savename=null, $alpha=80) { + //检查文件是否存在 + if (!file_exists($source) || !file_exists($water)) + return false; + + //图片信息 + $sInfo = self::getImageInfo($source); + $wInfo = self::getImageInfo($water); + + //如果图片小于水印图片,不生成图片 + if ($sInfo["width"] < $wInfo["width"] || $sInfo['height'] < $wInfo['height']) + return false; + + //建立图像 + $sCreateFun = "imagecreatefrom" . $sInfo['type']; + $sImage = $sCreateFun($source); + $wCreateFun = "imagecreatefrom" . $wInfo['type']; + $wImage = $wCreateFun($water); + + //设定图像的混色模式 + imagealphablending($wImage, true); + + //图像位置,默认为右下角右对齐 + $posY = $sInfo["height"] - $wInfo["height"]; + $posX = $sInfo["width"] - $wInfo["width"]; + + //生成混合图像 + imagecopymerge($sImage, $wImage, $posX, $posY, 0, 0, $wInfo['width'], $wInfo['height'], $alpha); + + //输出图像 + $ImageFun = 'Image' . $sInfo['type']; + //如果没有给出保存文件名,默认为原图像名 + if (!$savename) { + $savename = $source; + @unlink($source); + } + //保存图像 + $ImageFun($sImage, $savename); + imagedestroy($sImage); + } + + function showImg($imgFile, $text='', $x='10', $y='10', $alpha='50') { + //获取图像文件信息 + //2007/6/26 增加图片水印输出,$text为图片的完整路径即可 + $info = Image::getImageInfo($imgFile); + if ($info !== false) { + $createFun = str_replace('/', 'createfrom', $info['mime']); + $im = $createFun($imgFile); + if ($im) { + $ImageFun = str_replace('/', '', $info['mime']); + //水印开始 + if (!empty($text)) { + $tc = imagecolorallocate($im, 0, 0, 0); + if (is_file($text) && file_exists($text)) {//判断$text是否是图片路径 + // 取得水印信息 + $textInfo = Image::getImageInfo($text); + $createFun2 = str_replace('/', 'createfrom', $textInfo['mime']); + $waterMark = $createFun2($text); + //$waterMark=imagecolorallocatealpha($text,255,255,0,50); + $imgW = $info["width"]; + $imgH = $info["width"] * $textInfo["height"] / $textInfo["width"]; + //$y = ($info["height"]-$textInfo["height"])/2; + //设置水印的显示位置和透明度支持各种图片格式 + imagecopymerge($im, $waterMark, $x, $y, 0, 0, $textInfo['width'], $textInfo['height'], $alpha); + } else { + imagestring($im, 80, $x, $y, $text, $tc); + } + //ImageDestroy($tc); + } + //水印结束 + if ($info['type'] == 'png' || $info['type'] == 'gif') { + imagealphablending($im, FALSE); //取消默认的混色模式 + imagesavealpha($im, TRUE); //设定保存完整的 alpha 通道信息 + } + Header("Content-type: " . $info['mime']); + $ImageFun($im); + @ImageDestroy($im); + return; + } + + //保存图像 + $ImageFun($sImage, $savename); + imagedestroy($sImage); + //获取或者创建图像文件失败则生成空白PNG图片 + $im = imagecreatetruecolor(80, 30); + $bgc = imagecolorallocate($im, 255, 255, 255); + $tc = imagecolorallocate($im, 0, 0, 0); + imagefilledrectangle($im, 0, 0, 150, 30, $bgc); + imagestring($im, 4, 5, 5, "no pic", $tc); + Image::output($im); + return; + } + } + + /** + * 生成缩略图 + * @static + * @access public + * @param string $image 原图 + * @param string $type 图像格式 + * @param string $thumbname 缩略图文件名 + * @param string $maxWidth 宽度 + * @param string $maxHeight 高度 + * @param string $position 缩略图保存目录 + * @param boolean $interlace 启用隔行扫描 + * @return void + */ + static function thumb($image, $thumbname, $type='', $maxWidth=200, $maxHeight=50, $interlace=true) { + // 获取原图信息 + $info = Image::getImageInfo($image); + if ($info !== false) { + $srcWidth = $info['width']; + $srcHeight = $info['height']; + $type = empty($type) ? $info['type'] : $type; + $type = strtolower($type); + $interlace = $interlace ? 1 : 0; + unset($info); + $scale = min($maxWidth / $srcWidth, $maxHeight / $srcHeight); // 计算缩放比例 + if ($scale >= 1) { + // 超过原图大小不再缩略 + $width = $srcWidth; + $height = $srcHeight; + } else { + // 缩略图尺寸 + $width = (int) ($srcWidth * $scale); + $height = (int) ($srcHeight * $scale); + } + + // 载入原图 + $createFun = 'ImageCreateFrom' . ($type == 'jpg' ? 'jpeg' : $type); + if(!function_exists($createFun)) { + return false; + } + $srcImg = $createFun($image); + + //创建缩略图 + if ($type != 'gif' && function_exists('imagecreatetruecolor')) + $thumbImg = imagecreatetruecolor($width, $height); + else + $thumbImg = imagecreate($width, $height); + //png和gif的透明处理 by luofei614 + if('png'==$type){ + imagealphablending($thumbImg, false);//取消默认的混色模式(为解决阴影为绿色的问题) + imagesavealpha($thumbImg,true);//设定保存完整的 alpha 通道信息(为解决阴影为绿色的问题) + }elseif('gif'==$type){ + $trnprt_indx = imagecolortransparent($srcImg); + if ($trnprt_indx >= 0) { + //its transparent + $trnprt_color = imagecolorsforindex($srcImg , $trnprt_indx); + $trnprt_indx = imagecolorallocate($thumbImg, $trnprt_color['red'], $trnprt_color['green'], $trnprt_color['blue']); + imagefill($thumbImg, 0, 0, $trnprt_indx); + imagecolortransparent($thumbImg, $trnprt_indx); + } + } + // 复制图片 + if (function_exists("ImageCopyResampled")) + imagecopyresampled($thumbImg, $srcImg, 0, 0, 0, 0, $width, $height, $srcWidth, $srcHeight); + else + imagecopyresized($thumbImg, $srcImg, 0, 0, 0, 0, $width, $height, $srcWidth, $srcHeight); + + // 对jpeg图形设置隔行扫描 + if ('jpg' == $type || 'jpeg' == $type) + imageinterlace($thumbImg, $interlace); + + // 生成图片 + $imageFun = 'image' . ($type == 'jpg' ? 'jpeg' : $type); + $imageFun($thumbImg, $thumbname); + imagedestroy($thumbImg); + imagedestroy($srcImg); + return $thumbname; + } + return false; + } + + /** + * 生成特定尺寸缩略图 解决原版缩略图不能满足特定尺寸的问题 PS:会裁掉图片不符合缩略图比例的部分 + * @static + * @access public + * @param string $image 原图 + * @param string $type 图像格式 + * @param string $thumbname 缩略图文件名 + * @param string $maxWidth 宽度 + * @param string $maxHeight 高度 + * @param boolean $interlace 启用隔行扫描 + * @return void + */ + static function thumb2($image, $thumbname, $type='', $maxWidth=200, $maxHeight=50, $interlace=true) { + // 获取原图信息 + $info = Image::getImageInfo($image); + if ($info !== false) { + $srcWidth = $info['width']; + $srcHeight = $info['height']; + $type = empty($type) ? $info['type'] : $type; + $type = strtolower($type); + $interlace = $interlace ? 1 : 0; + unset($info); + $scale = max($maxWidth / $srcWidth, $maxHeight / $srcHeight); // 计算缩放比例 + //判断原图和缩略图比例 如原图宽于缩略图则裁掉两边 反之.. + if($maxWidth / $srcWidth > $maxHeight / $srcHeight){ + //高于 + $srcX = 0; + $srcY = ($srcHeight - $maxHeight / $scale) / 2 ; + $cutWidth = $srcWidth; + $cutHeight = $maxHeight / $scale; + }else{ + //宽于 + $srcX = ($srcWidth - $maxWidth / $scale) / 2; + $srcY = 0; + $cutWidth = $maxWidth / $scale; + $cutHeight = $srcHeight; + } + + // 载入原图 + $createFun = 'ImageCreateFrom' . ($type == 'jpg' ? 'jpeg' : $type); + $srcImg = $createFun($image); + + //创建缩略图 + if ($type != 'gif' && function_exists('imagecreatetruecolor')) + $thumbImg = imagecreatetruecolor($maxWidth, $maxHeight); + else + $thumbImg = imagecreate($maxWidth, $maxHeight); + + // 复制图片 + if (function_exists("ImageCopyResampled")) + imagecopyresampled($thumbImg, $srcImg, 0, 0, $srcX, $srcY, $maxWidth, $maxHeight, $cutWidth, $cutHeight); + else + imagecopyresized($thumbImg, $srcImg, 0, 0, $srcX, $srcY, $maxWidth, $maxHeight, $cutWidth, $cutHeight); + if ('gif' == $type || 'png' == $type) { + //imagealphablending($thumbImg, false);//取消默认的混色模式 + //imagesavealpha($thumbImg,true);//设定保存完整的 alpha 通道信息 + $background_color = imagecolorallocate($thumbImg, 0, 255, 0); // 指派一个绿色 + imagecolortransparent($thumbImg, $background_color); // 设置为透明色,若注释掉该行则输出绿色的图 + } + + // 对jpeg图形设置隔行扫描 + if ('jpg' == $type || 'jpeg' == $type) + imageinterlace($thumbImg, $interlace); + + // 生成图片 + $imageFun = 'image' . ($type == 'jpg' ? 'jpeg' : $type); + $imageFun($thumbImg, $thumbname); + imagedestroy($thumbImg); + imagedestroy($srcImg); + return $thumbname; + } + return false; + } + + /** + * 根据给定的字符串生成图像 + * @static + * @access public + * @param string $string 字符串 + * @param string $size 图像大小 width,height 或者 array(width,height) + * @param string $font 字体信息 fontface,fontsize 或者 array(fontface,fontsize) + * @param string $type 图像格式 默认PNG + * @param integer $disturb 是否干扰 1 点干扰 2 线干扰 3 复合干扰 0 无干扰 + * @param bool $border 是否加边框 array(color) + * @return string + */ + static function buildString($string, $rgb=array(), $filename='', $type='png', $disturb=1, $border=true) { + if (is_string($size)) + $size = explode(',', $size); + $width = $size[0]; + $height = $size[1]; + if (is_string($font)) + $font = explode(',', $font); + $fontface = $font[0]; + $fontsize = $font[1]; + $length = strlen($string); + $width = ($length * 9 + 10) > $width ? $length * 9 + 10 : $width; + $height = 22; + if ($type != 'gif' && function_exists('imagecreatetruecolor')) { + $im = @imagecreatetruecolor($width, $height); + } else { + $im = @imagecreate($width, $height); + } + if (empty($rgb)) { + $color = imagecolorallocate($im, 102, 104, 104); + } else { + $color = imagecolorallocate($im, $rgb[0], $rgb[1], $rgb[2]); + } + $backColor = imagecolorallocate($im, 255, 255, 255); //背景色(随机) + $borderColor = imagecolorallocate($im, 100, 100, 100); //边框色 + $pointColor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); //点颜色 + + @imagefilledrectangle($im, 0, 0, $width - 1, $height - 1, $backColor); + @imagerectangle($im, 0, 0, $width - 1, $height - 1, $borderColor); + @imagestring($im, 5, 5, 3, $string, $color); + if (!empty($disturb)) { + // 添加干扰 + if ($disturb = 1 || $disturb = 3) { + for ($i = 0; $i < 25; $i++) { + imagesetpixel($im, mt_rand(0, $width), mt_rand(0, $height), $pointColor); + } + } elseif ($disturb = 2 || $disturb = 3) { + for ($i = 0; $i < 10; $i++) { + imagearc($im, mt_rand(-10, $width), mt_rand(-10, $height), mt_rand(30, 300), mt_rand(20, 200), 55, 44, $pointColor); + } + } + } + Image::output($im, $type, $filename); + } + + /** + * 生成图像验证码 + * @static + * @access public + * @param string $length 位数 + * @param string $mode 类型 + * @param string $type 图像格式 + * @param string $width 宽度 + * @param string $height 高度 + * @return string + */ + static function buildImageVerify($length=4, $mode=1, $type='png', $width=48, $height=22, $verifyName='verify') { + import('ORG.Util.String'); + $randval = String::randString($length, $mode); + session($verifyName, md5($randval)); + $width = ($length * 10 + 10) > $width ? $length * 10 + 10 : $width; + if ($type != 'gif' && function_exists('imagecreatetruecolor')) { + $im = imagecreatetruecolor($width, $height); + } else { + $im = imagecreate($width, $height); + } + $r = Array(225, 255, 255, 223); + $g = Array(225, 236, 237, 255); + $b = Array(225, 236, 166, 125); + $key = mt_rand(0, 3); + + $backColor = imagecolorallocate($im, $r[$key], $g[$key], $b[$key]); //背景色(随机) + $borderColor = imagecolorallocate($im, 100, 100, 100); //边框色 + imagefilledrectangle($im, 0, 0, $width - 1, $height - 1, $backColor); + imagerectangle($im, 0, 0, $width - 1, $height - 1, $borderColor); + $stringColor = imagecolorallocate($im, mt_rand(0, 200), mt_rand(0, 120), mt_rand(0, 120)); + // 干扰 + for ($i = 0; $i < 10; $i++) { + imagearc($im, mt_rand(-10, $width), mt_rand(-10, $height), mt_rand(30, 300), mt_rand(20, 200), 55, 44, $stringColor); + } + for ($i = 0; $i < 25; $i++) { + imagesetpixel($im, mt_rand(0, $width), mt_rand(0, $height), $stringColor); + } + for ($i = 0; $i < $length; $i++) { + imagestring($im, 5, $i * 10 + 5, mt_rand(1, 8), $randval{$i}, $stringColor); + } + Image::output($im, $type); + } + + // 中文验证码 + static function GBVerify($length=4, $type='png', $width=180, $height=50, $fontface='simhei.ttf', $verifyName='verify') { + import('ORG.Util.String'); + $code = String::randString($length, 4); + $width = ($length * 45) > $width ? $length * 45 : $width; + session($verifyName, md5($code)); + $im = imagecreatetruecolor($width, $height); + $borderColor = imagecolorallocate($im, 100, 100, 100); //边框色 + $bkcolor = imagecolorallocate($im, 250, 250, 250); + imagefill($im, 0, 0, $bkcolor); + @imagerectangle($im, 0, 0, $width - 1, $height - 1, $borderColor); + // 干扰 + for ($i = 0; $i < 15; $i++) { + $fontcolor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); + imagearc($im, mt_rand(-10, $width), mt_rand(-10, $height), mt_rand(30, 300), mt_rand(20, 200), 55, 44, $fontcolor); + } + for ($i = 0; $i < 255; $i++) { + $fontcolor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); + imagesetpixel($im, mt_rand(0, $width), mt_rand(0, $height), $fontcolor); + } + if (!is_file($fontface)) { + $fontface = dirname(__FILE__) . "/" . $fontface; + } + for ($i = 0; $i < $length; $i++) { + $fontcolor = imagecolorallocate($im, mt_rand(0, 120), mt_rand(0, 120), mt_rand(0, 120)); //这样保证随机出来的颜色较深。 + $codex = String::msubstr($code, $i, 1); + imagettftext($im, mt_rand(16, 20), mt_rand(-60, 60), 40 * $i + 20, mt_rand(30, 35), $fontcolor, $fontface, $codex); + } + Image::output($im, $type); + } + + /** + * 把图像转换成字符显示 + * @static + * @access public + * @param string $image 要显示的图像 + * @param string $type 图像类型,默认自动获取 + * @return string + */ + static function showASCIIImg($image, $string='', $type='') { + $info = Image::getImageInfo($image); + if ($info !== false) { + $type = empty($type) ? $info['type'] : $type; + unset($info); + // 载入原图 + $createFun = 'ImageCreateFrom' . ($type == 'jpg' ? 'jpeg' : $type); + $im = $createFun($image); + $dx = imagesx($im); + $dy = imagesy($im); + $i = 0; + $out = ''; + set_time_limit(0); + for ($y = 0; $y < $dy; $y++) { + for ($x = 0; $x < $dx; $x++) { + $col = imagecolorat($im, $x, $y); + $rgb = imagecolorsforindex($im, $col); + $str = empty($string) ? '*' : $string[$i++]; + $out .= sprintf('' . $str . '', $rgb['red'], $rgb['green'], $rgb['blue']); + } + $out .= "
    \n"; + } + $out .= '
    '; + imagedestroy($im); + return $out; + } + return false; + } + + /** + * 生成UPC-A条形码 + * @static + * @param string $type 图像格式 + * @param string $type 图像格式 + * @param string $lw 单元宽度 + * @param string $hi 条码高度 + * @return string + */ + static function UPCA($code, $type='png', $lw=2, $hi=100) { + static $Lencode = array('0001101', '0011001', '0010011', '0111101', '0100011', + '0110001', '0101111', '0111011', '0110111', '0001011'); + static $Rencode = array('1110010', '1100110', '1101100', '1000010', '1011100', + '1001110', '1010000', '1000100', '1001000', '1110100'); + $ends = '101'; + $center = '01010'; + /* UPC-A Must be 11 digits, we compute the checksum. */ + if (strlen($code) != 11) { + die("UPC-A Must be 11 digits."); + } + /* Compute the EAN-13 Checksum digit */ + $ncode = '0' . $code; + $even = 0; + $odd = 0; + for ($x = 0; $x < 12; $x++) { + if ($x % 2) { + $odd += $ncode[$x]; + } else { + $even += $ncode[$x]; + } + } + $code.= ( 10 - (($odd * 3 + $even) % 10)) % 10; + /* Create the bar encoding using a binary string */ + $bars = $ends; + $bars.=$Lencode[$code[0]]; + for ($x = 1; $x < 6; $x++) { + $bars.=$Lencode[$code[$x]]; + } + $bars.=$center; + for ($x = 6; $x < 12; $x++) { + $bars.=$Rencode[$code[$x]]; + } + $bars.=$ends; + /* Generate the Barcode Image */ + if ($type != 'gif' && function_exists('imagecreatetruecolor')) { + $im = imagecreatetruecolor($lw * 95 + 30, $hi + 30); + } else { + $im = imagecreate($lw * 95 + 30, $hi + 30); + } + $fg = ImageColorAllocate($im, 0, 0, 0); + $bg = ImageColorAllocate($im, 255, 255, 255); + ImageFilledRectangle($im, 0, 0, $lw * 95 + 30, $hi + 30, $bg); + $shift = 10; + for ($x = 0; $x < strlen($bars); $x++) { + if (($x < 10) || ($x >= 45 && $x < 50) || ($x >= 85)) { + $sh = 10; + } else { + $sh = 0; + } + if ($bars[$x] == '1') { + $color = $fg; + } else { + $color = $bg; + } + ImageFilledRectangle($im, ($x * $lw) + 15, 5, ($x + 1) * $lw + 14, $hi + 5 + $sh, $color); + } + /* Add the Human Readable Label */ + ImageString($im, 4, 5, $hi - 5, $code[0], $fg); + for ($x = 0; $x < 5; $x++) { + ImageString($im, 5, $lw * (13 + $x * 6) + 15, $hi + 5, $code[$x + 1], $fg); + ImageString($im, 5, $lw * (53 + $x * 6) + 15, $hi + 5, $code[$x + 6], $fg); + } + ImageString($im, 4, $lw * 95 + 17, $hi - 5, $code[11], $fg); + /* Output the Header and Content. */ + Image::output($im, $type); + } + + static function output($im, $type='png', $filename='') { + header("Content-type: image/" . $type); + $ImageFun = 'image' . $type; + if (empty($filename)) { + $ImageFun($im); + } else { + $ImageFun($im, $filename); + } + imagedestroy($im); + } + +} diff --git a/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/GIF.class.php b/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/GIF.class.php new file mode 100644 index 0000000..d042ca7 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/GIF.class.php @@ -0,0 +1,570 @@ + +// +---------------------------------------------------------------------- +// | GIF.class.php 2013-03-09 +// +---------------------------------------------------------------------- + +class GIF{ + /** + * GIF帧列表 + * @var array + */ + private $frames = array(); + + /** + * 每帧等待时间列表 + * @var array + */ + private $delays = array(); + + /** + * 构造方法,用于解码GIF图片 + * @param string $src GIF图片数据 + * @param string $mod 图片数据类型 + */ + public function __construct($src = null, $mod = 'url') { + if(!is_null($src)){ + if('url' == $mod && is_file($src)){ + $src = file_get_contents($src); + } + + /* 解码GIF图片 */ + try{ + $de = new GIFDecoder($src); + $this->frames = $de->GIFGetFrames(); + $this->delays = $de->GIFGetDelays(); + } catch(Exception $e){ + throw new Exception("解码GIF图片出错"); + } + } + } + + /** + * 设置或获取当前帧的数据 + * @param string $stream 二进制数据流 + * @return boolean 获取到的数据 + */ + public function image($stream = null){ + if(is_null($stream)){ + $current = current($this->frames); + return false === $current ? reset($this->frames) : $current; + } else { + $this->frames[key($this->frames)] = $stream; + } + } + + /** + * 将当前帧移动到下一帧 + * @return string 当前帧数据 + */ + public function nextImage(){ + return next($this->frames); + } + + /** + * 编码并保存当前GIF图片 + * @param string $gifname 图片名称 + */ + public function save($gifname){ + $gif = new GIFEncoder($this->frames, $this->delays, 0, 2, 0, 0, 0, 'bin'); + file_put_contents($gifname, $gif->GetAnimation()); + } + +} + + +/* +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: GIFEncoder Version 2.0 by László Zsidi, http://gifs.hu +:: +:: This class is a rewritten 'GifMerge.class.php' version. +:: +:: Modification: +:: - Simplified and easy code, +:: - Ultra fast encoding, +:: - Built-in errors, +:: - Stable working +:: +:: +:: Updated at 2007. 02. 13. '00.05.AM' +:: +:: +:: +:: Try on-line GIFBuilder Form demo based on GIFEncoder. +:: +:: http://gifs.hu/phpclasses/demos/GifBuilder/ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +*/ + +Class GIFEncoder { + var $GIF = "GIF89a"; /* GIF header 6 bytes */ + var $VER = "GIFEncoder V2.05"; /* Encoder version */ + + var $BUF = Array ( ); + var $LOP = 0; + var $DIS = 2; + var $COL = -1; + var $IMG = -1; + + var $ERR = Array ( + 'ERR00'=>"Does not supported function for only one image!", + 'ERR01'=>"Source is not a GIF image!", + 'ERR02'=>"Unintelligible flag ", + 'ERR03'=>"Does not make animation from animated GIF source", + ); + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFEncoder... + :: + */ + function GIFEncoder ( + $GIF_src, $GIF_dly, $GIF_lop, $GIF_dis, + $GIF_red, $GIF_grn, $GIF_blu, $GIF_mod + ) { + if ( ! is_array ( $GIF_src ) && ! is_array ( $GIF_tim ) ) { + printf ( "%s: %s", $this->VER, $this->ERR [ 'ERR00' ] ); + exit ( 0 ); + } + $this->LOP = ( $GIF_lop > -1 ) ? $GIF_lop : 0; + $this->DIS = ( $GIF_dis > -1 ) ? ( ( $GIF_dis < 3 ) ? $GIF_dis : 3 ) : 2; + $this->COL = ( $GIF_red > -1 && $GIF_grn > -1 && $GIF_blu > -1 ) ? + ( $GIF_red | ( $GIF_grn << 8 ) | ( $GIF_blu << 16 ) ) : -1; + + for ( $i = 0; $i < count ( $GIF_src ); $i++ ) { + if ( strToLower ( $GIF_mod ) == "url" ) { + $this->BUF [ ] = fread ( fopen ( $GIF_src [ $i ], "rb" ), filesize ( $GIF_src [ $i ] ) ); + } + else if ( strToLower ( $GIF_mod ) == "bin" ) { + $this->BUF [ ] = $GIF_src [ $i ]; + } + else { + printf ( "%s: %s ( %s )!", $this->VER, $this->ERR [ 'ERR02' ], $GIF_mod ); + exit ( 0 ); + } + if ( substr ( $this->BUF [ $i ], 0, 6 ) != "GIF87a" && substr ( $this->BUF [ $i ], 0, 6 ) != "GIF89a" ) { + printf ( "%s: %d %s", $this->VER, $i, $this->ERR [ 'ERR01' ] ); + exit ( 0 ); + } + for ( $j = ( 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) ), $k = TRUE; $k; $j++ ) { + switch ( $this->BUF [ $i ] { $j } ) { + case "!": + if ( ( substr ( $this->BUF [ $i ], ( $j + 3 ), 8 ) ) == "NETSCAPE" ) { + printf ( "%s: %s ( %s source )!", $this->VER, $this->ERR [ 'ERR03' ], ( $i + 1 ) ); + exit ( 0 ); + } + break; + case ";": + $k = FALSE; + break; + } + } + } + GIFEncoder::GIFAddHeader ( ); + for ( $i = 0; $i < count ( $this->BUF ); $i++ ) { + GIFEncoder::GIFAddFrames ( $i, $GIF_dly [ $i ] ); + } + GIFEncoder::GIFAddFooter ( ); + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddHeader... + :: + */ + function GIFAddHeader ( ) { + $cmap = 0; + + if ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x80 ) { + $cmap = 3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) ); + + $this->GIF .= substr ( $this->BUF [ 0 ], 6, 7 ); + $this->GIF .= substr ( $this->BUF [ 0 ], 13, $cmap ); + $this->GIF .= "!\377\13NETSCAPE2.0\3\1" . GIFEncoder::GIFWord ( $this->LOP ) . "\0"; + } + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddFrames... + :: + */ + function GIFAddFrames ( $i, $d ) { + + $Locals_str = 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ); + + $Locals_end = strlen ( $this->BUF [ $i ] ) - $Locals_str - 1; + $Locals_tmp = substr ( $this->BUF [ $i ], $Locals_str, $Locals_end ); + + $Global_len = 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ); + $Locals_len = 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ); + + $Global_rgb = substr ( $this->BUF [ 0 ], 13, + 3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) ) ); + $Locals_rgb = substr ( $this->BUF [ $i ], 13, + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) ); + + $Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 0 ) . + chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . "\x0\x0"; + + if ( $this->COL > -1 && ord ( $this->BUF [ $i ] { 10 } ) & 0x80 ) { + for ( $j = 0; $j < ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ); $j++ ) { + if ( + ord ( $Locals_rgb { 3 * $j + 0 } ) == ( ( $this->COL >> 16 ) & 0xFF ) && + ord ( $Locals_rgb { 3 * $j + 1 } ) == ( ( $this->COL >> 8 ) & 0xFF ) && + ord ( $Locals_rgb { 3 * $j + 2 } ) == ( ( $this->COL >> 0 ) & 0xFF ) + ) { + $Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 1 ) . + chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . chr ( $j ) . "\x0"; + break; + } + } + } + switch ( $Locals_tmp { 0 } ) { + case "!": + $Locals_img = substr ( $Locals_tmp, 8, 10 ); + $Locals_tmp = substr ( $Locals_tmp, 18, strlen ( $Locals_tmp ) - 18 ); + break; + case ",": + $Locals_img = substr ( $Locals_tmp, 0, 10 ); + $Locals_tmp = substr ( $Locals_tmp, 10, strlen ( $Locals_tmp ) - 10 ); + break; + } + if ( ord ( $this->BUF [ $i ] { 10 } ) & 0x80 && $this->IMG > -1 ) { + if ( $Global_len == $Locals_len ) { + if ( GIFEncoder::GIFBlockCompare ( $Global_rgb, $Locals_rgb, $Global_len ) ) { + $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp ); + } + else { + $byte = ord ( $Locals_img { 9 } ); + $byte |= 0x80; + $byte &= 0xF8; + $byte |= ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ); + $Locals_img { 9 } = chr ( $byte ); + $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp ); + } + } + else { + $byte = ord ( $Locals_img { 9 } ); + $byte |= 0x80; + $byte &= 0xF8; + $byte |= ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ); + $Locals_img { 9 } = chr ( $byte ); + $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp ); + } + } + else { + $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp ); + } + $this->IMG = 1; + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddFooter... + :: + */ + function GIFAddFooter ( ) { + $this->GIF .= ";"; + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFBlockCompare... + :: + */ + function GIFBlockCompare ( $GlobalBlock, $LocalBlock, $Len ) { + + for ( $i = 0; $i < $Len; $i++ ) { + if ( + $GlobalBlock { 3 * $i + 0 } != $LocalBlock { 3 * $i + 0 } || + $GlobalBlock { 3 * $i + 1 } != $LocalBlock { 3 * $i + 1 } || + $GlobalBlock { 3 * $i + 2 } != $LocalBlock { 3 * $i + 2 } + ) { + return ( 0 ); + } + } + + return ( 1 ); + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFWord... + :: + */ + function GIFWord ( $int ) { + + return ( chr ( $int & 0xFF ) . chr ( ( $int >> 8 ) & 0xFF ) ); + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GetAnimation... + :: + */ + function GetAnimation ( ) { + return ( $this->GIF ); + } +} + + +/* +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: GIFDecoder Version 2.0 by László Zsidi, http://gifs.hu +:: +:: Created at 2007. 02. 01. '07.47.AM' +:: +:: +:: +:: +:: Try on-line GIFBuilder Form demo based on GIFDecoder. +:: +:: http://gifs.hu/phpclasses/demos/GifBuilder/ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +*/ + +Class GIFDecoder { + var $GIF_buffer = Array ( ); + var $GIF_arrays = Array ( ); + var $GIF_delays = Array ( ); + var $GIF_stream = ""; + var $GIF_string = ""; + var $GIF_bfseek = 0; + + var $GIF_screen = Array ( ); + var $GIF_global = Array ( ); + var $GIF_sorted; + var $GIF_colorS; + var $GIF_colorC; + var $GIF_colorF; + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFDecoder ( $GIF_pointer ) + :: + */ + function GIFDecoder ( $GIF_pointer ) { + $this->GIF_stream = $GIF_pointer; + + GIFDecoder::GIFGetByte ( 6 ); // GIF89a + GIFDecoder::GIFGetByte ( 7 ); // Logical Screen Descriptor + + $this->GIF_screen = $this->GIF_buffer; + $this->GIF_colorF = $this->GIF_buffer [ 4 ] & 0x80 ? 1 : 0; + $this->GIF_sorted = $this->GIF_buffer [ 4 ] & 0x08 ? 1 : 0; + $this->GIF_colorC = $this->GIF_buffer [ 4 ] & 0x07; + $this->GIF_colorS = 2 << $this->GIF_colorC; + + if ( $this->GIF_colorF == 1 ) { + GIFDecoder::GIFGetByte ( 3 * $this->GIF_colorS ); + $this->GIF_global = $this->GIF_buffer; + } + /* + * + * 05.06.2007. + * Made a little modification + * + * + - for ( $cycle = 1; $cycle; ) { + + if ( GIFDecoder::GIFGetByte ( 1 ) ) { + - switch ( $this->GIF_buffer [ 0 ] ) { + - case 0x21: + - GIFDecoder::GIFReadExtensions ( ); + - break; + - case 0x2C: + - GIFDecoder::GIFReadDescriptor ( ); + - break; + - case 0x3B: + - $cycle = 0; + - break; + - } + - } + + else { + + $cycle = 0; + + } + - } + */ + for ( $cycle = 1; $cycle; ) { + if ( GIFDecoder::GIFGetByte ( 1 ) ) { + switch ( $this->GIF_buffer [ 0 ] ) { + case 0x21: + GIFDecoder::GIFReadExtensions ( ); + break; + case 0x2C: + GIFDecoder::GIFReadDescriptor ( ); + break; + case 0x3B: + $cycle = 0; + break; + } + } + else { + $cycle = 0; + } + } + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFReadExtension ( ) + :: + */ + function GIFReadExtensions ( ) { + GIFDecoder::GIFGetByte ( 1 ); + for ( ; ; ) { + GIFDecoder::GIFGetByte ( 1 ); + if ( ( $u = $this->GIF_buffer [ 0 ] ) == 0x00 ) { + break; + } + GIFDecoder::GIFGetByte ( $u ); + /* + * 07.05.2007. + * Implemented a new line for a new function + * to determine the originaly delays between + * frames. + * + */ + if ( $u == 4 ) { + $this->GIF_delays [ ] = ( $this->GIF_buffer [ 1 ] | $this->GIF_buffer [ 2 ] << 8 ); + } + } + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFReadExtension ( ) + :: + */ + function GIFReadDescriptor ( ) { + $GIF_screen = Array ( ); + + GIFDecoder::GIFGetByte ( 9 ); + $GIF_screen = $this->GIF_buffer; + $GIF_colorF = $this->GIF_buffer [ 8 ] & 0x80 ? 1 : 0; + if ( $GIF_colorF ) { + $GIF_code = $this->GIF_buffer [ 8 ] & 0x07; + $GIF_sort = $this->GIF_buffer [ 8 ] & 0x20 ? 1 : 0; + } + else { + $GIF_code = $this->GIF_colorC; + $GIF_sort = $this->GIF_sorted; + } + $GIF_size = 2 << $GIF_code; + $this->GIF_screen [ 4 ] &= 0x70; + $this->GIF_screen [ 4 ] |= 0x80; + $this->GIF_screen [ 4 ] |= $GIF_code; + if ( $GIF_sort ) { + $this->GIF_screen [ 4 ] |= 0x08; + } + $this->GIF_string = "GIF87a"; + GIFDecoder::GIFPutByte ( $this->GIF_screen ); + if ( $GIF_colorF == 1 ) { + GIFDecoder::GIFGetByte ( 3 * $GIF_size ); + GIFDecoder::GIFPutByte ( $this->GIF_buffer ); + } + else { + GIFDecoder::GIFPutByte ( $this->GIF_global ); + } + $this->GIF_string .= chr ( 0x2C ); + $GIF_screen [ 8 ] &= 0x40; + GIFDecoder::GIFPutByte ( $GIF_screen ); + GIFDecoder::GIFGetByte ( 1 ); + GIFDecoder::GIFPutByte ( $this->GIF_buffer ); + for ( ; ; ) { + GIFDecoder::GIFGetByte ( 1 ); + GIFDecoder::GIFPutByte ( $this->GIF_buffer ); + if ( ( $u = $this->GIF_buffer [ 0 ] ) == 0x00 ) { + break; + } + GIFDecoder::GIFGetByte ( $u ); + GIFDecoder::GIFPutByte ( $this->GIF_buffer ); + } + $this->GIF_string .= chr ( 0x3B ); + /* + Add frames into $GIF_stream array... + */ + $this->GIF_arrays [ ] = $this->GIF_string; + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFGetByte ( $len ) + :: + */ + + /* + * + * 05.06.2007. + * Made a little modification + * + * + - function GIFGetByte ( $len ) { + - $this->GIF_buffer = Array ( ); + - + - for ( $i = 0; $i < $len; $i++ ) { + + if ( $this->GIF_bfseek > strlen ( $this->GIF_stream ) ) { + + return 0; + + } + - $this->GIF_buffer [ ] = ord ( $this->GIF_stream { $this->GIF_bfseek++ } ); + - } + + return 1; + - } + */ + function GIFGetByte ( $len ) { + $this->GIF_buffer = Array ( ); + + for ( $i = 0; $i < $len; $i++ ) { + if ( $this->GIF_bfseek > strlen ( $this->GIF_stream ) ) { + return 0; + } + $this->GIF_buffer [ ] = ord ( $this->GIF_stream { $this->GIF_bfseek++ } ); + } + return 1; + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFPutByte ( $bytes ) + :: + */ + function GIFPutByte ( $bytes ) { + for ( $i = 0; $i < count ( $bytes ); $i++ ) { + $this->GIF_string .= chr ( $bytes [ $i ] ); + } + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: PUBLIC FUNCTIONS + :: + :: + :: GIFGetFrames ( ) + :: + */ + function GIFGetFrames ( ) { + return ( $this->GIF_arrays ); + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFGetDelays ( ) + :: + */ + function GIFGetDelays ( ) { + return ( $this->GIF_delays ); + } +} diff --git a/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/ImageGd.class.php b/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/ImageGd.class.php new file mode 100644 index 0000000..a8ca8ab --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/ImageGd.class.php @@ -0,0 +1,543 @@ + +// +---------------------------------------------------------------------- +// | ImageGd.class.php 2013-03-05 +// +---------------------------------------------------------------------- + +class ImageGd{ + /** + * 图像资源对象 + * @var resource + */ + private $img; + + /** + * 图像信息,包括width,height,type,mime,size + * @var array + */ + private $info; + + /** + * 构造方法,可用于打开一张图像 + * @param string $imgname 图像路径 + */ + public function __construct($imgname = null) { + $imgname && $this->open($imgname); + } + + /** + * 打开一张图像 + * @param string $imgname 图像路径 + */ + public function open($imgname){ + //检测图像文件 + if(!is_file($imgname)) throw new Exception('不存在的图像文件'); + + //获取图像信息 + $info = getimagesize($imgname); + + //检测图像合法性 + if(false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))){ + throw new Exception('非法图像文件'); + } + + //设置图像信息 + $this->info = array( + 'width' => $info[0], + 'height' => $info[1], + 'type' => image_type_to_extension($info[2], false), + 'mime' => $info['mime'], + ); + + //销毁已存在的图像 + empty($this->img) || imagedestroy($this->img); + + //打开图像 + if('gif' == $this->info['type']){ + require_once 'GIF.class.php'; + $this->gif = new GIF($imgname); + $this->img = imagecreatefromstring($this->gif->image()); + } else { + $fun = "imagecreatefrom{$this->info['type']}"; + $this->img = $fun($imgname); + } + } + + /** + * 保存图像 + * @param string $imgname 图像保存名称 + * @param string $type 图像类型 + * @param boolean $interlace 是否对JPEG类型图像设置隔行扫描 + */ + public function save($imgname, $type = null, $interlace = true){ + if(empty($this->img)) throw new Exception('没有可以被保存的图像资源'); + + //自动获取图像类型 + if(is_null($type)){ + $type = $this->info['type']; + } else { + $type = strtolower($type); + } + + //JPEG图像设置隔行扫描 + if('jpeg' == $type || 'jpg' == $type){ + $type = 'jpeg'; + imageinterlace($this->img, $interlace); + } + + //保存图像 + if('gif' == $type && !empty($this->gif)){ + $this->gif->save($imgname); + } else { + $fun = "image{$type}"; + $fun($this->img, $imgname); + } + } + + /** + * 返回图像宽度 + * @return integer 图像宽度 + */ + public function width(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['width']; + } + + /** + * 返回图像高度 + * @return integer 图像高度 + */ + public function height(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['height']; + } + + /** + * 返回图像类型 + * @return string 图像类型 + */ + public function type(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['type']; + } + + /** + * 返回图像MIME类型 + * @return string 图像MIME类型 + */ + public function mime(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['mime']; + } + + /** + * 返回图像尺寸数组 0 - 图像宽度,1 - 图像高度 + * @return array 图像尺寸 + */ + public function size(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return array($this->info['width'], $this->info['height']); + } + + /** + * 裁剪图像 + * @param integer $w 裁剪区域宽度 + * @param integer $h 裁剪区域高度 + * @param integer $x 裁剪区域x坐标 + * @param integer $y 裁剪区域y坐标 + * @param integer $width 图像保存宽度 + * @param integer $height 图像保存高度 + */ + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){ + if(empty($this->img)) throw new Exception('没有可以被裁剪的图像资源'); + + //设置保存尺寸 + empty($width) && $width = $w; + empty($height) && $height = $h; + + do { + //创建新图像 + $img = imagecreatetruecolor($width, $height); + // 调整默认颜色 + $color = imagecolorallocate($img, 255, 255, 255); + imagefill($img, 0, 0, $color); + + //裁剪 + imagecopyresampled($img, $this->img, 0, 0, $x, $y, $width, $height, $w, $h); + imagedestroy($this->img); //销毁原图 + + //设置新图像 + $this->img = $img; + } while(!empty($this->gif) && $this->gifNext()); + + $this->info['width'] = $width; + $this->info['height'] = $height; + } + + /** + * 生成缩略图 + * @param integer $width 缩略图最大宽度 + * @param integer $height 缩略图最大高度 + * @param integer $type 缩略图裁剪类型 + */ + public function thumb($width, $height, $type = THINKIMAGE_THUMB_SCALE){ + if(empty($this->img)) throw new Exception('没有可以被缩略的图像资源'); + + //原图宽度和高度 + $w = $this->info['width']; + $h = $this->info['height']; + + /* 计算缩略图生成的必要参数 */ + switch ($type) { + /* 等比例缩放 */ + case THINKIMAGE_THUMB_SCALING: + //原图尺寸小于缩略图尺寸则不进行缩略 + if($w < $width && $h < $height) return; + + //计算缩放比例 + $scale = min($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $width = $w * $scale; + $height = $h * $scale; + break; + + /* 居中裁剪 */ + case THINKIMAGE_THUMB_CENTER: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $w = $width/$scale; + $h = $height/$scale; + $x = ($this->info['width'] - $w)/2; + $y = ($this->info['height'] - $h)/2; + break; + + /* 左上角裁剪 */ + case THINKIMAGE_THUMB_NORTHWEST: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $w = $width/$scale; + $h = $height/$scale; + break; + + /* 右下角裁剪 */ + case THINKIMAGE_THUMB_SOUTHEAST: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $w = $width/$scale; + $h = $height/$scale; + $x = $this->info['width'] - $w; + $y = $this->info['height'] - $h; + break; + + /* 填充 */ + case THINKIMAGE_THUMB_FILLED: + //计算缩放比例 + if($w < $width && $h < $height){ + $scale = 1; + } else { + $scale = min($width/$w, $height/$h); + } + + //设置缩略图的坐标及宽度和高度 + $neww = $w * $scale; + $newh = $h * $scale; + $posx = ($width - $w * $scale)/2; + $posy = ($height - $h * $scale)/2; + + do{ + //创建新图像 + $img = imagecreatetruecolor($width, $height); + // 调整默认颜色 + $color = imagecolorallocate($img, 255, 255, 255); + imagefill($img, 0, 0, $color); + + //裁剪 + imagecopyresampled($img, $this->img, $posx, $posy, $x, $y, $neww, $newh, $w, $h); + imagedestroy($this->img); //销毁原图 + $this->img = $img; + } while(!empty($this->gif) && $this->gifNext()); + + $this->info['width'] = $width; + $this->info['height'] = $height; + return; + + /* 固定 */ + case THINKIMAGE_THUMB_FIXED: + $x = $y = 0; + break; + + default: + throw new Exception('不支持的缩略图裁剪类型'); + } + + /* 裁剪图像 */ + $this->crop($w, $h, $x, $y, $width, $height); + } + + /** + * 添加水印 + * @param string $source 水印图片路径 + * @param integer $locate 水印位置 + * @param integer $alpha 水印透明度 + */ + public function water($source, $locate = THINKIMAGE_WATER_SOUTHEAST){ + //资源检测 + if(empty($this->img)) throw new Exception('没有可以被添加水印的图像资源'); + if(!is_file($source)) throw new Exception('水印图像不存在'); + + //获取水印图像信息 + $info = getimagesize($source); + if(false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))){ + throw new Exception('非法水印文件'); + } + + //创建水印图像资源 + $fun = 'imagecreatefrom' . image_type_to_extension($info[2], false); + $water = $fun($source); + + //设定水印图像的混色模式 + imagealphablending($water, true); + + /* 设定水印位置 */ + switch ($locate) { + /* 右下角水印 */ + case THINKIMAGE_WATER_SOUTHEAST: + $x = $this->info['width'] - $info[0]; + $y = $this->info['height'] - $info[1]; + break; + + /* 左下角水印 */ + case THINKIMAGE_WATER_SOUTHWEST: + $x = 0; + $y = $this->info['height'] - $info[1]; + break; + + /* 左上角水印 */ + case THINKIMAGE_WATER_NORTHWEST: + $x = $y = 0; + break; + + /* 右上角水印 */ + case THINKIMAGE_WATER_NORTHEAST: + $x = $this->info['width'] - $info[0]; + $y = 0; + break; + + /* 居中水印 */ + case THINKIMAGE_WATER_CENTER: + $x = ($this->info['width'] - $info[0])/2; + $y = ($this->info['height'] - $info[1])/2; + break; + + /* 下居中水印 */ + case THINKIMAGE_WATER_SOUTH: + $x = ($this->info['width'] - $info[0])/2; + $y = $this->info['height'] - $info[1]; + break; + + /* 右居中水印 */ + case THINKIMAGE_WATER_EAST: + $x = $this->info['width'] - $info[0]; + $y = ($this->info['height'] - $info[1])/2; + break; + + /* 上居中水印 */ + case THINKIMAGE_WATER_NORTH: + $x = ($this->info['width'] - $info[0])/2; + $y = 0; + break; + + /* 左居中水印 */ + case THINKIMAGE_WATER_WEST: + $x = 0; + $y = ($this->info['height'] - $info[1])/2; + break; + + default: + /* 自定义水印坐标 */ + if(is_array($locate)){ + list($x, $y) = $locate; + } else { + throw new Exception('不支持的水印位置类型'); + } + } + + do{ + //添加水印 + $src = imagecreatetruecolor($info[0], $info[1]); + // 调整默认颜色 + $color = imagecolorallocate($src, 255, 255, 255); + imagefill($src, 0, 0, $color); + + imagecopy($src, $this->img, 0, 0, $x, $y, $info[0], $info[1]); + imagecopy($src, $water, 0, 0, 0, 0, $info[0], $info[1]); + imagecopymerge($this->img, $src, $x, $y, 0, 0, $info[0], $info[1], 100); + + //销毁零时图片资源 + imagedestroy($src); + } while(!empty($this->gif) && $this->gifNext()); + + //销毁水印资源 + imagedestroy($water); + } + + /** + * 图像添加文字 + * @param string $text 添加的文字 + * @param string $font 字体路径 + * @param integer $size 字号 + * @param string $color 文字颜色 + * @param integer $locate 文字写入位置 + * @param integer $offset 文字相对当前位置的偏移量 + * @param integer $angle 文字倾斜角度 + */ + public function text($text, $font, $size, $color = '#00000000', + $locate = THINKIMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){ + //资源检测 + if(empty($this->img)) throw new Exception('没有可以被写入文字的图像资源'); + if(!is_file($font)) throw new Exception("不存在的字体文件:{$font}"); + + //获取文字信息 + $info = imagettfbbox($size, $angle, $font, $text); + $minx = min($info[0], $info[2], $info[4], $info[6]); + $maxx = max($info[0], $info[2], $info[4], $info[6]); + $miny = min($info[1], $info[3], $info[5], $info[7]); + $maxy = max($info[1], $info[3], $info[5], $info[7]); + + /* 计算文字初始坐标和尺寸 */ + $x = $minx; + $y = abs($miny); + $w = $maxx - $minx; + $h = $maxy - $miny; + + /* 设定文字位置 */ + switch ($locate) { + /* 右下角文字 */ + case THINKIMAGE_WATER_SOUTHEAST: + $x += $this->info['width'] - $w; + $y += $this->info['height'] - $h; + break; + + /* 左下角文字 */ + case THINKIMAGE_WATER_SOUTHWEST: + $y += $this->info['height'] - $h; + break; + + /* 左上角文字 */ + case THINKIMAGE_WATER_NORTHWEST: + // 起始坐标即为左上角坐标,无需调整 + break; + + /* 右上角文字 */ + case THINKIMAGE_WATER_NORTHEAST: + $x += $this->info['width'] - $w; + break; + + /* 居中文字 */ + case THINKIMAGE_WATER_CENTER: + $x += ($this->info['width'] - $w)/2; + $y += ($this->info['height'] - $h)/2; + break; + + /* 下居中文字 */ + case THINKIMAGE_WATER_SOUTH: + $x += ($this->info['width'] - $w)/2; + $y += $this->info['height'] - $h; + break; + + /* 右居中文字 */ + case THINKIMAGE_WATER_EAST: + $x += $this->info['width'] - $w; + $y += ($this->info['height'] - $h)/2; + break; + + /* 上居中文字 */ + case THINKIMAGE_WATER_NORTH: + $x += ($this->info['width'] - $w)/2; + break; + + /* 左居中文字 */ + case THINKIMAGE_WATER_WEST: + $y += ($this->info['height'] - $h)/2; + break; + + default: + /* 自定义文字坐标 */ + if(is_array($locate)){ + list($posx, $posy) = $locate; + $x += $posx; + $y += $posy; + } else { + throw new Exception('不支持的文字位置类型'); + } + } + + /* 设置偏移量 */ + if(is_array($offset)){ + $offset = array_map('intval', $offset); + list($ox, $oy) = $offset; + } else{ + $offset = intval($offset); + $ox = $oy = $offset; + } + + /* 设置颜色 */ + if(is_string($color) && 0 === strpos($color, '#')){ + $color = str_split(substr($color, 1), 2); + $color = array_map('hexdec', $color); + if(empty($color[3]) || $color[3] > 127){ + $color[3] = 0; + } + } elseif (!is_array($color)) { + throw new Exception('错误的颜色值'); + } + + do{ + /* 写入文字 */ + $col = imagecolorallocatealpha($this->img, $color[0], $color[1], $color[2], $color[3]); + imagettftext($this->img, $size, $angle, $x + $ox, $y + $oy, $col, $font, $text); + } while(!empty($this->gif) && $this->gifNext()); + } + + /* 切换到GIF的下一帧并保存当前帧,内部使用 */ + private function gifNext(){ + ob_start(); + ob_implicit_flush(0); + imagegif($this->img); + $img = ob_get_clean(); + + $this->gif->image($img); + $next = $this->gif->nextImage(); + + if($next){ + $this->img = imagecreatefromstring($next); + return $next; + } else { + $this->img = imagecreatefromstring($this->gif->image()); + return false; + } + } + + /** + * 析构方法,用于销毁图像资源 + */ + public function __destruct() { + empty($this->img) || imagedestroy($this->img); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/ImageImagick.class.php b/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/ImageImagick.class.php new file mode 100644 index 0000000..b65e07f --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Image/Driver/ImageImagick.class.php @@ -0,0 +1,588 @@ + +// +---------------------------------------------------------------------- +// | ImageImagick.class.php 2013-03-06 +// +---------------------------------------------------------------------- + +class ImageImagick{ + /** + * 图像资源对象 + * @var resource + */ + private $img; + + /** + * 图像信息,包括width,height,type,mime,size + * @var array + */ + private $info; + + /** + * 构造方法,可用于打开一张图像 + * @param string $imgname 图像路径 + */ + public function __construct($imgname = null) { + $imgname && $this->open($imgname); + } + + /** + * 打开一张图像 + * @param string $imgname 图像路径 + */ + public function open($imgname){ + //检测图像文件 + if(!is_file($imgname)) throw new Exception('不存在的图像文件'); + + //销毁已存在的图像 + empty($this->img) || $this->img->destroy(); + + //载入图像 + $this->img = new Imagick(realpath($imgname)); + + //设置图像信息 + $this->info = array( + 'width' => $this->img->getImageWidth(), + 'height' => $this->img->getImageHeight(), + 'type' => strtolower($this->img->getImageFormat()), + 'mime' => $this->img->getImageMimeType(), + ); + } + + /** + * 保存图像 + * @param string $imgname 图像保存名称 + * @param string $type 图像类型 + * @param boolean $interlace 是否对JPEG类型图像设置隔行扫描 + */ + public function save($imgname, $type = null, $interlace = true){ + if(empty($this->img)) throw new Exception('没有可以被保存的图像资源'); + + //设置图片类型 + if(is_null($type)){ + $type = $this->info['type']; + } else { + $type = strtolower($type); + $this->img->setImageFormat($type); + } + + //JPEG图像设置隔行扫描 + if('jpeg' == $type || 'jpg' == $type){ + $this->img->setImageInterlaceScheme(1); + } + + //去除图像配置信息 + $this->img->stripImage(); + + //保存图像 + $imgname = realpath(dirname($imgname)) . '/' . basename($imgname); //强制绝对路径 + if ('gif' == $type) { + $this->img->writeImages($imgname, true); + } else { + $this->img->writeImage($imgname); + } + } + + /** + * 返回图像宽度 + * @return integer 图像宽度 + */ + public function width(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['width']; + } + + /** + * 返回图像高度 + * @return integer 图像高度 + */ + public function height(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['height']; + } + + /** + * 返回图像类型 + * @return string 图像类型 + */ + public function type(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['type']; + } + + /** + * 返回图像MIME类型 + * @return string 图像MIME类型 + */ + public function mime(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['mime']; + } + + /** + * 返回图像尺寸数组 0 - 图像宽度,1 - 图像高度 + * @return array 图像尺寸 + */ + public function size(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return array($this->info['width'], $this->info['height']); + } + + /** + * 裁剪图像 + * @param integer $w 裁剪区域宽度 + * @param integer $h 裁剪区域高度 + * @param integer $x 裁剪区域x坐标 + * @param integer $y 裁剪区域y坐标 + * @param integer $width 图像保存宽度 + * @param integer $height 图像保存高度 + */ + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){ + if(empty($this->img)) throw new Exception('没有可以被裁剪的图像资源'); + + //设置保存尺寸 + empty($width) && $width = $w; + empty($height) && $height = $h; + + //裁剪图片 + if('gif' == $this->info['type']){ + $img = $this->img->coalesceImages(); + $this->img->destroy(); //销毁原图 + + //循环裁剪每一帧 + do { + $this->_crop($w, $h, $x, $y, $width, $height, $img); + } while ($img->nextImage()); + + //压缩图片 + $this->img = $img->deconstructImages(); + $img->destroy(); //销毁零时图片 + } else { + $this->_crop($w, $h, $x, $y, $width, $height); + } + } + + /* 裁剪图片,内部调用 */ + private function _crop($w, $h, $x, $y, $width, $height, $img = null){ + is_null($img) && $img = $this->img; + + //裁剪 + $info = $this->info; + if($x != 0 || $y != 0 || $w != $info['width'] || $h != $info['height']){ + $img->cropImage($w, $h, $x, $y); + $img->setImagePage($w, $h, 0, 0); //调整画布和图片一致 + } + + //调整大小 + if($w != $width || $h != $height){ + $img->sampleImage($width, $height); + } + + //设置缓存尺寸 + $this->info['width'] = $w; + $this->info['height'] = $h; + } + + /** + * 生成缩略图 + * @param integer $width 缩略图最大宽度 + * @param integer $height 缩略图最大高度 + * @param integer $type 缩略图裁剪类型 + */ + public function thumb($width, $height, $type = THINKIMAGE_THUMB_SCALE){ + if(empty($this->img)) throw new Exception('没有可以被缩略的图像资源'); + + //原图宽度和高度 + $w = $this->info['width']; + $h = $this->info['height']; + + /* 计算缩略图生成的必要参数 */ + switch ($type) { + /* 等比例缩放 */ + case THINKIMAGE_THUMB_SCALING: + //原图尺寸小于缩略图尺寸则不进行缩略 + if($w < $width && $h < $height) return; + + //计算缩放比例 + $scale = min($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $width = $w * $scale; + $height = $h * $scale; + break; + + /* 居中裁剪 */ + case THINKIMAGE_THUMB_CENTER: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $w = $width/$scale; + $h = $height/$scale; + $x = ($this->info['width'] - $w)/2; + $y = ($this->info['height'] - $h)/2; + break; + + /* 左上角裁剪 */ + case THINKIMAGE_THUMB_NORTHWEST: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $w = $width/$scale; + $h = $height/$scale; + break; + + /* 右下角裁剪 */ + case THINKIMAGE_THUMB_SOUTHEAST: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $w = $width/$scale; + $h = $height/$scale; + $x = $this->info['width'] - $w; + $y = $this->info['height'] - $h; + break; + + /* 填充 */ + case THINKIMAGE_THUMB_FILLED: + //计算缩放比例 + if($w < $width && $h < $height){ + $scale = 1; + } else { + $scale = min($width/$w, $height/$h); + } + + //设置缩略图的坐标及宽度和高度 + $neww = $w * $scale; + $newh = $h * $scale; + $posx = ($width - $w * $scale)/2; + $posy = ($height - $h * $scale)/2; + + //创建一张新图像 + $newimg = new Imagick(); + $newimg->newImage($width, $height, 'white', $this->info['type']); + + + if('gif' == $this->info['type']){ + $imgs = $this->img->coalesceImages(); + $img = new Imagick(); + $this->img->destroy(); //销毁原图 + + //循环填充每一帧 + do { + //填充图像 + $image = $this->_fill($newimg, $posx, $posy, $neww, $newh, $imgs); + + $img->addImage($image); + $img->setImageDelay($imgs->getImageDelay()); + $img->setImagePage($width, $height, 0, 0); + + $image->destroy(); //销毁零时图片 + + } while ($imgs->nextImage()); + + //压缩图片 + $this->img->destroy(); + $this->img = $img->deconstructImages(); + $imgs->destroy(); //销毁零时图片 + $img->destroy(); //销毁零时图片 + + } else { + //填充图像 + $img = $this->_fill($newimg, $posx, $posy, $neww, $newh); + //销毁原图 + $this->img->destroy(); + $this->img = $img; + } + + //设置新图像属性 + $this->info['width'] = $width; + $this->info['height'] = $height; + return; + + /* 固定 */ + case THINKIMAGE_THUMB_FIXED: + $x = $y = 0; + break; + + default: + throw new Exception('不支持的缩略图裁剪类型'); + } + + /* 裁剪图像 */ + $this->crop($w, $h, $x, $y, $width, $height); + } + + /* 填充指定图像,内部使用 */ + private function _fill($newimg, $posx, $posy, $neww, $newh, $img = null){ + is_null($img) && $img = $this->img; + + /* 将指定图片绘入空白图片 */ + $draw = new ImagickDraw(); + $draw->composite($img->getImageCompose(), $posx, $posy, $neww, $newh, $img); + $image = $newimg->clone(); + $image->drawImage($draw); + $draw->destroy(); + + return $image; + } + + /** + * 添加水印 + * @param string $source 水印图片路径 + * @param integer $locate 水印位置 + * @param integer $alpha 水印透明度 + */ + public function water($source, $locate = THINKIMAGE_WATER_SOUTHEAST){ + //资源检测 + if(empty($this->img)) throw new Exception('没有可以被添加水印的图像资源'); + if(!is_file($source)) throw new Exception('水印图像不存在'); + + //创建水印图像资源 + $water = new Imagick(realpath($source)); + $info = array($water->getImageWidth(), $water->getImageHeight()); + + /* 设定水印位置 */ + switch ($locate) { + /* 右下角水印 */ + case THINKIMAGE_WATER_SOUTHEAST: + $x = $this->info['width'] - $info[0]; + $y = $this->info['height'] - $info[1]; + break; + + /* 左下角水印 */ + case THINKIMAGE_WATER_SOUTHWEST: + $x = 0; + $y = $this->info['height'] - $info[1]; + break; + + /* 左上角水印 */ + case THINKIMAGE_WATER_NORTHWEST: + $x = $y = 0; + break; + + /* 右上角水印 */ + case THINKIMAGE_WATER_NORTHEAST: + $x = $this->info['width'] - $info[0]; + $y = 0; + break; + + /* 居中水印 */ + case THINKIMAGE_WATER_CENTER: + $x = ($this->info['width'] - $info[0])/2; + $y = ($this->info['height'] - $info[1])/2; + break; + + /* 下居中水印 */ + case THINKIMAGE_WATER_SOUTH: + $x = ($this->info['width'] - $info[0])/2; + $y = $this->info['height'] - $info[1]; + break; + + /* 右居中水印 */ + case THINKIMAGE_WATER_EAST: + $x = $this->info['width'] - $info[0]; + $y = ($this->info['height'] - $info[1])/2; + break; + + /* 上居中水印 */ + case THINKIMAGE_WATER_NORTH: + $x = ($this->info['width'] - $info[0])/2; + $y = 0; + break; + + /* 左居中水印 */ + case THINKIMAGE_WATER_WEST: + $x = 0; + $y = ($this->info['height'] - $info[1])/2; + break; + + default: + /* 自定义水印坐标 */ + if(is_array($locate)){ + list($x, $y) = $locate; + } else { + throw new Exception('不支持的水印位置类型'); + } + } + + //创建绘图资源 + $draw = new ImagickDraw(); + $draw->composite($water->getImageCompose(), $x, $y, $info[0], $info[1], $water); + + if('gif' == $this->info['type']){ + $img = $this->img->coalesceImages(); + $this->img->destroy(); //销毁原图 + + do{ + //添加水印 + $img->drawImage($draw); + } while ($img->nextImage()); + + //压缩图片 + $this->img = $img->deconstructImages(); + $img->destroy(); //销毁零时图片 + + } else { + //添加水印 + $this->img->drawImage($draw); + } + + //销毁水印资源 + $draw->destroy(); + $water->destroy(); + } + + /** + * 图像添加文字 + * @param string $text 添加的文字 + * @param string $font 字体路径 + * @param integer $size 字号 + * @param string $color 文字颜色 + * @param integer $locate 文字写入位置 + * @param integer $offset 文字相对当前位置的偏移量 + * @param integer $angle 文字倾斜角度 + */ + public function text($text, $font, $size, $color = '#00000000', + $locate = THINKIMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){ + //资源检测 + if(empty($this->img)) throw new Exception('没有可以被写入文字的图像资源'); + if(!is_file($font)) throw new Exception("不存在的字体文件:{$font}"); + + //获取颜色和透明度 + if(is_array($color)){ + $color = array_map('dechex', $color); + foreach ($color as &$value) { + $value = str_pad($value, 2, '0', STR_PAD_LEFT); + } + $color = '#' . implode('', $color); + } elseif(!is_string($color) || 0 !== strpos($color, '#')) { + throw new Exception('错误的颜色值'); + } + $col = substr($color, 0, 7); + $alp = strlen($color) == 9 ? substr($color, -2) : 0; + + + //获取文字信息 + $draw = new ImagickDraw(); + $draw->setFont(realpath($font)); + $draw->setFontSize($size); + $draw->setFillColor($col); + $draw->setFillAlpha(1-hexdec($alp)/127); + $draw->setTextAntialias(true); + $draw->setStrokeAntialias(true); + + $metrics = $this->img->queryFontMetrics($draw, $text); + + /* 计算文字初始坐标和尺寸 */ + $x = 0; + $y = $metrics['ascender']; + $w = $metrics['textWidth']; + $h = $metrics['textHeight']; + + /* 设定文字位置 */ + switch ($locate) { + /* 右下角文字 */ + case THINKIMAGE_WATER_SOUTHEAST: + $x += $this->info['width'] - $w; + $y += $this->info['height'] - $h; + break; + + /* 左下角文字 */ + case THINKIMAGE_WATER_SOUTHWEST: + $y += $this->info['height'] - $h; + break; + + /* 左上角文字 */ + case THINKIMAGE_WATER_NORTHWEST: + // 起始坐标即为左上角坐标,无需调整 + break; + + /* 右上角文字 */ + case THINKIMAGE_WATER_NORTHEAST: + $x += $this->info['width'] - $w; + break; + + /* 居中文字 */ + case THINKIMAGE_WATER_CENTER: + $x += ($this->info['width'] - $w)/2; + $y += ($this->info['height'] - $h)/2; + break; + + /* 下居中文字 */ + case THINKIMAGE_WATER_SOUTH: + $x += ($this->info['width'] - $w)/2; + $y += $this->info['height'] - $h; + break; + + /* 右居中文字 */ + case THINKIMAGE_WATER_EAST: + $x += $this->info['width'] - $w; + $y += ($this->info['height'] - $h)/2; + break; + + /* 上居中文字 */ + case THINKIMAGE_WATER_NORTH: + $x += ($this->info['width'] - $w)/2; + break; + + /* 左居中文字 */ + case THINKIMAGE_WATER_WEST: + $y += ($this->info['height'] - $h)/2; + break; + + default: + /* 自定义文字坐标 */ + if(is_array($locate)){ + list($posx, $posy) = $locate; + $x += $posx; + $y += $posy; + } else { + throw new Exception('不支持的文字位置类型'); + } + } + + /* 设置偏移量 */ + if(is_array($offset)){ + $offset = array_map('intval', $offset); + list($ox, $oy) = $offset; + } else{ + $offset = intval($offset); + $ox = $oy = $offset; + } + + /* 写入文字 */ + if('gif' == $this->info['type']){ + $img = $this->img->coalesceImages(); + $this->img->destroy(); //销毁原图 + do{ + $img->annotateImage($draw, $x + $ox, $y + $oy, $angle, $text); + } while ($img->nextImage()); + + //压缩图片 + $this->img = $img->deconstructImages(); + $img->destroy(); //销毁零时图片 + + } else { + $this->img->annotateImage($draw, $x + $ox, $y + $oy, $angle, $text); + } + $draw->destroy(); + } + + /** + * 析构方法,用于销毁图像资源 + */ + public function __destruct() { + empty($this->img) || $this->img->destroy(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Image/ThinkImage.class.php b/ThinkPHP/Extend/Library/ORG/Util/Image/ThinkImage.class.php new file mode 100644 index 0000000..e1e99bf --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Image/ThinkImage.class.php @@ -0,0 +1,188 @@ + +// +---------------------------------------------------------------------- +// | ThinkImage.class.php 2013-03-05 +// +---------------------------------------------------------------------- + +/* 驱动相关常量定义 */ +define('THINKIMAGE_GD', 1); //常量,标识GD库类型 +define('THINKIMAGE_IMAGICK', 2); //常量,标识imagick库类型 + +/* 缩略图相关常量定义 */ +define('THINKIMAGE_THUMB_SCALING', 1); //常量,标识缩略图等比例缩放类型 +define('THINKIMAGE_THUMB_FILLED', 2); //常量,标识缩略图缩放后填充类型 +define('THINKIMAGE_THUMB_CENTER', 3); //常量,标识缩略图居中裁剪类型 +define('THINKIMAGE_THUMB_NORTHWEST', 4); //常量,标识缩略图左上角裁剪类型 +define('THINKIMAGE_THUMB_SOUTHEAST', 5); //常量,标识缩略图右下角裁剪类型 +define('THINKIMAGE_THUMB_FIXED', 6); //常量,标识缩略图固定尺寸缩放类型 + +/* 水印相关常量定义 */ +define('THINKIMAGE_WATER_NORTHWEST', 1); //常量,标识左上角水印 +define('THINKIMAGE_WATER_NORTH', 2); //常量,标识上居中水印 +define('THINKIMAGE_WATER_NORTHEAST', 3); //常量,标识右上角水印 +define('THINKIMAGE_WATER_WEST', 4); //常量,标识左居中水印 +define('THINKIMAGE_WATER_CENTER', 5); //常量,标识居中水印 +define('THINKIMAGE_WATER_EAST', 6); //常量,标识右居中水印 +define('THINKIMAGE_WATER_SOUTHWEST', 7); //常量,标识左下角水印 +define('THINKIMAGE_WATER_SOUTH', 8); //常量,标识下居中水印 +define('THINKIMAGE_WATER_SOUTHEAST', 9); //常量,标识右下角水印 + +/** + * 图片处理驱动类,可配置图片处理库 + * 目前支持GD库和imagick + * @author 麦当苗儿 + */ +class ThinkImage{ + /** + * 图片资源 + * @var resource + */ + private $img; + + /** + * 构造方法,用于实例化一个图片处理对象 + * @param string $type 要使用的类库,默认使用GD库 + */ + public function __construct($type = THINKIMAGE_GD, $imgname = null){ + /* 判断调用库的类型 */ + switch ($type) { + case THINKIMAGE_GD: + $class = 'ImageGd'; + break; + case THINKIMAGE_IMAGICK: + $class = 'ImageImagick'; + break; + default: + throw new Exception('不支持的图片处理库类型'); + } + + /* 引入处理库,实例化图片处理对象 */ + require_once "Driver/{$class}.class.php"; + $this->img = new $class($imgname); + } + + /** + * 打开一幅图像 + * @param string $imgname 图片路径 + * @return Object 当前图片处理库对象 + */ + public function open($imgname){ + $this->img->open($imgname); + return $this; + } + + /** + * 保存图片 + * @param string $imgname 图片保存名称 + * @param string $type 图片类型 + * @param boolean $interlace 是否对JPEG类型图片设置隔行扫描 + * @return Object 当前图片处理库对象 + */ + public function save($imgname, $type = null, $interlace = true){ + $this->img->save($imgname, $type, $interlace); + return $this; + } + + /** + * 返回图片宽度 + * @return integer 图片宽度 + */ + public function width(){ + return $this->img->width(); + } + + /** + * 返回图片高度 + * @return integer 图片高度 + */ + public function height(){ + return $this->img->height(); + } + + /** + * 返回图像类型 + * @return string 图片类型 + */ + public function type(){ + return $this->img->type(); + } + + /** + * 返回图像MIME类型 + * @return string 图像MIME类型 + */ + public function mime(){ + return $this->img->mime(); + } + + /** + * 返回图像尺寸数组 0 - 图片宽度,1 - 图片高度 + * @return array 图片尺寸 + */ + public function size(){ + return $this->img->size(); + } + + /** + * 裁剪图片 + * @param integer $w 裁剪区域宽度 + * @param integer $h 裁剪区域高度 + * @param integer $x 裁剪区域x坐标 + * @param integer $y 裁剪区域y坐标 + * @param integer $width 图片保存宽度 + * @param integer $height 图片保存高度 + * @return Object 当前图片处理库对象 + */ + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){ + $this->img->crop($w, $h, $x, $y, $width, $height); + return $this; + } + + /** + * 生成缩略图 + * @param integer $width 缩略图最大宽度 + * @param integer $height 缩略图最大高度 + * @param integer $type 缩略图裁剪类型 + * @return Object 当前图片处理库对象 + */ + public function thumb($width, $height, $type = THINKIMAGE_THUMB_SCALE){ + $this->img->thumb($width, $height, $type); + return $this; + } + + /** + * 添加水印 + * @param string $source 水印图片路径 + * @param integer $locate 水印位置 + * @param integer $alpha 水印透明度 + * @return Object 当前图片处理库对象 + */ + public function water($source, $locate = THINKIMAGE_WATER_SOUTHEAST){ + $this->img->water($source, $locate); + return $this; + } + + /** + * 图像添加文字 + * @param string $text 添加的文字 + * @param string $font 字体路径 + * @param integer $size 字号 + * @param string $color 文字颜色 + * @param integer $locate 文字写入位置 + * @param integer $offset 文字相对当前位置的偏移量 + * @param integer $angle 文字倾斜角度 + * @return Object 当前图片处理库对象 + */ + public function text($text, $font, $size, $color = '#00000000', + $locate = THINKIMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){ + $this->img->text($text, $font, $size, $color, $locate, $offset, $angle); + return $this; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Image/readme.md b/ThinkPHP/Extend/Library/ORG/Util/Image/readme.md new file mode 100644 index 0000000..0fdd932 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Image/readme.md @@ -0,0 +1,150 @@ +## ThinkImage 是什么? + +ThinkImage是一个PHP图片处理工具。目前支持图片缩略图,图片裁剪,图片添加水印和文字水印等功能。可自由切换系统支持的图片处理工具,目前支持GD库和Imagick库。在GD库下也能良好的处理GIF图片。 + +## ThinkImage 怎么使用? + +ThinkImage的使用比较简单,你只需要引入ThinkImage类,实例化一个ThinkImage的对象并传入要使用的图片处理库类型和要处理的图片,就可以对图片进行操作了。关键代码如下:(以ThinkPHP为例,非ThinkPHP框架请使用PHP原生的文件引入方法) + + //引入图片处理库 + import('ORG.Util.Image.ThinkImage'); + //使用GD库来处理1.gif图片 + $img = new ThinkImage(THINKIMAGE_GD, './1.gif'); + //将图片裁剪为440x440并保存为corp.gif + $img->crop(440, 440)->save('./crop.gif'); + //给裁剪后的图片添加图片水印,位置为右下角,保存为water.gif + $img->water('./11.png', THINKIMAGE_WATER_SOUTHEAST)->save("water.gif"); + //给原图添加水印并保存为water_o.gif(需要重新打开原图) + $img->open('./1.gif')->water('./11.png', THINKIMAGE_WATER_SOUTHEAST)->save("water_o.gif"); + +## ThinkImage有哪些可以使用的常量? + +ThinkImage提供了部分常量,方便记忆,在使用的过程中,可以直接使用常量或对应的整型值。 + + /* 驱动相关常量定义 */ + define('THINKIMAGE_GD', 1); //常量,标识GD库类型 + define('THINKIMAGE_IMAGICK', 2); //常量,标识imagick库类型 + + /* 缩略图相关常量定义 */ + define('THINKIMAGE_THUMB_SCALING', 1); //常量,标识缩略图等比例缩放类型 + define('THINKIMAGE_THUMB_FILLED', 2); //常量,标识缩略图缩放后填充类型 + define('THINKIMAGE_THUMB_CENTER', 3); //常量,标识缩略图居中裁剪类型 + define('THINKIMAGE_THUMB_NORTHWEST', 4); //常量,标识缩略图左上角裁剪类型 + define('THINKIMAGE_THUMB_SOUTHEAST', 5); //常量,标识缩略图右下角裁剪类型 + define('THINKIMAGE_THUMB_FIXED', 6); //常量,标识缩略图固定尺寸缩放类型 + + /* 水印相关常量定义 */ + define('THINKIMAGE_WATER_NORTHWEST', 1); //常量,标识左上角水印 + define('THINKIMAGE_WATER_NORTH', 2); //常量,标识上居中水印 + define('THINKIMAGE_WATER_NORTHEAST', 3); //常量,标识右上角水印 + define('THINKIMAGE_WATER_WEST', 4); //常量,标识左居中水印 + define('THINKIMAGE_WATER_CENTER', 5); //常量,标识居中水印 + define('THINKIMAGE_WATER_EAST', 6); //常量,标识右居中水印 + define('THINKIMAGE_WATER_SOUTHWEST', 7); //常量,标识左下角水印 + define('THINKIMAGE_WATER_SOUTH', 8); //常量,标识下居中水印 + define('THINKIMAGE_WATER_SOUTHEAST', 9); //常量,标识右下角水印 + +## ThinkImage有哪些可以使用的方法? + +以下方法为ThinkImage提供的图片处理接口,可直接使用。 + +打开一幅图像 + + /** + * @param string $imgname 图片路径 + * @return Object 当前图片处理库对象 + */ + public function open($imgname){} + +保存图片 + + /** + * @param string $imgname 图片保存名称 + * @param string $type 图片类型 + * @param boolean $interlace 是否对JPEG类型图片设置隔行扫描 + * @return Object 当前图片处理库对象 + */ + public function save($imgname, $type = null, $interlace = true){} + +获取图片宽度 + + /** + * @return integer 图片宽度 + */ + public function width(){} + +获取图片高度 + + /** + * @return integer 图片高度 + */ + public function height(){} + +获取图像类型 + + /** + * @return string 图片类型 + */ + public function type(){} + +获取图像MIME类型 + + /** + * @return string 图像MIME类型 + */ + public function mime(){} + +获取图像尺寸数组 0 - 图片宽度,1 - 图片高度 + + /** + * @return array 图片尺寸 + */ + public function size(){} + +裁剪图片 + + /** + * @param integer $w 裁剪区域宽度 + * @param integer $h 裁剪区域高度 + * @param integer $x 裁剪区域x坐标 + * @param integer $y 裁剪区域y坐标 + * @param integer $width 图片保存宽度 + * @param integer $height 图片保存高度 + * @return Object 当前图片处理库对象 + */ + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){} + +生成缩略图 + + /** + * @param integer $width 缩略图最大宽度 + * @param integer $height 缩略图最大高度 + * @param integer $type 缩略图裁剪类型 + * @return Object 当前图片处理库对象 + */ + public function thumb($width, $height, $type = THINKIMAGE_THUMB_SCALE){} + +添加水印 + + /** + * @param string $source 水印图片路径 + * @param integer $locate 水印位置 + * @param integer $alpha 水印透明度 + * @return Object 当前图片处理库对象 + */ + public function water($source, $locate = THINKIMAGE_WATER_SOUTHEAST){} + +图像添加文字 + + /** + * @param string $text 添加的文字 + * @param string $font 字体路径 + * @param integer $size 字号 + * @param string $color 文字颜色 + * @param integer $locate 文字写入位置 + * @param integer $offset 文字相对当前位置的偏移量 + * @param integer $angle 文字倾斜角度 + * @return Object 当前图片处理库对象 + */ + public function text($text, $font, $size, $color = '#00000000', + $locate = THINKIMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Input.class.php b/ThinkPHP/Extend/Library/ORG/Util/Input.class.php new file mode 100644 index 0000000..eca0f55 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Input.class.php @@ -0,0 +1,460 @@ + +// +---------------------------------------------------------------------- +// $Id: Input.class.php 2528 2012-01-03 14:58:50Z liu21st $ + +/** 输入数据管理类 + * 使用方法 + * $Input = Input::getInstance(); + * $Input->get('name','md5','0'); + * $Input->session('memberId','','0'); + * + * 下面总结了一些常用的数据处理方法。以下方法无需考虑magic_quotes_gpc的设置。 + * + * 获取数据: + * 如果从$_POST或者$_GET中获取,使用Input::getVar($_POST['field']);,从数据库或者文件就不需要了。 + * 或者直接使用 Input::magicQuotes来消除所有的magic_quotes_gpc转义。 + * + * 存储过程: + * 经过Input::getVar($_POST['field'])获得的数据,就是干净的数据,可以直接保存。 + * 如果要过滤危险的html,可以使用 $html = Input::safeHtml($data); + * + * 页面显示: + * 纯文本显示在网页中,如文章标题$data: $data = Input::forShow($field); + * HTML 在网页中显示,如文章内容:无需处理。 + * 在网页中以源代码方式显示html:$vo = Input::forShow($html); + * 纯文本或者HTML在textarea中进行编辑: $vo = Input::forTarea($value); + * html在标签中使用,如 ,使用 $vo = Input::forTag($value); 或者 $vo = Input::hsc($value); + * + * 特殊使用情况: + * 字符串要在数据库进行搜索: $data = Input::forSearch($field); + */ +class Input { + + private $filter = null; // 输入过滤 + private static $_input = array('get','post','request','env','server','cookie','session','globals','config','lang','call'); + //html标签设置 + public static $htmlTags = array( + 'allow' => 'table|td|th|tr|i|b|u|strong|img|p|br|div|strong|em|ul|ol|li|dl|dd|dt|a', + 'ban' => 'html|head|meta|link|base|basefont|body|bgsound|title|style|script|form|iframe|frame|frameset|applet|id|ilayer|layer|name|script|style|xml', + ); + + static public function getInstance() { + return get_instance_of(__CLASS__); + } + + /** + +---------------------------------------------------------- + * 魔术方法 有不存在的操作的时候执行 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $type 输入数据类型 + * @param array $args 参数 array(key,filter,default) + +---------------------------------------------------------- + * @return mixed + +---------------------------------------------------------- + */ + public function __call($type,$args=array()) { + $type = strtolower(trim($type)); + if(in_array($type,self::$_input,true)) { + switch($type) { + case 'get': $input =& $_GET;break; + case 'post': $input =& $_POST;break; + case 'request': $input =& $_REQUEST;break; + case 'env': $input =& $_ENV;break; + case 'server': $input =& $_SERVER;break; + case 'cookie': $input =& $_COOKIE;break; + case 'session': $input =& $_SESSION;break; + case 'globals': $input =& $GLOBALS;break; + case 'files': $input =& $_FILES;break; + case 'call': $input = 'call';break; + case 'config': $input = C();break; + case 'lang': $input = L();break; + default:return NULL; + } + if('call' === $input) { + // 呼叫其他方式的输入数据 + $callback = array_shift($args); + $params = array_shift($args); + $data = call_user_func_array($callback,$params); + if(count($args)===0) { + return $data; + } + $filter = isset($args[0])?$args[0]:$this->filter; + if(!empty($filter)) { + $data = call_user_func_array($filter,$data); + } + }else{ + if(0==count($args) || empty($args[0]) ) { + return $input; + }elseif(array_key_exists($args[0],$input)) { + // 系统变量 + $data = $input[$args[0]]; + $filter = isset($args[1])?$args[1]:$this->filter; + if(!empty($filter)) { + $data = call_user_func_array($filter,$data); + } + }else{ + // 不存在指定输入 + $data = isset($args[2])?$args[2]:NULL; + } + } + return $data; + } + } + + /** + +---------------------------------------------------------- + * 设置数据过滤方法 + +---------------------------------------------------------- + * @access private + +---------------------------------------------------------- + * @param mixed $filter 过滤方法 + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + public function filter($filter) { + $this->filter = $filter; + return $this; + } + + /** + +---------------------------------------------------------- + * 字符MagicQuote转义过滤 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static public function noGPC() { + if ( get_magic_quotes_gpc() ) { + $_POST = stripslashes_deep($_POST); + $_GET = stripslashes_deep($_GET); + $_COOKIE = stripslashes_deep($_COOKIE); + $_REQUEST= stripslashes_deep($_REQUEST); + } + } + + /** + +---------------------------------------------------------- + * 处理字符串,以便可以正常进行搜索 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function forSearch($string) { + return str_replace( array('%','_'), array('\%','\_'), $string ); + } + + /** + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function forShow($string) { + return self::nl2Br( self::hsc($string) ); + } + + /** + +---------------------------------------------------------- + * 处理纯文本数据,以便在textarea标签中显示 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function forTarea($string) { + return str_ireplace(array(''), array('<textarea>','</textarea>'), $string); + } + + /** + +---------------------------------------------------------- + * 将数据中的单引号和双引号进行转义 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $text 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function forTag($string) { + return str_replace(array('"',"'"), array('"','''), $string); + } + + /** + +---------------------------------------------------------- + * 转换文字中的超链接为可点击连接 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function makeLink($string) { + $validChars = "a-z0-9\/\-_+=.~!%@?#&;:$\|"; + $patterns = array( + "/(^|[^]_a-z0-9-=\"'\/])([a-z]+?):\/\/([{$validChars}]+)/ei", + "/(^|[^]_a-z0-9-=\"'\/])www\.([a-z0-9\-]+)\.([{$validChars}]+)/ei", + "/(^|[^]_a-z0-9-=\"'\/])ftp\.([a-z0-9\-]+)\.([{$validChars}]+)/ei", + "/(^|[^]_a-z0-9-=\"'\/:\.])([a-z0-9\-_\.]+?)@([{$validChars}]+)/ei"); + $replacements = array( + "'\\1\\2://'.Input::truncate( '\\3' ).''", + "'\\1'.Input::truncate( 'www.\\2.\\3' ).''", + "'\\1'.Input::truncate( 'ftp.\\2.\\3' ).''", + "'\\1'.Input::truncate( '\\2@\\3' ).''"); + return preg_replace($patterns, $replacements, $string); + } + + /** + +---------------------------------------------------------- + * 缩略显示字符串 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + * @param int $length 缩略之后的长度 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function truncate($string, $length = '50') { + if ( empty($string) || empty($length) || strlen($string) < $length ) return $string; + $len = floor( $length / 2 ); + $ret = substr($string, 0, $len) . " ... ". substr($string, 5 - $len); + return $ret; + } + + /** + +---------------------------------------------------------- + * 把换行转换为
    标签 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function nl2Br($string) { + return preg_replace("/(\015\012)|(\015)|(\012)/", "
    ", $string); + } + + /** + +---------------------------------------------------------- + * 如果 magic_quotes_gpc 为关闭状态,这个函数可以转义字符串 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function addSlashes($string) { + if (!get_magic_quotes_gpc()) { + $string = addslashes($string); + } + return $string; + } + + /** + +---------------------------------------------------------- + * 从$_POST,$_GET,$_COOKIE,$_REQUEST等数组中获得数据 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function getVar($string) { + return Input::stripSlashes($string); + } + + /** + +---------------------------------------------------------- + * 如果 magic_quotes_gpc 为开启状态,这个函数可以反转义字符串 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function stripSlashes($string) { + if (get_magic_quotes_gpc()) { + $string = stripslashes($string); + } + return $string; + } + + /** + +---------------------------------------------------------- + * 用于在textbox表单中显示html代码 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function hsc($string) { + return preg_replace(array("/&/i", "/ /i"), array('&', '&nbsp;'), htmlspecialchars($string, ENT_QUOTES)); + } + + /** + +---------------------------------------------------------- + * 是hsc()方法的逆操作 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $text 要处理的字符串 + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function undoHsc($text) { + return preg_replace(array("/>/i", "/</i", "/"/i", "/'/i", '/&nbsp;/i'), array(">", "<", "\"", "'", " "), $text); + } + + /** + +---------------------------------------------------------- + * 输出安全的html,用于过滤危险代码 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $text 要处理的字符串 + * @param mixed $allowTags 允许的标签列表,如 table|td|th|td + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function safeHtml($text, $allowTags = null) { + $text = trim($text); + //完全过滤注释 + $text = preg_replace('//','',$text); + //完全过滤动态代码 + $text = preg_replace('/<\?|\?'.'>/','',$text); + //完全过滤js + $text = preg_replace('//','',$text); + + $text = str_replace('[','[',$text); + $text = str_replace(']',']',$text); + $text = str_replace('|','|',$text); + //过滤换行符 + $text = preg_replace('/\r?\n/','',$text); + //br + $text = preg_replace('//i','[br]',$text); + $text = preg_replace('/(\[br\]\s*){10,}/i','[br]',$text); + //过滤危险的属性,如:过滤on事件lang js + while(preg_match('/(<[^><]+)(lang|on|action|background|codebase|dynsrc|lowsrc)[^><]+/i',$text,$mat)){ + $text=str_replace($mat[0],$mat[1],$text); + } + while(preg_match('/(<[^><]+)(window\.|javascript:|js:|about:|file:|document\.|vbs:|cookie)([^><]*)/i',$text,$mat)){ + $text=str_replace($mat[0],$mat[1].$mat[3],$text); + } + if( empty($allowTags) ) { $allowTags = self::$htmlTags['allow']; } + //允许的HTML标签 + $text = preg_replace('/<('.$allowTags.')( [^><\[\]]*)>/i','[\1\2]',$text); + //过滤多余html + if ( empty($banTag) ) { $banTag = self::$htmlTags['ban']; } + $text = preg_replace('/<\/?('.$banTag.')[^><]*>/i','',$text); + //过滤合法的html标签 + while(preg_match('/<([a-z]+)[^><\[\]]*>[^><]*<\/\1>/i',$text,$mat)){ + $text=str_replace($mat[0],str_replace('>',']',str_replace('<','[',$mat[0])),$text); + } + //转换引号 + while(preg_match('/(\[[^\[\]]*=\s*)(\"|\')([^\2=\[\]]+)\2([^\[\]]*\])/i',$text,$mat)){ + $text=str_replace($mat[0],$mat[1].'|'.$mat[3].'|'.$mat[4],$text); + } + //空属性转换 + $text = str_replace('\'\'','||',$text); + $text = str_replace('""','||',$text); + //过滤错误的单个引号 + while(preg_match('/\[[^\[\]]*(\"|\')[^\[\]]*\]/i',$text,$mat)){ + $text=str_replace($mat[0],str_replace($mat[1],'',$mat[0]),$text); + } + //转换其它所有不合法的 < > + $text = str_replace('<','<',$text); + $text = str_replace('>','>',$text); + $text = str_replace('"','"',$text); + //反转换 + $text = str_replace('[','<',$text); + $text = str_replace(']','>',$text); + $text = str_replace('|','"',$text); + //过滤多余空格 + $text = str_replace(' ',' ',$text); + return $text; + } + + /** + +---------------------------------------------------------- + * 删除html标签,得到纯文本。可以处理嵌套的标签 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的html + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function deleteHtmlTags($string) { + while(strstr($string, '>')) { + $currentBeg = strpos($string, '<'); + $currentEnd = strpos($string, '>'); + $tmpStringBeg = @substr($string, 0, $currentBeg); + $tmpStringEnd = @substr($string, $currentEnd + 1, strlen($string)); + $string = $tmpStringBeg.$tmpStringEnd; + } + return $string; + } + + /** + +---------------------------------------------------------- + * 处理文本中的换行 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @param string $string 要处理的字符串 + * @param mixed $br 对换行的处理, + * false:去除换行;true:保留原样;string:替换成string + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static public function nl2($string, $br = '
    ') { + if ($br == false) { + $string = preg_replace("/(\015\012)|(\015)|(\012)/", '', $string); + } elseif ($br != true){ + $string = preg_replace("/(\015\012)|(\015)|(\012)/", $br, $string); + } + return $string; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Page.class.php b/ThinkPHP/Extend/Library/ORG/Util/Page.class.php new file mode 100644 index 0000000..e3b3ce3 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Page.class.php @@ -0,0 +1,154 @@ + +// | lanfengye +// +---------------------------------------------------------------------- + +class Page { + + // 分页栏每页显示的页数 + public $rollPage = 5; + // 页数跳转时要带的参数 + public $parameter ; + // 分页URL地址 + public $url = ''; + // 默认列表每页显示行数 + public $listRows = 20; + // 起始行数 + public $firstRow ; + // 分页总页面数 + protected $totalPages ; + // 总行数 + protected $totalRows ; + // 当前页数 + protected $nowPage ; + // 分页的栏的总页数 + protected $coolPages ; + // 分页显示定制 + protected $config = array('header'=>'条记录','prev'=>'上一页','next'=>'下一页','first'=>'第一页','last'=>'最后一页','theme'=>' %totalRow% %header% %nowPage%/%totalPage% 页 %upPage% %downPage% %first% %prePage% %linkPage% %nextPage% %end%'); + // 默认分页变量名 + protected $varPage; + + /** + * 架构函数 + * @access public + * @param array $totalRows 总的记录数 + * @param array $listRows 每页显示记录数 + * @param array $parameter 分页跳转的参数 + */ + public function __construct($totalRows,$listRows='',$parameter='',$url='') { + $this->totalRows = $totalRows; + $this->parameter = $parameter; + $this->varPage = C('VAR_PAGE') ? C('VAR_PAGE') : 'p' ; + if(!empty($listRows)) { + $this->listRows = intval($listRows); + } + $this->totalPages = ceil($this->totalRows/$this->listRows); //总页数 + $this->coolPages = ceil($this->totalPages/$this->rollPage); + $this->nowPage = !empty($_GET[$this->varPage])?intval($_GET[$this->varPage]):1; + if($this->nowPage<1){ + $this->nowPage = 1; + }elseif(!empty($this->totalPages) && $this->nowPage>$this->totalPages) { + $this->nowPage = $this->totalPages; + } + $this->firstRow = $this->listRows*($this->nowPage-1); + if(!empty($url)) $this->url = $url; + } + + public function setConfig($name,$value) { + if(isset($this->config[$name])) { + $this->config[$name] = $value; + } + } + + /** + * 分页显示输出 + * @access public + */ + public function show() { + if(0 == $this->totalRows) return ''; + $p = $this->varPage; + $nowCoolPage = ceil($this->nowPage/$this->rollPage); + + // 分析分页参数 + if($this->url){ + $depr = C('URL_PATHINFO_DEPR'); + $url = rtrim(U('/'.$this->url,'',false),$depr).$depr.'__PAGE__'; + }else{ + if($this->parameter && is_string($this->parameter)) { + parse_str($this->parameter,$parameter); + }elseif(is_array($this->parameter)){ + $parameter = $this->parameter; + }elseif(empty($this->parameter)){ + unset($_GET[C('VAR_URL_PARAMS')]); + $var = !empty($_POST)?$_POST:$_GET; + if(empty($var)) { + $parameter = array(); + }else{ + $parameter = $var; + } + } + $parameter[$p] = '__PAGE__'; + $url = U('',$parameter); + } + //上下翻页字符串 + $upRow = $this->nowPage-1; + $downRow = $this->nowPage+1; + if ($upRow>0){ + $upPage = "".$this->config['prev'].""; + }else{ + $upPage = ''; + } + + if ($downRow <= $this->totalPages){ + $downPage = "".$this->config['next'].""; + }else{ + $downPage = ''; + } + // << < > >> + if($nowCoolPage == 1){ + $theFirst = ''; + $prePage = ''; + }else{ + $preRow = $this->nowPage-$this->rollPage; + $prePage = "上".$this->rollPage."页"; + $theFirst = "".$this->config['first'].""; + } + if($nowCoolPage == $this->coolPages){ + $nextPage = ''; + $theEnd = ''; + }else{ + $nextRow = $this->nowPage+$this->rollPage; + $theEndRow = $this->totalPages; + $nextPage = "下".$this->rollPage."页"; + $theEnd = "".$this->config['last'].""; + } + // 1 2 3 4 5 + $linkPage = ""; + for($i=1;$i<=$this->rollPage;$i++){ + $page = ($nowCoolPage-1)*$this->rollPage+$i; + if($page!=$this->nowPage){ + if($page<=$this->totalPages){ + $linkPage .= "".$page.""; + }else{ + break; + } + }else{ + if($this->totalPages != 1){ + $linkPage .= "".$page.""; + } + } + } + $pageStr = str_replace( + array('%header%','%nowPage%','%totalRow%','%totalPage%','%upPage%','%downPage%','%first%','%prePage%','%linkPage%','%nextPage%','%end%'), + array($this->config['header'],$this->nowPage,$this->totalRows,$this->totalPages,$upPage,$downPage,$theFirst,$prePage,$linkPage,$nextPage,$theEnd),$this->config['theme']); + return $pageStr; + } + +} diff --git a/ThinkPHP/Extend/Library/ORG/Util/RBAC.class.php b/ThinkPHP/Extend/Library/ORG/Util/RBAC.class.php new file mode 100644 index 0000000..a8f5cfa --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/RBAC.class.php @@ -0,0 +1,292 @@ + +// +---------------------------------------------------------------------- +// $Id: RBAC.class.php 2947 2012-05-13 15:57:48Z liu21st@gmail.com $ + +/** + +------------------------------------------------------------------------------ + * 基于角色的数据库方式验证类 + +------------------------------------------------------------------------------ + * @category ORG + * @package ORG + * @subpackage Util + * @author liu21st + * @version $Id: RBAC.class.php 2947 2012-05-13 15:57:48Z liu21st@gmail.com $ + +------------------------------------------------------------------------------ + */ +// 配置文件增加设置 +// USER_AUTH_ON 是否需要认证 +// USER_AUTH_TYPE 认证类型 +// USER_AUTH_KEY 认证识别号 +// REQUIRE_AUTH_MODULE 需要认证模块 +// NOT_AUTH_MODULE 无需认证模块 +// USER_AUTH_GATEWAY 认证网关 +// RBAC_DB_DSN 数据库连接DSN +// RBAC_ROLE_TABLE 角色表名称 +// RBAC_USER_TABLE 用户表名称 +// RBAC_ACCESS_TABLE 权限表名称 +// RBAC_NODE_TABLE 节点表名称 +/* +-- -------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `think_access` ( + `role_id` smallint(6) unsigned NOT NULL, + `node_id` smallint(6) unsigned NOT NULL, + `level` tinyint(1) NOT NULL, + `module` varchar(50) DEFAULT NULL, + KEY `groupId` (`role_id`), + KEY `nodeId` (`node_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `think_node` ( + `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(20) NOT NULL, + `title` varchar(50) DEFAULT NULL, + `status` tinyint(1) DEFAULT '0', + `remark` varchar(255) DEFAULT NULL, + `sort` smallint(6) unsigned DEFAULT NULL, + `pid` smallint(6) unsigned NOT NULL, + `level` tinyint(1) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `level` (`level`), + KEY `pid` (`pid`), + KEY `status` (`status`), + KEY `name` (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `think_role` ( + `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(20) NOT NULL, + `pid` smallint(6) DEFAULT NULL, + `status` tinyint(1) unsigned DEFAULT NULL, + `remark` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `pid` (`pid`), + KEY `status` (`status`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; + +CREATE TABLE IF NOT EXISTS `think_role_user` ( + `role_id` mediumint(9) unsigned DEFAULT NULL, + `user_id` char(32) DEFAULT NULL, + KEY `group_id` (`role_id`), + KEY `user_id` (`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +*/ +class RBAC { + // 认证方法 + static public function authenticate($map,$model='') { + if(empty($model)) $model = C('USER_AUTH_MODEL'); + //使用给定的Map进行认证 + return M($model)->where($map)->find(); + } + + //用于检测用户权限的方法,并保存到Session中 + static function saveAccessList($authId=null) { + if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')]; + // 如果使用普通权限模式,保存当前用户的访问权限列表 + // 对管理员开发所有权限 + if(C('USER_AUTH_TYPE') !=2 && !$_SESSION[C('ADMIN_AUTH_KEY')] ) + $_SESSION['_ACCESS_LIST'] = RBAC::getAccessList($authId); + return ; + } + + // 取得模块的所属记录访问权限列表 返回有权限的记录ID数组 + static function getRecordAccessList($authId=null,$module='') { + if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')]; + if(empty($module)) $module = MODULE_NAME; + //获取权限访问列表 + $accessList = RBAC::getModuleAccessList($authId,$module); + return $accessList; + } + + //检查当前操作是否需要认证 + static function checkAccess() { + //如果项目要求认证,并且当前模块需要认证,则进行权限认证 + if( C('USER_AUTH_ON') ){ + $_module = array(); + $_action = array(); + if("" != C('REQUIRE_AUTH_MODULE')) { + //需要认证的模块 + $_module['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_MODULE'))); + }else { + //无需认证的模块 + $_module['no'] = explode(',',strtoupper(C('NOT_AUTH_MODULE'))); + } + //检查当前模块是否需要认证 + if((!empty($_module['no']) && !in_array(strtoupper(MODULE_NAME),$_module['no'])) || (!empty($_module['yes']) && in_array(strtoupper(MODULE_NAME),$_module['yes']))) { + if("" != C('REQUIRE_AUTH_ACTION')) { + //需要认证的操作 + $_action['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_ACTION'))); + }else { + //无需认证的操作 + $_action['no'] = explode(',',strtoupper(C('NOT_AUTH_ACTION'))); + } + //检查当前操作是否需要认证 + if((!empty($_action['no']) && !in_array(strtoupper(ACTION_NAME),$_action['no'])) || (!empty($_action['yes']) && in_array(strtoupper(ACTION_NAME),$_action['yes']))) { + return true; + }else { + return false; + } + }else { + return false; + } + } + return false; + } + + // 登录检查 + static public function checkLogin() { + //检查当前操作是否需要认证 + if(RBAC::checkAccess()) { + //检查认证识别号 + if(!$_SESSION[C('USER_AUTH_KEY')]) { + if(C('GUEST_AUTH_ON')) { + // 开启游客授权访问 + if(!isset($_SESSION['_ACCESS_LIST'])) + // 保存游客权限 + RBAC::saveAccessList(C('GUEST_AUTH_ID')); + }else{ + // 禁止游客访问跳转到认证网关 + redirect(PHP_FILE.C('USER_AUTH_GATEWAY')); + } + } + } + return true; + } + + //权限认证的过滤器方法 + static public function AccessDecision($appName=APP_NAME) { + //检查是否需要认证 + if(RBAC::checkAccess()) { + //存在认证识别号,则进行进一步的访问决策 + $accessGuid = md5($appName.MODULE_NAME.ACTION_NAME); + if(empty($_SESSION[C('ADMIN_AUTH_KEY')])) { + if(C('USER_AUTH_TYPE')==2) { + //加强验证和即时验证模式 更加安全 后台权限修改可以即时生效 + //通过数据库进行访问检查 + $accessList = RBAC::getAccessList($_SESSION[C('USER_AUTH_KEY')]); + }else { + // 如果是管理员或者当前操作已经认证过,无需再次认证 + if( $_SESSION[$accessGuid]) { + return true; + } + //登录验证模式,比较登录后保存的权限访问列表 + $accessList = $_SESSION['_ACCESS_LIST']; + } + //判断是否为组件化模式,如果是,验证其全模块名 + $module = defined('P_MODULE_NAME')? P_MODULE_NAME : MODULE_NAME; + if(!isset($accessList[strtoupper($appName)][strtoupper($module)][strtoupper(ACTION_NAME)])) { + $_SESSION[$accessGuid] = false; + return false; + } + else { + $_SESSION[$accessGuid] = true; + } + }else{ + //管理员无需认证 + return true; + } + } + return true; + } + + /** + +---------------------------------------------------------- + * 取得当前认证号的所有权限列表 + +---------------------------------------------------------- + * @param integer $authId 用户ID + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + */ + static public function getAccessList($authId) { + // Db方式权限数据 + $db = Db::getInstance(C('RBAC_DB_DSN')); + $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'),'node'=>C('RBAC_NODE_TABLE')); + $sql = "select node.id,node.name from ". + $table['role']." as role,". + $table['user']." as user,". + $table['access']." as access ,". + $table['node']." as node ". + "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=1 and node.status=1"; + $apps = $db->query($sql); + $access = array(); + foreach($apps as $key=>$app) { + $appId = $app['id']; + $appName = $app['name']; + // 读取项目的模块权限 + $access[strtoupper($appName)] = array(); + $sql = "select node.id,node.name from ". + $table['role']." as role,". + $table['user']." as user,". + $table['access']." as access ,". + $table['node']." as node ". + "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=2 and node.pid={$appId} and node.status=1"; + $modules = $db->query($sql); + // 判断是否存在公共模块的权限 + $publicAction = array(); + foreach($modules as $key=>$module) { + $moduleId = $module['id']; + $moduleName = $module['name']; + if('PUBLIC'== strtoupper($moduleName)) { + $sql = "select node.id,node.name from ". + $table['role']." as role,". + $table['user']." as user,". + $table['access']." as access ,". + $table['node']." as node ". + "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=3 and node.pid={$moduleId} and node.status=1"; + $rs = $db->query($sql); + foreach ($rs as $a){ + $publicAction[$a['name']] = $a['id']; + } + unset($modules[$key]); + break; + } + } + // 依次读取模块的操作权限 + foreach($modules as $key=>$module) { + $moduleId = $module['id']; + $moduleName = $module['name']; + $sql = "select node.id,node.name from ". + $table['role']." as role,". + $table['user']." as user,". + $table['access']." as access ,". + $table['node']." as node ". + "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=3 and node.pid={$moduleId} and node.status=1"; + $rs = $db->query($sql); + $action = array(); + foreach ($rs as $a){ + $action[$a['name']] = $a['id']; + } + // 和公共模块的操作权限合并 + $action += $publicAction; + $access[strtoupper($appName)][strtoupper($moduleName)] = array_change_key_case($action,CASE_UPPER); + } + } + return $access; + } + + // 读取模块所属的记录访问权限 + static public function getModuleAccessList($authId,$module) { + // Db方式 + $db = Db::getInstance(C('RBAC_DB_DSN')); + $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE')); + $sql = "select access.node_id from ". + $table['role']." as role,". + $table['user']." as user,". + $table['access']." as access ". + "where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.module='{$module}' and access.status=1"; + $rs = $db->query($sql); + $access = array(); + foreach ($rs as $node){ + $access[] = $node['node_id']; + } + return $access; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Session.class.php b/ThinkPHP/Extend/Library/ORG/Util/Session.class.php new file mode 100644 index 0000000..edae801 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Session.class.php @@ -0,0 +1,628 @@ + +// +---------------------------------------------------------------------- +// $Id: Session.class.php 2702 2012-02-02 12:35:01Z liu21st $ + +define("HTTP_SESSION_STARTED", 1); +define("HTTP_SESSION_CONTINUED", 2); + +/** + +------------------------------------------------------------------------------ + * Session管理类 + +------------------------------------------------------------------------------ + * @category Think + * @package Think + * @subpackage Util + * @author liu21st + * @version $Id: Session.class.php 2702 2012-02-02 12:35:01Z liu21st $ + +------------------------------------------------------------------------------ + */ +class Session { + + /** + +---------------------------------------------------------- + * 启动Session + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function start() { + session_start(); + if (!isset($_SESSION['__HTTP_Session_Info'])) { + $_SESSION['__HTTP_Session_Info'] = HTTP_SESSION_STARTED; + } else { + $_SESSION['__HTTP_Session_Info'] = HTTP_SESSION_CONTINUED; + } + Session::setExpire(C('SESSION_EXPIRE')); + } + + /** + +---------------------------------------------------------- + * 暂停Session + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function pause() { + session_write_close(); + } + + /** + +---------------------------------------------------------- + * 清空Session + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function clearLocal() { + $local = Session::localName(); + unset($_SESSION[$local]); + } + + /** + +---------------------------------------------------------- + * 清空Session + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function clear() { + $_SESSION = array(); + } + + /** + +---------------------------------------------------------- + * 销毁Session + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function destroy() { + unset($_SESSION); + session_destroy(); + } + + /** + +---------------------------------------------------------- + * 检测SessionID + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function detectID() { + if(session_id()!='') { + return session_id(); + } + if (Session::useCookies()) { + if (isset($_COOKIE[Session::name()])) { + return $_COOKIE[Session::name()]; + } + } else { + if (isset($_GET[Session::name()])) { + return $_GET[Session::name()]; + } + if (isset($_POST[Session::name()])) { + return $_POST[Session::name()]; + } + } + return null; + } + + /** + +---------------------------------------------------------- + * 设置或者获取当前Session name + +---------------------------------------------------------- + * @param string $name session名称 + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return string 返回之前的Session name + +---------------------------------------------------------- + */ + static function name($name = null) { + return isset($name) ? session_name($name) : session_name(); + } + + /** + +---------------------------------------------------------- + * 设置或者获取当前SessionID + +---------------------------------------------------------- + * @param string $id sessionID + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void 返回之前的sessionID + +---------------------------------------------------------- + */ + static function id($id = null) { + return isset($id) ? session_id($id) : session_id(); + } + + /** + +---------------------------------------------------------- + * 设置或者获取当前Session保存路径 + +---------------------------------------------------------- + * @param string $path 保存路径名 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function path($path = null) { + return !empty($path)? session_save_path($path):session_save_path(); + } + + /** + +---------------------------------------------------------- + * 设置Session 过期时间 + +---------------------------------------------------------- + * @param integer $time 过期时间 + * @param boolean $add 是否为增加时间 + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function setExpire($time, $add = false) { + if ($add) { + if (!isset($_SESSION['__HTTP_Session_Expire_TS'])) { + $_SESSION['__HTTP_Session_Expire_TS'] = time() + $time; + } + + // update session.gc_maxlifetime + $currentGcMaxLifetime = Session::setGcMaxLifetime(null); + Session::setGcMaxLifetime($currentGcMaxLifetime + $time); + + } elseif (!isset($_SESSION['__HTTP_Session_Expire_TS'])) { + $_SESSION['__HTTP_Session_Expire_TS'] = $time; + } + } + + /** + +---------------------------------------------------------- + * 设置Session 闲置时间 + +---------------------------------------------------------- + * @param integer $time 闲置时间 + * @param boolean $add 是否为增加时间 + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function setIdle($time, $add = false) { + if ($add) { + $_SESSION['__HTTP_Session_Idle'] = $time; + } else { + $_SESSION['__HTTP_Session_Idle'] = $time - time(); + } + } + + /** + +---------------------------------------------------------- + * 取得Session 有效时间 + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function sessionValidThru() { + if (!isset($_SESSION['__HTTP_Session_Idle_TS']) || !isset($_SESSION['__HTTP_Session_Idle'])) { + return 0; + } else { + return $_SESSION['__HTTP_Session_Idle_TS'] + $_SESSION['__HTTP_Session_Idle']; + } + } + + /** + +---------------------------------------------------------- + * 检查Session 是否过期 + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function isExpired() { + if (isset($_SESSION['__HTTP_Session_Expire_TS']) && $_SESSION['__HTTP_Session_Expire_TS'] < time()) { + return true; + } else { + return false; + } + } + + /** + +---------------------------------------------------------- + * 检查Session 是否闲置 + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function isIdle() { + if (isset($_SESSION['__HTTP_Session_Idle_TS']) && (($_SESSION['__HTTP_Session_Idle_TS'] + $_SESSION['__HTTP_Session_Idle']) < time())) { + return true; + } else { + return false; + } + } + + /** + +---------------------------------------------------------- + * 更新Session 闲置时间 + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return void + +---------------------------------------------------------- + */ + static function updateIdle() { + $_SESSION['__HTTP_Session_Idle_TS'] = time(); + } + + /** + +---------------------------------------------------------- + * 设置Session 对象反序列化时候的回调函数 + * 返回之前设置 + +---------------------------------------------------------- + * @param string $callback 回调函数方法名 + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function setCallback($callback = null) { + $return = ini_get('unserialize_callback_func'); + if (!empty($callback)) { + ini_set('unserialize_callback_func',$callback); + } + return $return; + } + + /** + +---------------------------------------------------------- + * 设置Session 是否使用cookie + * 返回之前设置 + +---------------------------------------------------------- + * @param boolean $useCookies 是否使用cookie + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function useCookies($useCookies = null) { + $return = ini_get('session.use_cookies') ? true : false; + if (isset($useCookies)) { + ini_set('session.use_cookies', $useCookies ? 1 : 0); + } + return $return; + } + + /** + +---------------------------------------------------------- + * 检查Session 是否新建 + +---------------------------------------------------------- + * @param boolean $useCookies 是否使用cookie + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function isNew() { + return !isset($_SESSION['__HTTP_Session_Info']) || + $_SESSION['__HTTP_Session_Info'] == HTTP_SESSION_STARTED; + } + + + /** + +---------------------------------------------------------- + * 取得当前项目的Session 值 + * 返回之前设置 + +---------------------------------------------------------- + * @param string $name + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function getLocal($name) { + $local = Session::localName(); + if (!is_array($_SESSION[$local])) { + $_SESSION[$local] = array(); + } + return $_SESSION[$local][$name]; + } + + /** + +---------------------------------------------------------- + * 取得当前项目的Session 值 + * 返回之前设置 + +---------------------------------------------------------- + * @param string $name + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function get($name) { + if(isset($_SESSION[$name])) { + return $_SESSION[$name]; + }else { + return null; + } + } + + /** + +---------------------------------------------------------- + * 设置当前项目的Session 值 + * 返回之前设置 + +---------------------------------------------------------- + * @param string $name + * @param mixed $value + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function setLocal($name, $value) { + $local = Session::localName(); + if (!is_array($_SESSION[$local])) { + $_SESSION[$local] = array(); + } + if (null === $value) { + unset($_SESSION[$local][$name]); + } else { + $_SESSION[$local][$name] = $value; + } + return; + } + + /** + +---------------------------------------------------------- + * 设置当前项目的Session 值 + * 返回之前设置 + +---------------------------------------------------------- + * @param string $name + * @param mixed $value + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function set($name, $value) { + if (null === $value) { + unset($_SESSION[$name]); + } else { + $_SESSION[$name] = $value; + } + return ; + } + + /** + +---------------------------------------------------------- + * 检查Session 值是否已经设置 + +---------------------------------------------------------- + * @param string $name + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function is_setLocal($name) { + $local = Session::localName(); + return isset($_SESSION[$local][$name]); + } + + /** + +---------------------------------------------------------- + * 检查Session 值是否已经设置 + +---------------------------------------------------------- + * @param string $name + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function is_set($name) { + return isset($_SESSION[$name]); + } + + /** + +---------------------------------------------------------- + * 设置或者获取 Session localname + +---------------------------------------------------------- + * @param string $name + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function localName($name = null) { + $return = (isset($GLOBALS['__HTTP_Session_Localname'])) ? $GLOBALS['__HTTP_Session_Localname'] : null; + if (!empty($name)) { + $GLOBALS['__HTTP_Session_Localname'] = md5($name); + } + return $return; + } + + /** + +---------------------------------------------------------- + * Session 初始化 + +---------------------------------------------------------- + * @static + * @access private + +---------------------------------------------------------- + * @return boolean + +---------------------------------------------------------- + */ + static function _init() { + ini_set('session.auto_start', 0); + if (is_null(Session::detectID())) { + Session::id(uniqid(dechex(mt_rand()))); + } + // 设置Session有效域名 + Session::setCookieDomain(C('COOKIE_DOMAIN')); + //设置当前项目运行脚本作为Session本地名 + Session::localName(APP_NAME); + Session::name(C('SESSION_NAME')); + Session::path(C('SESSION_PATH')); + Session::setCallback(C('SESSION_CALLBACK')); + } + + /** + +---------------------------------------------------------- + * 设置Session use_trans_sid + * 返回之前设置 + +---------------------------------------------------------- + * @param string $useTransSID + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function useTransSID($useTransSID = null) { + $return = ini_get('session.use_trans_sid') ? true : false; + if (isset($useTransSID)) { + ini_set('session.use_trans_sid', $useTransSID ? 1 : 0); + } + return $return; + } + + /** + +---------------------------------------------------------- + * 设置Session cookie_domain + * 返回之前设置 + +---------------------------------------------------------- + * @param string $sessionDomain + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function setCookieDomain($sessionDomain = null) { + $return = ini_get('session.cookie_domain'); + if(!empty($sessionDomain)) { + ini_set('session.cookie_domain', $sessionDomain);//跨域访问Session + } + return $return; + } + + + /** + +---------------------------------------------------------- + * 设置Session gc_maxlifetime值 + * 返回之前设置 + +---------------------------------------------------------- + * @param string $gc_maxlifetime + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function setGcMaxLifetime($gcMaxLifetime = null) { + $return = ini_get('session.gc_maxlifetime'); + if (isset($gcMaxLifetime) && is_int($gcMaxLifetime) && $gcMaxLifetime >= 1) { + ini_set('session.gc_maxlifetime', $gcMaxLifetime); + } + return $return; + } + + /** + +---------------------------------------------------------- + * 设置Session gc_probability 值 + * 返回之前设置 + +---------------------------------------------------------- + * @param string $gc_maxlifetime + +---------------------------------------------------------- + * @static + * @access public + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function setGcProbability($gcProbability = null) { + $return = ini_get('session.gc_probability'); + if (isset($gcProbability) && is_int($gcProbability) && $gcProbability >= 1 && $gcProbability <= 100) { + ini_set('session.gc_probability', $gcProbability); + } + return $return; + } + + /** + +---------------------------------------------------------- + * 当前Session文件名 + +---------------------------------------------------------- + * @access public + +---------------------------------------------------------- + * @return string + +---------------------------------------------------------- + */ + static function getFilename() { + return Session::path().'/sess_'.session_id(); + } + +}//类定义结束 +Session::_init(); \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Socket.class.php b/ThinkPHP/Extend/Library/ORG/Util/Socket.class.php new file mode 100644 index 0000000..8935326 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Socket.class.php @@ -0,0 +1,97 @@ + +// +---------------------------------------------------------------------- + +class Socket { + protected $_config = array( + 'persistent' => false, + 'host' => 'localhost', + 'protocol' => 'tcp', + 'port' => 80, + 'timeout' => 30 + ); + + public $config = array(); + public $connection = null; + public $connected = false; + public $error = array(); + + public function __construct($config = array()) { + $this->config = array_merge($this->_config,$config); + if (!is_numeric($this->config['protocol'])) { + $this->config['protocol'] = getprotobyname($this->config['protocol']); + } + } + + public function connect() { + if ($this->connection != null) { + $this->disconnect(); + } + + if ($this->config['persistent'] == true) { + $tmp = null; + $this->connection = @pfsockopen($this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']); + } else { + $this->connection = fsockopen($this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']); + } + + if (!empty($errNum) || !empty($errStr)) { + $this->error($errStr, $errNum); + } + + $this->connected = is_resource($this->connection); + + return $this->connected; + } + + public function error() { + } + + public function write($data) { + if (!$this->connected) { + if (!$this->connect()) { + return false; + } + } + return fwrite($this->connection, $data, strlen($data)); + } + + public function read($length=1024) { + if (!$this->connected) { + if (!$this->connect()) { + return false; + } + } + + if (!feof($this->connection)) { + return fread($this->connection, $length); + } else { + return false; + } + } + + public function disconnect() { + if (!is_resource($this->connection)) { + $this->connected = false; + return true; + } + $this->connected = !fclose($this->connection); + + if (!$this->connected) { + $this->connection = null; + } + return !$this->connected; + } + + public function __destruct() { + $this->disconnect(); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Library/ORG/Util/Stack.class.php b/ThinkPHP/Extend/Library/ORG/Util/Stack.class.php new file mode 100644 index 0000000..6183819 --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/Stack.class.php @@ -0,0 +1,51 @@ + +// +---------------------------------------------------------------------- +import("ORG.Util.ArrayList"); + +/** + * Stack实现类 + * @category ORG + * @package ORG + * @subpackage Util + * @author liu21st + */ +class Stack extends ArrayList { + + /** + * 架构函数 + * @access public + * @param array $values 初始化数组元素 + */ + public function __construct($values = array()) { + parent::__construct($values); + } + + /** + * 将堆栈的内部指针指向第一个单元 + * @access public + * @return mixed + */ + public function peek() { + return reset($this->toArray()); + } + + /** + * 元素进栈 + * @access public + * @param mixed $value + * @return mixed + */ + public function push($value) { + $this->add($value); + return $value; + } + +} diff --git a/ThinkPHP/Extend/Library/ORG/Util/String.class.php b/ThinkPHP/Extend/Library/ORG/Util/String.class.php new file mode 100644 index 0000000..7be70ae --- /dev/null +++ b/ThinkPHP/Extend/Library/ORG/Util/String.class.php @@ -0,0 +1,248 @@ + +// +---------------------------------------------------------------------- + +class String { + + /** + * 生成UUID 单机使用 + * @access public + * @return string + */ + static public function uuid() { + $charid = md5(uniqid(mt_rand(), true)); + $hyphen = chr(45);// "-" + $uuid = chr(123)// "{" + .substr($charid, 0, 8).$hyphen + .substr($charid, 8, 4).$hyphen + .substr($charid,12, 4).$hyphen + .substr($charid,16, 4).$hyphen + .substr($charid,20,12) + .chr(125);// "}" + return $uuid; + } + + /** + * 生成Guid主键 + * @return Boolean + */ + static public function keyGen() { + return str_replace('-','',substr(String::uuid(),1,-1)); + } + + /** + * 检查字符串是否是UTF8编码 + * @param string $string 字符串 + * @return Boolean + */ + static public function isUtf8($str) { + $c=0; $b=0; + $bits=0; + $len=strlen($str); + for($i=0; $i<$len; $i++){ + $c=ord($str[$i]); + if($c > 128){ + if(($c >= 254)) return false; + elseif($c >= 252) $bits=6; + elseif($c >= 248) $bits=5; + elseif($c >= 240) $bits=4; + elseif($c >= 224) $bits=3; + elseif($c >= 192) $bits=2; + else return false; + if(($i+$bits) > $len) return false; + while($bits > 1){ + $i++; + $b=ord($str[$i]); + if($b < 128 || $b > 191) return false; + $bits--; + } + } + } + return true; + } + + /** + * 字符串截取,支持中文和其他编码 + * @static + * @access public + * @param string $str 需要转换的字符串 + * @param string $start 开始位置 + * @param string $length 截取长度 + * @param string $charset 编码格式 + * @param string $suffix 截断显示字符 + * @return string + */ + static public function msubstr($str, $start=0, $length, $charset="utf-8", $suffix=true) { + if(function_exists("mb_substr")) + $slice = mb_substr($str, $start, $length, $charset); + elseif(function_exists('iconv_substr')) { + $slice = iconv_substr($str,$start,$length,$charset); + }else{ + $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/"; + $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/"; + $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/"; + $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/"; + preg_match_all($re[$charset], $str, $match); + $slice = join("",array_slice($match[0], $start, $length)); + } + return $suffix ? $slice.'...' : $slice; + } + + /** + * 产生随机字串,可用来自动生成密码 + * 默认长度6位 字母和数字混合 支持中文 + * @param string $len 长度 + * @param string $type 字串类型 + * 0 字母 1 数字 其它 混合 + * @param string $addChars 额外字符 + * @return string + */ + static public function randString($len=6,$type='',$addChars='') { + $str =''; + switch($type) { + case 0: + $chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.$addChars; + break; + case 1: + $chars= str_repeat('0123456789',3); + break; + case 2: + $chars='ABCDEFGHIJKLMNOPQRSTUVWXYZ'.$addChars; + break; + case 3: + $chars='abcdefghijklmnopqrstuvwxyz'.$addChars; + break; + case 4: + $chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借".$addChars; + break; + default : + // 默认去掉了容易混淆的字符oOLl和数字01,要添加请使用addChars参数 + $chars='ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789'.$addChars; + break; + } + if($len>10 ) {//位数过长重复字符串一定次数 + $chars= $type==1? str_repeat($chars,$len) : str_repeat($chars,5); + } + if($type!=4) { + $chars = str_shuffle($chars); + $str = substr($chars,0,$len); + }else{ + // 中文随机字 + for($i=0;$i<$len;$i++){ + $str.= self::msubstr($chars, floor(mt_rand(0,mb_strlen($chars,'utf-8')-1)),1,'utf-8',false); + } + } + return $str; + } + + /** + * 生成一定数量的随机数,并且不重复 + * @param integer $number 数量 + * @param string $len 长度 + * @param string $type 字串类型 + * 0 字母 1 数字 其它 混合 + * @return string + */ + static public function buildCountRand ($number,$length=4,$mode=1) { + if($mode==1 && $length $val) { + $_key = self::autoCharset($key, $from, $to); + $string[$_key] = self::autoCharset($val, $from, $to); + if ($key != $_key) + unset($string[$key]); + } + return $string; + } + else { + return $string; + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Amf/Action.class.php b/ThinkPHP/Extend/Mode/Amf/Action.class.php new file mode 100644 index 0000000..7d35f8c --- /dev/null +++ b/ThinkPHP/Extend/Mode/Amf/Action.class.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP AMF模式Action控制器基类 + */ +abstract class Action { + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $parms 参数 + * @return mixed + */ + public function __call($method,$parms) { + // 如果定义了_empty操作 则调用 + if(method_exists($this,'_empty')) { + $this->_empty($method,$parms); + } + } + +}//类定义结束 +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Amf/App.class.php b/ThinkPHP/Extend/Mode/Amf/App.class.php new file mode 100644 index 0000000..3fed094 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Amf/App.class.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP AMF模式应用程序类 + */ +class App { + + /** + * 应用程序初始化 + * @access public + * @return void + */ + static public function run() { + + //导入类库 + Vendor('Zend.Amf.Server'); + //实例化AMF + $server = new Zend_Amf_Server(); + $actions = explode(',',C('APP_AMF_ACTIONS')); + foreach ($actions as $action) + $server -> setClass($action.'Action'); + echo $server -> handle(); + + // 保存日志记录 + if(C('LOG_RECORD')) Log::save(); + return ; + } + +}; \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Amf/Db.class.php b/ThinkPHP/Extend/Mode/Amf/Db.class.php new file mode 100644 index 0000000..a2b5136 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Amf/Db.class.php @@ -0,0 +1,806 @@ + +// +---------------------------------------------------------------------- + +define('CLIENT_MULTI_RESULTS', 131072); +/** + * ThinkPHP AMF模式数据库中间层实现类 只支持Mysql + */ +class Db { + + static private $_instance = null; + // 是否自动释放查询结果 + protected $autoFree = false; + // 是否显示调试信息 如果启用会在日志文件记录sql语句 + public $debug = false; + // 是否使用永久连接 + protected $pconnect = false; + // 当前SQL指令 + protected $queryStr = ''; + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 当前连接ID + protected $linkID = null; + // 当前查询ID + protected $queryID = null; + // 是否已经连接数据库 + protected $connected = false; + // 数据库连接参数配置 + protected $config = ''; + // 数据库表达式 + protected $comparison = array('eq'=>'=','neq'=>'!=','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE'); + // 查询表达式 + protected $selectSql = 'SELECT%DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%'; + /** + * 架构函数 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysql') ) { + throw_exception(L('_NOT_SUPPERT_').':mysql'); + } + $this->config = $this->parseConfig($config); + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect() { + if(!$this->connected) { + $config = $this->config; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); + if($this->pconnect) { + $this->linkID = mysql_pconnect( $host, $config['username'], $config['password'],CLIENT_MULTI_RESULTS); + }else{ + $this->linkID = mysql_connect( $host, $config['username'], $config['password'],true,CLIENT_MULTI_RESULTS); + } + if ( !$this->linkID || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID)) ) { + throw_exception(mysql_error()); + } + $dbVersion = mysql_get_server_info($this->linkID); + if ($dbVersion >= "4.1") { + //使用UTF8存取数据库 需要mysql 4.1.0以上支持 + mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID); + } + //设置 sql_model + if($dbVersion >'5.0.1'){ + mysql_query("SET sql_mode=''",$this->linkID); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + unset($this->config); + } + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mysql_free_result($this->queryID); + $this->queryID = 0; + } + + /** + * 执行查询 主要针对 SELECT, SHOW 等指令 + * 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + * @throws ThinkExecption + */ + public function query($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mysql_query($this->queryStr, $this->linkID); + $this->debug(); + if ( !$this->queryID ) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 针对 INSERT, UPDATE 以及DELETE + * @access public + * @param string $str sql指令 + * @return integer + * @throws ThinkExecption + */ + public function execute($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = mysql_query($this->queryStr, $this->linkID) ; + $this->debug(); + if ( false === $result) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_affected_rows($this->linkID); + $this->lastInsID = mysql_insert_id($this->linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + * @throws ThinkExecption + */ + public function startTrans() { + $this->connect(true); + if ( !$this->linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mysql_query('START TRANSACTION', $this->linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function commit() + { + if ($this->transTimes > 0) { + $result = mysql_query('COMMIT', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function rollback() + { + if ($this->transTimes > 0) { + $result = mysql_query('ROLLBACK', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access public + * @return array + * @throws ThinkExecption + */ + public function getAll() { + if ( !$this->queryID ) { + throw_exception($this->error()); + return false; + } + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mysql_fetch_assoc($this->queryID)){ + $result[] = $row; + } + mysql_data_seek($this->queryID,0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query('SHOW COLUMNS FROM '.$tableName); + $info = array(); + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + if(!empty($dbName)) { + $sql = 'SHOW TABLES FROM '.$dbName; + }else{ + $sql = 'SHOW TABLES '; + } + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + * @throws ThinkExecption + */ + public function close() { + if (!empty($this->queryID)) + mysql_free_result($this->queryID); + if ($this->linkID && !mysql_close($this->linkID)){ + throw_exception($this->error()); + } + $this->linkID = 0; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mysql_error($this->linkID); + if($this->queryStr!=''){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escape_string($str) { + return mysql_escape_string($str); + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() + { + // 关闭连接 + $this->close(); + } + + /** + * 取得数据库类实例 + * @static + * @access public + * @return mixed 返回数据库驱动类 + */ + public static function getInstance($db_config='') + { + if ( self::$_instance==null ){ + self::$_instance = new Db($db_config); + } + return self::$_instance; + } + + /** + * 分析数据库配置信息,支持数组和DSN + * @access private + * @param mixed $db_config 数据库配置信息 + * @return string + */ + private function parseConfig($db_config='') { + if ( !empty($db_config) && is_string($db_config)) { + // 如果DSN字符串则进行解析 + $db_config = $this->parseDSN($db_config); + }else if(empty($db_config)){ + // 如果配置为空,读取配置文件设置 + $db_config = array ( + 'dbms' => C('DB_TYPE'), + 'username' => C('DB_USER'), + 'password' => C('DB_PWD'), + 'hostname' => C('DB_HOST'), + 'hostport' => C('DB_PORT'), + 'database' => C('DB_NAME'), + 'dsn' => C('DB_DSN'), + 'params' => C('DB_PARAMS'), + ); + } + return $db_config; + } + + /** + * DSN解析 + * 格式: mysql://username:passwd@localhost:3306/DbName + * @static + * @access public + * @param string $dsnStr + * @return array + */ + public function parseDSN($dsnStr) + { + if( empty($dsnStr) ){return false;} + $info = parse_url($dsnStr); + if($info['scheme']){ + $dsn = array( + 'dbms' => $info['scheme'], + 'username' => isset($info['user']) ? $info['user'] : '', + 'password' => isset($info['pass']) ? $info['pass'] : '', + 'hostname' => isset($info['host']) ? $info['host'] : '', + 'hostport' => isset($info['port']) ? $info['port'] : '', + 'database' => isset($info['path']) ? substr($info['path'],1) : '' + ); + }else { + preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); + $dsn = array ( + 'dbms' => $matches[1], + 'username' => $matches[2], + 'password' => $matches[3], + 'hostname' => $matches[4], + 'hostport' => $matches[5], + 'database' => $matches[6] + ); + } + return $dsn; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + // 记录操作结束时间 + if ( $this->debug ) { + G('queryEndTime'); + Log::record($this->queryStr." [ RunTime:".G('queryStartTime','queryEndTime',6)."s ]",Log::SQL); + } + } + + /** + * 设置锁机制 + * @access protected + * @return string + */ + protected function parseLock($lock=false) { + if(!$lock) return ''; + if('ORACLE' == $this->dbType) { + return ' FOR UPDATE NOWAIT '; + } + return ' FOR UPDATE '; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) // 过滤非标量数据 + $set[] = $this->parseKey($key).'='.$value; + } + return ' SET '.implode(',',$set); + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = '\''.$this->escape_string($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escape_string($value[1]); + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return string + */ + protected function parseField($fields) { + if(is_array($fields)) { + // 完善数组方式传字段名的支持 + // 支持 'field1'=>'field2' 这样的字段别名定义 + $array = array(); + foreach ($fields as $key=>$field){ + if(!is_numeric($key)) + $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); + else + $array[] = $this->parseKey($field); + } + $fieldsStr = implode(',', $array); + }elseif(is_string($fields) && !empty($fields)) { + $fieldsStr = $this->parseKey($fields); + }else{ + $fieldsStr = '*'; + } + return $fieldsStr; + } + + /** + * table分析 + * @access protected + * @param mixed $table + * @return string + */ + protected function parseTable($tables) { + if(is_string($tables)) + $tables = explode(',',$tables); + array_walk($tables, array(&$this, 'parseKey')); + return implode(',',$tables); + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return string + */ + protected function parseWhere($where) { + $whereStr = ''; + if(is_string($where)) { + // 直接使用字符串条件 + $whereStr = $where; + }else{ // 使用数组条件表达式 + if(isset($where['_logic'])) { + // 定义逻辑运算规则 例如 OR XOR AND NOT + $operate = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + // 默认进行 AND 运算 + $operate = ' AND '; + } + foreach ($where as $key=>$val){ + $whereStr .= "( "; + if(0===strpos($key,'_')) { + // 解析特殊条件表达式 + $whereStr .= $this->parseThinkWhere($key,$val); + }else{ + $key = $this->parseKey($key); + if(is_array($val)) { + if(is_string($val[0])) { + if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|NOTLIKE|LIKE)$/i',$val[0])) { // 比较运算 + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + }elseif('exp'==strtolower($val[0])){ // 使用表达式 + $whereStr .= ' ('.$key.' '.$val[1].') '; + }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 + $zone = is_array($val[1])? implode(',',$this->parseValue($val[1])):$val[1]; + $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; + }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $whereStr .= ' ('.$key.' BETWEEN '.$data[0].' AND '.$data[1].' )'; + }else{ + throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]); + } + }else { + $count = count($val); + if(in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) { + $rule = strtoupper(trim($val[$count-1])); + $count = $count -1; + }else{ + $rule = 'AND'; + } + for($i=0;$i<$count;$i++) { + $data = is_array($val[$i])?$val[$i][1]:$val[$i]; + if('exp'==strtolower($val[$i][0])) { + $whereStr .= '('.$key.' '.$data.') '.$rule.' '; + }else{ + $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; + $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' '; + } + } + $whereStr = substr($whereStr,0,-4); + } + }else { + //对字符串类型字段采用模糊匹配 + if(C('LIKE_MATCH_FIELDS') && preg_match('/('.C('LIKE_MATCH_FIELDS').')/i',$key)) { + $val = '%'.$val.'%'; + $whereStr .= $key." LIKE ".$this->parseValue($val); + }else { + $whereStr .= $key." = ".$this->parseValue($val); + } + } + } + $whereStr .= ' )'.$operate; + } + $whereStr = substr($whereStr,0,-strlen($operate)); + } + return empty($whereStr)?'':' WHERE '.$whereStr; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $whereStr = ''; + switch($key) { + case '_string': + // 字符串模式查询条件 + $whereStr = $val; + break; + case '_complex': + // 复合查询条件 + $whereStr = substr($this->parseWhere($val),6); + break; + case '_query': + // 字符串模式查询条件 + parse_str($val,$where); + if(isset($where['_logic'])) { + $op = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + $op = ' AND '; + } + $array = array(); + foreach ($where as $field=>$data) + $array[] = $this->parseKey($field).' = '.$this->parseValue($data); + $whereStr = implode($op,$array); + break; + } + return $whereStr; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + return !empty($limit)? ' LIMIT '.$limit.' ':''; + } + + /** + * join分析 + * @access protected + * @param mixed $join + * @return string + */ + protected function parseJoin($join) { + $joinStr = ''; + if(!empty($join)) { + if(is_array($join)) { + foreach ($join as $key=>$_join){ + if(false !== stripos($_join,'JOIN')) + $joinStr .= ' '.$_join; + else + $joinStr .= ' LEFT JOIN ' .$_join; + } + }else{ + $joinStr .= ' LEFT JOIN ' .$join; + } + } + return $joinStr; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + return !empty($order)? ' ORDER BY '.$order:''; + } + + /** + * group分析 + * @access protected + * @param mixed $group + * @return string + */ + protected function parseGroup($group) + { + return !empty($group)? ' GROUP BY '.$group:''; + } + + /** + * having分析 + * @access protected + * @param string $having + * @return string + */ + protected function parseHaving($having) + { + return !empty($having)? ' HAVING '.$having:''; + } + + /** + * distinct分析 + * @access protected + * @param mixed $distinct + * @return string + */ + protected function parseDistinct($distinct) { + return !empty($distinct)? ' DISTINCT ' :''; + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @return false | integer + */ + public function insert($data,$options=array()) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = 'INSERT INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(isset($options['where'])?$options['where']:'') + .$this->parseOrder(isset($options['order'])?$options['order']:'') + .$this->parseLimit(isset($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(isset($options['where'])?$options['where']:'') + .$this->parseOrder(isset($options['order'])?$options['order']:'') + .$this->parseLimit(isset($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return array + */ + public function select($options=array()) { + if(isset($options['page'])) { + // 根据页数计算limit + list($page,$listRows) = explode(',',$options['page']); + $listRows = $listRows?$listRows:($options['limit']?$options['limit']:20); + $offset = $listRows*((int)$page-1); + $options['limit'] = $offset.','.$listRows; + } + $sql = str_replace( + array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'), + array( + $this->parseTable($options['table']), + $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), + $this->parseField(isset($options['field'])?$options['field']:'*'), + $this->parseJoin(isset($options['join'])?$options['join']:''), + $this->parseWhere(isset($options['where'])?$options['where']:''), + $this->parseGroup(isset($options['group'])?$options['group']:''), + $this->parseHaving(isset($options['having'])?$options['having']:''), + $this->parseOrder(isset($options['order'])?$options['order']:''), + $this->parseLimit(isset($options['limit'])?$options['limit']:'') + ),$this->selectSql); + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->query($sql); + } + + /** + * 字段和表名添加` + * 保证指令中使用关键字不出错 针对mysql + * @access protected + * @param mixed $value + * @return mixed + */ + protected function parseKey(&$value) { + $value = trim($value); + if( false !== strpos($value,' ') || false !== strpos($value,',') || false !== strpos($value,'*') || false !== strpos($value,'(') || false !== strpos($value,'.') || false !== strpos($value,'`')) { + //如果包含* 或者 使用了sql方法 则不作处理 + }else{ + $value = '`'.$value.'`'; + } + return $value; + } + + /** + * 获取最近一次查询的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID(){ + return $this->lastInsID; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Amf/Model.class.php b/ThinkPHP/Extend/Mode/Amf/Model.class.php new file mode 100644 index 0000000..5218d39 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Amf/Model.class.php @@ -0,0 +1,472 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP AMF模式Model模型类 + * 只支持CURD和连贯操作 以及常用查询 去掉回调接口 + */ +class Model { + // 当前数据库操作对象 + protected $db = null; + // 主键名称 + protected $pk = 'id'; + // 数据表前缀 + protected $tablePrefix = ''; + // 模型名称 + protected $name = ''; + // 数据库名称 + protected $dbName = ''; + // 数据表名(不包含表前缀) + protected $tableName = ''; + // 实际数据表名(包含表前缀) + protected $trueTableName =''; + // 数据信息 + protected $data = array(); + // 查询表达式参数 + protected $options = array(); + // 最近错误信息 + protected $error = ''; + + /** + * 架构函数 + * 取得DB类的实例对象 + * @param string $name 模型名称 + * @access public + */ + public function __construct($name='') { + // 模型初始化 + $this->_initialize(); + // 获取模型名称 + if(!empty($name)) { + $this->name = $name; + }elseif(empty($this->name)){ + $this->name = $this->getModelName(); + } + // 数据库初始化操作 + import("Db"); + // 获取数据库操作对象 + $this->db = Db::getInstance(empty($this->connection)?'':$this->connection); + // 设置表前缀 + $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX'); + // 字段检测 + if(!empty($this->name)) $this->_checkTableInfo(); + } + + /** + * 自动检测数据表信息 + * @access protected + * @return void + */ + protected function _checkTableInfo() { + // 如果不是Model类 自动记录数据表信息 + // 只在第一次执行记录 + if(empty($this->fields)) { + // 如果数据表字段没有定义则自动获取 + if(C('DB_FIELDS_CACHE')) { + $this->fields = F('_fields/'.$this->name); + if(!$this->fields) $this->flush(); + }else{ + // 每次都会读取数据表信息 + $this->flush(); + } + } + } + + /** + * 获取字段信息并缓存 + * @access public + * @return void + */ + public function flush() { + // 缓存不存在则查询数据表信息 + $fields = $this->db->getFields($this->getTableName()); + $this->fields = array_keys($fields); + $this->fields['_autoinc'] = false; + foreach ($fields as $key=>$val){ + // 记录字段类型 + $type[$key] = $val['type']; + if($val['primary']) { + $this->fields['_pk'] = $key; + if($val['autoinc']) $this->fields['_autoinc'] = true; + } + } + // 记录字段类型信息 + if(C('DB_FIELDTYPE_CHECK')) $this->fields['_type'] = $type; + + // 2008-3-7 增加缓存开关控制 + if(C('DB_FIELDS_CACHE')) + // 永久缓存数据表信息 + F('_fields/'.$this->name,$this->fields); + } + + // 回调方法 初始化模型 + protected function _initialize() {} + + /** + * 利用__call方法实现一些特殊的Model方法 (魔术方法) + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(in_array(strtolower($method),array('field','table','where','order','limit','page','having','group','lock','distinct'),true)) { + // 连贯操作的实现 + $this->options[strtolower($method)] = $args[0]; + return $this; + }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){ + // 统计查询的实现 + $field = isset($args[0])?$args[0]:'*'; + return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method); + }elseif(strtolower(substr($method,0,5))=='getby') { + // 根据某个字段获取记录 + $field = parse_name(substr($method,5)); + $options['where'] = $field.'=\''.$args[0].'\''; + return $this->find($options); + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } + + /** + * 设置数据对象的值 (魔术方法) + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return void + */ + public function __set($name,$value) { + // 设置数据对象属性 + $this->data[$name] = $value; + } + + /** + * 获取数据对象的值 (魔术方法) + * @access public + * @param string $name 名称 + * @return mixed + */ + public function __get($name) { + return isset($this->data[$name])?$this->data[$name]:null; + } + + /** + * 新增数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return mixed + */ + public function add($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 分析表达式 + $options = $this->_parseOptions($options); + // 写入数据到数据库 + $result = $this->db->insert($data,$options); + $insertId = $this->getLastInsID(); + if($insertId) { + return $insertId; + } + //成功后返回插入ID + return $result; + } + + /** + * 保存数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return boolean + */ + public function save($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 分析表达式 + $options = $this->_parseOptions($options); + if(!isset($options['where']) ) { + // 如果存在主键数据 则自动作为更新条件 + if(isset($data[$this->getPk()])) { + $pk = $this->getPk(); + $options['where'] = $pk.'=\''.$data[$pk].'\''; + $pkValue = $data[$pk]; + unset($data[$pk]); + }else{ + // 如果没有任何更新条件则不执行 + $this->error = L('_OPERATION_WRONG_'); + return false; + } + } + return $this->db->update($data,$options); + } + + /** + * 删除数据 + * @access public + * @param mixed $options 表达式 + * @return mixed + */ + public function delete($options=array()) { + if(empty($options) && empty($this->options['where'])) { + // 如果删除条件为空 则删除当前数据对象所对应的记录 + if(!empty($this->data) && isset($this->data[$this->getPk()])) + return $this->delete($this->data[$this->getPk()]); + else + return false; + } + if(is_numeric($options) || is_string($options)) { + // 根据主键删除记录 + $pk = $this->getPk(); + $where = $pk.'=\''.$options.'\''; + $pkValue = $options; + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + return $this->db->delete($options); + } + + /** + * 查询数据集 + * @access public + * @param array $options 表达式参数 + * @return mixed + */ + public function select($options=array()) { + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(empty($resultSet)) { // 查询结果为空 + return false; + } + return $resultSet; + } + + /** + * 查询数据 + * @access public + * @param mixed $options 表达式参数 + * @return mixed + */ + public function find($options=array()) { + if(is_numeric($options) || is_string($options)) { + $where = $this->getPk().'=\''.$options.'\''; + $options = array(); + $options['where'] = $where; + } + // 总是查找一条记录 + $options['limit'] = 1; + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(empty($resultSet)) {// 查询结果为空 + return false; + } + $this->data = $resultSet[0]; + return $this->data; + } + + /** + * 分析表达式 + * @access private + * @param array $options 表达式参数 + * @return array + */ + private function _parseOptions($options) { + if(is_array($options)) + $options = array_merge($this->options,$options); + // 查询过后清空sql表达式组装 避免影响下次查询 + $this->options = array(); + if(!isset($options['table'])) + // 自动获取表名 + $options['table'] =$this->getTableName(); + return $options; + } + + /** + * 创建数据对象 但不保存到数据库 + * @access public + * @param mixed $data 创建数据 + * @param string $type 状态 + * @return mixed + */ + public function create($data='',$type='') { + // 如果没有传值默认取POST数据 + if(empty($data)) { + $data = $_POST; + }elseif(is_object($data)){ + $data = get_object_vars($data); + }elseif(!is_array($data)){ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + // 生成数据对象 + $vo = array(); + foreach ($this->fields as $key=>$name){ + if(substr($key,0,1)=='_') continue; + $val = isset($data[$name])?$data[$name]:null; + //保证赋值有效 + if(!is_null($val)){ + $vo[$name] = (MAGIC_QUOTES_GPC && is_string($val))? stripslashes($val) : $val; + if(C('DB_FIELDTYPE_CHECK')) { + // 字段类型检查 + $fieldType = strtolower($this->fields['_type'][$name]); + if(false !== strpos($fieldType,'int')) { + $vo[$name] = intval($vo[$name]); + }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){ + $vo[$name] = floatval($vo[$name]); + } + } + } + } + // 赋值当前数据对象 + $this->data = $vo; + // 返回创建的数据以供其他调用 + return $vo; + } + + /** + * SQL查询 + * @access public + * @param string $sql SQL指令 + * @return array + */ + public function query($sql) { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + return $this->db->query($sql); + }else{ + return false; + } + } + + /** + * 执行SQL语句 + * @access public + * @param string $sql SQL指令 + * @return false | integer + */ + public function execute($sql='') { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + return $this->db->execute($sql); + }else { + return false; + } + } + + /** + * 得到当前的数据对象名称 + * @access public + * @return string + */ + public function getModelName() { + if(empty($this->name)) { + $this->name = substr(get_class($this),0,-5); + } + return $this->name; + } + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + if(!empty($this->dbName)) { + $tableName = $this->dbName.'.'.$tableName; + } + $this->trueTableName = strtolower($tableName); + } + return $this->trueTableName; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->commit(); + $this->db->startTrans(); + return ; + } + + /** + * 提交事务 + * @access public + * @return boolean + */ + public function commit() { + return $this->db->commit(); + } + + /** + * 事务回滚 + * @access public + * @return boolean + */ + public function rollback() { + return $this->db->rollback(); + } + + /** + * 获取主键名称 + * @access public + * @return string + */ + public function getPk() { + return isset($this->fields['_pk'])?$this->fields['_pk']:$this->pk; + } + + /** + * 返回最后执行的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->db->getLastSql(); + } + + /** + * 返回最后插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->db->getLastInsID(); + } +}; \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Cli/Action.class.php b/ThinkPHP/Extend/Mode/Cli/Action.class.php new file mode 100644 index 0000000..1857d19 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Cli/Action.class.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 命令模式Action控制器基类 + */ +abstract class Action { + + /** + * 架构函数 + * @access public + */ + public function __construct() { + //控制器初始化 + if(method_exists($this,'_initialize')) { + $this->_initialize(); + } + } + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $parms 参数 + * @return mixed + */ + public function __call($method,$parms) { + if(strtolower($method) == strtolower(ACTION_NAME)) { + // 如果定义了_empty操作 则调用 + if(method_exists($this,'_empty')) { + $this->_empty($method,$parms); + }else { + // 抛出异常 + exit(L('_ERROR_ACTION_').ACTION_NAME); + } + }else{ + exit(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + } + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Cli/App.class.php b/ThinkPHP/Extend/Mode/Cli/App.class.php new file mode 100644 index 0000000..ef4149d --- /dev/null +++ b/ThinkPHP/Extend/Mode/Cli/App.class.php @@ -0,0 +1,63 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 命令模式应用程序类 + */ +class App { + + /** + * 执行应用程序 + * @access public + * @return void + */ + static public function run() { + + if(C('URL_MODEL')==1) {// PATHINFO 模式URL下面 采用 index.php module/action/id/4 + $depr = C('URL_PATHINFO_DEPR'); + $path = isset($_SERVER['argv'][1])?$_SERVER['argv'][1]:''; + if(!empty($path)) { + $params = explode($depr,trim($path,$depr)); + } + // 取得模块和操作名称 + define('MODULE_NAME', !empty($params)?array_shift($params):C('DEFAULT_MODULE')); + define('ACTION_NAME', !empty($params)?array_shift($params):C('DEFAULT_ACTION')); + if(count($params)>1) { + // 解析剩余参数 并采用GET方式获取 + preg_replace('@(\w+),([^,\/]+)@e', '$_GET[\'\\1\']="\\2";', implode(',',$params)); + } + }else{// 默认URL模式 采用 index.php module action id 4 + // 取得模块和操作名称 + define('MODULE_NAME', isset($_SERVER['argv'][1])?$_SERVER['argv'][1]:C('DEFAULT_MODULE')); + define('ACTION_NAME', isset($_SERVER['argv'][2])?$_SERVER['argv'][2]:C('DEFAULT_ACTION')); + if($_SERVER['argc']>3) { + // 解析剩余参数 并采用GET方式获取 + preg_replace('@(\w+),([^,\/]+)@e', '$_GET[\'\\1\']="\\2";', implode(',',array_slice($_SERVER['argv'],3))); + } + } + + // 执行操作 + $module = A(MODULE_NAME); + if(!$module) { + // 是否定义Empty模块 + $module = A("Empty"); + if(!$module){ + // 模块不存在 抛出异常 + throw_exception(L('_MODULE_NOT_EXIST_').MODULE_NAME); + } + } + call_user_func(array(&$module,ACTION_NAME)); + // 保存日志记录 + if(C('LOG_RECORD')) Log::save(); + return ; + } + +}; \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Cli/Db.class.php b/ThinkPHP/Extend/Mode/Cli/Db.class.php new file mode 100644 index 0000000..34f4be1 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Cli/Db.class.php @@ -0,0 +1,801 @@ + +// +---------------------------------------------------------------------- + +define('CLIENT_MULTI_RESULTS', 131072); +/** + * ThinkPHP 精简模式数据库中间层实现类 只支持Mysql + */ +class Db { + + static private $_instance = null; + // 是否自动释放查询结果 + protected $autoFree = false; + // 是否显示调试信息 如果启用会在日志文件记录sql语句 + public $debug = false; + // 是否使用永久连接 + protected $pconnect = false; + // 当前SQL指令 + protected $queryStr = ''; + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 当前连接ID + protected $linkID = null; + // 当前查询ID + protected $queryID = null; + // 是否已经连接数据库 + protected $connected = false; + // 数据库连接参数配置 + protected $config = ''; + // 数据库表达式 + protected $comparison = array('eq'=>'=','neq'=>'!=','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE'); + // 查询表达式 + protected $selectSql = 'SELECT%DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%'; + /** + * 架构函数 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysql') ) { + throw_exception(L('_NOT_SUPPERT_').':mysql'); + } + $this->config = $this->parseConfig($config); + if(APP_DEBUG) { + $this->debug = true; + } + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect() { + if(!$this->connected) { + $config = $this->config; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + if($pconnect) { + $this->linkID = mysql_pconnect( $host, $config['username'], $config['password'],CLIENT_MULTI_RESULTS); + }else{ + $this->linkID = mysql_connect( $host, $config['username'], $config['password'],true,CLIENT_MULTI_RESULTS); + } + if ( !$this->linkID || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID)) ) { + throw_exception(mysql_error()); + } + $dbVersion = mysql_get_server_info($this->linkID); + if ($dbVersion >= "4.1") { + //使用UTF8存取数据库 需要mysql 4.1.0以上支持 + mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID); + } + //设置 sql_model + if($dbVersion >'5.0.1'){ + mysql_query("SET sql_mode=''",$this->linkID); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + unset($this->config); + } + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mysql_free_result($this->queryID); + $this->queryID = 0; + } + + /** + * 执行查询 主要针对 SELECT, SHOW 等指令 + * 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + * @throws ThinkExecption + */ + public function query($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mysql_query($this->queryStr, $this->linkID); + $this->debug(); + if ( !$this->queryID ) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 针对 INSERT, UPDATE 以及DELETE + * @access public + * @param string $str sql指令 + * @return integer + * @throws ThinkExecption + */ + public function execute($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_write',1); + $result = mysql_query($this->queryStr, $this->linkID) ; + $this->debug(); + if ( false === $result) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_affected_rows($this->linkID); + $this->lastInsID = mysql_insert_id($this->linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + * @throws ThinkExecption + */ + public function startTrans() { + $this->connect(true); + if ( !$this->linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mysql_query('START TRANSACTION', $this->linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function commit() { + if ($this->transTimes > 0) { + $result = mysql_query('COMMIT', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = mysql_query('ROLLBACK', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access public + * @return array + * @throws ThinkExecption + */ + public function getAll() { + if ( !$this->queryID ) { + throw_exception($this->error()); + return false; + } + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mysql_fetch_assoc($this->queryID)){ + $result[] = $row; + } + mysql_data_seek($this->queryID,0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query('SHOW COLUMNS FROM '.$tableName); + $info = array(); + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + if(!empty($dbName)) { + $sql = 'SHOW TABLES FROM '.$dbName; + }else{ + $sql = 'SHOW TABLES '; + } + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + * @throws ThinkExecption + */ + public function close() { + if (!empty($this->queryID)) + mysql_free_result($this->queryID); + if ($this->linkID && !mysql_close($this->linkID)){ + throw_exception($this->error()); + } + $this->linkID = 0; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mysql_error($this->linkID); + if($this->queryStr!=''){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escapeString($str) { + return mysql_escape_string($str); + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 关闭连接 + $this->close(); + } + + /** + * 取得数据库类实例 + * @static + * @access public + * @return mixed 返回数据库驱动类 + */ + public static function getInstance($db_config='') { + if ( self::$_instance==null ){ + self::$_instance = new Db($db_config); + } + return self::$_instance; + } + + /** + * 分析数据库配置信息,支持数组和DSN + * @access private + * @param mixed $db_config 数据库配置信息 + * @return string + */ + private function parseConfig($db_config='') { + if ( !empty($db_config) && is_string($db_config)) { + // 如果DSN字符串则进行解析 + $db_config = $this->parseDSN($db_config); + }else if(empty($db_config)){ + // 如果配置为空,读取配置文件设置 + $db_config = array ( + 'dbms' => C('DB_TYPE'), + 'username' => C('DB_USER'), + 'password' => C('DB_PWD'), + 'hostname' => C('DB_HOST'), + 'hostport' => C('DB_PORT'), + 'database' => C('DB_NAME'), + 'dsn' => C('DB_DSN'), + 'params' => C('DB_PARAMS'), + ); + } + return $db_config; + } + + /** + * DSN解析 + * 格式: mysql://username:passwd@localhost:3306/DbName + * @static + * @access public + * @param string $dsnStr + * @return array + */ + public function parseDSN($dsnStr) { + if( empty($dsnStr) ){return false;} + $info = parse_url($dsnStr); + if($info['scheme']){ + $dsn = array( + 'dbms' => $info['scheme'], + 'username' => isset($info['user']) ? $info['user'] : '', + 'password' => isset($info['pass']) ? $info['pass'] : '', + 'hostname' => isset($info['host']) ? $info['host'] : '', + 'hostport' => isset($info['port']) ? $info['port'] : '', + 'database' => isset($info['path']) ? substr($info['path'],1) : '' + ); + }else { + preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); + $dsn = array ( + 'dbms' => $matches[1], + 'username' => $matches[2], + 'password' => $matches[3], + 'hostname' => $matches[4], + 'hostport' => $matches[5], + 'database' => $matches[6] + ); + } + return $dsn; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + // 记录操作结束时间 + if ( $this->debug ) { + G('queryEndTime'); + Log::record($this->queryStr." [ RunTime:".G('queryStartTime','queryEndTime',6)."s ]",Log::SQL); + } + } + + /** + * 设置锁机制 + * @access protected + * @return string + */ + protected function parseLock($lock=false) { + if(!$lock) return ''; + if('ORACLE' == $this->dbType) { + return ' FOR UPDATE NOWAIT '; + } + return ' FOR UPDATE '; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) // 过滤非标量数据 + $set[] = $this->parseKey($key).'='.$value; + } + return ' SET '.implode(',',$set); + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = '\''.$this->escapeString($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escapeString($value[1]); + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return string + */ + protected function parseField($fields) { + if(is_array($fields)) { + // 完善数组方式传字段名的支持 + // 支持 'field1'=>'field2' 这样的字段别名定义 + $array = array(); + foreach ($fields as $key=>$field){ + if(!is_numeric($key)) + $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); + else + $array[] = $this->parseKey($field); + } + $fieldsStr = implode(',', $array); + }elseif(is_string($fields) && !empty($fields)) { + $fieldsStr = $this->parseKey($fields); + }else{ + $fieldsStr = '*'; + } + return $fieldsStr; + } + + /** + * table分析 + * @access protected + * @param mixed $table + * @return string + */ + protected function parseTable($tables) { + if(is_string($tables)) + $tables = explode(',',$tables); + array_walk($tables, array(&$this, 'parseKey')); + return implode(',',$tables); + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return string + */ + protected function parseWhere($where) { + $whereStr = ''; + if(is_string($where)) { + // 直接使用字符串条件 + $whereStr = $where; + }else{ // 使用数组条件表达式 + if(isset($where['_logic'])) { + // 定义逻辑运算规则 例如 OR XOR AND NOT + $operate = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + // 默认进行 AND 运算 + $operate = ' AND '; + } + foreach ($where as $key=>$val){ + $whereStr .= "( "; + if(0===strpos($key,'_')) { + // 解析特殊条件表达式 + $whereStr .= $this->parseThinkWhere($key,$val); + }else{ + $key = $this->parseKey($key); + if(is_array($val)) { + if(is_string($val[0])) { + if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|NOTLIKE|LIKE)$/i',$val[0])) { // 比较运算 + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + }elseif('exp'==strtolower($val[0])){ // 使用表达式 + $whereStr .= ' ('.$key.' '.$val[1].') '; + }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 + $zone = is_array($val[1])? implode(',',$this->parseValue($val[1])):$val[1]; + $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; + }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $whereStr .= ' ('.$key.' BETWEEN '.$data[0].' AND '.$data[1].' )'; + }else{ + throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]); + } + }else { + $count = count($val); + if(in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) { + $rule = strtoupper(trim($val[$count-1])); + $count = $count -1; + }else{ + $rule = 'AND'; + } + for($i=0;$i<$count;$i++) { + $data = is_array($val[$i])?$val[$i][1]:$val[$i]; + if('exp'==strtolower($val[$i][0])) { + $whereStr .= '('.$key.' '.$data.') '.$rule.' '; + }else{ + $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; + $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' '; + } + } + $whereStr = substr($whereStr,0,-4); + } + }else { + //对字符串类型字段采用模糊匹配 + if(C('LIKE_MATCH_FIELDS') && preg_match('/('.C('LIKE_MATCH_FIELDS').')/i',$key)) { + $val = '%'.$val.'%'; + $whereStr .= $key." LIKE ".$this->parseValue($val); + }else { + $whereStr .= $key." = ".$this->parseValue($val); + } + } + } + $whereStr .= ' )'.$operate; + } + $whereStr = substr($whereStr,0,-strlen($operate)); + } + return empty($whereStr)?'':' WHERE '.$whereStr; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $whereStr = ''; + switch($key) { + case '_string': + // 字符串模式查询条件 + $whereStr = $val; + break; + case '_complex': + // 复合查询条件 + $whereStr = substr($this->parseWhere($val),6); + break; + case '_query': + // 字符串模式查询条件 + parse_str($val,$where); + if(isset($where['_logic'])) { + $op = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + $op = ' AND '; + } + $array = array(); + foreach ($where as $field=>$data) + $array[] = $this->parseKey($field).' = '.$this->parseValue($data); + $whereStr = implode($op,$array); + break; + } + return $whereStr; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + return !empty($limit)? ' LIMIT '.$limit.' ':''; + } + + /** + * join分析 + * @access protected + * @param mixed $join + * @return string + */ + protected function parseJoin($join) { + $joinStr = ''; + if(!empty($join)) { + if(is_array($join)) { + foreach ($join as $key=>$_join){ + if(false !== stripos($_join,'JOIN')) + $joinStr .= ' '.$_join; + else + $joinStr .= ' LEFT JOIN ' .$_join; + } + }else{ + $joinStr .= ' LEFT JOIN ' .$join; + } + } + return $joinStr; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + return !empty($order)? ' ORDER BY '.$order:''; + } + + /** + * group分析 + * @access protected + * @param mixed $group + * @return string + */ + protected function parseGroup($group) { + return !empty($group)? ' GROUP BY '.$group:''; + } + + /** + * having分析 + * @access protected + * @param string $having + * @return string + */ + protected function parseHaving($having) { + return !empty($having)? ' HAVING '.$having:''; + } + + /** + * distinct分析 + * @access protected + * @param mixed $distinct + * @return string + */ + protected function parseDistinct($distinct) { + return !empty($distinct)? ' DISTINCT ' :''; + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @return false | integer + */ + public function insert($data,$options=array()) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = 'INSERT INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(isset($options['where'])?$options['where']:'') + .$this->parseOrder(isset($options['order'])?$options['order']:'') + .$this->parseLimit(isset($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(isset($options['where'])?$options['where']:'') + .$this->parseOrder(isset($options['order'])?$options['order']:'') + .$this->parseLimit(isset($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return array + */ + public function select($options=array()) { + if(isset($options['page'])) { + // 根据页数计算limit + list($page,$listRows) = explode(',',$options['page']); + $listRows = $listRows?$listRows:($options['limit']?$options['limit']:20); + $offset = $listRows*((int)$page-1); + $options['limit'] = $offset.','.$listRows; + } + $sql = str_replace( + array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'), + array( + $this->parseTable($options['table']), + $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), + $this->parseField(isset($options['field'])?$options['field']:'*'), + $this->parseJoin(isset($options['join'])?$options['join']:''), + $this->parseWhere(isset($options['where'])?$options['where']:''), + $this->parseGroup(isset($options['group'])?$options['group']:''), + $this->parseHaving(isset($options['having'])?$options['having']:''), + $this->parseOrder(isset($options['order'])?$options['order']:''), + $this->parseLimit(isset($options['limit'])?$options['limit']:'') + ),$this->selectSql); + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->query($sql); + } + + /** + * 字段和表名添加` + * 保证指令中使用关键字不出错 针对mysql + * @access protected + * @param mixed $value + * @return mixed + */ + protected function parseKey(&$value) { + $value = trim($value); + if( false !== strpos($value,' ') || false !== strpos($value,',') || false !== strpos($value,'*') || false !== strpos($value,'(') || false !== strpos($value,'.') || false !== strpos($value,'`')) { + //如果包含* 或者 使用了sql方法 则不作处理 + }else{ + $value = '`'.$value.'`'; + } + return $value; + } + + /** + * 获取最近一次查询的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID(){ + return $this->lastInsID; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Cli/Log.class.php b/ThinkPHP/Extend/Mode/Cli/Log.class.php new file mode 100644 index 0000000..cba5c47 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Cli/Log.class.php @@ -0,0 +1,107 @@ + +// +---------------------------------------------------------------------- + +/** + * 日志处理类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Log { + + // 日志级别 从上到下,由低到高 + const EMERG = 'EMERG'; // 严重错误: 导致系统崩溃无法使用 + const ALERT = 'ALERT'; // 警戒性错误: 必须被立即修改的错误 + const CRIT = 'CRIT'; // 临界值错误: 超过临界值的错误,例如一天24小时,而输入的是25小时这样 + const ERR = 'ERR'; // 一般错误: 一般性错误 + const WARN = 'WARN'; // 警告性错误: 需要发出警告的错误 + const NOTICE = 'NOTIC'; // 通知: 程序可以运行但是还不够完美的错误 + const INFO = 'INFO'; // 信息: 程序输出信息 + const DEBUG = 'DEBUG'; // 调试: 调试信息 + const SQL = 'SQL'; // SQL:SQL语句 注意只在调试模式开启时有效 + + // 日志记录方式 + const SYSTEM = 0; + const MAIL = 1; + const TCP = 2; + const FILE = 3; + + // 日志信息 + static $log = array(); + + // 日期格式 + static $format = '[ c ]'; + + /** + * 记录日志 并且会过滤未经设置的级别 + * @static + * @access public + * @param string $message 日志信息 + * @param string $level 日志级别 + * @param boolean $record 是否强制记录 + * @return void + */ + static function record($message,$level=self::ERR,$record=false) { + if($record || false!== strpos(C('LOG_RECORD_LEVEL'),$level)) { + $now = date(self::$format); + self::$log[] = "{$now} {$level}: {$message}\r\n"; + } + } + + /** + * 日志保存 + * @static + * @access public + * @param integer $type 日志记录方式 + * @param string $destination 写入目标 + * @param string $extra 额外参数 + * @return void + */ + static function save($type=self::FILE,$destination='',$extra='') { + if(empty($destination)) + $destination = LOG_PATH.date('y_m_d').".log"; + if(self::FILE == $type) { // 文件方式记录日志信息 + //检测日志文件大小,超过配置大小则备份日志文件重新生成 + if(is_file($destination) && floor(C('LOG_FILE_SIZE')) <= filesize($destination) ) + rename($destination,dirname($destination).'/'.time().'-'.basename($destination)); + } + error_log(implode("",self::$log), $type,$destination ,$extra); + // 保存后清空日志缓存 + self::$log = array(); + //clearstatcache(); + } + + /** + * 日志直接写入 + * @static + * @access public + * @param string $message 日志信息 + * @param string $level 日志级别 + * @param integer $type 日志记录方式 + * @param string $destination 写入目标 + * @param string $extra 额外参数 + * @return void + */ + static function write($message,$level=self::ERR,$type=self::FILE,$destination='',$extra='') { + $now = date(self::$format); + if(empty($destination)) + $destination = LOG_PATH.date('y_m_d').".log"; + if(self::FILE == $type) { // 文件方式记录日志 + //检测日志文件大小,超过配置大小则备份日志文件重新生成 + if(is_file($destination) && floor(C('LOG_FILE_SIZE')) <= filesize($destination) ) + rename($destination,dirname($destination).'/'.time().'-'.basename($destination)); + } + error_log("{$now} {$level}: {$message}\r\n", $type,$destination,$extra ); + //clearstatcache(); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Cli/Model.class.php b/ThinkPHP/Extend/Mode/Cli/Model.class.php new file mode 100644 index 0000000..5de7a78 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Cli/Model.class.php @@ -0,0 +1,850 @@ + +// +---------------------------------------------------------------------- +// $Id: Model.class.php 2779 2012-02-24 02:56:57Z liu21st $ + +/** + * ThinkPHP CLI模式Model模型类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Model { + + // 当前数据库操作对象 + protected $db = null; + // 主键名称 + protected $pk = 'id'; + // 数据表前缀 + protected $tablePrefix = ''; + // 模型名称 + protected $name = ''; + // 数据库名称 + protected $dbName = ''; + // 数据表名(不包含表前缀) + protected $tableName = ''; + // 实际数据表名(包含表前缀) + protected $trueTableName =''; + // 最近错误信息 + protected $error = ''; + // 字段信息 + protected $fields = array(); + // 数据信息 + protected $data = array(); + // 查询表达式参数 + protected $options = array(); + protected $_validate = array(); // 自动验证定义 + protected $_auto = array(); // 自动完成定义 + // 是否自动检测数据表字段信息 + protected $autoCheckFields = true; + // 是否批处理验证 + protected $patchValidate = false; + + /** + * 架构函数 + * 取得DB类的实例对象 字段检查 + * @param string $name 模型名称 + * @param string $tablePrefix 表前缀 + * @param mixed $connection 数据库连接信息 + * @access public + */ + public function __construct($name='',$tablePrefix='',$connection='') { + // 模型初始化 + $this->_initialize(); + // 获取模型名称 + if(!empty($name)) { + if(strpos($name,'.')) { // 支持 数据库名.模型名的 定义 + list($this->dbName,$this->name) = explode('.',$name); + }else{ + $this->name = $name; + } + }elseif(empty($this->name)){ + $this->name = $this->getModelName(); + } + if(!empty($tablePrefix)) { + $this->tablePrefix = $tablePrefix; + } + // 设置表前缀 + $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX'); + // 数据库初始化操作 + // 获取数据库操作对象 + // 当前模型有独立的数据库连接信息 + $this->db(0,empty($this->connection)?$connection:$this->connection); + // 字段检测 + if(!empty($this->name) && $this->autoCheckFields) $this->_checkTableInfo(); + } + + /** + * 自动检测数据表信息 + * @access protected + * @return void + */ + protected function _checkTableInfo() { + // 如果不是Model类 自动记录数据表信息 + // 只在第一次执行记录 + if(empty($this->fields)) { + // 如果数据表字段没有定义则自动获取 + if(C('DB_FIELDS_CACHE')) { + $db = $this->dbName?$this->dbName:C('DB_NAME'); + $this->fields = F('_fields/'.$db.'.'.$this->name); + if(!$this->fields) $this->flush(); + }else{ + // 每次都会读取数据表信息 + $this->flush(); + } + } + } + + /** + * 获取字段信息并缓存 + * @access public + * @return void + */ + public function flush() { + // 缓存不存在则查询数据表信息 + $fields = $this->db->getFields($this->getTableName()); + if(!$fields) { // 无法获取字段信息 + return false; + } + $this->fields = array_keys($fields); + $this->fields['_autoinc'] = false; + foreach ($fields as $key=>$val){ + // 记录字段类型 + $type[$key] = $val['type']; + if($val['primary']) { + $this->fields['_pk'] = $key; + if($val['autoinc']) $this->fields['_autoinc'] = true; + } + } + // 记录字段类型信息 + if(C('DB_FIELDTYPE_CHECK')) $this->fields['_type'] = $type; + + // 2008-3-7 增加缓存开关控制 + if(C('DB_FIELDS_CACHE')){ + // 永久缓存数据表信息 + $db = $this->dbName?$this->dbName:C('DB_NAME'); + F('_fields/'.$db.'.'.$this->name,$this->fields); + } + } + + /** + * 设置数据对象的值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return void + */ + public function __set($name,$value) { + // 设置数据对象属性 + $this->data[$name] = $value; + } + + /** + * 获取数据对象的值 + * @access public + * @param string $name 名称 + * @return mixed + */ + public function __get($name) { + return isset($this->data[$name])?$this->data[$name]:null; + } + + /** + * 检测数据对象的值 + * @access public + * @param string $name 名称 + * @return boolean + */ + public function __isset($name) { + return isset($this->data[$name]); + } + + /** + * 销毁数据对象的值 + * @access public + * @param string $name 名称 + * @return void + */ + public function __unset($name) { + unset($this->data[$name]); + } + + /** + * 利用__call方法实现一些特殊的Model方法 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(in_array(strtolower($method),array('table','where','order','limit','page','alias','having','group','lock','distinct'),true)) { + // 连贯操作的实现 + $this->options[strtolower($method)] = $args[0]; + return $this; + }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){ + // 统计查询的实现 + $field = isset($args[0])?$args[0]:'*'; + return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method); + }elseif(strtolower(substr($method,0,5))=='getby') { + // 根据某个字段获取记录 + $field = parse_name(substr($method,5)); + $where[$field] = $args[0]; + return $this->where($where)->find(); + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } + // 回调方法 初始化模型 + protected function _initialize() {} + + /** + * 对保存到数据库的数据进行处理 + * @access protected + * @param mixed $data 要操作的数据 + * @return boolean + */ + protected function _facade($data) { + // 检查非数据字段 + if(!empty($this->fields)) { + foreach ($data as $key=>$val){ + if(!in_array($key,$this->fields,true)){ + unset($data[$key]); + }elseif(C('DB_FIELDTYPE_CHECK') && is_scalar($val)) { + // 字段类型检查 + $this->_parseType($data,$key); + } + } + } + return $data; + } + + /** + * 新增数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return mixed + */ + public function add($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 分析表达式 + $options = $this->_parseOptions($options); + // 数据处理 + $data = $this->_facade($data); + // 写入数据到数据库 + $result = $this->db->insert($data,$options); + if(false !== $result ) { + $insertId = $this->getLastInsID(); + if($insertId) { + // 自增主键返回插入ID + return $insertId; + } + } + return $result; + } + + /** + * 保存数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return boolean + */ + public function save($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 数据处理 + $data = $this->_facade($data); + // 分析表达式 + $options = $this->_parseOptions($options); + if(!isset($options['where']) ) { + // 如果存在主键数据 则自动作为更新条件 + if(isset($data[$this->getPk()])) { + $pk = $this->getPk(); + $where[$pk] = $data[$pk]; + $options['where'] = $where; + unset($data[$pk]); + }else{ + // 如果没有任何更新条件则不执行 + $this->error = L('_OPERATION_WRONG_'); + return false; + } + } + $result = $this->db->update($data,$options); + return $result; + } + + /** + * 删除数据 + * @access public + * @param mixed $options 表达式 + * @return mixed + */ + public function delete($options=array()) { + if(empty($options) && empty($this->options['where'])) { + // 如果删除条件为空 则删除当前数据对象所对应的记录 + if(!empty($this->data) && isset($this->data[$this->getPk()])) + return $this->delete($this->data[$this->getPk()]); + else + return false; + } + if(is_numeric($options) || is_string($options)) { + // 根据主键删除记录 + $pk = $this->getPk(); + if(strpos($options,',')) { + $where[$pk] = array('IN', $options); + }else{ + $where[$pk] = $options; + $pkValue = $options; + } + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + $result= $this->db->delete($options); + // 返回删除记录个数 + return $result; + } + + /** + * 查询数据集 + * @access public + * @param array $options 表达式参数 + * @return mixed + */ + public function select($options=array()) { + if(is_string($options) || is_numeric($options)) { + // 根据主键查询 + $pk = $this->getPk(); + if(strpos($options,',')) { + $where[$pk] = array('IN',$options); + }else{ + $where[$pk] = $options; + } + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(false === $resultSet) { + return false; + } + if(empty($resultSet)) { // 查询结果为空 + return null; + } + return $resultSet; + } + + /** + * 分析表达式 + * @access proteced + * @param array $options 表达式参数 + * @return array + */ + protected function _parseOptions($options=array()) { + if(is_array($options)) + $options = array_merge($this->options,$options); + // 查询过后清空sql表达式组装 避免影响下次查询 + $this->options = array(); + if(!isset($options['table'])) + // 自动获取表名 + $options['table'] =$this->getTableName(); + if(!empty($options['alias'])) { + $options['table'] .= ' '.$options['alias']; + } + // 字段类型验证 + if(C('DB_FIELDTYPE_CHECK')) { + if(isset($options['where']) && is_array($options['where'])) { + // 对数组查询条件进行字段类型检查 + foreach ($options['where'] as $key=>$val){ + if(in_array($key,$this->fields,true) && is_scalar($val)){ + $this->_parseType($options['where'],$key); + } + } + } + } + return $options; + } + + /** + * 数据类型检测 + * @access protected + * @param mixed $data 数据 + * @param string $key 字段名 + * @return void + */ + protected function _parseType(&$data,$key) { + $fieldType = strtolower($this->fields['_type'][$key]); + if(false !== strpos($fieldType,'int')) { + $data[$key] = intval($data[$key]); + }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){ + $data[$key] = floatval($data[$key]); + }elseif(false !== strpos($fieldType,'bool')){ + $data[$key] = (bool)$data[$key]; + } + } + + /** + * 查询数据 + * @access public + * @param mixed $options 表达式参数 + * @return mixed + */ + public function find($options=array()) { + if(is_numeric($options) || is_string($options)) { + $where[$this->getPk()] =$options; + $options = array(); + $options['where'] = $where; + } + // 总是查找一条记录 + $options['limit'] = 1; + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(false === $resultSet) { + return false; + } + if(empty($resultSet)) {// 查询结果为空 + return null; + } + $this->data = $resultSet[0]; + return $this->data; + } + + /** + * 设置记录的某个字段值 + * 支持使用数据库字段和方法 + * @access public + * @param string|array $field 字段名 + * @param string|array $value 字段值 + * @return boolean + */ + public function setField($field,$value) { + if(is_array($field)) { + $data = $field; + }else{ + $data[$field] = $value; + } + return $this->save($data); + } + + /** + * 字段值增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @return boolean + */ + public function setInc($field,$step=1) { + return $this->setField($field,array('exp',$field.'+'.$step)); + } + + /** + * 字段值减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @return boolean + */ + public function setDec($field,$step=1) { + return $this->setField($field,array('exp',$field.'-'.$step)); + } + + /** + * 获取一条记录的某个字段值 + * @access public + * @param string $field 字段名 + * @param string $spea 字段数据间隔符号 + * @return mixed + */ + public function getField($field,$sepa=null) { + $options['field'] = $field; + $options = $this->_parseOptions($options); + if(strpos($field,',')) { // 多字段 + $resultSet = $this->db->select($options); + if(!empty($resultSet)) { + $_field = explode(',', $field); + $field = array_keys($resultSet[0]); + $move = $_field[0]==$_field[1]?false:true; + $key = array_shift($field); + $key2 = array_shift($field); + $cols = array(); + $count = count($_field); + foreach ($resultSet as $result){ + $name = $result[$key]; + if($move) { // 删除键值记录 + unset($result[$key]); + } + if(2==$count) { + $cols[$name] = $result[$key2]; + }else{ + $cols[$name] = is_null($sepa)?$result:implode($sepa,$result); + } + } + return $cols; + } + }else{ // 查找一条记录 + $options['limit'] = 1; + $result = $this->db->select($options); + if(!empty($result)) { + return reset($result[0]); + } + } + return null; + } + + /** + * 创建数据对象 但不保存到数据库 + * @access public + * @param mixed $data 创建数据 + * @return mixed + */ + public function create($data='') { + // 如果没有传值默认取POST数据 + if(empty($data)) { + $data = $_POST; + }elseif(is_object($data)){ + $data = get_object_vars($data); + } + // 验证数据 + if(empty($data) || !is_array($data)) { + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + + // 验证完成生成数据对象 + if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据 + $vo = array(); + foreach ($this->fields as $key=>$name){ + if(substr($key,0,1)=='_') continue; + $val = isset($data[$name])?$data[$name]:null; + //保证赋值有效 + if(!is_null($val)){ + $vo[$name] = (MAGIC_QUOTES_GPC && is_string($val))? stripslashes($val) : $val; + } + } + }else{ + $vo = $data; + } + + // 赋值当前数据对象 + $this->data = $vo; + // 返回创建的数据以供其他调用 + return $vo; + } + + /** + * SQL查询 + * @access public + * @param mixed $sql SQL指令 + * @return mixed + */ + public function query($sql) { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + return $this->db->query($sql); + }else{ + return false; + } + } + + /** + * 执行SQL语句 + * @access public + * @param string $sql SQL指令 + * @return false | integer + */ + public function execute($sql) { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + return $this->db->execute($sql); + }else { + return false; + } + } + + /** + * 切换当前的数据库连接 + * @access public + * @param integer $linkNum 连接序号 + * @param mixed $config 数据库连接信息 + * @param array $params 模型参数 + * @return Model + */ + public function db($linkNum,$config='',$params=array()){ + static $_db = array(); + if(!isset($_db[$linkNum])) { + // 创建一个新的实例 + if(!empty($config) && false === strpos($config,'/')) { // 支持读取配置参数 + $config = C($config); + } + $_db[$linkNum] = Db::getInstance($config); + }elseif(NULL === $config){ + $_db[$linkNum]->close(); // 关闭数据库连接 + unset($_db[$linkNum]); + return ; + } + if(!empty($params)) { + if(is_string($params)) parse_str($params,$params); + foreach ($params as $name=>$value){ + $this->setProperty($name,$value); + } + } + // 切换数据库连接 + $this->db = $_db[$linkNum]; + return $this; + } + + /** + * 得到当前的数据对象名称 + * @access public + * @return string + */ + public function getModelName() { + if(empty($this->name)) + $this->name = substr(get_class($this),0,-5); + return $this->name; + } + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + $this->trueTableName = strtolower($tableName); + } + return (!empty($this->dbName)?$this->dbName.'.':'').$this->trueTableName; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->commit(); + $this->db->startTrans(); + return ; + } + + /** + * 提交事务 + * @access public + * @return boolean + */ + public function commit() { + return $this->db->commit(); + } + + /** + * 事务回滚 + * @access public + * @return boolean + */ + public function rollback() { + return $this->db->rollback(); + } + + /** + * 返回模型的错误信息 + * @access public + * @return string + */ + public function getError(){ + return $this->error; + } + + /** + * 返回数据库的错误信息 + * @access public + * @return string + */ + public function getDbError() { + return $this->db->getError(); + } + + /** + * 返回最后插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->db->getLastInsID(); + } + + /** + * 返回最后执行的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->db->getLastSql(); + } + // 鉴于getLastSql比较常用 增加_sql 别名 + public function _sql(){ + return $this->getLastSql(); + } + + /** + * 获取主键名称 + * @access public + * @return string + */ + public function getPk() { + return isset($this->fields['_pk'])?$this->fields['_pk']:$this->pk; + } + + /** + * 获取数据表字段信息 + * @access public + * @return array + */ + public function getDbFields(){ + if($this->fields) { + $fields = $this->fields; + unset($fields['_autoinc'],$fields['_pk'],$fields['_type']); + return $fields; + } + return false; + } + + /** + * 指定查询字段 支持字段排除 + * @access public + * @param mixed $field + * @param boolean $except 是否排除 + * @return Model + */ + public function field($field,$except=false){ + if($except) {// 字段排除 + if(is_string($field)) { + $field = explode(',',$field); + } + $fields = $this->getDbFields(); + $field = $fields?array_diff($fields,$field):$field; + } + $this->options['field'] = $field; + return $this; + } + + /** + * 设置数据对象值 + * @access public + * @param mixed $data 数据 + * @return Model + */ + public function data($data){ + if(is_object($data)){ + $data = get_object_vars($data); + }elseif(is_string($data)){ + parse_str($data,$data); + }elseif(!is_array($data)){ + throw_exception(L('_DATA_TYPE_INVALID_')); + } + $this->data = $data; + return $this; + } + + /** + * 查询SQL组装 join + * @access public + * @param mixed $join + * @return Model + */ + public function join($join) { + if(is_array($join)) + $this->options['join'] = $join; + else + $this->options['join'][] = $join; + return $this; + } + + /** + * 查询SQL组装 union + * @access public + * @param array $union + * @return Model + */ + public function union($union) { + if(empty($union)) return $this; + // 转换union表达式 + if($union instanceof Model) { + $options = $union->getProperty('options'); + if(!isset($options['table'])){ + // 自动获取表名 + $options['table'] =$union->getTableName(); + } + if(!isset($options['field'])) { + $options['field'] =$this->options['field']; + } + }elseif(is_object($union)) { + $options = get_object_vars($union); + }elseif(!is_array($union)){ + throw_exception(L('_DATA_TYPE_INVALID_')); + } + $this->options['union'][] = $options; + return $this; + } + + /** + * 设置模型的属性值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return Model + */ + public function setProperty($name,$value) { + if(property_exists($this,$name)) + $this->$name = $value; + return $this; + } + + /** + * 获取模型的属性值 + * @access public + * @param string $name 名称 + * @return mixed + */ + public function getProperty($name){ + if(property_exists($this,$name)) + return $this->$name; + else + return NULL; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Cli/functions.php b/ThinkPHP/Extend/Mode/Cli/functions.php new file mode 100644 index 0000000..f8e3632 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Cli/functions.php @@ -0,0 +1,186 @@ + +// +---------------------------------------------------------------------- + +/** + * Think 命令行模式公共函数库 + * @category Think + * @package Common + * @author liu21st + */ + +// 错误输出 +function halt($error) { + exit($error); +} + +// 自定义异常处理 +function throw_exception($msg, $type='ThinkException', $code=0) { + halt($msg); +} + +// 浏览器友好的变量输出 +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 = "
    " . $label . htmlspecialchars($output, ENT_QUOTES) . "
    "; + } 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; +} + + // 区间调试开始 +function debug_start($label='') { + $GLOBALS[$label]['_beginTime'] = microtime(TRUE); + if (MEMORY_LIMIT_ON) + $GLOBALS[$label]['_beginMem'] = memory_get_usage(); +} + +// 区间调试结束,显示指定标记到当前位置的调试 +function debug_end($label='') { + $GLOBALS[$label]['_endTime'] = microtime(TRUE); + echo '
    Process ' . $label . ': Times ' . number_format($GLOBALS[$label]['_endTime'] - $GLOBALS[$label]['_beginTime'], 6) . 's '; + if (MEMORY_LIMIT_ON) { + $GLOBALS[$label]['_endMem'] = memory_get_usage(); + echo ' Memories ' . number_format(($GLOBALS[$label]['_endMem'] - $GLOBALS[$label]['_beginMem']) / 1024) . ' k'; + } + echo '
    '; +} + +// 全局缓存设置和读取 +function S($name, $value='', $expire='', $type='',$options=null) { + static $_cache = array(); + alias_import('Cache'); + //取得缓存对象实例 + $cache = Cache::getInstance($type,$options); + if ('' !== $value) { + if (is_null($value)) { + // 删除缓存 + $result = $cache->rm($name); + if ($result) + unset($_cache[$type . '_' . $name]); + return $result; + }else { + // 缓存数据 + $cache->set($name, $value, $expire); + $_cache[$type . '_' . $name] = $value; + } + return; + } + if (isset($_cache[$type . '_' . $name])) + return $_cache[$type . '_' . $name]; + // 获取缓存数据 + $value = $cache->get($name); + $_cache[$type . '_' . $name] = $value; + return $value; +} + +// 快速文件数据读取和保存 针对简单类型数据 字符串、数组 +function F($name, $value='', $path=DATA_PATH) { + static $_cache = array(); + $filename = $path . $name . '.php'; + if ('' !== $value) { + if (is_null($value)) { + // 删除缓存 + return unlink($filename); + } else { + // 缓存数据 + $dir = dirname($filename); + // 目录不存在则创建 + if (!is_dir($dir)) + mkdir($dir); + return file_put_contents($filename, strip_whitespace("")); + } + } + if (isset($_cache[$name])) + return $_cache[$name]; + // 获取缓存数据 + if (is_file($filename)) { + $value = include $filename; + $_cache[$name] = $value; + } else { + $value = false; + } + return $value; +} + +// 取得对象实例 支持调用类的静态方法 +function get_instance_of($name, $method='', $args=array()) { + static $_instance = array(); + $identify = empty($args) ? $name . $method : $name . $method . to_guid_string($args); + if (!isset($_instance[$identify])) { + if (class_exists($name)) { + $o = new $name(); + if (method_exists($o, $method)) { + if (!empty($args)) { + $_instance[$identify] = call_user_func_array(array(&$o, $method), $args); + } else { + $_instance[$identify] = $o->$method(); + } + } + else + $_instance[$identify] = $o; + } + else + halt(L('_CLASS_NOT_EXIST_') . ':' . $name); + } + return $_instance[$identify]; +} + +// 根据PHP各种类型变量生成唯一标识号 +function to_guid_string($mix) { + if (is_object($mix) && function_exists('spl_object_hash')) { + return spl_object_hash($mix); + } elseif (is_resource($mix)) { + $mix = get_resource_type($mix) . strval($mix); + } else { + $mix = serialize($mix); + } + return md5($mix); +} + +// 加载扩展配置文件 +function load_ext_file() { + // 加载自定义外部文件 + if(C('LOAD_EXT_FILE')) { + $files = explode(',',C('LOAD_EXT_FILE')); + foreach ($files as $file){ + $file = COMMON_PATH.$file.'.php'; + if(is_file($file)) include $file; + } + } + // 加载自定义的动态配置文件 + if(C('LOAD_EXT_CONFIG')) { + $configs = C('LOAD_EXT_CONFIG'); + if(is_string($configs)) $configs = explode(',',$configs); + foreach ($configs as $key=>$config){ + $file = CONF_PATH.$config.'.php'; + if(is_file($file)) { + is_numeric($key)?C(include $file):C($key,include $file); + } + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Lite/Action.class.php b/ThinkPHP/Extend/Mode/Lite/Action.class.php new file mode 100644 index 0000000..c6699f8 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Lite/Action.class.php @@ -0,0 +1,344 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP Action控制器基类 精简模式 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +abstract class Action { + + // 当前Action名称 + private $name = ''; + protected $tVar = array(); // 模板输出变量 + + /** + * 架构函数 取得模板对象实例 + * @access public + */ + public function __construct() { + tag('action_begin'); + //控制器初始化 + if(method_exists($this,'_initialize')) + $this->_initialize(); + } + + /** + * 获取当前Action名称 + * @access protected + */ + protected function getActionName() { + if(empty($this->name)) { + // 获取Action名称 + $this->name = substr(get_class($this),0,-6); + } + return $this->name; + } + + /** + * 是否AJAX请求 + * @access protected + * @return bool + */ + protected function isAjax() { + if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) ) { + if('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) + return true; + } + if(!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) + // 判断Ajax方式提交 + return true; + return false; + } + + /** + * 模板变量赋值 + * @access public + * @param mixed $name + * @param mixed $value + */ + public function assign($name,$value=''){ + if(is_array($name)) { + $this->tVar = array_merge($this->tVar,$name); + }elseif(is_object($name)){ + foreach($name as $key =>$val) + $this->tVar[$key] = $val; + }else { + $this->tVar[$name] = $value; + } + } + + public function __set($name,$value) { + $this->assign($name,$value); + } + + /** + * 取得模板变量的值 + * @access public + * @param string $name + * @return mixed + */ + public function get($name){ + if(isset($this->tVar[$name])) + return $this->tVar[$name]; + else + return false; + } + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $args 参数 + * @return mixed + */ + public function __call($method,$args) { + if( 0 === strcasecmp($method,ACTION_NAME)) { + if(method_exists($this,'_empty')) { + // 如果定义了_empty操作 则调用 + $this->_empty($method,$args); + }elseif(file_exists_case(C('TEMPLATE_NAME'))){ + // 检查是否存在默认模版 如果有直接输出模版 + $this->display(); + }else{ + // 抛出异常 + throw_exception(L('_ERROR_ACTION_').ACTION_NAME); + } + }else{ + switch(strtolower($method)) { + // 判断提交方式 + case 'ispost': + case 'isget': + case 'ishead': + case 'isdelete': + case 'isput': + return strtolower($_SERVER['REQUEST_METHOD']) == strtolower(substr($method,2)); + // 获取变量 支持过滤和默认值 调用方式 $this->_post($key,$filter,$default); + case '_get': $input =& $_GET;break; + case '_post':$input =& $_POST;break; + case '_put': parse_str(file_get_contents('php://input'), $input);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; + default: + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + } + if(isset($input[$args[0]])) { // 取值操作 + $data = $input[$args[0]]; + $filters = isset($args[1])?$args[1]:C('DEFAULT_FILTER'); + if($filters) {// 2012/3/23 增加多方法过滤支持 + $filters = explode(',',$filters); + foreach($filters as $filter){ + if(function_exists($filter)) { + $data = is_array($data)?array_map($filter,$data):$filter($data); // 参数过滤 + } + } + } + }else{ // 变量默认值 + $data = isset($args[2])?$args[2]:NULL; + } + return $data; + } + } + + /** + * 操作错误跳转的快捷方法 + * @access protected + * @param string $message 错误信息 + * @param string $jumpUrl 页面跳转地址 + * @param Boolean $ajax 是否为Ajax方式 + * @return void + */ + protected function error($message,$jumpUrl='',$ajax=false) { + $this->dispatchJump($message,0,$jumpUrl,$ajax); + } + + /** + * 操作成功跳转的快捷方法 + * @access protected + * @param string $message 提示信息 + * @param string $jumpUrl 页面跳转地址 + * @param Boolean $ajax 是否为Ajax方式 + * @return void + */ + protected function success($message,$jumpUrl='',$ajax=false) { + $this->dispatchJump($message,1,$jumpUrl,$ajax); + } + + /** + * Ajax方式返回数据到客户端 + * @access protected + * @param mixed $data 要返回的数据 + * @param String $info 提示信息 + * @param boolean $status 返回状态 + * @param String $status ajax返回类型 JSON XML + * @return void + */ + protected function ajaxReturn($data,$info='',$status=1,$type='') { + $result = array(); + $result['status'] = $status; + $result['info'] = $info; + $result['data'] = $data; + //扩展ajax返回数据, 在Action中定义function ajaxAssign(&$result){} 方法 扩展ajax返回数据。 + if(method_exists($this,"ajaxAssign")) + $this->ajaxAssign($result); + if(empty($type)) $type = C('DEFAULT_AJAX_RETURN'); + if(strtoupper($type)=='JSON') { + // 返回JSON数据格式到客户端 包含状态信息 + header("Content-Type:text/html; charset=utf-8"); + exit(json_encode($result)); + }elseif(strtoupper($type)=='XML'){ + // 返回xml格式数据 + header("Content-Type:text/xml; charset=utf-8"); + exit(xml_encode($result)); + } + } + + /** + * Action跳转(URL重定向) 支持指定模块和延时跳转 + * @access protected + * @param string $url 跳转的URL表达式 + * @param array $params 其它URL参数 + * @param integer $delay 延时跳转的时间 单位为秒 + * @param string $msg 跳转提示信息 + * @return void + */ + protected function redirect($url,$params=array(),$delay=0,$msg='') { + $url = U($url,$params); + redirect($url,$delay,$msg); + } + + /** + * 默认跳转操作 支持错误导向和正确跳转 + * 调用模板显示 默认为public目录下面的success页面 + * 提示页面为可配置 支持模板标签 + * @param string $message 提示信息 + * @param Boolean $status 状态 + * @param string $jumpUrl 页面跳转地址 + * @param Boolean $ajax 是否为Ajax方式 + * @access private + * @return void + */ + private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) { + // 判断是否为AJAX返回 + if($ajax || $this->isAjax()) $this->ajaxReturn($ajax,$message,$status); + if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl); + // 提示标题 + $this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_')); + //如果设置了关闭窗口,则提示完毕后自动关闭窗口 + if($this->get('closeWin')) $this->assign('jumpUrl','javascript:window.close();'); + $this->assign('status',$status); // 状态 + //保证输出不受静态缓存影响 + C('HTML_CACHE_ON',false); + if($status) { //发送成功信息 + $this->assign('message',$message);// 提示信息 + // 成功操作后默认停留1秒 + if(!$this->get('waitSecond')) $this->assign('waitSecond',"1"); + // 默认操作成功自动返回操作前页面 + if(!$this->get('jumpUrl')) $this->assign("jumpUrl",$_SERVER["HTTP_REFERER"]); + $this->display(C('TMPL_ACTION_SUCCESS')); + }else{ + $this->assign('error',$message);// 提示信息 + //发生错误时候默认停留3秒 + if(!$this->get('waitSecond')) $this->assign('waitSecond',"3"); + // 默认发生错误的话自动返回上页 + if(!$this->get('jumpUrl')) $this->assign('jumpUrl',"javascript:history.back(-1);"); + $this->display(C('TMPL_ACTION_ERROR')); + // 中止执行 避免出错后继续执行 + exit ; + } + } + + /** + * 加载模板和页面输出 可以返回输出内容 + * @access public + * @param string $templateFile 模板文件名 + * @param string $charset 模板输出字符集 + * @param string $contentType 输出类型 + * @return mixed + */ + public function display($templateFile='',$charset='',$contentType='') { + G('viewStartTime'); + // 视图开始标签 + tag('view_begin',$templateFile); + // 解析并获取模板内容 + $content = $this->fetch($templateFile); + // 输出模板内容 + $this->show($content,$charset,$contentType); + // 视图结束标签 + tag('view_end'); + } + + /** + * 输出内容文本可以包括Html + * @access public + * @param string $content 输出内容 + * @param string $charset 模板输出字符集 + * @param string $contentType 输出类型 + * @return mixed + */ + public function show($content,$charset='',$contentType=''){ + if(empty($charset)) $charset = C('DEFAULT_CHARSET'); + if(empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE'); + // 网页字符编码 + header("Content-Type:".$contentType."; charset=".$charset); + header("Cache-control: private"); //支持页面回跳 + header("X-Powered-By:TOPThink/".THINK_VERSION); + // 输出模板文件 + echo $content; + } + + /** + * 解析和获取模板内容 用于输出 + * @access public + * @param string $templateFile 模板文件名 + * @return string + */ + public function fetch($templateFile='') { + // 模板文件解析标签 + tag('view_template',$templateFile); + // 模板文件不存在直接返回 + if(!is_file($templateFile)) return NULL; + // 页面缓存 + ob_start(); + ob_implicit_flush(0); + // 视图解析标签 + $params = array('var'=>$this->tVar,'file'=>$templateFile); + $result = tag('view_parse',$params); + if(false === $result) { // 未定义行为 则采用PHP原生模板 + // 模板阵列变量分解成为独立变量 + extract($this->tVar, EXTR_OVERWRITE); + // 直接载入PHP模板 + include $templateFile; + } + // 获取并清空缓存 + $content = ob_get_clean(); + // 内容过滤标签 + tag('view_filter',$content); + // 输出模板文件 + return $content; + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 保存日志 + if(C('LOG_RECORD')) Log::save(); + // 执行后续操作 + tag('action_end'); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Lite/App.class.php b/ThinkPHP/Extend/Mode/Lite/App.class.php new file mode 100644 index 0000000..6743367 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Lite/App.class.php @@ -0,0 +1,76 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 应用程序类 精简模式 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class App { + + /** + * 运行应用实例 入口文件使用的快捷方法 + * @access public + * @return void + */ + static public function run() { + // 设置系统时区 + date_default_timezone_set(C('DEFAULT_TIMEZONE')); + // 加载动态项目公共文件和配置 + load_ext_file(); + // 项目初始化标签 + tag('app_init'); + // URL调度 + Dispatcher::dispatch(); + // 项目开始标签 + tag('app_begin'); + // Session初始化 支持其他客户端 + if(isset($_REQUEST[C("VAR_SESSION_ID")])) + session_id($_REQUEST[C("VAR_SESSION_ID")]); + if(C('SESSION_AUTO_START')) session_start(); + // 记录应用初始化时间 + if(C('SHOW_RUN_TIME')) G('initTime'); + App::exec(); + // 项目结束标签 + tag('app_end'); + // 保存日志记录 + if(C('LOG_RECORD')) Log::save(); + return ; + } + + /** + * 执行应用程序 + * @access public + * @return void + * @throws ThinkExecption + */ + static public function exec() { + // 安全检测 + if(!preg_match('/^[A-Za-z_0-9]+$/',MODULE_NAME)){ + throw_exception(L('_MODULE_NOT_EXIST_')); + } + //创建Action控制器实例 + $group = defined('GROUP_NAME') ? GROUP_NAME.'/' : ''; + $module = A($group.MODULE_NAME); + if(!$module) { + // 是否定义Empty模块 + $module = A("Empty"); + if(!$module) + // 模块不存在 抛出异常 + throw_exception(L('_MODULE_NOT_EXIST_').MODULE_NAME); + } + //执行当前操作 + call_user_func(array(&$module,ACTION_NAME)); + return ; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Lite/Db.class.php b/ThinkPHP/Extend/Mode/Lite/Db.class.php new file mode 100644 index 0000000..34f4be1 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Lite/Db.class.php @@ -0,0 +1,801 @@ + +// +---------------------------------------------------------------------- + +define('CLIENT_MULTI_RESULTS', 131072); +/** + * ThinkPHP 精简模式数据库中间层实现类 只支持Mysql + */ +class Db { + + static private $_instance = null; + // 是否自动释放查询结果 + protected $autoFree = false; + // 是否显示调试信息 如果启用会在日志文件记录sql语句 + public $debug = false; + // 是否使用永久连接 + protected $pconnect = false; + // 当前SQL指令 + protected $queryStr = ''; + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 当前连接ID + protected $linkID = null; + // 当前查询ID + protected $queryID = null; + // 是否已经连接数据库 + protected $connected = false; + // 数据库连接参数配置 + protected $config = ''; + // 数据库表达式 + protected $comparison = array('eq'=>'=','neq'=>'!=','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE'); + // 查询表达式 + protected $selectSql = 'SELECT%DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%'; + /** + * 架构函数 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysql') ) { + throw_exception(L('_NOT_SUPPERT_').':mysql'); + } + $this->config = $this->parseConfig($config); + if(APP_DEBUG) { + $this->debug = true; + } + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect() { + if(!$this->connected) { + $config = $this->config; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + if($pconnect) { + $this->linkID = mysql_pconnect( $host, $config['username'], $config['password'],CLIENT_MULTI_RESULTS); + }else{ + $this->linkID = mysql_connect( $host, $config['username'], $config['password'],true,CLIENT_MULTI_RESULTS); + } + if ( !$this->linkID || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID)) ) { + throw_exception(mysql_error()); + } + $dbVersion = mysql_get_server_info($this->linkID); + if ($dbVersion >= "4.1") { + //使用UTF8存取数据库 需要mysql 4.1.0以上支持 + mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID); + } + //设置 sql_model + if($dbVersion >'5.0.1'){ + mysql_query("SET sql_mode=''",$this->linkID); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + unset($this->config); + } + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mysql_free_result($this->queryID); + $this->queryID = 0; + } + + /** + * 执行查询 主要针对 SELECT, SHOW 等指令 + * 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + * @throws ThinkExecption + */ + public function query($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mysql_query($this->queryStr, $this->linkID); + $this->debug(); + if ( !$this->queryID ) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 针对 INSERT, UPDATE 以及DELETE + * @access public + * @param string $str sql指令 + * @return integer + * @throws ThinkExecption + */ + public function execute($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_write',1); + $result = mysql_query($this->queryStr, $this->linkID) ; + $this->debug(); + if ( false === $result) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_affected_rows($this->linkID); + $this->lastInsID = mysql_insert_id($this->linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + * @throws ThinkExecption + */ + public function startTrans() { + $this->connect(true); + if ( !$this->linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mysql_query('START TRANSACTION', $this->linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function commit() { + if ($this->transTimes > 0) { + $result = mysql_query('COMMIT', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = mysql_query('ROLLBACK', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access public + * @return array + * @throws ThinkExecption + */ + public function getAll() { + if ( !$this->queryID ) { + throw_exception($this->error()); + return false; + } + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mysql_fetch_assoc($this->queryID)){ + $result[] = $row; + } + mysql_data_seek($this->queryID,0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query('SHOW COLUMNS FROM '.$tableName); + $info = array(); + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + if(!empty($dbName)) { + $sql = 'SHOW TABLES FROM '.$dbName; + }else{ + $sql = 'SHOW TABLES '; + } + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + * @throws ThinkExecption + */ + public function close() { + if (!empty($this->queryID)) + mysql_free_result($this->queryID); + if ($this->linkID && !mysql_close($this->linkID)){ + throw_exception($this->error()); + } + $this->linkID = 0; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mysql_error($this->linkID); + if($this->queryStr!=''){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escapeString($str) { + return mysql_escape_string($str); + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 关闭连接 + $this->close(); + } + + /** + * 取得数据库类实例 + * @static + * @access public + * @return mixed 返回数据库驱动类 + */ + public static function getInstance($db_config='') { + if ( self::$_instance==null ){ + self::$_instance = new Db($db_config); + } + return self::$_instance; + } + + /** + * 分析数据库配置信息,支持数组和DSN + * @access private + * @param mixed $db_config 数据库配置信息 + * @return string + */ + private function parseConfig($db_config='') { + if ( !empty($db_config) && is_string($db_config)) { + // 如果DSN字符串则进行解析 + $db_config = $this->parseDSN($db_config); + }else if(empty($db_config)){ + // 如果配置为空,读取配置文件设置 + $db_config = array ( + 'dbms' => C('DB_TYPE'), + 'username' => C('DB_USER'), + 'password' => C('DB_PWD'), + 'hostname' => C('DB_HOST'), + 'hostport' => C('DB_PORT'), + 'database' => C('DB_NAME'), + 'dsn' => C('DB_DSN'), + 'params' => C('DB_PARAMS'), + ); + } + return $db_config; + } + + /** + * DSN解析 + * 格式: mysql://username:passwd@localhost:3306/DbName + * @static + * @access public + * @param string $dsnStr + * @return array + */ + public function parseDSN($dsnStr) { + if( empty($dsnStr) ){return false;} + $info = parse_url($dsnStr); + if($info['scheme']){ + $dsn = array( + 'dbms' => $info['scheme'], + 'username' => isset($info['user']) ? $info['user'] : '', + 'password' => isset($info['pass']) ? $info['pass'] : '', + 'hostname' => isset($info['host']) ? $info['host'] : '', + 'hostport' => isset($info['port']) ? $info['port'] : '', + 'database' => isset($info['path']) ? substr($info['path'],1) : '' + ); + }else { + preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); + $dsn = array ( + 'dbms' => $matches[1], + 'username' => $matches[2], + 'password' => $matches[3], + 'hostname' => $matches[4], + 'hostport' => $matches[5], + 'database' => $matches[6] + ); + } + return $dsn; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + // 记录操作结束时间 + if ( $this->debug ) { + G('queryEndTime'); + Log::record($this->queryStr." [ RunTime:".G('queryStartTime','queryEndTime',6)."s ]",Log::SQL); + } + } + + /** + * 设置锁机制 + * @access protected + * @return string + */ + protected function parseLock($lock=false) { + if(!$lock) return ''; + if('ORACLE' == $this->dbType) { + return ' FOR UPDATE NOWAIT '; + } + return ' FOR UPDATE '; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) // 过滤非标量数据 + $set[] = $this->parseKey($key).'='.$value; + } + return ' SET '.implode(',',$set); + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = '\''.$this->escapeString($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escapeString($value[1]); + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return string + */ + protected function parseField($fields) { + if(is_array($fields)) { + // 完善数组方式传字段名的支持 + // 支持 'field1'=>'field2' 这样的字段别名定义 + $array = array(); + foreach ($fields as $key=>$field){ + if(!is_numeric($key)) + $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); + else + $array[] = $this->parseKey($field); + } + $fieldsStr = implode(',', $array); + }elseif(is_string($fields) && !empty($fields)) { + $fieldsStr = $this->parseKey($fields); + }else{ + $fieldsStr = '*'; + } + return $fieldsStr; + } + + /** + * table分析 + * @access protected + * @param mixed $table + * @return string + */ + protected function parseTable($tables) { + if(is_string($tables)) + $tables = explode(',',$tables); + array_walk($tables, array(&$this, 'parseKey')); + return implode(',',$tables); + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return string + */ + protected function parseWhere($where) { + $whereStr = ''; + if(is_string($where)) { + // 直接使用字符串条件 + $whereStr = $where; + }else{ // 使用数组条件表达式 + if(isset($where['_logic'])) { + // 定义逻辑运算规则 例如 OR XOR AND NOT + $operate = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + // 默认进行 AND 运算 + $operate = ' AND '; + } + foreach ($where as $key=>$val){ + $whereStr .= "( "; + if(0===strpos($key,'_')) { + // 解析特殊条件表达式 + $whereStr .= $this->parseThinkWhere($key,$val); + }else{ + $key = $this->parseKey($key); + if(is_array($val)) { + if(is_string($val[0])) { + if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|NOTLIKE|LIKE)$/i',$val[0])) { // 比较运算 + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + }elseif('exp'==strtolower($val[0])){ // 使用表达式 + $whereStr .= ' ('.$key.' '.$val[1].') '; + }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 + $zone = is_array($val[1])? implode(',',$this->parseValue($val[1])):$val[1]; + $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; + }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $whereStr .= ' ('.$key.' BETWEEN '.$data[0].' AND '.$data[1].' )'; + }else{ + throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]); + } + }else { + $count = count($val); + if(in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) { + $rule = strtoupper(trim($val[$count-1])); + $count = $count -1; + }else{ + $rule = 'AND'; + } + for($i=0;$i<$count;$i++) { + $data = is_array($val[$i])?$val[$i][1]:$val[$i]; + if('exp'==strtolower($val[$i][0])) { + $whereStr .= '('.$key.' '.$data.') '.$rule.' '; + }else{ + $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; + $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' '; + } + } + $whereStr = substr($whereStr,0,-4); + } + }else { + //对字符串类型字段采用模糊匹配 + if(C('LIKE_MATCH_FIELDS') && preg_match('/('.C('LIKE_MATCH_FIELDS').')/i',$key)) { + $val = '%'.$val.'%'; + $whereStr .= $key." LIKE ".$this->parseValue($val); + }else { + $whereStr .= $key." = ".$this->parseValue($val); + } + } + } + $whereStr .= ' )'.$operate; + } + $whereStr = substr($whereStr,0,-strlen($operate)); + } + return empty($whereStr)?'':' WHERE '.$whereStr; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $whereStr = ''; + switch($key) { + case '_string': + // 字符串模式查询条件 + $whereStr = $val; + break; + case '_complex': + // 复合查询条件 + $whereStr = substr($this->parseWhere($val),6); + break; + case '_query': + // 字符串模式查询条件 + parse_str($val,$where); + if(isset($where['_logic'])) { + $op = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + $op = ' AND '; + } + $array = array(); + foreach ($where as $field=>$data) + $array[] = $this->parseKey($field).' = '.$this->parseValue($data); + $whereStr = implode($op,$array); + break; + } + return $whereStr; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + return !empty($limit)? ' LIMIT '.$limit.' ':''; + } + + /** + * join分析 + * @access protected + * @param mixed $join + * @return string + */ + protected function parseJoin($join) { + $joinStr = ''; + if(!empty($join)) { + if(is_array($join)) { + foreach ($join as $key=>$_join){ + if(false !== stripos($_join,'JOIN')) + $joinStr .= ' '.$_join; + else + $joinStr .= ' LEFT JOIN ' .$_join; + } + }else{ + $joinStr .= ' LEFT JOIN ' .$join; + } + } + return $joinStr; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + return !empty($order)? ' ORDER BY '.$order:''; + } + + /** + * group分析 + * @access protected + * @param mixed $group + * @return string + */ + protected function parseGroup($group) { + return !empty($group)? ' GROUP BY '.$group:''; + } + + /** + * having分析 + * @access protected + * @param string $having + * @return string + */ + protected function parseHaving($having) { + return !empty($having)? ' HAVING '.$having:''; + } + + /** + * distinct分析 + * @access protected + * @param mixed $distinct + * @return string + */ + protected function parseDistinct($distinct) { + return !empty($distinct)? ' DISTINCT ' :''; + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @return false | integer + */ + public function insert($data,$options=array()) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = 'INSERT INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(isset($options['where'])?$options['where']:'') + .$this->parseOrder(isset($options['order'])?$options['order']:'') + .$this->parseLimit(isset($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(isset($options['where'])?$options['where']:'') + .$this->parseOrder(isset($options['order'])?$options['order']:'') + .$this->parseLimit(isset($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return array + */ + public function select($options=array()) { + if(isset($options['page'])) { + // 根据页数计算limit + list($page,$listRows) = explode(',',$options['page']); + $listRows = $listRows?$listRows:($options['limit']?$options['limit']:20); + $offset = $listRows*((int)$page-1); + $options['limit'] = $offset.','.$listRows; + } + $sql = str_replace( + array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'), + array( + $this->parseTable($options['table']), + $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), + $this->parseField(isset($options['field'])?$options['field']:'*'), + $this->parseJoin(isset($options['join'])?$options['join']:''), + $this->parseWhere(isset($options['where'])?$options['where']:''), + $this->parseGroup(isset($options['group'])?$options['group']:''), + $this->parseHaving(isset($options['having'])?$options['having']:''), + $this->parseOrder(isset($options['order'])?$options['order']:''), + $this->parseLimit(isset($options['limit'])?$options['limit']:'') + ),$this->selectSql); + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->query($sql); + } + + /** + * 字段和表名添加` + * 保证指令中使用关键字不出错 针对mysql + * @access protected + * @param mixed $value + * @return mixed + */ + protected function parseKey(&$value) { + $value = trim($value); + if( false !== strpos($value,' ') || false !== strpos($value,',') || false !== strpos($value,'*') || false !== strpos($value,'(') || false !== strpos($value,'.') || false !== strpos($value,'`')) { + //如果包含* 或者 使用了sql方法 则不作处理 + }else{ + $value = '`'.$value.'`'; + } + return $value; + } + + /** + * 获取最近一次查询的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID(){ + return $this->lastInsID; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Lite/Dispatcher.class.php b/ThinkPHP/Extend/Mode/Lite/Dispatcher.class.php new file mode 100644 index 0000000..99224cc --- /dev/null +++ b/ThinkPHP/Extend/Mode/Lite/Dispatcher.class.php @@ -0,0 +1,149 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP内置的Dispatcher类 用于精简模式 + * 完成URL解析、路由和调度 + * @category Think + * @package Think + * @subpackage Util + * @author liu21st + * @version $Id: Dispatcher.class.php 2702 2012-02-02 12:35:01Z liu21st $ + */ +class Dispatcher { + + /** + * URL映射到控制器 + * @access public + * @return void + */ + static public function dispatch() { + $urlMode = C('URL_MODEL'); + if($urlMode == URL_COMPAT || !empty($_GET[C('VAR_PATHINFO')])){ + // 兼容模式判断 + define('PHP_FILE',_PHP_FILE_.'?'.C('VAR_PATHINFO').'='); + $_SERVER['PATH_INFO'] = $_GET[C('VAR_PATHINFO')]; + unset($_GET[C('VAR_PATHINFO')]); + }elseif($urlMode == URL_REWRITE ) { + //当前项目地址 + $url = dirname(_PHP_FILE_); + if($url == '/' || $url == '\\') + $url = ''; + define('PHP_FILE',$url); + }else { + //当前项目地址 + define('PHP_FILE',_PHP_FILE_); + } + + // 分析PATHINFO信息 + tag('path_info'); + // 分析PATHINFO信息 + $depr = C('URL_PATHINFO_DEPR'); + if(!empty($_SERVER['PATH_INFO'])) { + if(C('URL_HTML_SUFFIX') && !empty($_SERVER['PATH_INFO'])) { + $_SERVER['PATH_INFO'] = preg_replace('/\.'.trim(C('URL_HTML_SUFFIX'),'.').'$/', '', $_SERVER['PATH_INFO']); + } + if(!self::routerCheck()){ // 检测路由规则 如果没有则按默认规则调度URL + $paths = explode($depr,trim($_SERVER['PATH_INFO'],'/')); + $var = array(); + if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){ + $var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : ''; + } + if(!isset($_GET[C('VAR_MODULE')])) {// 还没有定义模块名称 + $var[C('VAR_MODULE')] = array_shift($paths); + } + $var[C('VAR_ACTION')] = array_shift($paths); + // 解析剩余的URL参数 + $res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths)); + $_GET = array_merge($var,$_GET); + } + } + + // 获取分组 模块和操作名称 + if (C('APP_GROUP_LIST')) { + define('GROUP_NAME', self::getGroup(C('VAR_GROUP'))); + } + define('MODULE_NAME',self::getModule(C('VAR_MODULE'))); + define('ACTION_NAME',self::getAction(C('VAR_ACTION'))); + // URL常量 + define('__SELF__',$_SERVER['REQUEST_URI']); + // 当前项目地址 + define('__APP__',PHP_FILE); + // 当前模块和分组地址 + $module = defined('P_MODULE_NAME')?P_MODULE_NAME:MODULE_NAME; + if(defined('GROUP_NAME')) { + $group = C('URL_CASE_INSENSITIVE') ?strtolower(GROUP_NAME):GROUP_NAME; + define('__GROUP__', GROUP_NAME == C('DEFAULT_GROUP') ?__APP__ : __APP__.'/'.$group); + define('__URL__', __GROUP__.$depr.$module); + }else{ + define('__URL__',__APP__.'/'.$module); + } + // 当前操作地址 + define('__ACTION__',__URL__.$depr.ACTION_NAME); + //保证$_REQUEST正常取值 + $_REQUEST = array_merge($_POST,$_GET); + } + + /** + * 路由检测 + * @access public + * @return void + */ + static public function routerCheck() { + $return = false; + // 路由检测标签 + tag('route_check',$return); + return $return; + } + + /** + * 获得实际的模块名称 + * @access private + * @return string + */ + static private function getModule($var) { + $module = (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_MODULE')); + unset($_GET[$var]); + if(C('URL_CASE_INSENSITIVE')) { + // URL地址不区分大小写 + define('P_MODULE_NAME',strtolower($module)); + // 智能识别方式 index.php/user_type/index/ 识别到 UserTypeAction 模块 + $module = ucfirst(parse_name(P_MODULE_NAME,1)); + } + return $module; + } + + /** + * 获得实际的操作名称 + * @access private + * @return string + */ + static private function getAction($var) { + $action = !empty($_POST[$var]) ? + $_POST[$var] : + (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION')); + unset($_POST[$var],$_GET[$var]); + define('P_ACTION_NAME',$action); + return C('URL_CASE_INSENSITIVE')?strtolower($action):$action; + } + + /** + * 获得实际的分组名称 + * @access private + * @return string + */ + static private function getGroup($var) { + $group = (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_GROUP')); + unset($_GET[$var]); + return ucfirst(strtolower($group)); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Lite/Model.class.php b/ThinkPHP/Extend/Mode/Lite/Model.class.php new file mode 100644 index 0000000..d2bd579 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Lite/Model.class.php @@ -0,0 +1,1083 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 精简模式Model模型类 + * 只支持CURD和连贯操作 以及常用查询 去掉回调接口 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Model { + // 操作状态 + const MODEL_INSERT = 1; // 插入模型数据 + const MODEL_UPDATE = 2; // 更新模型数据 + const MODEL_BOTH = 3; // 包含上面两种方式 + const MUST_VALIDATE = 1;// 必须验证 + const EXISTS_VALIDATE = 0;// 表单存在字段则验证 + const VALUE_VALIDATE = 2;// 表单值不为空则验证 + + // 当前数据库操作对象 + protected $db = null; + // 主键名称 + protected $pk = 'id'; + // 数据表前缀 + protected $tablePrefix = ''; + // 模型名称 + protected $name = ''; + // 数据库名称 + protected $dbName = ''; + // 数据表名(不包含表前缀) + protected $tableName = ''; + // 实际数据表名(包含表前缀) + protected $trueTableName =''; + // 最近错误信息 + protected $error = ''; + // 字段信息 + protected $fields = array(); + // 数据信息 + protected $data = array(); + // 查询表达式参数 + protected $options = array(); + protected $_validate = array(); // 自动验证定义 + protected $_auto = array(); // 自动完成定义 + // 是否自动检测数据表字段信息 + protected $autoCheckFields = true; + // 是否批处理验证 + protected $patchValidate = false; + + /** + * 架构函数 + * 取得DB类的实例对象 字段检查 + * @param string $name 模型名称 + * @param string $tablePrefix 表前缀 + * @param mixed $connection 数据库连接信息 + * @access public + */ + public function __construct($name='',$tablePrefix='',$connection='') { + // 模型初始化 + $this->_initialize(); + // 获取模型名称 + if(!empty($name)) { + if(strpos($name,'.')) { // 支持 数据库名.模型名的 定义 + list($this->dbName,$this->name) = explode('.',$name); + }else{ + $this->name = $name; + } + }elseif(empty($this->name)){ + $this->name = $this->getModelName(); + } + if(!empty($tablePrefix)) { + $this->tablePrefix = $tablePrefix; + } + // 设置表前缀 + $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX'); + // 数据库初始化操作 + // 获取数据库操作对象 + // 当前模型有独立的数据库连接信息 + $this->db(0,empty($this->connection)?$connection:$this->connection); + // 字段检测 + if(!empty($this->name) && $this->autoCheckFields) $this->_checkTableInfo(); + } + + /** + * 自动检测数据表信息 + * @access protected + * @return void + */ + protected function _checkTableInfo() { + // 如果不是Model类 自动记录数据表信息 + // 只在第一次执行记录 + if(empty($this->fields)) { + // 如果数据表字段没有定义则自动获取 + if(C('DB_FIELDS_CACHE')) { + $db = $this->dbName?$this->dbName:C('DB_NAME'); + $this->fields = F('_fields/'.$db.'.'.$this->name); + if(!$this->fields) $this->flush(); + }else{ + // 每次都会读取数据表信息 + $this->flush(); + } + } + } + + /** + * 获取字段信息并缓存 + * @access public + * @return void + */ + public function flush() { + // 缓存不存在则查询数据表信息 + $fields = $this->db->getFields($this->getTableName()); + if(!$fields) { // 无法获取字段信息 + return false; + } + $this->fields = array_keys($fields); + $this->fields['_autoinc'] = false; + foreach ($fields as $key=>$val){ + // 记录字段类型 + $type[$key] = $val['type']; + if($val['primary']) { + $this->fields['_pk'] = $key; + if($val['autoinc']) $this->fields['_autoinc'] = true; + } + } + // 记录字段类型信息 + if(C('DB_FIELDTYPE_CHECK')) $this->fields['_type'] = $type; + + // 2008-3-7 增加缓存开关控制 + if(C('DB_FIELDS_CACHE')){ + // 永久缓存数据表信息 + $db = $this->dbName?$this->dbName:C('DB_NAME'); + F('_fields/'.$db.'.'.$this->name,$this->fields); + } + } + + /** + * 设置数据对象的值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return void + */ + public function __set($name,$value) { + // 设置数据对象属性 + $this->data[$name] = $value; + } + + /** + * 获取数据对象的值 + * @access public + * @param string $name 名称 + * @return mixed + */ + public function __get($name) { + return isset($this->data[$name])?$this->data[$name]:null; + } + + /** + * 检测数据对象的值 + * @access public + * @param string $name 名称 + * @return boolean + */ + public function __isset($name) { + return isset($this->data[$name]); + } + + /** + * 销毁数据对象的值 + * @access public + * @param string $name 名称 + * @return void + */ + public function __unset($name) { + unset($this->data[$name]); + } + + /** + * 利用__call方法实现一些特殊的Model方法 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(in_array(strtolower($method),array('table','where','order','limit','page','alias','having','group','lock','distinct'),true)) { + // 连贯操作的实现 + $this->options[strtolower($method)] = $args[0]; + return $this; + }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){ + // 统计查询的实现 + $field = isset($args[0])?$args[0]:'*'; + return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method); + }elseif(strtolower(substr($method,0,5))=='getby') { + // 根据某个字段获取记录 + $field = parse_name(substr($method,5)); + $where[$field] = $args[0]; + return $this->where($where)->find(); + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } + // 回调方法 初始化模型 + protected function _initialize() {} + + /** + * 对保存到数据库的数据进行处理 + * @access protected + * @param mixed $data 要操作的数据 + * @return boolean + */ + protected function _facade($data) { + // 检查非数据字段 + if(!empty($this->fields)) { + foreach ($data as $key=>$val){ + if(!in_array($key,$this->fields,true)){ + unset($data[$key]); + }elseif(C('DB_FIELDTYPE_CHECK') && is_scalar($val)) { + // 字段类型检查 + $this->_parseType($data,$key); + } + } + } + return $data; + } + + /** + * 新增数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return mixed + */ + public function add($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 分析表达式 + $options = $this->_parseOptions($options); + // 数据处理 + $data = $this->_facade($data); + // 写入数据到数据库 + $result = $this->db->insert($data,$options); + if(false !== $result ) { + $insertId = $this->getLastInsID(); + if($insertId) { + // 自增主键返回插入ID + return $insertId; + } + } + return $result; + } + + /** + * 保存数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return boolean + */ + public function save($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 数据处理 + $data = $this->_facade($data); + // 分析表达式 + $options = $this->_parseOptions($options); + if(!isset($options['where']) ) { + // 如果存在主键数据 则自动作为更新条件 + if(isset($data[$this->getPk()])) { + $pk = $this->getPk(); + $where[$pk] = $data[$pk]; + $options['where'] = $where; + unset($data[$pk]); + }else{ + // 如果没有任何更新条件则不执行 + $this->error = L('_OPERATION_WRONG_'); + return false; + } + } + $result = $this->db->update($data,$options); + return $result; + } + + /** + * 删除数据 + * @access public + * @param mixed $options 表达式 + * @return mixed + */ + public function delete($options=array()) { + if(empty($options) && empty($this->options['where'])) { + // 如果删除条件为空 则删除当前数据对象所对应的记录 + if(!empty($this->data) && isset($this->data[$this->getPk()])) + return $this->delete($this->data[$this->getPk()]); + else + return false; + } + if(is_numeric($options) || is_string($options)) { + // 根据主键删除记录 + $pk = $this->getPk(); + if(strpos($options,',')) { + $where[$pk] = array('IN', $options); + }else{ + $where[$pk] = $options; + $pkValue = $options; + } + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + $result= $this->db->delete($options); + // 返回删除记录个数 + return $result; + } + + /** + * 查询数据集 + * @access public + * @param array $options 表达式参数 + * @return mixed + */ + public function select($options=array()) { + if(is_string($options) || is_numeric($options)) { + // 根据主键查询 + $pk = $this->getPk(); + if(strpos($options,',')) { + $where[$pk] = array('IN',$options); + }else{ + $where[$pk] = $options; + } + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(false === $resultSet) { + return false; + } + if(empty($resultSet)) { // 查询结果为空 + return null; + } + return $resultSet; + } + + /** + * 分析表达式 + * @access proteced + * @param array $options 表达式参数 + * @return array + */ + protected function _parseOptions($options=array()) { + if(is_array($options)) + $options = array_merge($this->options,$options); + // 查询过后清空sql表达式组装 避免影响下次查询 + $this->options = array(); + if(!isset($options['table'])) + // 自动获取表名 + $options['table'] =$this->getTableName(); + if(!empty($options['alias'])) { + $options['table'] .= ' '.$options['alias']; + } + // 字段类型验证 + if(C('DB_FIELDTYPE_CHECK')) { + if(isset($options['where']) && is_array($options['where'])) { + // 对数组查询条件进行字段类型检查 + foreach ($options['where'] as $key=>$val){ + if(in_array($key,$this->fields,true) && is_scalar($val)){ + $this->_parseType($options['where'],$key); + } + } + } + } + return $options; + } + + /** + * 数据类型检测 + * @access protected + * @param mixed $data 数据 + * @param string $key 字段名 + * @return void + */ + protected function _parseType(&$data,$key) { + $fieldType = strtolower($this->fields['_type'][$key]); + if(false !== strpos($fieldType,'int')) { + $data[$key] = intval($data[$key]); + }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){ + $data[$key] = floatval($data[$key]); + }elseif(false !== strpos($fieldType,'bool')){ + $data[$key] = (bool)$data[$key]; + } + } + + /** + * 查询数据 + * @access public + * @param mixed $options 表达式参数 + * @return mixed + */ + public function find($options=array()) { + if(is_numeric($options) || is_string($options)) { + $where[$this->getPk()] =$options; + $options = array(); + $options['where'] = $where; + } + // 总是查找一条记录 + $options['limit'] = 1; + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(false === $resultSet) { + return false; + } + if(empty($resultSet)) {// 查询结果为空 + return null; + } + $this->data = $resultSet[0]; + return $this->data; + } + + /** + * 设置记录的某个字段值 + * 支持使用数据库字段和方法 + * @access public + * @param string|array $field 字段名 + * @param string|array $value 字段值 + * @return boolean + */ + public function setField($field,$value) { + if(is_array($field)) { + $data = $field; + }else{ + $data[$field] = $value; + } + return $this->save($data); + } + + /** + * 字段值增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @return boolean + */ + public function setInc($field,$step=1) { + return $this->setField($field,array('exp',$field.'+'.$step)); + } + + /** + * 字段值减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @return boolean + */ + public function setDec($field,$step=1) { + return $this->setField($field,array('exp',$field.'-'.$step)); + } + + /** + * 获取一条记录的某个字段值 + * @access public + * @param string $field 字段名 + * @param string $spea 字段数据间隔符号 + * @return mixed + */ + public function getField($field,$sepa=null) { + $options['field'] = $field; + $options = $this->_parseOptions($options); + if(strpos($field,',')) { // 多字段 + $resultSet = $this->db->select($options); + if(!empty($resultSet)) { + $_field = explode(',', $field); + $field = array_keys($resultSet[0]); + $move = $_field[0]==$_field[1]?false:true; + $key = array_shift($field); + $key2 = array_shift($field); + $cols = array(); + $count = count($_field); + foreach ($resultSet as $result){ + $name = $result[$key]; + if($move) { // 删除键值记录 + unset($result[$key]); + } + if(2==$count) { + $cols[$name] = $result[$key2]; + }else{ + $cols[$name] = is_null($sepa)?$result:implode($sepa,$result); + } + } + return $cols; + } + }else{ // 查找一条记录 + $options['limit'] = 1; + $result = $this->db->select($options); + if(!empty($result)) { + return reset($result[0]); + } + } + return null; + } + + /** + * 创建数据对象 但不保存到数据库 + * @access public + * @param mixed $data 创建数据 + * @param string $type 状态 + * @return mixed + */ + public function create($data='',$type='') { + // 如果没有传值默认取POST数据 + if(empty($data)) { + $data = $_POST; + }elseif(is_object($data)){ + $data = get_object_vars($data); + } + // 验证数据 + if(empty($data) || !is_array($data)) { + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + + // 状态 + $type = $type?$type:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT); + + // 数据自动验证 + if(!$this->autoValidation($data,$type)) return false; + + // 验证完成生成数据对象 + if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据 + $vo = array(); + foreach ($this->fields as $key=>$name){ + if(substr($key,0,1)=='_') continue; + $val = isset($data[$name])?$data[$name]:null; + //保证赋值有效 + if(!is_null($val)){ + $vo[$name] = (MAGIC_QUOTES_GPC && is_string($val))? stripslashes($val) : $val; + } + } + }else{ + $vo = $data; + } + + // 创建完成对数据进行自动处理 + $this->autoOperation($vo,$type); + // 赋值当前数据对象 + $this->data = $vo; + // 返回创建的数据以供其他调用 + return $vo; + } + + /** + * 使用正则验证数据 + * @access public + * @param string $value 要验证的数据 + * @param string $rule 验证规则 + * @return boolean + */ + public function regex($value,$rule) { + $validate = array( + 'require'=> '/.+/', + 'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/', + 'url' => '/^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/', + 'currency' => '/^\d+(\.\d+)?$/', + 'number' => '/^\d+$/', + 'zip' => '/^[1-9]\d{5}$/', + 'integer' => '/^[-\+]?\d+$/', + 'double' => '/^[-\+]?\d+(\.\d+)?$/', + 'english' => '/^[A-Za-z]+$/', + ); + // 检查是否有内置的正则表达式 + if(isset($validate[strtolower($rule)])) + $rule = $validate[strtolower($rule)]; + return preg_match($rule,$value)===1; + } + + /** + * 自动表单处理 + * @access public + * @param array $data 创建数据 + * @param string $type 创建类型 + * @return mixed + */ + private function autoOperation(&$data,$type) { + // 自动填充 + if(!empty($this->_auto)) { + foreach ($this->_auto as $auto){ + // 填充因子定义格式 + // array('field','填充内容','填充条件','附加规则',[额外参数]) + if(empty($auto[2])) $auto[2] = self::MODEL_INSERT; // 默认为新增的时候自动填充 + if( $type == $auto[2] || $auto[2] == self::MODEL_BOTH) { + switch($auto[3]) { + case 'function': // 使用函数进行填充 字段的值作为参数 + case 'callback': // 使用回调方法 + $args = isset($auto[4])?$auto[4]:array(); + if(isset($data[$auto[0]])) { + array_unshift($args,$data[$auto[0]]); + } + if('function'==$auto[3]) { + $data[$auto[0]] = call_user_func_array($auto[1], $args); + }else{ + $data[$auto[0]] = call_user_func_array(array(&$this,$auto[1]), $args); + } + break; + case 'field': // 用其它字段的值进行填充 + $data[$auto[0]] = $data[$auto[1]]; + break; + case 'string': + default: // 默认作为字符串填充 + $data[$auto[0]] = $auto[1]; + } + if(false === $data[$auto[0]] ) unset($data[$auto[0]]); + } + } + } + return $data; + } + + /** + * 自动表单验证 + * @access protected + * @param array $data 创建数据 + * @param string $type 创建类型 + * @return boolean + */ + protected function autoValidation($data,$type) { + // 属性验证 + if(!empty($this->_validate)) { // 如果设置了数据自动验证则进行数据验证 + if($this->patchValidate) { // 重置验证错误信息 + $this->error = array(); + } + foreach($this->_validate as $key=>$val) { + // 验证因子定义格式 + // array(field,rule,message,condition,type,when,params) + // 判断是否需要执行验证 + if(empty($val[5]) || $val[5]== self::MODEL_BOTH || $val[5]== $type ) { + if(0==strpos($val[2],'{%') && strpos($val[2],'}')) + // 支持提示信息的多语言 使用 {%语言定义} 方式 + $val[2] = L(substr($val[2],2,-1)); + $val[3] = isset($val[3])?$val[3]:self::EXISTS_VALIDATE; + $val[4] = isset($val[4])?$val[4]:'regex'; + // 判断验证条件 + switch($val[3]) { + case self::MUST_VALIDATE: // 必须验证 不管表单是否有设置该字段 + if(false === $this->_validationField($data,$val)) + return false; + break; + case self::VALUE_VALIDATE: // 值不为空的时候才验证 + if('' != trim($data[$val[0]])) + if(false === $this->_validationField($data,$val)) + return false; + break; + default: // 默认表单存在该字段就验证 + if(isset($data[$val[0]])) + if(false === $this->_validationField($data,$val)) + return false; + } + } + } + // 批量验证的时候最后返回错误 + if(!empty($this->error)) return false; + } + return true; + } + + /** + * 验证表单字段 支持批量验证 + * 如果批量验证返回错误的数组信息 + * @access protected + * @param array $data 创建数据 + * @param array $val 验证因子 + * @return boolean + */ + protected function _validationField($data,$val) { + if(false === $this->_validationFieldItem($data,$val)){ + if($this->patchValidate) { + $this->error[$val[0]] = $val[2]; + }else{ + $this->error = $val[2]; + return false; + } + } + return ; + } + + /** + * 根据验证因子验证字段 + * @access protected + * @param array $data 创建数据 + * @param array $val 验证因子 + * @return boolean + */ + protected function _validationFieldItem($data,$val) { + switch($val[4]) { + case 'function':// 使用函数进行验证 + case 'callback':// 调用方法进行验证 + $args = isset($val[6])?$val[6]:array(); + array_unshift($args,$data[$val[0]]); + if('function'==$val[4]) { + return call_user_func_array($val[1], $args); + }else{ + return call_user_func_array(array(&$this, $val[1]), $args); + } + case 'confirm': // 验证两个字段是否相同 + return $data[$val[0]] == $data[$val[1]]; + case 'unique': // 验证某个值是否唯一 + if(is_string($val[0]) && strpos($val[0],',')) + $val[0] = explode(',',$val[0]); + $map = array(); + if(is_array($val[0])) { + // 支持多个字段验证 + foreach ($val[0] as $field) + $map[$field] = $data[$field]; + }else{ + $map[$val[0]] = $data[$val[0]]; + } + if(!empty($data[$this->getPk()])) { // 完善编辑的时候验证唯一 + $map[$this->getPk()] = array('neq',$data[$this->getPk()]); + } + if($this->where($map)->find()) return false; + return true; + default: // 检查附加规则 + return $this->check($data[$val[0]],$val[1],$val[4]); + } + } + + /** + * 验证数据 支持 in between equal length regex expire ip_allow ip_deny + * @access public + * @param string $value 验证数据 + * @param mixed $rule 验证表达式 + * @param string $type 验证方式 默认为正则验证 + * @return boolean + */ + public function check($value,$rule,$type='regex'){ + switch(strtolower($type)) { + case 'in': // 验证是否在某个指定范围之内 逗号分隔字符串或者数组 + $range = is_array($rule)?$rule:explode(',',$rule); + return in_array($value ,$range); + case 'between': // 验证是否在某个范围 + list($min,$max) = explode(',',$rule); + return $value>=$min && $value<=$max; + case 'equal': // 验证是否等于某个值 + return $value == $rule; + case 'length': // 验证长度 + $length = mb_strlen($value,'utf-8'); // 当前数据长度 + if(strpos($rule,',')) { // 长度区间 + list($min,$max) = explode(',',$rule); + return $length >= $min && $length <= $max; + }else{// 指定长度 + return $length == $rule; + } + case 'expire': + list($start,$end) = explode(',',$rule); + if(!is_numeric($start)) $start = strtotime($start); + if(!is_numeric($end)) $end = strtotime($end); + return $_SERVER['REQUEST_TIME'] >= $start && $_SERVER['REQUEST_TIME'] <= $end; + case 'ip_allow': // IP 操作许可验证 + return in_array(get_client_ip(),explode(',',$rule)); + case 'ip_deny': // IP 操作禁止验证 + return !in_array(get_client_ip(),explode(',',$rule)); + case 'regex': + default: // 默认使用正则验证 可以使用验证类中定义的验证名称 + // 检查附加规则 + return $this->regex($value,$rule); + } + } + + /** + * SQL查询 + * @access public + * @param mixed $sql SQL指令 + * @return mixed + */ + public function query($sql) { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + return $this->db->query($sql); + }else{ + return false; + } + } + + /** + * 执行SQL语句 + * @access public + * @param string $sql SQL指令 + * @return false | integer + */ + public function execute($sql) { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + return $this->db->execute($sql); + }else { + return false; + } + } + + /** + * 切换当前的数据库连接 + * @access public + * @param integer $linkNum 连接序号 + * @param mixed $config 数据库连接信息 + * @param array $params 模型参数 + * @return Model + */ + public function db($linkNum,$config='',$params=array()){ + static $_db = array(); + if(!isset($_db[$linkNum])) { + // 创建一个新的实例 + if(!empty($config) && false === strpos($config,'/')) { // 支持读取配置参数 + $config = C($config); + } + $_db[$linkNum] = Db::getInstance($config); + }elseif(NULL === $config){ + $_db[$linkNum]->close(); // 关闭数据库连接 + unset($_db[$linkNum]); + return ; + } + if(!empty($params)) { + if(is_string($params)) parse_str($params,$params); + foreach ($params as $name=>$value){ + $this->setProperty($name,$value); + } + } + // 切换数据库连接 + $this->db = $_db[$linkNum]; + return $this; + } + + /** + * 得到当前的数据对象名称 + * @access public + * @return string + */ + public function getModelName() { + if(empty($this->name)) + $this->name = substr(get_class($this),0,-5); + return $this->name; + } + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + $this->trueTableName = strtolower($tableName); + } + return (!empty($this->dbName)?$this->dbName.'.':'').$this->trueTableName; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->commit(); + $this->db->startTrans(); + return ; + } + + /** + * 提交事务 + * @access public + * @return boolean + */ + public function commit() { + return $this->db->commit(); + } + + /** + * 事务回滚 + * @access public + * @return boolean + */ + public function rollback() { + return $this->db->rollback(); + } + + /** + * 返回模型的错误信息 + * @access public + * @return string + */ + public function getError() { + return $this->error; + } + + /** + * 返回数据库的错误信息 + * @access public + * @return string + */ + public function getDbError() { + return $this->db->getError(); + } + + /** + * 返回最后插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->db->getLastInsID(); + } + + /** + * 返回最后执行的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->db->getLastSql(); + } + // 鉴于getLastSql比较常用 增加_sql 别名 + public function _sql(){ + return $this->getLastSql(); + } + + /** + * 获取主键名称 + * @access public + * @return string + */ + public function getPk() { + return isset($this->fields['_pk'])?$this->fields['_pk']:$this->pk; + } + + /** + * 获取数据表字段信息 + * @access public + * @return array + */ + public function getDbFields(){ + if($this->fields) { + $fields = $this->fields; + unset($fields['_autoinc'],$fields['_pk'],$fields['_type']); + return $fields; + } + return false; + } + + /** + * 指定查询字段 支持字段排除 + * @access public + * @param mixed $field + * @param boolean $except 是否排除 + * @return Model + */ + public function field($field,$except=false){ + if($except) {// 字段排除 + if(is_string($field)) { + $field = explode(',',$field); + } + $fields = $this->getDbFields(); + $field = $fields?array_diff($fields,$field):$field; + } + $this->options['field'] = $field; + return $this; + } + + /** + * 设置数据对象值 + * @access public + * @param mixed $data 数据 + * @return Model + */ + public function data($data){ + if(is_object($data)){ + $data = get_object_vars($data); + }elseif(is_string($data)){ + parse_str($data,$data); + }elseif(!is_array($data)){ + throw_exception(L('_DATA_TYPE_INVALID_')); + } + $this->data = $data; + return $this; + } + + /** + * 查询SQL组装 join + * @access public + * @param mixed $join + * @return Model + */ + public function join($join) { + if(is_array($join)) + $this->options['join'] = $join; + else + $this->options['join'][] = $join; + return $this; + } + + /** + * 查询SQL组装 union + * @access public + * @param array $union + * @return Model + */ + public function union($union) { + if(empty($union)) return $this; + // 转换union表达式 + if($union instanceof Model) { + $options = $union->getProperty('options'); + if(!isset($options['table'])){ + // 自动获取表名 + $options['table'] =$union->getTableName(); + } + if(!isset($options['field'])) { + $options['field'] =$this->options['field']; + } + }elseif(is_object($union)) { + $options = get_object_vars($union); + }elseif(!is_array($union)){ + throw_exception(L('_DATA_TYPE_INVALID_')); + } + $this->options['union'][] = $options; + return $this; + } + + /** + * 设置模型的属性值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return Model + */ + public function setProperty($name,$value) { + if(property_exists($this,$name)) + $this->$name = $value; + return $this; + } + + /** + * 获取模型的属性值 + * @access public + * @param string $name 名称 + * @return mixed + */ + public function getProperty($name){ + if(property_exists($this,$name)) + return $this->$name; + else + return NULL; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Lite/tags.php b/ThinkPHP/Extend/Mode/Lite/tags.php new file mode 100644 index 0000000..cad9350 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Lite/tags.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- + +// 核心行为扩展列表文件 +return array( + 'app_begin'=>array( + 'CheckTemplate', // 模板检测 + ), + 'route_check'=>array('CheckRoute', // 路由检测 + ), + 'app_end'=>array( + 'ShowPageTrace', // 页面Trace显示 + ), + 'view_template'=>array( + 'LocationTemplate', // 自动定位模板文件 + ), + 'view_parse'=>array( + 'ParseTemplate', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 + ), + 'view_filter'=>array( + 'ContentReplace', // 模板输出替换 + 'ShowRuntime', // 运行时间显示 + ), +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Phprpc/Action.class.php b/ThinkPHP/Extend/Mode/Phprpc/Action.class.php new file mode 100644 index 0000000..77d19d9 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Phprpc/Action.class.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP AMF模式Action控制器基类 + */ +abstract class Action { + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $parms 参数 + * @return mixed + */ + public function __call($method,$parms) { + // 如果定义了_empty操作 则调用 + if(method_exists($this,'_empty')) { + $this->_empty($method,$parms); + } + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Phprpc/App.class.php b/ThinkPHP/Extend/Mode/Phprpc/App.class.php new file mode 100644 index 0000000..a29a0dd --- /dev/null +++ b/ThinkPHP/Extend/Mode/Phprpc/App.class.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP AMF模式应用程序类 + */ +class App { + + /** + * 应用程序初始化 + * @access public + * @return void + */ + static public function run() { + + //导入类库 + Vendor('phpRPC.phprpc_server'); + //实例化phprpc + $server = new PHPRPC_Server(); + $actions = explode(',',C('APP_PHPRPC_ACTIONS')); + foreach ($actions as $action){ + //$server -> setClass($action.'Action'); + $temp = $action.'Action'; + $methods = get_class_methods($temp); + $server->add($methods,new $temp); + } + if(APP_DEBUG) { + $server->setDebugMode(true); + } + $server->setEnableGZIP(true); + $server->start(); + //C('PHPRPC_COMMENT',$server->comment()); + echo $server->comment(); + // 保存日志记录 + if(C('LOG_RECORD')) Log::save(); + return ; + } + +}; \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Phprpc/Db.class.php b/ThinkPHP/Extend/Mode/Phprpc/Db.class.php new file mode 100644 index 0000000..eb440f3 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Phprpc/Db.class.php @@ -0,0 +1,799 @@ + +// +---------------------------------------------------------------------- + +define('CLIENT_MULTI_RESULTS', 131072); +/** + * ThinkPHP AMF模式数据库中间层实现类 只支持Mysql + */ +class Db { + + static private $_instance = null; + // 是否自动释放查询结果 + protected $autoFree = false; + // 是否显示调试信息 如果启用会在日志文件记录sql语句 + public $debug = false; + // 是否使用永久连接 + protected $pconnect = false; + // 当前SQL指令 + protected $queryStr = ''; + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 当前连接ID + protected $linkID = null; + // 当前查询ID + protected $queryID = null; + // 是否已经连接数据库 + protected $connected = false; + // 数据库连接参数配置 + protected $config = ''; + // 数据库表达式 + protected $comparison = array('eq'=>'=','neq'=>'!=','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE'); + // 查询表达式 + protected $selectSql = 'SELECT%DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%'; + /** + * 架构函数 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysql') ) { + throw_exception(L('_NOT_SUPPERT_').':mysql'); + } + $this->config = $this->parseConfig($config); + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect() { + if(!$this->connected) { + $config = $this->config; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); + if($this->pconnect) { + $this->linkID = mysql_pconnect( $host, $config['username'], $config['password'],CLIENT_MULTI_RESULTS); + }else{ + $this->linkID = mysql_connect( $host, $config['username'], $config['password'],true,CLIENT_MULTI_RESULTS); + } + if ( !$this->linkID || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID)) ) { + throw_exception(mysql_error()); + } + $dbVersion = mysql_get_server_info($this->linkID); + if ($dbVersion >= "4.1") { + //使用UTF8存取数据库 需要mysql 4.1.0以上支持 + mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID); + } + //设置 sql_model + if($dbVersion >'5.0.1'){ + mysql_query("SET sql_mode=''",$this->linkID); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + unset($this->config); + } + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mysql_free_result($this->queryID); + $this->queryID = 0; + } + + /** + * 执行查询 主要针对 SELECT, SHOW 等指令 + * 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + * @throws ThinkExecption + */ + public function query($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mysql_query($this->queryStr, $this->linkID); + $this->debug(); + if ( !$this->queryID ) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 针对 INSERT, UPDATE 以及DELETE + * @access public + * @param string $str sql指令 + * @return integer + * @throws ThinkExecption + */ + public function execute($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = mysql_query($this->queryStr, $this->linkID) ; + $this->debug(); + if ( false === $result) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_affected_rows($this->linkID); + $this->lastInsID = mysql_insert_id($this->linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + * @throws ThinkExecption + */ + public function startTrans() { + $this->connect(true); + if ( !$this->linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mysql_query('START TRANSACTION', $this->linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function commit() { + if ($this->transTimes > 0) { + $result = mysql_query('COMMIT', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = mysql_query('ROLLBACK', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access public + * @return array + * @throws ThinkExecption + */ + public function getAll() { + if ( !$this->queryID ) { + throw_exception($this->error()); + return false; + } + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mysql_fetch_assoc($this->queryID)){ + $result[] = $row; + } + mysql_data_seek($this->queryID,0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query('SHOW COLUMNS FROM '.$tableName); + $info = array(); + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + if(!empty($dbName)) { + $sql = 'SHOW TABLES FROM '.$dbName; + }else{ + $sql = 'SHOW TABLES '; + } + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + * @throws ThinkExecption + */ + public function close() { + if (!empty($this->queryID)) + mysql_free_result($this->queryID); + if ($this->linkID && !mysql_close($this->linkID)){ + throw_exception($this->error()); + } + $this->linkID = 0; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mysql_error($this->linkID); + if($this->queryStr!=''){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escape_string($str) { + return mysql_escape_string($str); + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 关闭连接 + $this->close(); + } + + /** + * 取得数据库类实例 + * @static + * @access public + * @return mixed 返回数据库驱动类 + */ + public static function getInstance($db_config='') { + if ( self::$_instance==null ){ + self::$_instance = new Db($db_config); + } + return self::$_instance; + } + + /** + * 分析数据库配置信息,支持数组和DSN + * @access private + * @param mixed $db_config 数据库配置信息 + * @return string + */ + private function parseConfig($db_config='') { + if ( !empty($db_config) && is_string($db_config)) { + // 如果DSN字符串则进行解析 + $db_config = $this->parseDSN($db_config); + }else if(empty($db_config)){ + // 如果配置为空,读取配置文件设置 + $db_config = array ( + 'dbms' => C('DB_TYPE'), + 'username' => C('DB_USER'), + 'password' => C('DB_PWD'), + 'hostname' => C('DB_HOST'), + 'hostport' => C('DB_PORT'), + 'database' => C('DB_NAME'), + 'dsn' => C('DB_DSN'), + 'params' => C('DB_PARAMS'), + ); + } + return $db_config; + } + + /** + * DSN解析 + * 格式: mysql://username:passwd@localhost:3306/DbName + * @static + * @access public + * @param string $dsnStr + * @return array + */ + public function parseDSN($dsnStr) { + if( empty($dsnStr) ){return false;} + $info = parse_url($dsnStr); + if($info['scheme']){ + $dsn = array( + 'dbms' => $info['scheme'], + 'username' => isset($info['user']) ? $info['user'] : '', + 'password' => isset($info['pass']) ? $info['pass'] : '', + 'hostname' => isset($info['host']) ? $info['host'] : '', + 'hostport' => isset($info['port']) ? $info['port'] : '', + 'database' => isset($info['path']) ? substr($info['path'],1) : '' + ); + }else { + preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); + $dsn = array ( + 'dbms' => $matches[1], + 'username' => $matches[2], + 'password' => $matches[3], + 'hostname' => $matches[4], + 'hostport' => $matches[5], + 'database' => $matches[6] + ); + } + return $dsn; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + // 记录操作结束时间 + if ( $this->debug ) { + G('queryEndTime'); + Log::record($this->queryStr." [ RunTime:".G('queryStartTime','queryEndTime',6)."s ]",Log::SQL); + } + } + + /** + * 设置锁机制 + * @access protected + * @return string + */ + protected function parseLock($lock=false) { + if(!$lock) return ''; + if('ORACLE' == $this->dbType) { + return ' FOR UPDATE NOWAIT '; + } + return ' FOR UPDATE '; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) // 过滤非标量数据 + $set[] = $this->parseKey($key).'='.$value; + } + return ' SET '.implode(',',$set); + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = '\''.$this->escape_string($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escape_string($value[1]); + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return string + */ + protected function parseField($fields) { + if(is_array($fields)) { + // 完善数组方式传字段名的支持 + // 支持 'field1'=>'field2' 这样的字段别名定义 + $array = array(); + foreach ($fields as $key=>$field){ + if(!is_numeric($key)) + $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); + else + $array[] = $this->parseKey($field); + } + $fieldsStr = implode(',', $array); + }elseif(is_string($fields) && !empty($fields)) { + $fieldsStr = $this->parseKey($fields); + }else{ + $fieldsStr = '*'; + } + return $fieldsStr; + } + + /** + * table分析 + * @access protected + * @param mixed $table + * @return string + */ + protected function parseTable($tables) { + if(is_string($tables)) + $tables = explode(',',$tables); + array_walk($tables, array(&$this, 'parseKey')); + return implode(',',$tables); + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return string + */ + protected function parseWhere($where) { + $whereStr = ''; + if(is_string($where)) { + // 直接使用字符串条件 + $whereStr = $where; + }else{ // 使用数组条件表达式 + if(isset($where['_logic'])) { + // 定义逻辑运算规则 例如 OR XOR AND NOT + $operate = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + // 默认进行 AND 运算 + $operate = ' AND '; + } + foreach ($where as $key=>$val){ + $whereStr .= "( "; + if(0===strpos($key,'_')) { + // 解析特殊条件表达式 + $whereStr .= $this->parseThinkWhere($key,$val); + }else{ + $key = $this->parseKey($key); + if(is_array($val)) { + if(is_string($val[0])) { + if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|NOTLIKE|LIKE)$/i',$val[0])) { // 比较运算 + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + }elseif('exp'==strtolower($val[0])){ // 使用表达式 + $whereStr .= ' ('.$key.' '.$val[1].') '; + }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 + $zone = is_array($val[1])? implode(',',$this->parseValue($val[1])):$val[1]; + $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; + }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $whereStr .= ' ('.$key.' BETWEEN '.$data[0].' AND '.$data[1].' )'; + }else{ + throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]); + } + }else { + $count = count($val); + if(in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) { + $rule = strtoupper(trim($val[$count-1])); + $count = $count -1; + }else{ + $rule = 'AND'; + } + for($i=0;$i<$count;$i++) { + $data = is_array($val[$i])?$val[$i][1]:$val[$i]; + if('exp'==strtolower($val[$i][0])) { + $whereStr .= '('.$key.' '.$data.') '.$rule.' '; + }else{ + $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; + $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' '; + } + } + $whereStr = substr($whereStr,0,-4); + } + }else { + //对字符串类型字段采用模糊匹配 + if(C('LIKE_MATCH_FIELDS') && preg_match('/('.C('LIKE_MATCH_FIELDS').')/i',$key)) { + $val = '%'.$val.'%'; + $whereStr .= $key." LIKE ".$this->parseValue($val); + }else { + $whereStr .= $key." = ".$this->parseValue($val); + } + } + } + $whereStr .= ' )'.$operate; + } + $whereStr = substr($whereStr,0,-strlen($operate)); + } + return empty($whereStr)?'':' WHERE '.$whereStr; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $whereStr = ''; + switch($key) { + case '_string': + // 字符串模式查询条件 + $whereStr = $val; + break; + case '_complex': + // 复合查询条件 + $whereStr = substr($this->parseWhere($val),6); + break; + case '_query': + // 字符串模式查询条件 + parse_str($val,$where); + if(isset($where['_logic'])) { + $op = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + $op = ' AND '; + } + $array = array(); + foreach ($where as $field=>$data) + $array[] = $this->parseKey($field).' = '.$this->parseValue($data); + $whereStr = implode($op,$array); + break; + } + return $whereStr; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + return !empty($limit)? ' LIMIT '.$limit.' ':''; + } + + /** + * join分析 + * @access protected + * @param mixed $join + * @return string + */ + protected function parseJoin($join) { + $joinStr = ''; + if(!empty($join)) { + if(is_array($join)) { + foreach ($join as $key=>$_join){ + if(false !== stripos($_join,'JOIN')) + $joinStr .= ' '.$_join; + else + $joinStr .= ' LEFT JOIN ' .$_join; + } + }else{ + $joinStr .= ' LEFT JOIN ' .$join; + } + } + return $joinStr; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + return !empty($order)? ' ORDER BY '.$order:''; + } + + /** + * group分析 + * @access protected + * @param mixed $group + * @return string + */ + protected function parseGroup($group) { + return !empty($group)? ' GROUP BY '.$group:''; + } + + /** + * having分析 + * @access protected + * @param string $having + * @return string + */ + protected function parseHaving($having) { + return !empty($having)? ' HAVING '.$having:''; + } + + /** + * distinct分析 + * @access protected + * @param mixed $distinct + * @return string + */ + protected function parseDistinct($distinct) { + return !empty($distinct)? ' DISTINCT ' :''; + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @return false | integer + */ + public function insert($data,$options=array()) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = 'INSERT INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(isset($options['where'])?$options['where']:'') + .$this->parseOrder(isset($options['order'])?$options['order']:'') + .$this->parseLimit(isset($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(isset($options['where'])?$options['where']:'') + .$this->parseOrder(isset($options['order'])?$options['order']:'') + .$this->parseLimit(isset($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->execute($sql); + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return array + */ + public function select($options=array()) { + if(isset($options['page'])) { + // 根据页数计算limit + list($page,$listRows) = explode(',',$options['page']); + $listRows = $listRows?$listRows:($options['limit']?$options['limit']:20); + $offset = $listRows*((int)$page-1); + $options['limit'] = $offset.','.$listRows; + } + $sql = str_replace( + array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'), + array( + $this->parseTable($options['table']), + $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), + $this->parseField(isset($options['field'])?$options['field']:'*'), + $this->parseJoin(isset($options['join'])?$options['join']:''), + $this->parseWhere(isset($options['where'])?$options['where']:''), + $this->parseGroup(isset($options['group'])?$options['group']:''), + $this->parseHaving(isset($options['having'])?$options['having']:''), + $this->parseOrder(isset($options['order'])?$options['order']:''), + $this->parseLimit(isset($options['limit'])?$options['limit']:'') + ),$this->selectSql); + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $this->query($sql); + } + + /** + * 字段和表名添加` + * 保证指令中使用关键字不出错 针对mysql + * @access protected + * @param mixed $value + * @return mixed + */ + protected function parseKey(&$value) { + $value = trim($value); + if( false !== strpos($value,' ') || false !== strpos($value,',') || false !== strpos($value,'*') || false !== strpos($value,'(') || false !== strpos($value,'.') || false !== strpos($value,'`')) { + //如果包含* 或者 使用了sql方法 则不作处理 + }else{ + $value = '`'.$value.'`'; + } + return $value; + } + + /** + * 获取最近一次查询的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID(){ + return $this->lastInsID; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Phprpc/Model.class.php b/ThinkPHP/Extend/Mode/Phprpc/Model.class.php new file mode 100644 index 0000000..aff13f0 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Phprpc/Model.class.php @@ -0,0 +1,469 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP Phprpc模式Model模型类 + * 只支持CURD和连贯操作 以及常用查询 去掉回调接口 + */ +class Model { + // 当前数据库操作对象 + protected $db = null; + // 主键名称 + protected $pk = 'id'; + // 数据表前缀 + protected $tablePrefix = ''; + // 模型名称 + protected $name = ''; + // 数据库名称 + protected $dbName = ''; + // 数据表名(不包含表前缀) + protected $tableName = ''; + // 实际数据表名(包含表前缀) + protected $trueTableName =''; + // 数据信息 + protected $data = array(); + // 查询表达式参数 + protected $options = array(); + // 最近错误信息 + protected $error = ''; + + /** + * 架构函数 + * 取得DB类的实例对象 + * @param string $name 模型名称 + * @access public + */ + public function __construct($name='') { + // 模型初始化 + $this->_initialize(); + // 获取模型名称 + if(!empty($name)) { + $this->name = $name; + }elseif(empty($this->name)){ + $this->name = $this->getModelName(); + } + // 数据库初始化操作 + $this->db = Db::getInstance(empty($this->connection)?'':$this->connection); + // 设置表前缀 + $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX'); + // 字段检测 + if(!empty($this->name)) $this->_checkTableInfo(); + } + + /** + * 自动检测数据表信息 + * @access protected + * @return void + */ + protected function _checkTableInfo() { + // 如果不是Model类 自动记录数据表信息 + // 只在第一次执行记录 + if(empty($this->fields)) { + // 如果数据表字段没有定义则自动获取 + if(C('DB_FIELDS_CACHE')) { + $this->fields = F('_fields/'.$this->name); + if(!$this->fields) $this->flush(); + }else{ + // 每次都会读取数据表信息 + $this->flush(); + } + } + } + + /** + * 获取字段信息并缓存 + * @access public + * @return void + */ + public function flush() { + // 缓存不存在则查询数据表信息 + $fields = $this->db->getFields($this->getTableName()); + $this->fields = array_keys($fields); + $this->fields['_autoinc'] = false; + foreach ($fields as $key=>$val){ + // 记录字段类型 + $type[$key] = $val['type']; + if($val['primary']) { + $this->fields['_pk'] = $key; + if($val['autoinc']) $this->fields['_autoinc'] = true; + } + } + // 记录字段类型信息 + if(C('DB_FIELDTYPE_CHECK')) $this->fields['_type'] = $type; + + // 2008-3-7 增加缓存开关控制 + if(C('DB_FIELDS_CACHE')) + // 永久缓存数据表信息 + F('_fields/'.$this->name,$this->fields); + } + + // 回调方法 初始化模型 + protected function _initialize() {} + /** + * 利用__call方法实现一些特殊的Model方法 (魔术方法) + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(in_array(strtolower($method),array('field','table','where','order','limit','page','having','group','lock','distinct'),true)) { + // 连贯操作的实现 + $this->options[strtolower($method)] = $args[0]; + return $this; + }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){ + // 统计查询的实现 + $field = isset($args[0])?$args[0]:'*'; + return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method); + }elseif(strtolower(substr($method,0,5))=='getby') { + // 根据某个字段获取记录 + $field = parse_name(substr($method,5)); + $options['where'] = $field.'=\''.$args[0].'\''; + return $this->find($options); + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } + + /** + * 设置数据对象的值 (魔术方法) + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return void + */ + public function __set($name,$value) { + // 设置数据对象属性 + $this->data[$name] = $value; + } + + /** + * 获取数据对象的值 (魔术方法) + * @access public + * @param string $name 名称 + * @return mixed + */ + public function __get($name) { + return isset($this->data[$name])?$this->data[$name]:null; + } + + /** + * 新增数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return mixed + */ + public function add($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 分析表达式 + $options = $this->_parseOptions($options); + // 写入数据到数据库 + $result = $this->db->insert($data,$options); + $insertId = $this->getLastInsID(); + if($insertId) { + return $insertId; + } + //成功后返回插入ID + return $result; + } + + /** + * 保存数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return boolean + */ + public function save($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 分析表达式 + $options = $this->_parseOptions($options); + if(!isset($options['where']) ) { + // 如果存在主键数据 则自动作为更新条件 + if(isset($data[$this->getPk()])) { + $pk = $this->getPk(); + $options['where'] = $pk.'=\''.$data[$pk].'\''; + $pkValue = $data[$pk]; + unset($data[$pk]); + }else{ + // 如果没有任何更新条件则不执行 + $this->error = L('_OPERATION_WRONG_'); + return false; + } + } + return $this->db->update($data,$options); + } + + /** + * 删除数据 + * @access public + * @param mixed $options 表达式 + * @return mixed + */ + public function delete($options=array()) { + if(empty($options) && empty($this->options['where'])) { + // 如果删除条件为空 则删除当前数据对象所对应的记录 + if(!empty($this->data) && isset($this->data[$this->getPk()])) + return $this->delete($this->data[$this->getPk()]); + else + return false; + } + if(is_numeric($options) || is_string($options)) { + // 根据主键删除记录 + $pk = $this->getPk(); + $where = $pk.'=\''.$options.'\''; + $pkValue = $options; + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + return $this->db->delete($options); + } + + /** + * 查询数据集 + * @access public + * @param array $options 表达式参数 + * @return mixed + */ + public function select($options=array()) { + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(empty($resultSet)) { // 查询结果为空 + return false; + } + return $resultSet; + } + + /** + * 查询数据 + * @access public + * @param mixed $options 表达式参数 + * @return mixed + */ + public function find($options=array()) { + if(is_numeric($options) || is_string($options)) { + $where = $this->getPk().'=\''.$options.'\''; + $options = array(); + $options['where'] = $where; + } + // 总是查找一条记录 + $options['limit'] = 1; + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(empty($resultSet)) {// 查询结果为空 + return false; + } + $this->data = $resultSet[0]; + return $this->data; + } + + /** + * 分析表达式 + * @access private + * @param array $options 表达式参数 + * @return array + */ + private function _parseOptions($options) { + if(is_array($options)) + $options = array_merge($this->options,$options); + // 查询过后清空sql表达式组装 避免影响下次查询 + $this->options = array(); + if(!isset($options['table'])) + // 自动获取表名 + $options['table'] =$this->getTableName(); + return $options; + } + + /** + * 创建数据对象 但不保存到数据库 + * @access public + * @param mixed $data 创建数据 + * @param string $type 状态 + * @return mixed + */ + public function create($data='',$type='') { + // 如果没有传值默认取POST数据 + if(empty($data)) { + $data = $_POST; + }elseif(is_object($data)){ + $data = get_object_vars($data); + }elseif(!is_array($data)){ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + // 生成数据对象 + $vo = array(); + foreach ($this->fields as $key=>$name){ + if(substr($key,0,1)=='_') continue; + $val = isset($data[$name])?$data[$name]:null; + //保证赋值有效 + if(!is_null($val)){ + $vo[$name] = (MAGIC_QUOTES_GPC && is_string($val))? stripslashes($val) : $val; + if(C('DB_FIELDTYPE_CHECK')) { + // 字段类型检查 + $fieldType = strtolower($this->fields['_type'][$name]); + if(false !== strpos($fieldType,'int')) { + $vo[$name] = intval($vo[$name]); + }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){ + $vo[$name] = floatval($vo[$name]); + } + } + } + } + // 赋值当前数据对象 + $this->data = $vo; + // 返回创建的数据以供其他调用 + return $vo; + } + + /** + * SQL查询 + * @access public + * @param string $sql SQL指令 + * @return array + */ + public function query($sql) { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + return $this->db->query($sql); + }else{ + return false; + } + } + + /** + * 执行SQL语句 + * @access public + * @param string $sql SQL指令 + * @return false | integer + */ + public function execute($sql='') { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + return $this->db->execute($sql); + }else { + return false; + } + } + + /** + * 得到当前的数据对象名称 + * @access public + * @return string + */ + public function getModelName() { + if(empty($this->name)) { + $this->name = substr(get_class($this),0,-5); + } + return $this->name; + } + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + if(!empty($this->dbName)) { + $tableName = $this->dbName.'.'.$tableName; + } + $this->trueTableName = strtolower($tableName); + } + return $this->trueTableName; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->commit(); + $this->db->startTrans(); + return ; + } + + /** + * 提交事务 + * @access public + * @return boolean + */ + public function commit() { + return $this->db->commit(); + } + + /** + * 事务回滚 + * @access public + * @return boolean + */ + public function rollback() { + return $this->db->rollback(); + } + /** + * 获取主键名称 + * @access public + * @return string + */ + public function getPk() { + return isset($this->fields['_pk'])?$this->fields['_pk']:$this->pk; + } + + /** + * 返回最后执行的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->db->getLastSql(); + } + + /** + * 返回最后插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->db->getLastInsID(); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Phprpc/alias.php b/ThinkPHP/Extend/Mode/Phprpc/alias.php new file mode 100644 index 0000000..b864caf --- /dev/null +++ b/ThinkPHP/Extend/Mode/Phprpc/alias.php @@ -0,0 +1,19 @@ + +// +---------------------------------------------------------------------- + +// 导入别名定义 +alias_import(array( + 'Model' => MODE_PATH.'Phprpc/Model.class.php', + 'Db' => MODE_PATH.'Phprpc/Db.class.php', + 'Debug' => CORE_PATH.'Util/Debug.class.php', + 'Session' => CORE_PATH.'Util/Session.class.php', + ) +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Rest/Action.class.php b/ThinkPHP/Extend/Mode/Rest/Action.class.php new file mode 100644 index 0000000..51d6eb2 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Rest/Action.class.php @@ -0,0 +1,291 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP RESTFul 控制器基类 抽象类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +abstract class Action { + + // 当前Action名称 + private $name = ''; + // 视图实例 + protected $view = null; + protected $_method = ''; // 当前请求类型 + protected $_type = ''; // 当前资源类型 + // 输出类型 + protected $_types = array(); + + /** + * 架构函数 取得模板对象实例 + * @access public + */ + public function __construct() { + //实例化视图类 + $this->view = Think::instance('View'); + + defined('__EXT__') or define('__EXT__',''); + if(''== __EXT__ || false === stripos(C('REST_CONTENT_TYPE_LIST'),__EXT__)) { + // 资源类型没有指定或者非法 则用默认资源类型访问 + $this->_type = C('REST_DEFAULT_TYPE'); + }else{ + $this->_type = __EXT__; + } + + // 请求方式检测 + $method = strtolower($_SERVER['REQUEST_METHOD']); + if(false === stripos(C('REST_METHOD_LIST'),$method)) { + // 请求方式非法 则用默认请求方法 + $method = C('REST_DEFAULT_METHOD'); + } + $this->_method = $method; + // 允许输出的资源类型 + $this->_types = C('REST_OUTPUT_TYPE'); + + //控制器初始化 + if(method_exists($this,'_initialize')) + $this->_initialize(); + } + + /** + * 获取当前Action名称 + * @access protected + */ + protected function getActionName() { + if(empty($this->name)) { + // 获取Action名称 + $this->name = substr(get_class($this),0,-6); + } + return $this->name; + } + + /** + * 是否AJAX请求 + * @access protected + * @return bool + */ + protected function isAjax() { + if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) ) { + if('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) + return true; + } + if(!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) + // 判断Ajax方式提交 + return true; + return false; + } + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $args 参数 + * @return mixed + */ + public function __call($method,$args) { + if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) { + if(method_exists($this,$method.'_'.$this->_method.'_'.$this->_type)) { // RESTFul方法支持 + $fun = $method.'_'.$this->_method.'_'.$this->_type; + $this->$fun(); + }elseif($this->_method == C('REST_DEFAULT_METHOD') && method_exists($this,$method.'_'.$this->_type) ){ + $fun = $method.'_'.$this->_type; + $this->$fun(); + }elseif($this->_type == C('REST_DEFAULT_TYPE') && method_exists($this,$method.'_'.$this->_method) ){ + $fun = $method.'_'.$this->_method; + $this->$fun(); + }elseif(method_exists($this,'_empty')) { + // 如果定义了_empty操作 则调用 + $this->_empty($method,$args); + }elseif(file_exists_case(C('TMPL_FILE_NAME'))){ + // 检查是否存在默认模版 如果有直接输出模版 + $this->display(); + }else{ + // 抛出异常 + throw_exception(L('_ERROR_ACTION_').ACTION_NAME); + } + }else{ + switch(strtolower($method)) { + // 获取变量 支持过滤和默认值 调用方式 $this->_post($key,$filter,$default); + case '_get': $input =& $_GET;break; + case '_post':$input =& $_POST;break; + case '_put': + case '_delete':parse_str(file_get_contents('php://input'), $input);break; + case '_request': $input =& $_REQUEST;break; + case '_session': $input =& $_SESSION;break; + case '_cookie': $input =& $_COOKIE;break; + case '_server': $input =& $_SERVER;break; + default: + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + } + if(isset($input[$args[0]])) { // 取值操作 + $data = $input[$args[0]]; + $fun = $args[1]?$args[1]:C('DEFAULT_FILTER'); + $data = $fun($data); // 参数过滤 + }else{ // 变量默认值 + $data = isset($args[2])?$args[2]:NULL; + } + return $data; + } + } + + /** + * 模板显示 + * 调用内置的模板引擎显示方法, + * @access protected + * @param string $templateFile 指定要调用的模板文件 + * 默认为空 由系统自动定位模板文件 + * @param string $charset 输出编码 + * @param string $contentType 输出类型 + * @return void + */ + protected function display($templateFile='',$charset='',$contentType='') { + $this->view->display($templateFile,$charset,$contentType); + } + + /** + * 模板变量赋值 + * @access protected + * @param mixed $name 要显示的模板变量 + * @param mixed $value 变量的值 + * @return void + */ + protected function assign($name,$value='') { + $this->view->assign($name,$value); + } + + public function __set($name,$value) { + $this->view->assign($name,$value); + } + + /** + * 设置页面输出的CONTENT_TYPE和编码 + * @access public + * @param string $type content_type 类型对应的扩展名 + * @param string $charset 页面输出编码 + * @return void + */ + public function setContentType($type, $charset=''){ + if(headers_sent()) return; + if(empty($charset)) $charset = C('DEFAULT_CHARSET'); + $type = strtolower($type); + if(isset($this->_types[$type])) //过滤content_type + header('Content-Type: '.$this->_types[$type].'; charset='.$charset); + } + + /** + * 输出返回数据 + * @access protected + * @param mixed $data 要返回的数据 + * @param String $type 返回类型 JSON XML + * @param integer $code HTTP状态 + * @return void + */ + protected function response($data,$type='',$code=200) { + $this->sendHttpStatus($code); + exit($this->encodeData($data,strtolower($type))); + } + + /** + * 编码数据 + * @access protected + * @param mixed $data 要返回的数据 + * @param String $type 返回类型 JSON XML + * @return void + */ + protected function encodeData($data,$type='') { + if(empty($data)) return ''; + if(empty($type)) $type = $this->_type; + if('json' == $type) { + // 返回JSON数据格式到客户端 包含状态信息 + $data = json_encode($data); + }elseif('xml' == $type){ + // 返回xml格式数据 + $data = xml_encode($data); + }elseif('php'==$type){ + $data = serialize($data); + }// 默认直接输出 + $this->setContentType($type); + header('Content-Length: ' . strlen($data)); + return $data; + } + + // 发送Http状态信息 + protected function sendHttpStatus($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]); + } + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 保存日志 + if(C('LOG_RECORD')) Log::save(); + // 执行后续操作 + tag('action_end'); + } +} diff --git a/ThinkPHP/Extend/Mode/Rest/Behavior/CheckRestRouteBehavior.class.php b/ThinkPHP/Extend/Mode/Rest/Behavior/CheckRestRouteBehavior.class.php new file mode 100644 index 0000000..0297acb --- /dev/null +++ b/ThinkPHP/Extend/Mode/Rest/Behavior/CheckRestRouteBehavior.class.php @@ -0,0 +1,208 @@ + +// +---------------------------------------------------------------------- + +/** + * 系统行为扩展 REST路由检测 + */ +class CheckRestRouteBehavior extends Behavior { + // 行为参数定义(默认值) 可在项目配置中覆盖 + protected $options = array( + 'URL_ROUTER_ON' => false, // 是否开启URL路由 + 'URL_ROUTE_RULES' => array(), // 默认路由规则,注:分组配置无法替代 + ); + + /** + * 路由检测 + * @access public + * @return void + */ + public function run(&$return) { + $regx = trim($_SERVER['PATH_INFO'],'/'); + // 是否开启路由使用 + if(empty($regx) || !C('URL_ROUTER_ON')) $return = false; + // 路由定义文件优先于config中的配置定义 + $routes = C('URL_ROUTE_RULES'); + if(is_array(C('routes'))) $routes = C('routes'); + // 路由处理 + if(!empty($routes)) { + $depr = C('URL_PATHINFO_DEPR'); + foreach ($routes as $key=>$route){ + // 定义格式: array('路由规则或者正则','路由地址','路由参数','提交类型','资源类型') + if(isset($route[3]) && strtolower($_SERVER['REQUEST_METHOD']) != strtolower($route[3])) { + continue; // 如果设置了提交类型则过滤 + } + if(isset($route[4]) && !in_array(__EXT__,explode(',',$route[4]),true)) { + continue; // 如果设置了扩展名则过滤 + } + if(0===strpos($route[0],'/') && preg_match($route[0],$regx,$matches)) { // 正则路由 + return self::parseRegex($matches,$route,$regx); + }else{ // 规则路由 + $len1= substr_count($regx,'/'); + $len2 = substr_count($route[0],'/'); + if($len1>=$len2) { + if('$' == substr($route[0],-1,1)) {// 完整匹配 + if($len1 != $len2) { + continue; + }else{ + $route[0] = substr($route[0],0,-1); + } + } + $match = self::checkUrlMatch($regx,$route[0]); + if($match) return $return = self::parseRule($route,$regx); + } + } + } + } + $return = false; + } + + // 检测URL和规则路由是否匹配 + static private function checkUrlMatch($regx,$rule) { + $m1 = explode('/',$regx); + $m2 = explode('/',$rule); + $match = true; // 是否匹配 + foreach ($m2 as $key=>$val){ + if(':' == substr($val,0,1)) {// 动态变量 + if(strpos($val,'\\')) { + $type = substr($val,-1); + if('d'==$type && !is_numeric($m1[$key])) { + $match = false; + break; + } + }elseif(strpos($val,'^')){ + $array = explode('|',substr(strstr($val,'^'),1)); + if(in_array($m1[$key],$array)) { + $match = false; + break; + } + } + }elseif(0 !== strcasecmp($val,$m1[$key])){ + $match = false; + break; + } + } + return $match; + } + + static private function parseUrl($url) { + $var = array(); + if(false !== strpos($url,'?')) { // [分组/模块/操作?]参数1=值1&参数2=值2... + $info = parse_url($url); + $path = explode('/',$info['path']); + parse_str($info['query'],$var); + }elseif(strpos($url,'/')){ // [分组/模块/操作] + $path = explode('/',$url); + }else{ // 参数1=值1&参数2=值2... + parse_str($url,$var); + } + if(isset($path)) { + $var[C('VAR_ACTION')] = array_pop($path); + if(!empty($path)) { + $var[C('VAR_MODULE')] = array_pop($path); + } + if(!empty($path)) { + $var[C('VAR_GROUP')] = array_pop($path); + } + } + return $var; + } + + // 解析规则路由 + // array('路由规则','[分组/模块/操作]','额外参数1=值1&额外参数2=值2...','请求类型','资源类型') + // array('路由规则','外部地址','重定向代码','请求类型','资源类型') + // 路由规则中 :开头 表示动态变量 + // 外部地址中可以用动态变量 采用 :1 :2 的方式 + // array('news/:month/:day/:id','News/read?cate=1','status=1','post','html,xml'), + // array('new/:id','/new.php?id=:1',301,'get','xml'), 重定向 + static private function parseRule($route,$regx) { + // 获取路由地址规则 + $url = $route[1]; + // 获取URL地址中的参数 + $paths = explode('/',$regx); + // 解析路由规则 + $matches = array(); + $rule = explode('/',$route[0]); + foreach ($rule as $item){ + if(0===strpos($item,':')) { // 动态变量获取 + if($pos = strpos($item,'^') ) { + $var = substr($item,1,$pos-1); + }elseif(strpos($item,'\\')){ + $var = substr($item,1,-2); + }else{ + $var = substr($item,1); + } + $matches[$var] = array_shift($paths); + }else{ // 过滤URL中的静态变量 + array_shift($paths); + } + } + if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 + if(strpos($url,':')) { // 传递动态参数 + $values = array_values($matches); + $url = preg_replace('/:(\d)/e','$values[\\1-1]',$url); + } + header("Location: $url", true,isset($route[2])?$route[2]:301); + exit; + }else{ + // 解析路由地址 + $var = self::parseUrl($url); + // 解析路由地址里面的动态参数 + $values = array_values($matches); + foreach ($var as $key=>$val){ + if(0===strpos($val,':')) { + $var[$key] = $values[substr($val,1)-1]; + } + } + $var = array_merge($matches,$var); + // 解析剩余的URL参数 + if($paths) { + preg_replace('@(\w+)\/([^,\/]+)@e', '$var[strtolower(\'\\1\')]="\\2";', implode('/',$paths)); + } + // 解析路由自动传人参数 + if(isset($route[2])) { + parse_str($route[2],$params); + $var = array_merge($var,$params); + } + $_GET = array_merge($var,$_GET); + } + return true; + } + + // 解析正则路由 + // array('路由正则','[分组/模块/操作]?参数1=值1&参数2=值2...','额外参数','请求类型','资源类型') + // array('路由正则','外部地址','重定向代码','请求类型','资源类型') + // 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式 + // array('/new\/(\d+)\/(\d+)/','News/read?id=:1&page=:2&cate=1','status=1','post','html,xml'), + // array('/new\/(\d+)/','/new.php?id=:1&page=:2&status=1','301','get','html,xml'), 重定向 + static private function parseRegex($matches,$route,$regx) { + // 获取路由地址规则 + $url = preg_replace('/:(\d)/e','$matches[\\1]',$route[1]); + if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 + header("Location: $url", true,isset($route[1])?$route[2]:301); + exit; + }else{ + // 解析路由地址 + $var = self::parseUrl($url); + // 解析剩余的URL参数 + $regx = substr_replace($regx,'',0,strlen($matches[0])); + if($regx) { + preg_replace('@(\w+)\/([^,\/]+)@e', '$var[strtolower(\'\\1\')]="\\2";', $regx); + } + // 解析路由自动传人参数 + if(isset($route[2])) { + parse_str($route[2],$params); + $var = array_merge($var,$params); + } + $_GET = array_merge($var,$_GET); + } + return true; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Rest/Behavior/CheckUrlExtBehavior.class.php b/ThinkPHP/Extend/Mode/Rest/Behavior/CheckUrlExtBehavior.class.php new file mode 100644 index 0000000..037e5fe --- /dev/null +++ b/ThinkPHP/Extend/Mode/Rest/Behavior/CheckUrlExtBehavior.class.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + +/** + * 行为扩展 URL资源类型检测 + */ +class CheckUrlExtBehavior extends Behavior { + + /** + * 检测URL地址中资源扩展 + * @access public + * @return void + */ + public function run(&$params) { + // 获取资源类型 + if(!empty($_SERVER['PATH_INFO'])) { + $part = pathinfo($_SERVER['PATH_INFO']); + if(isset($part['extension'])) { // 判断扩展名 + define('__EXT__', strtolower($part['extension'])); + $_SERVER['PATH_INFO'] = preg_replace('/.'.__EXT__.'$/i','',$_SERVER['PATH_INFO']); + } + } + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Rest/config.php b/ThinkPHP/Extend/Mode/Rest/config.php new file mode 100644 index 0000000..9354a37 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Rest/config.php @@ -0,0 +1,23 @@ + +// +---------------------------------------------------------------------- +// $Id: config.php 2668 2012-01-26 13:07:16Z liu21st $ + +return array( + 'REST_METHOD_LIST' => 'get,post,put,delete', // 允许的请求类型列表 + 'REST_DEFAULT_METHOD' => 'get', // 默认请求类型 + 'REST_CONTENT_TYPE_LIST' => 'html,xml,json,rss', // REST允许请求的资源类型列表 + 'REST_DEFAULT_TYPE' => 'html', // 默认的资源类型 + 'REST_OUTPUT_TYPE' => array( // REST允许输出的资源类型列表 + 'xml' => 'application/xml', + 'json' => 'application/json', + 'html' => 'text/html', + ), +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Rest/tags.php b/ThinkPHP/Extend/Mode/Rest/tags.php new file mode 100644 index 0000000..ea73c2d --- /dev/null +++ b/ThinkPHP/Extend/Mode/Rest/tags.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- +// $Id: tags.php 2802 2012-03-06 06:19:07Z liu21st $ + +// Rest 系统行为扩展列表文件 +return array( + 'app_begin'=>array( + 'ReadHtmlCache', // 读取静态缓存 + ), + 'route_check'=>array( + 'CheckRestRoute', // 路由检测 + ), + 'view_end'=>array( + 'ShowPageTrace', // 页面Trace显示 + ), + 'view_template'=>array( + 'LocationTemplate', // 自动定位模板文件 + ), + 'view_parse'=>array( + 'ParseTemplate', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 + ), + 'view_filter'=>array( + 'ContentReplace', // 模板输出替换 + 'TokenBuild', // 表单令牌 + 'WriteHtmlCache', // 写入静态缓存 + 'ShowRuntime', // 运行时间显示 + ), + 'path_info'=>array( + 'CheckUrlExt' + ), +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Thin/Action.class.php b/ThinkPHP/Extend/Mode/Thin/Action.class.php new file mode 100644 index 0000000..288f279 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Thin/Action.class.php @@ -0,0 +1,49 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 简洁模式Action控制器基类 + */ +abstract class Action { + + /** + * 架构函数 + * @access public + */ + public function __construct() { + //控制器初始化 + if(method_exists($this,'_initialize')) { + $this->_initialize(); + } + } + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $parms 参数 + * @return mixed + */ + public function __call($method,$parms) { + if(strtolower($method) == strtolower(ACTION_NAME)) { + // 如果定义了_empty操作 则调用 + if(method_exists($this,'_empty')) { + $this->_empty($method,$parms); + }else { + // 抛出异常 + throw_exception(L('_ERROR_ACTION_').ACTION_NAME); + } + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + } + } + +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Thin/App.class.php b/ThinkPHP/Extend/Mode/Thin/App.class.php new file mode 100644 index 0000000..79e3a76 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Thin/App.class.php @@ -0,0 +1,71 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 精简模式应用程序类 + */ +class App { + + /** + * 应用程序初始化 + * @access public + * @return void + */ + static public function run() { + + // 取得模块和操作名称 + define('MODULE_NAME', App::getModule()); // Module名称 + define('ACTION_NAME', App::getAction()); // Action操作 + + // 记录应用初始化时间 + if(C('SHOW_RUN_TIME')) $GLOBALS['_initTime'] = microtime(TRUE); + // 执行操作 + R(MODULE_NAME.'/'.ACTION_NAME); + // 保存日志记录 + if(C('LOG_RECORD')) Log::save(); + return ; + } + + /** + * 获得实际的模块名称 + * @access private + * @return string + */ + static private function getModule() { + $var = C('VAR_MODULE'); + $module = !empty($_POST[$var]) ? + $_POST[$var] : + (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_MODULE')); + if(C('URL_CASE_INSENSITIVE')) { + // URL地址不区分大小写 + define('P_MODULE_NAME',strtolower($module)); + // 智能识别方式 index.php/user_type/index/ 识别到 UserTypeAction 模块 + $module = ucfirst(parse_name(strtolower($module),1)); + } + unset($_POST[$var],$_GET[$var]); + return $module; + } + + /** + * 获得实际的操作名称 + * @access private + * @return string + */ + static private function getAction() { + $var = C('VAR_ACTION'); + $action = !empty($_POST[$var]) ? + $_POST[$var] : + (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION')); + unset($_POST[$var],$_GET[$var]); + return $action; + } + +}; \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Thin/Db.class.php b/ThinkPHP/Extend/Mode/Thin/Db.class.php new file mode 100644 index 0000000..e2d836a --- /dev/null +++ b/ThinkPHP/Extend/Mode/Thin/Db.class.php @@ -0,0 +1,389 @@ + +// +---------------------------------------------------------------------- + +define('CLIENT_MULTI_RESULTS', 131072); +/** + * ThinkPHP 简洁模式数据库中间层实现类 + * 只支持mysql + */ +class Db { + + static private $_instance = null; + // 是否自动释放查询结果 + protected $autoFree = false; + // 是否显示调试信息 如果启用会在日志文件记录sql语句 + public $debug = false; + // 是否使用永久连接 + protected $pconnect = false; + // 当前SQL指令 + protected $queryStr = ''; + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 当前连接ID + protected $linkID = null; + // 当前查询ID + protected $queryID = null; + // 是否已经连接数据库 + protected $connected = false; + // 数据库连接参数配置 + protected $config = ''; + // 数据库表达式 + protected $comparison = array('eq'=>'=','neq'=>'!=','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE'); + // 查询表达式 + protected $selectSql = 'SELECT%DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%'; + /** + * 架构函数 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysql') ) { + throw_exception(L('_NOT_SUPPERT_').':mysql'); + } + $this->config = $this->parseConfig($config); + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect() { + if(!$this->connected) { + $config = $this->config; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); + if($this->pconnect) { + $this->linkID = mysql_pconnect( $host, $config['username'], $config['password'],CLIENT_MULTI_RESULTS); + }else{ + $this->linkID = mysql_connect( $host, $config['username'], $config['password'],true,CLIENT_MULTI_RESULTS); + } + if ( !$this->linkID || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID)) ) { + throw_exception(mysql_error()); + } + $dbVersion = mysql_get_server_info($this->linkID); + if ($dbVersion >= "4.1") { + //使用UTF8存取数据库 需要mysql 4.1.0以上支持 + mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID); + } + //设置 sql_model + if($dbVersion >'5.0.1'){ + mysql_query("SET sql_mode=''",$this->linkID); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + unset($this->config); + } + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mysql_free_result($this->queryID); + $this->queryID = 0; + } + + /** + * 执行查询 主要针对 SELECT, SHOW 等指令 + * 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + * @throws ThinkExecption + */ + public function query($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mysql_query($this->queryStr, $this->linkID); + $this->debug(); + if ( !$this->queryID ) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 针对 INSERT, UPDATE 以及DELETE + * @access public + * @param string $str sql指令 + * @return integer + * @throws ThinkExecption + */ + public function execute($str='') { + $this->connect(); + if ( !$this->linkID ) return false; + if ( $str != '' ) $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = mysql_query($this->queryStr, $this->linkID) ; + $this->debug(); + if ( false === $result) { + if ( $this->debug ) + throw_exception($this->error()); + else + return false; + } else { + $this->numRows = mysql_affected_rows($this->linkID); + $this->lastInsID = mysql_insert_id($this->linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + * @throws ThinkExecption + */ + public function startTrans() { + $this->connect(true); + if ( !$this->linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mysql_query('START TRANSACTION', $this->linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function commit() { + if ($this->transTimes > 0) { + $result = mysql_query('COMMIT', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + * @throws ThinkExecption + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = mysql_query('ROLLBACK', $this->linkID); + $this->transTimes = 0; + if(!$result){ + throw_exception($this->error()); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access public + * @return array + * @throws ThinkExecption + */ + public function getAll() { + if ( !$this->queryID ) { + throw_exception($this->error()); + return false; + } + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mysql_fetch_assoc($this->queryID)){ + $result[] = $row; + } + mysql_data_seek($this->queryID,0); + } + return $result; + } + + /** + * 关闭数据库 + * @access public + * @throws ThinkExecption + */ + public function close() { + if (!empty($this->queryID)) + mysql_free_result($this->queryID); + if ($this->linkID && !mysql_close($this->linkID)){ + throw_exception($this->error()); + } + $this->linkID = 0; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mysql_error($this->linkID); + if($this->queryStr!=''){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escapeString($str) { + return mysql_escape_string($str); + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 关闭连接 + $this->close(); + } + + /** + * 取得数据库类实例 + * @static + * @access public + * @return mixed 返回数据库驱动类 + */ + public static function getInstance($db_config='') { + if ( self::$_instance==null ){ + self::$_instance = new Db($db_config); + } + return self::$_instance; + } + + /** + * 分析数据库配置信息,支持数组和DSN + * @access private + * @param mixed $db_config 数据库配置信息 + * @return string + */ + private function parseConfig($db_config='') { + if ( !empty($db_config) && is_string($db_config)) { + // 如果DSN字符串则进行解析 + $db_config = $this->parseDSN($db_config); + }else if(empty($db_config)){ + // 如果配置为空,读取配置文件设置 + $db_config = array ( + 'dbms' => C('DB_TYPE'), + 'username' => C('DB_USER'), + 'password' => C('DB_PWD'), + 'hostname' => C('DB_HOST'), + 'hostport' => C('DB_PORT'), + 'database' => C('DB_NAME'), + 'dsn' => C('DB_DSN'), + 'params' => C('DB_PARAMS'), + ); + } + return $db_config; + } + + /** + * DSN解析 + * 格式: mysql://username:passwd@localhost:3306/DbName + * @static + * @access public + * @param string $dsnStr + * @return array + */ + public function parseDSN($dsnStr) { + if( empty($dsnStr) ){return false;} + $info = parse_url($dsnStr); + if($info['scheme']){ + $dsn = array( + 'dbms' => $info['scheme'], + 'username' => isset($info['user']) ? $info['user'] : '', + 'password' => isset($info['pass']) ? $info['pass'] : '', + 'hostname' => isset($info['host']) ? $info['host'] : '', + 'hostport' => isset($info['port']) ? $info['port'] : '', + 'database' => isset($info['path']) ? substr($info['path'],1) : '' + ); + }else { + preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); + $dsn = array ( + 'dbms' => $matches[1], + 'username' => $matches[2], + 'password' => $matches[3], + 'hostname' => $matches[4], + 'hostport' => $matches[5], + 'database' => $matches[6] + ); + } + return $dsn; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + // 记录操作结束时间 + if ( $this->debug ) { + G('queryEndTime'); + Log::record($this->queryStr." [ RunTime:".G('queryStartTime','queryEndTime',6)."s ]",Log::SQL); + } + } + + /** + * 获取最近一次查询的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID(){ + return $this->lastInsID; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/Thin/Model.class.php b/ThinkPHP/Extend/Mode/Thin/Model.class.php new file mode 100644 index 0000000..b18ca95 --- /dev/null +++ b/ThinkPHP/Extend/Mode/Thin/Model.class.php @@ -0,0 +1,185 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 简洁模式Model模型类 + * 只支持原生SQL操作 支持多数据库连接和切换 + */ +class Model { + // 当前数据库操作对象 + protected $db = null; + // 数据表前缀 + protected $tablePrefix = ''; + // 模型名称 + protected $name = ''; + // 数据库名称 + protected $dbName = ''; + // 数据表名(不包含表前缀) + protected $tableName = ''; + // 实际数据表名(包含表前缀) + protected $trueTableName =''; + // 最近错误信息 + protected $error = ''; + + /** + * 架构函数 + * 取得DB类的实例对象 + * @param string $name 模型名称 + * @access public + */ + public function __construct($name='') { + // 模型初始化 + $this->_initialize(); + // 获取模型名称 + if(!empty($name)) { + $this->name = $name; + }elseif(empty($this->name)){ + $this->name = $this->getModelName(); + } + // 数据库初始化操作 + // 获取数据库操作对象 + // 当前模型有独立的数据库连接信息 + $this->db(0,empty($this->connection)?$connection:$this->connection); + // 设置表前缀 + $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX'); + } + + // 回调方法 初始化模型 + protected function _initialize() {} + + /** + * SQL查询 + * @access public + * @param mixed $sql SQL指令 + * @return array + */ + public function query($sql) { + if(is_array($sql)) { + return $this->patchQuery($sql); + } + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) { + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + } + return $this->db->query($sql); + }else{ + return false; + } + } + + /** + * 执行SQL语句 + * @access public + * @param string $sql SQL指令 + * @return false | integer + */ + public function execute($sql='') { + if(!empty($sql)) { + if(strpos($sql,'__TABLE__')) { + $sql = str_replace('__TABLE__',$this->getTableName(),$sql); + } + $result = $this->db->execute($sql); + return $result; + }else { + return false; + } + } + + /** + * 得到当前的数据对象名称 + * @access public + * @return string + */ + public function getModelName() { + if(empty($this->name)) { + $this->name = substr(get_class($this),0,-5); + } + return $this->name; + } + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + $this->trueTableName = strtolower($tableName); + } + return (!empty($this->dbName)?$this->dbName.'.':'').$this->trueTableName; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->commit(); + $this->db->startTrans(); + return ; + } + + /** + * 提交事务 + * @access public + * @return boolean + */ + public function commit() { + return $this->db->commit(); + } + + /** + * 事务回滚 + * @access public + * @return boolean + */ + public function rollback() { + return $this->db->rollback(); + } + + /** + * 切换当前的数据库连接 + * @access public + * @param integer $linkNum 连接序号 + * @param mixed $config 数据库连接信息 + * @return Model + */ + public function db($linkNum='',$config=''){ + if(''===$linkNum && $this->db) { + return $this->db; + } + static $_linkNum = array(); + static $_db = array(); + if(!isset($_db[$linkNum]) || (isset($_db[$linkNum]) && $_linkNum[$linkNum]!=$config) ) { + // 创建一个新的实例 + if(!empty($config) && is_string($config) && false === strpos($config,'/')) { // 支持读取配置参数 + $config = C($config); + } + $_db[$linkNum] = Db::getInstance($config); + }elseif(NULL === $config){ + $_db[$linkNum]->close(); // 关闭数据库连接 + unset($_db[$linkNum]); + return ; + } + // 记录连接信息 + $_linkNum[$linkNum] = $config; + // 切换数据库连接 + $this->db = $_db[$linkNum]; + return $this; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/amf.php b/ThinkPHP/Extend/Mode/amf.php new file mode 100644 index 0000000..fe1ce17 --- /dev/null +++ b/ThinkPHP/Extend/Mode/amf.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- + +// AMF模式定义文件 +return array( + 'core' => array( + THINK_PATH.'Common/functions.php', // 系统函数库 + CORE_PATH.'Core/Log.class.php',// 日志处理 + MODE_PATH.'Amf/App.class.php', // 应用程序类 + MODE_PATH.'Amf/Action.class.php',// 控制器类 + ), + + // 项目别名定义文件 [支持数组直接定义或者文件名定义] + 'alias' => array( + 'Model' => MODE_PATH.'Amf/Model.class.php', + 'Db' => MODE_PATH.'Amf/Db.class.php', + ), + // 系统行为定义文件 [必须 支持数组直接定义或者文件名定义 ] + 'extends' => array(), + + // 项目应用行为定义文件 [支持数组直接定义或者文件名定义] + 'tags' => array(), +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/cli.php b/ThinkPHP/Extend/Mode/cli.php new file mode 100644 index 0000000..69b4829 --- /dev/null +++ b/ThinkPHP/Extend/Mode/cli.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- + +// 命令行模式定义文件 +return array( + 'core' => array( + MODE_PATH.'Cli/functions.php', // 命令行系统函数库 + MODE_PATH.'Cli/Log.class.php', + MODE_PATH.'Cli/App.class.php', + MODE_PATH.'Cli/Action.class.php', + ), + + // 项目别名定义文件 [支持数组直接定义或者文件名定义] + 'alias' => array( + 'Model' => MODE_PATH.'Cli/Model.class.php', + 'Db' => MODE_PATH.'Cli/Db.class.php', + 'Cache' => CORE_PATH.'Core/Cache.class.php', + 'Debug' => CORE_PATH.'Util/Debug.class.php', + ), + + // 系统行为定义文件 [必须 支持数组直接定义或者文件名定义 ] + 'extends' => array(), + + // 项目应用行为定义文件 [支持数组直接定义或者文件名定义] + 'tags' => array(), + +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/lite.php b/ThinkPHP/Extend/Mode/lite.php new file mode 100644 index 0000000..479e352 --- /dev/null +++ b/ThinkPHP/Extend/Mode/lite.php @@ -0,0 +1,37 @@ + +// +---------------------------------------------------------------------- + +// Lite模式定义文件 +return array( + 'core' => array( + THINK_PATH.'Common/functions.php', // 系统函数库 + CORE_PATH.'Core/Log.class.php',// 日志处理 + MODE_PATH.'Lite/App.class.php', // 应用程序类 + MODE_PATH.'Lite/Action.class.php',// 控制器类 + MODE_PATH.'Lite/Dispatcher.class.php', + ), + + // 项目别名定义文件 [支持数组直接定义或者文件名定义] + 'alias' => array( + 'Model' => MODE_PATH.'Lite/Model.class.php', + 'Db' => MODE_PATH.'Lite/Db.class.php', + 'ThinkTemplate' => CORE_PATH.'Template/ThinkTemplate.class.php', + 'TagLib' => CORE_PATH.'Template/TagLib.class.php', + 'Cache' => CORE_PATH.'Core/Cache.class.php', + 'Debug' => CORE_PATH.'Util/Debug.class.php', + 'Session' => CORE_PATH.'Util/Session.class.php', + 'TagLibCx' => CORE_PATH.'Driver/TagLib/TagLibCx.class.php', + ), + + // 系统行为定义文件 [必须 支持数组直接定义或者文件名定义 ] + 'extends' => MODE_PATH.'Lite/tags.php', + +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/phprpc.php b/ThinkPHP/Extend/Mode/phprpc.php new file mode 100644 index 0000000..ce83cd7 --- /dev/null +++ b/ThinkPHP/Extend/Mode/phprpc.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- + +// PHPRPC模式定义文件 +return array( + 'core' => array( + THINK_PATH.'Common/functions.php', // 系统函数库 + CORE_PATH.'Core/Log.class.php',// 日志处理 + MODE_PATH.'Phprpc/App.class.php', // 应用程序类 + MODE_PATH.'Phprpc/Action.class.php',// 控制器类 + ), + + // 项目别名定义文件 [支持数组直接定义或者文件名定义] + 'alias' => array( + 'Model' => MODE_PATH.'Phprpc/Model.class.php', + 'Db' => MODE_PATH.'Phprpc/Db.class.php', + ), + + // 系统行为定义文件 [必须 支持数组直接定义或者文件名定义 ] + 'extends' => array(), + + // 项目应用行为定义文件 [支持数组直接定义或者文件名定义] + 'tags' => array(), + +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/rest.php b/ThinkPHP/Extend/Mode/rest.php new file mode 100644 index 0000000..9d4dbfa --- /dev/null +++ b/ThinkPHP/Extend/Mode/rest.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + +// REST模式定义文件 +return array( + + 'core' => array( + THINK_PATH.'Common/functions.php', // 标准模式函数库 + CORE_PATH.'Core/Log.class.php', // 日志处理类 + CORE_PATH.'Core/Dispatcher.class.php', // URL调度类 + CORE_PATH.'Core/App.class.php', // 应用程序类 + CORE_PATH.'Core/View.class.php', // 视图类 + MODE_PATH.'Rest/Action.class.php',// 控制器类 + ), + + // 系统行为定义文件 [必须 支持数组直接定义或者文件名定义 ] + 'extends' => MODE_PATH.'Rest/tags.php', + + // 模式配置文件 [支持数组直接定义或者文件名定义](如有相同则覆盖项目配置文件中的配置) + 'config' => MODE_PATH.'Rest/config.php', +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Mode/thin.php b/ThinkPHP/Extend/Mode/thin.php new file mode 100644 index 0000000..63f9016 --- /dev/null +++ b/ThinkPHP/Extend/Mode/thin.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +// 简洁模式核心定义文件列表 +return array( + + 'core' => array( + THINK_PATH.'Common/functions.php', // 系统函数库 + CORE_PATH.'Core/Log.class.php',// 日志处理 + MODE_PATH.'Thin/App.class.php', // 应用程序类 + MODE_PATH.'Thin/Action.class.php',// 控制器类 + ), + + // 项目别名定义文件 [支持数组直接定义或者文件名定义] + 'alias' => array( + 'Model' => MODE_PATH.'Thin/Model.class.php', + 'Db' => MODE_PATH.'Thin/Db.class.php', + ), + + // 系统行为定义文件 [必须 支持数组直接定义或者文件名定义 ] + 'extends' => array(), + + // 项目应用行为定义文件 [支持数组直接定义或者文件名定义] + 'tags' => array(), + +); \ No newline at end of file diff --git a/ThinkPHP/Extend/Model/AdvModel.class.php b/ThinkPHP/Extend/Model/AdvModel.class.php new file mode 100644 index 0000000..d13788e --- /dev/null +++ b/ThinkPHP/Extend/Model/AdvModel.class.php @@ -0,0 +1,667 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 高级模型扩展 + * @category Extend + * @package Extend + * @subpackage Model + * @author liu21st + */ +class AdvModel extends Model { + protected $optimLock = 'lock_version'; + protected $returnType = 'array'; + protected $blobFields = array(); + protected $blobValues = null; + protected $serializeField = array(); + protected $readonlyField = array(); + protected $_filter = array(); + protected $partition = array(); + + public function __construct($name='',$tablePrefix='',$connection='') { + if('' !== $name || is_subclass_of($this,'AdvModel') ){ + // 如果是AdvModel子类或者有传入模型名称则获取字段缓存 + }else{ + // 空的模型 关闭字段缓存 + $this->autoCheckFields = false; + } + parent::__construct($name,$tablePrefix,$connection); + } + + /** + * 利用__call方法重载 实现一些特殊的Model方法 (魔术方法) + * @access public + * @param string $method 方法名称 + * @param mixed $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(strtolower(substr($method,0,3))=='top'){ + // 获取前N条记录 + $count = substr($method,3); + array_unshift($args,$count); + return call_user_func_array(array(&$this, 'topN'), $args); + }else{ + return parent::__call($method,$args); + } + } + + /** + * 对保存到数据库的数据进行处理 + * @access protected + * @param mixed $data 要操作的数据 + * @return boolean + */ + protected function _facade($data) { + // 检查序列化字段 + $data = $this->serializeField($data); + return parent::_facade($data); + } + + // 查询成功后的回调方法 + protected function _after_find(&$result,$options='') { + // 检查序列化字段 + $this->checkSerializeField($result); + // 获取文本字段 + $this->getBlobFields($result); + // 检查字段过滤 + $result = $this->getFilterFields($result); + // 缓存乐观锁 + $this->cacheLockVersion($result); + } + + // 查询数据集成功后的回调方法 + protected function _after_select(&$resultSet,$options='') { + // 检查序列化字段 + $resultSet = $this->checkListSerializeField($resultSet); + // 获取文本字段 + $resultSet = $this->getListBlobFields($resultSet); + // 检查列表字段过滤 + $resultSet = $this->getFilterListFields($resultSet); + } + + // 写入前的回调方法 + protected function _before_insert(&$data,$options='') { + // 记录乐观锁 + $data = $this->recordLockVersion($data); + // 检查文本字段 + $data = $this->checkBlobFields($data); + // 检查字段过滤 + $data = $this->setFilterFields($data); + } + + protected function _after_insert($data,$options) { + // 保存文本字段 + $this->saveBlobFields($data); + } + + // 更新前的回调方法 + protected function _before_update(&$data,$options='') { + // 检查乐观锁 + if(!$this->checkLockVersion($data,$options)) { + return false; + } + // 检查文本字段 + $data = $this->checkBlobFields($data); + // 检查只读字段 + $data = $this->checkReadonlyField($data); + // 检查字段过滤 + $data = $this->setFilterFields($data); + } + + protected function _after_update($data,$options) { + // 保存文本字段 + $this->saveBlobFields($data); + } + + protected function _after_delete($data,$options) { + // 删除Blob数据 + $this->delBlobFields($data); + } + + /** + * 记录乐观锁 + * @access protected + * @param array $data 数据对象 + * @return array + */ + protected function recordLockVersion($data) { + // 记录乐观锁 + if($this->optimLock && !isset($data[$this->optimLock]) ) { + if(in_array($this->optimLock,$this->fields,true)) { + $data[$this->optimLock] = 0; + } + } + return $data; + } + + /** + * 缓存乐观锁 + * @access protected + * @param array $data 数据对象 + * @return void + */ + protected function cacheLockVersion($data) { + if($this->optimLock) { + if(isset($data[$this->optimLock]) && isset($data[$this->getPk()])) { + // 只有当存在乐观锁字段和主键有值的时候才记录乐观锁 + $_SESSION[$this->name.'_'.$data[$this->getPk()].'_lock_version'] = $data[$this->optimLock]; + } + } + } + + /** + * 检查乐观锁 + * @access protected + * @param array $data 当前数据 + * @param array $options 查询表达式 + * @return mixed + */ + protected function checkLockVersion(&$data,$options) { + $id = $data[$this->getPk()]; + // 检查乐观锁 + $identify = $this->name.'_'.$id.'_lock_version'; + if($this->optimLock && isset($_SESSION[$identify])) { + $lock_version = $_SESSION[$identify]; + $vo = $this->field($this->optimLock)->find($id); + $_SESSION[$identify] = $lock_version; + $curr_version = $vo[$this->optimLock]; + if(isset($curr_version)) { + if($curr_version>0 && $lock_version != $curr_version) { + // 记录已经更新 + $this->error = L('_RECORD_HAS_UPDATE_'); + return false; + }else{ + // 更新乐观锁 + $save_version = $data[$this->optimLock]; + if($save_version != $lock_version+1) { + $data[$this->optimLock] = $lock_version+1; + } + $_SESSION[$identify] = $lock_version+1; + } + } + } + return true; + } + + /** + * 查找前N个记录 + * @access public + * @param integer $count 记录个数 + * @param array $options 查询表达式 + * @return array + */ + public function topN($count,$options=array()) { + $options['limit'] = $count; + return $this->select($options); + } + + /** + * 查询符合条件的第N条记录 + * 0 表示第一条记录 -1 表示最后一条记录 + * @access public + * @param integer $position 记录位置 + * @param array $options 查询表达式 + * @return mixed + */ + public function getN($position=0,$options=array()) { + if($position>=0) { // 正向查找 + $options['limit'] = $position.',1'; + $list = $this->select($options); + return $list?$list[0]:false; + }else{ // 逆序查找 + $list = $this->select($options); + return $list?$list[count($list)-abs($position)]:false; + } + } + + /** + * 获取满足条件的第一条记录 + * @access public + * @param array $options 查询表达式 + * @return mixed + */ + public function first($options=array()) { + return $this->getN(0,$options); + } + + /** + * 获取满足条件的最后一条记录 + * @access public + * @param array $options 查询表达式 + * @return mixed + */ + public function last($options=array()) { + return $this->getN(-1,$options); + } + + /** + * 返回数据 + * @access public + * @param array $data 数据 + * @param string $type 返回类型 默认为数组 + * @return mixed + */ + public function returnResult($data,$type='') { + if('' === $type) + $type = $this->returnType; + switch($type) { + case 'array' : return $data; + case 'object': return (object)$data; + default:// 允许用户自定义返回类型 + if(class_exists($type)) + return new $type($data); + else + throw_exception(L('_CLASS_NOT_EXIST_').':'.$type); + } + } + + /** + * 获取数据的时候过滤数据字段 + * @access protected + * @param mixed $result 查询的数据 + * @return array + */ + protected function getFilterFields(&$result) { + if(!empty($this->_filter)) { + foreach ($this->_filter as $field=>$filter){ + if(isset($result[$field])) { + $fun = $filter[1]; + if(!empty($fun)) { + if(isset($filter[2]) && $filter[2]){ + // 传递整个数据对象作为参数 + $result[$field] = call_user_func($fun,$result); + }else{ + // 传递字段的值作为参数 + $result[$field] = call_user_func($fun,$result[$field]); + } + } + } + } + } + return $result; + } + + protected function getFilterListFields(&$resultSet) { + if(!empty($this->_filter)) { + foreach ($resultSet as $key=>$result) + $resultSet[$key] = $this->getFilterFields($result); + } + return $resultSet; + } + + /** + * 写入数据的时候过滤数据字段 + * @access protected + * @param mixed $result 查询的数据 + * @return array + */ + protected function setFilterFields($data) { + if(!empty($this->_filter)) { + foreach ($this->_filter as $field=>$filter){ + if(isset($data[$field])) { + $fun = $filter[0]; + if(!empty($fun)) { + if(isset($filter[2]) && $filter[2]) { + // 传递整个数据对象作为参数 + $data[$field] = call_user_func($fun,$data); + }else{ + // 传递字段的值作为参数 + $data[$field] = call_user_func($fun,$data[$field]); + } + } + } + } + } + return $data; + } + + /** + * 返回数据列表 + * @access protected + * @param array $resultSet 数据 + * @param string $type 返回类型 默认为数组 + * @return void + */ + protected function returnResultSet(&$resultSet,$type='') { + foreach ($resultSet as $key=>$data) + $resultSet[$key] = $this->returnResult($data,$type); + return $resultSet; + } + + protected function checkBlobFields(&$data) { + // 检查Blob文件保存字段 + if(!empty($this->blobFields)) { + foreach ($this->blobFields as $field){ + if(isset($data[$field])) { + if(isset($data[$this->getPk()])) + $this->blobValues[$this->name.'/'.$data[$this->getPk()].'_'.$field] = $data[$field]; + else + $this->blobValues[$this->name.'/@?id@_'.$field] = $data[$field]; + unset($data[$field]); + } + } + } + return $data; + } + + /** + * 获取数据集的文本字段 + * @access protected + * @param mixed $resultSet 查询的数据 + * @param string $field 查询的字段 + * @return void + */ + protected function getListBlobFields(&$resultSet,$field='') { + if(!empty($this->blobFields)) { + foreach ($resultSet as $key=>$result){ + $result = $this->getBlobFields($result,$field); + $resultSet[$key] = $result; + } + } + return $resultSet; + } + + /** + * 获取数据的文本字段 + * @access protected + * @param mixed $data 查询的数据 + * @param string $field 查询的字段 + * @return void + */ + protected function getBlobFields(&$data,$field='') { + if(!empty($this->blobFields)) { + $pk = $this->getPk(); + $id = $data[$pk]; + if(empty($field)) { + foreach ($this->blobFields as $field){ + $identify = $this->name.'/'.$id.'_'.$field; + $data[$field] = F($identify); + } + return $data; + }else{ + $identify = $this->name.'/'.$id.'_'.$field; + return F($identify); + } + } + } + + /** + * 保存File方式的字段 + * @access protected + * @param mixed $data 保存的数据 + * @return void + */ + protected function saveBlobFields(&$data) { + if(!empty($this->blobFields)) { + foreach ($this->blobValues as $key=>$val){ + if(strpos($key,'@?id@')) + $key = str_replace('@?id@',$data[$this->getPk()],$key); + F($key,$val); + } + } + } + + /** + * 删除File方式的字段 + * @access protected + * @param mixed $data 保存的数据 + * @param string $field 查询的字段 + * @return void + */ + protected function delBlobFields(&$data,$field='') { + if(!empty($this->blobFields)) { + $pk = $this->getPk(); + $id = $data[$pk]; + if(empty($field)) { + foreach ($this->blobFields as $field){ + $identify = $this->name.'/'.$id.'_'.$field; + F($identify,null); + } + }else{ + $identify = $this->name.'/'.$id.'_'.$field; + F($identify,null); + } + } + } + + /** + * 字段值延迟增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @param integer $lazyTime 延时时间(s) + * @return boolean + */ + public function setLazyInc($field,$step=1,$lazyTime=0) { + $condition = $this->options['where']; + if(empty($condition)) { // 没有条件不做任何更新 + return false; + } + if($lazyTime>0) {// 延迟写入 + $guid = md5($this->name.'_'.$field.'_'.serialize($condition)); + $step = $this->lazyWrite($guid,$step,$lazyTime); + if(false === $step ) return true; // 等待下次写入 + } + return $this->setField($field,array('exp',$field.'+'.$step)); + } + + /** + * 字段值延迟减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @param integer $lazyTime 延时时间(s) + * @return boolean + */ + public function setLazyDec($field,$step=1,$lazyTime=0) { + $condition = $this->options['where']; + if(empty($condition)) { // 没有条件不做任何更新 + return false; + } + if($lazyTime>0) {// 延迟写入 + $guid = md5($this->name.'_'.$field.'_'.serialize($condition)); + $step = $this->lazyWrite($guid,$step,$lazyTime); + if(false === $step ) return true; // 等待下次写入 + } + return $this->setField($field,array('exp',$field.'-'.$step)); + } + + /** + * 延时更新检查 返回false表示需要延时 + * 否则返回实际写入的数值 + * @access public + * @param string $guid 写入标识 + * @param integer $step 写入步进值 + * @param integer $lazyTime 延时时间(s) + * @return false|integer + */ + protected function lazyWrite($guid,$step,$lazyTime) { + if(false !== ($value = F($guid))) { // 存在缓存写入数据 + if(time()>F($guid.'_time')+$lazyTime) { + // 延时更新时间到了,删除缓存数据 并实际写入数据库 + F($guid,NULL); + F($guid.'_time',NULL); + return $value+$step; + }else{ + // 追加数据到缓存 + F($guid,$value+$step); + return false; + } + }else{ // 没有缓存数据 + F($guid,$step); + // 计时开始 + F($guid.'_time',time()); + return false; + } + } + + /** + * 检查序列化数据字段 + * @access protected + * @param array $data 数据 + * @return array + */ + protected function serializeField(&$data) { + // 检查序列化字段 + if(!empty($this->serializeField)) { + // 定义方式 $this->serializeField = array('ser'=>array('name','email')); + foreach ($this->serializeField as $key=>$val){ + if(empty($data[$key])) { + $serialize = array(); + foreach ($val as $name){ + if(isset($data[$name])) { + $serialize[$name] = $data[$name]; + unset($data[$name]); + } + } + if(!empty($serialize)) { + $data[$key] = serialize($serialize); + } + } + } + } + return $data; + } + + // 检查返回数据的序列化字段 + protected function checkSerializeField(&$result) { + // 检查序列化字段 + if(!empty($this->serializeField)) { + foreach ($this->serializeField as $key=>$val){ + if(isset($result[$key])) { + $serialize = unserialize($result[$key]); + foreach ($serialize as $name=>$value) + $result[$name] = $value; + unset($serialize,$result[$key]); + } + } + } + return $result; + } + + // 检查数据集的序列化字段 + protected function checkListSerializeField(&$resultSet) { + // 检查序列化字段 + if(!empty($this->serializeField)) { + foreach ($this->serializeField as $key=>$val){ + foreach ($resultSet as $k=>$result){ + if(isset($result[$key])) { + $serialize = unserialize($result[$key]); + foreach ($serialize as $name=>$value) + $result[$name] = $value; + unset($serialize,$result[$key]); + $resultSet[$k] = $result; + } + } + } + } + return $resultSet; + } + + /** + * 检查只读字段 + * @access protected + * @param array $data 数据 + * @return array + */ + protected function checkReadonlyField(&$data) { + if(!empty($this->readonlyField)) { + foreach ($this->readonlyField as $key=>$field){ + if(isset($data[$field])) + unset($data[$field]); + } + } + return $data; + } + + /** + * 批处理执行SQL语句 + * 批处理的指令都认为是execute操作 + * @access public + * @param array $sql SQL批处理指令 + * @return boolean + */ + public function patchQuery($sql=array()) { + if(!is_array($sql)) return false; + // 自动启动事务支持 + $this->startTrans(); + try{ + foreach ($sql as $_sql){ + $result = $this->execute($_sql); + if(false === $result) { + // 发生错误自动回滚事务 + $this->rollback(); + return false; + } + } + // 提交事务 + $this->commit(); + } catch (ThinkException $e) { + $this->rollback(); + } + return true; + } + + /** + * 得到分表的的数据表名 + * @access public + * @param array $data 操作的数据 + * @return string + */ + public function getPartitionTableName($data=array()) { + // 对数据表进行分区 + if(isset($data[$this->partition['field']])) { + $field = $data[$this->partition['field']]; + switch($this->partition['type']) { + case 'id': + // 按照id范围分表 + $step = $this->partition['expr']; + $seq = floor($field / $step)+1; + break; + case 'year': + // 按照年份分表 + if(!is_numeric($field)) { + $field = strtotime($field); + } + $seq = date('Y',$field)-$this->partition['expr']+1; + break; + case 'mod': + // 按照id的模数分表 + $seq = ($field % $this->partition['num'])+1; + break; + case 'md5': + // 按照md5的序列分表 + $seq = (ord(substr(md5($field),0,1)) % $this->partition['num'])+1; + break; + default : + if(function_exists($this->partition['type'])) { + // 支持指定函数哈希 + $fun = $this->partition['type']; + $seq = (ord(substr($fun($field),0,1)) % $this->partition['num'])+1; + }else{ + // 按照字段的首字母的值分表 + $seq = (ord($field{0}) % $this->partition['num'])+1; + } + } + return $this->getTableName().'_'.$seq; + }else{ + // 当设置的分表字段不在查询条件或者数据中 + // 进行联合查询,必须设定 partition['num'] + $tableName = array(); + for($i=0;$i<$this->partition['num'];$i++) + $tableName[] = 'SELECT * FROM '.$this->getTableName().'_'.($i+1); + $tableName = '( '.implode(" UNION ",$tableName).') AS '.$this->name; + return $tableName; + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Model/MongoModel.class.php b/ThinkPHP/Extend/Model/MongoModel.class.php new file mode 100644 index 0000000..5f394da --- /dev/null +++ b/ThinkPHP/Extend/Model/MongoModel.class.php @@ -0,0 +1,313 @@ + +// +---------------------------------------------------------------------- + +/** + * MongoModel模型类 + * 实现了ODM和ActiveRecords模式 + * @category Extend + * @package Extend + * @subpackage Model + * @author liu21st + */ +class MongoModel extends Model{ + // 主键类型 + const TYPE_OBJECT = 1; + const TYPE_INT = 2; + const TYPE_STRING = 3; + + // 主键名称 + protected $pk = '_id'; + // _id 类型 1 Object 采用MongoId对象 2 Int 整形 支持自动增长 3 String 字符串Hash + protected $_idType = self::TYPE_OBJECT; + // 主键是否自动增长 支持Int型主键 + protected $_autoInc = false; + // Mongo默认关闭字段检测 可以动态追加字段 + protected $autoCheckFields = false; + // 链操作方法列表 + protected $methods = array('table','order','auto','filter','validate'); + + /** + * 利用__call方法实现一些特殊的Model方法 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(in_array(strtolower($method),$this->methods,true)) { + // 连贯操作的实现 + $this->options[strtolower($method)] = $args[0]; + return $this; + }elseif(strtolower(substr($method,0,5))=='getby') { + // 根据某个字段获取记录 + $field = parse_name(substr($method,5)); + $where[$field] =$args[0]; + return $this->where($where)->find(); + }elseif(strtolower(substr($method,0,10))=='getfieldby') { + // 根据某个字段获取记录的某个值 + $name = parse_name(substr($method,10)); + $where[$name] =$args[0]; + return $this->where($where)->getField($args[1]); + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } + + /** + * 获取字段信息并缓存 主键和自增信息直接配置 + * @access public + * @return void + */ + public function flush() { + // 缓存不存在则查询数据表信息 + $fields = $this->db->getFields(); + if(!$fields) { // 暂时没有数据无法获取字段信息 下次查询 + return false; + } + $this->fields = array_keys($fields); + $this->fields['_pk'] = $this->pk; + $this->fields['_autoinc'] = $this->_autoInc; + foreach ($fields as $key=>$val){ + // 记录字段类型 + $type[$key] = $val['type']; + } + // 记录字段类型信息 + if(C('DB_FIELDTYPE_CHECK')) $this->fields['_type'] = $type; + + // 2008-3-7 增加缓存开关控制 + if(C('DB_FIELDS_CACHE')){ + // 永久缓存数据表信息 + $db = $this->dbName?$this->dbName:C('DB_NAME'); + F('_fields/'.$db.'.'.$this->name,$this->fields); + } + } + + // 写入数据前的回调方法 包括新增和更新 + protected function _before_write(&$data) { + $pk = $this->getPk(); + // 根据主键类型处理主键数据 + if(isset($data[$pk]) && $this->_idType == self::TYPE_OBJECT) { + $data[$pk] = new MongoId($data[$pk]); + } + } + + /** + * count统计 配合where连贯操作 + * @access public + * @return integer + */ + public function count(){ + // 分析表达式 + $options = $this->_parseOptions(); + return $this->db->count($options); + } + + /** + * 获取下一ID 用于自动增长型 + * @access public + * @param string $pk 字段名 默认为主键 + * @return mixed + */ + public function getMongoNextId($pk=''){ + if(empty($pk)) { + $pk = $this->getPk(); + } + return $this->db->mongo_next_id($pk); + } + + // 插入数据前的回调方法 + protected function _before_insert(&$data,$options) { + // 写入数据到数据库 + if($this->_autoInc && $this->_idType== self::TYPE_INT) { // 主键自动增长 + $pk = $this->getPk(); + if(!isset($data[$pk])) { + $data[$pk] = $this->db->mongo_next_id($pk); + } + } + } + + public function clear(){ + return $this->db->clear(); + } + + // 查询成功后的回调方法 + protected function _after_select(&$resultSet,$options) { + array_walk($resultSet,array($this,'checkMongoId')); + } + + /** + * 获取MongoId + * @access protected + * @param array $result 返回数据 + * @return array + */ + protected function checkMongoId(&$result){ + if(is_object($result['_id'])) { + $result['_id'] = $result['_id']->__toString(); + } + return $result; + } + + // 表达式过滤回调方法 + protected function _options_filter(&$options) { + $id = $this->getPk(); + if(isset($options['where'][$id]) && is_scalar($options['where'][$id]) && $this->_idType== self::TYPE_OBJECT) { + $options['where'][$id] = new MongoId($options['where'][$id]); + } + } + + /** + * 查询数据 + * @access public + * @param mixed $options 表达式参数 + * @return mixed + */ + public function find($options=array()) { + if( is_numeric($options) || is_string($options)) { + $id = $this->getPk(); + $where[$id] = $options; + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + $result = $this->db->find($options); + if(false === $result) { + return false; + } + if(empty($result)) {// 查询结果为空 + return null; + }else{ + $this->checkMongoId($result); + } + $this->data = $result; + $this->_after_find($this->data,$options); + return $this->data; + } + + /** + * 字段值增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @return boolean + */ + public function setInc($field,$step=1) { + return $this->setField($field,array('inc',$step)); + } + + /** + * 字段值减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @return boolean + */ + public function setDec($field,$step=1) { + return $this->setField($field,array('inc','-'.$step)); + } + + /** + * 获取一条记录的某个字段值 + * @access public + * @param string $field 字段名 + * @param string $spea 字段数据间隔符号 + * @return mixed + */ + public function getField($field,$sepa=null) { + $options['field'] = $field; + $options = $this->_parseOptions($options); + if(strpos($field,',')) { // 多字段 + if(is_numeric($sepa)) {// 限定数量 + $options['limit'] = $sepa; + $sepa = null;// 重置为null 返回数组 + } + $resultSet = $this->db->select($options); + if(!empty($resultSet)) { + $_field = explode(',', $field); + $field = array_keys($resultSet[0]); + $key = array_shift($field); + $key2 = array_shift($field); + $cols = array(); + $count = count($_field); + foreach ($resultSet as $result){ + $name = $result[$key]; + if(2==$count) { + $cols[$name] = $result[$key2]; + }else{ + $cols[$name] = is_null($sepa)?$result:implode($sepa,$result); + } + } + return $cols; + } + }else{ + // 返回数据个数 + if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据 + $options['limit'] = is_numeric($sepa)?$sepa:1; + } // 查找一条记录 + $result = $this->db->find($options); + if(!empty($result)) { + if(1==$options['limit']) return reset($result[0]); + foreach ($result as $val){ + $array[] = $val[$field]; + } + return $array; + } + } + return null; + } + + /** + * 执行Mongo指令 + * @access public + * @param array $command 指令 + * @return mixed + */ + public function command($command) { + return $this->db->command($command); + } + + /** + * 执行MongoCode + * @access public + * @param string $code MongoCode + * @param array $args 参数 + * @return mixed + */ + public function mongoCode($code,$args=array()) { + return $this->db->execute($code,$args); + } + + // 数据库切换后回调方法 + protected function _after_db() { + // 切换Collection + $this->db->switchCollection($this->getTableName(),$this->dbName?$this->dbName:C('db_name')); + } + + /** + * 得到完整的数据表名 Mongo表名不带dbName + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + $this->trueTableName = strtolower($tableName); + } + return $this->trueTableName; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Model/RelationModel.class.php b/ThinkPHP/Extend/Model/RelationModel.class.php new file mode 100644 index 0000000..66f770d --- /dev/null +++ b/ThinkPHP/Extend/Model/RelationModel.class.php @@ -0,0 +1,392 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * ThinkPHP关联模型扩展 + * @category Extend + * @package Extend + * @subpackage Model + * @author liu21st + */ +define('HAS_ONE',1); +define('BELONGS_TO',2); +define('HAS_MANY',3); +define('MANY_TO_MANY',4); + +class RelationModel extends Model { + // 关联定义 + protected $_link = array(); + + /** + * 动态方法实现 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(strtolower(substr($method,0,8))=='relation'){ + $type = strtoupper(substr($method,8)); + if(in_array($type,array('ADD','SAVE','DEL'),true)) { + array_unshift($args,$type); + return call_user_func_array(array(&$this, 'opRelation'), $args); + } + }else{ + return parent::__call($method,$args); + } + } + + /** + * 得到关联的数据表名 + * @access public + * @return string + */ + public function getRelationTableName($relation) { + $relationTable = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + $relationTable .= $this->tableName?$this->tableName:$this->name; + $relationTable .= '_'.$relation->getModelName(); + return strtolower($relationTable); + } + + // 查询成功后的回调方法 + protected function _after_find(&$result,$options) { + // 获取关联数据 并附加到结果中 + if(!empty($options['link'])) + $this->getRelation($result,$options['link']); + } + + // 查询数据集成功后的回调方法 + protected function _after_select(&$result,$options) { + // 获取关联数据 并附加到结果中 + if(!empty($options['link'])) + $this->getRelations($result,$options['link']); + } + + // 写入成功后的回调方法 + protected function _after_insert($data,$options) { + // 关联写入 + if(!empty($options['link'])) + $this->opRelation('ADD',$data,$options['link']); + } + + // 更新成功后的回调方法 + protected function _after_update($data,$options) { + // 关联更新 + if(!empty($options['link'])) + $this->opRelation('SAVE',$data,$options['link']); + } + + // 删除成功后的回调方法 + protected function _after_delete($data,$options) { + // 关联删除 + if(!empty($options['link'])) + $this->opRelation('DEL',$data,$options['link']); + } + + /** + * 对保存到数据库的数据进行处理 + * @access protected + * @param mixed $data 要操作的数据 + * @return boolean + */ + protected function _facade($data) { + $this->_before_write($data); + return $data; + } + + /** + * 获取返回数据集的关联记录 + * @access protected + * @param array $resultSet 返回数据 + * @param string|array $name 关联名称 + * @return array + */ + protected function getRelations(&$resultSet,$name='') { + // 获取记录集的主键列表 + foreach($resultSet as $key=>$val) { + $val = $this->getRelation($val,$name); + $resultSet[$key] = $val; + } + return $resultSet; + } + + /** + * 获取返回数据的关联记录 + * @access protected + * @param mixed $result 返回数据 + * @param string|array $name 关联名称 + * @param boolean $return 是否返回关联数据本身 + * @return array + */ + protected function getRelation(&$result,$name='',$return=false) { + if(!empty($this->_link)) { + foreach($this->_link as $key=>$val) { + $mappingName = !empty($val['mapping_name'])?$val['mapping_name']:$key; // 映射名称 + if(empty($name) || true === $name || $mappingName == $name || (is_array($name) && in_array($mappingName,$name))) { + $mappingType = !empty($val['mapping_type'])?$val['mapping_type']:$val; // 关联类型 + $mappingClass = !empty($val['class_name'])?$val['class_name']:$key; // 关联类名 + $mappingFields = !empty($val['mapping_fields'])?$val['mapping_fields']:'*'; // 映射字段 + $mappingCondition = !empty($val['condition'])?$val['condition']:'1=1'; // 关联条件 + $mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名 + if(strtoupper($mappingClass)==strtoupper($this->name)) { + // 自引用关联 获取父键名 + $mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id'; + }else{ + $mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($this->name).'_id'; // 关联外键 + } + // 获取关联模型对象 + $model = D($mappingClass); + switch($mappingType) { + case HAS_ONE: + $pk = $result[$mappingKey]; + $mappingCondition .= " AND {$mappingFk}='{$pk}'"; + $relationData = $model->where($mappingCondition)->field($mappingFields)->find(); + if (!empty($val['relation_deep'])){ + $model->getRelation($relationData,$val['relation_deep']); + } + break; + case BELONGS_TO: + if(strtoupper($mappingClass)==strtoupper($this->name)) { + // 自引用关联 获取父键名 + $mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id'; + }else{ + $mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($model->getModelName()).'_id'; // 关联外键 + } + $fk = $result[$mappingFk]; + $mappingCondition .= " AND {$model->getPk()}='{$fk}'"; + $relationData = $model->where($mappingCondition)->field($mappingFields)->find(); + if (!empty($val['relation_deep'])){ + $model->getRelation($relationData,$val['relation_deep']); + } + break; + case HAS_MANY: + $pk = $result[$mappingKey]; + $mappingCondition .= " AND {$mappingFk}='{$pk}'"; + $mappingOrder = !empty($val['mapping_order'])?$val['mapping_order']:''; + $mappingLimit = !empty($val['mapping_limit'])?$val['mapping_limit']:''; + // 延时获取关联记录 + $relationData = $model->where($mappingCondition)->field($mappingFields)->order($mappingOrder)->limit($mappingLimit)->select(); + if (!empty($val['relation_deep'])){ + foreach($relationData as $key=>$data){ + $model->getRelation($data,$val['relation_deep']); + $relationData[$key] = $data; + } + } + break; + case MANY_TO_MANY: + $pk = $result[$mappingKey]; + $mappingCondition = " {$mappingFk}='{$pk}'"; + $mappingOrder = $val['mapping_order']; + $mappingLimit = $val['mapping_limit']; + $mappingRelationFk = $val['relation_foreign_key']?$val['relation_foreign_key']:$model->getModelName().'_id'; + $mappingRelationTable = $val['relation_table']?$val['relation_table']:$this->getRelationTableName($model); + $sql = "SELECT b.{$mappingFields} FROM {$mappingRelationTable} AS a, ".$model->getTableName()." AS b WHERE a.{$mappingRelationFk} = b.{$model->getPk()} AND a.{$mappingCondition}"; + if(!empty($val['condition'])) { + $sql .= ' AND '.$val['condition']; + } + if(!empty($mappingOrder)) { + $sql .= ' ORDER BY '.$mappingOrder; + } + if(!empty($mappingLimit)) { + $sql .= ' LIMIT '.$mappingLimit; + } + $relationData = $this->query($sql); + if (!empty($val['relation_deep'])){ + foreach($relationData as $key=>$data){ + $model->getRelation($data,$val['relation_deep']); + $relationData[$key] = $data; + } + } + break; + } + if(!$return){ + if(isset($val['as_fields']) && in_array($mappingType,array(HAS_ONE,BELONGS_TO)) ) { + // 支持直接把关联的字段值映射成数据对象中的某个字段 + // 仅仅支持HAS_ONE BELONGS_TO + $fields = explode(',',$val['as_fields']); + foreach ($fields as $field){ + if(strpos($field,':')) { + list($relationName,$nick) = explode(':',$field); + $result[$nick] = $relationData[$relationName]; + }else{ + $result[$field] = $relationData[$field]; + } + } + }else{ + $result[$mappingName] = $relationData; + } + unset($relationData); + }else{ + return $relationData; + } + } + } + } + return $result; + } + + /** + * 操作关联数据 + * @access protected + * @param string $opType 操作方式 ADD SAVE DEL + * @param mixed $data 数据对象 + * @param string $name 关联名称 + * @return mixed + */ + protected function opRelation($opType,$data='',$name='') { + $result = false; + if(empty($data) && !empty($this->data)){ + $data = $this->data; + }elseif(!is_array($data)){ + // 数据无效返回 + return false; + } + if(!empty($this->_link)) { + // 遍历关联定义 + foreach($this->_link as $key=>$val) { + // 操作制定关联类型 + $mappingName = $val['mapping_name']?$val['mapping_name']:$key; // 映射名称 + if(empty($name) || true === $name || $mappingName == $name || (is_array($name) && in_array($mappingName,$name)) ) { + // 操作制定的关联 + $mappingType = !empty($val['mapping_type'])?$val['mapping_type']:$val; // 关联类型 + $mappingClass = !empty($val['class_name'])?$val['class_name']:$key; // 关联类名 + $mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名 + // 当前数据对象主键值 + $pk = $data[$mappingKey]; + if(strtoupper($mappingClass)==strtoupper($this->name)) { + // 自引用关联 获取父键名 + $mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id'; + }else{ + $mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($this->name).'_id'; // 关联外键 + } + if(!empty($val['condition'])) { + $mappingCondition = $val['condition']; + }else{ + $mappingCondition = array(); + $mappingCondition[$mappingFk] = $pk; + } + // 获取关联model对象 + $model = D($mappingClass); + $mappingData = isset($data[$mappingName])?$data[$mappingName]:false; + if(!empty($mappingData) || $opType == 'DEL') { + switch($mappingType) { + case HAS_ONE: + switch (strtoupper($opType)){ + case 'ADD': // 增加关联数据 + $mappingData[$mappingFk] = $pk; + $result = $model->add($mappingData); + break; + case 'SAVE': // 更新关联数据 + $result = $model->where($mappingCondition)->save($mappingData); + break; + case 'DEL': // 根据外键删除关联数据 + $result = $model->where($mappingCondition)->delete(); + break; + } + break; + case BELONGS_TO: + break; + case HAS_MANY: + switch (strtoupper($opType)){ + case 'ADD' : // 增加关联数据 + $model->startTrans(); + foreach ($mappingData as $val){ + $val[$mappingFk] = $pk; + $result = $model->add($val); + } + $model->commit(); + break; + case 'SAVE' : // 更新关联数据 + $model->startTrans(); + $pk = $model->getPk(); + foreach ($mappingData as $vo){ + if(isset($vo[$pk])) {// 更新数据 + $mappingCondition = "$pk ={$vo[$pk]}"; + $result = $model->where($mappingCondition)->save($vo); + }else{ // 新增数据 + $vo[$mappingFk] = $data[$mappingKey]; + $result = $model->add($vo); + } + } + $model->commit(); + break; + case 'DEL' : // 删除关联数据 + $result = $model->where($mappingCondition)->delete(); + break; + } + break; + case MANY_TO_MANY: + $mappingRelationFk = $val['relation_foreign_key']?$val['relation_foreign_key']:$model->getModelName().'_id';// 关联 + $mappingRelationTable = $val['relation_table']?$val['relation_table']:$this->getRelationTableName($model); + if(is_array($mappingData)) { + $ids = array(); + foreach ($mappingData as $vo) + $ids[] = $vo[$mappingKey]; + $relationId = implode(',',$ids); + } + switch (strtoupper($opType)){ + case 'ADD': // 增加关联数据 + case 'SAVE': // 更新关联数据 + if(isset($relationId)) { + $this->startTrans(); + // 删除关联表数据 + $this->table($mappingRelationTable)->where($mappingCondition)->delete(); + // 插入关联表数据 + $sql = 'INSERT INTO '.$mappingRelationTable.' ('.$mappingFk.','.$mappingRelationFk.') SELECT a.'.$this->getPk().',b.'.$model->getPk().' FROM '.$this->getTableName().' AS a ,'.$model->getTableName()." AS b where a.".$this->getPk().' ='. $pk.' AND b.'.$model->getPk().' IN ('.$relationId.") "; + $result = $model->execute($sql); + if(false !== $result) + // 提交事务 + $this->commit(); + else + // 事务回滚 + $this->rollback(); + } + break; + case 'DEL': // 根据外键删除中间表关联数据 + $result = $this->table($mappingRelationTable)->where($mappingCondition)->delete(); + break; + } + break; + } + if (!empty($val['relation_deep'])){ + $model->opRelation($opType,$mappingData,$val['relation_deep']); + } + } + } + } + } + return $result; + } + + /** + * 进行关联查询 + * @access public + * @param mixed $name 关联名称 + * @return Model + */ + public function relation($name) { + $this->options['link'] = $name; + return $this; + } + + /** + * 关联数据获取 仅用于查询后 + * @access public + * @param string $name 关联名称 + * @return array + */ + public function relationGet($name) { + if(empty($this->data)) + return false; + return $this->getRelation($this->data,$name,true); + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Model/ViewModel.class.php b/ThinkPHP/Extend/Model/ViewModel.class.php new file mode 100644 index 0000000..582191a --- /dev/null +++ b/ThinkPHP/Extend/Model/ViewModel.class.php @@ -0,0 +1,245 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * ThinkPHP视图模型扩展 + * @category Extend + * @package Extend + * @subpackage Model + * @author liu21st + */ +class ViewModel extends Model { + + protected $viewFields = array(); + + /** + * 自动检测数据表信息 + * @access protected + * @return void + */ + protected function _checkTableInfo() {} + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = ''; + foreach ($this->viewFields as $key=>$view){ + // 获取数据表名称 + if(isset($view['_table'])) { // 2011/10/17 添加实际表名定义支持 可以实现同一个表的视图 + $tableName .= $view['_table']; + }else{ + $class = $key.'Model'; + $Model = class_exists($class)?new $class():M($key); + $tableName .= $Model->getTableName(); + } + // 表别名定义 + $tableName .= !empty($view['_as'])?' '.$view['_as']:' '.$key; + // 支持ON 条件定义 + $tableName .= !empty($view['_on'])?' ON '.$view['_on']:''; + // 指定JOIN类型 例如 RIGHT INNER LEFT 下一个表有效 + $type = !empty($view['_type'])?$view['_type']:''; + $tableName .= ' '.strtoupper($type).' JOIN '; + $len = strlen($type.'_JOIN '); + } + $tableName = substr($tableName,0,-$len); + $this->trueTableName = $tableName; + } + return $this->trueTableName; + } + + /** + * 表达式过滤方法 + * @access protected + * @param string $options 表达式 + * @return void + */ + protected function _options_filter(&$options) { + if(isset($options['field'])) + $options['field'] = $this->checkFields($options['field']); + else + $options['field'] = $this->checkFields(); + if(isset($options['group'])) + $options['group'] = $this->checkGroup($options['group']); + if(isset($options['where'])) + $options['where'] = $this->checkCondition($options['where']); + if(isset($options['order'])) + $options['order'] = $this->checkOrder($options['order']); + } + + /** + * 检查是否定义了所有字段 + * @access protected + * @param string $name 模型名称 + * @param array $fields 字段数组 + * @return array + */ + private function _checkFields($name,$fields) { + if(false !== $pos = array_search('*',$fields)) {// 定义所有字段 + $fields = array_merge($fields,M($name)->getDbFields()); + unset($fields[$pos]); + } + return $fields; + } + + /** + * 检查条件中的视图字段 + * @access protected + * @param mixed $data 条件表达式 + * @return array + */ + protected function checkCondition($where) { + if(is_array($where)) { + $view = array(); + // 检查视图字段 + foreach ($this->viewFields as $key=>$val){ + $k = isset($val['_as'])?$val['_as']:$key; + $val = $this->_checkFields($key,$val); + foreach ($where as $name=>$value){ + if(false !== $field = array_search($name,$val,true)) { + // 存在视图字段 + $_key = is_numeric($field)? $k.'.'.$name : $k.'.'.$field; + $view[$_key] = $value; + unset($where[$name]); + } + } + } + $where = array_merge($where,$view); + } + return $where; + } + + /** + * 检查Order表达式中的视图字段 + * @access protected + * @param string $order 字段 + * @return string + */ + protected function checkOrder($order='') { + if(is_string($order) && !empty($order)) { + $orders = explode(',',$order); + $_order = array(); + foreach ($orders as $order){ + $array = explode(' ',$order); + $field = $array[0]; + $sort = isset($array[1])?$array[1]:'ASC'; + // 解析成视图字段 + foreach ($this->viewFields as $name=>$val){ + $k = isset($val['_as'])?$val['_as']:$name; + $val = $this->_checkFields($name,$val); + if(false !== $_field = array_search($field,$val,true)) { + // 存在视图字段 + $field = is_numeric($_field)?$k.'.'.$field:$k.'.'.$_field; + break; + } + } + $_order[] = $field.' '.$sort; + } + $order = implode(',',$_order); + } + return $order; + } + + /** + * 检查Group表达式中的视图字段 + * @access protected + * @param string $group 字段 + * @return string + */ + protected function checkGroup($group='') { + if(!empty($group)) { + $groups = explode(',',$group); + $_group = array(); + foreach ($groups as $field){ + // 解析成视图字段 + foreach ($this->viewFields as $name=>$val){ + $k = isset($val['_as'])?$val['_as']:$name; + $val = $this->_checkFields($name,$val); + if(false !== $_field = array_search($field,$val,true)) { + // 存在视图字段 + $field = is_numeric($_field)?$k.'.'.$field:$k.'.'.$_field; + break; + } + } + $_group[] = $field; + } + $group = implode(',',$_group); + } + return $group; + } + + /** + * 检查fields表达式中的视图字段 + * @access protected + * @param string $fields 字段 + * @return string + */ + protected function checkFields($fields='') { + if(empty($fields) || '*'==$fields ) { + // 获取全部视图字段 + $fields = array(); + foreach ($this->viewFields as $name=>$val){ + $k = isset($val['_as'])?$val['_as']:$name; + $val = $this->_checkFields($name,$val); + foreach ($val as $key=>$field){ + if(is_numeric($key)) { + $fields[] = $k.'.'.$field.' AS '.$field; + }elseif('_' != substr($key,0,1)) { + // 以_开头的为特殊定义 + if( false !== strpos($key,'*') || false !== strpos($key,'(') || false !== strpos($key,'.')) { + //如果包含* 或者 使用了sql方法 则不再添加前面的表名 + $fields[] = $key.' AS '.$field; + }else{ + $fields[] = $k.'.'.$key.' AS '.$field; + } + } + } + } + $fields = implode(',',$fields); + }else{ + if(!is_array($fields)) + $fields = explode(',',$fields); + // 解析成视图字段 + $array = array(); + foreach ($fields as $key=>$field){ + if(strpos($field,'(') || strpos(strtolower($field),' as ')){ + // 使用了函数或者别名 + $array[] = $field; + unset($fields[$key]); + } + } + foreach ($this->viewFields as $name=>$val){ + $k = isset($val['_as'])?$val['_as']:$name; + $val = $this->_checkFields($name,$val); + foreach ($fields as $key=>$field){ + if(false !== $_field = array_search($field,$val,true)) { + // 存在视图字段 + if(is_numeric($_field)) { + $array[] = $k.'.'.$field.' AS '.$field; + }elseif('_' != substr($_field,0,1)){ + if( false !== strpos($_field,'*') || false !== strpos($_field,'(') || false !== strpos($_field,'.')) + //如果包含* 或者 使用了sql方法 则不再添加前面的表名 + $array[] = $_field.' AS '.$field; + else + $array[] = $k.'.'.$_field.' AS '.$field; + } + } + } + } + $fields = implode(',',$array); + } + return $fields; + } +} \ No newline at end of file diff --git a/ThinkPHP/Extend/README.txt b/ThinkPHP/Extend/README.txt new file mode 100644 index 0000000..06eef0c --- /dev/null +++ b/ThinkPHP/Extend/README.txt @@ -0,0 +1,25 @@ +注意:下载后的扩展需要放入系统目录下面的Extend目录的相同位置。 + +Extend目录为系统扩展目录(核心版不含任何扩展),子目录结构为: + +|-Action 控制器扩展 +|-Behavior 行为扩展 +|-Driver 驱动扩展 +| ├Driver/Cache 缓存驱动 +| ├Driver/Db 数据库驱动 +| ├Driver/Session SESSION驱动 +| ├Driver/TagLib 标签库驱动 +| ├Driver/Template 模板引擎驱动 +| +|-Engine 引擎扩展 +|-Function 函数扩展 +|-Library 类库扩展 +| ├ORG ORG类库包 +| ├COM COM类库包 +| +|-Mode 模式扩展 +|-Model 模型扩展 +|-Tool 其他扩展或工具 +|-Vendor 第三方类库目录 + +关于扩展的详细使用,请参考开发手册的扩展章节。 \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/.htaccess b/ThinkPHP/Extend/Tool/Requirements-Checker/.htaccess new file mode 100644 index 0000000..da30fd5 --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/.htaccess @@ -0,0 +1 @@ +php_value display_errors 'On' \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/checker.phtml b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/checker.phtml new file mode 100644 index 0000000..e0db304 --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/checker.phtml @@ -0,0 +1,218 @@ + + + + + + + + + ThinkPHP环境探针 + + + + + + + +
    +

    ThinkPHP框架环境探针

    + +

    本脚本检测是否你的PHP配置满足运行ThinkPHP框架.它检测了PHP版本,是否合适的PHP扩展被加载了,还有是否PHP配置设置正确.

    + + +
    +

    对不起,你的服务器配置不满足ThinkPHP框架的要求.

    +
    + +
    +

    祝贺你!服务器配置满足ThinkPHP框架的要求.

    +

    请看下面列出的警告项.

    +
    + + + +

    详情

    + + + $requirement):?> + passed) ? ($requirement->passed ? 'passed' : ($requirement->required ? 'failed' : 'warning')) : 'info' ?> + + + + passed) && isset($requirement->errorMessage)): ?> + + message)): ?> + + passed)): ?> + + + + + + + description)): ?> + + + + + + script)): ?> + script ?> + + + +
    title) ?>errorMessage) ?>message) ?>passed ? '支持' : '不支持' ?>未测试
    description ?>
    + +

    请检查错误信息然后再试一次.

    + +

    探针版本

    +
    + + \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/.htaccess b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/.htaccess new file mode 100644 index 0000000..22b9ed2 --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/.htaccess @@ -0,0 +1,2 @@ +Order Allow,Deny +Deny from all \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/checker.js b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/checker.js new file mode 100644 index 0000000..4deeafe --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/checker.js @@ -0,0 +1 @@ +fileProtectionChecker = true; diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/web.config b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/web.config new file mode 100644 index 0000000..830e021 --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/denied/web.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/failed.gif b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/failed.gif new file mode 100644 index 0000000..33b146b Binary files /dev/null and b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/failed.gif differ diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/info.gif b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/info.gif new file mode 100644 index 0000000..f74df45 Binary files /dev/null and b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/info.gif differ diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/logo.png b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/logo.png new file mode 100644 index 0000000..c687118 Binary files /dev/null and b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/logo.png differ diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/passed.gif b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/passed.gif new file mode 100644 index 0000000..ed23561 Binary files /dev/null and b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/passed.gif differ diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/.htaccess b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/.htaccess new file mode 100644 index 0000000..b64de8f --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/.htaccess @@ -0,0 +1,2 @@ +RewriteEngine On +RewriteRule .* checker.js [L] diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/checker.js b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/checker.js new file mode 100644 index 0000000..75ddc52 --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/checker.js @@ -0,0 +1 @@ +modRewriteChecker = true; diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/web.config b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/web.config new file mode 100644 index 0000000..a75b224 --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/rewrite/web.config @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/assets/warning.gif b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/warning.gif new file mode 100644 index 0000000..8322f65 Binary files /dev/null and b/ThinkPHP/Extend/Tool/Requirements-Checker/assets/warning.gif differ diff --git a/ThinkPHP/Extend/Tool/Requirements-Checker/checker.php b/ThinkPHP/Extend/Tool/Requirements-Checker/checker.php new file mode 100644 index 0000000..30f14b5 --- /dev/null +++ b/ThinkPHP/Extend/Tool/Requirements-Checker/checker.php @@ -0,0 +1,278 @@ + 'Web服务器', + 'message' => $_SERVER['SERVER_SOFTWARE'], +); + +$tests[] = array( + 'title' => 'PHP版本', + 'required' => TRUE, + 'passed' => version_compare(PHP_VERSION, '5.2.0', '>='), + 'message' => PHP_VERSION, + 'description' => '你的PHP太低了.ThinkPHP框架需要至少PHP 5.2.0或更高.', +); + +$tests[] = array( + 'title' => 'Memory限制', + 'message' => ini_get('memory_limit'), +); + +$tests['hf'] = array( + 'title' => '.htaccess文件保护', + 'required' => FALSE, + 'description' => '通过.htaccess的File保护不支持.你必须小心的放入文件到document_root目录.', + 'script' => '', +); + +$tests['hr'] = array( + 'title' => '.htaccess mod_rewrite', + 'required' => FALSE, + 'description' => 'Mod_rewrite可能不支持.你将无法使用Cool URL(URL_MODEL=2不启作用,入口文件无法隐藏).', + 'script' => '', +); + +$tests[] = array( + 'title' => '函数ini_set()', + 'required' => FALSE, + 'passed' => function_exists('ini_set'), + 'description' => '函数ini_set()不支持.部分ThinkPHP框架功能可能工作不正常.', +); + +$tests[] = array( + 'title' => '函数error_reporting()', + 'required' => TRUE, + 'passed' => function_exists('error_reporting'), + 'description' => '函数error_reporting()不支持. ThinkPHP框架需要这个被启用', +); + +// $tests[] = array( +// 'title' => 'Function flock()', +// 'required' => TRUE, +// 'passed' => flock(fopen(__FILE__, 'r'), LOCK_SH), +// 'description' => 'Function flock() is not supported on this filesystem. ThinkPHP Framework requires this to process atomic file operations.', +// ); + +$tests[] = array( + 'title' => 'Register_globals', + 'required' => TRUE, + 'passed' => iniFlag('register_globals'), + 'message' => '启用', + 'errorMessage' => '不支持', + 'description' => '配置Configuration显示register_globals禁用了. ThinkPHP框架要求此项开启.', +); + +// $tests[] = array( +// 'title' => 'Variables_order', +// 'required' => TRUE, +// 'passed' => strpos(ini_get('variables_order'), 'G') !== FALSE && strpos(ini_get('variables_order'), 'P') !== FALSE && strpos(ini_get('variables_order'), 'C') !== FALSE, +// 'description' => 'Configuration directive variables_order is missing. ThinkPHP Framework requires this to be set.', +// ); + +$tests[] = array( + 'title' => 'Session auto-start', + 'required' => FALSE, + 'passed' => session_id() === '' && !defined('SID'), + 'description' => 'Session auto-start启用了. ThinkPHP框架默认情况下,初始化之后系统会自动启动session.', +); + +$tests[] = array( + 'title' => 'Reflection扩展', + 'required' => TRUE, + 'passed' => class_exists('ReflectionFunction'), + 'description' => 'ThinkPHP必须开启Reflection扩展.', +); + +// $tests[] = array( +// 'title' => 'SPL extension', +// 'required' => TRUE, +// 'passed' => extension_loaded('SPL'), +// 'description' => 'SPL extension is required.', +// ); + +$tests[] = array( + 'title' => 'PCRE扩展', + 'required' => TRUE, + 'passed' => extension_loaded('pcre') && @preg_match('/pcre/u', 'pcre'), + 'message' => '支持并且工作正常', + 'errorMessage' => '禁用或者不支持UTF-8', + 'description' => 'PCRE扩展推荐开启并支持UTF-8.', +); + +$tests[] = array( + 'title' => 'ICONV扩展', + 'required' => TRUE, + 'passed' => extension_loaded('iconv') && (ICONV_IMPL !== 'unknown') && @iconv('UTF-16', 'UTF-8//IGNORE', iconv('UTF-8', 'UTF-16//IGNORE', 'test')) === 'test', + 'message' => '支持并且工作正常', + 'errorMessage' => '禁用或者工作不正常', + 'description' => 'ICONV扩展必须且工作正常.', +); + +// $tests[] = array( +// 'title' => 'PHP tokenizer', +// 'required' => TRUE, +// 'passed' => extension_loaded('tokenizer'), +// 'description' => 'PHP tokenizer is required.', +// ); + +$tests[] = array( + 'title' => 'PDO扩展', + 'required' => FALSE, + 'passed' => $pdo = extension_loaded('pdo') && PDO::getAvailableDrivers(), + 'message' => $pdo ? '可用驱动有drivers: ' . implode(' ', PDO::getAvailableDrivers()) : NULL, + 'description' => 'PDO扩展或者PDO驱动不支持.你将不能使用ThinkPHP\DbPdo.', +); + +$tests[] = array( + 'title' => '多字节字符串扩展', + 'required' => FALSE, + 'passed' => extension_loaded('mbstring'), + 'description' => 'Multibyte String扩展不支持.一些国际化组件可能无法正常工作.', +); + +$tests[] = array( + 'title' => '多字节字符串overloading函数', + 'required' => TRUE, + 'passed' => !extension_loaded('mbstring') || !(mb_get_info('func_overload') & 2), + 'message' => '禁用', + 'errorMessage' => '启用', + 'description' => '启用了多字节字符串重载函数. ThinkPHP框架要求这项被禁用.如果它开启着,一些字符串函数将可能工作不正常.', +); + +$tests[] = array( + 'title' => 'Memcache扩展', + 'required' => FALSE, + 'passed' => extension_loaded('memcache'), + 'description' => 'Memcache扩展不支持.你将不能使用Memcache作为ThinkPHP的缓存方式.', +); + +$tests[] = array( + 'title' => 'GD扩展', + 'required' => TRUE, + 'passed' => extension_loaded('gd'), + 'description' => 'GD扩展不支持. 你将不能使用ThinkPHP\Image类.', +); + +$tests[] = array( + 'title' => 'Imagick扩展', + 'required' => FALSE, + 'passed' => extension_loaded('imagick'), + 'description' => 'Imagick扩展不支持. 你将不能使用Imagick进行高效图像处理.', +); + +// $tests[] = array( +// 'title' => 'Bundled GD extension', +// 'required' => FALSE, +// 'passed' => extension_loaded('gd') && GD_BUNDLED, +// 'description' => 'Bundled GD extension is absent. You will not be able to use some functions such as ThinkPHP\Image::filter() or ThinkPHP\Image::rotate().', +// ); + +$tests[] = array( + 'title' => 'Fileinfo扩展 或 mime_content_type()', + 'required' => FALSE, + 'passed' => extension_loaded('fileinfo') || function_exists('mime_content_type'), + 'description' => 'Fileinfo 扩展或者 函数mime_content_type() 不支持.你将不能检测上传文件的mime类型.', +); + +// $tests[] = array( +// 'title' => 'HTTP_HOST or SERVER_NAME', +// 'required' => TRUE, +// 'passed' => isset($_SERVER["HTTP_HOST"]) || isset($_SERVER["SERVER_NAME"]), +// 'message' => 'Present', +// 'errorMessage' => 'Absent', +// 'description' => 'Either $_SERVER["HTTP_HOST"] or $_SERVER["SERVER_NAME"] must be available for resolving host name.', +// ); + +$tests[] = array( + 'title' => 'REQUEST_URI 或 ORIG_PATH_INFO', + 'required' => TRUE, + 'passed' => isset($_SERVER["REQUEST_URI"]) || isset($_SERVER["ORIG_PATH_INFO"]), + 'message' => '支持', + 'errorMessage' => '不支持', + 'description' => ' $_SERVER["REQUEST_URI"] 或者$_SERVER["ORIG_PATH_INFO"]必学能获取到用于分解请求的URL.', +); + +// $tests[] = array( +// 'title' => 'DOCUMENT_ROOT & SCRIPT_FILENAME or SCRIPT_NAME', +// 'required' => TRUE, +// 'passed' => isset($_SERVER['DOCUMENT_ROOT'], $_SERVER['SCRIPT_FILENAME']) || isset($_SERVER['SCRIPT_NAME']), +// 'message' => 'Present', +// 'errorMessage' => 'Absent', +// 'description' => '$_SERVER["DOCUMENT_ROOT"] and $_SERVER["SCRIPT_FILENAME"] or $_SERVER["SCRIPT_NAME"] must be available for resolving script file path.', +// ); + +// $tests[] = array( +// 'title' => 'SERVER_ADDR or LOCAL_ADDR', +// 'required' => TRUE, +// 'passed' => isset($_SERVER["SERVER_ADDR"]) || isset($_SERVER["LOCAL_ADDR"]), +// 'message' => 'Present', +// 'errorMessage' => 'Absent', +// 'description' => '$_SERVER["SERVER_ADDR"] or $_SERVER["LOCAL_ADDR"] must be available for detecting development / production mode.', +// ); + +paint($tests); +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// +/** + * Paints checker. + * @param array + * @return void + */ +function paint($requirements){ + $errors = $warnings = FALSE; + + foreach ($requirements as $id => $requirement){ + $requirements[$id] = $requirement = (object) $requirement; + if (isset($requirement->passed) && !$requirement->passed) { + if ($requirement->required) { + $errors = TRUE; + } else { + $warnings = TRUE; + } + } + } + + require TEMPLATE_FILE; +} + +/** + * 获取配置项的布尔值. + * @param string 配置项名称 + * @return bool + */ +function iniFlag($var){ + $status = strtolower(ini_get($var)); + return $status === 'on' || $status === 'true' || $status === 'yes' || (int) $status; +} \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/TPM/SwitchMobileTplBehavior.class.php b/ThinkPHP/Extend/Tool/TPM/SwitchMobileTplBehavior.class.php new file mode 100644 index 0000000..7a7d788 --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/SwitchMobileTplBehavior.class.php @@ -0,0 +1,25 @@ +$replace))); + //判断如果是云窗调试器访问跳转访问首页到client目录 + if(APP_DEBUG && ''==__INFO__ && preg_match('/android|iphone/i',$_SERVER['HTTP_USER_AGENT'])){ + redirect(__ROOT__.'/client'); + exit(); + } + } + } + } +} diff --git a/ThinkPHP/Extend/Tool/TPM/TemplateMobile.class.php b/ThinkPHP/Extend/Tool/TPM/TemplateMobile.class.php new file mode 100644 index 0000000..77e3b02 --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/TemplateMobile.class.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * MobileTemplate模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author luofei614 + */ +class TemplateMobile { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile=substr($templateFile,strlen(THEME_PATH)); + if($tpm_theme=C('TPM_THEME')){ + $tpm_theme.='/'; + }else{ + $tpm_theme=''; + } + $var['_think_template_path']=$tpm_theme.$templateFile; + exit(json_encode($var)); + } +} diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Index/index.html b/ThinkPHP/Extend/Tool/TPM/Tpl/Index/index.html new file mode 100644 index 0000000..cb6bdd0 --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Index/index.html @@ -0,0 +1 @@ +欢迎使用 TPM! diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/css/TPMlist.css b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/css/TPMlist.css new file mode 100644 index 0000000..e8dfa4e --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/css/TPMlist.css @@ -0,0 +1,42 @@ +.pullDown{ + background:#fff; + height:40px; + line-height:40px; + padding:5px 10px; + border-bottom:1px solid #ccc; + font-weight:bold; + font-size:14px; + color:#888; +} +.pullDown .pullDownIcon{ + display:block; float:left; + width:40px; height:40px; + background:url(TPMlist-pull-icon-2x.png) 0 0 no-repeat; + -webkit-background-size:40px 80px; background-size:40px 80px; + -webkit-transition-property:-webkit-transform; + -webkit-transition-duration:250ms; +} +.pullDown .pullDownIcon { + -webkit-transform:rotate(0deg) translateZ(0); +} + +.pullDown.flip .pullDownIcon { + -webkit-transform:rotate(-180deg) translateZ(0); +} + + +.pullDown.loading .pullDownIcon { + background-position:0 100%; + -webkit-transform:rotate(0deg) translateZ(0); + -webkit-transition-duration:0ms; + + -webkit-animation-name:loading; + -webkit-animation-duration:2s; + -webkit-animation-iteration-count:infinite; + -webkit-animation-timing-function:linear; +} + +@-webkit-keyframes loading { + from { -webkit-transform:rotate(0deg) translateZ(0); } + to { -webkit-transform:rotate(360deg) translateZ(0); } +} diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/css/TPMmodal.css b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/css/TPMmodal.css new file mode 100644 index 0000000..1ff0a6e --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/css/TPMmodal.css @@ -0,0 +1,201 @@ +#tpm_backdrop{ + opacity: 0; + filter: alpha(opacity=0); + transition:opacity 0.3s; + position:fixed; + top:0; + left:0; + right:0; + bottom:0; + background:#000; + display:none; + z-index:3000; +} + +#tpm_backdrop.in{ + display:block; + opacity:0.8; + filter: alpha(opacity=80); +} + +#tpm_modal{ + top:-50%; + position:fixed; + left:50%; + width:560px; + margin-left:-280px; + transition:top 0.3s; + z-index:3001; + background:#fff; + border-radius:6px; + display:none; +} + +#tpm_modal.in{ + top:10%; + display:block; +} +#tpm_modal .tpm_modal_head{ + padding:9px 15px; + border-bottom: 1px solid #EEEEEE; + position:relative; +} +#tpm_modal .tpm_modal_head .tpm_modal_close{ + position:absolute; + right:10px; + top:10px; + text-decoration:none; + font-size: 16px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +#tpm_modal .tpm_modal_head h3{ + margin:0px; + padding:0px; + font-size:18px; + color:#333; +} +#tpm_modal .tpm_modal_body{ + padding:15px; +} +#tpm_modal .tpm_modal_foot{ + background:#F5F5F5; + border-radius:0 0 6px 6px; + border-top:1px solid #DDDDDD; + box-shadow:0 1px 0 #FFFFFF inset; + padding:14px 15px 15px; + text-align:right; +} +.tpm_modal_foot button{ + border-radius:2px; + background:#0078E7; + color:#fff; + border:none; + padding:0.5em 1.5em; +} +.tpm_modal_foot button:hover{ + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#00000000', GradientType=0); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.05))); + background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.15)); + background-image: -moz-linear-gradient(top, rgba(0,0,0, 0.05) 0%, rgba(0,0,0, 0.05)); + background-image: -ms-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.15)); + background-image: -o-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.05)); + background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.05)); +} +.tpm_modal_foot button.tpm_modal_cancel{ + color:#444; + background-color:#E6E6E6; + margin-right:15px; +} + +#tpm_modal_phone{ + bottom:-50%; + position:fixed; + width:100%; + transition:bottom 0.3s; + z-index:3001; + background:#eee; + display:none; +} + +#tpm_modal_phone.in{ + bottom:0; + display:block; +} + +#tpm_modal_phone .tpm_modal_head{ + padding:9px 10px; +} +#tpm_modal_phone .tpm_modal_head h3{ + margin:0px; + padding:0px; + font-size:16px; + color:#333; +} + +#tpm_modal_phone .tpm_modal_body{ + padding:10px 20px 20px 20px; +} + +#tpm_modal_phone .tpm_modal_foot{ + border-top:1px solid #DDDDDD; + box-shadow:0 1px 0 #FFFFFF inset; + padding:14px 10px 10px; + text-align:right; +} + +#tpm_modal_iframe{ + margin:0px; + padding:0px; + border:none; + overflow:auto; + width:100%; + height:350px; +} + +#tpm_info{ + position:fixed; + top:-30%; + left:50%; + width:200px; + margin-left:-100px; + text-align:center; + opacity:0; + filter: alpha(opacity=0); + border-radius:6px; + background:#5FC6DA; + color:#fff; + padding:10px; + display:none; + z-index:3001; + transition:0.3s; +} +#tpm_info.in{ + top:10%; + opacity:1; + filter: alpha(opacity=100); +} + +#tpm_info_phone{ + position:fixed; + bottom:-30%; + opacity:0; + filter:alpha(opacity=0); + width:100%; + background:#5FC6DA; + color:#fff; + padding:5px; + text-align:center; + transition:0.3s; + z-index:3001; + display:none; +} +#tpm_info_phone.in{ + bottom:0; + opacity:0.8; + filter:alpha(opacity=80); +} + + +@media (max-width:767px) { +#tpm_modal{ + left:2%; + right:2%; + width:auto; + margin-left:0px; +} + +#tpm_modal.in{ + top:5%; +} + +#tpm_modal_iframe{ + height:250px; +} + +} diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/.TPM.js.swp b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/.TPM.js.swp new file mode 100644 index 0000000..1d04e1c Binary files /dev/null and b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/.TPM.js.swp differ diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPM.js b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPM.js new file mode 100644 index 0000000..c0a7845 --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPM.js @@ -0,0 +1,835 @@ +//ThinkTemplate 用js实现了ThinkPHP的模板引擎。 +//用户可以在手机客户端中用ThinkPHP的模板引擎。 +//@author luofei614 +// +var ThinkTemplate={ + tags:['Include','Volist','Foreach','For','Empty','Notempty','Present','Notpresent','Compare','If','Elseif','Else','Swith','Case','Default','Var','Range'], + parse:function(tplContent,vars){ + var render=function(){ + tplContent='<% var key,mod=0;%>'+tplContent;//定义模板中循环需要使用的到变量 + $.each(ThinkTemplate.tags,function(k,v){ + tplContent=ThinkTemplate['parse'+v](tplContent); + }); + return ThinkTemplate.template(tplContent,vars); + }; + + return render(); + }, + //解析 <% %> 标签 + template:function(text,vars){ + var source=""; + var index=0; + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + text.replace(/<%=([\s\S]+?)%>|<%([\s\S]+?)%>/g,function(match,interpolate,evaluate,offset){ + var p=text.slice(index,offset).replace(escaper,function(match){ + return '\\'+escapes[match]; + }); + if(''!=$.trim(p)){ + source+="__p+='"+p+"';\n"; + } + + if(evaluate){ + source+=evaluate+"\n"; + } + if(interpolate){ + source+="if( 'undefined'!=typeof("+interpolate+") && (__t=(" + interpolate + "))!=null) __p+=__t;\n"; + } + index=offset+match.length; + return match; + }); + source+="__p+='"+text.slice(index).replace(escaper,function(match){ return '\\'+escapes[match]; })+"';\n";//拼接剩余的字符串 + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + "with(obj){\n"+ + source + + "}\n"+ + "return __p;\n"; + try { + render = new Function('obj', source); + + } catch (e) { + e.source = source; + throw e; + } + return render(vars); + }, + parseVar:function(tplContent){ + var matcher=/\{\$(.*?)\}/g + return tplContent.replace(matcher,function(match,varname,offset){ + //支持定义默认值 + if(varname.indexOf('|')!=-1){ + var arr=varname.split('|'); + var name=arr[0]; + var defaultvalue='""'; + arr[1].replace(/default=(.*?)$/ig,function(m,v,o){ + defaultvalue=v; + }); + return '<% '+name+'?print('+name+'):print('+defaultvalue+'); %>'; + } + return '<%='+varname+'%>'; + }); + }, + //include标签解析 路径需要写全,写为 Action:method, 暂不支持变量。 + parseInclude:function(tplContent){ + var include=//ig; + tplContent=tplContent.replace(include,function(m,v,o){ + var $think=$(''); + var file=$think.attr('file').replace(':','/')+'.html'; + var content=''; + //加载模板 + $.ajax({ + dataType:'text', + url:file, + cache:false, + async:false,//同步请求 + success:function(d,s,x){ + content=d; + }, + error:function(){ + //pass + } + }); + return content; + }); + tplContent=tplContent.replace('','');//兼容浏览器中元素自动闭合的情况 + return tplContent; + }, + //volist标签解析 + parseVolist:function(tplContent){ + var voliststart=//ig; + var volistend=/<\/volist>/ig; + //解析volist开始标签 + tplContent=tplContent.replace(voliststart,function(m,v,o){ + //属性分析 + var $think=$(''); + var name=$think.attr('name'); + var id=$think.attr('id'); + var empty=$think.attr('empty')||''; + var key=$think.attr('key')||'i'; + var mod=$think.attr('mod')||'2'; + //替换为代码 + return '<% if("undefined"==typeof('+name+') || ThinkTemplate.empty('+name+')){'+ + ' print(\''+empty+'\');'+ + ' }else{ '+ + key+'=0;'+ + ' $.each('+name+',function(key,'+id+'){'+ + ' mod='+key+'%'+mod+';'+ + ' ++'+key+';'+ + ' %>'; + }); + //解析volist结束标签 + tplContent=tplContent.replace(volistend,'<% }); } %>'); + return tplContent; + }, + //解析foreach标签 + parseForeach:function(tplContent){ + var foreachstart=//ig; + var foreachend=/<\/foreach>/i; + tplContent=tplContent.replace(foreachstart,function(m,v,o){ + var $think=$(''); + var name=$think.attr('name'); + var item=$think.attr('item'); + var key=$think.attr('key')||'key'; + return '<% $.each('+name+',function('+key+','+item+'){ %>' + }); + tplContent=tplContent.replace(foreachend,'<% }); %>'); + return tplContent; + }, + parseFor:function(tplContent){ + var forstart=//ig; + var forend=/<\/for>/ig; + tplContent=tplContent.replace(forstart,function(m,v,o){ + var $think=$(''); + var name=$think.attr('name') || 'i'; + var comparison=$think.attr('comparison') || 'lt'; + var start=$think.attr('start') || '0'; + if('$'==start.substr(0,1)){ + start=start.substr(1); + } + var end=$think.attr('end') || '0'; + if('$'==end.substr(0,1)){ + end=end.substr(1); + } + var step=$think.attr('step') || '1'; + if('$'==step.substr(0,1)){ + step=step.substr(1); + } + return '<% for(var '+name+'='+start+';'+ThinkTemplate.parseCondition(name+comparison+end)+';i=i+'+step+'){ %>' + }); + tplContent=tplContent.replace(forend,'<% } %>'); + return tplContent; + }, + //empty标签 + parseEmpty:function(tplContent){ + var emptystart=//ig; + var emptyend=/<\/empty>/ig; + tplContent=tplContent.replace(emptystart,function(m,v,o){ + var name=$('').attr('name'); + return '<% if("undefined"==typeof('+name+') || ThinkTemplate.empty('+name+')){ %>'; + }); + tplContent=tplContent.replace(emptyend,'<% } %>'); + return tplContent; + }, + //notempty 标签解析 + parseNotempty:function(tplContent){ + var notemptystart=//ig; + var notemptyend=/<\/notempty>/ig; + tplContent=tplContent.replace(notemptystart,function(m,v,o){ + var name=$('').attr('name'); + return '<% if("undefined"!=typeof('+name+') && !ThinkTemplate.empty('+name+')){ %>'; + }); + tplContent=tplContent.replace(notemptyend,'<% } %>'); + return tplContent; + }, + //present标签解析 + parsePresent:function(tplContent){ + var presentstart=//ig; + var presentend=/<\/present>/ig; + tplContent=tplContent.replace(presentstart,function(m,v,o){ + var name=$('').attr('name'); + return '<% if("undefined"!=typeof('+name+')){ %>'; + }); + tplContent=tplContent.replace(presentend,'<% } %>'); + return tplContent; + }, + //notpresent 标签解析 + parseNotpresent:function(tplContent){ + var notpresentstart=//ig; + var notpresentend=/<\/notpresent>/ig; + tplContent=tplContent.replace(notpresentstart,function(m,v,o){ + var name=$('').attr('name'); + return '<% if("undefined"==typeof('+name+')){ %>'; + }); + tplContent=tplContent.replace(notpresentend,'<% } %>'); + return tplContent; + }, + parseCompare:function(tplContent){ + var compares={ + "compare":"==", + "eq":"==", + "neq":"!=", + "heq":"===", + "nheq":"!==", + "egt":">=", + "gt":">", + "elt":"<=", + "lt":"<" + }; + $.each(compares,function(type,sign){ + var start=new RegExp('<'+type+' (.*?)>','ig'); + var end=new RegExp('','ig'); + tplContent=tplContent.replace(start,function(m,v,o){ + var $think=$(''); + var name=$think.attr('name'); + var value=$think.attr('value'); + if("compare"==type && $think.attr('type')){ + sign=compares[$think.attr('type')]; + } + if('$'==value.substr(0,1)){ + //value支持变量 + value=value.substr(1); + }else{ + value='"'+value+'"'; + } + return '<% if('+name+sign+value+'){ %>'; + }); + tplContent=tplContent.replace(end,'<% } %>'); + + }); + return tplContent; + }, + //解析if标签 + parseIf:function(tplContent){ + var ifstart=//ig; + var ifend=/<\/if>/ig; + tplContent=tplContent.replace(ifstart,function(m,v,o){ + var condition=$('').attr('condition'); + return '<% if('+ThinkTemplate.parseCondition(condition)+'){ %>'; + }); + tplContent=tplContent.replace(ifend,'<% } %>'); + return tplContent; + }, + //解析elseif + parseElseif:function(tplContent){ + var elseif=//ig; + tplContent=tplContent.replace(elseif,function(m,v,o){ + var condition=$('').attr('condition'); + return '<% }else if('+ThinkTemplate.parseCondition(condition)+'){ %>'; + }); + tplContent=tplContent.replace('',''); + return tplContent; + }, + //解析else标签 + parseElse:function(tplContent){ + var el=//ig + tplContent=tplContent.replace(el,'<% }else{ %>'); + tplContent=tplContent.replace('',''); + return tplContent; + }, + //解析swith标签 + parseSwith:function(tplContent){ + var switchstart=/(\s*)/ig; + var switchend=/<\/switch>/ig; + tplContent=tplContent.replace(switchstart,function(m,v,s,o){ + var name=$('').attr('name'); + return '<% switch('+name+'){ %>'; + }); + tplContent=tplContent.replace(switchend,'<% } %>'); + return tplContent; + }, + //解析case标签 + parseCase:function(tplContent){ + var casestart=//ig; + var caseend=/<\/case>/ig; + var breakstr=''; + tplContent=tplContent.replace(casestart,function(m,v,o){ + var $think=$(''); + var value=$think.attr('value'); + if('$'==value.substr(0,1)){ + value=value.substr(1); + }else{ + value='"'+value+'"'; + } + if('false'!=$think.attr('break')){ + breakstr='<% break; %> '; + } + return '<% case '+value+': %>'; + }); + tplContent=tplContent.replace(caseend,breakstr); + return tplContent; + }, + //解析default标签 + parseDefault:function(tplContent){ + var defaulttag=//ig; + tplContent=tplContent.replace(defaulttag,'<% default: %>'); + tplContent=tplContent.replace('',''); + return tplContent; + }, + //解析in,notin,between,notbetween 标签 + parseRange:function(tplContent){ + var ranges=['in','notin','between','notbetween']; + $.each(ranges,function(k,tag){ + var start=new RegExp('<'+tag+' (.*?)>','ig'); + var end=new RegExp('','ig'); + tplContent=tplContent.replace(start,function(m,v,o){ + var $think=$(''); + var name=$think.attr('name'); + var value=$think.attr('value'); + if('$'==value.substr(0,1)){ + value=value.substr(1); + }else{ + value='"'+value+'"'; + } + switch(tag){ + case "in": + var condition='ThinkTemplate.inArray('+name+','+value+')'; + break; + case "notin": + var condition='!ThinkTemplate.inArray('+name+','+value+')'; + break; + case "between": + var condition=name+'>='+value+'[0] && '+name+'<='+value+'[1]'; + break; + case "notbetween": + var condition=name+'<'+value+'[0] || '+name+'>'+value+'[1]'; + break; + } + return '<% if('+condition+'){ %>' + }); + tplContent=tplContent.replace(end,'<% } %>') + }); + return tplContent; + }, + //扩展 + extend:function(name,cb){ + name=name.substr(0,1).toUpperCase()+name.substr(1); + this.tags.push(name); + this['parse'+name]=cb; + }, + //判断是否在数组中,支持判断object类型的数据 + inArray:function(name,value){ + if('string'==$.type(value)){ + value=value.split(','); + } + var ret=false; + $.each(value,function(k,v){ + if(v==name){ + ret=true; + return false; + } + }); + return ret; + }, + empty:function(data){ + if(!data) + return true; + if('array'==$.type(data) && 0==data.length) + return true; + if('object'==$.type(data) && 0==Object.keys(data).length) + return true; + return false; + }, + parseCondition:function(condition){ + var conditions={ + "eq":"==", + "neq":"!=", + "heq":"===", + "nheq":"!==", + "egt":">=", + "gt":">", + "elt":"<=", + "lt":"<", + "or":"||", + "and":"&&", + "\\$":"" + }; + $.each(conditions,function(k,v){ + var matcher=new RegExp(k,'ig'); + condition=condition.replace(matcher,v); + }); + return condition; + } + + +}; + +//TPMobi框架 +//实现用ThinkPHP做手机客户端 +//@author luofei614 +var TPM={ + op:{ + api_base:'',//接口基地址,末尾不带斜杠 + api_index:'/Index/index',//首页请求地址 + main:"main",//主体层的ID + routes:{}, //路由,支持参数如:id 支持通配符* + error_handle:false,//错误接管函数 + _before:[], + _ready:[],//UI回调函数集合 + single:true,//单一入口模式 + + ajax_wait:".ajax_wait",//正在加载层的选择符 + ajax_timeout:15000,//ajax请求超时时间 + ajax_data_type:'',//请求接口类型 如json,jsonp + ajax_jsonp_callback:'callback',//jsonp 传递的回调函数参数名词 + + before_request_api:false,//请求接口之前的hook + //请求接口之后的hook,处理TP的success和error + after_request_api:function(data,url){ + if(data.info){ + TPM.info(data.info,function(){ + if(data.url){ + TPM.http(data.url); + }else if(1==data.status){ + //如果success, 刷新数据 + TPM.reload(TPM.op.main); + } + }); + return false; + } + }, + + anchor_move_speed:500, //移动到锚点的速度 + + tpl_path_var:'_think_template_path',//接口指定模板 + + tpl_parse_string:{ + '../Public':'./Public' + },//模板替换变量 + + //指定接口请求的header + headers:{ + 'client':'PhoneClient', + //跨域请求时,不会带X-Requested-with 的header,会导致服务认为不是ajax请求,所以这样手动加上这个header 。 + 'X-Requested-With':'XMLHttpRequest' + }, + + tpl:ThinkTemplate.parse//模板引擎 + + }, + config:function(options){ + $.extend(this.op,options); + }, + ready:function(fun){ + this.op._ready.push(fun); + }, + before:function(fun){ + this.op._before.push(fun); + }, + //输出错误 + error:function(errno,msg){ + TPM.alert('错误['+errno+']:'+msg); + }, + info:function(msg,cb){ + if('undefined'==typeof(tpm_info)){ + alert(msg); + if($.isFunction(cb)) cb(); + }else{ + tpm_info(msg,cb); + } + }, + alert:function(msg,cb,title){ + if('undefined'==typeof(tpm_alert)){ + alert(msg); + if($.isFunction(cb)) cb(); + }else{ + tpm_alert(msg,cb,title); + } + }, + //初始化运行 + run:function(options,vars){ + if(!this.defined(window.jQuery) && !this.defined(window.Zepto)){ + this.error('-1','请加载jquery或zepto'); + return ; + } + //如果只设置api_base 可以只传递一个字符串。 + if('string'==$.type(options)){ + options={api_base:options}; + } + //配置处理 + options=options||{}; + this.config(options); + $.ajaxSetup({ + error:this.ajaxError, + timeout:this.op.ajax_timeout || 5000, + cache:false, + headers:this.op.headers + }); + var _self=this; + //ajax加载状态 + window.TPMshowAjaxWait=true; + $(document).ajaxStart(function(){ + //在程序中可以设置TPMshowAjaxWait为false,终止显示等待层。 + if(window.TPMshowAjaxWait) $(_self.op.ajax_wait).show(); + } + ).ajaxStop(function(){ + $(_self.op.ajax_wait).hide(); + }); + $(document).ready(function(){ + //标签解析 + vars=vars||{}; + var render=function(vars){ + var tplcontent=$('body').html(); + tplcontent=tplcontent.replace(/<%/g,'<%'); + tplcontent=tplcontent.replace(/%>/g,'%>'); + var html=_self.parseTpl(tplcontent,vars); + $('body').html(html); + if(!_self.op.single){ + + $.each(_self.op._ready,function(k,fun){ + fun($); + }); + } + } + if('string'==$.type(vars)){ + _self.sendAjax(vars,{},'get',function(response){ + render(response); + }); + }else{ + render(vars); + } + + + if(_self.op.single){ + //单一入口模式 + _self.initUI(document); + var api_url=''!=location.hash?location.hash.substr(1):_self.op.api_index; + _self.op._old_hash=location.hash; + _self.http(api_url); + //监听hash变化 + var listenHashChange=function(){ + if(location.hash!=_self.op._old_hash){ + var api_url=''!=location.hash?location.hash.substr(1):_self.op.api_index; + _self.http(api_url); + } + setTimeout(listenHashChange,50); + } + listenHashChange(); + } + }); + }, + //初始化界面 + initUI:function(_box){ + //调用自定义加载完成后的UI处理函数,自定义事件绑定先于系统绑定,可以控制系统绑定函数的触发。 + var selector=function(obj){ + var $obj=$(obj,_box) + return $obj.size()>0?$obj:$(obj); + }; + + $.each(this.op._before,function(k,fun){ + fun(selector); + }) + + var _self=this; + //A标签, 以斜杠开始的地址才会监听,不然会直接打开 + $('a[href^="/"],a[href^="./"]',_box).click(function(e){ + if(false===e.result) return ; //如果自定义事件return false了, 不再指向请求操作 + e.preventDefault(); + //如果有tpl属性,则光请求模板 + var url=$(this).attr('href'); + if(undefined!==$(this).attr('tpl')){ + url='.'+url+'.html'; + } + //绝对地址的链接不过滤 + _self.http(url,$(this).attr('rel')); + }); + //form标签的处理 + $('form[action^="/"],form[action^="./"]',_box).submit(function(e){ + if(false===e.result) return ; //如果自定义事件return false了, 不再指向请求操作 + e.preventDefault(); + var url=$(this).attr('action'); + if(undefined!==$(this).attr('tpl')){ + url='.'+url+'.html'; + } + _self.http(url,$(this).attr('rel'),$(this).serializeArray(),$(this).attr('method')); + }); + //锚点处理 + $('a[href^="#"]',_box).click(function(e){ + e.preventDefault(); + var anchor=$(this).attr('href').substr(1); + if($('#'+anchor).size()>0){ + _self.scrollTop($('#'+anchor),_self.op.anchor_move_speed); + }else if($('a[name="'+anchor+'"]').size()>0){ + _self.scrollTop($('a[name="'+anchor+'"]'),_self.op.anchor_move_speed); + }else{ + _self.scrollTop(0,_self.op.anchor_move_speed); + } + }); + + $.each(this.op._ready,function(k,fun){ + fun(selector); + }) + + }, + //请求接口, 支持情况:1, 请求接口同时渲染模板 2,只请求模板不请求接口 3,只请求接口不渲染模板, 如果有更复杂的逻辑可以自己封住函数,调TPM.sendAjax, TPM.render。 + http:function(url,rel,data,type){ + rel=rel||this.op.main; + type=type || 'get'; + //分析url,如果./开始直接请求模板 + if('./'==url.substr(0,2)){ + this.render(url,rel); + $('#'+rel).data('url',url); + + if(this.op.main==rel && 'get'==type.toLowerCase()) this.changeHash(url); + return ; + } + //分析模板地址 + var tpl_path=this.route(url); + //改变hash + if(tpl_path && this.op.main==rel && 'get'==type.toLowerCase()) this.changeHash(url); + //ajax请求 + var _self=this; + this.sendAjax(url,data,type,function(response){ + if(!tpl_path && _self.defined(response[_self.op.tpl_path_var])){ + tpl_path=response[_self.op.tpl_path_var]; //接口可以指定模板 + //改变hash + if(tpl_path && _self.op.main==rel && 'get'==type.toLowerCase()) _self.changeHash(url); + } + if(!tpl_path){ + //如果没有模板,默认只请求ajax,请求成后刷新rel + if('false'!=rel.toLowerCase()) _self.reload(rel); + }else{ + //模板渲染 + _self.render(tpl_path,rel,response); + $('#'+rel).data('url',url); + } + }); + }, + sendAjax:function(url,data,type,cb,async,options){ + var _self=this; + data=data||{}; + type=type||'get'; + options=options||{}; + + api_options=$.extend({},_self.op,options); + if(false!==async){ + async==true; + } + //请求接口之前hook(可以用做签名) + if($.isFunction(api_options.before_request_api)) + data=api_options.before_request_api(data,url); + //ajax请求 + //TODO ,以http开头的url,不加api_base + var api_url=api_options.api_base+url; + + $.ajax( + { + type: type, + url: api_url, + data: data, + dataType:api_options.ajax_data_type||'', + jsonp:api_options.ajax_jsonp_callback|| 'callback', + async:async, + success: function(d,s,x){ + if(redirect=x.getResponseHeader('redirect')){ + //跳转 + if(api_options.single) _self.http(redirect); + return ; + } + //接口数据分析 + try{ + var response='object'==$.type(d)?d:$.parseJSON(d); + }catch(e){ + _self.error('-2','接口返回数据格式错误'); + return ; + } + //接口请求后的hook + if($.isFunction(api_options.after_request_api)){ + var hook_result=api_options.after_request_api(response,url); + if(undefined!=hook_result){ + response=hook_result; + } + } + if(false!=response && $.isFunction(cb)) + cb(response); + } + } + ); + }, + changeHash:function(url){ + if(url!=this.op.api_index){ + this.op._old_hash='#'+url; + location.hash=url; + }else{ + if(''!=this.op._old_hash) this.op._old_hash=this.isIE()?'#':'';//IE如果描点为# 获得值不为空 + if(''!=location.hash) location.hash='';//赋值为空其实浏览器会赋值为 # + } + }, + //渲染模板 + render:function(tpl_path,rel,vars){ + vars=vars||{}; + var _self=this; + $.get(tpl_path,function(d,x,s){ + //模板解析 + var content=_self.parseTpl(d,vars); + //解析模板替换变量 + $.each(_self.op.tpl_parse_string,function(find,replace){ + var matcher=new RegExp(find.replace(/[-[\]{}()+?.,\\^$|#\s]/g,'\\$&'),'g'); + content=content.replace(matcher,replace); + }); + //分离js + var ret=_self.stripScripts(content); + var html=ret.text; + var js=ret.scripts; + $('#'+rel).empty().append(html); + _self.initUI($('#'+rel)); + //执行页面js + _self.execScript(js,$('#'+rel)); + + },'text'); + }, + //重新加载区域内容 + reload:function(rel){ + var url=$('#'+rel).data('url'); + if(url){ + this.http(url,rel); + } + }, + //路由解析 + route:function(url){ + var tpl_path=false; + var _self=this; + $.each(this.op.routes,function(route,path){ + if(_self._routeToRegExp(route).test(url)){ + tpl_path=path; + return false; + } + }); + return tpl_path; + }, + _routeToRegExp: function(route) { + var namedParam = /:\w+/g; + var splatParam = /\*\w+/g; + var escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g; + route = route.replace(escapeRegExp, '\\$&') + .replace(namedParam, '([^\/]+)') + .replace(splatParam, '(.*?)'); + return new RegExp('^' + route + '$'); + }, + //模板解析 + parseTpl:function(tplContent,vars){ + return this.op.tpl(tplContent,vars); + }, + ajaxError: function(xhr, ajaxOptions, thrownError) + { + window.TPMshowAjaxWait=true; + TPM.info('网络异常'); + }, + + + //------实用工具 + //判断是否为IE + isIE:function(){ + return /msie [\w.]+/.exec(navigator.userAgent.toLowerCase()); + }, + //判断是否为IE7以下浏览器 + isOldIE:function(){ + return this.isIE() && (!docMode || docMode <= 7); + }, + //移动滚动条,n可以是数字也可以是对象 + scrollTop:function(n,t,obj){ + t=t||0; + obj=obj ||'html,body' + num=$.type(n)!="number"?n.offset().top:n; + $(obj).animate( { + scrollTop: num + }, t ); + }, + //分离js代码 + stripScripts:function(codes){ + var scripts = ''; + //将字符串去除script标签, 并获得script标签中的内容。 + var text = codes.replace(/]*>([\s\S]*?)<\/script>/gi, function(all, code){ + scripts += code + '\n'; + return ''; + }); + return {text:text,scripts:scripts} + }, + //执行js代码 + execScript:function(scripts,_box){ + if(scripts!=''){ + //执行js代码, 在闭包中执行。改变$选择符。 + var e=new Function('$',scripts); + var selector=function(obj){ + var $obj=$(obj,_box) + return $obj.size()>0?$obj:$(obj); + }; + e(selector); + + } + }, + //判断变量是否定义 + defined:function(variable){ + return $.type(variable) == "undefined" ? false : true; + }, + //获得get参数 + get:function(name){ + if('undefined'==$.type(this._gets)){ + var querystring=window.location.search.substring(1); + var gets={}; + var vars=querystring.split('&') + var param; + for(var i=0;i +;(function($){ +$.fn.extend({ + 'TPMlist':function(options){ + var defaults={ + "param_pagesize":"pagesize", + "param_page":"page", + "tabletpagesize":40, + "phonepagesize":20 + }; + options=$.extend(defaults,options); + $(this).each(function(){ + //获得api + var api=$(this).data('api'); + //获得请求参数 + var datas=$(this).data('datas'); + //获得模板 + var tpl=$(this).data('tpl'); + //获得数据集合名称 + //获得pagesize + var type=$(window).height()>767?'tablet':'phone'; + var defaultpagesize='tablet'==type?options.tabletpagesize:options.phonepagesize;//默认每页显示条数 + var pagesize=$(this).data(type+'pagesize') || defaultpagesize; + $children=$('
    加载中..
    ').appendTo(this).find('.list_content'); + //下拉刷新 + var sc=$(this).TPMpulltorefresh(function(){ + $children.TPMgetListData(api,datas,tpl,pagesize,1,this,options); + }); + $children.TPMgetListData(api,datas,tpl,pagesize,1,sc,options); + + }); + }, + 'TPMgetListData':function(api,datas,tpl,pagesize,page,sc,options){ + var params=datas?datas.split('&'):{}; + var datas_obj={}; + for(var i=0;i加载更多'); + $more.appendTo($this); + $more.click(function(){ + $(this).html('加载中...');//TODO 加载中样式 + $this.TPMgetListData(api,datas,tpl,pagesize,parseInt($this.data('currentpage'))+1,sc,options); + }); + } + sc.refresh();//iscroll refresh; + //记录当前页面 + $this.data('currentpage',response.currentpage); + },'text') + }); + }, + //下拉刷新 + 'TPMpulltorefresh':function(cb){ + //增加下拉刷新提示层 + var $pulldown=$('
    下拉可以刷新
    ') + $pulldown.prependTo($(this).children()); + var offset=$pulldown.outerHeight(true); + var myScroll=new iScroll($(this)[0],{ + useTransition: true, + topOffset:offset, + hideScrollbar:true, + onRefresh: function () { + $pulldown.removeClass('loading'); + $pulldown.find('.pullDownLabel').html('下拉可以刷新'); + }, + onScrollMove: function () { + if (this.y > 5 && !$pulldown.is('.flip')) { + $pulldown.addClass('flip'); + $pulldown.find('.pullDownLabel').html('松开可以刷新'); + this.minScrollY = 0; + } else if (this.y < 5 && $pulldown.is('.flip')) { + $pulldown.removeClass('flip'); + $pulldown.find('.pullDownLabel').html('下拉可以刷新'); + this.minScrollY = -offset; + } + }, + onScrollEnd: function () { + if($pulldown.is('.flip')){ + $pulldown.removeClass('flip'); + $pulldown.addClass('loading'); + $pulldown.find('.pullDownLabel').html('加载中...'); + cb.call(this);//触发回调函数 + } + } + }); + return myScroll; + } + +}); +})(jQuery); + diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPMmodal.js b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPMmodal.js new file mode 100644 index 0000000..d374356 --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPMmodal.js @@ -0,0 +1,145 @@ +function tpm_alert(msg,callback,title){ + title=title||'系统信息'; + var $modal=$('

    '+title+'

    '+msg+'
    '); + $modal.find('.tpm_modal_foot>button').on('click',function(){ + tpm_close_float_box(); + }); + var id=Modernizr.mq("(max-width:767px)")?'tpm_modal_phone':'tpm_modal'; + tpm_show_float_box($modal,id); + if($.isFunction(callback)){ + $('#'+id).on('end',function(){ + callback(); + $('#'+id).off('end'); + }); + } +} + +function tpm_info(msg,callback){ + var id=Modernizr.mq("(max-width:767px)")?'tpm_info_phone':'tpm_info'; + if(0==$('#'+id).size()){ + $('
    ').appendTo('body').on('webkitTransitionEnd oTransitionEnd otransitionend transitionend',function(){ + if(!$(this).is('.in')){ + $(this).hide(); + if($.isFunction(callback)) callback(); + } + }); + } + //显示 + $('#'+id).show(); + $('#'+id).html(msg); + $('#'+id).offset();//强制回流 + $('#'+id).addClass('in'); + //3秒后隐藏 + setTimeout(function(){ + $('#'+id).removeClass('in'); + if(!Modernizr.csstransitions){ + $('#'+id).hide(); + if($.isFunction(callback)) callback(); + } + },1000) +} + +function tpm_confirm(msg,callback,title){ + title=title||'请确认'; + var $modal=$('

    '+title+'

    '+msg+'
    '); + var id=Modernizr.mq("(max-width:767px)")?'tpm_modal_phone':'tpm_modal'; + $modal.find('.tpm_modal_foot>button').on('click',function(){ + if($(this).is('.tpm_modal_ok')){ + $('#'+id).on('end',function(){ + if($.isFunction(callback)) callback(); + $('#'+id).off('end'); + }) + } + tpm_close_float_box(); + }); + tpm_show_float_box($modal,id); +} + +function tpm_popurl(url,callback,title){ + var text='

    '+title+'

    ×
    loading
    '; + tpm_show_float_box(text,'tpm_modal'); + if($.isFunction(callback)){ + $('#tpm_modal').on('end',function(){ + callback(); + $('#tpm_modal').off('end'); + }); + } + //增加随机数,防止缓存 + url+=-1==url.indexOf('?')?'?tpm_r='+Math.random():'&tpm_r='+Math.random(); + //判断是否为http开头。 + if('http'==url.substr(0,4).toLowerCase()){ + $(window).off('message.tpm'); + //以http开头用iframe显示。 + $(window).on('message.tpm',function(e){ + if('tpm_close_float_box'==e.originalEvent.data){ + tpm_close_float_box(); + } + }); + $('#tpm_modal_body').html(''); + }else{ + //判断是否加载tpm类库。 + if(!window.TPM){ + $('#tpm_modal_body').load(url); + }else{ + window.TPMshowAjaxWait=false; + TPM.http(url,'tpm_modal_body'); + } + } +} + +function tpm_show_float_box(text,id){ + tpm_show_backdrop(); + //创建modal层 + if(0==$('#'+id).size()){ + $('
    ').appendTo('body').on('webkitTransitionEnd oTransitionEnd otransitionend transitionend',function(){ + if(!$(this).is('.in')){ + $(this).trigger('end'); + $(this).hide(); + } + }); + } + $('#'+id).empty(); + //加入弹出框内容 + $(text).appendTo('#'+id); + //显示modal层 + $('#'+id).show() + $('#'+id).offset(); + //添加modal层in样式 + $('#'+id).addClass('in'); +} + + +function tpm_close_float_box(){ + //如果iframe中发送postMessage给父窗口 + if(parent!=window){ + parent.postMessage('tpm_close_float_box','*'); + return ; + } + tpm_hide_backdrop(); + //删除modal层in样式 + $('#tpm_modal,#tpm_modal_phone').removeClass('in'); + if(!Modernizr.csstransitions){ + $('#tpm_modal,#tpm_modal_phone').hide(); + $('#tpm_modal,#tpm_modal_phone').trigger('end'); + } +} + + + +//显示笼罩层 +function tpm_show_backdrop(){ + if(0==$('#tpm_backdrop').size()){ + $('
    ').appendTo('body').on('webkitTransitionEnd oTransitionEnd otransitionend transitionend',function(){ + if(!$(this).is('.in')) $(this).hide(); + }); + } + $('#tpm_backdrop').show(); + $('#tpm_backdrop').offset();//强制回流 + $('#tpm_backdrop').addClass('in'); +} + +//隐藏笼罩层 +function tpm_hide_backdrop(){ + $('#tpm_backdrop').removeClass('in'); + if(!Modernizr.csstransitions) $('#tpm_backdrop').hide(); +} diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPMupload.js b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPMupload.js new file mode 100644 index 0000000..b4ef615 --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/TPMupload.js @@ -0,0 +1,212 @@ +//兼容phonegap,电脑,手机的上传插件 +//autor luofei614(http://weibo.com/luofei614) +;(function($){ + $.fn.extend({ + TPMupload:function(options){ + //配置项处理 + var defaults={ + "url":"", + "name":"file", + "sourceType":"Image", //针对手机有效, 上传类型,Image,Video,Audio,Libray 注意首字母大写。 Libray 表示上传手机相册中的图片。 + "dataUrl":true, + "quality":20,//图片质量 + "imgWidth":300, + "imgHeight":300 + }; + if('string'==$.type(options)) + options={"url":options}; + var op=$.extend(defaults,options); + //电脑上传 + var desktop_upload=function(index){ + op.name=$(this).attr('name') || op.name + //增加上传按钮 + var $uploadBtn=$('').insertBefore(this); + //添加状态层 + var $status=$('').insertBefore(this); + //增加隐藏域 + var $hiddenInput=$('').insertBefore(this);; + //增加结果显示层 + var $show=$('
    ').insertBefore(this); + //增加提交表单 + var $form=$('
    ').css({"position":"absolute","opacity":"0"}).insertBefore(this); + //定位提交表单 + $uploadBtn.hover(function(e){ + $form.offset({top:e.pageY-20,left:e.pageX-50}); + }); + var $uploadInput=$form.find('input:file'); + $uploadInput.change(function(){ + $status.html('正在上传...'); + $form.submit(); + }); + $(this).remove(); + //增加iframe + var $iframe=$('').appendTo('body'); + //获得iframe返回结果 + var iframe=$iframe[0]; + $iframe.bind("load", function(){ + if (iframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" || // For Safari + iframe.src == "javascript:'';") { // For FF, IE + return; + } + + var doc = iframe.contentDocument ? iframe.contentDocument : window.frames[iframe.id].document; + + // fixing Opera 9.26,10.00 + if (doc.readyState && doc.readyState != 'complete') return; + // fixing Opera 9.64 + if (doc.body && doc.body.innerHTML == "false") return; + + var response; + + if (doc.XMLDocument) { + // response is a xml document Internet Explorer property + response = doc.XMLDocument; + } else if (doc.body){ + try{ + response = $iframe.contents().find("body").html(); + } catch (e){ // response is html document or plain text + response = doc.body.innerHTML; + } + } else { + // response is a xml document + response = doc; + } + if(''!=response){ + $status.html(''); + if(-1!=response.indexOf('
    ')){
    +               //iframe中的json格式,浏览器会自动渲染,加上pre标签,转义html标签,所以这里去掉pre标签,还原html标签。
    +                   var htmldecode=function(str)   
    +                   {   
    +                         var    s    =    "";   
    +                         if    (str.length    ==    0)    return    "";   
    +                         s    =    str.replace(/&/g,    "&");   
    +                         s    =    s.replace(/</g,"<");   
    +                         s    =    s.replace(/>/g,">");   
    +                         s    =    s.replace(/ /g,"    ");   
    +                         s    =    s.replace(/'/g,"\'");   
    +                         s    =    s.replace(/"/g, "\"");   
    +                         s    =    s.replace(/
    /g,"\n"); + return s; + } + response=htmldecode($(response).html()); + console.log(response); + } + try{ + var ret=$.parseJSON(response); + //显示图片 + if(ret.path) $hiddenInput.val(ret.path); + if(ret.show) $show.html(ret.show); + if(ret.error) $show.html(ret.error); + }catch(e){ + console.log(response); + alert('服务器返回格式错误'); + } + } + }); + + }; + //客户端上传 + var client_upload=function(index){ + op.name=$(this).attr('name') || op.name + //增加上传按钮 + var $uploadBtn=$('').insertBefore(this); + //添加状态层 + var $status=$('').insertBefore(this); + //增加隐藏域 + var $hiddenInput=$('').insertBefore(this);; + //增加结果显示层 + var $show=$('
    ').insertBefore(this); + $(this).remove(); + var upload=function(file,isbase64){ + isbase64=isbase64 || false; + if('http'!=op.url.substr(0,4).toLowerCase()){ + //如果上传地址不是绝对地址, 加上TPM的基路径。 + op.url=TPM.op.api_base+op.url; + } + if(isbase64){ + //如果是base64的图片数据 + var $imgshow=$('

    点击图片可调整图片角度
    ').appendTo($show); + var $img=$imgshow.find('img'); + $imgshow.click(function(){ + var c=document.createElement('canvas'); + var ctx=c.getContext("2d"); + var img=new Image(); + img.onload = function(){ + c.width=this.height; + c.height=this.width; + ctx.rotate(90 * Math.PI / 180); + ctx.drawImage(img, 0,-this.height); + var dataURL = c.toDataURL("image/png"); + $img.attr('src',dataURL); + $hiddenInput.val(dataURL); + }; + img.src=$img.attr('src'); + }); + $hiddenInput.val('data:image/png;base64,'+file); + }else{ + $status.html('正在上传...'); + //视频,语音等文件上传 + resolveLocalFileSystemURI(file,function(fileEntry){ + fileEntry.file(function(info){ + var options = new FileUploadOptions(); + options.fileKey=op.name; + options.chunkedMode=false; + var ft = new FileTransfer(); + + ft.upload(info.fullPath,op.url,function(r){ + $status.html(''); + try{ + var ret=$.parseJSON(r.response); + //显示图片 + if(ret.path) $hiddenInput.val(ret.path); + if(ret.show) $show.html(ret.show); + if(ret.error) $show.html(ret.error); + }catch(e){ + console.log(r.response); + alert('服务器返回格式错误'); + } + },function(error){ + $status.html(''); + alert("文件上传失败,错误码: " + error.code); + },options); + }); + }); + } + + }; + //扑捉对象 + $uploadBtn.click(function(){ + + if('Libray'==op.sourceType || 'Image'==op.sourceType){ + var sourceType='Image'==op.sourceType?navigator.camera.PictureSourceType.CAMERA:navigator.camera.PictureSourceType.PHOTOLIBRARY; + var destinationType=op.dataUrl?navigator.camera.DestinationType.DATA_URL:navigator.camera.DestinationType.FILE_URI; + navigator.camera.getPicture(function(imageURI){ + upload(imageURI,op.dataUrl); + }, function(){ + }, {quality:op.quality,destinationType: destinationType,sourceType:sourceType,targetWidth:op.imgWidth,targetHeight:op.imgHeight}); + }else{ + var action='capture'+op.sourceType; + navigator.device.capture[action](function(mediaFiles){ + upload(mediaFiles[0].fullPath); + },function(){ + }); + } + }); + + }; + + $(this).each(function(index){ + //在SAE云窗调试器下可能有延迟问题,第一次加载会判断window.cordova未定义,这时候需要点击一下页面其他链接,再点击回来就可以了 + if('cordova' in window){ + //手机上的处理方法 + client_upload.call(this,index); + }else{ + //电脑上的处理方法 + desktop_upload.call(this,index); + } + }); + + + } + }); +})(jQuery); diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/app.js b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/app.js new file mode 100644 index 0000000..41206ab --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/app.js @@ -0,0 +1,78 @@ +function app_ready($){ + $("#login").height($(window).height()); + if(Modernizr.mq("(max-width:767px)")){ + if($('#right').size()>0){ + $('#right_box').empty(); + $('#right').appendTo('#right_box'); + // 防止多次监听 + $('#main').off('swipeLeft.once'); + $('#main').on('swipeLeft.once',function(){ + $('#main').addClass('show_right_nav'); + }); + $('#main').off('swipeRight.once'); + $('#main').on('swipeRight.once',function(){ + $('#main').removeClass('show_right_nav'); + }); + } + } + $('input:file').TPMupload('/Index/upload'); +} + +function show_right_nav(){ + if($('#main').is('.show_right_nav')){ + $('#main').removeClass('show_right_nav'); + }else{ + $('#main').addClass('show_right_nav'); + } +} +//扫描二维码 +function qrcode(){ + sina.barcodeScanner.scan(function(result) { + TPM.http(result.text); + }); +} +//语言识别 +function voice(){ + if(!isclient){ + alert('请在手机客户端中使用'); + return ; + } + + var appId = '4fa77fe4'; + sina.voice.recognizer.init(appId); + + sina.voice.recognizer.setOption({ + engine: 'sms', + sampleRate: 'rate16k', + }); + + sina.voice.recognizer.setListener("onResults"); + + sina.voice.recognizer.start(function(response) { + console.log("response: " + response.errorCode + ", msg: " + response.message); + }); +} + +function onResults(response) +{ + response.results.forEach(function(recognizerResult) { + $("#content").val( $("#content").val() + recognizerResult.text ); + }); +} + +//绑定账户 +function bind(type){ + var url="/Index/bind/type/"+type; + if(isclient){ + tpm_popurl(TPM.op.api_base+url,function(){ + TPM.reload(TPM.op.main); + },'绑定账号') + }else{ + url=$('')[0].href; + tpm_popurl(url,function(){ + location.reload(); + },'绑定账号'); + } +} + + diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/bootstrap.min.js b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/bootstrap.min.js new file mode 100644 index 0000000..95c5ac5 --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/bootstrap.min.js @@ -0,0 +1,6 @@ +/*! +* Bootstrap.js by @fat & @mdo +* Copyright 2012 Twitter, Inc. +* http://www.apache.org/licenses/LICENSE-2.0.txt +*/ +!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||s.toggleClass("open"),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'
    ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'

    '}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery); \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/desktopBrowsers.js b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/desktopBrowsers.js new file mode 100644 index 0000000..27c4f0e --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/desktopBrowsers.js @@ -0,0 +1,149 @@ +//desktopBrowsers contributed by Carlos Ouro @ Badoo +//translates desktop browsers events to touch events and prevents defaults +//It can be used independently in other apps but it is required for using the touchLayer in the desktop + + +;(function ($) { + + var cancelClickMove=false; + var preventAll = function(e) + { + e.preventDefault(); + e.stopPropagation(); + } + + var redirectMouseToTouch = function(type, originalEvent, newTarget) + { + + var theTarget = newTarget ? newTarget : originalEvent.target; + + //stop propagation, and remove default behavior for everything but INPUT, TEXTAREA & SELECT fields + if (theTarget.tagName.toUpperCase().indexOf("SELECT") == -1 && + theTarget.tagName.toUpperCase().indexOf("TEXTAREA") == -1 && + theTarget.tagName.toUpperCase().indexOf("INPUT") == -1) //SELECT, TEXTAREA & INPUT + { + // by luofei , 为了兼容iscroll 去掉原生事件的取消监听 + // preventAll(originalEvent); + } + + var touchevt = document.createEvent("Event"); + touchevt.initEvent(type, true, true); + if(type!='touchend'){ + touchevt.touches = new Array(); + touchevt.touches[0] = new Object(); + touchevt.touches[0].pageX = originalEvent.pageX; + touchevt.touches[0].pageY = originalEvent.pageY; + //target + touchevt.touches[0].target = theTarget; + touchevt.changedTouches = touchevt.touches; //for jqtouch + touchevt.targetTouches = touchevt.touches; //for jqtouch + } + //target + touchevt.target = theTarget; + + touchevt.mouseToTouch = true; + theTarget.dispatchEvent(touchevt); + } + + var mouseDown = false, + lastTarget = null,firstMove=false; + + + if(!window.navigator.msPointerEnabled){ + + document.addEventListener("mousedown", function(e) + { + mouseDown = true; + lastTarget = e.target; + if(e.target.nodeName.toLowerCase()=="a"&&e.target.href.toLowerCase()=="javascript:;") + e.target.href="#"; + redirectMouseToTouch("touchstart", e); + firstMove = true; + cancelClickMove=false; + }, true); + + document.addEventListener("mouseup", function(e) + { + if(!mouseDown) return; + redirectMouseToTouch("touchend", e, lastTarget); //bind it to initial mousedown target + lastTarget = null; + mouseDown = false; + }, true); + + document.addEventListener("mousemove", function(e) + { + if (!mouseDown) return; + if(firstMove) return firstMove=false + redirectMouseToTouch("touchmove", e); + e.preventDefault(); + + cancelClickMove=true; + }, true); + } + else { //Win8 + document.addEventListener("MSPointerDown", function(e) + { + + mouseDown = true; + lastTarget = e.target; + if(e.target.nodeName.toLowerCase()=="a"&&e.target.href.toLowerCase()=="javascript:;") + e.target.href="#"; + redirectMouseToTouch("touchstart", e); + firstMove = true; + cancelClickMove=false; + // e.preventDefault();e.stopPropagation(); + }, true); + + document.addEventListener("MSPointerUp", function(e) + { + if(!mouseDown) return; + redirectMouseToTouch("touchend", e, lastTarget); //bind it to initial mousedown target + lastTarget = null; + mouseDown = false; + // e.preventDefault();e.stopPropagation(); + }, true); + + document.addEventListener("MSPointerMove", function(e) + { + + if (!mouseDown) return; + if(firstMove) return firstMove=false + redirectMouseToTouch("touchmove", e); + e.preventDefault(); + //e.stopPropagation(); + + cancelClickMove=true; + + }, true); + } + + + //prevent all mouse events which dont exist on touch devices + document.addEventListener("drag", preventAll, true); + document.addEventListener("dragstart", preventAll, true); + document.addEventListener("dragenter", preventAll, true); + document.addEventListener("dragover", preventAll, true); + document.addEventListener("dragleave", preventAll, true); + document.addEventListener("dragend", preventAll, true); + document.addEventListener("drop", preventAll, true); + document.addEventListener("selectstart", preventAll, true); + document.addEventListener("click", function(e) + { + if(!e.mouseToTouch&&e.target==lastTarget){ + preventAll(e); + } + if(cancelClickMove) + { + preventAll(e); + cancelClickMove=false; + } + }, true); + + + window.addEventListener("resize",function(){ + var touchevt = document.createEvent("Event"); + touchevt.initEvent("orientationchange", true, true); + document.dispatchEvent(touchevt); + },false); + +})(jQuery); diff --git a/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/jquery-1.9.1.min.js b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/jquery-1.9.1.min.js new file mode 100644 index 0000000..006e953 --- /dev/null +++ b/ThinkPHP/Extend/Tool/TPM/Tpl/Public/js/jquery-1.9.1.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery.min.map +*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
    a",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="
    t
    ",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
    ",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; +return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="
    ",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:b.support.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) +}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("'); + + opt.noRights = opt.noRights || ""; + var noRights = opt.noRights.split(","); + //调整结构 + $main.insertBefore($area) + .append($area); + //加入frame + $frame.appendTo($main); + //加入bottom + if (opt.resizeType != 0) { + //拖动改变编辑器高度 + $("
    ").addClass(opt.cssname.resizeCenter).mousedown(function (e) { + var y = e.pageY, + x = e.pageX, + height = _self.$main.height(), + width = _self.$main.width(); + $(document).add(_self.doc).mousemove(function (e) { + var mh = e.pageY - y; + _self.resize(width, height + mh); + }); + $(document).add(_self.doc).mouseup(function (e) { + $(document).add(_self.doc).unbind("mousemove"); + $(document).add(_self.doc).unbind("mousemup"); + }); + }).appendTo($bottom); + } + if (opt.resizeType == 2) { + //拖动改变编辑器高度和宽度 + $("
    ").addClass(opt.cssname.resizeLeft).mousedown(function (e) { + var y = e.pageY, + x = e.pageX, + height = _self.$main.height(), + width = _self.$main.width(); + $(document).add(_self.doc).mousemove(function (e) { + var mh = e.pageY - y, + mw = e.pageX - x; + _self.resize(width + mw, height + mh); + }); + $(document).add(_self.doc).mouseup(function (e) { + $(document).add(_self.doc).unbind("mousemove"); + $(document).add(_self.doc).unbind("mousemup"); + }); + }).appendTo($bottom); + } + $bottom.appendTo($main); + $dialog.appendTo($main); + //循环按钮处理。 + //TODO 默认参数处理 + $.each(opt.controls.split(","), function (idx, bname) { + var _fn = arguments.callee; + if (_fn.count == undefined) { + _fn.count = 0; + } + + //处理分组 + if (bname == "|") { + //设定分组宽 + if (_fn.count) { + $toolbar.find('.' + opt.cssname.group + ':last').css('width', (opt.cssname.btnWidth * _fn.count + opt.cssname.lineWidth) + 'px'); + _fn.count = 0; + } + //分组宽结束 + $group = $("
    ").addClass(opt.cssname.group).appendTo($toolbar); + $("
     
    ").addClass(opt.cssname.line).appendTo($group); + + } else { + //更新统计数 + _fn.count += 1; + //获取按钮属性 + var btn = $.extend({}, $.TE.defaultEvent, $.TE.buttons[bname]); + //标记无权限 + var noRightCss = "", noRightTitle = ""; + if ($.inArray(bname, noRights) != -1) { + noRightCss = " " + opt.cssname.noRight; + noRightTitle = "(无权限)"; + } + $btn = $("
    ").addClass(opt.cssname.btn + " " + opt.cssname.btnpre + bname + noRightCss) + .data("bname", bname) + .attr("title", btn.title + noRightTitle) + .appendTo($group) + .bind(btn.event, function (e) { + //不可用触发 + if ($(this).is("." + opt.cssname.disable)) { + if ($.isFunction(btn.disable)) btn.disable.call(btn, e); + return false; + } + //判断权限和是否可用 + if ($(this).is("." + opt.cssname.noRight)) { + //点击时触发无权限说明 + btn['noRight'].call(btn, e); + return false; + } + if ($.isFunction(btn[e.type])) { + //触发事件 + btn[e.type].call(btn, e); + //TODO 刷新按钮 + } + }); + if ($.isFunction(btn.init)) btn.init.call(btn); //初始化 + if (ie) $btn.attr("unselectable", "on"); + btn.editor = _self; + btn.$btn = $btn; + } + }); + //调用核心 + this.core = new editorCore($frame, $area); + this.doc = this.core.doc; + this.$frame = this.core.$frame; + this.$area = this.core.$area; + this.restoreRange = this.core.restoreRange; + this.selectedHTML = function () { return this.core.selectedHTML(); } + this.selectedText = function () { return this.core.selectedText(); } + this.pasteHTML = function (v) { this.core.pasteHTML(v); } + this.sourceMode = this.core.sourceMode; + this.focus = this.core.focus; + //监控变化 + $(this.core.doc).click(function () { + //隐藏对话框 + _self.hideDialog(); + }).bind("keyup mouseup", function () { + _self.refreshBtn(); + }) + this.refreshBtn(); + //调整大小 + this.resize(opt.width, opt.height); + + //获取DOM层级 + this.core.focus(); + } + //end ThinkEditor + ThinkEditor.prototype.resize = function (w, h) { + //最小高度和宽度 + var opt = this.opt, + h = h < opt.minHeight ? opt.minHeight : h, + w = w < opt.minWidth ? opt.minWidth : w; + this.$main.width(w).height(h); + var height = h - (this.$toolbar.parent().outerHeight() + this.$bottom.height()); + this.$frame.height(height).width("100%"); + this.$area.height(height).width("100%"); + }; + //隐藏对话框 + ThinkEditor.prototype.hideDialog = function () { + var opt = this.opt; + $("." + opt.cssname.dialog).hide(); + }; + //刷新按钮 + ThinkEditor.prototype.refreshBtn = function () { + var sourceMode = this.sourceMode(); // 标记状态。 + var opt = this.opt; + if (!iOS && $.browser.webkit && !this.focused) { + this.$frame[0].contentWindow.focus(); + window.focus(); + this.focused = true; + } + var queryObj = this.doc; + if (ie) queryObj = this.core.getRange(); + //循环按钮 + //TODO undo,redo等判断 + this.$toolbar.find("." + opt.cssname.btn + ":not(." + opt.cssname.noRight + ")").each(function () { + var enabled = true, + btnName = $(this).data("bname"), + btn = $.extend({}, $.TE.defaultEvent, $.TE.buttons[btnName]), + command = btn.cmd; + if (sourceMode && btnName != "source") { + enabled = false; + } else if ($.isFunction(btn.getEnable)) { + enabled = btn.getEnable.call(btn); + } else if ($.isFunction(btn[command])) { + enabled = true; //如果命令为自定义命令,默认为可用 + } else { + if (!ie || btn.cmd != "inserthtml") { + try { + enabled = queryObj.queryCommandEnabled(command); + $.debug(enabled.toString(), "命令:" + command); + } + catch (err) { + enabled = false; + } + } + + //判断该功能是否有实现 @TODO 代码胶着 + if ($.TE.buttons[btnName]) enabled = true; + } + if (enabled) { + $(this).removeClass(opt.cssname.disable); + } else { + $(this).addClass(opt.cssname.disable); + } + }); + }; + //core code start + function editorCore($frame, $area, v) { + //TODO 参数改为全局的。 + var defaults = { + docType: '', + docCss: "", + bodyStyle: "margin:4px; font:10pt Arial,Verdana; cursor:text", + focusExt: function (editor) { + //触发编辑器获得焦点时执行,比如刷新按钮 + }, + //textarea内容更新到iframe的处理函数 + updateFrame: function (code) { + //翻转flash为占位符 + code = code.replace(/(]*?type="application\/x-shockwave-flash" [^>]*?>)/ig, function ($1) { + var ret = ']*?class=(?:"|)_flash_position(?:"|)[^>]*?>)/ig, function ($1) { + var ret = '', + data = $1.match(/_data="([^"]*)"/); + + if (data && data[1]) { + data = eval('(' + data + ')'); + } + + ret += '' + + ((options.docCss === '') ? '' : '') + + '' + ); + doc.close(); + //设置frame编辑模式 + try { + if (ie) { + doc.body.contentEditable = true; + } + else { + doc.designMode = "on"; + } + } catch (err) { + $.debug(err, "创建编辑模式错误"); + } + + //统一 IE FF 等的 execCommand 行为 + try { + this.e.execCommand("styleWithCSS", 0, 0) + } + catch (e) { + try { + this.e.execCommand("useCSS", 0, 1); + } catch (e) { } + } + + //监听 + if (ie) + $doc.click(function () { + _self.focus(); + }); + this.updateFrame(); //更新内容 + + if (ie) { + $doc.bind("beforedeactivate beforeactivate selectionchange keypress", function (e) { + if (e.type == "beforedeactivate") + _self.inactive = true; + + else if (e.type == "beforeactivate") { + if (!_self.inactive && _self.range && _self.range.length > 1) + _self.range.shift(); + delete _self.inactive; + } + + else if (!_self.inactive) { + if (!_self.range) + _self.range = []; + _self.range.unshift(_self.getRange()); + + while (_self.range.length > 2) + _self.range.pop(); + } + + }); + + // Restore the text range when the iframe gains focus + $frame.focus(function () { + _self.restoreRange(); + }); + } + + ($.browser.mozilla ? $doc : $(contentWindow)).blur(function () { + _self.updateTextArea(true); + }); + this.$area.blur(function () { + // Update the iframe when the textarea loses focus + _self.updateFrame(true); + }); + + /* + * //自动添加p标签 + * $doc.keydown(function(e){ + * if(e.keyCode == 13){ + * //_self.pasteHTML('

     

    '); + * //this.execCommand( 'formatblock', false, '

    ' ); + * } + * }); + */ + + } + //是否为源码模式 + editorCore.prototype.sourceMode = function () { + return this.$area.is(":visible"); + }; + //编辑器获得焦点 + editorCore.prototype.focus = function () { + var opt = this.opt; + if (this.sourceMode()) { + this.$area.focus(); + } + else { + this.$frame[0].contentWindow.focus(); + } + if ($.isFunction(opt.focusExt)) opt.focusExt(this); + }; + //textarea内容更新到iframe + editorCore.prototype.updateFrame = function (checkForChange) { + var code = this.$area.val(), + options = this.opt, + updateFrameCallback = options.updateFrame, + $body = $(this.doc.body); + //判断是否已经修改 + if (updateFrameCallback) { + var sum = checksum(code); + if (checkForChange && this.areaChecksum == sum) + return; + this.areaChecksum = sum; + } + + //回调函数处理 + var html = updateFrameCallback ? updateFrameCallback(code) : code; + + // 禁止script标签 + + html = html.replace(/<(?=\/?script)/ig, "<"); + + // TODO,判断是否有作用 + if (options.updateTextArea) + this.frameChecksum = checksum(html); + + if (html != $body.html()) { + $body.html(html); + } + }; + editorCore.prototype.getRange = function () { + if (ie) return this.getSelection().createRange(); + return this.getSelection().getRangeAt(0); + }; + + editorCore.prototype.getSelection = function () { + if (ie) return this.doc.selection; + return this.$frame[0].contentWindow.getSelection(); + }; + editorCore.prototype.restoreRange = function () { + if (ie && this.range) + this.range[0].select(); + }; + + editorCore.prototype.selectedHTML = function () { + this.restoreRange(); + var range = this.getRange(); + if (ie) + return range.htmlText; + var layer = $("")[0]; + layer.appendChild(range.cloneContents()); + var html = layer.innerHTML; + layer = null; + return html; + }; + + + editorCore.prototype.selectedText = function () { + this.restoreRange(); + if (ie) return this.getRange().text; + return this.getSelection().toString(); + }; + + editorCore.prototype.pasteHTML = function (value) { + this.restoreRange(); + if (ie) { + this.getRange().pasteHTML(value); + } else { + this.doc.execCommand("inserthtml", 0, value || null); + } + //获得焦点 + this.$frame[0].contentWindow.focus(); + } + + editorCore.prototype.updateTextArea = function (checkForChange) { + var html = $(this.doc.body).html(), + options = this.opt, + updateTextAreaCallback = options.updateTextArea, + $area = this.$area; + + + if (updateTextAreaCallback) { + var sum = checksum(html); + if (checkForChange && this.frameChecksum == sum) + return; + this.frameChecksum = sum; + } + + + var code = updateTextAreaCallback ? updateTextAreaCallback(html) : html; + // TODO 判断是否有必要 + if (options.updateFrame) + this.areaChecksum = checksum(code); + if (code != $area.val()) { + $area.val(code); + } + + }; + function checksum(text) { + var a = 1, b = 0; + for (var index = 0; index < text.length; ++index) { + a = (a + text.charCodeAt(index)) % 65521; + b = (b + a) % 65521; + } + return (b << 16) | a; + } + $.extend({ + teExt: { + //扩展配置 + }, + debug: function (msg, group) { + //判断是否有console对象 + if ($.TE.debug && window.console !== undefined) { + //分组开始 + if (group) console.group(group); + if ($.type(msg) == "string") { + //是否为执行特殊函数,用双冒号隔开 + if (msg.indexOf("::") != -1) { + var arr = msg.split("::"); + eval("console." + arr[0] + "('" + arr[1] + "')"); + } else { + console.debug(msg); + } + } else { + if ($(msg).html() == null) { + console.dir(msg); //输出对象或数组 + } else { + console.dirxml($(msg)[0]); //输出dom对象 + } + + } + //记录trace信息 + if ($.TE.debug == 2) { + console.group("trace 信息:"); + console.trace(); + console.groupEnd(); + } + //分组结束 + if (group) console.groupEnd(); + } + }, + //end debug + defined: function (variable) { + return $.type(variable) == "undefined" ? false : true; + }, + isTag: function (tn) { + if (!tn) return false; + return $(this)[0].tagName.toLowerCase() == tn ? true : false; + }, + //end istag + include: function (file) { + if (!$.defined($.TE.loadUrl)) $.TE.loadUrl = {}; + //定义皮肤路径和插件路径。 + var basePath = $.TE.basePath(), + skinsDir = basePath + "skins/", + pluginDir = basePath + "plugins/"; + var files = $.type(file) == "string" ? [file] : file; + for (var i = 0; i < files.length; i++) { + var loadurl = name = $.trim(files[i]); + //判断是否已经加载过 + if ($.TE.loadUrl[loadurl]) { + continue; + } + //判断是否有@ + var at = false; + if (name.indexOf("@") != -1) { + at = true; + name = name.substr(1); + } + var att = name.split('.'); + var ext = att[att.length - 1].toLowerCase(); + if (ext == "css") { + //加载css + var filepath = at ? name : skinsDir + name; + var newNode = document.createElement("link"); + newNode.setAttribute('type', 'text/css'); + newNode.setAttribute('rel', 'stylesheet'); + newNode.setAttribute('href', filepath); + $.TE.loadUrl[loadurl] = 1; + } else { + var filepath = at ? name : pluginDir + name; + //$(""+"").attr({src:filepath,type:'text/javascript'}).appendTo('head'); + var newNode = document.createElement("script"); + newNode.type = "text/javascript"; + newNode.src = filepath; + newNode.id = loadurl; //实现批量加载 + newNode.onload = function () { + $.TE.loadUrl[this.id] = 1; + }; + newNode.onreadystatechange = function () { + //针对ie + if ((newNode.readyState == 'loaded' || newNode.readyState == 'complete')) { + $.TE.loadUrl[this.id] = 1; + } + }; + } + $("head")[0].appendChild(newNode); + } + }, + //end include + loadedFile: function (file) { + //判断是否加载 + if (!$.defined($.TE.loadUrl)) return false; + var files = $.type(file) == "string" ? [file] : file, + result = true; + $.each(files, function (i, name) { + if (!$.TE.loadUrl[name]) result = false; + //alert(name+':'+result); + }); + + return result; + }, + //end loaded + + loadFile: function (file, fun) { + //加载文件,加载完毕后执行fun函数。 + $.include(file); + + var time = 0; + var check = function () { + //alert($.loadedFile(file)); + if ($.loadedFile(file)) { + if ($.isFunction(fun)) fun(); + } else { + //alert(time); + if (time >= $.TE.timeOut) { + // TODO 细化哪些文件加载失败。 + $.debug(file, "文件加载失败"); + } else { + //alert('time:'+time); + setTimeout(check, 50); + time += 50; + } + } + }; + check(); + } + //end loadFile +}); + +})(jQuery); + +jQuery.TE.config( 'mini', { + 'controls' : 'font,fontsize,fontcolor,backcolor,bold,italic,underline,unformat,leftalign,centeralign,rightalign,orderedlist,unorderedlist', + 'width':498, + 'height':400, + 'resizeType':1 +} ); \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/thinkeditor/jquery-1.6.2.min.js b/ThinkPHP/Extend/Tool/thinkeditor/jquery-1.6.2.min.js new file mode 100644 index 0000000..48590ec --- /dev/null +++ b/ThinkPHP/Extend/Tool/thinkeditor/jquery-1.6.2.min.js @@ -0,0 +1,18 @@ +/*! + * jQuery JavaScript Library v1.6.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Jun 30 14:16:56 2011 -0400 + */ +(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c

    a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i. +shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j +)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
    ";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/thinkeditor/plugins/myplugins.js b/ThinkPHP/Extend/Tool/thinkeditor/plugins/myplugins.js new file mode 100644 index 0000000..8ad9d9e --- /dev/null +++ b/ThinkPHP/Extend/Tool/thinkeditor/plugins/myplugins.js @@ -0,0 +1,26 @@ +$.TE.plugin("bold",{ + title:"标题", + cmd:"bold", + click:function(){ + this.editor.pasteHTML("sdfdf"); + }, + bold:function(){ + alert('sdfsdf'); + }, + noRight:function(e){ + if(e.type=="click"){ + alert('noright'); + } + }, + init:function(){ + }, + event:"click mouseover mouseout", + mouseover:function(e){ + this.$btn.css("color","red"); + + }, + mouseout:function(e){ + this.$btn.css("color","#000") + } +}); + \ No newline at end of file diff --git a/ThinkPHP/Extend/Tool/thinkeditor/plugins/system.js b/ThinkPHP/Extend/Tool/thinkeditor/plugins/system.js new file mode 100644 index 0000000..9cd390b --- /dev/null +++ b/ThinkPHP/Extend/Tool/thinkeditor/plugins/system.js @@ -0,0 +1,1182 @@ +// 系统自带插件 +( function ( $ ) { + +//全屏 +$.TE.plugin( "fullscreen", { + fullscreen:function(e){ + var $btn = this.$btn, + opt = this.editor.opt; + + if($btn.is("."+opt.cssname.fulled)){ + //取消全屏 + this.editor.$main.removeAttr("style"); + this.editor.$bottom.find("div").show(); + this.editor.resize(opt.width,opt.height); + $("html,body").css("overflow","auto"); + $btn.removeClass(opt.cssname.fulled); + $(window).scrollTop(this.scrolltop); + }else{ + //全屏 + this.scrolltop=$(window).scrollTop(); + this.editor.$main.attr("style","z-index:900000;position:absolute;left:0;top:0px"); + $(window).scrollTop(0); + $("html,body").css("overflow","hidden");//隐藏滚蛋条 + this.editor.$bottom.find("div").hide();//隐藏底部的调整大小控制块 + this.editor.resize($(window).width(),$(window).height()); + $btn.addClass(opt.cssname.fulled); + } + } +} ); +//切换源码 +$.TE.plugin( "source", { + source:function(e){ + var $btn = this.$btn, + $area = this.editor.$area, + $frame = this.editor.$frame, + opt = this.editor.opt, + _self = this; + + if($btn.is("."+opt.cssname.sourceMode)){ + //切换到可视化 + _self.editor.core.updateFrame(); + $area.hide(); + $frame.show(); + $btn.removeClass(opt.cssname.sourceMode); + }else{ + //切换到源码 + _self.editor.core.updateTextArea(); + $area.show(); + $frame.hide(); + $btn.addClass(opt.cssname.sourceMode); + } + + setTimeout(function(){_self.editor.refreshBtn()},100); + } +} ); +//剪切 +$.TE.plugin( 'cut', { + click: function() { + if( $.browser.mozilla ) { + alert('您的浏览器安全设置不支持该操作,请使用Ctrl/Cmd+X快捷键完成操作。'); + } else { + this.exec(); + } + } +}); +//复制 +$.TE.plugin( 'copy', { + click: function() { + if( $.browser.mozilla ) { + alert('您的浏览器安全设置不支持该操作,请使用Ctrl/Cmd+C快捷键完成操作。'); + } else { + this.exec(); + } + } +}); +//粘贴 +$.TE.plugin( 'paste', { + click: function() { + if( $.browser.mozilla ) { + alert('您的浏览器安全设置不支持该操作,请使用Ctrl/Cmd+V快捷键完成操作。'); + } else { + this.exec(); + } + } +}); +//创建链接 +$.TE.plugin( "link", { + click:function(e){ + var _self = this; + var $html = $( + '' + ); + + if( _self.isie6() ) { + window.selectionCache = [ + /* 暂存选区对象 */ + _self.editor.doc.selection.createRange(), + /* 选区html内容 */ + _self.editor.doc.selection.createRange().htmlText, + /* 选区文本用来计算差值 */ + _self.editor.doc.selection.createRange().text + ]; + } + + this.createDialog({ + body:$html, + ok:function(){ + _self.value=$html.find("#te_dialog_url").val(); + if( _self.isie6() ) { + var _sCache = window.selectionCache, + str1 = ''+_sCache[1]+'', + str2 = ''+_sCache[2]+''; + + _sCache[0].pasteHTML( str1 ); + _sCache[0].moveStart( 'character', -_self.strlen( str2 ) + ( str2.length - _sCache[2].length ) ); + _sCache[0].moveEnd( 'character', -0 ); + _sCache[0].select(); + //置空暂存对象 + window.selectionCache = _sCache = null; + + } else { + _self.exec(); + } + _self.hideDialog(); + } + }); + }, + strlen : function ( str ) { + return window.ActiveXObject && str.indexOf("\n") != -1 ? str.replace(/\r?\n/g, "_").length : str.length; + }, + isie6 : function () { + return $.browser.msie && $.browser.version == '6.0' ? true : false; + } +} ); + +$.TE.plugin( 'print', { + click: function(e) { + var _win = this.editor.core.$frame[0].contentWindow; + if($.browser.msie) { + this.exec(); + } else if(_win.print) { + _win.print(); + } else { + alert('您的系统不支持打印接口'); + } + } +} ); + +$.TE.plugin( 'pagebreak', { + exec: function() { + var _self = this; + _self.editor.pasteHTML('
     

     

    '); + } +} ); + +$.TE.plugin( 'pastetext', { + exec: function() { + var _self = this, + _html = ''; + clipData = window.clipboardData ? window.clipboardData.getData('text') : false; + + if( clipData ) { + _self.editor.pasteHTML( clipData.replace( /\r\n/g, '
    ' ) ); + } else { + _html = $( + '
    '+ + '
    '+ + ' '+ + '
     
    '+ + '
    '+ + '
    '+ + '
    '+ + ' 请使用键盘快捷键(Ctrl/Cmd+V)把内容粘贴到下面的方框里。'+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + ' '+ + '
    '+ + '
    ' + ); + this.createDialog({ + body : _html, + ok : function(){ + _self.editor.pasteHTML(_html.find('#pasteText').val().replace(/\n/g, '
    ')); + _self.hideDialog(); + } + }); + } + } +} ); + +$.TE.plugin( 'table', { + exec : function (e) { + var _self = this, + _html = ''; + + _html = $( + '
    '+ + '
    '+ + ' '+ + '
     
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ' 行数:'+ + ' '+ + ' 列数:'+ + ' '+ + '
    '+ + '
    '+ + ' 宽度:'+ + ' '+ + ' 高度:'+ + ' '+ + '
    '+ + '
    '+ + ' 边框:'+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + ' '+ + '
    '+ + '
    ' + ); + + this.createDialog({ + body : _html, + ok : function () { + //获取参数 + var rows = parseInt(_html.find('#te_tab_rows').val()), + cols = parseInt(_html.find('#te_tab_cols').val()), + width = parseInt(_html.find('#te_tab_width').val()), + height = parseInt(_html.find('#te_tab_height').val()), + border = parseInt(_html.find('#te_tab_border').val()), + tab_html = ''; + } else { + elem.outerHTML = '
    ' + elem.outerHTML + '
    '; + } + + } else { + _doc.execCommand( 'formatblock', false, '
    ' ) + + } + + } + + }, + getElement : function () { + var ret = false; + + if( $.browser.msie ) { + ret = this.editor.doc.selection.createRange().parentElement(); + } else { + ret = this.editor.$frame.get( 0 ).contentWindow.getSelection().getRangeAt( 0 ).startContainer; + } + + return ret; + + } +} ); + +$.TE.plugin( 'image', { + + upid : 'te_image_upload', + uptype : [ 'jpg', 'jpeg', 'gif', 'png', 'bmp' ], + //文件大小 + maxsize : 1024*1024*1024*2, // 2MB + exec : function() { + var _self = this, + //上传地址 + updir = _self.editor.opt.uploadURL, + //传给上传页的参数 + parame = 'callback='+this.upid+this.editor.guid+'&rands='+(+new Date()); + if(updir && updir!='about:blank'){ + if( updir.indexOf('?') > -1 ) { + updir += '&' + parame; + } else { + updir += '?' + parame; + } + //弹出窗内容 + var $html = $( + '
    '+ + '
    '+ + ' '+ + '
     
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ' 图片地址:'+ + '
    '+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + ' 上传图片:'+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + ' '+ + ' '+ + ' 上传'+ + '
    '+ + ' '+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + ' 图片宽度:'+ + '
    '+ + ' '+ + '
    '+ + ' 图片高度:'+ + '
    '+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + ' '+ + '
    '+ + '
    ' + ), + _upcall = function(path) { + //获取上传的值 + $html.find( '#te_image_url' ).val(path); + // 刷新iframe上传页 + //var _url = $html.find( 'iframe' ).attr( 'src' ); + //_url = _url.replace( /rands=[^&]+/, 'rands=' + (+ new Date()) ); + $html.find( 'iframe' ).attr( 'src', 'about:blank' ); + } + //注册通信 + te_upload_interface( 'reg', { + 'callid' : this.upid+this.editor.guid, + 'filetype': this.uptype, + 'maxsize' : this.maxsize, + 'callback': _upcall + } ); + //创建对话框 + this.createDialog( { + body : $html, + ok : function() { + var _src = $html.find('#te_image_url').val(), + _width = parseInt($html.find('#te_image_width').val()), + _height = parseInt($html.find('#te_image_height').val()); + _src = _APP+_src; + var _insertHTML = ' -1 ) { + updir += '&' + parame; + } else { + updir += '?' + parame; + } + //弹出窗内容 + var $html = $( + '
    '+ + '
    '+ + ' '+ + '
     
    '+ + '
    '+ + '
    '+ + '
    '+ + ' flash地址:'+ + '
    '+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + ' 上传flash:'+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + ' '+ + ' '+ + ' 上传'+ + '
    '+ + ' '+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + ' 宽度:'+ + '
    '+ + ' '+ + '
    '+ + ' 高度:'+ + '
    '+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + '  '+ + '
    '+ + ' '+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + ' '+ + '
    '+ + '
    ' + ), + _upcall = function(path) { + //获取上传的值 + $html.find( '#te_flash_url' ).val(path); + // 刷新iframe上传页 + //var _url = $html.find( 'iframe' ).attr( 'src' ); + //_url = _url.replace( /rands=[^&]+/, 'rands=' + (+ new Date()) ); + $html.find( 'iframe' ).attr( 'src', 'about:blank' ); + } + + //注册通信 + te_upload_interface( 'reg', { + 'callid' : this.upid+this.editor.guid, + 'filetype': this.uptype, + 'maxsize' : this.maxsize, + 'callback': _upcall + } ); + //创建对话框 + this.createDialog( { + body : $html, + ok : function() { + var _src = $html.find('#te_flash_url').val(), + _width = parseInt($html.find('#te_flash_width').val()), + _height = parseInt($html.find('#te_flash_height').val()); + _wmode = !!$html.find('#te_flash_wmode').attr('checked'); + + if( _src == '' ) { + alert('请输入flash地址,或者从本地选择文件上传'); + return true; + } + if( isNaN(_width) || isNaN(_height) ) { + alert('请输入宽高'); + return true; + } + _src = _APP+_src; + var _data = "{'src':'"+_src+"','width':'"+_width+"','height':'"+_height+"','wmode':"+(_wmode)+"}"; + var _insertHTML = ''+ + '
    '+ + ' '+ + '
     
    '+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + '
    '+ + '' + ); + + $html.find('.insertFace span').click(function( e ) { + var _url = $.TE.basePath()+'skins/'+_fp[1]+'/'+_fp[0]+'_'+$( this ).attr( 'face_num' )+'.gif', + _insertHtml = ''; + + _self.editor.pasteHTML( _insertHtml ); + _self.hideDialog(); + + }); + + this.createDialog( { + body : $html + } ); + + } +} ); + +$.TE.plugin( 'code', { + exec: function() { + var _self = this, + $html = $( + '
    '+ + '
    '+ + ' '+ + '
     
    '+ + '
    '+ + '
    '+ + '
    '+ + ' 选择语言:'+ + ' '+ + '
    '+ + ' '+ + '
    '+ + '
    '+ + ' '+ + ' '+ + '
    '+ + '
    ' + ); + this.createDialog({ + body : $html, + ok : function(){ + var _code = $html.find('#insertCode').val(), + _type = $html.find('#langType').val(), + _html = ''; + + _code = _code.replace( //g, '>' ); + _code = _code.split('\n'); + _html += '
    '
    +				_html += '语言类型:'+_type;
    +				_html += '
      '; + for(var i=0; i<_code.length; i++) { + _html += '
    1. '+_code[i].replace( /^(\t+)/g, function( $1 ) {return $1.replace(/\t/g, ' ');} );+'
    2. '; + } + _html += '

     

    '; + _self.editor.pasteHTML( _html ); + _self.hideDialog(); + } + }); + + } +} ); + +$.TE.plugin( 'style', { + click: function() { + var _self = this, + $html = $( + '
    '+ + '
    '+ + '

    一级标题

    '+ + '

    二级标题

    '+ + '

    三级标题

    '+ + '

    四级标题

    '+ + '
    五级标题
    '+ + '
    六级标题
    '+ + '
    '+ + '
    ' + ), + _call = function(e) { + var _value = this.nodeName; + _self.value= _value; + _self.exec(); + //_self.hideDialog(); + }; + + $html.find( '>.centbox>*' ).click( _call ); + + this.createDialog( { + body: $html + } ); + }, + exec: function() { + var _self = this, + _html = '<'+_self.value+'>'+_self.editor.selectedHTML()+''; + + _self.editor.pasteHTML( _html ); + } + +} ); + +$.TE.plugin( 'font', { + click: function() { + var _self = this; + $html = $( + '
    '+ + '
    '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' ------'+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + '
    '+ + '
    ' + ), + _call = function(e) { + var _value = this.style.fontFamily; + _self.value= _value; + _self.exec(); + }; + + $html.find( '>.centbox a' ).click( _call ); + + this.createDialog( { + body: $html + } ); + } +} ); + +$.TE.plugin( 'fontsize', { + click: function() { + var _self = this, + $html = $( + '
    '+ + '
    '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + '
    '+ + '
    ' + ), + _call = function(e) { + var _value = this.style.fontSize; + _self.value= _value; + _self.exec(); + }; + + $html.find( '>.centbox a' ).click( _call ); + + this.createDialog( { + body: $html + } ); + + }, + exec: function() { + var _self = this, + _html = ''+_self.editor.selectedText()+''; + + _self.editor.pasteHTML( _html ); + } +} ); + +$.TE.plugin( 'fontcolor', { + click: function() { + var _self = this, + $html = $( + '
    '+ + '
    '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '
    '+ + '
    ' + ), + _call = function(e) { + var _value = this.style.backgroundColor; + _self.value= _value; + _self.exec(); + }; + + $html.find( '>.colorsel a' ).click( _call ); + + this.createDialog( { + body: $html + } ); + } +} ); + +$.TE.plugin( 'backcolor', { + click: function() { + var _self = this, + $html = $( + '
    '+ + '
    '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + ' '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '  '+ + '
    '+ + '
    ' + ), + _call = function(e) { + var _value = this.style.backgroundColor; + _self.value= _value; + _self.exec(); + }; + + $html.find( '>.colorsel a' ).click( _call ); + + this.createDialog( { + body: $html + } ); + } +} ); + +$.TE.plugin( 'about', { + 'click': function() { + var _self = this, + $html = $( + '
    '+ + '
    '+ + ' '+ + '
     
    '+ + '
    '+ + '
    '+ + '
    '+ + '

    ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业级应用开发而诞生的。拥有众多的优秀功能和特性,经历了三年多发展的同时,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,众多的典型案例确保可以稳定用于商业以及门户级的开发。

    '+ + '

    ThinkPHP借鉴了国外很多优秀的框架和模式,使用面向对象的开发结构和MVC模式,采用单一入口模式等,融合了Struts的Action思想和JSP的TagLib(标签库)、RoR的ORM映射和ActiveRecord模式,封装了CURD和一些常用操作,在项目配置、类库导入、模版引擎、查询语言、自动验证、视图模型、项目编译、缓存机制、SEO支持、分布式数据库、多数据库连接和切换、认证机制和扩展性方面均有独特的表现。

    '+ + '

    使用ThinkPHP,你可以更方便和快捷的开发和部署应用。当然不仅仅是企业级应用,任何PHP应用开发都可以从ThinkPHP的简单和快速的特性中受益。ThinkPHP本身具有很多的原创特性,并且倡导大道至简,开发由我的开发理念,用最少的代码完成更多的功能,宗旨就是让WEB应用开发更简单、更快速。为此ThinkPHP会不断吸收和融入更好的技术以保证其新鲜和活力,提供WEB应用开发的最佳实践!

    '+ + '

    ThinkPHP遵循Apache2开源许可协议发布,意味着你可以免费使用ThinkPHP,甚至允许把你基于ThinkPHP开发的应用开源或商业产品发布/销售。

    '+ + '
    '+ + '
    '+ + '
    '+ + ' '+ + '
    '+ + '
    ' + ); + + _self.createDialog( { + body: $html + } ); + + } +} ); + +//$.TE.plugin( 'eq', { +// 'click': function() { +// var _self = this, +// $html = $( +// '
    '+ +// '
    '+ +// ' '+ +// '
     
    '+ +// '
    '+ +// '
    '+ +// '
    '+ +// ' '+ +// '
    '+ +// ' '+ +// '
    '+ +// ' '+ +// '
    '+ +// '
    '+ +// '
    '+ +// ' '+ +// ' '+ +// '
    '+ +// '
    ' +// ); +// +// _self.createDialog({ +// body: $html, +// ok : function(){ +// var _name = $html.find('#eq_name').val(), +// _val = $html.find('#eq_val').val(), +// _content = $html.find('#eq_content').val(), +// _html = ''; +// _html += ''+ +// _content + +// ''; +// _self.editor.pasteHTML( _html ); +// _self.hideDialog(); +// } +// }); +// +// } +//}); + +} )( jQuery ); diff --git a/ThinkPHP/Extend/Tool/thinkeditor/plugins/upload_interface.js b/ThinkPHP/Extend/Tool/thinkeditor/plugins/upload_interface.js new file mode 100644 index 0000000..73aaea3 --- /dev/null +++ b/ThinkPHP/Extend/Tool/thinkeditor/plugins/upload_interface.js @@ -0,0 +1,68 @@ +function te_upload_interface() { + //初始化参数 + var _args = arguments, + _fn = _args.callee, + _data = ''; + + if( _args[0] == 'reg' ) { + //注册回调 + _data = _args[1]; + _fn.curr = _data['callid']; + _fn.data = _data; + jQuery('#temaxsize').val(_data['maxsize']); + } else if( _args[0] == 'get' ) { + //获取配置 + return _fn.data || false; + + } else if( _args[0] == 'call' ) { + //处理回调与实例不一致 + if( _args[1] != _fn.curr ) { + alert( '上传出错,请不要同时打开多个上传弹窗' ); + return false; + } + //上传成功 + if( _args[2] == 'success' ) { + _fn.data['callback']( _args[3] ); + } + //上传失败 + else if( _args[2] == 'failure' ) { + alert( '[上传失败]\n错误信息:'+_args[3] ); + } + //文件类型检测错误 + else if( _args[2] == 'filetype' ) { + alert( '[上传失败]\n错误信息:您上传的文件类型有误' ); + } + //处理状态改变 + else if( _args[2] == 'change' ) { + // TODO 更细致的回调实现,此处返回true自动提交 + return true; + } + } +} +//用户选择文件时 +function checkTypes(id){ + //校验文件类型 + var filename = document.getElementById( 'teupload' ).value, + filetype = document.getElementById( 'tefiletype' ).value.split( ',' ); + + currtype = filename.split( '.' ).pop(), + checktype = false; + + if( filetype[0] == '*' ) { + checktype = true; + } else { + for(var i=0; i + + + + + + + + + + + +
    +
    +
    + +
     
    +
    +
    +
    +
    + 图片地址: +
    + +
    +
    +
    + 上传图片: +
    +
    +
    + + + + 上传 +
    + +
    +
    +
    + 宽度: +
    + +
    + 高度: +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + +
     
    +
    +
    +
    + 请使用键盘快捷键(Ctrl/Cmd+V)把内容粘贴到下面的方框里。 + +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + +
     
    +
    +
    +
    +
    + flash地址: +
    + +
    +
    +
    + 上传flash: +
    + +
    +
    +
    + 宽度: +
    + +
    + 高度: +
    + +
    +
    +
    +   +
    + + +
    +
    +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + +
     
    +
    +
    +
    +
    + 行数: + + 列数: + +
    +
    + 宽度: + + 高度: + +
    +
    + 边框: + +
    +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + +
     
    +
    +
    +
    +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +   +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + +
     
    +
    +
    +
    + 选择语言: + +
    + +
    +
    + + +
    +
    +
    + + + + + + + + +
    +
    +
    + + + + + + + + + + + + +
    +
    +
    + + +
    +
    +
    + +   +   +   +   +   +   +   +   +   +   +   +   + +   +   +   +   +   +   +   +   +   +   +   +   + +   +   +   +   +   +   +   +   +   +   +   +   + +   +   +   +   +   +   +   +   +   +   +   +   + +   +   +   +   +   +   +   +   +   +   +   +   + +   +   +   +   +   +   +   +   +   +   +   +   +
    +
    +
    + + +
    +
    +
    + +
     
    +
    +
    +
    +

    ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业级应用开发而诞生的。拥有众多的优秀功能和特性,经历了三年多发展的同时,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,众多的典型案例确保可以稳定用于商业以及门户级的开发。

    +

    ThinkPHP借鉴了国外很多优秀的框架和模式,使用面向对象的开发结构和MVC模式,采用单一入口模式等,融合了Struts的Action思想和JSP的TagLib(标签库)、RoR的ORM映射和ActiveRecord模式,封装了CURD和一些常用操作,在项目配置、类库导入、模版引擎、查询语言、自动验证、视图模型、项目编译、缓存机制、SEO支持、分布式数据库、多数据库连接和切换、认证机制和扩展性方面均有独特的表现。

    +

    使用ThinkPHP,你可以更方便和快捷的开发和部署应用。当然不仅仅是企业级应用,任何PHP应用开发都可以从ThinkPHP的简单和快速的特性中受益。ThinkPHP本身具有很多的原创特性,并且倡导大道至简,开发由我的开发理念,用最少的代码完成更多的功能,宗旨就是让WEB应用开发更简单、更快速。为此ThinkPHP会不断吸收和融入更好的技术以保证其新鲜和活力,提供WEB应用开发的最佳实践!

    +

    ThinkPHP遵循Apache2开源许可协议发布,意味着你可以免费使用ThinkPHP,甚至允许把你基于ThinkPHP开发的应用开源或商业产品发布/销售。

    +
    +
    +
    + +
    +
    +
    + + +
    + +
    + + + diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/bg_img.jpg b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/bg_img.jpg new file mode 100644 index 0000000..a133fc0 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/bg_img.jpg differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/bg_img.png b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/bg_img.png new file mode 100644 index 0000000..41d2fdd Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/bg_img.png differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/resize_center.jpg b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/resize_center.jpg new file mode 100644 index 0000000..124775b Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/resize_center.jpg differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/resize_leftjpg.jpg b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/resize_leftjpg.jpg new file mode 100644 index 0000000..def740f Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/resize_leftjpg.jpg differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/spacer.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/spacer.gif new file mode 100644 index 0000000..5bfd67a Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/img/spacer.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/default/style.css b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/style.css new file mode 100644 index 0000000..d3e303e --- /dev/null +++ b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/style.css @@ -0,0 +1,233 @@ +.te_main{ + border:#b1bab7 1px solid; + background:#FFF; +} +.te_toolbar_box { + padding-bottom:5px; + border-bottom:#b1bab7 1px solid; + background:#f5f5f5; +} +.te_toolbar{ + margin-left:10px; + margin-right:8px; + overflow:hidden; + _zoom: 1; +} + +.te_toolbar:after { + content: "\0020"; + display: block; + height: 0; + clear: both; +} +*+html .te_toolbar{ + overflow:hidden; +} + +.te_main iframe{ +} + +/*textarea样式, 注意设置resize:none,不然火狐能拖动*/ + +.te_main textarea{ + border:none; + resize:none; + overflow-y:scroll; +} +.te_dialog{ + position:absolute; + display:none; +} + +.te_group{ + float:left; + margin:1px; + height:17px; + overflow-y:hidden; + margin-top:5px; + margin-left:-2px; + margin-right:2px; +} + +.te_btn{ + float:left; + margin-right:5px; + width:27px; + height:17px; + cursor:pointer; + font-size:8px; + background-image:url(img/bg_img.png); + background-repeat:no-repeat; +} + +.te_line{ + width:0; + height:17px; + border-left:1px solid #fff; + border-right:1px solid #b0baba; + float:left; + overflow:hidden; + zoom:1; + margin-right:5px; +} + +.te_btn_source{ + background-position: 2px -4px ; +} +.te_btn_undo{ + background-position: 6px -29px; +} +.te_btn_redo{ + background-position: 6px -54px; +} +.te_btn_cut{ + background-position: 6px -79px; +} +.te_btn_copy{ + background-position: 6px -104px; +} +.te_btn_paste{ + background-position: 6px -129px; +} +.te_btn_pastetext{ + background-position: 6px -154px; +} +.te_btn_pastefromword{ + background-position: 6px -179px; +} +.te_btn_selectAll{ + background-position: 6px -204px; +} +.te_btn_blockquote{ + background-position: 6px -229px; +} +.te_btn_find{ + background-position: 6px -254px; +} +.te_btn_image{ + background-position: 6px -279px; +} +.te_btn_flash{ + background-position: 6px -304px; +} +.te_btn_media{ + background-position: 6px -329px; +} +.te_btn_table{ + background-position: 6px -354px; +} +.te_btn_hr{ + background-position: 6px -379px; +} +.te_btn_pagebreak{ + background-position: 6px -404px; +} +.te_btn_face{ + background-position: 6px -429px; +} +.te_btn_code{ + background-position: 6px -454px; +} +.te_btn_link{ + background-position: 6px -479px; +} +.te_btn_unlink{ + background-position: 6px -504px; +} +.te_btn_print{ + background-position: 6px -529px; +} +.te_btn_fullscreen{ + background-position: 6px -554px; +} +.te_btn_style{ + background-position: 6px -579px; +} +.te_btn_font{ + background-position: 6px -604px; +} +.te_btn_fontsize{ + background-position: 6px -629px; +} +.te_btn_fontcolor{ + background-position: 6px -654px; +} +.te_btn_backcolor{ + background-position: 6px -679px; +} +.te_btn_bold{ + background-position: 6px -704px; +} +.te_btn_italic{ + background-position: 6px -729px; +} +.te_btn_underline{ + background-position: 6px -754px; +} +.te_btn_strikethrough{ + background-position: 6px -779px; +} +.te_btn_unformat{ + background-position: 6px -804px; +} +.te_btn_leftalign{ + background-position: 6px -829px; +} +.te_btn_centeralign{ + background-position: 6px -854px; +} +.te_btn_rightalign{ + background-position: 6px -879px; +} +.te_btn_blockjustify{ + background-position: 6px -904px; +} +.te_btn_orderedlist{ + background-position: 6px -929px; +} +.te_btn_unorderedlist{ + background-position: 6px -954px; +} +.te_btn_indent{ + background-position: 6px -979px; +} +.te_btn_outdent{ + background-position: 6px -1004px; +} +.te_btn_subscript{ + background-position: 6px -1029px; +} +.te_btn_superscript{ + background-position: 6px -1054px; +} +.te_btn_about{ + background-position: 6px -1079px; +} + +.te_bottom{ + border-top:#b1bab7 1px solid; + position:relative; + top:-1px; + height:12px; + overflow:hidden; + zoom:1; +} +.te_resize_center{ + height:12px; + overflow:hidden; + cursor:n-resize; + zoom:1; + background:#f5f5f5 url(img/resize_center.jpg) center center no-repeat; +} +.te_resize_left{ + width:10px; + height:10px; + cursor:nw-resize; + background:url(img/resize_leftjpg.jpg) no-repeat; + position:absolute; + bottom:0; + right:0; + overflow:hidden; + zoom:1; +} + diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/default/styles.css b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/styles.css new file mode 100644 index 0000000..52ef632 --- /dev/null +++ b/ThinkPHP/Extend/Tool/thinkeditor/skins/default/styles.css @@ -0,0 +1,218 @@ +.te_main { + background: none repeat scroll 0 0 #FFFFFF; + border: 1px solid #B1BAB7; +} +.te_toolbar_box { + background: none repeat scroll 0 0 #F5F5F5; + border-bottom: 1px solid #B1BAB7; + padding-bottom: 12px; +} +.te_toolbar { + margin-left: 10px; + margin-right: 8px; + overflow: hidden; +} +.te_toolbar:after { + clear: both; + content: " "; + display: block; + height: 0; +} +* + html .te_toolbar { + overflow: hidden; +} +.te_main iframe { +} +.te_main textarea { + border: medium none; + overflow-y: scroll; + resize: none; +} +.te_dialog { + display: none; + position: absolute; +} +.te_group { + float: left; + height: 22px; + margin: 8px 2px 1px -2px; + overflow-y: hidden; +} +.te_btn { + background-image: url("img/bg_img.png"); + background-repeat: no-repeat; + border: 1px solid #F5F5F5; + cursor: pointer; + float: left; + font-size: 8px; + height: 20px; + margin-right: 5px; + width: 20px; +} +.te_line { + border-left: 1px solid #FFFFFF; + border-right: 1px solid #B0BABA; + float: left; + height: 20px; + margin-right: 5px; + overflow: hidden; + width: 0; +} +.te_mouseover { + border: 1px solid #C0C0C0; +} +.te_btn_source { + background-position: 2px -4px; +} +.te_btn_undo { + background-position: 3px -28px; +} +.te_btn_redo { + background-position: 3px -53px; +} +.te_btn_cut { + background-position: 2px -78px; +} +.te_btn_copy { + background-position: 3px -103px; +} +.te_btn_paste { + background-position: 2px -128px; +} +.te_btn_pastetext { + background-position: 2px -153px; +} +.te_btn_pastefromword { + background-position: 3px -177px; +} +.te_btn_selectAll { + background-position: 2px -203px; +} +.te_btn_blockquote { + background-position: 2px -228px; +} +.te_btn_find { + background-position: 3px -254px; +} +.te_btn_image { + background-position: 2px -278px; +} +.te_btn_flash { + background-position: 2px -303px; +} +.te_btn_media { + background-position: 3px -329px; +} +.te_btn_table { + background-position: 2px -353px; +} +.te_btn_hr { + background-position: 3px -377px; +} +.te_btn_pagebreak { + background-position: 2px -403px; +} +.te_btn_face { + background-position: 2px -428px; +} +.te_btn_code { + background-position: 1px -452px; +} +.te_btn_link { + background-position: 3px -478px; +} +.te_btn_unlink { + background-position: 3px -503px; +} +.te_btn_print { + background-position: 2px -528px; +} +.te_btn_fullscreen { + background-position: 2px -553px; +} +.te_btn_style { + background-position: 3px -579px; +} +.te_btn_font { + background-position: 2px -604px; +} +.te_btn_fontsize { + background-position: 2px -629px; +} +.te_btn_fontcolor { + background-position: 3px -652px; +} +.te_btn_backcolor { + background-position: 2px -678px; +} +.te_btn_bold { + background-position: 3px -702px; +} +.te_btn_italic { + background-position: 4px -727px; +} +.te_btn_underline { + background-position: 3px -752px; +} +.te_btn_strikethrough { + background-position: 2px -779px; +} +.te_btn_unformat { + background-position: 3px -803px; +} +.te_btn_leftalign { + background-position: 3px -828px; +} +.te_btn_centeralign { + background-position: 3px -853px; +} +.te_btn_rightalign { + background-position: 3px -878px; +} +.te_btn_blockjustify { + background-position: 3px -903px; +} +.te_btn_orderedlist { + background-position: 3px -929px; +} +.te_btn_unorderedlist { + background-position: 3px -953px; +} +.te_btn_indent { + background-position: 4px -978px; +} +.te_btn_outdent { + background-position: 4px -1003px; +} +.te_btn_subscript { + background-position: 2px -1028px; +} +.te_btn_superscript { + background-position: 3px -1053px; +} +.te_btn_about { + background-position: 4px -1079px; +} +.te_bottom { + border-top: 1px solid #B1BAB7; + height: 12px; + overflow: hidden; + position: relative; + top: -1px; +} +.te_resize_center { + background: url("img/resize_center.jpg") no-repeat scroll center center #F5F5F5; + cursor: n-resize; + height: 12px; + overflow: hidden; +} +.te_resize_left { + background: url("img/resize_leftjpg.jpg") no-repeat scroll 0 0 transparent; + bottom: 0; + cursor: nw-resize; + height: 10px; + overflow: hidden; + position: absolute; + right: 0; + width: 10px; +} diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face.gif new file mode 100644 index 0000000..2d3d9d0 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_0.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_0.gif new file mode 100644 index 0000000..5be27cb Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_0.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_1.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_1.gif new file mode 100644 index 0000000..a2644a9 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_1.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_10.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_10.gif new file mode 100644 index 0000000..905c15b Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_10.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_100.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_100.gif new file mode 100644 index 0000000..92ad35d Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_100.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_101.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_101.gif new file mode 100644 index 0000000..1f27663 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_101.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_102.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_102.gif new file mode 100644 index 0000000..748ded1 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_102.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_103.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_103.gif new file mode 100644 index 0000000..be9eaa0 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_103.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_104.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_104.gif new file mode 100644 index 0000000..d7c2066 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_104.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_11.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_11.gif new file mode 100644 index 0000000..b512dd5 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_11.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_12.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_12.gif new file mode 100644 index 0000000..547529c Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_12.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_13.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_13.gif new file mode 100644 index 0000000..3475300 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_13.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_14.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_14.gif new file mode 100644 index 0000000..6a788f8 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_14.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_15.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_15.gif new file mode 100644 index 0000000..debab8e Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_15.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_16.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_16.gif new file mode 100644 index 0000000..ed5d29f Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_16.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_17.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_17.gif new file mode 100644 index 0000000..85886fe Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_17.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_18.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_18.gif new file mode 100644 index 0000000..b6af218 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_18.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_19.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_19.gif new file mode 100644 index 0000000..e045ff2 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_19.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_2.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_2.gif new file mode 100644 index 0000000..40cfda4 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_2.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_20.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_20.gif new file mode 100644 index 0000000..efd650f Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_20.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_21.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_21.gif new file mode 100644 index 0000000..cb8cf6d Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_21.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_22.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_22.gif new file mode 100644 index 0000000..96b04df Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_22.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_23.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_23.gif new file mode 100644 index 0000000..96516b8 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_23.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_24.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_24.gif new file mode 100644 index 0000000..5f925c7 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_24.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_25.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_25.gif new file mode 100644 index 0000000..97f8b1a Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_25.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_26.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_26.gif new file mode 100644 index 0000000..a7cded7 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_26.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_27.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_27.gif new file mode 100644 index 0000000..bb46890 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_27.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_28.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_28.gif new file mode 100644 index 0000000..f59dd58 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_28.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_29.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_29.gif new file mode 100644 index 0000000..3c5227e Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_29.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_3.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_3.gif new file mode 100644 index 0000000..6d6f762 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_3.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_30.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_30.gif new file mode 100644 index 0000000..e24a180 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_30.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_31.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_31.gif new file mode 100644 index 0000000..073e743 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_31.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_32.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_32.gif new file mode 100644 index 0000000..772eff2 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_32.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_33.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_33.gif new file mode 100644 index 0000000..217c1c5 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_33.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_34.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_34.gif new file mode 100644 index 0000000..e9d4213 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_34.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_35.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_35.gif new file mode 100644 index 0000000..d6da2c3 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_35.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_36.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_36.gif new file mode 100644 index 0000000..c1e6ac9 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_36.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_37.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_37.gif new file mode 100644 index 0000000..92efec6 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_37.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_38.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_38.gif new file mode 100644 index 0000000..489f0f9 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_38.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_39.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_39.gif new file mode 100644 index 0000000..734f6d8 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_39.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_4.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_4.gif new file mode 100644 index 0000000..6ccdaa2 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_4.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_40.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_40.gif new file mode 100644 index 0000000..24a8eb6 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_40.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_41.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_41.gif new file mode 100644 index 0000000..99139e1 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_41.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_42.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_42.gif new file mode 100644 index 0000000..f60897e Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_42.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_43.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_43.gif new file mode 100644 index 0000000..4350491 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_43.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_44.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_44.gif new file mode 100644 index 0000000..650d3dd Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_44.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_45.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_45.gif new file mode 100644 index 0000000..5c8e071 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_45.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_46.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_46.gif new file mode 100644 index 0000000..f3cb074 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_46.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_47.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_47.gif new file mode 100644 index 0000000..5b3057a Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_47.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_48.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_48.gif new file mode 100644 index 0000000..27a30c1 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_48.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_49.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_49.gif new file mode 100644 index 0000000..dcfa48a Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_49.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_5.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_5.gif new file mode 100644 index 0000000..90c3d86 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_5.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_50.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_50.gif new file mode 100644 index 0000000..029cf0f Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_50.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_51.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_51.gif new file mode 100644 index 0000000..69f183f Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_51.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_52.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_52.gif new file mode 100644 index 0000000..d41e8aa Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_52.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_53.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_53.gif new file mode 100644 index 0000000..56352dd Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_53.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_54.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_54.gif new file mode 100644 index 0000000..b28d848 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_54.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_55.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_55.gif new file mode 100644 index 0000000..e18da84 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_55.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_56.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_56.gif new file mode 100644 index 0000000..edf96f0 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_56.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_57.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_57.gif new file mode 100644 index 0000000..3f0e2b9 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_57.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_58.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_58.gif new file mode 100644 index 0000000..47b1aaa Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_58.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_59.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_59.gif new file mode 100644 index 0000000..918288b Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_59.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_6.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_6.gif new file mode 100644 index 0000000..ceab122 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_6.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_60.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_60.gif new file mode 100644 index 0000000..66d2113 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_60.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_61.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_61.gif new file mode 100644 index 0000000..034933e Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_61.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_62.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_62.gif new file mode 100644 index 0000000..8d5c4fd Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_62.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_63.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_63.gif new file mode 100644 index 0000000..d58fcf6 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_63.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_64.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_64.gif new file mode 100644 index 0000000..c4e00bd Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_64.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_65.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_65.gif new file mode 100644 index 0000000..da23bfa Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_65.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_66.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_66.gif new file mode 100644 index 0000000..310ec65 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_66.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_67.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_67.gif new file mode 100644 index 0000000..51761ba Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_67.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_68.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_68.gif new file mode 100644 index 0000000..345cb43 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_68.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_69.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_69.gif new file mode 100644 index 0000000..e0f28a0 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_69.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_7.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_7.gif new file mode 100644 index 0000000..2f45399 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_7.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_70.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_70.gif new file mode 100644 index 0000000..24284cf Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_70.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_71.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_71.gif new file mode 100644 index 0000000..a0ccf2e Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_71.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_72.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_72.gif new file mode 100644 index 0000000..7e113ee Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_72.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_73.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_73.gif new file mode 100644 index 0000000..c0293c3 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_73.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_74.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_74.gif new file mode 100644 index 0000000..1c52bde Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_74.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_75.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_75.gif new file mode 100644 index 0000000..9cb9aa7 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_75.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_76.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_76.gif new file mode 100644 index 0000000..27019f8 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_76.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_77.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_77.gif new file mode 100644 index 0000000..8f882f5 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_77.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_78.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_78.gif new file mode 100644 index 0000000..d0d0856 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_78.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_79.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_79.gif new file mode 100644 index 0000000..61652a7 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_79.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_8.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_8.gif new file mode 100644 index 0000000..f6c8834 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_8.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_80.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_80.gif new file mode 100644 index 0000000..9a77936 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_80.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_81.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_81.gif new file mode 100644 index 0000000..2329101 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_81.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_82.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_82.gif new file mode 100644 index 0000000..644748a Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_82.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_83.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_83.gif new file mode 100644 index 0000000..fbf275b Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_83.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_84.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_84.gif new file mode 100644 index 0000000..076f0c6 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_84.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_85.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_85.gif new file mode 100644 index 0000000..d254af4 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_85.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_86.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_86.gif new file mode 100644 index 0000000..8f09d33 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_86.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_87.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_87.gif new file mode 100644 index 0000000..df70756 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_87.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_88.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_88.gif new file mode 100644 index 0000000..4d8b15e Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_88.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_89.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_89.gif new file mode 100644 index 0000000..f7152f9 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_89.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_9.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_9.gif new file mode 100644 index 0000000..73fc097 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_9.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_90.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_90.gif new file mode 100644 index 0000000..adaf20e Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_90.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_91.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_91.gif new file mode 100644 index 0000000..608d0ad Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_91.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_92.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_92.gif new file mode 100644 index 0000000..b909e16 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_92.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_93.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_93.gif new file mode 100644 index 0000000..7f71a8c Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_93.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_94.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_94.gif new file mode 100644 index 0000000..4f26d7d Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_94.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_95.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_95.gif new file mode 100644 index 0000000..5ef6d38 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_95.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_96.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_96.gif new file mode 100644 index 0000000..2b709e1 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_96.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_97.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_97.gif new file mode 100644 index 0000000..cf29be8 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_97.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_98.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_98.gif new file mode 100644 index 0000000..c70e7d3 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_98.gif differ diff --git a/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_99.gif b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_99.gif new file mode 100644 index 0000000..05c1863 Binary files /dev/null and b/ThinkPHP/Extend/Tool/thinkeditor/skins/qq_face/qq_face_99.gif differ diff --git a/ThinkPHP/Extend/Vendor/EaseTemplate/template.core.php b/ThinkPHP/Extend/Vendor/EaseTemplate/template.core.php new file mode 100644 index 0000000..630c38d --- /dev/null +++ b/ThinkPHP/Extend/Vendor/EaseTemplate/template.core.php @@ -0,0 +1,970 @@ +Power by Ease Template!');}"; + var $Compile = array(); + var $Analysis = array(); + var $Emc = array(); + + /** + * 声明模板用法 + */ + function ETCoreStart( + $set = array( + 'ID' =>'1', //缓存ID + 'TplType' =>'htm', //模板格式 + 'CacheDir' =>'cache', //缓存目录 + 'TemplateDir'=>'template' , //模板存放目录 + 'AutoImage' =>'on' , //自动解析图片目录开关 on表示开放 off表示关闭 + 'LangDir' =>'language' , //语言文件存放的目录 + 'Language' =>'default' , //语言的默认文件 + 'Copyright' =>'off' , //版权保护 + 'MemCache' =>'' , //Memcache服务器地址例如:127.0.0.1:11211 + ) + ){ + + $this->TplID = (defined('TemplateID')?TemplateID:( ((int)@$set['ID']<=1)?1:(int)$set['ID']) ).'_'; + + $this->CacheDir = (defined('NewCache')?NewCache:( (trim($set['CacheDir']) != '')?$set['CacheDir']:'cache') ).'/'; + + $this->TemplateDir = (defined('NewTemplate')?NewTemplate:( (trim($set['TemplateDir']) != '')?$set['TemplateDir']:'template') ).'/'; + + $this->Ext = (@$set['TplType'] != '')?$set['TplType']:'htm'; + + $this->AutoImage = (@$set['AutoImage']=='off')?0:1; + + $this->Copyright = (@$set['Copyright']=='off')?0:1; + + $this->Server = (is_array($GLOBALS['_SERVER']))?$GLOBALS['_SERVER']:$_SERVER; + $this->version = (trim($_GET['EaseTemplateVer']))?die('Ease Templae E3!'):''; + + //载入语言文件 + $this->LangDir = (defined('LangDir')?LangDir:( ((@$set['LangDir']!='language' && @$set['LangDir'])?$set['LangDir']:'language') )).'/'; + if(is_dir($this->LangDir)){ + $this->Language = (defined('Language')?Language:( (($set['Language']!='default' && $set['Language'])?$set['Language']:'default') )); + if(@is_file($this->LangDir.$this->Language.'.php')){ + $lang = array(); + @include_once $this->LangDir.$this->Language.'.php'; + $this->LangData = $lang; + } + }else{ + $this->Language = 'default'; + } + + + //缓存目录检测以及运行模式 + if(@ereg(':',$set['MemCache'])){ + $this->RunType = 'MemCache'; + $memset = explode(":",$set['MemCache']); + $this->Emc = memcache_connect($memset[0], $memset[1]) OR die("Could not connect!"); + }else{ + $this->RunType = (@substr(@sprintf('%o', @fileperms($this->CacheDir)), -3)==777 && is_dir($this->CacheDir))?'Cache':'Replace'; + } + + $CompileBasic = array( + '/(\{\s*|)/eis', + + '//is', + '//is', + '//is', + '//is', + '//is', + '//', + '//is', + + '/(\{\s*|)/eis', + '/(\{\s*|)/eis', + '/(\{\s*|)/eis', + '/(\{\s*|)/eis', + '/(\{\s*|)\s*(.+?)\s*(\{|)/is', + '/(\{\s*|)/is', + '/\{([a-zA-Z0-9_\'\"\[\]\$]{1,100})\}/', + ); + $this->Compile = (is_array($this->Compile))?array_merge($this->Compile,$CompileBasic):$CompileBasic; + + $AnalysisBasic = array( + '$this->inc_php("\\2")', + + '";if($ET_Del==true){echo"', + '";if(\\2){echo"', + '";}elseif(\\2){echo"', + '";}else{echo"', + '";}echo"', + '";\$_i=0;foreach((array)\\1 AS \\3){\$_i++;echo"', + '";\$_i=0;while(\\1){\$_i++;echo"', + + '$this->lang("\\2")', + '$this->Row("\\2")', + '$this->Color("\\2")', + '$this->Dirs("\\2")', + '";\\3;echo"', + '";\\2;echo"', + '";echo \$\\1;echo"', + ); + $this->Analysis = (is_array($this->Analysis))?array_merge($this->Analysis,$AnalysisBasic):$AnalysisBasic; + + } + + + /** + * 设置数值 + * set_var(变量名或是数组,设置数值[数组不设置此值]); + */ + function set_var( + $name, + $value = '' + ){ + if (is_array($name)){ + $this->ThisValue = @array_merge($this->ThisValue,$name); + }else{ + $this->ThisValue[$name] = $value; + } + } + + + /** + * 设置模板文件 + * set_file(文件名,设置目录); + */ + function set_file( + $FileName, + $NewDir = '' + ){ + //当前模板名 + $this->ThisFile = $FileName.'.'.$this->Ext; + + //目录地址检测 + $this->FileDir[$this->ThisFile] = (trim($NewDir) != '')?$NewDir.'/':$this->TemplateDir; + + $this->IncFile[$FileName] = $this->FileDir[$this->ThisFile].$this->ThisFile; + + if(!is_file($this->IncFile[$FileName]) && $this->Copyright==1){ + die('Sorry, The file '.$this->IncFile[$FileName].' does not exist.'); + } + + + //bug 系统 + $this->IncList[] = $this->ThisFile; + } + + //解析替换程序 + function ParseCode( + $FileList = '', + $CacheFile = '' + ){ + //模板数据 + $ShowTPL = ''; + //解析续载 + if (@is_array($FileList) && $FileList!='include_page'){ + foreach ($FileList AS $K=>$V) { + $ShowTPL .= $this->reader($V.$K); + } + }else{ + + + //如果指定文件地址则载入 + $SourceFile = ($FileList!='')?$FileList:$this->FileDir[$this->ThisFile].$this->ThisFile; + + if(!is_file($SourceFile) && $this->Copyright==1){ + die('Sorry, The file '.$SourceFile.' does not exist.'); + } + + $ShowTPL = $this->reader($SourceFile); + } + + //引用模板处理 + $ShowTPL = $this->inc_preg($ShowTPL); + + //检测run方法 + $run = 0; + if (eregi("run:",$ShowTPL)){ + $run = 1; + //Fix = + $ShowTPL = preg_replace('/(\{|)\s*=/','{run:}echo ',$ShowTPL); + $ShowTPL = preg_replace('/(\{|)\s*(.+?)\s*(\{|)/is', '(T_T)\\3;(T_T!)',$ShowTPL); + } + + //Fix XML + if (eregi("/is', '\\1', $ShowTPL); + } + + //修复代码中\n换行错误 + $ShowTPL = str_replace('\\','\\\\',$ShowTPL); + //修复双引号问题 + $ShowTPL = str_replace('"','\"',$ShowTPL); + + //编译运算 + $ShowTPL = @preg_replace($this->Compile, $this->Analysis, $ShowTPL); + + //分析图片地址 + $ShowTPL = $this->ImgCheck($ShowTPL); + + //Fix 模板中金钱符号 + $ShowTPL = str_replace('$','\$',$ShowTPL); + + //修复php运行错误 + $ShowTPL = @preg_replace("/\";(.+?)echo\"/e", '$this->FixPHP(\'\\1\')', $ShowTPL); + + //Fix Run 2 + if ($run==1){ + $ShowTPL = preg_replace("/\(T_T\)(.+?)\(T_T!\)/ise", '$this->FixPHP(\'\\1\')', $ShowTPL); + } + + //还原xml + $ShowTPL = (strrpos($ShowTPL,''))?@preg_replace('/ET>(.+?)<\/ET/is', '?\\1?', $ShowTPL):$ShowTPL; + + //修复"问题 + $ShowTPL = str_replace('echo ""','echo "\"',$ShowTPL); + + + //从数组中将变量导入到当前的符号表 + @extract($this->Value()); + ob_start(); + ob_implicit_flush(0); + @eval('echo "'.$ShowTPL.'";'); + $contents = ob_get_contents(); + ob_end_clean(); + + //Cache htm + if($this->HtmID){ + $this->writer($this->HtmDir.$this->HtmID,$this->Hacker."?>".$contents); + } + + + //编译模板 + if ($this->RunType=='Cache'){ + $this->CompilePHP($ShowTPL,$CacheFile); + } + + + //错误检查 + if(strlen($contents)<=0){ + //echo $ShowTPL; + die('
    Sorry, Error or complicated syntax error exists in '.$SourceFile.' file.'); + } + + return $contents; + } + + + /** + * 多语言 + */ + function lang( + $str = '' + ){ + if (is_dir($this->LangDir)){ + + //采用MD5效验 + $id = md5($str); + + //不存在数据则写入 + if($this->LangData[$id]=='' && $this->Language=='default'){ + + //语言包文件 + if (@is_file($this->LangDir.$this->Language.'.php')){ + unset($lang); + @include($this->LangDir.$this->Language.'.php'); + } + + + //如果检测到有数据则输出 + if ($lang[$id]){ + $out = str_replace('\\','\\\\',$lang[$id]); + return str_replace('"','\"',$out); + } + + + //修复'多\问题 + $str = str_replace("\\'","'",$str); + + + //语言文件过大时采取建立新文件 + if(strlen($docs)>400){ + $this->writer($this->LangDir.$this->Language.'.'.$id.'.php',''); + $docs= substr($str,0,40); //简要说明 + $docs = str_replace('\"','"',$docs); + $docs = str_replace('\\\\','\\',$docs); + $str = 'o(O_O)o.ET Lang.o(*_*)o'; //语言新文件 + }else{ + $docs = str_replace('\"','"',$str); + $docs = str_replace('\\\\','\\',$docs); + } + + //文件安全处理 + $data = (!is_file($this->LangDir.'default.php'))?"Language."\n*/\n\n\n":''; + + + if (trim($str)){ + //写入数据 + $data .= "/**".date("Y.m.d",time())."\n"; + $data.= $docs."\n"; + $data.= "*/\n"; + $data.= '$lang["'.$id.'"] = "'.$str.'";'."\n\n"; + $this->writer($this->LangDir.'default.php',$data,'a+'); + } + } + + //单独语言文件包 + if($this->LangData[$id]=='o(O_O)o.ET Lang.o(*_*)o'){ + unset($etl); + include($this->LangDir.$this->Language.".".$id.".php"); + $this->LangData[$id] = $etl; + } + + $out = ($this->LangData[$id])?$this->LangData[$id]:$str; + + //输出部分要做处理 + if(($this->RunType=='Replace' || $this->RunType!='Replace') && $data==''){ + $out = str_replace('\\','\\\\',$out); + $out = str_replace('"','\"',$out); + } + + return $out; + }else{ + return $str; + } + } + + /** + * inc引用函数 + */ + function inc_preg( + $content + ){ + return preg_replace('/<\!--\s*\#include\s*file\s*=(\"|\')([a-zA-Z0-9_\.\|]{1,100})(\"|\')\s*-->/eis', '$this->inc("\\2")', preg_replace('/(\{\s*|)/eis', '$this->inc("\\2")', $content)); + } + + + /** + * 引用函数运算 + */ + function inc( + $Files = '' + ){ + if($Files){ + if (!strrpos($Files,$this->Ext)){ + $Files = $Files.".".$this->Ext; + } + $FileLs = $this->TemplateDir.$Files; + $contents =$this->ParseCode($FileLs,$Files); + + if($this->RunType=='Cache'){ + //引用模板 + $this->IncList[] = $Files; + $cache_file = $this->CacheDir.$this->TplID.$Files.".".$this->Language.".php"; + return " +{inc_php:".$cache_file."} +{run:@eval('echo \"'.\$EaseTemplate3_Cache.'\";')} +"; + }elseif($this->RunType=='MemCache'){ + //cache date + memcache_set($this->Emc,$Files.'_date', time()) OR die("Failed to save data at the server."); + memcache_set($this->Emc,$Files, $contents) OR die("Failed to save data at the server"); + return "".$contents; + }else{ + //引用模板 + $this->IncList[] = $Files; + return $contents; + } + } + } + + + /** + * 编译解析处理 + */ + function CompilePHP( + $content='', + $cachename = '' + ){ + if ($content){ + //如果没有安全文件则自动创建 + if($this->RunType=='Cache' && !is_file($this->CacheDir.'index.htm')){ + $Ease_name = 'Ease Template!'; + $Ease_base = "$Ease_name$Ease_name"; + $this->writer($this->CacheDir.'index.htm',$Ease_base); + $this->writer($this->CacheDir.'index.html',$Ease_base); + $this->writer($this->CacheDir.'default.htm',$Ease_base); + } + + + //编译记录 + $content = str_replace("\\","\\\\",$content); + $content = str_replace("'","\'",$content); + $content = str_replace('echo"";',"",$content); //替换多余数据 + + $wfile = ($cachename)?$cachename:$this->ThisFile; + $this->writer($this->FileName($wfile,$this->TplID) ,$this->Hacker.'$EaseTemplate3_Cache = \''.$content.'\';'); + } + } + + + //修复PHP执行时产生的错误 + function FixPHP( + $content='' + ){ + $content = str_replace('\\\\','\\',$content); + return '";'.str_replace('\\"','"',str_replace('\$','$',$content)).'echo"'; + } + + + /** + * 检测缓存是否要更新 + * filename 缓存文件名 + * settime 指定事件则提供更新,只用于memcache + */ + function FileUpdate($filname,$settime=0){ + + //检测设置模板文件 + if (is_array($this->IncFile)){ + unset($k,$v); + $update = 0; + $settime = ($settime>0)?$settime:@filemtime($filname); + foreach ($this->IncFile AS $k=>$v) { + if (@filemtime($v)>$settime){$update = 1;} + } + //更新缓存 + if($update==1){ + return false; + }else { + return $filname; + } + + }else{ + return $filname; + } + } + + + /** + * 输出运算 + * Filename 连载编译输出文件名 + */ + function output( + $Filename = '' + ){ + switch($this->RunType){ + + //Mem编译模式 + case'MemCache': + if ($Filename=='include_page'){ + //直接输出文件 + return $this->reader($this->FileDir[$this->ThisFile].$this->ThisFile); + }else{ + + $FileNames = ($Filename)?$Filename:$this->ThisFile; + $CacheFile = $this->FileName($FileNames,$this->TplID); + + //检测记录时间 + $updateT = memcache_get($this->Emc,$CacheFile.'_date'); + $update = $this->FileUpdate($CacheFile,$updateT); + + $CacheData = memcache_get($this->Emc,$CacheFile); + + if(trim($CacheData) && $update){ + //获得列表文件 + unset($ks,$vs); + preg_match_all('/<\!-- ET\_inc\_cache\[(.+?)\] -->/',$CacheData, $IncFile); + if (is_array($IncFile[1])){ + foreach ($IncFile[1] AS $ks=>$vs) { + $this->IncList[] = $vs; + $listDate = memcache_get($this->Emc,$vs.'_date'); + + echo @filemtime($this->TemplateDir.$vs).' - '.$listDate.'
    '; + + //更新inc缓存 + if (@filemtime($this->TemplateDir.$vs)>$listDate){ + $update = 1; + $this->inc($vs); + } + } + + //更新数据 + if ($update == 1){ + $CacheData = $this->ParseCode($this->FileList,$Filename); + //cache date + @memcache_set($this->Emc,$CacheFile.'_date', time()) OR die("Failed to save data at the server."); + @memcache_set($this->Emc,$CacheFile, $CacheData) OR die("Failed to save data at the server."); + } + } + //Close + memcache_close($this->Emc); + return $CacheData; + }else{ + if ($Filename){ + $CacheData = $this->ParseCode($this->FileList,$Filename); + //cache date + @memcache_set($this->Emc,$CacheFile.'_date', time()) OR die("Failed to save data at the server."); + @memcache_set($this->Emc,$CacheFile, $CacheData) OR die("Failed to save data at the server."); + //Close + memcache_close($this->Emc); + return $CacheData; + }else{ + $CacheData = $this->ParseCode(); + //cache date + @memcache_set($this->Emc,$CacheFile.'_date', time()) OR die("Failed to save data at the server."); + @memcache_set($this->Emc,$CacheFile, $CacheData) OR die("Failed to save data at the server2"); + //Close + memcache_close($this->Emc); + return $CacheData; + } + } + } + break; + + + //编译模式 + case'Cache': + if ($Filename=='include_page'){ + //直接输出文件 + return $this->reader($this->FileDir[$this->ThisFile].$this->ThisFile); + }else{ + + $FileNames = ($Filename)?$Filename:$this->ThisFile; + $CacheFile = $this->FileName($FileNames,$this->TplID); + + $CacheFile = $this->FileUpdate($CacheFile); + + if (@is_file($CacheFile)){ + @extract($this->Value()); + ob_start(); + ob_implicit_flush(0); + include $CacheFile; + + //获得列表文件 + if($EaseTemplate3_Cache!=''){ + unset($ks,$vs); + preg_match_all('/<\!-- ET\_inc\_cache\[(.+?)\] -->/',$EaseTemplate3_Cache, $IncFile); + + if (is_array($IncFile[1])){ + foreach ($IncFile[1] AS $ks=>$vs) { + $this->IncList[] = $vs; + //更新inc缓存 + if (@filemtime($this->TemplateDir.$vs)>@filemtime($this->CacheDir.$this->TplID.$vs.'.'.$this->Language.'.php')){ + $this->inc($vs); + } + } + } + + @eval('echo "'.$EaseTemplate3_Cache.'";'); + $contents = ob_get_contents(); + ob_end_clean(); + return $contents; + } + }else{ + if ($Filename){ + return $this->ParseCode($this->FileList,$Filename); + }else{ + return $this->ParseCode(); + } + } + } + break; + + + //替换引擎 + default: + if($Filename){ + if ($Filename=='include_page'){ + //直接输出文件 + return $this->reader($this->FileDir[$this->ThisFile].$this->ThisFile); + }else { + return $this->ParseCode($this->FileList); + } + }else{ + return $this->ParseCode(); + } + } + } + + + /** + * 连载函数 + */ + function n(){ + //连载模板 + $this->FileList[$this->ThisFile] = $this->FileDir[$this->ThisFile]; + } + + + /** + * 输出模板内容 + * Filename 连载编译输出文件名 + */ + function r( + $Filename = '' + ){ + return $this->output($Filename); + } + + + /** + * 打印模板内容 + * Filename 连载编译输出文件名 + */ + function p( + $Filename = '' + ){ + echo $this->output($Filename); + } + + + /** + * 分析图片地址 + */ + function ImgCheck( + $content + ){ + //Check Image Dir + if($this->AutoImage==1){ + $NewFileDir = $this->FileDir[$this->ThisFile]; + + //FIX img + if(is_array($this->ImgDir)){ + foreach($this->ImgDir AS $rep){ + $rep = trim($rep); + //检测是否执行替换 + if(strrpos($content,$rep."/")){ + if(substr($rep,-1)=='/'){ + $rep = substr($rep,0,strlen($rep)-1); + } + $content = str_replace($rep.'/',$NewFileDir.$rep.'/',$content); + } + } + } + + //FIX Dir + $NewFileDirs = $NewFileDir.$NewFileDir; + if(strrpos($content,$NewFileDirs)){ + $content = str_replace($NewFileDirs,$NewFileDir,$content); + } + } + return $content; + } + + + /** + * 获得所有设置与公共变量 + */ + function Value(){ + return (is_array($this->ThisValue))?array_merge($this->ThisValue,$GLOBALS):$GLOBALS; + } + + + /** + * 清除设置 + */ + function clear(){ + $this->RunType = 'Replace'; + } + + + /** + * 静态文件写入 + */ + function htm_w( + $w_dir = '', + $w_filename = '', + $w_content = '' + ){ + + $dvs = ''; + if($w_dir && $w_filename && $w_content){ + //目录检测数量 + $w_dir_ex = explode('/',$w_dir); + $w_new_dir = ''; //处理后的写入目录 + unset($dvs,$fdk,$fdv,$w_dir_len); + foreach((array)$w_dir_ex AS $dvs){ + if(trim($dvs) && $dvs!='..'){ + $w_dir_len .= '../'; + $w_new_dir .= $dvs.'/'; + if (!@is_dir($w_new_dir)) @mkdir($w_new_dir, 0777); + } + } + + + //获得需要更改的目录数 + foreach((array)$this->FileDir AS $fdk=>$fdv){ + $w_content = str_replace($fdv,$w_dir_len.str_replace('../','',$fdv),$w_content); + } + + $this->writer($w_dir.$w_filename,$w_content); + } + } + + + /** + * 改变静态刷新时间 + */ + function htm_time($times=0){ + if((int)$times>0){ + $this->HtmTime = (int)$times; + } + } + + + /** + * 静态文件存放的绝对目录 + */ + function htm_dir($Name = ''){ + if(trim($Name)){ + $this->HtmDir = trim($Name).'/'; + } + } + + + /** + * 产生静态文件输出 + */ + function HtmCheck( + $Name = '' + ){ + $this->HtmID = md5(trim($Name)? trim($Name).'.php' : $this->Server['REQUEST_URI'].'.php' ); + //检测时间 + if(is_file($this->HtmDir.$this->HtmID) && (time() - @filemtime($this->HtmDir.$this->HtmID)<=$this->HtmTime)){ + ob_start(); + ob_implicit_flush(0); + include $this->HtmDir.$this->HtmID; + $HtmContent = ob_get_contents(); + ob_end_clean(); + return $HtmContent; + } + } + + + /** + * 打印静态内容 + */ + function htm_p( + $Name = '' + ){ + $output = $this->HtmCheck($Name); + if ($output){ + die($this->HtmCheck($Name)); + } + } + + + /** + * 输出静态内容 + */ + function htm_r( + $Name = '' + ){ + return $this->HtmCheck($Name); + } + + + + + + /** + * 解析文件 + */ + function FileName( + $name, + $id = '1' + ){ + $extdir = explode("/",$name); + $dircnt = @count($extdir) - 1; + $extdir[$dircnt] = $id.$extdir[$dircnt]; + + return $this->CacheDir.implode("_",$extdir).".".$this->Language.'.php'; + } + + + /** + * 检测引入文件 + */ + function inc_php( + $url = '' + ){ + $parse = parse_url($url); + unset($vals,$code_array); + foreach((array)explode('&',$parse['query']) AS $vals){ + $code_array .= preg_replace('/(.+)=(.+)/',"\$_GET['\\1']= \$\\1 ='\\2';",$vals); + } + return '";'.$code_array.' @include(\''.$parse['path'].'\');echo"'; + } + + + /** + * 换行函数 + * Row(换行数,换行颜色); + * Row("5,#ffffff:#e1e1e1"); + */ + function Row( + $Num = '' + ){ + $Num = trim($Num); + if($Num != ''){ + $Nums = explode(",",$Num); + $Numr = ((int)$Nums[0]>0)?(int)$Nums[0]:2; + $input = (trim($Nums[1]) == '')?'
    ':$Nums[1]; + + if(trim($Nums[1]) != ''){ + $Co = explode(":",$Nums[1]); + $OutStr = "if(\$_i%$Numr===0){\$row_count++;echo(\$row_count%2===0)?'':'';}"; + }else{ + $OutStr = "if(\$_i%$Numr===0){echo '$input';}"; + } + return '";'.$OutStr.'echo "'; + } + } + + + /** + * 间隔变色 + * Color(两组颜色代码); + * Color('#FFFFFF,#DCDCDC'); + */ + function Color( + $color = '' + ){ + if($color != ''){ + $OutStr = preg_replace("/(.+),(.+)/","_i%2===0)?'\\1':'\\2';",$color); + if(strrpos($OutStr,"%2")){ + return '";echo(\$'.$OutStr.'echo "'; + } + } + } + + + /** + * 映射图片地址 + */ + function Dirs( + $adds = '' + ){ + $adds_ary = explode(",",$adds); + if(is_array($adds_ary)){ + $this->ImgDir = (is_array($this->ImgDir))?@array_merge($adds_ary, $this->ImgDir):$adds_ary; + } + } + + + /** + * 读取函数 + * reader(文件名); + */ + function reader( + $filename + ){ + $get_fun = @get_defined_functions(); + return (in_array('file_get_contents',$get_fun['internal']))?@file_get_contents($filename):@implode("", @file($filename)); + } + + + /** + * 写入函数 + * writer(文件名,写入数据, 写入数据方式); + */ + function writer( + $filename, + $data = '', + $mode='w' + ){ + if(trim($filename)){ + $file = @fopen($filename, $mode); + $filedata = @fwrite($file, $data); + @fclose($file); + } + if(!is_file($filename)){ + die('Sorry,'.$filename.' file write in failed!'); + } + } + + + /** + * 引入模板系统 + * 察看当前使用的模板以及调试信息 + */ + function inc_list(){ + if(is_array($this->IncList)){ + $EXTS = explode("/",$this->Server['REQUEST_URI']); + $Last = count($EXTS) -1; + //处理清除工作 START + if(strrpos($EXTS[$Last],'Ease_Templatepage=Clear') && trim($EXTS[$Last]) != ''){ + $dir_name = $this->CacheDir; + if(file_exists($dir_name)){ + $handle=@opendir($dir_name); + while($tmp_file=@readdir($handle)){ + if(@file_exists($dir_name.$tmp_file)){ + @unlink($dir_name.$tmp_file); + } + } + @closedir($handle); + } + $GoURL = urldecode(preg_replace("/.+?REFERER=(.+?)!!!/","\\1",$EXTS[$Last])); + + die(''); + } + //处理清除工作 END + + $list_file = array(); + $file_nums = count($this->IncList); + $AllSize = 0; + foreach($this->IncList AS $Ks=>$Vs){ + $FSize[$Ks] = @filesize($this->TemplateDir.$Vs); + $AllSize += $FSize[$Ks]; + } + + foreach($this->IncList AS $K=>$V){ + $File_Size = @round($FSize[$K] / 1024 * 100) / 100 . 'KB'; + $Fwidth = @floor(100*$FSize[$K]/$AllSize); + $list_file[] = ""; + } + + //连接地址 + $BackURL = preg_replace("/.+\//","\\1",$this->Server['REQUEST_URI']); + $NowPAGE = 'http://'.$this->Server['HTTP_HOST'].$this->Server['SCRIPT_NAME']; + $clear_link = $NowPAGE."?Ease_Templatepage=Clear&REFERER=".urlencode($BackURL)."!!!"; + $sf13 = ' style="font-size:13px;color:#666666"'; + echo '
    ".$this->TemplateDir.$V." + ".$File_Size." +
    + +'.implode("",$list_file)."
    Include Templates (Num:'.count($this-> IncList).')'; + +if($this->RunType=='Cache'){ + echo '[Clear Cache]'; +} + +echo '
    +Cache File ID: '.substr($this->TplID,0,-1).' +Index: '.((count($this->FileList)==0)?'False':'True').' +Format: '.$this->Ext.' +Cache: '.($this->RunType=='MemCache'?'Memcache Engine':($this->RunType == 'Replace'?'Replace Engine':$this->CacheDir)).' +Template: '.$this->TemplateDir.' +
    "; + } + } + +} + +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/EaseTemplate/template.ease.php b/ThinkPHP/Extend/Vendor/EaseTemplate/template.ease.php new file mode 100644 index 0000000..9366b29 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/EaseTemplate/template.ease.php @@ -0,0 +1,42 @@ +'1', //缓存ID + 'TplType' =>'htm', //模板格式 + 'CacheDir' =>'cache', //缓存目录 + 'TemplateDir'=>'template' , //模板存放目录 + 'AutoImage' =>'on' , //自动解析图片目录开关 on表示开放 off表示关闭 + 'LangDir' =>'language' , //语言文件存放的目录 + 'Language' =>'default' , //语言的默认文件 + 'Copyright' =>'off' , //版权保护 + 'MemCache' =>'' , //Memcache服务器地址例如:127.0.0.1:11211 + ) + ){ + + parent::ETCoreStart($set); + } + +} +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplate.php b/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplate.php new file mode 100644 index 0000000..e245e38 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplate.php @@ -0,0 +1,392 @@ +assign( 'TITLE', 'TemplateDemo - Userlist' ); + * $page->assign( 'user', DB_read_all( 'select * from ris_user' ) ); + * $page->output(); + * + * Usage Example II: + * + * $data = array( + * 'TITLE' => 'TemplateDemo - Userlist', + * 'user' => DB_read_all( 'select * from ris_user' ) + * ); + * $page = new SmartTemplate( "template.html" ); + * $page->output( $data ); + * + * + * @author Philipp v. Criegern philipp@criegern.com + * @author Manuel 'EndelWar' Dalla Lana endelwar@aregar.it + * @version 1.2.1 03.07.2006 + * + * CVS ID: $Id: class.smarttemplate.php 2504 2011-12-28 07:35:29Z liu21st $ + */ + class SmartTemplate + { + /** + * Whether to store compiled php code or not (for debug purpose) + * + * @access public + */ + var $reuse_code = true; + + /** + * Directory where all templates are stored + * Can be overwritten by global configuration array $_CONFIG['template_dir'] + * + * @access public + */ + var $template_dir = 'templates/'; + + /** + * Where to store compiled templates + * Can be overwritten by global configuration array $_CONFIG['smarttemplate_compiled'] + * + * @access public + */ + var $temp_dir = 'templates_c/'; + + /** + * Temporary folder for output cache storage + * Can be overwritten by global configuration array $_CONFIG['smarttemplate_cache'] + * + * @access public + */ + var $cache_dir = 'templates_c/'; + + /** + * Default Output Cache Lifetime in Seconds + * Can be overwritten by global configuration array $_CONFIG['cache_lifetime'] + * + * @access public + */ + var $cache_lifetime = 600; + + /** + * Temporary file for output cache storage + * + * @access private + */ + var $cache_filename; + + /** + * The template filename + * + * @access private + */ + var $tpl_file; + + /** + * The compiled template filename + * + * @access private + */ + var $cpl_file; + + /** + * Template content array + * + * @access private + */ + var $data = array(); + + /** + * Parser Class + * + * @access private + */ + var $parser; + + /** + * Debugger Class + * + * @access private + */ + var $debugger; + + /** + * SmartTemplate Constructor + * + * @access public + * @param string $template_filename Template Filename + */ + function SmartTemplate ( $template_filename = '' ) + { + global $_CONFIG; + + if (!empty($_CONFIG['smarttemplate_compiled'])) + { + $this->temp_dir = $_CONFIG['smarttemplate_compiled']; + } + if (!empty($_CONFIG['smarttemplate_cache'])) + { + $this->cache_dir = $_CONFIG['smarttemplate_cache']; + } + if (is_numeric($_CONFIG['cache_lifetime'])) + { + $this->cache_lifetime = $_CONFIG['cache_lifetime']; + } + if (!empty($_CONFIG['template_dir']) && is_file($_CONFIG['template_dir'] . '/' . $template_filename)) + { + $this->template_dir = $_CONFIG['template_dir']; + } + $this->tpl_file = $template_filename; + } + + // DEPRECATED METHODS + // Methods used in older parser versions, soon will be removed + function set_templatefile ($template_filename) { $this->tpl_file = $template_filename; } + function add_value ($name, $value ) { $this->assign($name, $value); } + function add_array ($name, $value ) { $this->append($name, $value); } + + + /** + * Assign Template Content + * + * Usage Example: + * $page->assign( 'TITLE', 'My Document Title' ); + * $page->assign( 'userlist', array( + * array( 'ID' => 123, 'NAME' => 'John Doe' ), + * array( 'ID' => 124, 'NAME' => 'Jack Doe' ), + * ); + * + * @access public + * @param string $name Parameter Name + * @param mixed $value Parameter Value + * @desc Assign Template Content + */ + function assign ( $name, $value = '' ) + { + if (is_array($name)) + { + foreach ($name as $k => $v) + { + $this->data[$k] = $v; + } + } + else + { + $this->data[$name] = $value; + } + } + + + /** + * Assign Template Content + * + * Usage Example: + * $page->append( 'userlist', array( 'ID' => 123, 'NAME' => 'John Doe' ) ); + * $page->append( 'userlist', array( 'ID' => 124, 'NAME' => 'Jack Doe' ) ); + * + * @access public + * @param string $name Parameter Name + * @param mixed $value Parameter Value + * @desc Assign Template Content + */ + function append ( $name, $value ) + { + if (is_array($value)) + { + $this->data[$name][] = $value; + } + elseif (!is_array($this->data[$name])) + { + $this->data[$name] .= $value; + } + } + + + /** + * Parser Wrapper + * Returns Template Output as a String + * + * @access public + * @param array $_top Content Array + * @return string Parsed Template + * @desc Output Buffer Parser Wrapper + */ + function result ( $_top = '' ) + { + ob_start(); + $this->output( $_top ); + $result = ob_get_contents(); + ob_end_clean(); + return $result; + } + + + /** + * Execute parsed Template + * Prints Parsing Results to Standard Output + * + * @access public + * @param array $_top Content Array + * @desc Execute parsed Template + */ + function output ( $_top = '' ) + { + global $_top; + + // Make sure that folder names have a trailing '/' + if (strlen($this->template_dir) && substr($this->template_dir, -1) != '/') + { + $this->template_dir .= '/'; + } + if (strlen($this->temp_dir) && substr($this->temp_dir, -1) != '/') + { + $this->temp_dir .= '/'; + } + // Prepare Template Content + if (!is_array($_top)) + { + if (strlen($_top)) + { + $this->tpl_file = $_top; + } + $_top = $this->data; + } + $_obj = &$_top; + $_stack_cnt = 0; + $_stack[$_stack_cnt++] = $_obj; + + // Check if template is already compiled + $cpl_file_name = preg_replace('/[:\/.\\\\]/', '_', $this->tpl_file); + if (strlen($cpl_file_name) > 0) + { + $this->cpl_file = $this->temp_dir . $cpl_file_name . '.php'; + $compile_template = true; + if ($this->reuse_code) + { + if (is_file($this->cpl_file)) + { + if ($this->mtime($this->cpl_file) > $this->mtime($this->template_dir . $this->tpl_file)) + { + $compile_template = false; + } + } + } + if ($compile_template) + { + if (@include_once("class.smarttemplateparser.php")) + { + $this->parser = new SmartTemplateParser($this->template_dir . $this->tpl_file); + if (!$this->parser->compile($this->cpl_file)) + { + exit( "SmartTemplate Parser Error: " . $this->parser->error ); + } + } + else + { + exit( "SmartTemplate Error: Cannot find class.smarttemplateparser.php; check SmartTemplate installation"); + } + } + // Execute Compiled Template + include($this->cpl_file); + } + else + { + exit( "SmartTemplate Error: You must set a template file name"); + } + // Delete Global Content Array in order to allow multiple use of SmartTemplate class in one script + unset ($_top); + } + + + /** + * Debug Template + * + * @access public + * @param array $_top Content Array + * @desc Debug Template + */ + function debug ( $_top = '' ) + { + // Prepare Template Content + if (!$_top) + { + $_top = $this->data; + } + if (@include_once("class.smarttemplatedebugger.php")) + { + $this->debugger = new SmartTemplateDebugger($this->template_dir . $this->tpl_file); + $this->debugger->start($_top); + } + else + { + exit( "SmartTemplate Error: Cannot find class.smarttemplatedebugger.php; check SmartTemplate installation"); + } + } + + + /** + * Start Ouput Content Buffering + * + * Usage Example: + * $page = new SmartTemplate('template.html'); + * $page->use_cache(); + * ... + * + * @access public + * @desc Output Cache + */ + function use_cache ( $key = '' ) + { + if (empty($_POST)) + { + $this->cache_filename = $this->cache_dir . 'cache_' . md5($_SERVER['REQUEST_URI'] . serialize($key)) . '.ser'; + if (($_SERVER['HTTP_CACHE_CONTROL'] != 'no-cache') && ($_SERVER['HTTP_PRAGMA'] != 'no-cache') && @is_file($this->cache_filename)) + { + if ((time() - filemtime($this->cache_filename)) < $this->cache_lifetime) + { + readfile($this->cache_filename); + exit; + } + } + ob_start( array( &$this, 'cache_callback' ) ); + } + } + + + /** + * Output Buffer Callback Function + * + * @access private + * @param string $output + * @return string $output + */ + function cache_callback ( $output ) + { + if ($hd = @fopen($this->cache_filename, 'w')) + { + fputs($hd, $output); + fclose($hd); + } + return $output; + } + + + /** + * Determine Last Filechange Date (if File exists) + * + * @access private + * @param string $filename + * @return mixed + * @desc Determine Last Filechange Date + */ + function mtime ( $filename ) + { + if (@is_file($filename)) + { + $ret = filemtime($filename); + return $ret; + } + } + } +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplatedebugger.php b/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplatedebugger.php new file mode 100644 index 0000000..8a2ebf4 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplatedebugger.php @@ -0,0 +1,456 @@ +filename = $template_filename; + + // Load Template + if ($hd = @fopen($template_filename, "r")) + { + $this->template = fread($hd, filesize($template_filename)); + fclose($hd); + } + else + { + $this->template = "SmartTemplate Debugger Error: File not found: '$template_filename'"; + } + $this->tab[0] = ''; + for ($i=1; $i < 10; $i++) { + $this->tab[$i] = str_repeat(' ', $i); + } + } + + + /** + * Main Template Parser + * + * @param string $compiled_template_filename Compiled Template Filename + * @desc Creates Compiled PHP Template + */ + function start ( $vars ) + { + $page = $this->template; + + $page = preg_replace("/()/", "\n$1\n", $page); + $page = preg_replace("/()/", "\n$1\n", $page); + $page = preg_replace("/()/", "\n$1\n", $page); + $page = preg_replace("/()/", "\n$1\n", $page); + $page = preg_replace("/()/", "\n$1\n", $page); + + $page = $this->highlight_html($page); + + $rows = explode("\n", $page); + $page_arr = array(); + $level = 0; + $blocklvl = 0; + $rowcnt = 0; + $spancnt = 0; + $offset = 22; + $lvl_block = array(); + $lvl_row = array(); + $lvl_typ = array(); + foreach ($rows as $row) + { + if ($row = trim($row)) + { + $closespan = false; + if (substr($row, $offset, 12) == '<!-- END ') + { + if ($level < 1) + { + $level++; + $error[$rowcnt] = "END Without BEGIN"; + } + elseif ($lvl_typ[$level] != 'BEGIN') + { + $error[$lvl_row[$level]] = "IF without ENDIF"; + $error[$rowcnt] = "END Without BEGIN"; + } + $blocklvl--; + $level--; + $closespan = true; + } + if (substr($row, $offset, 14) == '<!-- ENDIF ') + { + if ($level < 1) + { + $level++; + $error[$rowcnt] = "ENDIF Without IF"; + } + elseif ($lvl_typ[$level] != 'IF') + { + $error[$lvl_row[$level]] = "BEGIN without END"; + $error[$rowcnt] = "ENDIF Without IF"; + } + $closespan = true; + $level--; + } + if ($closespan) + { + $page_arr[$rowcnt-1] .= ''; + } + $this_row = $this->tab[$level] . $row; + if (substr($row, $offset, 12) == '<!-- ELSE') + { + if ($level < 1) + { + $error[$rowcnt] = "ELSE Without IF"; + } + elseif ($lvl_typ[$level] != 'IF') + { + $error[$rowcnt] = "ELSE Without IF"; + } + else + { + $this_row = $this->tab[$level-1] . $row; + } + } + if (substr($row, $offset, 14) == '<!-- BEGIN ') + { + if ($blocklvl == 0) + { + if ($lp = strpos($row, '-->')) + { + if ($blockname = trim(substr($row, $offset + 14, $lp -$offset -14))) + { + if ($nr = count($vars[$blockname])) + { + $this_row .= $this->toggleview("$nr Entries"); + } + else + { + $this_row .= $this->toggleview("Emtpy"); + } + } + } + } + else + { + $this_row .= $this->toggleview('['); + } + $blocklvl++; + $level++; + $lvl_row[$level] = $rowcnt; + $lvl_typ[$level] = 'BEGIN'; + } + elseif (substr($row, $offset, 11) == '<!-- IF ') + { + $level++; + $lvl_row[$level] = $rowcnt; + $lvl_typ[$level] = 'IF'; + $this_row .= $this->toggleview(); + } + $page_arr[] = $this_row; + $lvl_block[$rowcnt] = $blocklvl; + $rowcnt++; + } + } + if ($level > 0) + { + $error[$lvl_row[$level]] = "Block not closed"; + } + + $page = join("\n", $page_arr); + $rows = explode("\n", $page); + $cnt = count($rows); + + for ($i = 0; $i < $cnt; $i++) + { + // Add Errortext + if (isset($error)) + { + if ($err = $error[$i]) + { + $rows[$i] = '' . $rows[$i] . ' ERROR: ' . $err . '!'; + } + } + + // Replace Scalars + if (preg_match_all('/{([a-zA-Z0-9_. &;]+)}/', $rows[$i], $var)) + { + foreach ($var[1] as $tag) + { + $fulltag = $tag; + if ($delim = strpos($tag, ' > ')) + { + $tag = substr($tag, 0, $delim); + } + if (substr($tag, 0, 4) == 'top.') + { + $title = $this->tip($vars[substr($tag, 4)]); + } + elseif ($lvl_block[$i] == 0) + { + $title = $this->tip($vars[$tag]); + } + else + { + $title = '[BLOCK?]'; + } + $code = '{' . $fulltag . '}'; + $rows[$i] = str_replace('{'.$fulltag.'}', $code, $rows[$i]); + } + } + + // Replace Extensions + if (preg_match_all('/{([a-zA-Z0-9_]+):([^}]*)}/', $rows[$i], $var)) + { + foreach ($var[2] as $tmpcnt => $tag) + { + $fulltag = $tag; + if ($delim = strpos($tag, ' > ')) + { + $tag = substr($tag, 0, $delim); + } + if (strpos($tag, ',')) + { + list($tag, $addparam) = explode(',', $tag, 2); + } + $extension = $var[1][$tmpcnt]; + + if (substr($tag, 0, 4) == 'top.') + { + $title = $this->tip($vars[substr($tag, 4)]); + } + elseif ($lvl_block[$i] == 0) + { + $title = $this->tip($vars[$tag]); + } + else + { + $title = '[BLOCK?]'; + } + $code = '{' . $extension . ':' . $fulltag . '}'; + $rows[$i] = str_replace('{'.$extension . ':' . $fulltag .'}', $code, $rows[$i]); + } + } + + // 'IF nnn' Blocks + if (preg_match_all('/<!-- IF ([a-zA-Z0-9_.]+) -->/', $rows[$i], $var)) + { + foreach ($var[1] as $tag) + { + if (substr($tag, 0, 4) == 'top.') + { + $title = $this->tip($vars[substr($tag, 4)]); + } + elseif ($lvl_block[$i] == 0) + { + $title = $this->tip($vars[$tag]); + } + else + { + $title = '[BLOCK?]'; + } + $code = '<!-- IF ' . $tag . ' -->'; + $rows[$i] = str_replace("<!-- IF $tag -->", $code, $rows[$i]); + if ($title == '[NULL]') + { + $rows[$i] = str_replace('Hide', 'Show', $rows[$i]); + $rows[$i] = str_replace('block', 'none', $rows[$i]); + } + } + } + } + $page = join("
    ", $rows); + + // Print Header + echo ''; + + // Print Index + echo ''; + echo 'SmartTemplate Debugger
    '; + echo '
  • PHP-Script: ' . $_SERVER['PATH_TRANSLATED'] . '
  • Template: ' . $this->filename . '

  • '; + echo '
  • Template
  • '; + echo '
  • Compiled Template
  • '; + echo '
  • Data
  • '; + echo '

    '; + + // Print Template + echo '
    Template: [
    Hide Ouptut]
    '; + echo '
    ';
    +			echo $page;
    +			echo '
    '; + + // Print Compiled Template + if (@include_once ("class.smarttemplateparser.php")) + { + $parser = new SmartTemplateParser($this->filename); + $compiled = $parser->compile(); + echo '

    Compiled Template: [
    Hide Ouptut]
    '; + echo '
    ';
    +				highlight_string($compiled);
    +				echo '
    '; + } + else + { + exit( "SmartTemplate Error: Cannot find class.smarttemplateparser.php; check SmartTemplate installation"); + } + + // Print Data + echo '

    Data: [
    Hide Ouptut]
    '; + echo '
    ';
    +			echo $this->vardump($vars);
    +			echo '
    '; + } + + + /** + * Insert Hide/Show Layer Switch + * + * @param string $suffix Additional Text + * @desc Insert Hide/Show Layer Switch + */ + function toggleview ( $suffix = '') + { + global $spancnt; + + $spancnt++; + if ($suffix) + { + $suffix .= ':'; + } + $ret = '[' . $suffix . 'Hide Block]'; + return $ret; + } + + + /** + * Create Title Text + * + * @param string $value Content + * @desc Create Title Text + */ + function tip ( $value ) + { + if (empty($value)) + { + return "[NULL]"; + } + else + { + $ret = htmlentities(substr($value,0,200)); + return $ret; + } + } + + + /** + * Recursive Variable Display Output + * + * @param mixed $var Content + * @param int $depth Incremented Indent Counter for Recursive Calls + * @return string Variable Content + * @access private + * @desc Recursive Variable Display Output + */ + function vardump($var, $depth = 0) + { + if (is_array($var)) + { + $result = "Array (" . count($var) . ")
    "; + foreach(array_keys($var) as $key) + { + $result .= $this->tab[$depth] . "$key: " . $this->vardump($var[$key], $depth+1); + } + return $result; + } + else + { + $ret = htmlentities($var) . "
    "; + return $ret; + } + } + + + /** + * Splits Template-Style Variable Names into an Array-Name/Key-Name Components + * + * @param string $tag Variale Name used in Template + * @return array Array Name, Key Name + * @access private + * @desc Splits Template-Style Variable Names into an Array-Name/Key-Name Components + */ + function var_name($tag) + { + $parent_level = 0; + while (substr($tag, 0, 7) == 'parent.') + { + $tag = substr($tag, 7); + $parent_level++; + } + if (substr($tag, 0, 4) == 'top.') + { + $ret = array('_stack[0]', substr($tag,4)); + return $ret; + } + elseif ($parent_level) + { + $ret = array('_stack[$_stack_cnt-'.$parent_level.']', $tag); + return $ret; + } + else + { + $ret = array('_obj', $tag); + return $ret; + } + } + + + /** + * Highlight HTML Source + * + * @param string $code HTML Source + * @return string Hightlighte HTML Source + * @access private + * @desc Highlight HTML Source + */ + function highlight_html ( $code ) + { + $code = htmlentities($code); + $code = preg_replace('/([a-zA-Z_]+)=/', '$1=', $code); + $code = preg_replace('/(<[\/a-zA-Z0-9&;]+)/', '$1', $code); + $code = str_replace('<!--', '<!--', $code); + $code = str_replace('-->', '-->', $code); + $code = preg_replace('/[\r\n]+/', "\n", $code); + return $code; + } + } +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplateparser.php b/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplateparser.php new file mode 100644 index 0000000..e16d2cf --- /dev/null +++ b/ThinkPHP/Extend/Vendor/SmartTemplate/class.smarttemplateparser.php @@ -0,0 +1,365 @@ +template = fread($hd, filesize($template_filename)); + } + else + { + $this->template = "SmartTemplate Parser Error: File size is zero byte: '$template_filename'"; + } + fclose($hd); + // Extract the name of the template directory + $this->template_dir = dirname($template_filename); + } + else + { + $this->template = "SmartTemplate Parser Error: File not found: '$template_filename'"; + } + } + + /** + * Main Template Parser + * + * @param string $compiled_template_filename Compiled Template Filename + * @desc Creates Compiled PHP Template + */ + function compile( $compiled_template_filename = '' ) + { + if (empty($this->template)) + { + return; + } + /* Quick hack to allow subtemplates */ + if(eregi("/', $this->template, $tvar); + foreach($tvar[1] as $subfile) + { + if(file_exists($this->template_dir . "/$subfile")) + { + $subst = implode('',file($this->template_dir . "/$subfile")); + } + else + { + $subst = 'SmartTemplate Parser Error: Subtemplate not found: \''.$subfile.'\''; + } + $this->template = str_replace("", $subst, $this->template); + } + } + } + // END, ELSE Blocks + $page = preg_replace("//", "", $this->template); + $page = preg_replace("//", "", $page); + $page = str_replace("", "", $page); + + // 'BEGIN - END' Blocks + if (preg_match_all('//', $page, $var)) + { + foreach ($var[1] as $tag) + { + list($parent, $block) = $this->var_name($tag); + $code = "\$$parent"."['$block']));\n" + . "\$_tmp_arr_keys=array_keys(\$$parent"."['$block']);\n" + . "if (\$_tmp_arr_keys[0]!='0')\n" + . "\$$parent"."['$block']=array(0=>\$$parent"."['$block']);\n" + . "\$_stack[\$_stack_cnt++]=\$_obj;\n" + . "foreach (\$$parent"."['$block'] as \$rowcnt=>\$$block) {\n" + . "\$$block"."['ROWCNT']=\$rowcnt;\n" + . "\$$block"."['ALTROW']=\$rowcnt%2;\n" + . "\$$block"."['ROWBIT']=\$rowcnt%2;\n" + . "\$_obj=&\$$block;\n?>"; + $page = str_replace("", $code, $page); + } + } + + // 'IF nnn=mmm' Blocks + if (preg_match_all('//', $page, $var)) + { + foreach ($var[2] as $cnt => $tag) + { + list($parent, $block) = $this->var_name($tag); + $cmp = $var[3][$cnt]; + $val = $var[4][$cnt]; + $else = ($var[1][$cnt] == 'ELSE') ? '} else' : ''; + if ($cmp == '=') + { + $cmp = '=='; + } + + if (preg_match('/"([^"]*)"/',$val,$matches)) + { + $code = ""; + } + elseif (preg_match('/([^"]*)/',$val,$matches)) + { + list($parent_right, $block_right) = $this->var_name($matches[1]); + $code = ""; + } + + $page = str_replace($var[0][$cnt], $code, $page); + } + } + + // 'IF nnn' Blocks + if (preg_match_all('//', $page, $var)) + { + foreach ($var[2] as $cnt => $tag) + { + $else = ($var[1][$cnt] == 'ELSE') ? '} else' : ''; + list($parent, $block) = $this->var_name($tag); + $code = ""; + $page = str_replace($var[0][$cnt], $code, $page); + } + } + + // Replace Scalars + if (preg_match_all('/{([a-zA-Z0-9_. >]+)}/', $page, $var)) + { + foreach ($var[1] as $fulltag) + { + // Determin Command (echo / $obj[n]=) + list($cmd, $tag) = $this->cmd_name($fulltag); + + list($block, $skalar) = $this->var_name($tag); + $code = "\n"; + $page = str_replace('{'.$fulltag.'}', $code, $page); + } + } + + + // ROSI Special: Replace Translations + if (preg_match_all('/<"([a-zA-Z0-9_.]+)">/', $page, $var)) + { + foreach ($var[1] as $tag) + { + list($block, $skalar) = $this->var_name($tag); + $code = "\n"; + $page = str_replace('<"'.$tag.'">', $code, $page); + } + } + + + // Include Extensions + $header = ''; + if (preg_match_all('/{([a-zA-Z0-9_]+):([^}]*)}/', $page, $var)) + { + foreach ($var[2] as $cnt => $tag) + { + // Determin Command (echo / $obj[n]=) + list($cmd, $tag) = $this->cmd_name($tag); + + $extension = $var[1][$cnt]; + if (!isset($this->extension_tagged[$extension])) + { + $header .= "include_once \"smarttemplate_extensions/smarttemplate_extension_$extension.php\";\n"; + $this->extension_tagged[$extension] = true; + } + if (!strlen($tag)) + { + $code = "\n"; + } + elseif (substr($tag, 0, 1) == '"') + { + $code = "\n"; + } + elseif (strpos($tag, ',')) + { + list($tag, $addparam) = explode(',', $tag, 2); + list($block, $skalar) = $this->var_name($tag); + if (preg_match('/^([a-zA-Z_]+)/', $addparam, $match)) + { + $nexttag = $match[1]; + list($nextblock, $nextskalar) = $this->var_name($nexttag); + $addparam = substr($addparam, strlen($nexttag)); + $code = "\n"; + } + else + { + $code = "\n"; + } + } + else + { + list($block, $skalar) = $this->var_name($tag); + $code = "\n"; + } + $page = str_replace($var[0][$cnt], $code, $page); + } + } + + // Add Include Header + if (isset($header) && !empty($header)) + { + $page = "$page"; + } + + // Store Code to Temp Dir + if (strlen($compiled_template_filename)) + { + if ($hd = fopen($compiled_template_filename, "w")) + { + fwrite($hd, $page); + fclose($hd); + return true; + } + else + { + $this->error = "Could not write compiled file."; + return false; + } + } + else + { + return $page; + } + } + + + /** + * Splits Template-Style Variable Names into an Array-Name/Key-Name Components + * {example} : array( "_obj", "example" ) -> $_obj['example'] + * {example.value} : array( "_obj['example']", "value" ) -> $_obj['example']['value'] + * {example.0.value} : array( "_obj['example'][0]", "value" ) -> $_obj['example'][0]['value'] + * {top.example} : array( "_stack[0]", "example" ) -> $_stack[0]['example'] + * {parent.example} : array( "_stack[$_stack_cnt-1]", "example" ) -> $_stack[$_stack_cnt-1]['example'] + * {parent.parent.example} : array( "_stack[$_stack_cnt-2]", "example" ) -> $_stack[$_stack_cnt-2]['example'] + * + * @param string $tag Variale Name used in Template + * @return array Array Name, Key Name + * @access private + * @desc Splits Template-Style Variable Names into an Array-Name/Key-Name Components + */ + function var_name($tag) + { + $parent_level = 0; + while (substr($tag, 0, 7) == 'parent.') + { + $tag = substr($tag, 7); + $parent_level++; + } + if (substr($tag, 0, 4) == 'top.') + { + $obj = '_stack[0]'; + $tag = substr($tag,4); + } + elseif ($parent_level) + { + $obj = '_stack[$_stack_cnt-'.$parent_level.']'; + } + else + { + $obj = '_obj'; + } + while (is_int(strpos($tag, '.'))) + { + list($parent, $tag) = explode('.', $tag, 2); + if (is_numeric($parent)) + { + $obj .= "[" . $parent . "]"; + } + else + { + $obj .= "['" . $parent . "']"; + } + } + $ret = array($obj, $tag); + return $ret; + } + + + /** + * Determine Template Command from Variable Name + * {variable} : array( "echo", "variable" ) -> echo $_obj['variable'] + * {variable > new_name} : array( "_obj['new_name']=", "variable" ) -> $_obj['new_name']= $_obj['variable'] + * + * @param string $tag Variale Name used in Template + * @return array Array Command, Variable + * @access private + * @desc Determine Template Command from Variable Name + */ + function cmd_name($tag) + { + if (preg_match('/^(.+) > ([a-zA-Z0-9_.]+)$/', $tag, $tagvar)) + { + $tag = $tagvar[1]; + list($newblock, $newskalar) = $this->var_name($tagvar[2]); + $cmd = "\$$newblock"."['$newskalar']="; + } + else + { + $cmd = "echo"; + } + $ret = array($cmd, $tag); + return $ret; + } + + /** + * @return int Number of subtemplate included + * @access private + * @desc Count number of subtemplates included in current template + */ + function count_subtemplates() + { + preg_match_all('//', $this->template, $tvar); + $count_subtemplates = count($tvar[1]); + $ret = intval($count_subtemplates); + return $ret; + } + } +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/Smarty/Smarty.class.php b/ThinkPHP/Extend/Vendor/Smarty/Smarty.class.php new file mode 100644 index 0000000..f2d3408 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Smarty/Smarty.class.php @@ -0,0 +1,1473 @@ + +* @author Uwe Tews +* @author Rodney Rehm +* @package Smarty +* @version 3.1.6 +*/ + +/** +* define shorthand directory separator constant +*/ +if (!defined('DS')) { + define('DS', DIRECTORY_SEPARATOR); +} + +/** +* set SMARTY_DIR to absolute path to Smarty library files. +* Sets SMARTY_DIR only if user application has not already defined it. +*/ +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DS); +} + +/** +* set SMARTY_SYSPLUGINS_DIR to absolute path to Smarty internal plugins. +* Sets SMARTY_SYSPLUGINS_DIR only if user application has not already defined it. +*/ +if (!defined('SMARTY_SYSPLUGINS_DIR')) { + define('SMARTY_SYSPLUGINS_DIR', SMARTY_DIR . 'sysplugins' . DS); +} +if (!defined('SMARTY_PLUGINS_DIR')) { + define('SMARTY_PLUGINS_DIR', SMARTY_DIR . 'plugins' . DS); +} +if (!defined('SMARTY_MBSTRING')) { + define('SMARTY_MBSTRING', function_exists('mb_strlen')); +} +if (!defined('SMARTY_RESOURCE_CHAR_SET')) { + // UTF-8 can only be done properly when mbstring is available! + define('SMARTY_RESOURCE_CHAR_SET', SMARTY_MBSTRING ? 'UTF-8' : 'ISO-8859-1'); +} +if (!defined('SMARTY_RESOURCE_DATE_FORMAT')) { + define('SMARTY_RESOURCE_DATE_FORMAT', '%b %e, %Y'); +} + +/** +* register the class autoloader +*/ +if (!defined('SMARTY_SPL_AUTOLOAD')) { + define('SMARTY_SPL_AUTOLOAD', 0); +} + +if (SMARTY_SPL_AUTOLOAD && set_include_path(get_include_path() . PATH_SEPARATOR . SMARTY_SYSPLUGINS_DIR) !== false) { + $registeredAutoLoadFunctions = spl_autoload_functions(); + if (!isset($registeredAutoLoadFunctions['spl_autoload'])) { + spl_autoload_register(); + } +} else { + spl_autoload_register('smartyAutoload'); +} + +/** +* Load always needed external class files +*/ +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_data.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_templatebase.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_template.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_resource.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_resource_file.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_cacheresource.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_cacheresource_file.php'; + +/** +* This is the main Smarty class +* @package Smarty +*/ +class Smarty extends Smarty_Internal_TemplateBase { + + /**#@+ + * constant definitions + */ + + /** + * smarty version + */ + const SMARTY_VERSION = 'Smarty-3.1.6'; + + /** + * define variable scopes + */ + const SCOPE_LOCAL = 0; + const SCOPE_PARENT = 1; + const SCOPE_ROOT = 2; + const SCOPE_GLOBAL = 3; + /** + * define caching modes + */ + const CACHING_OFF = 0; + const CACHING_LIFETIME_CURRENT = 1; + const CACHING_LIFETIME_SAVED = 2; + /** + * define compile check modes + */ + const COMPILECHECK_OFF = 0; + const COMPILECHECK_ON = 1; + const COMPILECHECK_CACHEMISS = 2; + /** + * modes for handling of "" tags in templates. + */ + const PHP_PASSTHRU = 0; //-> print tags as plain text + const PHP_QUOTE = 1; //-> escape tags as entities + const PHP_REMOVE = 2; //-> escape tags as entities + const PHP_ALLOW = 3; //-> escape tags as entities + /** + * filter types + */ + const FILTER_POST = 'post'; + const FILTER_PRE = 'pre'; + const FILTER_OUTPUT = 'output'; + const FILTER_VARIABLE = 'variable'; + /** + * plugin types + */ + const PLUGIN_FUNCTION = 'function'; + const PLUGIN_BLOCK = 'block'; + const PLUGIN_COMPILER = 'compiler'; + const PLUGIN_MODIFIER = 'modifier'; + const PLUGIN_MODIFIERCOMPILER = 'modifiercompiler'; + + /**#@-*/ + + /** + * assigned global tpl vars + */ + public static $global_tpl_vars = array(); + + /** + * error handler returned by set_error_hanlder() in Smarty::muteExpectedErrors() + */ + public static $_previous_error_handler = null; + /** + * contains directories outside of SMARTY_DIR that are to be muted by muteExpectedErrors() + */ + public static $_muted_directories = array(); + + /**#@+ + * variables + */ + + /** + * auto literal on delimiters with whitspace + * @var boolean + */ + public $auto_literal = true; + /** + * display error on not assigned variables + * @var boolean + */ + public $error_unassigned = false; + /** + * look up relative filepaths in include_path + * @var boolean + */ + public $use_include_path = false; + /** + * template directory + * @var array + */ + private $template_dir = array(); + /** + * joined template directory string used in cache keys + * @var string + */ + public $joined_template_dir = null; + /** + * joined config directory string used in cache keys + * @var string + */ + public $joined_config_dir = null; + /** + * default template handler + * @var callable + */ + public $default_template_handler_func = null; + /** + * default config handler + * @var callable + */ + public $default_config_handler_func = null; + /** + * default plugin handler + * @var callable + */ + public $default_plugin_handler_func = null; + /** + * compile directory + * @var string + */ + private $compile_dir = null; + /** + * plugins directory + * @var array + */ + private $plugins_dir = array(); + /** + * cache directory + * @var string + */ + private $cache_dir = null; + /** + * config directory + * @var array + */ + private $config_dir = array(); + /** + * force template compiling? + * @var boolean + */ + public $force_compile = false; + /** + * check template for modifications? + * @var boolean + */ + public $compile_check = true; + /** + * use sub dirs for compiled/cached files? + * @var boolean + */ + public $use_sub_dirs = false; + /** + * allow ambiguous resources (that are made unique by the resource handler) + * @var boolean + */ + public $allow_ambiguous_resources = false; + /** + * caching enabled + * @var boolean + */ + public $caching = false; + /** + * merge compiled includes + * @var boolean + */ + public $merge_compiled_includes = false; + /** + * cache lifetime in seconds + * @var integer + */ + public $cache_lifetime = 3600; + /** + * force cache file creation + * @var boolean + */ + public $force_cache = false; + /** + * Set this if you want different sets of cache files for the same + * templates. + * + * @var string + */ + public $cache_id = null; + /** + * Set this if you want different sets of compiled files for the same + * templates. + * + * @var string + */ + public $compile_id = null; + /** + * template left-delimiter + * @var string + */ + public $left_delimiter = "{"; + /** + * template right-delimiter + * @var string + */ + public $right_delimiter = "}"; + /**#@+ + * security + */ + /** + * class name + * + * This should be instance of Smarty_Security. + * + * @var string + * @see Smarty_Security + */ + public $security_class = 'Smarty_Security'; + /** + * implementation of security class + * + * @var Smarty_Security + */ + public $security_policy = null; + /** + * controls handling of PHP-blocks + * + * @var integer + */ + public $php_handling = self::PHP_PASSTHRU; + /** + * controls if the php template file resource is allowed + * + * @var bool + */ + public $allow_php_templates = false; + /** + * Should compiled-templates be prevented from being called directly? + * + * {@internal + * Currently used by Smarty_Internal_Template only. + * }} + * + * @var boolean + */ + public $direct_access_security = true; + /**#@-*/ + /** + * debug mode + * + * Setting this to true enables the debug-console. + * + * @var boolean + */ + public $debugging = false; + /** + * This determines if debugging is enable-able from the browser. + *
      + *
    • NONE => no debugging control allowed
    • + *
    • URL => enable debugging when SMARTY_DEBUG is found in the URL.
    • + *
    + * @var string + */ + public $debugging_ctrl = 'NONE'; + /** + * Name of debugging URL-param. + * + * Only used when $debugging_ctrl is set to 'URL'. + * The name of the URL-parameter that activates debugging. + * + * @var type + */ + public $smarty_debug_id = 'SMARTY_DEBUG'; + /** + * Path of debug template. + * @var string + */ + public $debug_tpl = null; + /** + * When set, smarty uses this value as error_reporting-level. + * @var int + */ + public $error_reporting = null; + /** + * Internal flag for getTags() + * @var boolean + */ + public $get_used_tags = false; + + /**#@+ + * config var settings + */ + + /** + * Controls whether variables with the same name overwrite each other. + * @var boolean + */ + public $config_overwrite = true; + /** + * Controls whether config values of on/true/yes and off/false/no get converted to boolean. + * @var boolean + */ + public $config_booleanize = true; + /** + * Controls whether hidden config sections/vars are read from the file. + * @var boolean + */ + public $config_read_hidden = false; + + /**#@-*/ + + /**#@+ + * resource locking + */ + + /** + * locking concurrent compiles + * @var boolean + */ + public $compile_locking = true; + /** + * Controls whether cache resources should emply locking mechanism + * @var boolean + */ + public $cache_locking = false; + /** + * seconds to wait for acquiring a lock before ignoring the write lock + * @var float + */ + public $locking_timeout = 10; + + /**#@-*/ + + /** + * global template functions + * @var array + */ + public $template_functions = array(); + /** + * resource type used if none given + * + * Must be an valid key of $registered_resources. + * @var string + */ + public $default_resource_type = 'file'; + /** + * caching type + * + * Must be an element of $cache_resource_types. + * + * @var string + */ + public $caching_type = 'file'; + /** + * internal config properties + * @var array + */ + public $properties = array(); + /** + * config type + * @var string + */ + public $default_config_type = 'file'; + /** + * cached template objects + * @var array + */ + public $template_objects = array(); + /** + * check If-Modified-Since headers + * @var boolean + */ + public $cache_modified_check = false; + /** + * registered plugins + * @var array + */ + public $registered_plugins = array(); + /** + * plugin search order + * @var array + */ + public $plugin_search_order = array('function', 'block', 'compiler', 'class'); + /** + * registered objects + * @var array + */ + public $registered_objects = array(); + /** + * registered classes + * @var array + */ + public $registered_classes = array(); + /** + * registered filters + * @var array + */ + public $registered_filters = array(); + /** + * registered resources + * @var array + */ + public $registered_resources = array(); + /** + * resource handler cache + * @var array + */ + public $_resource_handlers = array(); + /** + * registered cache resources + * @var array + */ + public $registered_cache_resources = array(); + /** + * cache resource handler cache + * @var array + */ + public $_cacheresource_handlers = array(); + /** + * autoload filter + * @var array + */ + public $autoload_filters = array(); + /** + * default modifier + * @var array + */ + public $default_modifiers = array(); + /** + * autoescape variable output + * @var boolean + */ + public $escape_html = false; + /** + * global internal smarty vars + * @var array + */ + public static $_smarty_vars = array(); + /** + * start time for execution time calculation + * @var int + */ + public $start_time = 0; + /** + * default file permissions + * @var int + */ + public $_file_perms = 0644; + /** + * default dir permissions + * @var int + */ + public $_dir_perms = 0771; + /** + * block tag hierarchy + * @var array + */ + public $_tag_stack = array(); + /** + * self pointer to Smarty object + * @var Smarty + */ + public $smarty; + /** + * required by the compiler for BC + * @var string + */ + public $_current_file = null; + /** + * internal flag to enable parser debugging + * @var bool + */ + public $_parserdebug = false; + /** + * Saved parameter of merged templates during compilation + * + * @var array + */ + public $merged_templates_func = array(); + /**#@-*/ + + /** + * Initialize new Smarty object + * + */ + public function __construct() + { + // selfpointer needed by some other class methods + $this->smarty = $this; + if (is_callable('mb_internal_encoding')) { + mb_internal_encoding(SMARTY_RESOURCE_CHAR_SET); + } + $this->start_time = microtime(true); + // set default dirs + $this->setTemplateDir('.' . DS . 'templates' . DS) + ->setCompileDir('.' . DS . 'templates_c' . DS) + ->setPluginsDir(SMARTY_PLUGINS_DIR) + ->setCacheDir('.' . DS . 'cache' . DS) + ->setConfigDir('.' . DS . 'configs' . DS); + + $this->debug_tpl = 'file:' . dirname(__FILE__) . '/debug.tpl'; + if (isset($_SERVER['SCRIPT_NAME'])) { + $this->assignGlobal('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']); + } + } + + + /** + * Class destructor + */ + public function __destruct() + { + // intentionally left blank + } + + /** + * <> set selfpointer on cloned object + */ + public function __clone() + { + $this->smarty = $this; + } + + + /** + * <> Generic getter. + * + * Calls the appropriate getter function. + * Issues an E_USER_NOTICE if no valid getter is found. + * + * @param string $name property name + * @return mixed + */ + public function __get($name) + { + $allowed = array( + 'template_dir' => 'getTemplateDir', + 'config_dir' => 'getConfigDir', + 'plugins_dir' => 'getPluginsDir', + 'compile_dir' => 'getCompileDir', + 'cache_dir' => 'getCacheDir', + ); + + if (isset($allowed[$name])) { + return $this->{$allowed[$name]}(); + } else { + trigger_error('Undefined property: '. get_class($this) .'::$'. $name, E_USER_NOTICE); + } + } + + /** + * <> Generic setter. + * + * Calls the appropriate setter function. + * Issues an E_USER_NOTICE if no valid setter is found. + * + * @param string $name property name + * @param mixed $value parameter passed to setter + */ + public function __set($name, $value) + { + $allowed = array( + 'template_dir' => 'setTemplateDir', + 'config_dir' => 'setConfigDir', + 'plugins_dir' => 'setPluginsDir', + 'compile_dir' => 'setCompileDir', + 'cache_dir' => 'setCacheDir', + ); + + if (isset($allowed[$name])) { + $this->{$allowed[$name]}($value); + } else { + trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE); + } + } + + /** + * Check if a template resource exists + * + * @param string $resource_name template name + * @return boolean status + */ + public function templateExists($resource_name) + { + // create template object + $save = $this->template_objects; + $tpl = new $this->template_class($resource_name, $this); + // check if it does exists + $result = $tpl->source->exists; + $this->template_objects = $save; + return $result; + } + + /** + * Returns a single or all global variables + * + * @param object $smarty + * @param string $varname variable name or null + * @return string variable value or or array of variables + */ + public function getGlobal($varname = null) + { + if (isset($varname)) { + if (isset(self::$global_tpl_vars[$varname])) { + return self::$global_tpl_vars[$varname]->value; + } else { + return ''; + } + } else { + $_result = array(); + foreach (self::$global_tpl_vars AS $key => $var) { + $_result[$key] = $var->value; + } + return $_result; + } + } + + /** + * Empty cache folder + * + * @param integer $exp_time expiration time + * @param string $type resource type + * @return integer number of cache files deleted + */ + function clearAllCache($exp_time = null, $type = null) + { + // load cache resource and call clearAll + $_cache_resource = Smarty_CacheResource::load($this, $type); + Smarty_CacheResource::invalidLoadedCache($this); + return $_cache_resource->clearAll($this, $exp_time); + } + + /** + * Empty cache for a specific template + * + * @param string $template_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer $exp_time expiration time + * @param string $type resource type + * @return integer number of cache files deleted + */ + public function clearCache($template_name, $cache_id = null, $compile_id = null, $exp_time = null, $type = null) + { + // load cache resource and call clear + $_cache_resource = Smarty_CacheResource::load($this, $type); + Smarty_CacheResource::invalidLoadedCache($this); + return $_cache_resource->clear($this, $template_name, $cache_id, $compile_id, $exp_time); + } + + /** + * Loads security class and enables security + * + * @param string|Smarty_Security $security_class if a string is used, it must be class-name + * @return Smarty current Smarty instance for chaining + * @throws SmartyException when an invalid class name is provided + */ + public function enableSecurity($security_class = null) + { + if ($security_class instanceof Smarty_Security) { + $this->security_policy = $security_class; + return $this; + } elseif (is_object($security_class)) { + throw new SmartyException("Class '" . get_class($security_class) . "' must extend Smarty_Security."); + } + if ($security_class == null) { + $security_class = $this->security_class; + } + if (!class_exists($security_class)) { + throw new SmartyException("Security class '$security_class' is not defined"); + } elseif ($security_class !== 'Smarty_Security' && !is_subclass_of($security_class, 'Smarty_Security')) { + throw new SmartyException("Class '$security_class' must extend Smarty_Security."); + } else { + $this->security_policy = new $security_class($this); + } + + return $this; + } + + /** + * Disable security + * @return Smarty current Smarty instance for chaining + */ + public function disableSecurity() + { + $this->security_policy = null; + + return $this; + } + + /** + * Set template directory + * + * @param string|array $template_dir directory(s) of template sources + * @return Smarty current Smarty instance for chaining + */ + public function setTemplateDir($template_dir) + { + $this->template_dir = array(); + foreach ((array) $template_dir as $k => $v) { + $this->template_dir[$k] = rtrim($v, '/\\') . DS; + } + + $this->joined_template_dir = join(DIRECTORY_SEPARATOR, $this->template_dir); + return $this; + } + + /** + * Add template directory(s) + * + * @param string|array $template_dir directory(s) of template sources + * @param string $key of the array element to assign the template dir to + * @return Smarty current Smarty instance for chaining + * @throws SmartyException when the given template directory is not valid + */ + public function addTemplateDir($template_dir, $key=null) + { + // make sure we're dealing with an array + $this->template_dir = (array) $this->template_dir; + + if (is_array($template_dir)) { + foreach ($template_dir as $k => $v) { + if (is_int($k)) { + // indexes are not merged but appended + $this->template_dir[] = rtrim($v, '/\\') . DS; + } else { + // string indexes are overridden + $this->template_dir[$k] = rtrim($v, '/\\') . DS; + } + } + } elseif ($key !== null) { + // override directory at specified index + $this->template_dir[$key] = rtrim($template_dir, '/\\') . DS; + } else { + // append new directory + $this->template_dir[] = rtrim($template_dir, '/\\') . DS; + } + $this->joined_template_dir = join(DIRECTORY_SEPARATOR, $this->template_dir); + return $this; + } + + /** + * Get template directories + * + * @param mixed index of directory to get, null to get all + * @return array|string list of template directories, or directory of $index + */ + public function getTemplateDir($index=null) + { + if ($index !== null) { + return isset($this->template_dir[$index]) ? $this->template_dir[$index] : null; + } + + return (array)$this->template_dir; + } + + /** + * Set config directory + * + * @param string|array $template_dir directory(s) of configuration sources + * @return Smarty current Smarty instance for chaining + */ + public function setConfigDir($config_dir) + { + $this->config_dir = array(); + foreach ((array) $config_dir as $k => $v) { + $this->config_dir[$k] = rtrim($v, '/\\') . DS; + } + + $this->joined_config_dir = join(DIRECTORY_SEPARATOR, $this->config_dir); + return $this; + } + + /** + * Add config directory(s) + * + * @param string|array $config_dir directory(s) of config sources + * @param string key of the array element to assign the config dir to + * @return Smarty current Smarty instance for chaining + */ + public function addConfigDir($config_dir, $key=null) + { + // make sure we're dealing with an array + $this->config_dir = (array) $this->config_dir; + + if (is_array($config_dir)) { + foreach ($config_dir as $k => $v) { + if (is_int($k)) { + // indexes are not merged but appended + $this->config_dir[] = rtrim($v, '/\\') . DS; + } else { + // string indexes are overridden + $this->config_dir[$k] = rtrim($v, '/\\') . DS; + } + } + } elseif( $key !== null ) { + // override directory at specified index + $this->config_dir[$key] = rtrim($config_dir, '/\\') . DS; + } else { + // append new directory + $this->config_dir[] = rtrim($config_dir, '/\\') . DS; + } + + $this->joined_config_dir = join(DIRECTORY_SEPARATOR, $this->config_dir); + return $this; + } + + /** + * Get config directory + * + * @param mixed index of directory to get, null to get all + * @return array|string configuration directory + */ + public function getConfigDir($index=null) + { + if ($index !== null) { + return isset($this->config_dir[$index]) ? $this->config_dir[$index] : null; + } + + return (array)$this->config_dir; + } + + /** + * Set plugins directory + * + * @param string|array $plugins_dir directory(s) of plugins + * @return Smarty current Smarty instance for chaining + */ + public function setPluginsDir($plugins_dir) + { + $this->plugins_dir = array(); + foreach ((array)$plugins_dir as $k => $v) { + $this->plugins_dir[$k] = rtrim($v, '/\\') . DS; + } + + return $this; + } + + /** + * Adds directory of plugin files + * + * @param object $smarty + * @param string $ |array $ plugins folder + * @return Smarty current Smarty instance for chaining + */ + public function addPluginsDir($plugins_dir) + { + // make sure we're dealing with an array + $this->plugins_dir = (array) $this->plugins_dir; + + if (is_array($plugins_dir)) { + foreach ($plugins_dir as $k => $v) { + if (is_int($k)) { + // indexes are not merged but appended + $this->plugins_dir[] = rtrim($v, '/\\') . DS; + } else { + // string indexes are overridden + $this->plugins_dir[$k] = rtrim($v, '/\\') . DS; + } + } + } else { + // append new directory + $this->plugins_dir[] = rtrim($plugins_dir, '/\\') . DS; + } + + $this->plugins_dir = array_unique($this->plugins_dir); + return $this; + } + + /** + * Get plugin directories + * + * @return array list of plugin directories + */ + public function getPluginsDir() + { + return (array)$this->plugins_dir; + } + + /** + * Set compile directory + * + * @param string $compile_dir directory to store compiled templates in + * @return Smarty current Smarty instance for chaining + */ + public function setCompileDir($compile_dir) + { + $this->compile_dir = rtrim($compile_dir, '/\\') . DS; + if (!isset(Smarty::$_muted_directories[$this->compile_dir])) { + Smarty::$_muted_directories[$this->compile_dir] = null; + } + return $this; + } + + /** + * Get compiled directory + * + * @return string path to compiled templates + */ + public function getCompileDir() + { + return $this->compile_dir; + } + + /** + * Set cache directory + * + * @param string $cache_dir directory to store cached templates in + * @return Smarty current Smarty instance for chaining + */ + public function setCacheDir($cache_dir) + { + $this->cache_dir = rtrim($cache_dir, '/\\') . DS; + if (!isset(Smarty::$_muted_directories[$this->cache_dir])) { + Smarty::$_muted_directories[$this->cache_dir] = null; + } + return $this; + } + + /** + * Get cache directory + * + * @return string path of cache directory + */ + public function getCacheDir() + { + return $this->cache_dir; + } + + /** + * Set default modifiers + * + * @param array|string $modifiers modifier or list of modifiers to set + * @return Smarty current Smarty instance for chaining + */ + public function setDefaultModifiers($modifiers) + { + $this->default_modifiers = (array) $modifiers; + return $this; + } + + /** + * Add default modifiers + * + * @param array|string $modifiers modifier or list of modifiers to add + * @return Smarty current Smarty instance for chaining + */ + public function addDefaultModifiers($modifiers) + { + if (is_array($modifiers)) { + $this->default_modifiers = array_merge($this->default_modifiers, $modifiers); + } else { + $this->default_modifiers[] = $modifiers; + } + + return $this; + } + + /** + * Get default modifiers + * + * @return array list of default modifiers + */ + public function getDefaultModifiers() + { + return $this->default_modifiers; + } + + + /** + * Set autoload filters + * + * @param array $filters filters to load automatically + * @param string $type "pre", "output", … specify the filter type to set. Defaults to none treating $filters' keys as the appropriate types + * @return Smarty current Smarty instance for chaining + */ + public function setAutoloadFilters($filters, $type=null) + { + if ($type !== null) { + $this->autoload_filters[$type] = (array) $filters; + } else { + $this->autoload_filters = (array) $filters; + } + + return $this; + } + + /** + * Add autoload filters + * + * @param array $filters filters to load automatically + * @param string $type "pre", "output", … specify the filter type to set. Defaults to none treating $filters' keys as the appropriate types + * @return Smarty current Smarty instance for chaining + */ + public function addAutoloadFilters($filters, $type=null) + { + if ($type !== null) { + if (!empty($this->autoload_filters[$type])) { + $this->autoload_filters[$type] = array_merge($this->autoload_filters[$type], (array) $filters); + } else { + $this->autoload_filters[$type] = (array) $filters; + } + } else { + foreach ((array) $filters as $key => $value) { + if (!empty($this->autoload_filters[$key])) { + $this->autoload_filters[$key] = array_merge($this->autoload_filters[$key], (array) $value); + } else { + $this->autoload_filters[$key] = (array) $value; + } + } + } + + return $this; + } + + /** + * Get autoload filters + * + * @param string $type type of filter to get autoloads for. Defaults to all autoload filters + * @return array array( 'type1' => array( 'filter1', 'filter2', … ) ) or array( 'filter1', 'filter2', …) if $type was specified + */ + public function getAutoloadFilters($type=null) + { + if ($type !== null) { + return isset($this->autoload_filters[$type]) ? $this->autoload_filters[$type] : array(); + } + + return $this->autoload_filters; + } + + /** + * return name of debugging template + * + * @return string + */ + public function getDebugTemplate() + { + return $this->debug_tpl; + } + + /** + * set the debug template + * + * @param string $tpl_name + * @return Smarty current Smarty instance for chaining + * @throws SmartyException if file is not readable + */ + public function setDebugTemplate($tpl_name) + { + if (!is_readable($tpl_name)) { + throw new SmartyException("Unknown file '{$tpl_name}'"); + } + $this->debug_tpl = $tpl_name; + + return $this; + } + + /** + * creates a template object + * + * @param string $template the resource handle of the template file + * @param mixed $cache_id cache id to be used with this template + * @param mixed $compile_id compile id to be used with this template + * @param object $parent next higher level of Smarty variables + * @param boolean $do_clone flag is Smarty object shall be cloned + * @return object template object + */ + public function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null, $do_clone = true) + { + if (!empty($cache_id) && (is_object($cache_id) || is_array($cache_id))) { + $parent = $cache_id; + $cache_id = null; + } + if (!empty($parent) && is_array($parent)) { + $data = $parent; + $parent = null; + } else { + $data = null; + } + // default to cache_id and compile_id of Smarty object + $cache_id = $cache_id === null ? $this->cache_id : $cache_id; + $compile_id = $compile_id === null ? $this->compile_id : $compile_id; + // already in template cache? + if ($this->allow_ambiguous_resources) { + $_templateId = Smarty_Resource::getUniqueTemplateName($this, $template) . $cache_id . $compile_id; + } else { + $_templateId = $this->joined_template_dir . '#' . $template . $cache_id . $compile_id; + } + if (isset($_templateId[150])) { + $_templateId = sha1($_templateId); + } + if ($do_clone) { + if (isset($this->template_objects[$_templateId])) { + // return cached template object + $tpl = clone $this->template_objects[$_templateId]; + $tpl->smarty = clone $tpl->smarty; + $tpl->parent = $parent; + $tpl->tpl_vars = array(); + $tpl->config_vars = array(); + } else { + $tpl = new $this->template_class($template, clone $this, $parent, $cache_id, $compile_id); + } + } else { + if (isset($this->template_objects[$_templateId])) { + // return cached template object + $tpl = $this->template_objects[$_templateId]; + $tpl->parent = $parent; + $tpl->tpl_vars = array(); + $tpl->config_vars = array(); + } else { + $tpl = new $this->template_class($template, $this, $parent, $cache_id, $compile_id); + } + } + // fill data if present + if (!empty($data) && is_array($data)) { + // set up variable values + foreach ($data as $_key => $_val) { + $tpl->tpl_vars[$_key] = new Smarty_variable($_val); + } + } + return $tpl; + } + + + /** + * Takes unknown classes and loads plugin files for them + * class name format: Smarty_PluginType_PluginName + * plugin filename format: plugintype.pluginname.php + * + * @param string $plugin_name class plugin name to load + * @param bool $check check if already loaded + * @return string |boolean filepath of loaded file or false + */ + public function loadPlugin($plugin_name, $check = true) + { + // if function or class exists, exit silently (already loaded) + if ($check && (is_callable($plugin_name) || class_exists($plugin_name, false))) { + return true; + } + // Plugin name is expected to be: Smarty_[Type]_[Name] + $_name_parts = explode('_', $plugin_name, 3); + // class name must have three parts to be valid plugin + // count($_name_parts) < 3 === !isset($_name_parts[2]) + if (!isset($_name_parts[2]) || strtolower($_name_parts[0]) !== 'smarty') { + throw new SmartyException("plugin {$plugin_name} is not a valid name format"); + return false; + } + // if type is "internal", get plugin from sysplugins + if (strtolower($_name_parts[1]) == 'internal') { + $file = SMARTY_SYSPLUGINS_DIR . strtolower($plugin_name) . '.php'; + if (file_exists($file)) { + require_once($file); + return $file; + } else { + return false; + } + } + // plugin filename is expected to be: [type].[name].php + $_plugin_filename = "{$_name_parts[1]}.{$_name_parts[2]}.php"; + + // loop through plugin dirs and find the plugin + foreach($this->getPluginsDir() as $_plugin_dir) { + $names = array( + $_plugin_dir . $_plugin_filename, + $_plugin_dir . strtolower($_plugin_filename), + ); + foreach ($names as $file) { + if (file_exists($file)) { + require_once($file); + return $file; + } + if ($this->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_plugin_dir)) { + // try PHP include_path + if (($file = Smarty_Internal_Get_Include_Path::getIncludePath($file)) !== false) { + require_once($file); + return $file; + } + } + } + } + // no plugin loaded + return false; + } + + /** + * Compile all template files + * + * @param string $extension file extension + * @param bool $force_compile force all to recompile + * @param int $time_limit + * @param int $max_errors + * @return integer number of template files recompiled + */ + public function compileAllTemplates($extention = '.tpl', $force_compile = false, $time_limit = 0, $max_errors = null) + { + return Smarty_Internal_Utility::compileAllTemplates($extention, $force_compile, $time_limit, $max_errors, $this); + } + + /** + * Compile all config files + * + * @param string $extension file extension + * @param bool $force_compile force all to recompile + * @param int $time_limit + * @param int $max_errors + * @return integer number of template files recompiled + */ + public function compileAllConfig($extention = '.conf', $force_compile = false, $time_limit = 0, $max_errors = null) + { + return Smarty_Internal_Utility::compileAllConfig($extention, $force_compile, $time_limit, $max_errors, $this); + } + + /** + * Delete compiled template file + * + * @param string $resource_name template name + * @param string $compile_id compile id + * @param integer $exp_time expiration time + * @return integer number of template files deleted + */ + public function clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null) + { + return Smarty_Internal_Utility::clearCompiledTemplate($resource_name, $compile_id, $exp_time, $this); + } + + + /** + * Return array of tag/attributes of all tags used by an template + * + * @param object $templae template object + * @return array of tag/attributes + */ + public function getTags(Smarty_Internal_Template $template) + { + return Smarty_Internal_Utility::getTags($template); + } + + /** + * Run installation test + * + * @param array $errors Array to write errors into, rather than outputting them + * @return boolean true if setup is fine, false if something is wrong + */ + public function testInstall(&$errors=null) + { + return Smarty_Internal_Utility::testInstall($this, $errors); + } + + /** + * Error Handler to mute expected messages + * + * @link http://php.net/set_error_handler + * @param integer $errno Error level + * @return boolean + */ + public static function mutingErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) + { + $_is_muted_directory = false; + + // add the SMARTY_DIR to the list of muted directories + if (!isset(Smarty::$_muted_directories[SMARTY_DIR])) { + $smarty_dir = realpath(SMARTY_DIR); + Smarty::$_muted_directories[SMARTY_DIR] = array( + 'file' => $smarty_dir, + 'length' => strlen($smarty_dir), + ); + } + + // walk the muted directories and test against $errfile + foreach (Smarty::$_muted_directories as $key => &$dir) { + if (!$dir) { + // resolve directory and length for speedy comparisons + $file = realpath($key); + $dir = array( + 'file' => $file, + 'length' => strlen($file), + ); + } + if (!strncmp($errfile, $dir['file'], $dir['length'])) { + $_is_muted_directory = true; + break; + } + } + + // pass to next error handler if this error did not occur inside SMARTY_DIR + // or the error was within smarty but masked to be ignored + if (!$_is_muted_directory || ($errno && $errno & error_reporting())) { + if (Smarty::$_previous_error_handler) { + return call_user_func(Smarty::$_previous_error_handler, $errno, $errstr, $errfile, $errline, $errcontext); + } else { + return false; + } + } + } + + /** + * Enable error handler to mute expected messages + * + * @return void + */ + public static function muteExpectedErrors() + { + /* + error muting is done because some people implemented custom error_handlers using + http://php.net/set_error_handler and for some reason did not understand the following paragraph: + + It is important to remember that the standard PHP error handler is completely bypassed for the + error types specified by error_types unless the callback function returns FALSE. + error_reporting() settings will have no effect and your error handler will be called regardless - + however you are still able to read the current value of error_reporting and act appropriately. + Of particular note is that this value will be 0 if the statement that caused the error was + prepended by the @ error-control operator. + + Smarty deliberately uses @filemtime() over file_exists() and filemtime() in some places. Reasons include + - @filemtime() is almost twice as fast as using an additional file_exists() + - between file_exists() and filemtime() a possible race condition is opened, + which does not exist using the simple @filemtime() approach. + */ + $error_handler = array('Smarty', 'mutingErrorHandler'); + $previous = set_error_handler($error_handler); + + // avoid dead loops + if ($previous !== $error_handler) { + Smarty::$_previous_error_handler = $previous; + } + } + + /** + * Disable error handler muting expected messages + * + * @return void + */ + public static function unmuteExpectedErrors() + { + restore_error_handler(); + } +} + +/** +* Smarty exception class +* @package Smarty +*/ +class SmartyException extends Exception { +} + +/** +* Smarty compiler exception class +* @package Smarty +*/ +class SmartyCompilerException extends SmartyException { +} + +/** +* Autoloader +*/ +function smartyAutoload($class) +{ + $_class = strtolower($class); + $_classes = array( + 'smarty_config_source' => true, + 'smarty_config_compiled' => true, + 'smarty_security' => true, + 'smarty_cacheresource' => true, + 'smarty_cacheresource_custom' => true, + 'smarty_cacheresource_keyvaluestore' => true, + 'smarty_resource' => true, + 'smarty_resource_custom' => true, + 'smarty_resource_uncompiled' => true, + 'smarty_resource_recompiled' => true, + ); + + if (!strncmp($_class, 'smarty_internal_', 16) || isset($_classes[$_class])) { + include SMARTY_SYSPLUGINS_DIR . $_class . '.php'; + } +} + +?> diff --git a/ThinkPHP/Extend/Vendor/Smarty/SmartyBC.class.php b/ThinkPHP/Extend/Vendor/Smarty/SmartyBC.class.php new file mode 100644 index 0000000..c060a25 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Smarty/SmartyBC.class.php @@ -0,0 +1,460 @@ + + * @author Uwe Tews + * @author Rodney Rehm + * @package Smarty + */ +/** + * @ignore + */ +require(dirname(__FILE__) . '/Smarty.class.php'); + +/** + * Smarty Backward Compatability Wrapper Class + * + * @package Smarty + */ +class SmartyBC extends Smarty { + + /** + * Smarty 2 BC + * @var string + */ + public $_version = self::SMARTY_VERSION; + + /** + * Initialize new SmartyBC object + * + * @param array $options options to set during initialization, e.g. array( 'forceCompile' => false ) + */ + public function __construct(array $options=array()) + { + parent::__construct($options); + // register {php} tag + $this->registerPlugin('block', 'php', 'smarty_php_tag'); + } + + /** + * wrapper for assign_by_ref + * + * @param string $tpl_var the template variable name + * @param mixed &$value the referenced value to assign + */ + public function assign_by_ref($tpl_var, &$value) + { + $this->assignByRef($tpl_var, $value); + } + + /** + * wrapper for append_by_ref + * + * @param string $tpl_var the template variable name + * @param mixed &$value the referenced value to append + * @param boolean $merge flag if array elements shall be merged + */ + public function append_by_ref($tpl_var, &$value, $merge = false) + { + $this->appendByRef($tpl_var, $value, $merge); + } + + /** + * clear the given assigned template variable. + * + * @param string $tpl_var the template variable to clear + */ + public function clear_assign($tpl_var) + { + $this->clearAssign($tpl_var); + } + + /** + * Registers custom function to be used in templates + * + * @param string $function the name of the template function + * @param string $function_impl the name of the PHP function to register + * @param bool $cacheable + * @param mixed $cache_attrs + */ + public function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) + { + $this->registerPlugin('function', $function, $function_impl, $cacheable, $cache_attrs); + } + + /** + * Unregisters custom function + * + * @param string $function name of template function + */ + public function unregister_function($function) + { + $this->unregisterPlugin('function', $function); + } + + /** + * Registers object to be used in templates + * + * @param string $object name of template object + * @param object $object_impl the referenced PHP object to register + * @param array $allowed list of allowed methods (empty = all) + * @param boolean $smarty_args smarty argument format, else traditional + * @param array $block_functs list of methods that are block format + */ + public function register_object($object, $object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + { + settype($allowed, 'array'); + settype($smarty_args, 'boolean'); + $this->registerObject($object, $object_impl, $allowed, $smarty_args, $block_methods); + } + + /** + * Unregisters object + * + * @param string $object name of template object + */ + public function unregister_object($object) + { + $this->unregisterObject($object); + } + + /** + * Registers block function to be used in templates + * + * @param string $block name of template block + * @param string $block_impl PHP function to register + * @param bool $cacheable + * @param mixed $cache_attrs + */ + public function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) + { + $this->registerPlugin('block', $block, $block_impl, $cacheable, $cache_attrs); + } + + /** + * Unregisters block function + * + * @param string $block name of template function + */ + public function unregister_block($block) + { + $this->unregisterPlugin('block', $block); + } + + /** + * Registers compiler function + * + * @param string $function name of template function + * @param string $function_impl name of PHP function to register + * @param bool $cacheable + */ + public function register_compiler_function($function, $function_impl, $cacheable=true) + { + $this->registerPlugin('compiler', $function, $function_impl, $cacheable); + } + + /** + * Unregisters compiler function + * + * @param string $function name of template function + */ + public function unregister_compiler_function($function) + { + $this->unregisterPlugin('compiler', $function); + } + + /** + * Registers modifier to be used in templates + * + * @param string $modifier name of template modifier + * @param string $modifier_impl name of PHP function to register + */ + public function register_modifier($modifier, $modifier_impl) + { + $this->registerPlugin('modifier', $modifier, $modifier_impl); + } + + /** + * Unregisters modifier + * + * @param string $modifier name of template modifier + */ + public function unregister_modifier($modifier) + { + $this->unregisterPlugin('modifier', $modifier); + } + + /** + * Registers a resource to fetch a template + * + * @param string $type name of resource + * @param array $functions array of functions to handle resource + */ + public function register_resource($type, $functions) + { + $this->registerResource($type, $functions); + } + + /** + * Unregisters a resource + * + * @param string $type name of resource + */ + public function unregister_resource($type) + { + $this->unregisterResource($type); + } + + /** + * Registers a prefilter function to apply + * to a template before compiling + * + * @param callable $function + */ + public function register_prefilter($function) + { + $this->registerFilter('pre', $function); + } + + /** + * Unregisters a prefilter function + * + * @param callable $function + */ + public function unregister_prefilter($function) + { + $this->unregisterFilter('pre', $function); + } + + /** + * Registers a postfilter function to apply + * to a compiled template after compilation + * + * @param callable $function + */ + public function register_postfilter($function) + { + $this->registerFilter('post', $function); + } + + /** + * Unregisters a postfilter function + * + * @param callable $function + */ + public function unregister_postfilter($function) + { + $this->unregisterFilter('post', $function); + } + + /** + * Registers an output filter function to apply + * to a template output + * + * @param callable $function + */ + public function register_outputfilter($function) + { + $this->registerFilter('output', $function); + } + + /** + * Unregisters an outputfilter function + * + * @param callable $function + */ + public function unregister_outputfilter($function) + { + $this->unregisterFilter('output', $function); + } + + /** + * load a filter of specified type and name + * + * @param string $type filter type + * @param string $name filter name + */ + public function load_filter($type, $name) + { + $this->loadFilter($type, $name); + } + + /** + * clear cached content for the given template and cache id + * + * @param string $tpl_file name of template file + * @param string $cache_id name of cache_id + * @param string $compile_id name of compile_id + * @param string $exp_time expiration time + * @return boolean + */ + public function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + return $this->clearCache($tpl_file, $cache_id, $compile_id, $exp_time); + } + + /** + * clear the entire contents of cache (all templates) + * + * @param string $exp_time expire time + * @return boolean + */ + public function clear_all_cache($exp_time = null) + { + return $this->clearCache(null, null, null, $exp_time); + } + + /** + * test to see if valid cache exists for this template + * + * @param string $tpl_file name of template file + * @param string $cache_id + * @param string $compile_id + * @return boolean + */ + public function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + return $this->isCached($tpl_file, $cache_id, $compile_id); + } + + /** + * clear all the assigned template variables. + */ + public function clear_all_assign() + { + $this->clearAllAssign(); + } + + /** + * clears compiled version of specified template resource, + * or all compiled template files if one is not specified. + * This function is for advanced use only, not normally needed. + * + * @param string $tpl_file + * @param string $compile_id + * @param string $exp_time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + public function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) + { + return $this->clearCompiledTemplate($tpl_file, $compile_id, $exp_time); + } + + /** + * Checks whether requested template exists. + * + * @param string $tpl_file + * @return boolean + */ + public function template_exists($tpl_file) + { + return $this->templateExists($tpl_file); + } + + /** + * Returns an array containing template variables + * + * @param string $name + * @return array + */ + public function get_template_vars($name=null) + { + return $this->getTemplateVars($name); + } + + /** + * Returns an array containing config variables + * + * @param string $name + * @return array + */ + public function get_config_vars($name=null) + { + return $this->getConfigVars($name); + } + + /** + * load configuration values + * + * @param string $file + * @param string $section + * @param string $scope + */ + public function config_load($file, $section = null, $scope = 'global') + { + $this->ConfigLoad($file, $section, $scope); + } + + /** + * return a reference to a registered object + * + * @param string $name + * @return object + */ + public function get_registered_object($name) + { + return $this->getRegisteredObject($name); + } + + /** + * clear configuration values + * + * @param string $var + */ + public function clear_config($var = null) + { + $this->clearConfig($var); + } + + /** + * trigger Smarty error + * + * @param string $error_msg + * @param integer $error_type + */ + public function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Smarty error: $error_msg", $error_type); + } + +} + +/** + * Smarty {php}{/php} block function + * + * @param array $params parameter list + * @param string $content contents of the block + * @param object $template template object + * @param boolean &$repeat repeat flag + * @return string content re-formatted + */ +function smarty_php_tag($params, $content, $template, &$repeat) +{ + eval($content); + return ''; +} + +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/Smarty/debug.tpl b/ThinkPHP/Extend/Vendor/Smarty/debug.tpl new file mode 100644 index 0000000..12eef0f --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Smarty/debug.tpl @@ -0,0 +1,133 @@ +{capture name='_smarty_debug' assign=debug_output} + + + + Smarty Debug Console + + + + +

    Smarty Debug Console - {if isset($template_name)}{$template_name|debug_print_var nofilter}{else}Total Time {$execution_time|string_format:"%.5f"}{/if}

    + +{if !empty($template_data)} +

    included templates & config files (load time in seconds)

    + +
    +{foreach $template_data as $template} + {$template.name} + + (compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"}) + +
    +{/foreach} +
    +{/if} + +

    assigned template variables

    + + + {foreach $assigned_vars as $vars} + + + + {/foreach} +
    ${$vars@key|escape:'html'}{$vars|debug_print_var nofilter}
    + +

    assigned config file variables (outer template scope)

    + + + {foreach $config_vars as $vars} + + + + {/foreach} + +
    {$vars@key|escape:'html'}{$vars|debug_print_var nofilter}
    + + +{/capture} + diff --git a/ThinkPHP/Extend/Vendor/Smarty/plugins/block.textformat.php b/ThinkPHP/Extend/Vendor/Smarty/plugins/block.textformat.php new file mode 100644 index 0000000..bdd8067 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Smarty/plugins/block.textformat.php @@ -0,0 +1,113 @@ + + * Name: textformat
    + * Purpose: format text a certain way with preset styles + * or custom wrap/indent settings
    + * Params: + *
    + * - style         - string (email)
    + * - indent        - integer (0)
    + * - wrap          - integer (80)
    + * - wrap_char     - string ("\n")
    + * - indent_char   - string (" ")
    + * - wrap_boundary - boolean (true)
    + * 
    + * + * @link http://www.smarty.net/manual/en/language.function.textformat.php {textformat} + * (Smarty online manual) + * @param array $params parameters + * @param string $content contents of the block + * @param Smarty_Internal_Template $template template object + * @param boolean &$repeat repeat flag + * @return string content re-formatted + * @author Monte Ohrt + */ +function smarty_block_textformat($params, $content, $template, &$repeat) +{ + if (is_null($content)) { + return; + } + + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + foreach ($params as $_key => $_val) { + switch ($_key) { + case 'style': + case 'indent_char': + case 'wrap_char': + case 'assign': + $$_key = (string)$_val; + break; + + case 'indent': + case 'indent_first': + case 'wrap': + $$_key = (int)$_val; + break; + + case 'wrap_cut': + $$_key = (bool)$_val; + break; + + default: + trigger_error("textformat: unknown attribute '$_key'"); + } + } + + if ($style == 'email') { + $wrap = 72; + } + // split into paragraphs + $_paragraphs = preg_split('![\r\n]{2}!', $content); + $_output = ''; + + + foreach ($_paragraphs as &$_paragraph) { + if (!$_paragraph) { + continue; + } + // convert mult. spaces & special chars to single space + $_paragraph = preg_replace(array('!\s+!u', '!(^\s+)|(\s+$)!u'), array(' ', ''), $_paragraph); + // indent first line + if ($indent_first > 0) { + $_paragraph = str_repeat($indent_char, $indent_first) . $_paragraph; + } + // wordwrap sentences + if (SMARTY_MBSTRING /* ^phpunit */&&empty($_SERVER['SMARTY_PHPUNIT_DISABLE_MBSTRING'])/* phpunit$ */) { + require_once(SMARTY_PLUGINS_DIR . 'shared.mb_wordwrap.php'); + $_paragraph = smarty_mb_wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut); + } else { + $_paragraph = wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut); + } + // indent lines + if ($indent > 0) { + $_paragraph = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraph); + } + } + $_output = implode($wrap_char . $wrap_char, $_paragraphs); + + if ($assign) { + $template->assign($assign, $_output); + } else { + return $_output; + } +} + +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/Smarty/plugins/function.counter.php b/ThinkPHP/Extend/Vendor/Smarty/plugins/function.counter.php new file mode 100644 index 0000000..3906bad --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Smarty/plugins/function.counter.php @@ -0,0 +1,78 @@ + + * Name: counter
    + * Purpose: print out a counter value + * + * @author Monte Ohrt + * @link http://www.smarty.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array $params parameters + * @param Smarty_Internal_Template $template template object + * @return string|null + */ +function smarty_function_counter($params, $template) +{ + static $counters = array(); + + $name = (isset($params['name'])) ? $params['name'] : 'default'; + if (!isset($counters[$name])) { + $counters[$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter =& $counters[$name]; + + if (isset($params['start'])) { + $counter['start'] = $counter['count'] = (int)$params['start']; + } + + if (!empty($params['assign'])) { + $counter['assign'] = $params['assign']; + } + + if (isset($counter['assign'])) { + $template->assign($counter['assign'], $counter['count']); + } + + if (isset($params['print'])) { + $print = (bool)$params['print']; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($params['skip'])) { + $counter['skip'] = $params['skip']; + } + + if (isset($params['direction'])) { + $counter['direction'] = $params['direction']; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/Smarty/plugins/function.cycle.php b/ThinkPHP/Extend/Vendor/Smarty/plugins/function.cycle.php new file mode 100644 index 0000000..1778ffb --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Smarty/plugins/function.cycle.php @@ -0,0 +1,106 @@ + + * Name: cycle
    + * Date: May 3, 2002
    + * Purpose: cycle through given values
    + * Params: + *
    + * - name      - name of cycle (optional)
    + * - values    - comma separated list of values to cycle, or an array of values to cycle
    + *               (this can be left out for subsequent calls)
    + * - reset     - boolean - resets given var to true
    + * - print     - boolean - print var or not. default is true
    + * - advance   - boolean - whether or not to advance the cycle
    + * - delimiter - the value delimiter, default is ","
    + * - assign    - boolean, assigns to template var instead of printed.
    + * 
    + * Examples:
    + *
    + * {cycle values="#eeeeee,#d0d0d0d"}
    + * {cycle name=row values="one,two,three" reset=true}
    + * {cycle name=row}
    + * 
    + * + * @link http://www.smarty.net/manual/en/language.function.cycle.php {cycle} + * (Smarty online manual) + * @author Monte Ohrt + * @author credit to Mark Priatel + * @author credit to Gerard + * @author credit to Jason Sweat + * @version 1.3 + * @param array $params parameters + * @param Smarty_Internal_Template $template template object + * @return string|null + */ + +function smarty_function_cycle($params, $template) +{ + static $cycle_vars; + + $name = (empty($params['name'])) ? 'default' : $params['name']; + $print = (isset($params['print'])) ? (bool)$params['print'] : true; + $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; + $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; + + if (!isset($params['values'])) { + if(!isset($cycle_vars[$name]['values'])) { + trigger_error("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($cycle_vars[$name]['values']) + && $cycle_vars[$name]['values'] != $params['values'] ) { + $cycle_vars[$name]['index'] = 0; + } + $cycle_vars[$name]['values'] = $params['values']; + } + + if (isset($params['delimiter'])) { + $cycle_vars[$name]['delimiter'] = $params['delimiter']; + } elseif (!isset($cycle_vars[$name]['delimiter'])) { + $cycle_vars[$name]['delimiter'] = ','; + } + + if(is_array($cycle_vars[$name]['values'])) { + $cycle_array = $cycle_vars[$name]['values']; + } else { + $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); + } + + if(!isset($cycle_vars[$name]['index']) || $reset ) { + $cycle_vars[$name]['index'] = 0; + } + + if (isset($params['assign'])) { + $print = false; + $template->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]); + } + + if($print) { + $retval = $cycle_array[$cycle_vars[$name]['index']]; + } else { + $retval = null; + } + + if($advance) { + if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { + $cycle_vars[$name]['index'] = 0; + } else { + $cycle_vars[$name]['index']++; + } + } + + return $retval; +} + +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/Smarty/plugins/function.fetch.php b/ThinkPHP/Extend/Vendor/Smarty/plugins/function.fetch.php new file mode 100644 index 0000000..cde98d2 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Smarty/plugins/function.fetch.php @@ -0,0 +1,216 @@ + + * Name: fetch
    + * Purpose: fetch file, web or ftp data and display results + * + * @link http://www.smarty.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @author Monte Ohrt + * @param array $params parameters + * @param Smarty_Internal_Template $template template object + * @return string|null if the assign parameter is passed, Smarty assigns the result to a template variable + */ +function smarty_function_fetch($params, $template) +{ + if (empty($params['file'])) { + trigger_error("[plugin] fetch parameter 'file' cannot be empty",E_USER_NOTICE); + return; + } + + $content = ''; + if (isset($template->smarty->security_policy) && !preg_match('!^(http|ftp)://!i', $params['file'])) { + if(!$template->smarty->security_policy->isTrustedResourceDir($params['file'])) { + return; + } + + // fetch the file + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + trigger_error('[plugin] fetch cannot read file \'' . $params['file'] . '\'',E_USER_NOTICE); + return; + } + } else { + // not a local file + if(preg_match('!^http://!i',$params['file'])) { + // http fetch + if($uri_parts = parse_url($params['file'])) { + // set defaults + $host = $server_name = $uri_parts['host']; + $timeout = 30; + $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + $agent = "Smarty Template Engine ". Smarty::SMARTY_VERSION; + $referer = ""; + $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; + $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; + $_is_proxy = false; + if(empty($uri_parts['port'])) { + $port = 80; + } else { + $port = $uri_parts['port']; + } + if(!empty($uri_parts['user'])) { + $user = $uri_parts['user']; + } + if(!empty($uri_parts['pass'])) { + $pass = $uri_parts['pass']; + } + // loop through parameters, setup headers + foreach($params as $param_key => $param_value) { + switch($param_key) { + case "file": + case "assign": + case "assign_headers": + break; + case "user": + if(!empty($param_value)) { + $user = $param_value; + } + break; + case "pass": + if(!empty($param_value)) { + $pass = $param_value; + } + break; + case "accept": + if(!empty($param_value)) { + $accept = $param_value; + } + break; + case "header": + if(!empty($param_value)) { + if(!preg_match('![\w\d-]+: .+!',$param_value)) { + trigger_error("[plugin] invalid header format '".$param_value."'",E_USER_NOTICE); + return; + } else { + $extra_headers[] = $param_value; + } + } + break; + case "proxy_host": + if(!empty($param_value)) { + $proxy_host = $param_value; + } + break; + case "proxy_port": + if(!preg_match('!\D!', $param_value)) { + $proxy_port = (int) $param_value; + } else { + trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE); + return; + } + break; + case "agent": + if(!empty($param_value)) { + $agent = $param_value; + } + break; + case "referer": + if(!empty($param_value)) { + $referer = $param_value; + } + break; + case "timeout": + if(!preg_match('!\D!', $param_value)) { + $timeout = (int) $param_value; + } else { + trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE); + return; + } + break; + default: + trigger_error("[plugin] unrecognized attribute '".$param_key."'",E_USER_NOTICE); + return; + } + } + if(!empty($proxy_host) && !empty($proxy_port)) { + $_is_proxy = true; + $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); + } else { + $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); + } + + if(!$fp) { + trigger_error("[plugin] unable to fetch: $errstr ($errno)",E_USER_NOTICE); + return; + } else { + if($_is_proxy) { + fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); + } else { + fputs($fp, "GET $uri HTTP/1.0\r\n"); + } + if(!empty($host)) { + fputs($fp, "Host: $host\r\n"); + } + if(!empty($accept)) { + fputs($fp, "Accept: $accept\r\n"); + } + if(!empty($agent)) { + fputs($fp, "User-Agent: $agent\r\n"); + } + if(!empty($referer)) { + fputs($fp, "Referer: $referer\r\n"); + } + if(isset($extra_headers) && is_array($extra_headers)) { + foreach($extra_headers as $curr_header) { + fputs($fp, $curr_header."\r\n"); + } + } + if(!empty($user) && !empty($pass)) { + fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); + } + + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = preg_split("!\r\n\r\n!",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $template->assign($params['assign_headers'],preg_split("!\r\n!",$csplit[0])); + } + } + } else { + trigger_error("[plugin fetch] unable to parse URL, check syntax",E_USER_NOTICE); + return; + } + } else { + // ftp fetch + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + trigger_error('[plugin] fetch cannot read file \'' . $params['file'] .'\'',E_USER_NOTICE); + return; + } + } + + } + + + if (!empty($params['assign'])) { + $template->assign($params['assign'],$content); + } else { + return $content; + } +} + +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/Smarty/plugins/function.html_checkboxes.php b/ThinkPHP/Extend/Vendor/Smarty/plugins/function.html_checkboxes.php new file mode 100644 index 0000000..4251369 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Smarty/plugins/function.html_checkboxes.php @@ -0,0 +1,216 @@ + + * Type: function
    + * Name: html_checkboxes
    + * Date: 24.Feb.2003
    + * Purpose: Prints out a list of checkbox input types
    + * Examples: + *
    + * {html_checkboxes values=$ids output=$names}
    + * {html_checkboxes values=$ids name='box' separator='
    ' output=$names} + * {html_checkboxes values=$ids checked=$checked separator='
    ' output=$names} + *
    + * Params: + *
    + * - name       (optional) - string default "checkbox"
    + * - values     (required) - array
    + * - options    (optional) - associative array
    + * - checked    (optional) - array default not set
    + * - separator  (optional) - ie 
    or   + * - output (optional) - the output next to each checkbox + * - assign (optional) - assign the output as an array to this variable + * - escape (optional) - escape the content (not value), defaults to true + *
    + * + * @link http://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array $params parameters + * @param object $template template object + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, $template) +{ + require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = array(); + $separator = ''; + $escape = true; + $labels = true; + $label_ids = false; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = (string) $_val; + break; + + case 'escape': + case 'labels': + case 'label_ids': + $$_key = (bool) $_val; + break; + + case 'options': + $$_key = (array) $_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array) $_val); + break; + + case 'checked': + case 'selected': + if (is_array($_val)) { + $selected = array(); + foreach ($_val as $_sel) { + if (is_object($_sel)) { + if (method_exists($_sel, "__toString")) { + $_sel = smarty_function_escape_special_chars((string) $_sel->__toString()); + } else { + trigger_error("html_checkboxes: selected attribute contains an object of class '". get_class($_sel) ."' without __toString() method", E_USER_NOTICE); + continue; + } + } else { + $_sel = smarty_function_escape_special_chars((string) $_sel); + } + $selected[$_sel] = true; + } + } elseif (is_object($_val)) { + if (method_exists($_val, "__toString")) { + $selected = smarty_function_escape_special_chars((string) $_val->__toString()); + } else { + trigger_error("html_checkboxes: selected attribute is an object of class '". get_class($_val) ."' without __toString() method", E_USER_NOTICE); + } + } else { + $selected = smarty_function_escape_special_chars((string) $_val); + } + break; + + case 'checkboxes': + trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array) $_val; + break; + + case 'assign': + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + $_html_result = array(); + + if (isset($options)) { + foreach ($options as $_key=>$_val) { + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids, $escape); + } + } else { + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids, $escape); + } + } + + if(!empty($params['assign'])) { + $template->assign($params['assign'], $_html_result); + } else { + return implode("\n", $_html_result); + } + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids, $escape=true) { + $_output = ''; + + if (is_object($value)) { + if (method_exists($value, "__toString")) { + $value = (string) $value->__toString(); + } else { + trigger_error("html_options: value is an object of class '". get_class($value) ."' without __toString() method", E_USER_NOTICE); + return ''; + } + } else { + $value = (string) $value; + } + + if (is_object($output)) { + if (method_exists($output, "__toString")) { + $output = (string) $output->__toString(); + } else { + trigger_error("html_options: output is an object of class '". get_class($output) ."' without __toString() method", E_USER_NOTICE); + return ''; + } + } else { + $output = (string) $output; + } + + if ($labels) { + if ($label_ids) { + $_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!u', '_', $name . '_' . $value)); + $_output .= '
    + * of the message. + * @const int + */ + const LOGIN_OPERATION = 8; + + /** + * This operation is used to log the user out of the current channel, and + * will invalidate the server session if the channel is HTTP based. + * @const int + */ + const LOGOUT_OPERATION = 9; + + /** + * This operation is used to indicate that the client's subscription to a + * remote destination has been invalidated. + * @const int + */ + const SESSION_INVALIDATE_OPERATION = 10; + + /** + * This operation is used by the MultiTopicConsumer to subscribe/unsubscribe + * from multiple subtopics/selectors in the same message. + * @const int + */ + const MULTI_SUBSCRIBE_OPERATION = 11; + + /** + * This operation is used to indicate that a channel has disconnected + * @const int + */ + const DISCONNECT_OPERATION = 12; + + /** + * This is the default operation for new CommandMessage instances. + * @const int + */ + const UNKNOWN_OPERATION = 10000; + + /** + * The operation to execute for messages of this type + * @var int + */ + public $operation = self::UNKNOWN_OPERATION; +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Amf/Value/Messaging/ErrorMessage.php b/ThinkPHP/Extend/Vendor/Zend/Amf/Value/Messaging/ErrorMessage.php new file mode 100644 index 0000000..df6a10c --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Amf/Value/Messaging/ErrorMessage.php @@ -0,0 +1,67 @@ +clientId = $this->generateId(); + $this->destination = null; + $this->messageId = $this->generateId(); + $this->timestamp = time().'00'; + $this->timeToLive = 0; + $this->headers = new stdClass(); + $this->body = null; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Amf/Value/TraitsInfo.php b/ThinkPHP/Extend/Vendor/Zend/Amf/Value/TraitsInfo.php new file mode 100644 index 0000000..2c1f687 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Amf/Value/TraitsInfo.php @@ -0,0 +1,154 @@ +_className = $className; + $this->_dynamic = $dynamic; + $this->_externalizable = $externalizable; + $this->_properties = $properties; + } + + /** + * Test if the class is a dynamic class + * + * @return boolean + */ + public function isDynamic() + { + return $this->_dynamic; + } + + /** + * Test if class is externalizable + * + * @return boolean + */ + public function isExternalizable() + { + return $this->_externalizable; + } + + /** + * Return the number of properties in the class + * + * @return int + */ + public function length() + { + return count($this->_properties); + } + + /** + * Return the class name + * + * @return string + */ + public function getClassName() + { + return $this->_className; + } + + /** + * Add an additional property + * + * @param string $name + * @return Zend_Amf_Value_TraitsInfo + */ + public function addProperty($name) + { + $this->_properties[] = $name; + return $this; + } + + /** + * Add all properties of the class. + * + * @param array $props + * @return Zend_Amf_Value_TraitsInfo + */ + public function addAllProperties(array $props) + { + $this->_properties = $props; + return $this; + } + + /** + * Get the property at a given index + * + * @param int $index + * @return string + */ + public function getProperty($index) + { + return $this->_properties[(int) $index]; + } + + /** + * Return all properties of the class. + * + * @return array + */ + public function getAllProperties() + { + return $this->_properties; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Auth.php b/ThinkPHP/Extend/Vendor/Zend/Auth.php new file mode 100644 index 0000000..94f4d17 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Auth.php @@ -0,0 +1,169 @@ +_storage) { + /** + * @see Zend_Auth_Storage_Session + */ + require_once 'Zend/Auth/Storage/Session.php'; + $this->setStorage(new Zend_Auth_Storage_Session()); + } + + return $this->_storage; + } + + /** + * Sets the persistent storage handler + * + * @param Zend_Auth_Storage_Interface $storage + * @return Zend_Auth Provides a fluent interface + */ + public function setStorage(Zend_Auth_Storage_Interface $storage) + { + $this->_storage = $storage; + return $this; + } + + /** + * Authenticates against the supplied adapter + * + * @param Zend_Auth_Adapter_Interface $adapter + * @return Zend_Auth_Result + */ + public function authenticate(Zend_Auth_Adapter_Interface $adapter) + { + $result = $adapter->authenticate(); + + /** + * ZF-7546 - prevent multiple succesive calls from storing inconsistent results + * Ensure storage has clean state + */ + if ($this->hasIdentity()) { + $this->clearIdentity(); + } + + if ($result->isValid()) { + $this->getStorage()->write($result->getIdentity()); + } + + return $result; + } + + /** + * Returns true if and only if an identity is available from storage + * + * @return boolean + */ + public function hasIdentity() + { + return !$this->getStorage()->isEmpty(); + } + + /** + * Returns the identity from storage or null if no identity is available + * + * @return mixed|null + */ + public function getIdentity() + { + $storage = $this->getStorage(); + + if ($storage->isEmpty()) { + return null; + } + + return $storage->read(); + } + + /** + * Clears the identity from persistent storage + * + * @return void + */ + public function clearIdentity() + { + $this->getStorage()->clear(); + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Date.php b/ThinkPHP/Extend/Vendor/Zend/Date.php new file mode 100644 index 0000000..7c0c9f4 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Date.php @@ -0,0 +1,4772 @@ + 'iso', // format for date strings 'iso' or 'php' + 'fix_dst' => true, // fix dst on summer/winter time change + 'extend_month' => false, // false - addMonth like SQL, true like excel + 'cache' => null, // cache to set + 'timesync' => null // timesync server to set + ); + + // Class wide Date Constants + const DAY = 'dd'; + const DAY_SHORT = 'd'; + const DAY_SUFFIX = 'SS'; + const DAY_OF_YEAR = 'D'; + const WEEKDAY = 'EEEE'; + const WEEKDAY_SHORT = 'EEE'; + const WEEKDAY_NARROW = 'E'; + const WEEKDAY_NAME = 'EE'; + const WEEKDAY_8601 = 'eee'; + const WEEKDAY_DIGIT = 'e'; + const WEEK = 'ww'; + const MONTH = 'MM'; + const MONTH_SHORT = 'M'; + const MONTH_DAYS = 'ddd'; + const MONTH_NAME = 'MMMM'; + const MONTH_NAME_SHORT = 'MMM'; + const MONTH_NAME_NARROW = 'MMMMM'; + const YEAR = 'y'; + const YEAR_SHORT = 'yy'; + const YEAR_8601 = 'Y'; + const YEAR_SHORT_8601 = 'YY'; + const LEAPYEAR = 'l'; + const MERIDIEM = 'a'; + const SWATCH = 'B'; + const HOUR = 'HH'; + const HOUR_SHORT = 'H'; + const HOUR_AM = 'hh'; + const HOUR_SHORT_AM = 'h'; + const MINUTE = 'mm'; + const MINUTE_SHORT = 'm'; + const SECOND = 'ss'; + const SECOND_SHORT = 's'; + const MILLISECOND = 'S'; + const TIMEZONE_NAME = 'zzzz'; + const DAYLIGHT = 'I'; + const GMT_DIFF = 'Z'; + const GMT_DIFF_SEP = 'ZZZZ'; + const TIMEZONE = 'z'; + const TIMEZONE_SECS = 'X'; + const ISO_8601 = 'c'; + const RFC_2822 = 'r'; + const TIMESTAMP = 'U'; + const ERA = 'G'; + const ERA_NAME = 'GGGG'; + const ERA_NARROW = 'GGGGG'; + const DATES = 'F'; + const DATE_FULL = 'FFFFF'; + const DATE_LONG = 'FFFF'; + const DATE_MEDIUM = 'FFF'; + const DATE_SHORT = 'FF'; + const TIMES = 'WW'; + const TIME_FULL = 'TTTTT'; + const TIME_LONG = 'TTTT'; + const TIME_MEDIUM = 'TTT'; + const TIME_SHORT = 'TT'; + const DATETIME = 'K'; + const DATETIME_FULL = 'KKKKK'; + const DATETIME_LONG = 'KKKK'; + const DATETIME_MEDIUM = 'KKK'; + const DATETIME_SHORT = 'KK'; + const ATOM = 'OOO'; + const COOKIE = 'CCC'; + const RFC_822 = 'R'; + const RFC_850 = 'RR'; + const RFC_1036 = 'RRR'; + const RFC_1123 = 'RRRR'; + const RFC_3339 = 'RRRRR'; + const RSS = 'SSS'; + const W3C = 'WWW'; + + /** + * Generates the standard date object, could be a unix timestamp, localized date, + * string, integer, array and so on. Also parts of dates or time are supported + * Always set the default timezone: http://php.net/date_default_timezone_set + * For example, in your bootstrap: date_default_timezone_set('America/Los_Angeles'); + * For detailed instructions please look in the docu. + * + * @param string|integer|Zend_Date|array $date OPTIONAL Date value or value of date part to set + * ,depending on $part. If null the actual time is set + * @param string $part OPTIONAL Defines the input format of $date + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function __construct($date = null, $part = null, $locale = null) + { + if (is_object($date) and !($date instanceof Zend_TimeSync_Protocol) and + !($date instanceof Zend_Date)) { + if ($locale instanceof Zend_Locale) { + $locale = $date; + $date = null; + $part = null; + } else { + $date = (string) $date; + } + } + + if (($date !== null) and !is_array($date) and !($date instanceof Zend_TimeSync_Protocol) and + !($date instanceof Zend_Date) and !defined($date) and Zend_Locale::isLocale($date, true, false)) { + $locale = $date; + $date = null; + $part = null; + } else if (($part !== null) and !defined($part) and Zend_Locale::isLocale($part, true, false)) { + $locale = $part; + $part = null; + } + + $this->setLocale($locale); + if (is_string($date) && ($part === null) && (strlen($date) <= 5)) { + $part = $date; + $date = null; + } + + if ($date === null) { + if ($part === null) { + $date = time(); + } else if ($part !== self::TIMESTAMP) { + $date = self::now($locale); + $date = $date->get($part); + } + } + + if ($date instanceof Zend_TimeSync_Protocol) { + $date = $date->getInfo(); + $date = $this->_getTime($date['offset']); + $part = null; + } else if (parent::$_defaultOffset != 0) { + $date = $this->_getTime(parent::$_defaultOffset); + } + + // set the timezone and offset for $this + $zone = @date_default_timezone_get(); + $this->setTimezone($zone); + + // try to get timezone from date-string + if (!is_int($date)) { + $zone = $this->getTimezoneFromString($date); + $this->setTimezone($zone); + } + + // set datepart + if (($part !== null && $part !== self::TIMESTAMP) or (!is_numeric($date))) { + // switch off dst handling for value setting + $this->setUnixTimestamp($this->getGmtOffset()); + $this->set($date, $part, $this->_locale); + + // DST fix + if (is_array($date) === true) { + if (!isset($date['hour'])) { + $date['hour'] = 0; + } + + $hour = $this->toString('H'); + $hour = $date['hour'] - $hour; + switch ($hour) { + case 1 : + case -23 : + $this->addTimestamp(3600); + break; + case -1 : + case 23 : + $this->subTimestamp(3600); + break; + case 2 : + case -22 : + $this->addTimestamp(7200); + break; + case -2 : + case 22 : + $this->subTimestamp(7200); + break; + } + } + } else { + $this->setUnixTimestamp($date); + } + } + + /** + * Sets class wide options, if no option was given, the actual set options will be returned + * + * @param array $options Options to set + * @throws Zend_Date_Exception + * @return Options array if no option was given + */ + public static function setOptions(array $options = array()) + { + if (empty($options)) { + return self::$_options; + } + foreach ($options as $name => $value) { + $name = strtolower($name); + + if (array_key_exists($name, self::$_options)) { + switch($name) { + case 'format_type' : + if ((strtolower($value) != 'php') && (strtolower($value) != 'iso')) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("Unknown format type ($value) for dates, only 'iso' and 'php' supported", $value); + } + break; + case 'fix_dst' : + if (!is_bool($value)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("'fix_dst' has to be boolean", $value); + } + break; + case 'extend_month' : + if (!is_bool($value)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("'extend_month' has to be boolean", $value); + } + break; + case 'cache' : + if (!$value instanceof Zend_Cache_Core) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("Instance of Zend_Cache expected"); + } + parent::$_cache = $value; + Zend_Locale_Data::setCache($value); + break; + case 'timesync' : + if (!$value instanceof Zend_TimeSync_Protocol) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("Instance of Zend_TimeSync expected"); + } + $date = $value->getInfo(); + parent::$_defaultOffset = $date['offset']; + break; + } + self::$_options[$name] = $value; + } + else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("Unknown option: $name = $value"); + } + } + } + + /** + * Returns this object's internal UNIX timestamp (equivalent to Zend_Date::TIMESTAMP). + * If the timestamp is too large for integers, then the return value will be a string. + * This function does not return the timestamp as an object. + * Use clone() or copyPart() instead. + * + * @return integer|string UNIX timestamp + */ + public function getTimestamp() + { + return $this->getUnixTimestamp(); + } + + /** + * Returns the calculated timestamp + * HINT: timestamps are always GMT + * + * @param string $calc Type of calculation to make + * @param string|integer|array|Zend_Date $stamp Timestamp to calculate, when null the actual timestamp is calculated + * @return Zend_Date|integer + * @throws Zend_Date_Exception + */ + private function _timestamp($calc, $stamp) + { + if ($stamp instanceof Zend_Date) { + // extract timestamp from object + $stamp = $stamp->get(self::TIMESTAMP, true); + } + + if (is_array($stamp)) { + if (isset($stamp['timestamp']) === true) { + $stamp = $stamp['timestamp']; + } else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('no timestamp given in array'); + } + } + + if ($calc === 'set') { + $return = $this->setUnixTimestamp($stamp); + } else { + $return = $this->_calcdetail($calc, $stamp, self::TIMESTAMP, null); + } + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + /** + * Sets a new timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to set + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function setTimestamp($timestamp) + { + return $this->_timestamp('set', $timestamp); + } + + /** + * Adds a timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to add + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function addTimestamp($timestamp) + { + return $this->_timestamp('add', $timestamp); + } + + /** + * Subtracts a timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to sub + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function subTimestamp($timestamp) + { + return $this->_timestamp('sub', $timestamp); + } + + /** + * Compares two timestamps, returning the difference as integer + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to compare + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareTimestamp($timestamp) + { + return $this->_timestamp('cmp', $timestamp); + } + + /** + * Returns a string representation of the object + * Supported format tokens are: + * G - era, y - year, Y - ISO year, M - month, w - week of year, D - day of year, d - day of month + * E - day of week, e - number of weekday (1-7), h - hour 1-12, H - hour 0-23, m - minute, s - second + * A - milliseconds of day, z - timezone, Z - timezone offset, S - fractional second, a - period of day + * + * Additionally format tokens but non ISO conform are: + * SS - day suffix, eee - php number of weekday(0-6), ddd - number of days per month + * l - Leap year, B - swatch internet time, I - daylight saving time, X - timezone offset in seconds + * r - RFC2822 format, U - unix timestamp + * + * Not supported ISO tokens are + * u - extended year, Q - quarter, q - quarter, L - stand alone month, W - week of month + * F - day of week of month, g - modified julian, c - stand alone weekday, k - hour 0-11, K - hour 1-24 + * v - wall zone + * + * @param string $format OPTIONAL Rule for formatting output. If null the default date format is used + * @param string $type OPTIONAL Type for the format string which overrides the standard setting + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function toString($format = null, $type = null, $locale = null) + { + if (is_object($format)) { + if ($format instanceof Zend_Locale) { + $locale = $format; + $format = null; + } else { + $format = (string) $format; + } + } + + if (is_object($type)) { + if ($type instanceof Zend_Locale) { + $locale = $type; + $type = null; + } else { + $type = (string) $type; + } + } + + if (($format !== null) and !defined($format) and + ($format != 'ee') and ($format != 'ss') and Zend_Locale::isLocale($format, null, false)) { + $locale = $format; + $format = null; + } + + if (($type !== null) and ($type != 'php') and ($type != 'iso') and + Zend_Locale::isLocale($type, null, false)) { + $locale = $type; + $type = null; + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($format === null) { + $format = Zend_Locale_Format::getDateFormat($locale) . ' ' . Zend_Locale_Format::getTimeFormat($locale); + } else if (((self::$_options['format_type'] == 'php') && ($type === null)) or ($type == 'php')) { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + + return $this->get($format, $locale); + } + + /** + * Returns a string representation of the date which is equal with the timestamp + * + * @return string + */ + public function __toString() + { + return $this->toString(null, $this->_locale); + } + + /** + * Returns a integer representation of the object + * But returns false when the given part is no value f.e. Month-Name + * + * @param string|integer|Zend_Date $part OPTIONAL Defines the date or datepart to return as integer + * @return integer|false + */ + public function toValue($part = null) + { + $result = $this->get($part); + if (is_numeric($result)) { + return intval("$result"); + } else { + return false; + } + } + + /** + * Returns an array representation of the object + * + * @return array + */ + public function toArray() + { + return array('day' => $this->get(self::DAY_SHORT), + 'month' => $this->get(self::MONTH_SHORT), + 'year' => $this->get(self::YEAR), + 'hour' => $this->get(self::HOUR_SHORT), + 'minute' => $this->get(self::MINUTE_SHORT), + 'second' => $this->get(self::SECOND_SHORT), + 'timezone' => $this->get(self::TIMEZONE), + 'timestamp' => $this->get(self::TIMESTAMP), + 'weekday' => $this->get(self::WEEKDAY_8601), + 'dayofyear' => $this->get(self::DAY_OF_YEAR), + 'week' => $this->get(self::WEEK), + 'gmtsecs' => $this->get(self::TIMEZONE_SECS)); + } + + /** + * Returns a representation of a date or datepart + * This could be for example a localized monthname, the time without date, + * the era or only the fractional seconds. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * + * @param string $part OPTIONAL Part of the date to return, if null the timestamp is returned + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string date or datepart + */ + public function get($part = null, $locale = null) + { + if ($locale === null) { + $locale = $this->getLocale(); + } + + if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) { + $locale = $part; + $part = null; + } + + if ($part === null) { + $part = self::TIMESTAMP; + } + + return $this->date($this->_toToken($part, $locale), $this->getUnixTimestamp(), false); + } + + /** + * Internal method to apply tokens + * + * @param string $part + * @param string $locale + * @return string + */ + private function _toToken($part, $locale) { + // get format tokens + $comment = false; + $format = ''; + $orig = ''; + for ($i = 0; $i < strlen($part); ++$i) { + if ($part[$i] == "'") { + $comment = $comment ? false : true; + if (isset($part[$i+1]) && ($part[$i+1] == "'")) { + $comment = $comment ? false : true; + $format .= "\\'"; + ++$i; + } + + $orig = ''; + continue; + } + + if ($comment) { + $format .= '\\' . $part[$i]; + $orig = ''; + } else { + $orig .= $part[$i]; + if (!isset($part[$i+1]) || (isset($orig[0]) && ($orig[0] != $part[$i+1]))) { + $format .= $this->_parseIsoToDate($orig, $locale); + $orig = ''; + } + } + } + + return $format; + } + + /** + * Internal parsing method + * + * @param string $token + * @param string $locale + * @return string + */ + private function _parseIsoToDate($token, $locale) { + switch($token) { + case self::DAY : + return 'd'; + break; + + case self::WEEKDAY_SHORT : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday)); + return $this->_toComment(iconv_substr($day, 0, 3, 'UTF-8')); + break; + + case self::DAY_SHORT : + return 'j'; + break; + + case self::WEEKDAY : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday))); + break; + + case self::WEEKDAY_8601 : + return 'N'; + break; + + case 'ee' : + return $this->_toComment(str_pad($this->date('N', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::DAY_SUFFIX : + return 'S'; + break; + + case self::WEEKDAY_DIGIT : + return 'w'; + break; + + case self::DAY_OF_YEAR : + return 'z'; + break; + + case 'DDD' : + return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 3, '0', STR_PAD_LEFT)); + break; + + case 'DD' : + return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::WEEKDAY_NARROW : + case 'EEEEE' : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday)); + return $this->_toComment(iconv_substr($day, 0, 1, 'UTF-8')); + break; + + case self::WEEKDAY_NAME : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday))); + break; + + case 'w' : + $week = $this->date('W', $this->getUnixTimestamp(), false); + return $this->_toComment(($week[0] == '0') ? $week[1] : $week); + break; + + case self::WEEK : + return 'W'; + break; + + case self::MONTH_NAME : + $month = $this->date('n', $this->getUnixTimestamp(), false); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month))); + break; + + case self::MONTH : + return 'm'; + break; + + case self::MONTH_NAME_SHORT : + $month = $this->date('n', $this->getUnixTimestamp(), false); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month))); + break; + + case self::MONTH_SHORT : + return 'n'; + break; + + case self::MONTH_DAYS : + return 't'; + break; + + case self::MONTH_NAME_NARROW : + $month = $this->date('n', $this->getUnixTimestamp(), false); + $mon = Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month)); + return $this->_toComment(iconv_substr($mon, 0, 1, 'UTF-8')); + break; + + case self::LEAPYEAR : + return 'L'; + break; + + case self::YEAR_8601 : + return 'o'; + break; + + case self::YEAR : + return 'Y'; + break; + + case self::YEAR_SHORT : + return 'y'; + break; + + case self::YEAR_SHORT_8601 : + return $this->_toComment(substr($this->date('o', $this->getUnixTimestamp(), false), -2, 2)); + break; + + case self::MERIDIEM : + $am = $this->date('a', $this->getUnixTimestamp(), false); + if ($am == 'am') { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'am')); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'pm')); + break; + + case self::SWATCH : + return 'B'; + break; + + case self::HOUR_SHORT_AM : + return 'g'; + break; + + case self::HOUR_SHORT : + return 'G'; + break; + + case self::HOUR_AM : + return 'h'; + break; + + case self::HOUR : + return 'H'; + break; + + case self::MINUTE : + return $this->_toComment(str_pad($this->date('i', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::SECOND : + return $this->_toComment(str_pad($this->date('s', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::MINUTE_SHORT : + return 'i'; + break; + + case self::SECOND_SHORT : + return 's'; + break; + + case self::MILLISECOND : + return $this->_toComment($this->_fractional); + break; + + case self::TIMEZONE_NAME : + case 'vvvv' : + return 'e'; + break; + + case self::DAYLIGHT : + return 'I'; + break; + + case self::GMT_DIFF : + case 'ZZ' : + case 'ZZZ' : + return 'O'; + break; + + case self::GMT_DIFF_SEP : + return 'P'; + break; + + case self::TIMEZONE : + case 'v' : + case 'zz' : + case 'zzz' : + return 'T'; + break; + + case self::TIMEZONE_SECS : + return 'Z'; + break; + + case self::ISO_8601 : + return 'c'; + break; + + case self::RFC_2822 : + return 'r'; + break; + + case self::TIMESTAMP : + return 'U'; + break; + + case self::ERA : + case 'GG' : + case 'GGG' : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0'))); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1'))); + break; + + case self::ERA_NARROW : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0')), 0, 1, 'UTF-8')) . '.'; + } + + return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1')), 0, 1, 'UTF-8')) . '.'; + break; + + case self::ERA_NAME : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '0'))); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '1'))); + break; + + case self::DATES : + return $this->_toToken(Zend_Locale_Format::getDateFormat($locale), $locale); + break; + + case self::DATE_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')), $locale); + break; + + case self::DATE_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')), $locale); + break; + + case self::DATE_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')), $locale); + break; + + case self::DATE_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')), $locale); + break; + + case self::TIMES : + return $this->_toToken(Zend_Locale_Format::getTimeFormat($locale), $locale); + break; + + case self::TIME_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'full'), $locale); + break; + + case self::TIME_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'long'), $locale); + break; + + case self::TIME_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'medium'), $locale); + break; + + case self::TIME_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'short'), $locale); + break; + + case self::DATETIME : + return $this->_toToken(Zend_Locale_Format::getDateTimeFormat($locale), $locale); + break; + + case self::DATETIME_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')), $locale); + break; + + case self::DATETIME_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')), $locale); + break; + + case self::DATETIME_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')), $locale); + break; + + case self::DATETIME_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')), $locale); + break; + + case self::ATOM : + return 'Y\-m\-d\TH\:i\:sP'; + break; + + case self::COOKIE : + return 'l\, d\-M\-y H\:i\:s e'; + break; + + case self::RFC_822 : + return 'D\, d M y H\:i\:s O'; + break; + + case self::RFC_850 : + return 'l\, d\-M\-y H\:i\:s e'; + break; + + case self::RFC_1036 : + return 'D\, d M y H\:i\:s O'; + break; + + case self::RFC_1123 : + return 'D\, d M Y H\:i\:s O'; + break; + + case self::RFC_3339 : + return 'Y\-m\-d\TH\:i\:sP'; + break; + + case self::RSS : + return 'D\, d M Y H\:i\:s O'; + break; + + case self::W3C : + return 'Y\-m\-d\TH\:i\:sP'; + break; + } + + if ($token == '') { + return ''; + } + + switch ($token[0]) { + case 'y' : + if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) { + return 'Y'; + } + + $length = iconv_strlen($token, 'UTF-8'); + return $this->_toComment(str_pad($this->date('Y', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT)); + break; + + case 'Y' : + if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) { + return 'o'; + } + + $length = iconv_strlen($token, 'UTF-8'); + return $this->_toComment(str_pad($this->date('o', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT)); + break; + + case 'A' : + $length = iconv_strlen($token, 'UTF-8'); + $result = $this->_fractional; + $result += $this->date('s', $this->getUnixTimestamp(), false) * 1000; + $result += $this->date('i', $this->getUnixTimestamp(), false) * 60000; + $result += $this->date('H', $this->getUnixTimestamp(), false) * 3600000; + + return $this->_toComment(str_pad($result, $length, '0', STR_PAD_LEFT)); + break; + } + + return $this->_toComment($token); + } + + /** + * Private function to make a comment of a token + * + * @param string $token + * @return string + */ + private function _toComment($token) + { + $token = str_split($token); + $result = ''; + foreach ($token as $tok) { + $result .= '\\' . $tok; + } + + return $result; + } + + /** + * Return digit from standard names (english) + * Faster implementation than locale aware searching + * + * @param string $name + * @return integer Number of this month + * @throws Zend_Date_Exception + */ + private function _getDigitFromName($name) + { + switch($name) { + case "Jan": + return 1; + + case "Feb": + return 2; + + case "Mar": + return 3; + + case "Apr": + return 4; + + case "May": + return 5; + + case "Jun": + return 6; + + case "Jul": + return 7; + + case "Aug": + return 8; + + case "Sep": + return 9; + + case "Oct": + return 10; + + case "Nov": + return 11; + + case "Dec": + return 12; + + default: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('Month ($name) is not a known month'); + } + } + + /** + * Counts the exact year number + * < 70 - 2000 added, >70 < 100 - 1900, others just returned + * + * @param integer $value year number + * @return integer Number of year + */ + public static function getFullYear($value) + { + if ($value >= 0) { + if ($value < 70) { + $value += 2000; + } else if ($value < 100) { + $value += 1900; + } + } + return $value; + } + + /** + * Sets the given date as new date or a given datepart as new datepart returning the new datepart + * This could be for example a localized dayname, the date without time, + * the month or only the seconds. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * + * @param string|integer|array|Zend_Date $date Date or datepart to set + * @param string $part OPTIONAL Part of the date to set, if null the timestamp is set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|string new datepart + * @throws Zend_Date_Exception + */ + public function set($date, $part = null, $locale = null) + { + $zone = $this->getTimezoneFromString($date); + $this->setTimezone($zone); + + $result = $this->_calculate('set', $date, $part, $locale); + return $result; + } + + /** + * Adds a date or datepart to the existing date, by extracting $part from $date, + * and modifying this object by adding that part. The $part is then extracted from + * this object and returned as an integer or numeric string (for large values, or $part's + * corresponding to pre-defined formatted date strings). + * This could be for example a ISO 8601 date, the hour the monthname or only the minute. + * There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu. + * + * @param string|integer|array|Zend_Date $date Date or datepart to add + * @param string $part OPTIONAL Part of the date to add, if null the timestamp is added + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|string new datepart + * @throws Zend_Date_Exception + */ + public function add($date, $part = null, $locale = null) + { + $this->_calculate('add', $date, $part, $locale); + $result = $this->get($part, $locale); + + return $result; + } + + /** + * Subtracts a date from another date. + * This could be for example a RFC2822 date, the time, + * the year or only the timestamp. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * Be aware: Adding -2 Months is not equal to Subtracting 2 Months !!! + * + * @param string|integer|array|Zend_Date $date Date or datepart to subtract + * @param string $part OPTIONAL Part of the date to sub, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|string new datepart + * @throws Zend_Date_Exception + */ + public function sub($date, $part = null, $locale = null) + { + $this->_calculate('sub', $date, $part, $locale); + $result = $this->get($part, $locale); + + return $result; + } + + /** + * Compares a date or datepart with the existing one. + * Returns -1 if earlier, 0 if equal and 1 if later. + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with the date object + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compare($date, $part = null, $locale = null) + { + $compare = $this->_calculate('cmp', $date, $part, $locale); + + if ($compare > 0) { + return 1; + } else if ($compare < 0) { + return -1; + } + return 0; + } + + /** + * Returns a new instance of Zend_Date with the selected part copied. + * To make an exact copy, use PHP's clone keyword. + * For a complete list of supported date part values look into the docu. + * If a date part is copied, all other date parts are set to standard values. + * For example: If only YEAR is copied, the returned date object is equal to + * 01-01-YEAR 00:00:00 (01-01-1970 00:00:00 is equal to timestamp 0) + * If only HOUR is copied, the returned date object is equal to + * 01-01-1970 HOUR:00:00 (so $this contains a timestamp equal to a timestamp of 0 plus HOUR). + * + * @param string $part Part of the date to compare, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL New object's locale. No adjustments to timezone are made. + * @return Zend_Date + */ + public function copyPart($part, $locale = null) + { + $clone = clone $this; // copy all instance variables + $clone->setUnixTimestamp(0); // except the timestamp + if ($locale != null) { + $clone->setLocale($locale); // set an other locale if selected + } + $clone->set($this, $part); + return $clone; + } + + /** + * Internal function, returns the offset of a given timezone + * + * @param string $zone + * @return integer + */ + public function getTimezoneFromString($zone) + { + if (is_array($zone)) { + return $this->getTimezone(); + } + + if ($zone instanceof Zend_Date) { + return $zone->getTimezone(); + } + + $match = array(); + preg_match('/\dZ$/', $zone, $match); + if (!empty($match)) { + return "Etc/UTC"; + } + + preg_match('/([+-]\d{2}):{0,1}\d{2}/', $zone, $match); + if (!empty($match) and ($match[count($match) - 1] <= 12) and ($match[count($match) - 1] >= -12)) { + $zone = "Etc/GMT"; + $zone .= ($match[count($match) - 1] < 0) ? "+" : "-"; + $zone .= (int) abs($match[count($match) - 1]); + return $zone; + } + + preg_match('/([[:alpha:]\/]{3,30})(?!.*([[:alpha:]\/]{3,30}))/', $zone, $match); + try { + if (!empty($match) and (!is_int($match[count($match) - 1]))) { + $oldzone = $this->getTimezone(); + $this->setTimezone($match[count($match) - 1]); + $result = $this->getTimezone(); + $this->setTimezone($oldzone); + if ($result !== $oldzone) { + return $match[count($match) - 1]; + } + } + } catch (Exception $e) { + // fall through + } + + return $this->getTimezone(); + } + + /** + * Calculates the date or object + * + * @param string $calc Calculation to make + * @param string|integer $date Date for calculation + * @param string|integer $comp Second date for calculation + * @param boolean|integer $dst Use dst correction if option is set + * @return integer|string|Zend_Date new timestamp or Zend_Date depending on calculation + */ + private function _assign($calc, $date, $comp = 0, $dst = false) + { + switch ($calc) { + case 'set' : + if (!empty($comp)) { + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $comp)); + } + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + case 'add' : + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + case 'sub' : + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + default : + // cmp - compare + return call_user_func(Zend_Locale_Math::$comp, $comp, $date); + break; + } + + // dst-correction if 'fix_dst' = true and dst !== false but only for non UTC and non GMT + if ((self::$_options['fix_dst'] === true) and ($dst !== false) and ($this->_dst === true)) { + $hour = $this->get(self::HOUR); + if ($hour != $dst) { + if (($dst == ($hour + 1)) or ($dst == ($hour - 23))) { + $value += 3600; + } else if (($dst == ($hour - 1)) or ($dst == ($hour + 23))) { + $value -= 3600; + } + $this->setUnixTimestamp($value); + } + } + return $this->getUnixTimestamp(); + } + + + /** + * Calculates the date or object + * + * @param string $calc Calculation to make, one of: 'add'|'sub'|'cmp'|'copy'|'set' + * @param string|integer|array|Zend_Date $date Date or datepart to calculate with + * @param string $part Part of the date to calculate, if null the timestamp is used + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|string|Zend_Date new timestamp + * @throws Zend_Date_Exception + */ + private function _calculate($calc, $date, $part, $locale) + { + if ($date === null) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('parameter $date must be set, null is not allowed'); + } + + if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) { + $locale = $part; + $part = null; + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + $locale = (string) $locale; + + // Create date parts + $year = $this->get(self::YEAR); + $month = $this->get(self::MONTH_SHORT); + $day = $this->get(self::DAY_SHORT); + $hour = $this->get(self::HOUR_SHORT); + $minute = $this->get(self::MINUTE_SHORT); + $second = $this->get(self::SECOND_SHORT); + // If object extract value + if ($date instanceof Zend_Date) { + $date = $date->get($part, $locale); + } + + if (is_array($date) === true) { + if (empty($part) === false) { + switch($part) { + // Fall through + case self::DAY: + case self::DAY_SHORT: + if (isset($date['day']) === true) { + $date = $date['day']; + } + break; + // Fall through + case self::WEEKDAY_SHORT: + case self::WEEKDAY: + case self::WEEKDAY_8601: + case self::WEEKDAY_DIGIT: + case self::WEEKDAY_NARROW: + case self::WEEKDAY_NAME: + if (isset($date['weekday']) === true) { + $date = $date['weekday']; + $part = self::WEEKDAY_DIGIT; + } + break; + case self::DAY_OF_YEAR: + if (isset($date['day_of_year']) === true) { + $date = $date['day_of_year']; + } + break; + // Fall through + case self::MONTH: + case self::MONTH_SHORT: + case self::MONTH_NAME: + case self::MONTH_NAME_SHORT: + case self::MONTH_NAME_NARROW: + if (isset($date['month']) === true) { + $date = $date['month']; + } + break; + // Fall through + case self::YEAR: + case self::YEAR_SHORT: + case self::YEAR_8601: + case self::YEAR_SHORT_8601: + if (isset($date['year']) === true) { + $date = $date['year']; + } + break; + // Fall through + case self::HOUR: + case self::HOUR_AM: + case self::HOUR_SHORT: + case self::HOUR_SHORT_AM: + if (isset($date['hour']) === true) { + $date = $date['hour']; + } + break; + // Fall through + case self::MINUTE: + case self::MINUTE_SHORT: + if (isset($date['minute']) === true) { + $date = $date['minute']; + } + break; + // Fall through + case self::SECOND: + case self::SECOND_SHORT: + if (isset($date['second']) === true) { + $date = $date['second']; + } + break; + // Fall through + case self::TIMEZONE: + case self::TIMEZONE_NAME: + if (isset($date['timezone']) === true) { + $date = $date['timezone']; + } + break; + case self::TIMESTAMP: + if (isset($date['timestamp']) === true) { + $date = $date['timestamp']; + } + break; + case self::WEEK: + if (isset($date['week']) === true) { + $date = $date['week']; + } + break; + case self::TIMEZONE_SECS: + if (isset($date['gmtsecs']) === true) { + $date = $date['gmtsecs']; + } + break; + default: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("datepart for part ($part) not found in array"); + break; + } + } else { + $hours = 0; + if (isset($date['hour']) === true) { + $hours = $date['hour']; + } + $minutes = 0; + if (isset($date['minute']) === true) { + $minutes = $date['minute']; + } + $seconds = 0; + if (isset($date['second']) === true) { + $seconds = $date['second']; + } + $months = 0; + if (isset($date['month']) === true) { + $months = $date['month']; + } + $days = 0; + if (isset($date['day']) === true) { + $days = $date['day']; + } + $years = 0; + if (isset($date['year']) === true) { + $years = $date['year']; + } + return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, $months, $days, $years, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), $hour); + } + } + + // $date as object, part of foreign date as own date + switch($part) { + + // day formats + case self::DAY: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + intval($day), 1970, true), $hour); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", $date); + break; + + case self::WEEKDAY_SHORT: + $daylist = Zend_Locale_Data::getList($locale, 'day'); + $weekday = (int) $this->get(self::WEEKDAY_DIGIT, $locale); + $cnt = 0; + + foreach ($daylist as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 3, 'UTF-8')) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date); + break; + + case self::DAY_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + intval($day), 1970, true), $hour); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", $date); + break; + + case self::WEEKDAY: + $daylist = Zend_Locale_Data::getList($locale, 'day'); + $weekday = (int) $this->get(self::WEEKDAY_DIGIT, $locale); + $cnt = 0; + + foreach ($daylist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date); + break; + + case self::WEEKDAY_8601: + $weekday = (int) $this->get(self::WEEKDAY_8601, $locale); + if ((intval($date) > 0) and (intval($date) < 8)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date); + break; + + case self::DAY_SUFFIX: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('day suffix not supported', $date); + break; + + case self::WEEKDAY_DIGIT: + $weekday = (int) $this->get(self::WEEKDAY_DIGIT, $locale); + if (is_numeric($date) and (intval($date) >= 0) and (intval($date) < 7)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $date, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date); + break; + + case self::DAY_OF_YEAR: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $date, 1970, true), + $this->mktime(0, 0, 0, $month, 1 + $day, 1970, true), $hour); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", $date); + break; + + case self::WEEKDAY_NARROW: + $daylist = Zend_Locale_Data::getList($locale, 'day', array('gregorian', 'format', 'abbreviated')); + $weekday = (int) $this->get(self::WEEKDAY_DIGIT, $locale); + $cnt = 0; + foreach ($daylist as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 1, 'UTF-8')) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date); + break; + + case self::WEEKDAY_NAME: + $daylist = Zend_Locale_Data::getList($locale, 'day', array('gregorian', 'format', 'abbreviated')); + $weekday = (int) $this->get(self::WEEKDAY_DIGIT, $locale); + $cnt = 0; + foreach ($daylist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", $date); + break; + + // week formats + case self::WEEK: + if (is_numeric($date)) { + $week = (int) $this->get(self::WEEK, $locale); + return $this->_assign($calc, parent::mktime(0, 0, 0, 1, 1 + ($date * 7), 1970, true), + parent::mktime(0, 0, 0, 1, 1 + ($week * 7), 1970, true), $hour); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, week expected", $date); + break; + + // month formats + case self::MONTH_NAME: + $monthlist = Zend_Locale_Data::getList($locale, 'month'); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc == 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date); + break; + + case self::MONTH: + if (is_numeric($date)) { + $fixday = 0; + if ($calc == 'add') { + $date += $month; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $date; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date); + break; + + case self::MONTH_NAME_SHORT: + $monthlist = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'format', 'abbreviated')); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc == 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date); + break; + + case self::MONTH_SHORT: + if (is_numeric($date) === true) { + $fixday = 0; + if ($calc === 'add') { + $date += $month; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc === 'sub') { + $date = $month - $date; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date); + break; + + case self::MONTH_DAYS: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('month days not supported', $date); + break; + + case self::MONTH_NAME_NARROW: + $monthlist = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'stand-alone', 'narrow')); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) === strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc === 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc === 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", $date); + break; + + // year formats + case self::LEAPYEAR: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('leap year not supported', $date); + break; + + case self::YEAR_8601: + if (is_numeric($date)) { + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, intval($date), true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", $date); + break; + + case self::YEAR: + if (is_numeric($date)) { + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, intval($date), true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", $date); + break; + + case self::YEAR_SHORT: + if (is_numeric($date)) { + $date = intval($date); + if (($calc == 'set') || ($calc == 'cmp')) { + $date = self::getFullYear($date); + } + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", $date); + break; + + case self::YEAR_SHORT_8601: + if (is_numeric($date)) { + $date = intval($date); + if (($calc === 'set') || ($calc === 'cmp')) { + $date = self::getFullYear($date); + } + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", $date); + break; + + // time formats + case self::MERIDIEM: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('meridiem not supported', $date); + break; + + case self::SWATCH: + if (is_numeric($date)) { + $rest = intval($date); + $hours = floor($rest * 24 / 1000); + $rest = $rest - ($hours * 1000 / 24); + $minutes = floor($rest * 1440 / 1000); + $rest = $rest - ($minutes * 1000 / 1440); + $seconds = floor($rest * 86400 / 1000); + return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, 1, 1, 1970, true), + $this->mktime($hour, $minute, $second, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, swatchstamp expected", $date); + break; + + case self::HOUR_SHORT_AM: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", $date); + break; + + case self::HOUR_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", $date); + break; + + case self::HOUR_AM: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", $date); + break; + + case self::HOUR: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", $date); + break; + + case self::MINUTE: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, intval($date), 0, 1, 1, 1970, true), + $this->mktime(0, $minute, 0, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", $date); + break; + + case self::SECOND: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, intval($date), 1, 1, 1970, true), + $this->mktime(0, 0, $second, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, second expected", $date); + break; + + case self::MILLISECOND: + if (is_numeric($date)) { + switch($calc) { + case 'set' : + return $this->setMillisecond($date); + break; + case 'add' : + return $this->addMillisecond($date); + break; + case 'sub' : + return $this->subMillisecond($date); + break; + } + return $this->compareMillisecond($date); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, milliseconds expected", $date); + break; + + case self::MINUTE_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, intval($date), 0, 1, 1, 1970, true), + $this->mktime(0, $minute, 0, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", $date); + break; + + case self::SECOND_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, intval($date), 1, 1, 1970, true), + $this->mktime(0, 0, $second, 1, 1, 1970, true), false); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, second expected", $date); + break; + + // timezone formats + // break intentionally omitted + case self::TIMEZONE_NAME: + case self::TIMEZONE: + case self::TIMEZONE_SECS: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('timezone not supported', $date); + break; + + case self::DAYLIGHT: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('daylight not supported', $date); + break; + + case self::GMT_DIFF: + case self::GMT_DIFF_SEP: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('gmtdiff not supported', $date); + break; + + // date strings + case self::ISO_8601: + // (-)YYYY-MM-dd + preg_match('/^(-{0,1}\d{4})-(\d{2})-(\d{2})/', $date, $datematch); + // (-)YY-MM-dd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{2})-(\d{2})-(\d{2})/', $date, $datematch); + } + // (-)YYYYMMdd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{4})(\d{2})(\d{2})/', $date, $datematch); + } + // (-)YYMMdd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{2})(\d{2})(\d{2})/', $date, $datematch); + } + $tmpdate = $date; + if (!empty($datematch)) { + $dateMatchCharCount = iconv_strlen($datematch[0], 'UTF-8'); + $tmpdate = iconv_substr($date, + $dateMatchCharCount, + iconv_strlen($date, 'UTF-8') - $dateMatchCharCount, + 'UTF-8'); + } + // (T)hh:mm:ss + preg_match('/[T,\s]{0,1}(\d{2}):(\d{2}):(\d{2})/', $tmpdate, $timematch); + if (empty($timematch)) { + preg_match('/[T,\s]{0,1}(\d{2})(\d{2})(\d{2})/', $tmpdate, $timematch); + } + if (empty($datematch) and empty($timematch)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("unsupported ISO8601 format ($date)", $date); + } + if (!empty($timematch)) { + $timeMatchCharCount = iconv_strlen($timematch[0], 'UTF-8'); + $tmpdate = iconv_substr($tmpdate, + $timeMatchCharCount, + iconv_strlen($tmpdate, 'UTF-8') - $timeMatchCharCount, + 'UTF-8'); + } + if (empty($datematch)) { + $datematch[1] = 1970; + $datematch[2] = 1; + $datematch[3] = 1; + } else if (iconv_strlen($datematch[1], 'UTF-8') == 2) { + $datematch[1] = self::getFullYear($datematch[1]); + } + if (empty($timematch)) { + $timematch[1] = 0; + $timematch[2] = 0; + $timematch[3] = 0; + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$datematch[2]; + --$month; + --$datematch[3]; + --$day; + $datematch[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($timematch[1], $timematch[2], $timematch[3], 1 + $datematch[2], 1 + $datematch[3], 1970 + $datematch[1], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::RFC_2822: + $result = preg_match('/^\w{3},\s(\d{1,2})\s(\w{3})\s(\d{4})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4})$/', $date, $match); + if (!$result) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("no RFC 2822 format ($date)", $date); + } + + $months = $this->_getDigitFromName($match[2]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::TIMESTAMP: + if (is_numeric($date)) { + return $this->_assign($calc, $date, $this->getUnixTimestamp()); + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, timestamp expected", $date); + break; + + // additional formats + // break intentionally omitted + case self::ERA: + case self::ERA_NAME: + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('era not supported', $date); + break; + + case self::DATES: + try { + $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATE_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATE_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')){ + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATE_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATE_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + $parsed['year'] = self::getFullYear($parsed['year']); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::TIMES: + try { + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + $parsed = Zend_Locale_Format::getTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::TIME_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::TIME_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::TIME_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::TIME_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATETIME: + try { + $parsed = Zend_Locale_Format::getDateTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATETIME_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATETIME_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')){ + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATETIME_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + case self::DATETIME_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + $parsed['year'] = self::getFullYear($parsed['year']); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + break; + + // ATOM and RFC_3339 are identical + case self::ATOM: + case self::RFC_3339: + $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\d{0,4}([+-]{1}\d{2}:\d{2}|Z)$/', $date, $match); + if (!$result) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, ATOM format expected", $date); + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$match[2]; + --$month; + --$match[3]; + --$day; + $match[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::COOKIE: + $result = preg_match("/^\w{6,9},\s(\d{2})-(\w{3})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s.{3,20}$/", $date, $match); + if (!$result) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, COOKIE format expected", $date); + } + $matchStartPos = iconv_strpos($match[0], ' ', 0, 'UTF-8') + 1; + $match[0] = iconv_substr($match[0], + $matchStartPos, + iconv_strlen($match[0], 'UTF-8') - $matchStartPos, + 'UTF-8'); + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RFC_822: + case self::RFC_1036: + // new RFC 822 format, identical to RFC 1036 standard + $result = preg_match('/^\w{0,3},{0,1}\s{0,1}(\d{1,2})\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match); + if (!$result) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 822 date format expected", $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::RFC_850: + $result = preg_match('/^\w{6,9},\s(\d{2})-(\w{3})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s.{3,21}$/', $date, $match); + if (!$result) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 850 date format expected", $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RFC_1123: + $result = preg_match('/^\w{0,3},{0,1}\s{0,1}(\d{1,2})\s(\w{3})\s(\d{2,4})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match); + if (!$result) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 1123 date format expected", $date); + } + + $months = $this->_getDigitFromName($match[2]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RSS: + $result = preg_match('/^\w{3},\s(\d{2})\s(\w{3})\s(\d{2,4})\s(\d{1,2}):(\d{2}):(\d{2})\s.{1,21}$/', $date, $match); + if (!$result) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, RSS date format expected", $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::W3C: + $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})[+-]{1}\d{2}:\d{2}$/', $date, $match); + if (!$result) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid date ($date) operand, W3C date format expected", $date); + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$match[2]; + --$month; + --$match[3]; + --$day; + $match[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + default: + if (!is_numeric($date) || !empty($part)) { + try { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + if (empty($part)) { + $part = Zend_Locale_Format::getDateFormat($locale) . " "; + $part .= Zend_Locale_Format::getTimeFormat($locale); + } + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $part, 'locale' => $locale, 'fix_date' => true, 'format_type' => 'iso')); + if ((strpos(strtoupper($part), 'YY') !== false) and (strpos(strtoupper($part), 'YYYY') === false)) { + $parsed['year'] = self::getFullYear($parsed['year']); + } + if (($calc == 'set') || ($calc == 'cmp')) { + if (isset($parsed['month'])) { + --$parsed['month']; + } else { + $parsed['month'] = 0; + } + if (isset($parsed['day'])) { + --$parsed['day']; + } else { + $parsed['day'] = 0; + } + if (isset($parsed['year'])) { + $parsed['year'] -= 1970; + } else { + $parsed['year'] = 0; + } + } + return $this->_assign($calc, $this->mktime( + isset($parsed['hour']) ? $parsed['hour'] : 0, + isset($parsed['minute']) ? $parsed['minute'] : 0, + isset($parsed['second']) ? $parsed['second'] : 0, + 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], + false), $this->getUnixTimestamp(), false); + } catch (Zend_Locale_Exception $e) { + if (!is_numeric($date)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage(), $date); + } + } + } + return $this->_assign($calc, $date, $this->getUnixTimestamp(), false); + break; + } + } + + /** + * Returns true when both date objects or date parts are equal. + * For example: + * 15.May.2000 <-> 15.June.2000 Equals only for Day or Year... all other will return false + * + * @param string|integer|array|Zend_Date $date Date or datepart to equal with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function equals($date, $part = null, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == 0) { + return true; + } + return false; + } + + /** + * Returns if the given date or datepart is earlier + * For example: + * 15.May.2000 <-> 13.June.1999 will return true for day, year and date, but not for month + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function isEarlier($date, $part = null, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == -1) { + return true; + } + return false; + } + + /** + * Returns if the given date or datepart is later + * For example: + * 15.May.2000 <-> 13.June.1999 will return true for month but false for day, year and date + * Returns if the given date is later + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function isLater($date, $part = null, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == 1) { + return true; + } + return false; + } + + /** + * Returns only the time of the date as new Zend_Date object + * For example: + * 15.May.2000 10:11:23 will return a dateobject equal to 01.Jan.1970 10:11:23 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getTime($locale = null) + { + return $this->copyPart(self::TIME_MEDIUM, $locale); + } + + /** + * Returns the calculated time + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $time Time to calculate with, if null the actual time is taken + * @param string $format Timeformat for parsing input + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new time + * @throws Zend_Date_Exception + */ + private function _time($calc, $time, $format, $locale) + { + if ($time === null) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('parameter $time must be set, null is not allowed'); + } + + if ($time instanceof Zend_Date) { + // extract time from object + $time = $time->get('HH:mm:ss'); + } else { + if (is_array($time)) { + if ((isset($time['hour']) === true) or (isset($time['minute']) === true) or + (isset($time['second']) === true)) { + $parsed = $time; + } else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("no hour, minute or second given in array"); + } + } else { + if (self::$_options['format_type'] == 'php') { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + try { + if ($locale === null) { + $locale = $this->getLocale(); + } + + $parsed = Zend_Locale_Format::getTime($time, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso')); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage()); + } + } + $time = str_pad($parsed['hour'], 2, '0', STR_PAD_LEFT) . ":"; + $time .= str_pad($parsed['minute'], 2, '0', STR_PAD_LEFT) . ":"; + $time .= str_pad($parsed['second'], 2, '0', STR_PAD_LEFT); + } + + $return = $this->_calcdetail($calc, $time, self::TIMES, 'de'); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new time for the date object. Format defines how to parse the time string. + * Also a complete date can be given, but only the time is used for setting. + * For example: dd.MMMM.yyTHH:mm' and 'ss sec'-> 10.May.07T25:11 and 44 sec => 1h11min44sec + 1 day + * Returned is the new date object and the existing date is left as it was before + * + * @param string|integer|array|Zend_Date $time Time to set + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new time + * @throws Zend_Date_Exception + */ + public function setTime($time, $format = null, $locale = null) + { + return $this->_time('set', $time, $format, $locale); + } + + + /** + * Adds a time to the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> +10 hours + * + * @param string|integer|array|Zend_Date $time Time to add + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new time + * @throws Zend_Date_Exception + */ + public function addTime($time, $format = null, $locale = null) + { + return $this->_time('add', $time, $format, $locale); + } + + + /** + * Subtracts a time from the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> -10 hours + * + * @param string|integer|array|Zend_Date $time Time to sub + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new time + * @throws Zend_Date_Exception + */ + public function subTime($time, $format = null, $locale = null) + { + return $this->_time('sub', $time, $format, $locale); + } + + + /** + * Compares the time from the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to default. + * If no format us given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> 10 hours + * + * @param string|integer|array|Zend_Date $time Time to compare + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareTime($time, $format = null, $locale = null) + { + return $this->_time('cmp', $time, $format, $locale); + } + + /** + * Returns a clone of $this, with the time part set to 00:00:00. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDate($locale = null) + { + $date = $this->copyPart(self::DATE_MEDIUM, $locale); + $date->addTimestamp($this->getGmtOffset()); + return $date; + } + + /** + * Returns the calculated date + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $date Date to calculate with, if null the actual date is taken + * @param string $format Date format for parsing + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + private function _date($calc, $date, $format, $locale) + { + if ($date === null) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('parameter $date must be set, null is not allowed'); + } + + if ($date instanceof Zend_Date) { + // extract date from object + $date = $date->get('d.M.Y'); + } else { + if (is_array($date)) { + if ((isset($date['year']) === true) or (isset($date['month']) === true) or + (isset($date['day']) === true)) { + $parsed = $date; + } else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("no day,month or year given in array"); + } + } else { + if (self::$_options['format_type'] == 'php') { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + try { + if ($locale === null) { + $locale = $this->getLocale(); + } + + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso')); + if ((strpos(strtoupper($format), 'YY') !== false) and (strpos(strtoupper($format), 'YYYY') === false)) { + $parsed['year'] = self::getFullYear($parsed['year']); + } + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage()); + } + } + $date = $parsed['day'] . "." . $parsed['month'] . "." . $parsed['year']; + } + + $return = $this->_calcdetail($calc, $date, self::DATE_MEDIUM, 'de'); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new date for the date object. Format defines how to parse the date string. + * Also a complete date with time can be given, but only the date is used for setting. + * For example: MMMM.yy HH:mm-> May.07 22:11 => 01.May.07 00:00 + * Returned is the new date object and the existing time is left as it was before + * + * @param string|integer|array|Zend_Date $date Date to set + * @param string $format OPTIONAL Date format for parsing + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setDate($date, $format = null, $locale = null) + { + return $this->_date('set', $date, $format, $locale); + } + + + /** + * Adds a date to the existing date object. Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: MM.dd.YYYY -> 10 -> +10 months + * + * @param string|integer|array|Zend_Date $date Date to add + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addDate($date, $format = null, $locale = null) + { + return $this->_date('add', $date, $format, $locale); + } + + + /** + * Subtracts a date from the existing date object. Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: MM.dd.YYYY -> 10 -> -10 months + * Be aware: Subtracting 2 months is not equal to Adding -2 months !!! + * + * @param string|integer|array|Zend_Date $date Date to sub + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subDate($date, $format = null, $locale = null) + { + return $this->_date('sub', $date, $format, $locale); + } + + + /** + * Compares the date from the existing date object, ignoring the time. + * Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: 10.01.2000 => 10.02.1999 -> false + * + * @param string|integer|array|Zend_Date $date Date to compare + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function compareDate($date, $format = null, $locale = null) + { + return $this->_date('cmp', $date, $format, $locale); + } + + + /** + * Returns the full ISO 8601 date from the date object. + * Always the complete ISO 8601 specifiction is used. If an other ISO date is needed + * (ISO 8601 defines several formats) use toString() instead. + * This function does not return the ISO date as object. Use copy() instead. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function getIso($locale = null) + { + return $this->get(self::ISO_8601, $locale); + } + + + /** + * Sets a new date for the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> 01.Sept.2005 00:00:00, 20050201T10:00:30 -> 01.Feb.2005 10h00m30s + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setIso($date, $locale = null) + { + return $this->_calcvalue('set', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Adds a ISO date to the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> + 01.Sept.2005 00:00:00, 10:00:00 -> +10h + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addIso($date, $locale = null) + { + return $this->_calcvalue('add', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Subtracts a ISO date from the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subIso($date, $locale = null) + { + return $this->_calcvalue('sub', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Compares a ISO date with the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h + * Returns if equal, earlier or later + * + * @param string|integer|Zend_Date $date ISO Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareIso($date, $locale = null) + { + return $this->_calcvalue('cmp', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Returns a RFC 822 compilant datestring from the date object. + * This function does not return the RFC date as object. Use copy() instead. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function getArpa($locale = null) + { + return $this->get(self::RFC_822, $locale); + } + + + /** + * Sets a RFC 822 date as new date for the date object. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setArpa($date, $locale = null) + { + return $this->_calcvalue('set', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Adds a RFC 822 date to the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 Date to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addArpa($date, $locale = null) + { + return $this->_calcvalue('add', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Subtracts a RFC 822 date from the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subArpa($date, $locale = null) + { + return $this->_calcvalue('sub', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Compares a RFC 822 compilant date with the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returns if equal, earlier or later + * + * @param string|integer|Zend_Date $date RFC 822 Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareArpa($date, $locale = null) + { + return $this->_calcvalue('cmp', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Check if location is supported + * + * @param $location array - locations array + * @return $horizon float + */ + private function _checkLocation($location) + { + if (!isset($location['longitude']) or !isset($location['latitude'])) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('Location must include \'longitude\' and \'latitude\'', $location); + } + if (($location['longitude'] > 180) or ($location['longitude'] < -180)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('Longitude must be between -180 and 180', $location); + } + if (($location['latitude'] > 90) or ($location['latitude'] < -90)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('Latitude must be between -90 and 90', $location); + } + + if (!isset($location['horizon'])){ + $location['horizon'] = 'effective'; + } + + switch ($location['horizon']) { + case 'civil' : + return -0.104528; + break; + case 'nautic' : + return -0.207912; + break; + case 'astronomic' : + return -0.309017; + break; + default : + return -0.0145439; + break; + } + } + + + /** + * Returns the time of sunrise for this date and a given location as new date object + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param $location array - location of sunrise + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function getSunrise($location) + { + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, true), self::TIMESTAMP); + return $result; + } + + + /** + * Returns the time of sunset for this date and a given location as new date object + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param $location array - location of sunset + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function getSunset($location) + { + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, false), self::TIMESTAMP); + return $result; + } + + + /** + * Returns an array with the sunset and sunrise dates for all horizon types + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param $location array - location of suninfo + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return array - [sunset|sunrise][effective|civil|nautic|astronomic] + * @throws Zend_Date_Exception + */ + public function getSunInfo($location) + { + $suninfo = array(); + for ($i = 0; $i < 4; ++$i) { + switch ($i) { + case 0 : + $location['horizon'] = 'effective'; + break; + case 1 : + $location['horizon'] = 'civil'; + break; + case 2 : + $location['horizon'] = 'nautic'; + break; + case 3 : + $location['horizon'] = 'astronomic'; + break; + } + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, true), self::TIMESTAMP); + $suninfo['sunrise'][$location['horizon']] = $result; + $result = clone $this; + $result->set($this->calcSun($location, $horizon, false), self::TIMESTAMP); + $suninfo['sunset'][$location['horizon']] = $result; + } + return $suninfo; + } + + + /** + * Check a given year for leap year. + * + * @param integer|array|Zend_Date $year Year to check + * @return boolean + */ + public static function checkLeapYear($year) + { + if ($year instanceof Zend_Date) { + $year = (int) $year->get(self::YEAR); + } + if (is_array($year)) { + if (isset($year['year']) === true) { + $year = $year['year']; + } else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("no year given in array"); + } + } + if (!is_numeric($year)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("year ($year) has to be integer for checkLeapYear()", $year); + } + + return (bool) parent::isYearLeapYear($year); + } + + + /** + * Returns true, if the year is a leap year. + * + * @return boolean + */ + public function isLeapYear() + { + return self::checkLeapYear($this); + } + + + /** + * Returns if the set date is todays date + * + * @return boolean + */ + public function isToday() + { + $today = $this->date('Ymd', $this->_getTime()); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return ($today == $day); + } + + + /** + * Returns if the set date is yesterdays date + * + * @return boolean + */ + public function isYesterday() + { + list($year, $month, $day) = explode('-', $this->date('Y-m-d', $this->_getTime())); + // adjusts for leap days and DST changes that are timezone specific + $yesterday = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day -1, $year)); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return $day == $yesterday; + } + + + /** + * Returns if the set date is tomorrows date + * + * @return boolean + */ + public function isTomorrow() + { + list($year, $month, $day) = explode('-', $this->date('Y-m-d', $this->_getTime())); + // adjusts for leap days and DST changes that are timezone specific + $tomorrow = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day +1, $year)); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return $day == $tomorrow; + } + + /** + * Returns the actual date as new date object + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public static function now($locale = null) + { + return new Zend_Date(time(), self::TIMESTAMP, $locale); + } + + /** + * Calculate date details + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $date Date or Part to calculate + * @param string $part Datepart for Calculation + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|string new date + * @throws Zend_Date_Exception + */ + private function _calcdetail($calc, $date, $type, $locale) + { + switch($calc) { + case 'set' : + return $this->set($date, $type, $locale); + break; + case 'add' : + return $this->add($date, $type, $locale); + break; + case 'sub' : + return $this->sub($date, $type, $locale); + break; + } + return $this->compare($date, $type, $locale); + } + + /** + * Internal calculation, returns the requested date type + * + * @param string $calc Calculation to make + * @param string|integer|Zend_Date $value Datevalue to calculate with, if null the actual value is taken + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + private function _calcvalue($calc, $value, $type, $parameter, $locale) + { + if ($value === null) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("parameter $type must be set, null is not allowed"); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($value instanceof Zend_Date) { + // extract value from object + $value = $value->get($parameter, $locale); + } else if (!is_array($value) && !is_numeric($value) && ($type != 'iso') && ($type != 'arpa')) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid $type ($value) operand", $value); + } + + $return = $this->_calcdetail($calc, $value, $parameter, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Returns only the year from the date object as new object. + * For example: 10.May.2000 10:30:00 -> 01.Jan.2000 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getYear($locale = null) + { + return $this->copyPart(self::YEAR, $locale); + } + + + /** + * Sets a new year + * If the year is between 0 and 69, 2000 will be set (2000-2069) + * If the year if between 70 and 99, 1999 will be set (1970-1999) + * 3 or 4 digit years are set as expected. If you need to set year 0-99 + * use set() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $date Year to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setYear($year, $locale = null) + { + return $this->_calcvalue('set', $year, 'year', self::YEAR, $locale); + } + + + /** + * Adds the year to the existing date object + * If the year is between 0 and 69, 2000 will be added (2000-2069) + * If the year if between 70 and 99, 1999 will be added (1970-1999) + * 3 or 4 digit years are added as expected. If you need to add years from 0-99 + * use add() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $date Year to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addYear($year, $locale = null) + { + return $this->_calcvalue('add', $year, 'year', self::YEAR, $locale); + } + + + /** + * Subs the year from the existing date object + * If the year is between 0 and 69, 2000 will be subtracted (2000-2069) + * If the year if between 70 and 99, 1999 will be subtracted (1970-1999) + * 3 or 4 digit years are subtracted as expected. If you need to subtract years from 0-99 + * use sub() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $date Year to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subYear($year, $locale = null) + { + return $this->_calcvalue('sub', $year, 'year', self::YEAR, $locale); + } + + + /** + * Compares the year with the existing date object, ignoring other date parts. + * For example: 10.03.2000 -> 15.02.2000 -> true + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $year Year to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareYear($year, $locale = null) + { + return $this->_calcvalue('cmp', $year, 'year', self::YEAR, $locale); + } + + + /** + * Returns only the month from the date object as new object. + * For example: 10.May.2000 10:30:00 -> 01.May.1970 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getMonth($locale = null) + { + return $this->copyPart(self::MONTH, $locale); + } + + + /** + * Returns the calculated month + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $month Month to calculate with, if null the actual month is taken + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new time + * @throws Zend_Date_Exception + */ + private function _month($calc, $month, $locale) + { + if ($month === null) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('parameter $month must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($month instanceof Zend_Date) { + // extract month from object + $found = $month->get(self::MONTH_SHORT, $locale); + } else { + if (is_numeric($month)) { + $found = $month; + } else if (is_array($month)) { + if (isset($month['month']) === true) { + $month = $month['month']; + } else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("no month given in array"); + } + } else { + $monthlist = Zend_Locale_Data::getList($locale, 'month'); + $monthlist2 = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'format', 'abbreviated')); + + $monthlist = array_merge($monthlist, $monthlist2); + $found = 0; + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($month)) { + $found = ($key % 12) + 1; + break; + } + ++$cnt; + } + if ($found == 0) { + foreach ($monthlist2 as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 1, 'UTF-8')) == strtoupper($month)) { + $found = $key + 1; + break; + } + ++$cnt; + } + } + if ($found == 0) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("unknown month name ($month)", $month); + } + } + } + $return = $this->_calcdetail($calc, $found, self::MONTH_SHORT, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new month + * The month can be a number or a string. Setting months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setMonth($month, $locale = null) + { + return $this->_month('set', $month, $locale); + } + + + /** + * Adds months to the existing date object. + * The month can be a number or a string. Adding months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addMonth($month, $locale = null) + { + return $this->_month('add', $month, $locale); + } + + + /** + * Subtracts months from the existing date object. + * The month can be a number or a string. Subtracting months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subMonth($month, $locale = null) + { + return $this->_month('sub', $month, $locale); + } + + + /** + * Compares the month with the existing date object, ignoring other date parts. + * For example: 10.03.2000 -> 15.03.1950 -> true + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $month Month to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareMonth($month, $locale = null) + { + return $this->_month('cmp', $month, $locale); + } + + + /** + * Returns the day as new date object + * Example: 20.May.1986 -> 20.Jan.1970 00:00:00 + * + * @param $locale string|Zend_Locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDay($locale = null) + { + return $this->copyPart(self::DAY_SHORT, $locale); + } + + + /** + * Returns the calculated day + * + * @param $calc string Type of calculation to make + * @param $day string|integer|Zend_Date Day to calculate, when null the actual day is calculated + * @param $locale string|Zend_Locale Locale for parsing input + * @return Zend_Date|integer + */ + private function _day($calc, $day, $locale) + { + if ($day === null) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('parameter $day must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($day instanceof Zend_Date) { + $day = $day->get(self::DAY_SHORT, $locale); + } + + if (is_numeric($day)) { + $type = self::DAY_SHORT; + } else if (is_array($day)) { + if (isset($day['day']) === true) { + $day = $day['day']; + $type = self::WEEKDAY; + } else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("no day given in array"); + } + } else { + switch (iconv_strlen($day, 'UTF-8')) { + case 1 : + $type = self::WEEKDAY_NARROW; + break; + case 2: + $type = self::WEEKDAY_NAME; + break; + case 3: + $type = self::WEEKDAY_SHORT; + break; + default: + $type = self::WEEKDAY; + break; + } + } + $return = $this->_calcdetail($calc, $day, $type, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new day + * The day can be a number or a string. Setting days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: setDay('Montag', 'de_AT'); will set the monday of this week as day. + * + * @param string|integer|array|Zend_Date $month Day to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setDay($day, $locale = null) + { + return $this->_day('set', $day, $locale); + } + + + /** + * Adds days to the existing date object. + * The day can be a number or a string. Adding days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: addDay('Montag', 'de_AT'); will add the number of days until the next monday + * + * @param string|integer|array|Zend_Date $month Day to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addDay($day, $locale = null) + { + return $this->_day('add', $day, $locale); + } + + + /** + * Subtracts days from the existing date object. + * The day can be a number or a string. Subtracting days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: subDay('Montag', 'de_AT'); will sub the number of days until the previous monday + * + * @param string|integer|array|Zend_Date $month Day to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subDay($day, $locale = null) + { + return $this->_day('sub', $day, $locale); + } + + + /** + * Compares the day with the existing date object, ignoring other date parts. + * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $day Day to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareDay($day, $locale = null) + { + return $this->_day('cmp', $day, $locale); + } + + + /** + * Returns the weekday as new date object + * Weekday is always from 1-7 + * Example: 09-Jan-2007 -> 2 = Tuesday -> 02-Jan-1970 (when 02.01.1970 is also Tuesday) + * + * @param $locale string|Zend_Locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getWeekday($locale = null) + { + return $this->copyPart(self::WEEKDAY, $locale); + } + + + /** + * Returns the calculated weekday + * + * @param $calc string Type of calculation to make + * @param $weekday string|integer|array|Zend_Date Weekday to calculate, when null the actual weekday is calculated + * @param $locale string|Zend_Locale Locale for parsing input + * @return Zend_Date|integer + * @throws Zend_Date_Exception + */ + private function _weekday($calc, $weekday, $locale) + { + if ($weekday === null) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('parameter $weekday must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($weekday instanceof Zend_Date) { + $weekday = $weekday->get(self::WEEKDAY_8601, $locale); + } + + if (is_numeric($weekday)) { + $type = self::WEEKDAY_8601; + } else if (is_array($weekday)) { + if (isset($weekday['weekday']) === true) { + $weekday = $weekday['weekday']; + $type = self::WEEKDAY; + } else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("no weekday given in array"); + } + } else { + switch(iconv_strlen($weekday, 'UTF-8')) { + case 1: + $type = self::WEEKDAY_NARROW; + break; + case 2: + $type = self::WEEKDAY_NAME; + break; + case 3: + $type = self::WEEKDAY_SHORT; + break; + default: + $type = self::WEEKDAY; + break; + } + } + $return = $this->_calcdetail($calc, $weekday, $type, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new weekday + * The weekday can be a number or a string. If a localized weekday name is given, + * then it will be parsed as a date in $locale (defaults to the same locale as $this). + * Returned is the new date object. + * Example: setWeekday(3); will set the wednesday of this week as day. + * + * @param string|integer|array|Zend_Date $month Weekday to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setWeekday($weekday, $locale = null) + { + return $this->_weekday('set', $weekday, $locale); + } + + + /** + * Adds weekdays to the existing date object. + * The weekday can be a number or a string. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: addWeekday(3); will add the difference of days from the begining of the month until + * wednesday. + * + * @param string|integer|array|Zend_Date $month Weekday to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addWeekday($weekday, $locale = null) + { + return $this->_weekday('add', $weekday, $locale); + } + + + /** + * Subtracts weekdays from the existing date object. + * The weekday can be a number or a string. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: subWeekday(3); will subtract the difference of days from the begining of the month until + * wednesday. + * + * @param string|integer|array|Zend_Date $month Weekday to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subWeekday($weekday, $locale = null) + { + return $this->_weekday('sub', $weekday, $locale); + } + + + /** + * Compares the weekday with the existing date object, ignoring other date parts. + * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $weekday Weekday to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareWeekday($weekday, $locale = null) + { + return $this->_weekday('cmp', $weekday, $locale); + } + + + /** + * Returns the day of year as new date object + * Example: 02.Feb.1986 10:00:00 -> 02.Feb.1970 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDayOfYear($locale = null) + { + return $this->copyPart(self::DAY_OF_YEAR, $locale); + } + + + /** + * Sets a new day of year + * The day of year is always a number. + * Returned is the new date object + * Example: 04.May.2004 -> setDayOfYear(10) -> 10.Jan.2004 + * + * @param string|integer|array|Zend_Date $day Day of Year to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setDayOfYear($day, $locale = null) + { + return $this->_calcvalue('set', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Adds a day of year to the existing date object. + * The day of year is always a number. + * Returned is the new date object + * Example: addDayOfYear(10); will add 10 days to the existing date object. + * + * @param string|integer|array|Zend_Date $day Day of Year to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addDayOfYear($day, $locale = null) + { + return $this->_calcvalue('add', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Subtracts a day of year from the existing date object. + * The day of year is always a number. + * Returned is the new date object + * Example: subDayOfYear(10); will subtract 10 days from the existing date object. + * + * @param string|integer|array|Zend_Date $day Day of Year to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subDayOfYear($day, $locale = null) + { + return $this->_calcvalue('sub', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Compares the day of year with the existing date object. + * For example: compareDayOfYear(33) -> 02.Feb.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $day Day of Year to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareDayOfYear($day, $locale = null) + { + return $this->_calcvalue('cmp', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Returns the hour as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 10:00:00 + * + * @param $locale string|Zend_Locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getHour($locale = null) + { + return $this->copyPart(self::HOUR, $locale); + } + + + /** + * Sets a new hour + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setHour(7); -> 04.May.1993 07:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setHour($hour, $locale = null) + { + return $this->_calcvalue('set', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Adds hours to the existing date object. + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addHour(12); -> 05.May.1993 01:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addHour($hour, $locale = null) + { + return $this->_calcvalue('add', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Subtracts hours from the existing date object. + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subHour(6); -> 05.May.1993 07:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subHour($hour, $locale = null) + { + return $this->_calcvalue('sub', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Compares the hour with the existing date object. + * For example: 10:30:25 -> compareHour(10) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $hour Hour to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareHour($hour, $locale = null) + { + return $this->_calcvalue('cmp', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Returns the minute as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:30:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getMinute($locale = null) + { + return $this->copyPart(self::MINUTE, $locale); + } + + + /** + * Sets a new minute + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setMinute(29); -> 04.May.1993 13:29:25 + * + * @param string|integer|array|Zend_Date $minute Minute to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setMinute($minute, $locale = null) + { + return $this->_calcvalue('set', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Adds minutes to the existing date object. + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addMinute(65); -> 04.May.1993 13:12:25 + * + * @param string|integer|array|Zend_Date $minute Minute to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addMinute($minute, $locale = null) + { + return $this->_calcvalue('add', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Subtracts minutes from the existing date object. + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subMinute(9); -> 04.May.1993 12:58:25 + * + * @param string|integer|array|Zend_Date $minute Minute to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subMinute($minute, $locale = null) + { + return $this->_calcvalue('sub', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Compares the minute with the existing date object. + * For example: 10:30:25 -> compareMinute(30) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $minute Hour to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareMinute($minute, $locale = null) + { + return $this->_calcvalue('cmp', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Returns the second as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:00:25 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getSecond($locale = null) + { + return $this->copyPart(self::SECOND, $locale); + } + + + /** + * Sets new seconds to the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setSecond(100); -> 04.May.1993 13:08:40 + * + * @param string|integer|array|Zend_Date $second Second to set + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function setSecond($second, $locale = null) + { + return $this->_calcvalue('set', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Adds seconds to the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addSecond(65); -> 04.May.1993 13:08:30 + * + * @param string|integer|array|Zend_Date $second Second to add + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function addSecond($second, $locale = null) + { + return $this->_calcvalue('add', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Subtracts seconds from the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subSecond(10); -> 04.May.1993 13:07:15 + * + * @param string|integer|array|Zend_Date $second Second to sub + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date new date + * @throws Zend_Date_Exception + */ + public function subSecond($second, $locale = null) + { + return $this->_calcvalue('sub', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Compares the second with the existing date object. + * For example: 10:30:25 -> compareSecond(25) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $second Second to compare + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareSecond($second, $locale = null) + { + return $this->_calcvalue('cmp', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Returns the precision for fractional seconds + * + * @return integer + */ + public function getFractionalPrecision() + { + return $this->_precision; + } + + + /** + * Sets a new precision for fractional seconds + * + * @param integer $precision Precision for the fractional datepart 3 = milliseconds + * @throws Zend_Date_Exception + * @return void + */ + public function setFractionalPrecision($precision) + { + if (!intval($precision) or ($precision < 0) or ($precision > 9)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", $precision); + } + $this->_precision = (int) $precision; + } + + + /** + * Returns the milliseconds of the date object + * + * @return integer + */ + public function getMilliSecond() + { + return $this->_fractional; + } + + + /** + * Sets new milliseconds for the date object + * Example: setMilliSecond(550, 2) -> equals +5 Sec +50 MilliSec + * + * @param integer|Zend_Date $milli (Optional) Millisecond to set, when null the actual millisecond is set + * @param integer $precision (Optional) Fraction precision of the given milliseconds + * @return integer|string + */ + public function setMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + $precision = 6; + } else if (!is_numeric($milli)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid milli second ($milli) operand", $milli); + } + + if ($precision === null) { + $precision = $this->_precision; + } else if (!is_int($precision) || $precision < 1 || $precision > 9) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", $precision); + } + + $this->_fractional = 0; + $this->addMilliSecond($milli, $precision); + return $this->_fractional; + } + + + /** + * Adds milliseconds to the date object + * + * @param integer|Zend_Date $milli (Optional) Millisecond to add, when null the actual millisecond is added + * @param integer $precision (Optional) Fractional precision for the given milliseconds + * @return integer|string + */ + public function addMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + } else if (!is_numeric($milli)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid milli second ($milli) operand", $milli); + } + + if ($precision === null) { + $precision = $this->_precision; + } else if (!is_int($precision) || $precision < 1 || $precision > 9) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", $precision); + } + + if ($precision != $this->_precision) { + if ($precision > $this->_precision) { + $diff = $precision - $this->_precision; + $milli = (int) ($milli / (10 * $diff)); + } else { + $diff = $this->_precision - $precision; + $milli = (int) ($milli * (10 * $diff)); + } + } + + $this->_fractional += $milli; + // Add/sub milliseconds + add/sub seconds + + $max = pow(10, $this->_precision); + // Milli includes seconds + if ($this->_fractional >= $max) { + while ($this->_fractional >= $max) { + $this->addSecond(1); + $this->_fractional -= $max; + } + } + + if ($this->_fractional < 0) { + while ($this->_fractional < 0) { + $this->subSecond(1); + $this->_fractional += $max; + } + } + + return $this->_fractional; + } + + + /** + * Subtracts a millisecond + * + * @param integer|Zend_Date $milli (Optional) Millisecond to sub, when null the actual millisecond is subtracted + * @param integer $precision (Optional) Fractional precision for the given milliseconds + * @return integer + */ + public function subMilliSecond($milli = null, $precision = null) + { + return $this->addMilliSecond(0 - $milli, $precision); + } + + /** + * Compares only the millisecond part, returning the difference + * + * @param integer|Zend_Date $milli OPTIONAL Millisecond to compare, when null the actual millisecond is compared + * @param integer $precision OPTIONAL Fractional precision for the given milliseconds + * @return integer + */ + public function compareMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + } else if (is_numeric($milli) === false) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("invalid milli second ($milli) operand", $milli); + } + + if ($precision === null) { + $precision = $this->_precision; + } else if (!is_int($precision) || $precision < 1 || $precision > 9) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", $precision); + } + + if ($precision === 0) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('precision is 0'); + } + + if ($precision != $this->_precision) { + if ($precision > $this->_precision) { + $diff = $precision - $this->_precision; + $milli = (int) ($milli / (10 * $diff)); + } else { + $diff = $this->_precision - $precision; + $milli = (int) ($milli * (10 * $diff)); + } + } + + $comp = $this->_fractional - $milli; + if ($comp < 0) { + return -1; + } else if ($comp > 0) { + return 1; + } + return 0; + } + + /** + * Returns the week as new date object using monday as begining of the week + * Example: 12.Jan.2007 -> 08.Jan.1970 00:00:00 + * + * @param $locale string|Zend_Locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getWeek($locale = null) + { + return $this->copyPart(self::WEEK, $locale); + } + + /** + * Sets a new week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> setWeek(1); -> 02.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function setWeek($week, $locale = null) + { + return $this->_calcvalue('set', $week, 'week', self::WEEK, $locale); + } + + /** + * Adds a week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> addWeek(1); -> 16.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function addWeek($week, $locale = null) + { + return $this->_calcvalue('add', $week, 'week', self::WEEK, $locale); + } + + /** + * Subtracts a week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> subWeek(1); -> 02.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function subWeek($week, $locale = null) + { + return $this->_calcvalue('sub', $week, 'week', self::WEEK, $locale); + } + + /** + * Compares only the week part, returning the difference + * Returned is the new date object + * Returns if equal, earlier or later + * Example: 09.Jan.2007 13:07:25 -> compareWeek(2); -> 0 + * + * @param string|integer|array|Zend_Date $week Week to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + */ + public function compareWeek($week, $locale = null) + { + return $this->_calcvalue('cmp', $week, 'week', self::WEEK, $locale); + } + + /** + * Sets a new standard locale for the date object. + * This locale will be used for all functions + * Returned is the really set locale. + * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist + * 'xx_YY' will be set to 'root' because 'xx' does not exist + * + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @throws Zend_Date_Exception When the given locale does not exist + * @return Zend_Date Provides fluent interface + */ + public function setLocale($locale = null) + { + try { + $this->_locale = Zend_Locale::findLocale($locale); + } catch (Zend_Locale_Exception $e) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception($e->getMessage()); + } + + return $this; + } + + /** + * Returns the actual set locale + * + * @return string + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Checks if the given date is a real date or datepart. + * Returns false if a expected datepart is missing or a datepart exceeds its possible border. + * But the check will only be done for the expected dateparts which are given by format. + * If no format is given the standard dateformat for the actual locale is used. + * f.e. 30.February.2007 will return false if format is 'dd.MMMM.YYYY' + * + * @param string|array|Zend_Date $date Date to parse for correctness + * @param string $format (Optional) Format for parsing the date string + * @param string|Zend_Locale $locale (Optional) Locale for parsing date parts + * @return boolean True when all date parts are correct + */ + public static function isDate($date, $format = null, $locale = null) + { + if (!is_string($date) && !is_numeric($date) && !($date instanceof Zend_Date) && + !is_array($date)) { + return false; + } + + if (($format !== null) and (Zend_Locale::isLocale($format, null, false))) { + $locale = $format; + $format = null; + } + + $locale = Zend_Locale::findLocale($locale); + + if ($format === null) { + $format = Zend_Locale_Format::getDateFormat($locale); + } else if (self::$_options['format_type'] == 'php') { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + + $format = self::_getLocalizedToken($format, $locale); + if (!is_array($date)) { + try { + $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale, + 'date_format' => $format, 'format_type' => 'iso', + 'fix_date' => false)); + } catch (Zend_Locale_Exception $e) { + // Date can not be parsed + return false; + } + } else { + $parsed = $date; + } + + if (((strpos($format, 'Y') !== false) or (strpos($format, 'y') !== false)) and + (!isset($parsed['year']))) { + // Year expected but not found + return false; + } + + if ((strpos($format, 'M') !== false) and (!isset($parsed['month']))) { + // Month expected but not found + return false; + } + + if ((strpos($format, 'd') !== false) and (!isset($parsed['day']))) { + // Day expected but not found + return false; + } + + if (((strpos($format, 'H') !== false) or (strpos($format, 'h') !== false)) and + (!isset($parsed['hour']))) { + // Hour expected but not found + return false; + } + + if ((strpos($format, 'm') !== false) and (!isset($parsed['minute']))) { + // Minute expected but not found + return false; + } + + if ((strpos($format, 's') !== false) and (!isset($parsed['second']))) { + // Second expected but not found + return false; + } + + // Set not given dateparts + if (isset($parsed['hour']) === false) { + $parsed['hour'] = 12; + } + + if (isset($parsed['minute']) === false) { + $parsed['minute'] = 0; + } + + if (isset($parsed['second']) === false) { + $parsed['second'] = 0; + } + + if (isset($parsed['month']) === false) { + $parsed['month'] = 1; + } + + if (isset($parsed['day']) === false) { + $parsed['day'] = 1; + } + + if (isset($parsed['year']) === false) { + $parsed['year'] = 1970; + } + + if (self::isYearLeapYear($parsed['year'])) { + $parsed['year'] = 1972; + } else { + $parsed['year'] = 1971; + } + + $date = new self($parsed, null, $locale); + $timestamp = $date->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], + $parsed['month'], $parsed['day'], $parsed['year']); + + if ($parsed['year'] != $date->date('Y', $timestamp)) { + // Given year differs from parsed year + return false; + } + + if ($parsed['month'] != $date->date('n', $timestamp)) { + // Given month differs from parsed month + return false; + } + + if ($parsed['day'] != $date->date('j', $timestamp)) { + // Given day differs from parsed day + return false; + } + + if ($parsed['hour'] != $date->date('G', $timestamp)) { + // Given hour differs from parsed hour + return false; + } + + if ($parsed['minute'] != $date->date('i', $timestamp)) { + // Given minute differs from parsed minute + return false; + } + + if ($parsed['second'] != $date->date('s', $timestamp)) { + // Given second differs from parsed second + return false; + } + + return true; + } + + /** + * Returns the ISO Token for all localized constants + * + * @param string $token Token to normalize + * @param string $locale Locale to search + * @return string + */ + protected static function _getLocalizedToken($token, $locale) + { + switch($token) { + case self::ISO_8601 : + return "dd mm yy"; + break; + case self::RFC_2822 : + return "EEE, dd MMM yyyy HH:mm:ss"; + break; + case self::DATES : + return Zend_Locale_Data::getContent($locale, 'date'); + break; + case self::DATE_FULL : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')); + break; + case self::DATE_LONG : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')); + break; + case self::DATE_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')); + break; + case self::DATE_SHORT : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')); + break; + case self::TIMES : + return Zend_Locale_Data::getContent($locale, 'date'); + break; + case self::TIME_FULL : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full')); + break; + case self::TIME_LONG : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')); + break; + case self::TIME_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')); + break; + case self::TIME_SHORT : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')); + break; + case self::DATETIME : + return Zend_Locale_Data::getContent($locale, 'datetime'); + break; + case self::DATETIME_FULL : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')); + break; + case self::DATETIME_LONG : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')); + break; + case self::DATETIME_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')); + break; + case self::DATETIME_SHORT : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')); + break; + case self::ATOM : + case self::RFC_3339 : + case self::W3C : + return "yyyy-MM-DD HH:mm:ss"; + break; + case self::COOKIE : + case self::RFC_850 : + return "EEEE, dd-MM-yyyy HH:mm:ss"; + break; + case self::RFC_822 : + case self::RFC_1036 : + case self::RFC_1123 : + case self::RSS : + return "EEE, dd MM yyyy HH:mm:ss"; + break; + } + + return $token; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Date/Cities.php b/ThinkPHP/Extend/Vendor/Zend/Date/Cities.php new file mode 100644 index 0000000..add7b9c --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Date/Cities.php @@ -0,0 +1,322 @@ + array('latitude' => 5.3411111, 'longitude' => -4.0280556), + 'Abu Dhabi' => array('latitude' => 24.4666667, 'longitude' => 54.3666667), + 'Abuja' => array('latitude' => 9.1758333, 'longitude' => 7.1808333), + 'Accra' => array('latitude' => 5.55, 'longitude' => -0.2166667), + 'Adamstown' => array('latitude' => -25.0666667, 'longitude' => -130.0833333), + 'Addis Ababa' => array('latitude' => 9.0333333, 'longitude' => 38.7), + 'Adelaide' => array('latitude' => -34.9333333, 'longitude' => 138.6), + 'Algiers' => array('latitude' => 36.7630556, 'longitude' => 3.0505556), + 'Alofi' => array('latitude' => -19.0166667, 'longitude' => -169.9166667), + 'Amman' => array('latitude' => 31.95, 'longitude' => 35.9333333), + 'Amsterdam' => array('latitude' => 52.35, 'longitude' => 4.9166667), + 'Andorra la Vella' => array('latitude' => 42.5, 'longitude' => 1.5166667), + 'Ankara' => array('latitude' => 39.9272222, 'longitude' => 32.8644444), + 'Antananarivo' => array('latitude' => -18.9166667, 'longitude' => 47.5166667), + 'Apia' => array('latitude' => -13.8333333, 'longitude' => -171.7333333), + 'Ashgabat' => array('latitude' => 37.95, 'longitude' => 58.3833333), + 'Asmara' => array('latitude' => 15.3333333, 'longitude' => 38.9333333), + 'Astana' => array('latitude' => 51.1811111, 'longitude' => 71.4277778), + 'Asunción' => array('latitude' => -25.2666667, 'longitude' => -57.6666667), + 'Athens' => array('latitude' => 37.9833333, 'longitude' => 23.7333333), + 'Auckland' => array('latitude' => -36.8666667, 'longitude' => 174.7666667), + 'Avarua' => array('latitude' => -21.2, 'longitude' => -159.7666667), + 'Baghdad' => array('latitude' => 33.3386111, 'longitude' => 44.3938889), + 'Baku' => array('latitude' => 40.3952778, 'longitude' => 49.8822222), + 'Bamako' => array('latitude' => 12.65, 'longitude' => -8), + 'Bandar Seri Begawan' => array('latitude' => 4.8833333, 'longitude' => 114.9333333), + 'Bankok' => array('latitude' => 13.5833333, 'longitude' => 100.2166667), + 'Bangui' => array('latitude' => 4.3666667, 'longitude' => 18.5833333), + 'Banjul' => array('latitude' => 13.4530556, 'longitude' => -16.5775), + 'Basel' => array('latitude' => 47.5666667, 'longitude' => 7.6), + 'Basseterre' => array('latitude' => 17.3, 'longitude' => -62.7166667), + 'Beijing' => array('latitude' => 39.9288889, 'longitude' => 116.3883333), + 'Beirut' => array('latitude' => 33.8719444, 'longitude' => 35.5097222), + 'Belgrade' => array('latitude' => 44.8186111, 'longitude' => 20.4680556), + 'Belmopan' => array('latitude' => 17.25, 'longitude' => -88.7666667), + 'Berlin' => array('latitude' => 52.5166667, 'longitude' => 13.4), + 'Bern' => array('latitude' => 46.9166667, 'longitude' => 7.4666667), + 'Bishkek' => array('latitude' => 42.8730556, 'longitude' => 74.6002778), + 'Bissau' => array('latitude' => 11.85, 'longitude' => -15.5833333), + 'Bloemfontein' => array('latitude' => -29.1333333, 'longitude' => 26.2), + 'Bogotá' => array('latitude' => 4.6, 'longitude' => -74.0833333), + 'Brasilia' => array('latitude' => -15.7833333, 'longitude' => -47.9166667), + 'Bratislava' => array('latitude' => 48.15, 'longitude' => 17.1166667), + 'Brazzaville' => array('latitude' => -4.2591667, 'longitude' => 15.2847222), + 'Bridgetown' => array('latitude' => 13.1, 'longitude' => -59.6166667), + 'Brisbane' => array('latitude' => -27.5, 'longitude' => 153.0166667), + 'Brussels' => array('latitude' => 50.8333333, 'longitude' => 4.3333333), + 'Bucharest' => array('latitude' => 44.4333333, 'longitude' => 26.1), + 'Budapest' => array('latitude' => 47.5, 'longitude' => 19.0833333), + 'Buenos Aires' => array('latitude' => -34.5875, 'longitude' => -58.6725), + 'Bujumbura' => array('latitude' => -3.3761111, 'longitude' => 29.36), + 'Cairo' => array('latitude' => 30.05, 'longitude' => 31.25), + 'Calgary' => array('latitude' => 51.0833333, 'longitude' => -114.0833333), + 'Canberra' => array('latitude' => -35.2833333, 'longitude' => 149.2166667), + 'Cape Town' => array('latitude' => -33.9166667, 'longitude' => 18.4166667), + 'Caracas' => array('latitude' => 10.5, 'longitude' => -66.9166667), + 'Castries' => array('latitude' => 14, 'longitude' => -61), + 'Charlotte Amalie' => array('latitude' => 18.34389, 'longitude' => -64.93111), + 'Chicago' => array('latitude' => 41.85, 'longitude' => -87.65), + 'Chisinau' => array('latitude' => 47.055556, 'longitude' => 28.8575), + 'Cockburn Town' => array('latitude' => 21.4666667, 'longitude' => -71.1333333), + 'Colombo' => array('latitude' => 6.9319444, 'longitude' => 79.8477778), + 'Conakry' => array('latitude' => 9.5091667, 'longitude' => -13.7122222), + 'Copenhagen' => array('latitude' => 55.6666667, 'longitude' => 12.5833333), + 'Cotonou' => array('latitude' => 6.35, 'longitude' => 2.4333333), + 'Dakar' => array('latitude' => 14.6708333, 'longitude' => -17.4380556), + 'Damascus' => array('latitude' => 33.5, 'longitude' => 36.3), + 'Dar es Salaam' => array('latitude' => -6.8, 'longitude' => 39.2833333), + 'Dhaka' => array('latitude' => 23.7230556, 'longitude' => 90.4086111), + 'Dili' => array('latitude' => -8.5586111, 'longitude' => 125.5736111), + 'Djibouti' => array('latitude' => 11.595, 'longitude' => 43.1480556), + 'Dodoma' => array('latitude' => -6.1833333, 'longitude' => 35.75), + 'Doha' => array('latitude' => 25.2866667, 'longitude' => 51.5333333), + 'Dubai' => array('latitude' => 25.2522222, 'longitude' => 55.28), + 'Dublin' => array('latitude' => 53.3330556, 'longitude' => -6.2488889), + 'Dushanbe' => array('latitude' => 38.56, 'longitude' => 68.7738889 ), + 'Fagatogo' => array('latitude' => -14.2825, 'longitude' => -170.69), + 'Fongafale' => array('latitude' => -8.5166667, 'longitude' => 179.2166667), + 'Freetown' => array('latitude' => 8.49, 'longitude' => -13.2341667), + 'Gaborone' => array('latitude' => -24.6463889, 'longitude' => 25.9119444), + 'Geneva' => array('latitude' => 46.2, 'longitude' => 6.1666667), + 'George Town' => array('latitude' => 19.3, 'longitude' => -81.3833333), + 'Georgetown' => array('latitude' => 6.8, 'longitude' => -58.1666667), + 'Gibraltar' => array('latitude' => 36.1333333, 'longitude' => -5.35), + 'Glasgow' => array('latitude' => 55.8333333, 'longitude' => -4.25), + 'Guatemala la Nueva' => array('latitude' => 14.6211111, 'longitude' => -90.5269444), + 'Hagatna' => array('latitude' => 13.47417, 'longitude' => 144.74778), + 'The Hague' => array('latitude' => 52.0833333, 'longitude' => 4.3), + 'Hamilton' => array('latitude' => 32.2941667, 'longitude' => -64.7838889), + 'Hanoi' => array('latitude' => 21.0333333, 'longitude' => 105.85), + 'Harare' => array('latitude' => -17.8177778, 'longitude' => 31.0447222), + 'Havana' => array('latitude' => 23.1319444, 'longitude' => -82.3641667), + 'Helsinki' => array('latitude' => 60.1755556, 'longitude' => 24.9341667), + 'Honiara' => array('latitude' => -9.4333333, 'longitude' => 159.95), + 'Islamabad' => array('latitude' => 30.8486111, 'longitude' => 72.4944444), + 'Istanbul' => array('latitude' => 41.0186111, 'longitude' => 28.9647222), + 'Jakarta' => array('latitude' => -6.1744444, 'longitude' => 106.8294444), + 'Jamestown' => array('latitude' => -15.9333333, 'longitude' => -5.7166667), + 'Jerusalem' => array('latitude' => 31.7666667, 'longitude' => 35.2333333), + 'Johannesburg' => array('latitude' => -26.2, 'longitude' => 28.0833333), + 'Kabul' => array('latitude' => 34.5166667, 'longitude' => 69.1833333), + 'Kampala' => array('latitude' => 0.3155556, 'longitude' => 32.5655556), + 'Kathmandu' => array('latitude' => 27.7166667, 'longitude' => 85.3166667), + 'Khartoum' => array('latitude' => 15.5880556, 'longitude' => 32.5341667), + 'Kigali' => array('latitude' => -1.9536111, 'longitude' => 30.0605556), + 'Kingston' => array('latitude' => -29.05, 'longitude' => 167.95), + 'Kingstown' => array('latitude' => 13.1333333, 'longitude' => -61.2166667), + 'Kinshasa' => array('latitude' => -4.3, 'longitude' => 15.3), + 'Kolkata' => array('latitude' => 22.5697222, 'longitude' => 88.3697222), + 'Kuala Lumpur' => array('latitude' => 3.1666667, 'longitude' => 101.7), + 'Kuwait City' => array('latitude' => 29.3697222, 'longitude' => 47.9783333), + 'Kiev' => array('latitude' => 50.4333333, 'longitude' => 30.5166667), + 'La Paz' => array('latitude' => -16.5, 'longitude' => -68.15), + 'Libreville' => array('latitude' => 0.3833333, 'longitude' => 9.45), + 'Lilongwe' => array('latitude' => -13.9833333, 'longitude' => 33.7833333), + 'Lima' => array('latitude' => -12.05, 'longitude' => -77.05), + 'Lisbon' => array('latitude' => 38.7166667, 'longitude' => -9.1333333), + 'Ljubljana' => array('latitude' => 46.0552778, 'longitude' => 14.5144444), + 'Lobamba' => array('latitude' => -26.4666667, 'longitude' => 31.2), + 'Lomé' => array('latitude' => 9.7166667, 'longitude' => 38.3), + 'London' => array('latitude' => 51.5, 'longitude' => -0.1166667), + 'Los Angeles' => array('latitude' => 34.05222, 'longitude' => -118.24278), + 'Luanda' => array('latitude' => -8.8383333, 'longitude' => 13.2344444), + 'Lusaka' => array('latitude' => -15.4166667, 'longitude' => 28.2833333), + 'Luxembourg' => array('latitude' => 49.6116667, 'longitude' => 6.13), + 'Madrid' => array('latitude' => 40.4, 'longitude' => -3.6833333), + 'Majuro' => array('latitude' => 7.1, 'longitude' => 171.3833333), + 'Malabo' => array('latitude' => 3.75, 'longitude' => 8.7833333), + 'Managua' => array('latitude' => 12.1508333, 'longitude' => -86.2683333), + 'Manama' => array('latitude' => 26.2361111, 'longitude' => 50.5830556), + 'Manila' => array('latitude' => 14.6041667, 'longitude' => 120.9822222), + 'Maputo' => array('latitude' => -25.9652778, 'longitude' => 32.5891667), + 'Maseru' => array('latitude' => -29.3166667, 'longitude' => 27.4833333), + 'Mbabane' => array('latitude' => -26.3166667, 'longitude' => 31.1333333), + 'Melbourne' => array('latitude' => -37.8166667, 'longitude' => 144.9666667), + 'Melekeok' => array('latitude' => 7.4933333, 'longitude' => 134.6341667), + 'Mexiko City' => array('latitude' => 19.4341667, 'longitude' => -99.1386111), + 'Minsk' => array('latitude' => 53.9, 'longitude' => 27.5666667), + 'Mogadishu' => array('latitude' => 2.0666667, 'longitude' => 45.3666667), + 'Monaco' => array('latitude' => 43.7333333, 'longitude' => 7.4166667), + 'Monrovia' => array('latitude' => 6.3105556, 'longitude' => -10.8047222), + 'Montevideo' => array('latitude' => -34.8580556, 'longitude' => -56.1708333), + 'Montreal' => array('latitude' => 45.5, 'longitude' => -73.5833333), + 'Moroni' => array('latitude' => -11.7041667, 'longitude' => 43.2402778), + 'Moscow' => array('latitude' => 55.7522222, 'longitude' => 37.6155556), + 'Muscat' => array('latitude' => 23.6133333, 'longitude' => 58.5933333), + 'Nairobi' => array('latitude' => -1.3166667, 'longitude' => 36.8333333), + 'Nassau' => array('latitude' => 25.0833333, 'longitude' => -77.35), + 'N´Djamena' => array('latitude' => 12.1130556, 'longitude' => 15.0491667), + 'New Dehli' => array('latitude' => 28.6, 'longitude' => 77.2), + 'New York' => array('latitude' => 40.71417, 'longitude' => -74.00639), + 'Newcastle' => array('latitude' => -32.9166667, 'longitude' => 151.75), + 'Niamey' => array('latitude' => 13.6666667, 'longitude' => 1.7833333), + 'Nicosia' => array('latitude' => 35.1666667, 'longitude' => 33.3666667), + 'Nouakchott' => array('latitude' => 18.0863889, 'longitude' => -15.9752778), + 'Noumea' => array('latitude' => -22.2666667, 'longitude' => 166.45), + 'Nuku´alofa' => array('latitude' => -21.1333333, 'longitude' => -175.2), + 'Nuuk' => array('latitude' => 64.1833333, 'longitude' => -51.75), + 'Oranjestad' => array('latitude' => 12.5166667, 'longitude' => -70.0333333), + 'Oslo' => array('latitude' => 59.9166667, 'longitude' => 10.75), + 'Ouagadougou' => array('latitude' => 12.3702778, 'longitude' => -1.5247222), + 'Palikir' => array('latitude' => 6.9166667, 'longitude' => 158.15), + 'Panama City' => array('latitude' => 8.9666667, 'longitude' => -79.5333333), + 'Papeete' => array('latitude' => -17.5333333, 'longitude' => -149.5666667), + 'Paramaribo' => array('latitude' => 5.8333333, 'longitude' => -55.1666667), + 'Paris' => array('latitude' => 48.8666667, 'longitude' => 2.3333333), + 'Perth' => array('latitude' => -31.9333333, 'longitude' => 115.8333333), + 'Phnom Penh' => array('latitude' => 11.55, 'longitude' => 104.9166667), + 'Podgorica' => array('latitude' => 43.7752778, 'longitude' => 19.6827778), + 'Port Louis' => array('latitude' => -20.1666667, 'longitude' => 57.5), + 'Port Moresby' => array('latitude' => -9.4647222, 'longitude' => 147.1925), + 'Port-au-Prince' => array('latitude' => 18.5391667, 'longitude' => -72.335), + 'Port of Spain' => array('latitude' => 10.6666667, 'longitude' => -61.5), + 'Porto-Novo' => array('latitude' => 6.4833333, 'longitude' => 2.6166667), + 'Prague' => array('latitude' => 50.0833333, 'longitude' => 14.4666667), + 'Praia' => array('latitude' => 14.9166667, 'longitude' => -23.5166667), + 'Pretoria' => array('latitude' => -25.7069444, 'longitude' => 28.2294444), + 'Pyongyang' => array('latitude' => 39.0194444, 'longitude' => 125.7547222), + 'Quito' => array('latitude' => -0.2166667, 'longitude' => -78.5), + 'Rabat' => array('latitude' => 34.0252778, 'longitude' => -6.8361111), + 'Reykjavik' => array('latitude' => 64.15, 'longitude' => -21.95), + 'Riga' => array('latitude' => 56.95, 'longitude' => 24.1), + 'Rio de Janero' => array('latitude' => -22.9, 'longitude' => -43.2333333), + 'Road Town' => array('latitude' => 18.4166667, 'longitude' => -64.6166667), + 'Rome' => array('latitude' => 41.9, 'longitude' => 12.4833333), + 'Roseau' => array('latitude' => 15.3, 'longitude' => -61.4), + 'Rotterdam' => array('latitude' => 51.9166667, 'longitude' => 4.5), + 'Salvador' => array('latitude' => -12.9833333, 'longitude' => -38.5166667), + 'San José' => array('latitude' => 9.9333333, 'longitude' => -84.0833333), + 'San Juan' => array('latitude' => 18.46833, 'longitude' => -66.10611), + 'San Marino' => array('latitude' => 43.5333333, 'longitude' => 12.9666667), + 'San Salvador' => array('latitude' => 13.7086111, 'longitude' => -89.2030556), + 'Sanaá' => array('latitude' => 15.3547222, 'longitude' => 44.2066667), + 'Santa Cruz' => array('latitude' => -17.8, 'longitude' => -63.1666667), + 'Santiago' => array('latitude' => -33.45, 'longitude' => -70.6666667), + 'Santo Domingo' => array('latitude' => 18.4666667, 'longitude' => -69.9), + 'Sao Paulo' => array('latitude' => -23.5333333, 'longitude' => -46.6166667), + 'Sarajevo' => array('latitude' => 43.85, 'longitude' => 18.3833333), + 'Seoul' => array('latitude' => 37.5663889, 'longitude' => 126.9997222), + 'Shanghai' => array('latitude' => 31.2222222, 'longitude' => 121.4580556), + 'Sydney' => array('latitude' => -33.8833333, 'longitude' => 151.2166667), + 'Singapore' => array('latitude' => 1.2930556, 'longitude' => 103.8558333), + 'Skopje' => array('latitude' => 42, 'longitude' => 21.4333333), + 'Sofia' => array('latitude' => 42.6833333, 'longitude' => 23.3166667), + 'St. George´s' => array('latitude' => 12.05, 'longitude' => -61.75), + 'St. John´s' => array('latitude' => 17.1166667, 'longitude' => -61.85), + 'Stanley' => array('latitude' => -51.7, 'longitude' => -57.85), + 'Stockholm' => array('latitude' => 59.3333333, 'longitude' => 18.05), + 'Suva' => array('latitude' => -18.1333333, 'longitude' => 178.4166667), + 'Taipei' => array('latitude' => 25.0166667, 'longitude' => 121.45), + 'Tallinn' => array('latitude' => 59.4338889, 'longitude' => 24.7280556), + 'Tashkent' => array('latitude' => 41.3166667, 'longitude' => 69.25), + 'Tbilisi' => array('latitude' => 41.725, 'longitude' => 44.7908333), + 'Tegucigalpa' => array('latitude' => 14.1, 'longitude' => -87.2166667), + 'Tehran' => array('latitude' => 35.6719444, 'longitude' => 51.4244444), + 'The Hague' => array('latitude' => 52.0833333, 'longitude' => 4.3), + 'Thimphu' => array('latitude' => 27.4833333, 'longitude' => 89.6), + 'Tirana' => array('latitude' => 41.3275, 'longitude' => 19.8188889), + 'Tiraspol' => array('latitude' => 46.8402778, 'longitude' => 29.6433333), + 'Tokyo' => array('latitude' => 35.685, 'longitude' => 139.7513889), + 'Toronto' => array('latitude' => 43.6666667, 'longitude' => -79.4166667), + 'Tórshavn' => array('latitude' => 62.0166667, 'longitude' => -6.7666667), + 'Tripoli' => array('latitude' => 32.8925, 'longitude' => 13.18), + 'Tunis' => array('latitude' => 36.8027778, 'longitude' => 10.1797222), + 'Ulaanbaatar' => array('latitude' => 47.9166667, 'longitude' => 106.9166667), + 'Vaduz' => array('latitude' => 47.1333333, 'longitude' => 9.5166667), + 'Valletta' => array('latitude' => 35.8997222, 'longitude' => 14.5147222), + 'Valparaiso' => array('latitude' => -33.0477778, 'longitude' => -71.6011111), + 'Vancouver' => array('latitude' => 49.25, 'longitude' => -123.1333333), + 'Vatican City' => array('latitude' => 41.9, 'longitude' => 12.4833333), + 'Victoria' => array('latitude' => -4.6166667, 'longitude' => 55.45), + 'Vienna' => array('latitude' => 48.2, 'longitude' => 16.3666667), + 'Vientaine' => array('latitude' => 17.9666667, 'longitude' => 102.6), + 'Vilnius' => array('latitude' => 54.6833333, 'longitude' => 25.3166667), + 'Warsaw' => array('latitude' => 52.25, 'longitude' => 21), + 'Washington dc' => array('latitude' => 38.895, 'longitude' => -77.03667), + 'Wellington' => array('latitude' => -41.3, 'longitude' => 174.7833333), + 'Willemstad' => array('latitude' => 12.1, 'longitude' => -68.9166667), + 'Windhoek' => array('latitude' => -22.57, 'longitude' => 17.0836111), + 'Yamoussoukro' => array('latitude' => 6.8166667, 'longitude' => -5.2833333), + 'Yaoundé' => array('latitude' => 3.8666667, 'longitude' => 11.5166667), + 'Yerevan' => array('latitude' => 40.1811111, 'longitude' => 44.5136111), + 'Zürich' => array('latitude' => 47.3666667, 'longitude' => 8.55), + 'Zagreb' => array('latitude' => 45.8, 'longitude' => 16) + ); + + /** + * Returns the location from the selected city + * + * @param string $city City to get location for + * @param string $horizon Horizon to use : + * default: effective + * others are civil, nautic, astronomic + * @return array + * @throws Zend_Date_Exception When city is unknown + */ + public static function City($city, $horizon = false) + { + foreach (self::$cities as $key => $value) { + if (strtolower($key) === strtolower($city)) { + $return = $value; + $return['horizon'] = $horizon; + return $return; + } + } + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('unknown city'); + } + + /** + * Return a list with all known cities + * + * @return array + */ + public static function getCityList() + { + return array_keys(self::$cities); + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Date/DateObject.php b/ThinkPHP/Extend/Vendor/Zend/Date/DateObject.php new file mode 100644 index 0000000..276e466 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Date/DateObject.php @@ -0,0 +1,1057 @@ + 0, 1960 => -315619200, 1950 => -631152000, + 1940 => -946771200, 1930 => -1262304000, 1920 => -1577923200, + 1910 => -1893456000, 1900 => -2208988800, 1890 => -2524521600, + 1880 => -2840140800, 1870 => -3155673600, 1860 => -3471292800, + 1850 => -3786825600, 1840 => -4102444800, 1830 => -4417977600, + 1820 => -4733596800, 1810 => -5049129600, 1800 => -5364662400, + 1790 => -5680195200, 1780 => -5995814400, 1770 => -6311347200, + 1760 => -6626966400, 1750 => -6942499200, 1740 => -7258118400, + 1730 => -7573651200, 1720 => -7889270400, 1710 => -8204803200, + 1700 => -8520336000, 1690 => -8835868800, 1680 => -9151488000, + 1670 => -9467020800, 1660 => -9782640000, 1650 => -10098172800, + 1640 => -10413792000, 1630 => -10729324800, 1620 => -11044944000, + 1610 => -11360476800, 1600 => -11676096000); + + /** + * Set this object to have a new UNIX timestamp. + * + * @param string|integer $timestamp OPTIONAL timestamp; defaults to local time using time() + * @return string|integer old timestamp + * @throws Zend_Date_Exception + */ + protected function setUnixTimestamp($timestamp = null) + { + $old = $this->_unixTimestamp; + + if (is_numeric($timestamp)) { + $this->_unixTimestamp = $timestamp; + } else if ($timestamp === null) { + $this->_unixTimestamp = time(); + } else { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception('\'' . $timestamp . '\' is not a valid UNIX timestamp', $timestamp); + } + + return $old; + } + + /** + * Returns this object's UNIX timestamp + * A timestamp greater then the integer range will be returned as string + * This function does not return the timestamp as object. Use copy() instead. + * + * @return integer|string timestamp + */ + protected function getUnixTimestamp() + { + if ($this->_unixTimestamp === intval($this->_unixTimestamp)) { + return (int) $this->_unixTimestamp; + } else { + return (string) $this->_unixTimestamp; + } + } + + /** + * Internal function. + * Returns time(). This method exists to allow unit tests to work-around methods that might otherwise + * be hard-coded to use time(). For example, this makes it possible to test isYesterday() in Date.php. + * + * @param integer $sync OPTIONAL time syncronisation value + * @return integer timestamp + */ + protected function _getTime($sync = null) + { + if ($sync !== null) { + $this->_syncronised = round($sync); + } + return (time() + $this->_syncronised); + } + + /** + * Internal mktime function used by Zend_Date. + * The timestamp returned by mktime() can exceed the precision of traditional UNIX timestamps, + * by allowing PHP to auto-convert to using a float value. + * + * Returns a timestamp relative to 1970/01/01 00:00:00 GMT/UTC. + * DST (Summer/Winter) is depriciated since php 5.1.0. + * Year has to be 4 digits otherwise it would be recognised as + * year 70 AD instead of 1970 AD as expected !! + * + * @param integer $hour + * @param integer $minute + * @param integer $second + * @param integer $month + * @param integer $day + * @param integer $year + * @param boolean $gmt OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date + * @return integer|float timestamp (number of seconds elapsed relative to 1970/01/01 00:00:00 GMT/UTC) + */ + protected function mktime($hour, $minute, $second, $month, $day, $year, $gmt = false) + { + + // complete date but in 32bit timestamp - use PHP internal + if ((1901 < $year) and ($year < 2038)) { + + $oldzone = @date_default_timezone_get(); + // Timezone also includes DST settings, therefor substracting the GMT offset is not enough + // We have to set the correct timezone to get the right value + if (($this->_timezone != $oldzone) and ($gmt === false)) { + date_default_timezone_set($this->_timezone); + } + $result = ($gmt) ? @gmmktime($hour, $minute, $second, $month, $day, $year) + : @mktime($hour, $minute, $second, $month, $day, $year); + date_default_timezone_set($oldzone); + + return $result; + } + + if ($gmt !== true) { + $second += $this->_offset; + } + + if (isset(self::$_cache)) { + $id = strtr('Zend_DateObject_mkTime_' . $this->_offset . '_' . $year.$month.$day.'_'.$hour.$minute.$second . '_'.(int)$gmt, '-','_'); + if ($result = self::$_cache->load($id)) { + return unserialize($result); + } + } + + // date to integer + $day = intval($day); + $month = intval($month); + $year = intval($year); + + // correct months > 12 and months < 1 + if ($month > 12) { + $overlap = floor($month / 12); + $year += $overlap; + $month -= $overlap * 12; + } else { + $overlap = ceil((1 - $month) / 12); + $year -= $overlap; + $month += $overlap * 12; + } + + $date = 0; + if ($year >= 1970) { + + // Date is after UNIX epoch + // go through leapyears + // add months from latest given year + for ($count = 1970; $count <= $year; $count++) { + + $leapyear = self::isYearLeapYear($count); + if ($count < $year) { + + $date += 365; + if ($leapyear === true) { + $date++; + } + + } else { + + for ($mcount = 0; $mcount < ($month - 1); $mcount++) { + $date += self::$_monthTable[$mcount]; + if (($leapyear === true) and ($mcount == 1)) { + $date++; + } + + } + } + } + + $date += $day - 1; + $date = (($date * 86400) + ($hour * 3600) + ($minute * 60) + $second); + } else { + + // Date is before UNIX epoch + // go through leapyears + // add months from latest given year + for ($count = 1969; $count >= $year; $count--) { + + $leapyear = self::isYearLeapYear($count); + if ($count > $year) + { + $date += 365; + if ($leapyear === true) + $date++; + } else { + + for ($mcount = 11; $mcount > ($month - 1); $mcount--) { + $date += self::$_monthTable[$mcount]; + if (($leapyear === true) and ($mcount == 1)) { + $date++; + } + + } + } + } + + $date += (self::$_monthTable[$month - 1] - $day); + $date = -(($date * 86400) + (86400 - (($hour * 3600) + ($minute * 60) + $second))); + + // gregorian correction for 5.Oct.1582 + if ($date < -12220185600) { + $date += 864000; + } else if ($date < -12219321600) { + $date = -12219321600; + } + } + + if (isset(self::$_cache)) { + self::$_cache->save( serialize($date), $id); + } + + return $date; + } + + /** + * Returns true, if given $year is a leap year. + * + * @param integer $year + * @return boolean true, if year is leap year + */ + protected static function isYearLeapYear($year) + { + // all leapyears can be divided through 4 + if (($year % 4) != 0) { + return false; + } + + // all leapyears can be divided through 400 + if ($year % 400 == 0) { + return true; + } else if (($year > 1582) and ($year % 100 == 0)) { + return false; + } + + return true; + } + + /** + * Internal mktime function used by Zend_Date for handling 64bit timestamps. + * + * Returns a formatted date for a given timestamp. + * + * @param string $format format for output + * @param mixed $timestamp + * @param boolean $gmt OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date + * @return string + */ + protected function date($format, $timestamp = null, $gmt = false) + { + $oldzone = @date_default_timezone_get(); + if ($this->_timezone != $oldzone) { + date_default_timezone_set($this->_timezone); + } + if ($timestamp === null) { + $result = ($gmt) ? @gmdate($format) : @date($format); + date_default_timezone_set($oldzone); + return $result; + } + + if (abs($timestamp) <= 0x7FFFFFFF) { + $result = ($gmt) ? @gmdate($format, $timestamp) : @date($format, $timestamp); + date_default_timezone_set($oldzone); + return $result; + } + + $jump = false; + if (isset(self::$_cache)) { + $idstamp = strtr('Zend_DateObject_date_' . $this->_offset . '_'. $timestamp . '_'.(int)$gmt, '-','_'); + if ($result2 = self::$_cache->load($idstamp)) { + $timestamp = unserialize($result2); + $jump = true; + } + } + + // check on false or null alone failes + if (empty($gmt) and empty($jump)) { + $tempstamp = $timestamp; + if ($tempstamp > 0) { + while (abs($tempstamp) > 0x7FFFFFFF) { + $tempstamp -= (86400 * 23376); + } + $dst = date("I", $tempstamp); + if ($dst === 1) { + $timestamp += 3600; + } + $temp = date('Z', $tempstamp); + $timestamp += $temp; + } + + if (isset(self::$_cache)) { + self::$_cache->save( serialize($timestamp), $idstamp); + } + } + + + if (($timestamp < 0) and ($gmt !== true)) { + $timestamp -= $this->_offset; + } + date_default_timezone_set($oldzone); + + $date = $this->getDateParts($timestamp, true); + $length = strlen($format); + $output = ''; + + for ($i = 0; $i < $length; $i++) { + + switch($format[$i]) { + + // day formats + case 'd': // day of month, 2 digits, with leading zero, 01 - 31 + $output .= (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']); + break; + + case 'D': // day of week, 3 letters, Mon - Sun + $output .= date('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))); + break; + + case 'j': // day of month, without leading zero, 1 - 31 + $output .= $date['mday']; + break; + + case 'l': // day of week, full string name, Sunday - Saturday + $output .= date('l', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))); + break; + + case 'N': // ISO 8601 numeric day of week, 1 - 7 + $day = self::dayOfWeek($date['year'], $date['mon'], $date['mday']); + if ($day == 0) { + $day = 7; + } + $output .= $day; + break; + + case 'S': // english suffix for day of month, st nd rd th + if (($date['mday'] % 10) == 1) { + $output .= 'st'; + } else if ((($date['mday'] % 10) == 2) and ($date['mday'] != 12)) { + $output .= 'nd'; + } else if (($date['mday'] % 10) == 3) { + $output .= 'rd'; + } else { + $output .= 'th'; + } + break; + + case 'w': // numeric day of week, 0 - 6 + $output .= self::dayOfWeek($date['year'], $date['mon'], $date['mday']); + break; + + case 'z': // day of year, 0 - 365 + $output .= $date['yday']; + break; + + + // week formats + case 'W': // ISO 8601, week number of year + $output .= $this->weekNumber($date['year'], $date['mon'], $date['mday']); + break; + + + // month formats + case 'F': // string month name, january - december + $output .= date('F', mktime(0, 0, 0, $date['mon'], 2, 1971)); + break; + + case 'm': // number of month, with leading zeros, 01 - 12 + $output .= (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']); + break; + + case 'M': // 3 letter month name, Jan - Dec + $output .= date('M',mktime(0, 0, 0, $date['mon'], 2, 1971)); + break; + + case 'n': // number of month, without leading zeros, 1 - 12 + $output .= $date['mon']; + break; + + case 't': // number of day in month + $output .= self::$_monthTable[$date['mon'] - 1]; + break; + + + // year formats + case 'L': // is leap year ? + $output .= (self::isYearLeapYear($date['year'])) ? '1' : '0'; + break; + + case 'o': // ISO 8601 year number + $week = $this->weekNumber($date['year'], $date['mon'], $date['mday']); + if (($week > 50) and ($date['mon'] == 1)) { + $output .= ($date['year'] - 1); + } else { + $output .= $date['year']; + } + break; + + case 'Y': // year number, 4 digits + $output .= $date['year']; + break; + + case 'y': // year number, 2 digits + $output .= substr($date['year'], strlen($date['year']) - 2, 2); + break; + + + // time formats + case 'a': // lower case am/pm + $output .= (($date['hours'] >= 12) ? 'pm' : 'am'); + break; + + case 'A': // upper case am/pm + $output .= (($date['hours'] >= 12) ? 'PM' : 'AM'); + break; + + case 'B': // swatch internet time + $dayseconds = ($date['hours'] * 3600) + ($date['minutes'] * 60) + $date['seconds']; + if ($gmt === true) { + $dayseconds += 3600; + } + $output .= (int) (($dayseconds % 86400) / 86.4); + break; + + case 'g': // hours without leading zeros, 12h format + if ($date['hours'] > 12) { + $hour = $date['hours'] - 12; + } else { + if ($date['hours'] == 0) { + $hour = '12'; + } else { + $hour = $date['hours']; + } + } + $output .= $hour; + break; + + case 'G': // hours without leading zeros, 24h format + $output .= $date['hours']; + break; + + case 'h': // hours with leading zeros, 12h format + if ($date['hours'] > 12) { + $hour = $date['hours'] - 12; + } else { + if ($date['hours'] == 0) { + $hour = '12'; + } else { + $hour = $date['hours']; + } + } + $output .= (($hour < 10) ? '0'.$hour : $hour); + break; + + case 'H': // hours with leading zeros, 24h format + $output .= (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']); + break; + + case 'i': // minutes with leading zeros + $output .= (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']); + break; + + case 's': // seconds with leading zeros + $output .= (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']); + break; + + + // timezone formats + case 'e': // timezone identifier + if ($gmt === true) { + $output .= gmdate('e', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('e', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'I': // daylight saving time or not + if ($gmt === true) { + $output .= gmdate('I', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('I', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'O': // difference to GMT in hours + $gmtstr = ($gmt === true) ? 0 : $this->getGmtOffset(); + $output .= sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36); + break; + + case 'P': // difference to GMT with colon + $gmtstr = ($gmt === true) ? 0 : $this->getGmtOffset(); + $gmtstr = sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36); + $output = $output . substr($gmtstr, 0, 3) . ':' . substr($gmtstr, 3); + break; + + case 'T': // timezone settings + if ($gmt === true) { + $output .= gmdate('T', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('T', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'Z': // timezone offset in seconds + $output .= ($gmt === true) ? 0 : -$this->getGmtOffset(); + break; + + + // complete time formats + case 'c': // ISO 8601 date format + $difference = $this->getGmtOffset(); + $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36); + $output .= $date['year'] . '-' + . (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']) . '-' + . (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']) . 'T' + . (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']) . ':' + . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':' + . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']) + . $difference; + break; + + case 'r': // RFC 2822 date format + $difference = $this->getGmtOffset(); + $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36); + $output .= gmdate('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))) . ', ' + . (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']) . ' ' + . date('M', mktime(0, 0, 0, $date['mon'], 2, 1971)) . ' ' + . $date['year'] . ' ' + . (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']) . ':' + . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':' + . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']) . ' ' + . $difference; + break; + + case 'U': // Unix timestamp + $output .= $timestamp; + break; + + + // special formats + case "\\": // next letter to print with no format + $i++; + if ($i < $length) { + $output .= $format[$i]; + } + break; + + default: // letter is no format so add it direct + $output .= $format[$i]; + break; + } + } + + return (string) $output; + } + + /** + * Returns the day of week for a Gregorian calendar date. + * 0 = sunday, 6 = saturday + * + * @param integer $year + * @param integer $month + * @param integer $day + * @return integer dayOfWeek + */ + protected static function dayOfWeek($year, $month, $day) + { + if ((1901 < $year) and ($year < 2038)) { + return (int) date('w', mktime(0, 0, 0, $month, $day, $year)); + } + + // gregorian correction + $correction = 0; + if (($year < 1582) or (($year == 1582) and (($month < 10) or (($month == 10) && ($day < 15))))) { + $correction = 3; + } + + if ($month > 2) { + $month -= 2; + } else { + $month += 10; + $year--; + } + + $day = floor((13 * $month - 1) / 5) + $day + ($year % 100) + floor(($year % 100) / 4); + $day += floor(($year / 100) / 4) - 2 * floor($year / 100) + 77 + $correction; + + return (int) ($day - 7 * floor($day / 7)); + } + + /** + * Internal getDateParts function for handling 64bit timestamps, similar to: + * http://www.php.net/getdate + * + * Returns an array of date parts for $timestamp, relative to 1970/01/01 00:00:00 GMT/UTC. + * + * $fast specifies ALL date parts should be returned (slower) + * Default is false, and excludes $dayofweek, weekday, month and timestamp from parts returned. + * + * @param mixed $timestamp + * @param boolean $fast OPTIONAL defaults to fast (false), resulting in fewer date parts + * @return array + */ + protected function getDateParts($timestamp = null, $fast = null) + { + + // actual timestamp + if (!is_numeric($timestamp)) { + return getdate(); + } + + // 32bit timestamp + if (abs($timestamp) <= 0x7FFFFFFF) { + return @getdate((int) $timestamp); + } + + if (isset(self::$_cache)) { + $id = strtr('Zend_DateObject_getDateParts_' . $timestamp.'_'.(int)$fast, '-','_'); + if ($result = self::$_cache->load($id)) { + return unserialize($result); + } + } + + $otimestamp = $timestamp; + $numday = 0; + $month = 0; + // gregorian correction + if ($timestamp < -12219321600) { + $timestamp -= 864000; + } + + // timestamp lower 0 + if ($timestamp < 0) { + $sec = 0; + $act = 1970; + + // iterate through 10 years table, increasing speed + foreach(self::$_yearTable as $year => $seconds) { + if ($timestamp >= $seconds) { + $i = $act; + break; + } + $sec = $seconds; + $act = $year; + } + + $timestamp -= $sec; + if (!isset($i)) { + $i = $act; + } + + // iterate the max last 10 years + do { + --$i; + $day = $timestamp; + + $timestamp += 31536000; + $leapyear = self::isYearLeapYear($i); + if ($leapyear === true) { + $timestamp += 86400; + } + + if ($timestamp >= 0) { + $year = $i; + break; + } + } while ($timestamp < 0); + + $secondsPerYear = 86400 * ($leapyear ? 366 : 365) + $day; + + $timestamp = $day; + // iterate through months + for ($i = 12; --$i >= 0;) { + $day = $timestamp; + + $timestamp += self::$_monthTable[$i] * 86400; + if (($leapyear === true) and ($i == 1)) { + $timestamp += 86400; + } + + if ($timestamp >= 0) { + $month = $i; + $numday = self::$_monthTable[$i]; + if (($leapyear === true) and ($i == 1)) { + ++$numday; + } + break; + } + } + + $timestamp = $day; + $numberdays = $numday + ceil(($timestamp + 1) / 86400); + + $timestamp += ($numday - $numberdays + 1) * 86400; + $hours = floor($timestamp / 3600); + } else { + + // iterate through years + for ($i = 1970;;$i++) { + $day = $timestamp; + + $timestamp -= 31536000; + $leapyear = self::isYearLeapYear($i); + if ($leapyear === true) { + $timestamp -= 86400; + } + + if ($timestamp < 0) { + $year = $i; + break; + } + } + + $secondsPerYear = $day; + + $timestamp = $day; + // iterate through months + for ($i = 0; $i <= 11; $i++) { + $day = $timestamp; + $timestamp -= self::$_monthTable[$i] * 86400; + + if (($leapyear === true) and ($i == 1)) { + $timestamp -= 86400; + } + + if ($timestamp < 0) { + $month = $i; + $numday = self::$_monthTable[$i]; + if (($leapyear === true) and ($i == 1)) { + ++$numday; + } + break; + } + } + + $timestamp = $day; + $numberdays = ceil(($timestamp + 1) / 86400); + $timestamp = $timestamp - ($numberdays - 1) * 86400; + $hours = floor($timestamp / 3600); + } + + $timestamp -= $hours * 3600; + + $month += 1; + $minutes = floor($timestamp / 60); + $seconds = $timestamp - $minutes * 60; + + if ($fast === true) { + $array = array( + 'seconds' => $seconds, + 'minutes' => $minutes, + 'hours' => $hours, + 'mday' => $numberdays, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secondsPerYear / 86400), + ); + } else { + + $dayofweek = self::dayOfWeek($year, $month, $numberdays); + $array = array( + 'seconds' => $seconds, + 'minutes' => $minutes, + 'hours' => $hours, + 'mday' => $numberdays, + 'wday' => $dayofweek, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secondsPerYear / 86400), + 'weekday' => gmdate('l', 86400 * (3 + $dayofweek)), + 'month' => gmdate('F', mktime(0, 0, 0, $month, 1, 1971)), + 0 => $otimestamp + ); + } + + if (isset(self::$_cache)) { + self::$_cache->save( serialize($array), $id); + } + + return $array; + } + + /** + * Internal getWeekNumber function for handling 64bit timestamps + * + * Returns the ISO 8601 week number of a given date + * + * @param integer $year + * @param integer $month + * @param integer $day + * @return integer + */ + protected function weekNumber($year, $month, $day) + { + if ((1901 < $year) and ($year < 2038)) { + return (int) date('W', mktime(0, 0, 0, $month, $day, $year)); + } + + $dayofweek = self::dayOfWeek($year, $month, $day); + $firstday = self::dayOfWeek($year, 1, 1); + if (($month == 1) and (($firstday < 1) or ($firstday > 4)) and ($day < 4)) { + $firstday = self::dayOfWeek($year - 1, 1, 1); + $month = 12; + $day = 31; + + } else if (($month == 12) and ((self::dayOfWeek($year + 1, 1, 1) < 5) and + (self::dayOfWeek($year + 1, 1, 1) > 0))) { + return 1; + } + + return intval (((self::dayOfWeek($year, 1, 1) < 5) and (self::dayOfWeek($year, 1, 1) > 0)) + + 4 * ($month - 1) + (2 * ($month - 1) + ($day - 1) + $firstday - $dayofweek + 6) * 36 / 256); + } + + /** + * Internal _range function + * Sets the value $a to be in the range of [0, $b] + * + * @param float $a - value to correct + * @param float $b - maximum range to set + */ + private function _range($a, $b) { + while ($a < 0) { + $a += $b; + } + while ($a >= $b) { + $a -= $b; + } + return $a; + } + + /** + * Calculates the sunrise or sunset based on a location + * + * @param array $location Location for calculation MUST include 'latitude', 'longitude', 'horizon' + * @param bool $horizon true: sunrise; false: sunset + * @return mixed - false: midnight sun, integer: + */ + protected function calcSun($location, $horizon, $rise = false) + { + // timestamp within 32bit + if (abs($this->_unixTimestamp) <= 0x7FFFFFFF) { + if ($rise === false) { + return date_sunset($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'], + $location['longitude'], 90 + $horizon, $this->getGmtOffset() / 3600); + } + return date_sunrise($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'], + $location['longitude'], 90 + $horizon, $this->getGmtOffset() / 3600); + } + + // self calculation - timestamp bigger than 32bit + // fix circle values + $quarterCircle = 0.5 * M_PI; + $halfCircle = M_PI; + $threeQuarterCircle = 1.5 * M_PI; + $fullCircle = 2 * M_PI; + + // radiant conversion for coordinates + $radLatitude = $location['latitude'] * $halfCircle / 180; + $radLongitude = $location['longitude'] * $halfCircle / 180; + + // get solar coordinates + $tmpRise = $rise ? $quarterCircle : $threeQuarterCircle; + $radDay = $this->date('z',$this->_unixTimestamp) + ($tmpRise - $radLongitude) / $fullCircle; + + // solar anomoly and longitude + $solAnomoly = $radDay * 0.017202 - 0.0574039; + $solLongitude = $solAnomoly + 0.0334405 * sin($solAnomoly); + $solLongitude += 4.93289 + 3.49066E-4 * sin(2 * $solAnomoly); + + // get quadrant + $solLongitude = $this->_range($solLongitude, $fullCircle); + + if (($solLongitude / $quarterCircle) - intval($solLongitude / $quarterCircle) == 0) { + $solLongitude += 4.84814E-6; + } + + // solar ascension + $solAscension = sin($solLongitude) / cos($solLongitude); + $solAscension = atan2(0.91746 * $solAscension, 1); + + // adjust quadrant + if ($solLongitude > $threeQuarterCircle) { + $solAscension += $fullCircle; + } else if ($solLongitude > $quarterCircle) { + $solAscension += $halfCircle; + } + + // solar declination + $solDeclination = 0.39782 * sin($solLongitude); + $solDeclination /= sqrt(-$solDeclination * $solDeclination + 1); + $solDeclination = atan2($solDeclination, 1); + + $solHorizon = $horizon - sin($solDeclination) * sin($radLatitude); + $solHorizon /= cos($solDeclination) * cos($radLatitude); + + // midnight sun, always night + if (abs($solHorizon) > 1) { + return false; + } + + $solHorizon /= sqrt(-$solHorizon * $solHorizon + 1); + $solHorizon = $quarterCircle - atan2($solHorizon, 1); + + if ($rise) { + $solHorizon = $fullCircle - $solHorizon; + } + + // time calculation + $localTime = $solHorizon + $solAscension - 0.0172028 * $radDay - 1.73364; + $universalTime = $localTime - $radLongitude; + + // determinate quadrant + $universalTime = $this->_range($universalTime, $fullCircle); + + // radiant to hours + $universalTime *= 24 / $fullCircle; + + // convert to time + $hour = intval($universalTime); + $universalTime = ($universalTime - $hour) * 60; + $min = intval($universalTime); + $universalTime = ($universalTime - $min) * 60; + $sec = intval($universalTime); + + return $this->mktime($hour, $min, $sec, $this->date('m', $this->_unixTimestamp), + $this->date('j', $this->_unixTimestamp), $this->date('Y', $this->_unixTimestamp), + -1, true); + } + + /** + * Sets a new timezone for calculation of $this object's gmt offset. + * For a list of supported timezones look here: http://php.net/timezones + * If no timezone can be detected or the given timezone is wrong UTC will be set. + * + * @param string $zone OPTIONAL timezone for date calculation; defaults to date_default_timezone_get() + * @return Zend_Date_DateObject Provides fluent interface + * @throws Zend_Date_Exception + */ + public function setTimezone($zone = null) + { + $oldzone = @date_default_timezone_get(); + if ($zone === null) { + $zone = $oldzone; + } + + // throw an error on false input, but only if the new date extension is available + if (function_exists('timezone_open')) { + if (!@timezone_open($zone)) { + require_once 'Zend/Date/Exception.php'; + throw new Zend_Date_Exception("timezone ($zone) is not a known timezone", $zone); + } + } + // this can generate an error if the date extension is not available and a false timezone is given + $result = @date_default_timezone_set($zone); + if ($result === true) { + $this->_offset = mktime(0, 0, 0, 1, 2, 1970) - gmmktime(0, 0, 0, 1, 2, 1970); + $this->_timezone = $zone; + } + date_default_timezone_set($oldzone); + + if (($zone == 'UTC') or ($zone == 'GMT')) { + $this->_dst = false; + } else { + $this->_dst = true; + } + + return $this; + } + + /** + * Return the timezone of $this object. + * The timezone is initially set when the object is instantiated. + * + * @return string actual set timezone string + */ + public function getTimezone() + { + return $this->_timezone; + } + + /** + * Return the offset to GMT of $this object's timezone. + * The offset to GMT is initially set when the object is instantiated using the currently, + * in effect, default timezone for PHP functions. + * + * @return integer seconds difference between GMT timezone and timezone when object was instantiated + */ + public function getGmtOffset() + { + $date = $this->getDateParts($this->getUnixTimestamp(), true); + $zone = @date_default_timezone_get(); + $result = @date_default_timezone_set($this->_timezone); + if ($result === true) { + $offset = $this->mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], $date['year'], false) + - $this->mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], $date['year'], true); + } + date_default_timezone_set($zone); + + return $offset; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Date/Exception.php b/ThinkPHP/Extend/Vendor/Zend/Date/Exception.php new file mode 100644 index 0000000..ed73470 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Date/Exception.php @@ -0,0 +1,49 @@ +operand = $op; + parent::__construct($message); + } + + public function getOperand() + { + return $this->operand; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Exception.php b/ThinkPHP/Extend/Vendor/Zend/Exception.php new file mode 100644 index 0000000..57f14a5 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Exception.php @@ -0,0 +1,31 @@ + $dir) { + if ($dir == '.') { + $dirs[$key] = $dirPath; + } else { + $dir = rtrim($dir, '\\/'); + $dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath; + } + } + $file = basename($file); + self::loadFile($file, $dirs, true); + } else { + self::_securityCheck($file); + include $file; + } + + if (!class_exists($class, false) && !interface_exists($class, false)) { + require_once 'Zend/Exception.php'; + throw new Zend_Exception("File \"$file\" does not exist or class \"$class\" was not found in the file"); + } + } + + /** + * Loads a PHP file. This is a wrapper for PHP's include() function. + * + * $filename must be the complete filename, including any + * extension such as ".php". Note that a security check is performed that + * does not permit extended characters in the filename. This method is + * intended for loading Zend Framework files. + * + * If $dirs is a string or an array, it will search the directories + * in the order supplied, and attempt to load the first matching file. + * + * If the file was not found in the $dirs, or if no $dirs were specified, + * it will attempt to load it from PHP's include_path. + * + * If $once is TRUE, it will use include_once() instead of include(). + * + * @param string $filename + * @param string|array $dirs - OPTIONAL either a path or array of paths + * to search. + * @param boolean $once + * @return boolean + * @throws Zend_Exception + */ + public static function loadFile($filename, $dirs = null, $once = false) + { + self::_securityCheck($filename); + + /** + * Search in provided directories, as well as include_path + */ + $incPath = false; + if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) { + if (is_array($dirs)) { + $dirs = implode(PATH_SEPARATOR, $dirs); + } + $incPath = get_include_path(); + set_include_path($dirs . PATH_SEPARATOR . $incPath); + } + + /** + * Try finding for the plain filename in the include_path. + */ + if ($once) { + include_once $filename; + } else { + include $filename; + } + + /** + * If searching in directories, reset include_path + */ + if ($incPath) { + set_include_path($incPath); + } + + return true; + } + + /** + * Returns TRUE if the $filename is readable, or FALSE otherwise. + * This function uses the PHP include_path, where PHP's is_readable() + * does not. + * + * Note from ZF-2900: + * If you use custom error handler, please check whether return value + * from error_reporting() is zero or not. + * At mark of fopen() can not suppress warning if the handler is used. + * + * @param string $filename + * @return boolean + */ + public static function isReadable($filename) + { + if (!$fh = @fopen($filename, 'r', true)) { + return false; + } + @fclose($fh); + return true; + } + + /** + * spl_autoload() suitable implementation for supporting class autoloading. + * + * Attach to spl_autoload() using the following: + * + * spl_autoload_register(array('Zend_Loader', 'autoload')); + * + * + * @deprecated Since 1.8.0 + * @param string $class + * @return string|false Class name on success; false on failure + */ + public static function autoload($class) + { + trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE); + try { + @self::loadClass($class); + return $class; + } catch (Exception $e) { + return false; + } + } + + /** + * Register {@link autoload()} with spl_autoload() + * + * @deprecated Since 1.8.0 + * @param string $class (optional) + * @param boolean $enabled (optional) + * @return void + * @throws Zend_Exception if spl_autoload() is not found + * or if the specified class does not have an autoload() method. + */ + public static function registerAutoload($class = 'Zend_Loader', $enabled = true) + { + trigger_error(__CLASS__ . '::' . __METHOD__ . ' is deprecated as of 1.8.0 and will be removed with 2.0.0; use Zend_Loader_Autoloader instead', E_USER_NOTICE); + require_once 'Zend/Loader/Autoloader.php'; + $autoloader = Zend_Loader_Autoloader::getInstance(); + $autoloader->setFallbackAutoloader(true); + + if ('Zend_Loader' != $class) { + self::loadClass($class); + $methods = get_class_methods($class); + if (!in_array('autoload', (array) $methods)) { + require_once 'Zend/Exception.php'; + throw new Zend_Exception("The class \"$class\" does not have an autoload() method"); + } + + $callback = array($class, 'autoload'); + + if ($enabled) { + $autoloader->pushAutoloader($callback); + } else { + $autoloader->removeAutoloader($callback); + } + } + } + + /** + * Ensure that filename does not contain exploits + * + * @param string $filename + * @return void + * @throws Zend_Exception + */ + protected static function _securityCheck($filename) + { + /** + * Security check + */ + if (preg_match('/[^a-z0-9\\/\\\\_.:-]/i', $filename)) { + require_once 'Zend/Exception.php'; + throw new Zend_Exception('Security check: Illegal character in filename'); + } + } + + /** + * Attempt to include() the file. + * + * include() is not prefixed with the @ operator because if + * the file is loaded and contains a parse error, execution + * will halt silently and this is difficult to debug. + * + * Always set display_errors = Off on production servers! + * + * @param string $filespec + * @param boolean $once + * @return boolean + * @deprecated Since 1.5.0; use loadFile() instead + */ + protected static function _includeFile($filespec, $once = false) + { + if ($once) { + return include_once $filespec; + } else { + return include $filespec ; + } + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Loader/Autoloader.php b/ThinkPHP/Extend/Vendor/Zend/Loader/Autoloader.php new file mode 100644 index 0000000..0e7ac61 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Loader/Autoloader.php @@ -0,0 +1,584 @@ + true, + 'ZendX_' => true, + ); + + /** + * @var array Namespace-specific autoloaders + */ + protected $_namespaceAutoloaders = array(); + + /** + * @var bool Whether or not to suppress file not found warnings + */ + protected $_suppressNotFoundWarnings = false; + + /** + * @var null|string + */ + protected $_zfPath; + + /** + * Retrieve singleton instance + * + * @return Zend_Loader_Autoloader + */ + public static function getInstance() + { + if (null === self::$_instance) { + self::$_instance = new self(); + } + return self::$_instance; + } + + /** + * Reset the singleton instance + * + * @return void + */ + public static function resetInstance() + { + self::$_instance = null; + } + + /** + * Autoload a class + * + * @param string $class + * @return bool + */ + public static function autoload($class) + { + $self = self::getInstance(); + + foreach ($self->getClassAutoloaders($class) as $autoloader) { + if ($autoloader instanceof Zend_Loader_Autoloader_Interface) { + if ($autoloader->autoload($class)) { + return true; + } + } elseif (is_string($autoloader)) { + if ($autoloader($class)) { + return true; + } + } elseif (is_array($autoloader)) { + $object = array_shift($autoloader); + $method = array_shift($autoloader); + if (call_user_func(array($object, $method), $class)) { + return true; + } + } + } + + return false; + } + + /** + * Set the default autoloader implementation + * + * @param string|array $callback PHP callback + * @return void + */ + public function setDefaultAutoloader($callback) + { + if (!is_callable($callback)) { + throw new Zend_Loader_Exception('Invalid callback specified for default autoloader'); + } + + $this->_defaultAutoloader = $callback; + return $this; + } + + /** + * Retrieve the default autoloader callback + * + * @return string|array PHP Callback + */ + public function getDefaultAutoloader() + { + return $this->_defaultAutoloader; + } + + /** + * Set several autoloader callbacks at once + * + * @param array $autoloaders Array of PHP callbacks (or Zend_Loader_Autoloader_Interface implementations) to act as autoloaders + * @return Zend_Loader_Autoloader + */ + public function setAutoloaders(array $autoloaders) + { + $this->_autoloaders = $autoloaders; + return $this; + } + + /** + * Get attached autoloader implementations + * + * @return array + */ + public function getAutoloaders() + { + return $this->_autoloaders; + } + + /** + * Return all autoloaders for a given namespace + * + * @param string $namespace + * @return array + */ + public function getNamespaceAutoloaders($namespace) + { + $namespace = (string) $namespace; + if (!array_key_exists($namespace, $this->_namespaceAutoloaders)) { + return array(); + } + return $this->_namespaceAutoloaders[$namespace]; + } + + /** + * Register a namespace to autoload + * + * @param string|array $namespace + * @return Zend_Loader_Autoloader + */ + public function registerNamespace($namespace) + { + if (is_string($namespace)) { + $namespace = (array) $namespace; + } elseif (!is_array($namespace)) { + throw new Zend_Loader_Exception('Invalid namespace provided'); + } + + foreach ($namespace as $ns) { + if (!isset($this->_namespaces[$ns])) { + $this->_namespaces[$ns] = true; + } + } + return $this; + } + + /** + * Unload a registered autoload namespace + * + * @param string|array $namespace + * @return Zend_Loader_Autoloader + */ + public function unregisterNamespace($namespace) + { + if (is_string($namespace)) { + $namespace = (array) $namespace; + } elseif (!is_array($namespace)) { + throw new Zend_Loader_Exception('Invalid namespace provided'); + } + + foreach ($namespace as $ns) { + if (isset($this->_namespaces[$ns])) { + unset($this->_namespaces[$ns]); + } + } + return $this; + } + + /** + * Get a list of registered autoload namespaces + * + * @return array + */ + public function getRegisteredNamespaces() + { + return array_keys($this->_namespaces); + } + + public function setZfPath($spec, $version = 'latest') + { + $path = $spec; + if (is_array($spec)) { + if (!isset($spec['path'])) { + throw new Zend_Loader_Exception('No path specified for ZF'); + } + $path = $spec['path']; + if (isset($spec['version'])) { + $version = $spec['version']; + } + } + + $this->_zfPath = $this->_getVersionPath($path, $version); + set_include_path(implode(PATH_SEPARATOR, array( + $this->_zfPath, + get_include_path(), + ))); + return $this; + } + + public function getZfPath() + { + return $this->_zfPath; + } + + /** + * Get or set the value of the "suppress not found warnings" flag + * + * @param null|bool $flag + * @return bool|Zend_Loader_Autoloader Returns boolean if no argument is passed, object instance otherwise + */ + public function suppressNotFoundWarnings($flag = null) + { + if (null === $flag) { + return $this->_suppressNotFoundWarnings; + } + $this->_suppressNotFoundWarnings = (bool) $flag; + return $this; + } + + /** + * Indicate whether or not this autoloader should be a fallback autoloader + * + * @param bool $flag + * @return Zend_Loader_Autoloader + */ + public function setFallbackAutoloader($flag) + { + $this->_fallbackAutoloader = (bool) $flag; + return $this; + } + + /** + * Is this instance acting as a fallback autoloader? + * + * @return bool + */ + public function isFallbackAutoloader() + { + return $this->_fallbackAutoloader; + } + + /** + * Get autoloaders to use when matching class + * + * Determines if the class matches a registered namespace, and, if so, + * returns only the autoloaders for that namespace. Otherwise, it returns + * all non-namespaced autoloaders. + * + * @param string $class + * @return array Array of autoloaders to use + */ + public function getClassAutoloaders($class) + { + $namespace = false; + $autoloaders = array(); + + // Add concrete namespaced autoloaders + foreach (array_keys($this->_namespaceAutoloaders) as $ns) { + if ('' == $ns) { + continue; + } + if (0 === strpos($class, $ns)) { + $namespace = $ns; + $autoloaders = $autoloaders + $this->getNamespaceAutoloaders($ns); + break; + } + } + + // Add internal namespaced autoloader + foreach ($this->getRegisteredNamespaces() as $ns) { + if (0 === strpos($class, $ns)) { + $namespace = $ns; + $autoloaders[] = $this->_internalAutoloader; + break; + } + } + + // Add non-namespaced autoloaders + $autoloaders = $autoloaders + $this->getNamespaceAutoloaders(''); + + // Add fallback autoloader + if (!$namespace && $this->isFallbackAutoloader()) { + $autoloaders[] = $this->_internalAutoloader; + } + + return $autoloaders; + } + + /** + * Add an autoloader to the beginning of the stack + * + * @param object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation + * @param string|array $namespace Specific namespace(s) under which to register callback + * @return Zend_Loader_Autoloader + */ + public function unshiftAutoloader($callback, $namespace = '') + { + $autoloaders = $this->getAutoloaders(); + array_unshift($autoloaders, $callback); + $this->setAutoloaders($autoloaders); + + $namespace = (array) $namespace; + foreach ($namespace as $ns) { + $autoloaders = $this->getNamespaceAutoloaders($ns); + array_unshift($autoloaders, $callback); + $this->_setNamespaceAutoloaders($autoloaders, $ns); + } + + return $this; + } + + /** + * Append an autoloader to the autoloader stack + * + * @param object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation + * @param string|array $namespace Specific namespace(s) under which to register callback + * @return Zend_Loader_Autoloader + */ + public function pushAutoloader($callback, $namespace = '') + { + $autoloaders = $this->getAutoloaders(); + array_push($autoloaders, $callback); + $this->setAutoloaders($autoloaders); + + $namespace = (array) $namespace; + foreach ($namespace as $ns) { + $autoloaders = $this->getNamespaceAutoloaders($ns); + array_push($autoloaders, $callback); + $this->_setNamespaceAutoloaders($autoloaders, $ns); + } + + return $this; + } + + /** + * Remove an autoloader from the autoloader stack + * + * @param object|array|string $callback PHP callback or Zend_Loader_Autoloader_Interface implementation + * @param null|string|array $namespace Specific namespace(s) from which to remove autoloader + * @return Zend_Loader_Autoloader + */ + public function removeAutoloader($callback, $namespace = null) + { + if (null === $namespace) { + $autoloaders = $this->getAutoloaders(); + if (false !== ($index = array_search($callback, $autoloaders, true))) { + unset($autoloaders[$index]); + $this->setAutoloaders($autoloaders); + } + + foreach ($this->_namespaceAutoloaders as $ns => $autoloaders) { + if (false !== ($index = array_search($callback, $autoloaders, true))) { + unset($autoloaders[$index]); + $this->_setNamespaceAutoloaders($autoloaders, $ns); + } + } + } else { + $namespace = (array) $namespace; + foreach ($namespace as $ns) { + $autoloaders = $this->getNamespaceAutoloaders($ns); + if (false !== ($index = array_search($callback, $autoloaders, true))) { + unset($autoloaders[$index]); + $this->_setNamespaceAutoloaders($autoloaders, $ns); + } + } + } + + return $this; + } + + /** + * Constructor + * + * Registers instance with spl_autoload stack + * + * @return void + */ + protected function __construct() + { + spl_autoload_register(array(__CLASS__, 'autoload')); + $this->_internalAutoloader = array($this, '_autoload'); + } + + /** + * Internal autoloader implementation + * + * @param string $class + * @return bool + */ + protected function _autoload($class) + { + $callback = $this->getDefaultAutoloader(); + try { + if ($this->suppressNotFoundWarnings()) { + @call_user_func($callback, $class); + } else { + call_user_func($callback, $class); + } + return $class; + } catch (Zend_Exception $e) { + return false; + } + } + + /** + * Set autoloaders for a specific namespace + * + * @param array $autoloaders + * @param string $namespace + * @return Zend_Loader_Autoloader + */ + protected function _setNamespaceAutoloaders(array $autoloaders, $namespace = '') + { + $namespace = (string) $namespace; + $this->_namespaceAutoloaders[$namespace] = $autoloaders; + return $this; + } + + /** + * Retrieve the filesystem path for the requested ZF version + * + * @param string $path + * @param string $version + * @return void + */ + protected function _getVersionPath($path, $version) + { + $type = $this->_getVersionType($version); + + if ($type == 'latest') { + $version = 'latest'; + } + + $availableVersions = $this->_getAvailableVersions($path, $version); + if (empty($availableVersions)) { + throw new Zend_Loader_Exception('No valid ZF installations discovered'); + } + + $matchedVersion = array_pop($availableVersions); + return $matchedVersion; + } + + /** + * Retrieve the ZF version type + * + * @param string $version + * @return string "latest", "major", "minor", or "specific" + * @throws Zend_Loader_Exception if version string contains too many dots + */ + protected function _getVersionType($version) + { + if (strtolower($version) == 'latest') { + return 'latest'; + } + + $parts = explode('.', $version); + $count = count($parts); + if (1 == $count) { + return 'major'; + } + if (2 == $count) { + return 'minor'; + } + if (3 < $count) { + throw new Zend_Loader_Exception('Invalid version string provided'); + } + return 'specific'; + } + + /** + * Get available versions for the version type requested + * + * @param string $path + * @param string $version + * @return array + */ + protected function _getAvailableVersions($path, $version) + { + if (!is_dir($path)) { + throw new Zend_Loader_Exception('Invalid ZF path provided'); + } + + $path = rtrim($path, '/'); + $path = rtrim($path, '\\'); + $versionLen = strlen($version); + $versions = array(); + $dirs = glob("$path/*", GLOB_ONLYDIR); + foreach ($dirs as $dir) { + $dirName = substr($dir, strlen($path) + 1); + if (!preg_match('/^(?:ZendFramework-)?(\d+\.\d+\.\d+((a|b|pl|pr|p|rc)\d+)?)(?:-minimal)?$/i', $dirName, $matches)) { + continue; + } + + $matchedVersion = $matches[1]; + + if (('latest' == $version) + || ((strlen($matchedVersion) >= $versionLen) + && (0 === strpos($matchedVersion, $version))) + ) { + $versions[$matchedVersion] = $dir . '/library'; + } + } + + uksort($versions, 'version_compare'); + return $versions; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Loader/Autoloader/Interface.php b/ThinkPHP/Extend/Vendor/Zend/Loader/Autoloader/Interface.php new file mode 100644 index 0000000..f847ac5 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Loader/Autoloader/Interface.php @@ -0,0 +1,34 @@ +toArray(); + } + if (!is_array($options)) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception('Options must be passed to resource loader constructor'); + } + + $this->setOptions($options); + + $namespace = $this->getNamespace(); + if ((null === $namespace) + || (null === $this->getBasePath()) + ) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception('Resource loader requires both a namespace and a base path for initialization'); + } + + if (!empty($namespace)) { + $namespace .= '_'; + } + Zend_Loader_Autoloader::getInstance()->unshiftAutoloader($this, $namespace); + } + + /** + * Overloading: methods + * + * Allow retrieving concrete resource object instances using 'get()' + * syntax. Example: + * + * $loader = new Zend_Loader_Autoloader_Resource(array( + * 'namespace' => 'Stuff_', + * 'basePath' => '/path/to/some/stuff', + * )) + * $loader->addResourceType('Model', 'models', 'Model'); + * + * $foo = $loader->getModel('Foo'); // get instance of Stuff_Model_Foo class + * + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Loader_Exception if method not beginning with 'get' or not matching a valid resource type is called + */ + public function __call($method, $args) + { + if ('get' == substr($method, 0, 3)) { + $type = strtolower(substr($method, 3)); + if (!$this->hasResourceType($type)) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception("Invalid resource type $type; cannot load resource"); + } + if (empty($args)) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception("Cannot load resources; no resource specified"); + } + $resource = array_shift($args); + return $this->load($resource, $type); + } + + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception("Method '$method' is not supported"); + } + + /** + * Attempt to autoload a class + * + * @param string $class + * @return mixed False if not matched, otherwise result if include operation + */ + public function autoload($class) + { + $segments = explode('_', $class); + $namespaceTopLevel = $this->getNamespace(); + $namespace = ''; + + if (!empty($namespaceTopLevel)) { + $namespace = array_shift($segments); + if ($namespace != $namespaceTopLevel) { + // wrong prefix? we're done + return false; + } + } + + if (count($segments) < 2) { + // assumes all resources have a component and class name, minimum + return false; + } + + $final = array_pop($segments); + $component = $namespace; + $lastMatch = false; + do { + $segment = array_shift($segments); + $component .= empty($component) ? $segment : '_' . $segment; + if (isset($this->_components[$component])) { + $lastMatch = $component; + } + } while (count($segments)); + + if (!$lastMatch) { + return false; + } + + $final = substr($class, strlen($lastMatch)); + $path = $this->_components[$lastMatch]; + return include $path . '/' . str_replace('_', '/', $final) . '.php'; + } + + /** + * Set class state from options + * + * @param array $options + * @return Zend_Loader_Autoloader_Resource + */ + public function setOptions(array $options) + { + $methods = get_class_methods($this); + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (in_array($method, $methods)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set namespace that this autoloader handles + * + * @param string $namespace + * @return Zend_Loader_Autoloader_Resource + */ + public function setNamespace($namespace) + { + $this->_namespace = rtrim((string) $namespace, '_'); + return $this; + } + + /** + * Get namespace this autoloader handles + * + * @return string + */ + public function getNamespace() + { + return $this->_namespace; + } + + /** + * Set base path for this set of resources + * + * @param string $path + * @return Zend_Loader_Autoloader_Resource + */ + public function setBasePath($path) + { + $this->_basePath = (string) $path; + return $this; + } + + /** + * Get base path to this set of resources + * + * @return string + */ + public function getBasePath() + { + return $this->_basePath; + } + + /** + * Add resource type + * + * @param string $type identifier for the resource type being loaded + * @param string $path path relative to resource base path containing the resource types + * @param null|string $namespace sub-component namespace to append to base namespace that qualifies this resource type + * @return Zend_Loader_Autoloader_Resource + */ + public function addResourceType($type, $path, $namespace = null) + { + $type = strtolower($type); + if (!isset($this->_resourceTypes[$type])) { + if (null === $namespace) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception('Initial definition of a resource type must include a namespace'); + } + $namespaceTopLevel = $this->getNamespace(); + $namespace = ucfirst(trim($namespace, '_')); + $this->_resourceTypes[$type] = array( + 'namespace' => empty($namespaceTopLevel) ? $namespace : $namespaceTopLevel . '_' . $namespace, + ); + } + if (!is_string($path)) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception('Invalid path specification provided; must be string'); + } + $this->_resourceTypes[$type]['path'] = $this->getBasePath() . '/' . rtrim($path, '\/'); + + $component = $this->_resourceTypes[$type]['namespace']; + $this->_components[$component] = $this->_resourceTypes[$type]['path']; + return $this; + } + + /** + * Add multiple resources at once + * + * $types should be an associative array of resource type => specification + * pairs. Each specification should be an associative array containing + * minimally the 'path' key (specifying the path relative to the resource + * base path) and optionally the 'namespace' key (indicating the subcomponent + * namespace to append to the resource namespace). + * + * As an example: + * + * $loader->addResourceTypes(array( + * 'model' => array( + * 'path' => 'models', + * 'namespace' => 'Model', + * ), + * 'form' => array( + * 'path' => 'forms', + * 'namespace' => 'Form', + * ), + * )); + * + * + * @param array $types + * @return Zend_Loader_Autoloader_Resource + */ + public function addResourceTypes(array $types) + { + foreach ($types as $type => $spec) { + if (!is_array($spec)) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception('addResourceTypes() expects an array of arrays'); + } + if (!isset($spec['path'])) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception('addResourceTypes() expects each array to include a paths element'); + } + $paths = $spec['path']; + $namespace = null; + if (isset($spec['namespace'])) { + $namespace = $spec['namespace']; + } + $this->addResourceType($type, $paths, $namespace); + } + return $this; + } + + /** + * Overwrite existing and set multiple resource types at once + * + * @see Zend_Loader_Autoloader_Resource::addResourceTypes() + * @param array $types + * @return Zend_Loader_Autoloader_Resource + */ + public function setResourceTypes(array $types) + { + $this->clearResourceTypes(); + return $this->addResourceTypes($types); + } + + /** + * Retrieve resource type mappings + * + * @return array + */ + public function getResourceTypes() + { + return $this->_resourceTypes; + } + + /** + * Is the requested resource type defined? + * + * @param string $type + * @return bool + */ + public function hasResourceType($type) + { + return isset($this->_resourceTypes[$type]); + } + + /** + * Remove the requested resource type + * + * @param string $type + * @return Zend_Loader_Autoloader_Resource + */ + public function removeResourceType($type) + { + if ($this->hasResourceType($type)) { + $namespace = $this->_resourceTypes[$type]['namespace']; + unset($this->_components[$namespace]); + unset($this->_resourceTypes[$type]); + } + return $this; + } + + /** + * Clear all resource types + * + * @return Zend_Loader_Autoloader_Resource + */ + public function clearResourceTypes() + { + $this->_resourceTypes = array(); + $this->_components = array(); + return $this; + } + + /** + * Set default resource type to use when calling load() + * + * @param string $type + * @return Zend_Loader_Autoloader_Resource + */ + public function setDefaultResourceType($type) + { + if ($this->hasResourceType($type)) { + $this->_defaultResourceType = $type; + } + return $this; + } + + /** + * Get default resource type to use when calling load() + * + * @return string|null + */ + public function getDefaultResourceType() + { + return $this->_defaultResourceType; + } + + /** + * Object registry and factory + * + * Loads the requested resource of type $type (or uses the default resource + * type if none provided). If the resource has been loaded previously, + * returns the previous instance; otherwise, instantiates it. + * + * @param string $resource + * @param string $type + * @return object + * @throws Zend_Loader_Exception if resource type not specified or invalid + */ + public function load($resource, $type = null) + { + if (null === $type) { + $type = $this->getDefaultResourceType(); + if (empty($type)) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception('No resource type specified'); + } + } + if (!$this->hasResourceType($type)) { + require_once 'Zend/Loader/Exception.php'; + throw new Zend_Loader_Exception('Invalid resource type specified'); + } + $namespace = $this->_resourceTypes[$type]['namespace']; + $class = $namespace . '_' . ucfirst($resource); + if (!isset($this->_resources[$class])) { + $this->_resources[$class] = new $class; + } + return $this->_resources[$class]; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Loader/Exception.php b/ThinkPHP/Extend/Vendor/Zend/Loader/Exception.php new file mode 100644 index 0000000..7ab627f --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Loader/Exception.php @@ -0,0 +1,35 @@ +_useStaticRegistry = $staticRegistryName; + if(!isset(self::$_staticPrefixToPaths[$staticRegistryName])) { + self::$_staticPrefixToPaths[$staticRegistryName] = array(); + } + if(!isset(self::$_staticLoadedPlugins[$staticRegistryName])) { + self::$_staticLoadedPlugins[$staticRegistryName] = array(); + } + } + + foreach ($prefixToPaths as $prefix => $path) { + $this->addPrefixPath($prefix, $path); + } + } + + /** + * Format prefix for internal use + * + * @param string $prefix + * @return string + */ + protected function _formatPrefix($prefix) + { + if($prefix == "") { + return $prefix; + } + return rtrim($prefix, '_') . '_'; + } + + /** + * Add prefixed paths to the registry of paths + * + * @param string $prefix + * @param string $path + * @return Zend_Loader_PluginLoader + */ + public function addPrefixPath($prefix, $path) + { + if (!is_string($prefix) || !is_string($path)) { + require_once 'Zend/Loader/PluginLoader/Exception.php'; + throw new Zend_Loader_PluginLoader_Exception('Zend_Loader_PluginLoader::addPrefixPath() method only takes strings for prefix and path.'); + } + + $prefix = $this->_formatPrefix($prefix); + $path = rtrim($path, '/\\') . '/'; + + if ($this->_useStaticRegistry) { + self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix][] = $path; + } else { + if (!isset($this->_prefixToPaths[$prefix])) { + $this->_prefixToPaths[$prefix] = array(); + } + if (!in_array($path, $this->_prefixToPaths[$prefix])) { + $this->_prefixToPaths[$prefix][] = $path; + } + } + return $this; + } + + /** + * Get path stack + * + * @param string $prefix + * @return false|array False if prefix does not exist, array otherwise + */ + public function getPaths($prefix = null) + { + if ((null !== $prefix) && is_string($prefix)) { + $prefix = $this->_formatPrefix($prefix); + if ($this->_useStaticRegistry) { + if (isset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix])) { + return self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix]; + } + + return false; + } + + if (isset($this->_prefixToPaths[$prefix])) { + return $this->_prefixToPaths[$prefix]; + } + + return false; + } + + if ($this->_useStaticRegistry) { + return self::$_staticPrefixToPaths[$this->_useStaticRegistry]; + } + + return $this->_prefixToPaths; + } + + /** + * Clear path stack + * + * @param string $prefix + * @return bool False only if $prefix does not exist + */ + public function clearPaths($prefix = null) + { + if ((null !== $prefix) && is_string($prefix)) { + $prefix = $this->_formatPrefix($prefix); + if ($this->_useStaticRegistry) { + if (isset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix])) { + unset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix]); + return true; + } + + return false; + } + + if (isset($this->_prefixToPaths[$prefix])) { + unset($this->_prefixToPaths[$prefix]); + return true; + } + + return false; + } + + if ($this->_useStaticRegistry) { + self::$_staticPrefixToPaths[$this->_useStaticRegistry] = array(); + } else { + $this->_prefixToPaths = array(); + } + + return true; + } + + /** + * Remove a prefix (or prefixed-path) from the registry + * + * @param string $prefix + * @param string $path OPTIONAL + * @return Zend_Loader_PluginLoader + */ + public function removePrefixPath($prefix, $path = null) + { + $prefix = $this->_formatPrefix($prefix); + if ($this->_useStaticRegistry) { + $registry =& self::$_staticPrefixToPaths[$this->_useStaticRegistry]; + } else { + $registry =& $this->_prefixToPaths; + } + + if (!isset($registry[$prefix])) { + require_once 'Zend/Loader/PluginLoader/Exception.php'; + throw new Zend_Loader_PluginLoader_Exception('Prefix ' . $prefix . ' was not found in the PluginLoader.'); + } + + if ($path != null) { + $pos = array_search($path, $registry[$prefix]); + if ($pos === null) { + require_once 'Zend/Loader/PluginLoader/Exception.php'; + throw new Zend_Loader_PluginLoader_Exception('Prefix ' . $prefix . ' / Path ' . $path . ' was not found in the PluginLoader.'); + } + unset($registry[$prefix][$pos]); + } else { + unset($registry[$prefix]); + } + + return $this; + } + + /** + * Normalize plugin name + * + * @param string $name + * @return string + */ + protected function _formatName($name) + { + return ucfirst((string) $name); + } + + /** + * Whether or not a Plugin by a specific name is loaded + * + * @param string $name + * @return Zend_Loader_PluginLoader + */ + public function isLoaded($name) + { + $name = $this->_formatName($name); + if ($this->_useStaticRegistry) { + return isset(self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]); + } + + return isset($this->_loadedPlugins[$name]); + } + + /** + * Return full class name for a named plugin + * + * @param string $name + * @return string|false False if class not found, class name otherwise + */ + public function getClassName($name) + { + $name = $this->_formatName($name); + if ($this->_useStaticRegistry + && isset(self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]) + ) { + return self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]; + } elseif (isset($this->_loadedPlugins[$name])) { + return $this->_loadedPlugins[$name]; + } + + return false; + } + + /** + * Get path to plugin class + * + * @param mixed $name + * @return string|false False if not found + */ + public function getClassPath($name) + { + $name = $this->_formatName($name); + if ($this->_useStaticRegistry + && !empty(self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name]) + ) { + return self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name]; + } elseif (!empty($this->_loadedPluginPaths[$name])) { + return $this->_loadedPluginPaths[$name]; + } + + if ($this->isLoaded($name)) { + $class = $this->getClassName($name); + $r = new ReflectionClass($class); + $path = $r->getFileName(); + if ($this->_useStaticRegistry) { + self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name] = $path; + } else { + $this->_loadedPluginPaths[$name] = $path; + } + return $path; + } + + return false; + } + + /** + * Load a plugin via the name provided + * + * @param string $name + * @param bool $throwExceptions Whether or not to throw exceptions if the + * class is not resolved + * @return string|false Class name of loaded class; false if $throwExceptions + * if false and no class found + * @throws Zend_Loader_Exception if class not found + */ + public function load($name, $throwExceptions = true) + { + $name = $this->_formatName($name); + if ($this->isLoaded($name)) { + return $this->getClassName($name); + } + + if ($this->_useStaticRegistry) { + $registry = self::$_staticPrefixToPaths[$this->_useStaticRegistry]; + } else { + $registry = $this->_prefixToPaths; + } + + $registry = array_reverse($registry, true); + $found = false; + $classFile = str_replace('_', DIRECTORY_SEPARATOR, $name) . '.php'; + $incFile = self::getIncludeFileCache(); + foreach ($registry as $prefix => $paths) { + $className = $prefix . $name; + + if (class_exists($className, false)) { + $found = true; + break; + } + + $paths = array_reverse($paths, true); + + foreach ($paths as $path) { + $loadFile = $path . $classFile; + if (Zend_Loader::isReadable($loadFile)) { + include_once $loadFile; + if (class_exists($className, false)) { + if (null !== $incFile) { + self::_appendIncFile($loadFile); + } + $found = true; + break 2; + } + } + } + } + + if (!$found) { + if (!$throwExceptions) { + return false; + } + + $message = "Plugin by name '$name' was not found in the registry; used paths:"; + foreach ($registry as $prefix => $paths) { + $message .= "\n$prefix: " . implode(PATH_SEPARATOR, $paths); + } + require_once 'Zend/Loader/PluginLoader/Exception.php'; + throw new Zend_Loader_PluginLoader_Exception($message); + } + + if ($this->_useStaticRegistry) { + self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name] = $className; + self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name] = (isset($loadFile) ? $loadFile : ''); + } else { + $this->_loadedPlugins[$name] = $className; + $this->_loadedPluginPaths[$name] = (isset($loadFile) ? $loadFile : ''); + } + return $className; + } + + /** + * Set path to class file cache + * + * Specify a path to a file that will add include_once statements for each + * plugin class loaded. This is an opt-in feature for performance purposes. + * + * @param string $file + * @return void + * @throws Zend_Loader_PluginLoader_Exception if file is not writeable or path does not exist + */ + public static function setIncludeFileCache($file) + { + if (null === $file) { + self::$_includeFileCache = null; + return; + } + + if (!file_exists($file) && !file_exists(dirname($file))) { + require_once 'Zend/Loader/PluginLoader/Exception.php'; + throw new Zend_Loader_PluginLoader_Exception('Specified file does not exist and/or directory does not exist (' . $file . ')'); + } + if (file_exists($file) && !is_writable($file)) { + require_once 'Zend/Loader/PluginLoader/Exception.php'; + throw new Zend_Loader_PluginLoader_Exception('Specified file is not writeable (' . $file . ')'); + } + if (!file_exists($file) && file_exists(dirname($file)) && !is_writable(dirname($file))) { + require_once 'Zend/Loader/PluginLoader/Exception.php'; + throw new Zend_Loader_PluginLoader_Exception('Specified file is not writeable (' . $file . ')'); + } + + self::$_includeFileCache = $file; + } + + /** + * Retrieve class file cache path + * + * @return string|null + */ + public static function getIncludeFileCache() + { + return self::$_includeFileCache; + } + + /** + * Append an include_once statement to the class file cache + * + * @param string $incFile + * @return void + */ + protected static function _appendIncFile($incFile) + { + if (!file_exists(self::$_includeFileCache)) { + $file = '_table = new Zend_Server_Definition(); + $this->_table->setOverwriteExistingMethods($this->_overwriteExistingMethods); + } + + /** + * Returns a list of registered methods + * + * Returns an array of method definitions. + * + * @return Zend_Server_Definition + */ + public function getFunctions() + { + return $this->_table; + } + + /** + * Lowercase a string + * + * Lowercase's a string by reference + * + * @deprecated + * @param string $string value + * @param string $key + * @return string Lower cased string + */ + public static function lowerCase(&$value, &$key) + { + trigger_error(__CLASS__ . '::' . __METHOD__ . '() is deprecated and will be removed in a future version', E_USER_NOTICE); + return $value = strtolower($value); + } + + /** + * Build callback for method signature + * + * @param Zend_Server_Reflection_Function_Abstract $reflection + * @return Zend_Server_Method_Callback + */ + protected function _buildCallback(Zend_Server_Reflection_Function_Abstract $reflection) + { + $callback = new Zend_Server_Method_Callback(); + if ($reflection instanceof Zend_Server_Reflection_Method) { + $callback->setType($reflection->isStatic() ? 'static' : 'instance') + ->setClass($reflection->getDeclaringClass()->getName()) + ->setMethod($reflection->getName()); + } elseif ($reflection instanceof Zend_Server_Reflection_Function) { + $callback->setType('function') + ->setFunction($reflection->getName()); + } + return $callback; + } + + /** + * Build a method signature + * + * @param Zend_Server_Reflection_Function_Abstract $reflection + * @param null|string|object $class + * @return Zend_Server_Method_Definition + * @throws Zend_Server_Exception on duplicate entry + */ + protected function _buildSignature(Zend_Server_Reflection_Function_Abstract $reflection, $class = null) + { + $ns = $reflection->getNamespace(); + $name = $reflection->getName(); + $method = empty($ns) ? $name : $ns . '.' . $name; + + if (!$this->_overwriteExistingMethods && $this->_table->hasMethod($method)) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Duplicate method registered: ' . $method); + } + + $definition = new Zend_Server_Method_Definition(); + $definition->setName($method) + ->setCallback($this->_buildCallback($reflection)) + ->setMethodHelp($reflection->getDescription()) + ->setInvokeArguments($reflection->getInvokeArguments()); + + foreach ($reflection->getPrototypes() as $proto) { + $prototype = new Zend_Server_Method_Prototype(); + $prototype->setReturnType($this->_fixType($proto->getReturnType())); + foreach ($proto->getParameters() as $parameter) { + $param = new Zend_Server_Method_Parameter(array( + 'type' => $this->_fixType($parameter->getType()), + 'name' => $parameter->getName(), + 'optional' => $parameter->isOptional(), + )); + if ($parameter->isDefaultValueAvailable()) { + $param->setDefaultValue($parameter->getDefaultValue()); + } + $prototype->addParameter($param); + } + $definition->addPrototype($prototype); + } + if (is_object($class)) { + $definition->setObject($class); + } + $this->_table->addMethod($definition); + return $definition; + } + + /** + * Dispatch method + * + * @param Zend_Server_Method_Definition $invocable + * @param array $params + * @return mixed + */ + protected function _dispatch(Zend_Server_Method_Definition $invocable, array $params) + { + $callback = $invocable->getCallback(); + $type = $callback->getType(); + + if ('function' == $type) { + $function = $callback->getFunction(); + return call_user_func_array($function, $params); + } + + $class = $callback->getClass(); + $method = $callback->getMethod(); + + if ('static' == $type) { + return call_user_func_array(array($class, $method), $params); + } + + $object = $invocable->getObject(); + if (!is_object($object)) { + $invokeArgs = $invocable->getInvokeArguments(); + if (!empty($invokeArgs)) { + $reflection = new ReflectionClass($class); + $object = $reflection->newInstanceArgs($invokeArgs); + } else { + $object = new $class; + } + } + return call_user_func_array(array($object, $method), $params); + } + + /** + * Map PHP type to protocol type + * + * @param string $type + * @return string + */ + abstract protected function _fixType($type); +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Cache.php b/ThinkPHP/Extend/Vendor/Zend/Server/Cache.php new file mode 100644 index 0000000..1dccf5d --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Cache.php @@ -0,0 +1,147 @@ +getFunctions(); + + if ($methods instanceof Zend_Server_Definition) { + $definition = new Zend_Server_Definition(); + foreach ($methods as $method) { + if (in_array($method->getName(), self::$_skipMethods)) { + continue; + } + $definition->addMethod($method); + } + $methods = $definition; + } + + if (0 === @file_put_contents($filename, serialize($methods))) { + return false; + } + + return true; + } + + /** + * Load server definition from a file + * + * Unserializes a stored server definition from $filename. Returns false if + * it fails in any way, true on success. + * + * Useful to prevent needing to build the server definition on each + * request. Sample usage: + * + * + * if (!Zend_Server_Cache::get($filename, $server)) { + * require_once 'Some/Service/Class.php'; + * require_once 'Another/Service/Class.php'; + * + * // Attach Some_Service_Class with namespace 'some' + * $server->attach('Some_Service_Class', 'some'); + * + * // Attach Another_Service_Class with namespace 'another' + * $server->attach('Another_Service_Class', 'another'); + * + * Zend_Server_Cache::save($filename, $server); + * } + * + * $response = $server->handle(); + * echo $response; + * + * + * @param string $filename + * @param Zend_Server_Interface $server + * @return bool + */ + public static function get($filename, Zend_Server_Interface $server) + { + if (!is_string($filename) + || !file_exists($filename) + || !is_readable($filename)) + { + return false; + } + + + if (false === ($dispatch = @file_get_contents($filename))) { + return false; + } + + if (false === ($dispatchArray = @unserialize($dispatch))) { + return false; + } + + $server->loadFunctions($dispatchArray); + + return true; + } + + /** + * Remove a cache file + * + * @param string $filename + * @return boolean + */ + public static function delete($filename) + { + if (is_string($filename) && file_exists($filename)) { + unlink($filename); + return true; + } + + return false; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Definition.php b/ThinkPHP/Extend/Vendor/Zend/Server/Definition.php new file mode 100644 index 0000000..c5c3ef8 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Definition.php @@ -0,0 +1,267 @@ +setMethods($methods); + } + } + + /** + * Set flag indicating whether or not overwriting existing methods is allowed + * + * @param mixed $flag + * @return void + */ + public function setOverwriteExistingMethods($flag) + { + $this->_overwriteExistingMethods = (bool) $flag; + return $this; + } + + /** + * Add method to definition + * + * @param array|Zend_Server_Method_Definition $method + * @param null|string $name + * @return Zend_Server_Definition + * @throws Zend_Server_Exception if duplicate or invalid method provided + */ + public function addMethod($method, $name = null) + { + if (is_array($method)) { + require_once 'Zend/Server/Method/Definition.php'; + $method = new Zend_Server_Method_Definition($method); + } elseif (!$method instanceof Zend_Server_Method_Definition) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid method provided'); + } + + if (is_numeric($name)) { + $name = null; + } + if (null !== $name) { + $method->setName($name); + } else { + $name = $method->getName(); + } + if (null === $name) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('No method name provided'); + } + + if (!$this->_overwriteExistingMethods && array_key_exists($name, $this->_methods)) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception(sprintf('Method by name of "%s" already exists', $name)); + } + $this->_methods[$name] = $method; + return $this; + } + + /** + * Add multiple methods + * + * @param array $methods Array of Zend_Server_Method_Definition objects or arrays + * @return Zend_Server_Definition + */ + public function addMethods(array $methods) + { + foreach ($methods as $key => $method) { + $this->addMethod($method, $key); + } + return $this; + } + + /** + * Set all methods at once (overwrite) + * + * @param array $methods Array of Zend_Server_Method_Definition objects or arrays + * @return Zend_Server_Definition + */ + public function setMethods(array $methods) + { + $this->clearMethods(); + $this->addMethods($methods); + return $this; + } + + /** + * Does the definition have the given method? + * + * @param string $method + * @return bool + */ + public function hasMethod($method) + { + return array_key_exists($method, $this->_methods); + } + + /** + * Get a given method definition + * + * @param string $method + * @return null|Zend_Server_Method_Definition + */ + public function getMethod($method) + { + if ($this->hasMethod($method)) { + return $this->_methods[$method]; + } + return false; + } + + /** + * Get all method definitions + * + * @return array Array of Zend_Server_Method_Definition objects + */ + public function getMethods() + { + return $this->_methods; + } + + /** + * Remove a method definition + * + * @param string $method + * @return Zend_Server_Definition + */ + public function removeMethod($method) + { + if ($this->hasMethod($method)) { + unset($this->_methods[$method]); + } + return $this; + } + + /** + * Clear all method definitions + * + * @return Zend_Server_Definition + */ + public function clearMethods() + { + $this->_methods = array(); + return $this; + } + + /** + * Cast definition to an array + * + * @return array + */ + public function toArray() + { + $methods = array(); + foreach ($this->getMethods() as $key => $method) { + $methods[$key] = $method->toArray(); + } + return $methods; + } + + /** + * Countable: count of methods + * + * @return int + */ + public function count() + { + return count($this->_methods); + } + + /** + * Iterator: current item + * + * @return mixed + */ + public function current() + { + return current($this->_methods); + } + + /** + * Iterator: current item key + * + * @return int|string + */ + public function key() + { + return key($this->_methods); + } + + /** + * Iterator: advance to next method + * + * @return void + */ + public function next() + { + return next($this->_methods); + } + + /** + * Iterator: return to first method + * + * @return void + */ + public function rewind() + { + return reset($this->_methods); + } + + /** + * Iterator: is the current index valid? + * + * @return bool + */ + public function valid() + { + return (bool) $this->current(); + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Exception.php b/ThinkPHP/Extend/Vendor/Zend/Server/Exception.php new file mode 100644 index 0000000..446f1f8 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Exception.php @@ -0,0 +1,35 @@ +setOptions($options); + } + } + + /** + * Set object state from array of options + * + * @param array $options + * @return Zend_Server_Method_Callback + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set callback class + * + * @param string $class + * @return Zend_Server_Method_Callback + */ + public function setClass($class) + { + if (is_object($class)) { + $class = get_class($class); + } + $this->_class = $class; + return $this; + } + + /** + * Get callback class + * + * @return string|null + */ + public function getClass() + { + return $this->_class; + } + + /** + * Set callback function + * + * @param string $function + * @return Zend_Server_Method_Callback + */ + public function setFunction($function) + { + $this->_function = (string) $function; + $this->setType('function'); + return $this; + } + + /** + * Get callback function + * + * @return null|string + */ + public function getFunction() + { + return $this->_function; + } + + /** + * Set callback class method + * + * @param string $method + * @return Zend_Server_Method_Callback + */ + public function setMethod($method) + { + $this->_method = $method; + return $this; + } + + /** + * Get callback class method + * + * @return null|string + */ + public function getMethod() + { + return $this->_method; + } + + /** + * Set callback type + * + * @param string $type + * @return Zend_Server_Method_Callback + * @throws Zend_Server_Exception + */ + public function setType($type) + { + if (!in_array($type, $this->_types)) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid method callback type passed to ' . __CLASS__ . '::' . __METHOD__); + } + $this->_type = $type; + return $this; + } + + /** + * Get callback type + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Cast callback to array + * + * @return array + */ + public function toArray() + { + $type = $this->getType(); + $array = array( + 'type' => $type, + ); + if ('function' == $type) { + $array['function'] = $this->getFunction(); + } else { + $array['class'] = $this->getClass(); + $array['method'] = $this->getMethod(); + } + return $array; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Method/Definition.php b/ThinkPHP/Extend/Vendor/Zend/Server/Method/Definition.php new file mode 100644 index 0000000..cf11f3b --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Method/Definition.php @@ -0,0 +1,293 @@ +setOptions($options); + } + } + + /** + * Set object state from options + * + * @param array $options + * @return Zend_Server_Method_Definition + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set method name + * + * @param string $name + * @return Zend_Server_Method_Definition + */ + public function setName($name) + { + $this->_name = (string) $name; + return $this; + } + + /** + * Get method name + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Set method callback + * + * @param array|Zend_Server_Method_Callback $callback + * @return Zend_Server_Method_Definition + */ + public function setCallback($callback) + { + if (is_array($callback)) { + require_once 'Zend/Server/Method/Callback.php'; + $callback = new Zend_Server_Method_Callback($callback); + } elseif (!$callback instanceof Zend_Server_Method_Callback) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid method callback provided'); + } + $this->_callback = $callback; + return $this; + } + + /** + * Get method callback + * + * @return Zend_Server_Method_Callback + */ + public function getCallback() + { + return $this->_callback; + } + + /** + * Add prototype to method definition + * + * @param array|Zend_Server_Method_Prototype $prototype + * @return Zend_Server_Method_Definition + */ + public function addPrototype($prototype) + { + if (is_array($prototype)) { + require_once 'Zend/Server/Method/Prototype.php'; + $prototype = new Zend_Server_Method_Prototype($prototype); + } elseif (!$prototype instanceof Zend_Server_Method_Prototype) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid method prototype provided'); + } + $this->_prototypes[] = $prototype; + return $this; + } + + /** + * Add multiple prototypes at once + * + * @param array $prototypes Array of Zend_Server_Method_Prototype objects or arrays + * @return Zend_Server_Method_Definition + */ + public function addPrototypes(array $prototypes) + { + foreach ($prototypes as $prototype) { + $this->addPrototype($prototype); + } + return $this; + } + + /** + * Set all prototypes at once (overwrites) + * + * @param array $prototypes Array of Zend_Server_Method_Prototype objects or arrays + * @return Zend_Server_Method_Definition + */ + public function setPrototypes(array $prototypes) + { + $this->_prototypes = array(); + $this->addPrototypes($prototypes); + return $this; + } + + /** + * Get all prototypes + * + * @return array $prototypes Array of Zend_Server_Method_Prototype objects or arrays + */ + public function getPrototypes() + { + return $this->_prototypes; + } + + /** + * Set method help + * + * @param string $methodHelp + * @return Zend_Server_Method_Definition + */ + public function setMethodHelp($methodHelp) + { + $this->_methodHelp = (string) $methodHelp; + return $this; + } + + /** + * Get method help + * + * @return string + */ + public function getMethodHelp() + { + return $this->_methodHelp; + } + + /** + * Set object to use with method calls + * + * @param object $object + * @return Zend_Server_Method_Definition + */ + public function setObject($object) + { + if (!is_object($object) && (null !== $object)) { + require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid object passed to ' . __CLASS__ . '::' . __METHOD__); + } + $this->_object = $object; + return $this; + } + + /** + * Get object to use with method calls + * + * @return null|object + */ + public function getObject() + { + return $this->_object; + } + + /** + * Set invoke arguments + * + * @param array $invokeArguments + * @return Zend_Server_Method_Definition + */ + public function setInvokeArguments(array $invokeArguments) + { + $this->_invokeArguments = $invokeArguments; + return $this; + } + + /** + * Retrieve invoke arguments + * + * @return array + */ + public function getInvokeArguments() + { + return $this->_invokeArguments; + } + + /** + * Serialize to array + * + * @return array + */ + public function toArray() + { + $prototypes = $this->getPrototypes(); + $signatures = array(); + foreach ($prototypes as $prototype) { + $signatures[] = $prototype->toArray(); + } + + return array( + 'name' => $this->getName(), + 'callback' => $this->getCallback()->toArray(), + 'prototypes' => $signatures, + 'methodHelp' => $this->getMethodHelp(), + 'invokeArguments' => $this->getInvokeArguments(), + 'object' => $this->getObject(), + ); + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Method/Parameter.php b/ThinkPHP/Extend/Vendor/Zend/Server/Method/Parameter.php new file mode 100644 index 0000000..bbce909 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Method/Parameter.php @@ -0,0 +1,214 @@ +setOptions($options); + } + } + + /** + * Set object state from array of options + * + * @param array $options + * @return Zend_Server_Method_Parameter + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set default value + * + * @param mixed $defaultValue + * @return Zend_Server_Method_Parameter + */ + public function setDefaultValue($defaultValue) + { + $this->_defaultValue = $defaultValue; + return $this; + } + + /** + * Retrieve default value + * + * @return mixed + */ + public function getDefaultValue() + { + return $this->_defaultValue; + } + + /** + * Set description + * + * @param string $description + * @return Zend_Server_Method_Parameter + */ + public function setDescription($description) + { + $this->_description = (string) $description; + return $this; + } + + /** + * Retrieve description + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Set name + * + * @param string $name + * @return Zend_Server_Method_Parameter + */ + public function setName($name) + { + $this->_name = (string) $name; + return $this; + } + + /** + * Retrieve name + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Set optional flag + * + * @param bool $flag + * @return Zend_Server_Method_Parameter + */ + public function setOptional($flag) + { + $this->_optional = (bool) $flag; + return $this; + } + + /** + * Is the parameter optional? + * + * @return bool + */ + public function isOptional() + { + return $this->_optional; + } + + /** + * Set parameter type + * + * @param string $type + * @return Zend_Server_Method_Parameter + */ + public function setType($type) + { + $this->_type = (string) $type; + return $this; + } + + /** + * Retrieve parameter type + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Cast to array + * + * @return array + */ + public function toArray() + { + return array( + 'type' => $this->getType(), + 'name' => $this->getName(), + 'optional' => $this->isOptional(), + 'defaultValue' => $this->getDefaultValue(), + 'description' => $this->getDescription(), + ); + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Method/Prototype.php b/ThinkPHP/Extend/Vendor/Zend/Server/Method/Prototype.php new file mode 100644 index 0000000..d0936ca --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Method/Prototype.php @@ -0,0 +1,208 @@ +setOptions($options); + } + } + + /** + * Set return value + * + * @param string $returnType + * @return Zend_Server_Method_Prototype + */ + public function setReturnType($returnType) + { + $this->_returnType = $returnType; + return $this; + } + + /** + * Retrieve return type + * + * @return string + */ + public function getReturnType() + { + return $this->_returnType; + } + + /** + * Add a parameter + * + * @param string $parameter + * @return Zend_Server_Method_Prototype + */ + public function addParameter($parameter) + { + if ($parameter instanceof Zend_Server_Method_Parameter) { + $this->_parameters[] = $parameter; + if (null !== ($name = $parameter->getName())) { + $this->_parameterNameMap[$name] = count($this->_parameters) - 1; + } + } else { + require_once 'Zend/Server/Method/Parameter.php'; + $parameter = new Zend_Server_Method_Parameter(array( + 'type' => (string) $parameter, + )); + $this->_parameters[] = $parameter; + } + return $this; + } + + /** + * Add parameters + * + * @param array $parameter + * @return Zend_Server_Method_Prototype + */ + public function addParameters(array $parameters) + { + foreach ($parameters as $parameter) { + $this->addParameter($parameter); + } + return $this; + } + + /** + * Set parameters + * + * @param array $parameters + * @return Zend_Server_Method_Prototype + */ + public function setParameters(array $parameters) + { + $this->_parameters = array(); + $this->_parameterNameMap = array(); + $this->addParameters($parameters); + return $this; + } + + /** + * Retrieve parameters as list of types + * + * @return array + */ + public function getParameters() + { + $types = array(); + foreach ($this->_parameters as $parameter) { + $types[] = $parameter->getType(); + } + return $types; + } + + /** + * Get parameter objects + * + * @return array + */ + public function getParameterObjects() + { + return $this->_parameters; + } + + /** + * Retrieve a single parameter by name or index + * + * @param string|int $index + * @return null|Zend_Server_Method_Parameter + */ + public function getParameter($index) + { + if (!is_string($index) && !is_numeric($index)) { + return null; + } + if (array_key_exists($index, $this->_parameterNameMap)) { + $index = $this->_parameterNameMap[$index]; + } + if (array_key_exists($index, $this->_parameters)) { + return $this->_parameters[$index]; + } + return null; + } + + /** + * Set object state from array + * + * @param array $options + * @return Zend_Server_Method_Prototype + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Serialize to array + * + * @return array + */ + public function toArray() + { + return array( + 'returnType' => $this->getReturnType(), + 'parameters' => $this->getParameters(), + ); + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Reflection.php b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection.php new file mode 100644 index 0000000..96751c6 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection.php @@ -0,0 +1,111 @@ +_reflection = $reflection; + $this->setNamespace($namespace); + + foreach ($reflection->getMethods() as $method) { + // Don't aggregate magic methods + if ('__' == substr($method->getName(), 0, 2)) { + continue; + } + + if ($method->isPublic()) { + // Get signatures and description + $this->_methods[] = new Zend_Server_Reflection_Method($this, $method, $this->getNamespace(), $argv); + } + } + } + + /** + * Proxy reflection calls + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (method_exists($this->_reflection, $method)) { + return call_user_func_array(array($this->_reflection, $method), $args); + } + + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid reflection method'); + } + + /** + * Retrieve configuration parameters + * + * Values are retrieved by key from {@link $_config}. Returns null if no + * value found. + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + if (isset($this->_config[$key])) { + return $this->_config[$key]; + } + + return null; + } + + /** + * Set configuration parameters + * + * Values are stored by $key in {@link $_config}. + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + $this->_config[$key] = $value; + } + + /** + * Return array of dispatchable {@link Zend_Server_Reflection_Method}s. + * + * @access public + * @return array + */ + public function getMethods() + { + return $this->_methods; + } + + /** + * Get namespace for this class + * + * @return string + */ + public function getNamespace() + { + return $this->_namespace; + } + + /** + * Set namespace for this class + * + * @param string $namespace + * @return void + */ + public function setNamespace($namespace) + { + if (empty($namespace)) { + $this->_namespace = ''; + return; + } + + if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid namespace'); + } + + $this->_namespace = $namespace; + } + + /** + * Wakeup from serialization + * + * Reflection needs explicit instantiation to work correctly. Re-instantiate + * reflection object on wakeup. + * + * @return void + */ + public function __wakeup() + { + $this->_reflection = new ReflectionClass($this->getName()); + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Exception.php b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Exception.php new file mode 100644 index 0000000..a2e343c --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Exception.php @@ -0,0 +1,38 @@ +_reflection = $r; + + // Determine namespace + if (null !== $namespace){ + $this->setNamespace($namespace); + } + + // Determine arguments + if (is_array($argv)) { + $this->_argv = $argv; + } + + // If method call, need to store some info on the class + if ($r instanceof ReflectionMethod) { + $this->_class = $r->getDeclaringClass()->getName(); + } + + // Perform some introspection + $this->_reflect(); + } + + /** + * Create signature node tree + * + * Recursive method to build the signature node tree. Increments through + * each array in {@link $_sigParams}, adding every value of the next level + * to the current value (unless the current value is null). + * + * @param Zend_Server_Reflection_Node $parent + * @param int $level + * @return void + */ + protected function _addTree(Zend_Server_Reflection_Node $parent, $level = 0) + { + if ($level >= $this->_sigParamsDepth) { + return; + } + + foreach ($this->_sigParams[$level] as $value) { + $node = new Zend_Server_Reflection_Node($value, $parent); + if ((null !== $value) && ($this->_sigParamsDepth > $level + 1)) { + $this->_addTree($node, $level + 1); + } + } + } + + /** + * Build the signature tree + * + * Builds a signature tree starting at the return values and descending + * through each method argument. Returns an array of + * {@link Zend_Server_Reflection_Node}s. + * + * @return array + */ + protected function _buildTree() + { + $returnTree = array(); + foreach ((array) $this->_return as $value) { + $node = new Zend_Server_Reflection_Node($value); + $this->_addTree($node); + $returnTree[] = $node; + } + + return $returnTree; + } + + /** + * Build method signatures + * + * Builds method signatures using the array of return types and the array of + * parameters types + * + * @param array $return Array of return types + * @param string $returnDesc Return value description + * @param array $params Array of arguments (each an array of types) + * @param array $paramDesc Array of parameter descriptions + * @return array + */ + protected function _buildSignatures($return, $returnDesc, $paramTypes, $paramDesc) + { + $this->_return = $return; + $this->_returnDesc = $returnDesc; + $this->_paramDesc = $paramDesc; + $this->_sigParams = $paramTypes; + $this->_sigParamsDepth = count($paramTypes); + $signatureTrees = $this->_buildTree(); + $signatures = array(); + + $endPoints = array(); + foreach ($signatureTrees as $root) { + $tmp = $root->getEndPoints(); + if (empty($tmp)) { + $endPoints = array_merge($endPoints, array($root)); + } else { + $endPoints = array_merge($endPoints, $tmp); + } + } + + foreach ($endPoints as $node) { + if (!$node instanceof Zend_Server_Reflection_Node) { + continue; + } + + $signature = array(); + do { + array_unshift($signature, $node->getValue()); + $node = $node->getParent(); + } while ($node instanceof Zend_Server_Reflection_Node); + + $signatures[] = $signature; + } + + // Build prototypes + $params = $this->_reflection->getParameters(); + foreach ($signatures as $signature) { + $return = new Zend_Server_Reflection_ReturnValue(array_shift($signature), $this->_returnDesc); + $tmp = array(); + foreach ($signature as $key => $type) { + $param = new Zend_Server_Reflection_Parameter($params[$key], $type, $this->_paramDesc[$key]); + $param->setPosition($key); + $tmp[] = $param; + } + + $this->_prototypes[] = new Zend_Server_Reflection_Prototype($return, $tmp); + } + } + + /** + * Use code reflection to create method signatures + * + * Determines the method help/description text from the function DocBlock + * comment. Determines method signatures using a combination of + * ReflectionFunction and parsing of DocBlock @param and @return values. + * + * @param ReflectionFunction $function + * @return array + */ + protected function _reflect() + { + $function = $this->_reflection; + $helpText = ''; + $signatures = array(); + $returnDesc = ''; + $paramCount = $function->getNumberOfParameters(); + $paramCountRequired = $function->getNumberOfRequiredParameters(); + $parameters = $function->getParameters(); + $docBlock = $function->getDocComment(); + + if (!empty($docBlock)) { + // Get help text + if (preg_match(':/\*\*\s*\r?\n\s*\*\s(.*?)\r?\n\s*\*(\s@|/):s', $docBlock, $matches)) + { + $helpText = $matches[1]; + $helpText = preg_replace('/(^\s*\*\s)/m', '', $helpText); + $helpText = preg_replace('/\r?\n\s*\*\s*(\r?\n)*/s', "\n", $helpText); + $helpText = trim($helpText); + } + + // Get return type(s) and description + $return = 'void'; + if (preg_match('/@return\s+(\S+)/', $docBlock, $matches)) { + $return = explode('|', $matches[1]); + if (preg_match('/@return\s+\S+\s+(.*?)(@|\*\/)/s', $docBlock, $matches)) + { + $value = $matches[1]; + $value = preg_replace('/\s?\*\s/m', '', $value); + $value = preg_replace('/\s{2,}/', ' ', $value); + $returnDesc = trim($value); + } + } + + // Get param types and description + if (preg_match_all('/@param\s+([^\s]+)/m', $docBlock, $matches)) { + $paramTypesTmp = $matches[1]; + if (preg_match_all('/@param\s+\S+\s+(\$^\S+)\s+(.*?)(@|\*\/)/s', $docBlock, $matches)) + { + $paramDesc = $matches[2]; + foreach ($paramDesc as $key => $value) { + $value = preg_replace('/\s?\*\s/m', '', $value); + $value = preg_replace('/\s{2,}/', ' ', $value); + $paramDesc[$key] = trim($value); + } + } + } + } else { + $helpText = $function->getName(); + $return = 'void'; + } + + // Set method description + $this->setDescription($helpText); + + // Get all param types as arrays + if (!isset($paramTypesTmp) && (0 < $paramCount)) { + $paramTypesTmp = array_fill(0, $paramCount, 'mixed'); + } elseif (!isset($paramTypesTmp)) { + $paramTypesTmp = array(); + } elseif (count($paramTypesTmp) < $paramCount) { + $start = $paramCount - count($paramTypesTmp); + for ($i = $start; $i < $paramCount; ++$i) { + $paramTypesTmp[$i] = 'mixed'; + } + } + + // Get all param descriptions as arrays + if (!isset($paramDesc) && (0 < $paramCount)) { + $paramDesc = array_fill(0, $paramCount, ''); + } elseif (!isset($paramDesc)) { + $paramDesc = array(); + } elseif (count($paramDesc) < $paramCount) { + $start = $paramCount - count($paramDesc); + for ($i = $start; $i < $paramCount; ++$i) { + $paramDesc[$i] = ''; + } + } + + if (count($paramTypesTmp) != $paramCount) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception( + 'Variable number of arguments is not supported for services (except optional parameters). ' + . 'Number of function arguments must correspond to actual number of arguments described in a docblock.'); + } + + $paramTypes = array(); + foreach ($paramTypesTmp as $i => $param) { + $tmp = explode('|', $param); + if ($parameters[$i]->isOptional()) { + array_unshift($tmp, null); + } + $paramTypes[] = $tmp; + } + + $this->_buildSignatures($return, $returnDesc, $paramTypes, $paramDesc); + } + + + /** + * Proxy reflection calls + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (method_exists($this->_reflection, $method)) { + return call_user_func_array(array($this->_reflection, $method), $args); + } + + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid reflection method ("' .$method. '")'); + } + + /** + * Retrieve configuration parameters + * + * Values are retrieved by key from {@link $_config}. Returns null if no + * value found. + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + if (isset($this->_config[$key])) { + return $this->_config[$key]; + } + + return null; + } + + /** + * Set configuration parameters + * + * Values are stored by $key in {@link $_config}. + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + $this->_config[$key] = $value; + } + + /** + * Set method's namespace + * + * @param string $namespace + * @return void + */ + public function setNamespace($namespace) + { + if (empty($namespace)) { + $this->_namespace = ''; + return; + } + + if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid namespace'); + } + + $this->_namespace = $namespace; + } + + /** + * Return method's namespace + * + * @return string + */ + public function getNamespace() + { + return $this->_namespace; + } + + /** + * Set the description + * + * @param string $string + * @return void + */ + public function setDescription($string) + { + if (!is_string($string)) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid description'); + } + + $this->_description = $string; + } + + /** + * Retrieve the description + * + * @return void + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Retrieve all prototypes as array of + * {@link Zend_Server_Reflection_Prototype Zend_Server_Reflection_Prototypes} + * + * @return array + */ + public function getPrototypes() + { + return $this->_prototypes; + } + + /** + * Retrieve additional invocation arguments + * + * @return array + */ + public function getInvokeArguments() + { + return $this->_argv; + } + + /** + * Wakeup from serialization + * + * Reflection needs explicit instantiation to work correctly. Re-instantiate + * reflection object on wakeup. + * + * @return void + */ + public function __wakeup() + { + if ($this->_reflection instanceof ReflectionMethod) { + $class = new ReflectionClass($this->_class); + $this->_reflection = new ReflectionMethod($class->newInstance(), $this->getName()); + } else { + $this->_reflection = new ReflectionFunction($this->getName()); + } + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Method.php b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Method.php new file mode 100644 index 0000000..7af28de --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Method.php @@ -0,0 +1,110 @@ +_classReflection = $class; + $this->_reflection = $r; + + $classNamespace = $class->getNamespace(); + + // Determine namespace + if (!empty($namespace)) { + $this->setNamespace($namespace); + } elseif (!empty($classNamespace)) { + $this->setNamespace($classNamespace); + } + + // Determine arguments + if (is_array($argv)) { + $this->_argv = $argv; + } + + // If method call, need to store some info on the class + $this->_class = $class->getName(); + + // Perform some introspection + $this->_reflect(); + } + + /** + * Return the reflection for the class that defines this method + * + * @return Zend_Server_Reflection_Class + */ + public function getDeclaringClass() + { + return $this->_classReflection; + } + + /** + * Wakeup from serialization + * + * Reflection needs explicit instantiation to work correctly. Re-instantiate + * reflection object on wakeup. + * + * @return void + */ + public function __wakeup() + { + $this->_classReflection = new Zend_Server_Reflection_Class(new ReflectionClass($this->_class), $this->getNamespace(), $this->getInvokeArguments()); + $this->_reflection = new ReflectionMethod($this->_classReflection->getName(), $this->getName()); + } + +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Node.php b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Node.php new file mode 100644 index 0000000..171a025 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Node.php @@ -0,0 +1,201 @@ +_value = $value; + if (null !== $parent) { + $this->setParent($parent, true); + } + + return $this; + } + + /** + * Set parent node + * + * @param Zend_Server_Reflection_Node $node + * @param boolean $new Whether or not the child node is newly created + * and should always be attached + * @return void + */ + public function setParent(Zend_Server_Reflection_Node $node, $new = false) + { + $this->_parent = $node; + + if ($new) { + $node->attachChild($this); + return; + } + } + + /** + * Create and attach a new child node + * + * @param mixed $value + * @access public + * @return Zend_Server_Reflection_Node New child node + */ + public function createChild($value) + { + $child = new self($value, $this); + + return $child; + } + + /** + * Attach a child node + * + * @param Zend_Server_Reflection_Node $node + * @return void + */ + public function attachChild(Zend_Server_Reflection_Node $node) + { + $this->_children[] = $node; + + if ($node->getParent() !== $this) { + $node->setParent($this); + } + } + + /** + * Return an array of all child nodes + * + * @return array + */ + public function getChildren() + { + return $this->_children; + } + + /** + * Does this node have children? + * + * @return boolean + */ + public function hasChildren() + { + return count($this->_children) > 0; + } + + /** + * Return the parent node + * + * @return null|Zend_Server_Reflection_Node + */ + public function getParent() + { + return $this->_parent; + } + + /** + * Return the node's current value + * + * @return mixed + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the node value + * + * @param mixed $value + * @return void + */ + public function setValue($value) + { + $this->_value = $value; + } + + /** + * Retrieve the bottommost nodes of this node's tree + * + * Retrieves the bottommost nodes of the tree by recursively calling + * getEndPoints() on all children. If a child is null, it returns the parent + * as an end point. + * + * @return array + */ + public function getEndPoints() + { + $endPoints = array(); + if (!$this->hasChildren()) { + return $endPoints; + } + + foreach ($this->_children as $child) { + $value = $child->getValue(); + + if (null === $value) { + $endPoints[] = $this; + } elseif ((null !== $value) + && $child->hasChildren()) + { + $childEndPoints = $child->getEndPoints(); + if (!empty($childEndPoints)) { + $endPoints = array_merge($endPoints, $childEndPoints); + } + } elseif ((null !== $value) && !$child->hasChildren()) { + $endPoints[] = $child; + } + } + + return $endPoints; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Parameter.php b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Parameter.php new file mode 100644 index 0000000..3b17232 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Parameter.php @@ -0,0 +1,161 @@ +_reflection = $r; + $this->setType($type); + $this->setDescription($description); + } + + /** + * Proxy reflection calls + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (method_exists($this->_reflection, $method)) { + return call_user_func_array(array($this->_reflection, $method), $args); + } + + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid reflection method'); + } + + /** + * Retrieve parameter type + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Set parameter type + * + * @param string|null $type + * @return void + */ + public function setType($type) + { + if (!is_string($type) && (null !== $type)) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameter type'); + } + + $this->_type = $type; + } + + /** + * Retrieve parameter description + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Set parameter description + * + * @param string|null $description + * @return void + */ + public function setDescription($description) + { + if (!is_string($description) && (null !== $description)) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameter description'); + } + + $this->_description = $description; + } + + /** + * Set parameter position + * + * @param int $index + * @return void + */ + public function setPosition($index) + { + $this->_position = (int) $index; + } + + /** + * Return parameter position + * + * @return int + */ + public function getPosition() + { + return $this->_position; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Prototype.php b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Prototype.php new file mode 100644 index 0000000..dab34e8 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/Prototype.php @@ -0,0 +1,103 @@ +_return = $return; + + if (!is_array($params) && (null !== $params)) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameters'); + } + + if (is_array($params)) { + foreach ($params as $param) { + if (!$param instanceof Zend_Server_Reflection_Parameter) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('One or more params are invalid'); + } + } + } + + $this->_params = $params; + } + + /** + * Retrieve return type + * + * @return string + */ + public function getReturnType() + { + return $this->_return->getType(); + } + + /** + * Retrieve the return value object + * + * @access public + * @return Zend_Server_Reflection_ReturnValue + */ + public function getReturnValue() + { + return $this->_return; + } + + /** + * Retrieve method parameters + * + * @return array Array of {@link Zend_Server_Reflection_Parameter}s + */ + public function getParameters() + { + return $this->_params; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/ReturnValue.php b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/ReturnValue.php new file mode 100644 index 0000000..fe5eea7 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Server/Reflection/ReturnValue.php @@ -0,0 +1,110 @@ +setType($type); + $this->setDescription($description); + } + + /** + * Retrieve parameter type + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Set parameter type + * + * @param string|null $type + * @return void + */ + public function setType($type) + { + if (!is_string($type) && (null !== $type)) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameter type'); + } + + $this->_type = $type; + } + + /** + * Retrieve parameter description + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Set parameter description + * + * @param string|null $description + * @return void + */ + public function setDescription($description) + { + if (!is_string($description) && (null !== $description)) { + require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameter description'); + } + + $this->_description = $description; + } +} diff --git a/ThinkPHP/Extend/Vendor/Zend/Version.php b/ThinkPHP/Extend/Vendor/Zend/Version.php new file mode 100644 index 0000000..b151666 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/Zend/Version.php @@ -0,0 +1,53 @@ + | +| | +| This file may be distributed and/or modified under the | +| terms of the GNU General Public License (GPL) version | +| 2.0 as published by the Free Software Foundation and | +| appearing in the included file LICENSE. | +| | +\**********************************************************/ + +/* Big integer expansion library. + * + * Copyright: Ma Bingyao + * mgccl + * Version: 3.0.1 + * LastModified: Apr 12, 2010 + * This library is free. You can redistribute it and/or modify it under GPL. + */ + +if (extension_loaded('gmp')) { + function bigint_dec2num($dec) { + return gmp_init($dec); + } + function bigint_num2dec($num) { + return gmp_strval($num); + } + function bigint_str2num($str) { + return gmp_init("0x".bin2hex($str)); + } + function bigint_num2str($num) { + $str = gmp_strval($num, 16); + $len = strlen($str); + if ($len % 2 == 1) { + $str = '0'.$str; + } + return pack("H*", $str); + } + function bigint_random($n, $s) { + $result = gmp_init(0); + for ($i = 0; $i < $n; $i++) { + if (mt_rand(0, 1)) { + gmp_setbit($result, $i); + } + } + if ($s) { + gmp_setbit($result, $n - 1); + } + return $result; + } + function bigint_powmod($x, $y, $m) { + return gmp_powm($x, $y, $m); + } +} +else if (extension_loaded('big_int')) { + function bigint_dec2num($dec) { + return bi_from_str($dec); + } + function bigint_num2dec($num) { + return bi_to_str($num); + } + function bigint_str2num($str) { + return bi_from_str(bin2hex($str), 16); + } + function bigint_num2str($num) { + $str = bi_to_str($num, 16); + $len = strlen($str); + if ($len % 2 == 1) { + $str = '0'.$str; + } + return pack("H*", $str); + } + function bigint_random($n, $s) { + $result = bi_rand($n); + if ($s) { + $result = bi_set_bit($result, $n - 1); + } + return $result; + } + function bigint_powmod($x, $y, $m) { + return bi_powmod($x, $y, $m); + } +} +else if (extension_loaded('bcmath')) { + function bigint_dec2num($dec) { + return $dec; + } + function bigint_num2dec($num) { + return $num; + } + function bigint_str2num($str) { + bcscale(0); + $len = strlen($str); + $result = '0'; + $m = '1'; + for ($i = 0; $i < $len; $i++) { + $result = bcadd(bcmul($m, ord($str{$len - $i - 1})), $result); + $m = bcmul($m, '256'); + } + return $result; + } + function bigint_num2str($num) { + bcscale(0); + $str = ""; + while (bccomp($num, '0') == 1) { + $str = chr(bcmod($num, '256')) . $str; + $num = bcdiv($num, '256'); + } + return $str; + } + // author of bcmath bigint_random: mgccl + function bigint_pow($b, $e) { + if ($b == 2) { + $a[96] = '79228162514264337593543950336'; + $a[128] = '340282366920938463463374607431768211456'; + $a[160] = '1461501637330902918203684832716283019655932542976'; + $a[192] = '6277101735386680763835789423207666416102355444464034512896'; + $a[256] = '115792089237316195423570985008687907853269984665640564039457584007913129639936'; + $a[512] = '13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096'; + $a[768] = '1552518092300708935148979488462502555256886017116696611139052038026050952686376886330878408828646477950487730697131073206171580044114814391444287275041181139204454976020849905550265285631598444825262999193716468750892846853816057856'; + $a[1024] = '179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216'; + $a[1356] = '1572802244866018108182967249994981337399178505432223228293716677435703277129801955281491139254988030713172834803458459525011536776047399098682525970017006610187370020027540826048617586909475175880278263391147764612823746132583281588112028234096933800670620569966257212339315820309710495898777306979706509398705741430192541287726011814541176060679505247297118998085067003005943214893171428950699778511718055936'; + $a[2048] = '32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656'; + $a[3072] = '5809605995369958062859502533304574370686975176362895236661486152287203730997110225737336044533118407251326157754980517443990529594540047121662885672187032401032111639706440498844049850989051627200244765807041812394729680540024104827976584369381522292361208779044769892743225751738076979568811309579125511333093243519553784816306381580161860200247492568448150242515304449577187604136428738580990172551573934146255830366405915000869643732053218566832545291107903722831634138599586406690325959725187447169059540805012310209639011750748760017095360734234945757416272994856013308616958529958304677637019181594088528345061285863898271763457294883546638879554311615446446330199254382340016292057090751175533888161918987295591531536698701292267685465517437915790823154844634780260102891718032495396075041899485513811126977307478969074857043710716150121315922024556759241239013152919710956468406379442914941614357107914462567329693696'; + $a[4096] = '1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085903001302413467189726673216491511131602920781738033436090243804708340403154190336'; + $a[8192] = '1090748135619415929462984244733782862448264161996232692431832786189721331849119295216264234525201987223957291796157025273109870820177184063610979765077554799078906298842192989538609825228048205159696851613591638196771886542609324560121290553901886301017900252535799917200010079600026535836800905297805880952350501630195475653911005312364560014847426035293551245843928918752768696279344088055617515694349945406677825140814900616105920256438504578013326493565836047242407382442812245131517757519164899226365743722432277368075027627883045206501792761700945699168497257879683851737049996900961120515655050115561271491492515342105748966629547032786321505730828430221664970324396138635251626409516168005427623435996308921691446181187406395310665404885739434832877428167407495370993511868756359970390117021823616749458620969857006263612082706715408157066575137281027022310927564910276759160520878304632411049364568754920967322982459184763427383790272448438018526977764941072715611580434690827459339991961414242741410599117426060556483763756314527611362658628383368621157993638020878537675545336789915694234433955666315070087213535470255670312004130725495834508357439653828936077080978550578912967907352780054935621561090795845172954115972927479877527738560008204118558930004777748727761853813510493840581861598652211605960308356405941821189714037868726219481498727603653616298856174822413033485438785324024751419417183012281078209729303537372804574372095228703622776363945290869806258422355148507571039619387449629866808188769662815778153079393179093143648340761738581819563002994422790754955061288818308430079648693232179158765918035565216157115402992120276155607873107937477466841528362987708699450152031231862594203085693838944657061346236704234026821102958954951197087076546186622796294536451620756509351018906023773821539532776208676978589731966330308893304665169436185078350641568336944530051437491311298834367265238595404904273455928723949525227184617404367854754610474377019768025576605881038077270707717942221977090385438585844095492116099852538903974655703943973086090930596963360767529964938414598185705963754561497355827813623833288906309004288017321424808663962671333528009232758350873059614118723781422101460198615747386855096896089189180441339558524822867541113212638793675567650340362970031930023397828465318547238244232028015189689660418822976000815437610652254270163595650875433851147123214227266605403581781469090806576468950587661997186505665475715792896'; + return (isset($a[$e]) ? $a[$e] : bcpow(2, $e)); + } + return bcpow($b, $e); + } + function bigint_random($n, $s) { + bcscale(0); + $t = bigint_pow(2, $n); + if ($s == 1) { + $m = bcdiv($t, 2); + $t = bcsub($m, 1); + } + else { + $m = 0; + $t = bcsub($t, 1); + } + $l = strlen($t); + $n = (int) ($l / 9) + 1; + $r = ''; + while($n) { + $r .= substr('000000000' . mt_rand(0, 999999999), -9); + --$n; + } + $r = substr($r, 0, $l); + while (bccomp($r, $t) == 1) $r = substr($r, 1, $l) . mt_rand(0, 9); + return bcadd($r, $m); + } + if (!function_exists('bcpowmod')) { + function bcpowmod($x, $y, $modulus, $scale = 0) { + $t = '1'; + while (bccomp($y, '0')) { + if (bccomp(bcmod($y, '2'), '0')) { + $t = bcmod(bcmul($t, $x), $modulus); + $y = bcsub($y, '1'); + } + + $x = bcmod(bcmul($x, $x), $modulus); + $y = bcdiv($y, '2'); + } + return $t; + } + } + function bigint_powmod($x, $y, $m) { + return bcpowmod($x, $y, $m); + } +} +else { + function bigint_mul($a, $b) { + $n = count($a); + $m = count($b); + $nm = $n + $m; + $c = array_fill(0, $nm, 0); + for ($i = 0; $i < $n; $i++) { + for ($j = 0; $j < $m; $j++) { + $c[$i + $j] += $a[$i] * $b[$j]; + $c[$i + $j + 1] += ($c[$i + $j] >> 15) & 0x7fff; + $c[$i + $j] &= 0x7fff; + } + } + return $c; + } + function bigint_div($a, $b, $is_mod = 0) { + $n = count($a); + $m = count($b); + $c = array(); + $d = floor(0x8000 / ($b[$m - 1] + 1)); + $a = bigint_mul($a, array($d)); + $b = bigint_mul($b, array($d)); + for ($j = $n - $m; $j >= 0; $j--) { + $tmp = $a[$j + $m] * 0x8000 + $a[$j + $m - 1]; + $rr = $tmp % $b[$m - 1]; + $qq = round(($tmp - $rr) / $b[$m - 1]); + if (($qq == 0x8000) || (($m > 1) && ($qq * $b[$m - 2] > 0x8000 * $rr + $a[$j + $m - 2]))) { + $qq--; + $rr += $b[$m - 1]; + if (($rr < 0x8000) && ($qq * $b[$m - 2] > 0x8000 * $rr + $a[$j + $m - 2])) $qq--; + } + for ($i = 0; $i < $m; $i++) { + $tmp = $i + $j; + $a[$tmp] -= $b[$i] * $qq; + $a[$tmp + 1] += floor($a[$tmp] / 0x8000); + $a[$tmp] &= 0x7fff; + } + $c[$j] = $qq; + if ($a[$tmp + 1] < 0) { + $c[$j]--; + for ($i = 0; $i < $m; $i++) { + $tmp = $i + $j; + $a[$tmp] += $b[$i]; + if ($a[$tmp] > 0x7fff) { + $a[$tmp + 1]++; + $a[$tmp] &= 0x7fff; + } + } + } + } + if (!$is_mod) return $c; + $b = array(); + for ($i = 0; $i < $m; $i++) $b[$i] = $a[$i]; + return bigint_div($b, array($d)); + } + function bigint_zerofill($str, $num) { + return str_pad($str, $num, '0', STR_PAD_LEFT); + } + function bigint_dec2num($dec) { + $n = strlen($dec); + $a = array(0); + $n += 4 - ($n % 4); + $dec = bigint_zerofill($dec, $n); + $n >>= 2; + for ($i = 0; $i < $n; $i++) { + $a = bigint_mul($a, array(10000)); + $a[0] += (int)substr($dec, 4 * $i, 4); + $m = count($a); + $j = 0; + $a[$m] = 0; + while ($j < $m && $a[$j] > 0x7fff) { + $a[$j++] &= 0x7fff; + $a[$j]++; + } + while ((count($a) > 1) && (!$a[count($a) - 1])) array_pop($a); + } + return $a; + } + function bigint_num2dec($num) { + $n = count($num) << 1; + $b = array(); + for ($i = 0; $i < $n; $i++) { + $tmp = bigint_div($num, array(10000), 1); + $b[$i] = bigint_zerofill($tmp[0], 4); + $num = bigint_div($num, array(10000)); + } + while ((count($b) > 1) && !(int)$b[count($b) - 1]) array_pop($b); + $n = count($b) - 1; + $b[$n] = (int)$b[$n]; + $b = join('', array_reverse($b)); + return $b; + } + function bigint_str2num($str) { + $n = strlen($str); + $n += 15 - ($n % 15); + $str = str_pad($str, $n, chr(0), STR_PAD_LEFT); + $j = 0; + $result = array(); + for ($i = 0; $i < $n; $i++) { + $result[$j++] = (ord($str{$i++}) << 7) | (ord($str{$i}) >> 1); + $result[$j++] = ((ord($str{$i++}) & 0x01) << 14) | (ord($str{$i++}) << 6) | (ord($str{$i}) >> 2); + $result[$j++] = ((ord($str{$i++}) & 0x03) << 13) | (ord($str{$i++}) << 5) | (ord($str{$i}) >> 3); + $result[$j++] = ((ord($str{$i++}) & 0x07) << 12) | (ord($str{$i++}) << 4) | (ord($str{$i}) >> 4); + $result[$j++] = ((ord($str{$i++}) & 0x0f) << 11) | (ord($str{$i++}) << 3) | (ord($str{$i}) >> 5); + $result[$j++] = ((ord($str{$i++}) & 0x1f) << 10) | (ord($str{$i++}) << 2) | (ord($str{$i}) >> 6); + $result[$j++] = ((ord($str{$i++}) & 0x3f) << 9) | (ord($str{$i++}) << 1) | (ord($str{$i}) >> 7); + $result[$j++] = ((ord($str{$i++}) & 0x7f) << 8) | ord($str{$i}); + } + $result = array_reverse($result); + $i = count($result) - 1; + while ($result[$i] == 0) { + array_pop($result); + $i--; + } + return $result; + } + function bigint_num2str($num) { + ksort($num, SORT_NUMERIC); + $n = count($num); + $n += 8 - ($n % 8); + $num = array_reverse(array_pad($num, $n, 0)); + $s = ''; + for ($i = 0; $i < $n; $i++) { + $s .= chr($num[$i] >> 7); + $s .= chr((($num[$i++] & 0x7f) << 1) | ($num[$i] >> 14)); + $s .= chr(($num[$i] >> 6) & 0xff); + $s .= chr((($num[$i++] & 0x3f) << 2) | ($num[$i] >> 13)); + $s .= chr(($num[$i] >> 5) & 0xff); + $s .= chr((($num[$i++] & 0x1f) << 3) | ($num[$i] >> 12)); + $s .= chr(($num[$i] >> 4) & 0xff); + $s .= chr((($num[$i++] & 0x0f) << 4) | ($num[$i] >> 11)); + $s .= chr(($num[$i] >> 3) & 0xff); + $s .= chr((($num[$i++] & 0x07) << 5) | ($num[$i] >> 10)); + $s .= chr(($num[$i] >> 2) & 0xff); + $s .= chr((($num[$i++] & 0x03) << 6) | ($num[$i] >> 9)); + $s .= chr(($num[$i] >> 1) & 0xff); + $s .= chr((($num[$i++] & 0x01) << 7) | ($num[$i] >> 8)); + $s .= chr($num[$i] & 0xff); + } + return ltrim($s, chr(0)); + } + + function bigint_random($n, $s) { + $lowBitMasks = array(0x0000, 0x0001, 0x0003, 0x0007, + 0x000f, 0x001f, 0x003f, 0x007f, + 0x00ff, 0x01ff, 0x03ff, 0x07ff, + 0x0fff, 0x1fff, 0x3fff); + $r = $n % 15; + $q = floor($n / 15); + $result = array(); + for ($i = 0; $i < $q; $i++) { + $result[$i] = mt_rand(0, 0x7fff); + } + if ($r != 0) { + $result[$q] = mt_rand(0, $lowBitMasks[$r]); + if ($s) { + $result[$q] |= 1 << ($r - 1); + } + } + else if ($s) { + $result[$q - 1] |= 0x4000; + } + return $result; + } + function bigint_powmod($x, $y, $m) { + $n = count($y); + $p = array(1); + for ($i = 0; $i < $n - 1; $i++) { + $tmp = $y[$i]; + for ($j = 0; $j < 0xf; $j++) { + if ($tmp & 1) $p = bigint_div(bigint_mul($p, $x), $m, 1); + $tmp >>= 1; + $x = bigint_div(bigint_mul($x, $x), $m, 1); + } + } + $tmp = $y[$i]; + while ($tmp) { + if ($tmp & 1) $p = bigint_div(bigint_mul($p, $x), $m, 1); + $tmp >>= 1; + $x = bigint_div(bigint_mul($x, $x), $m, 1); + } + return $p; + } +} +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/compat.php b/ThinkPHP/Extend/Vendor/phpRPC/compat.php new file mode 100644 index 0000000..def4338 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/compat.php @@ -0,0 +1,241 @@ + | +| | +| This file may be distributed and/or modified under the | +| terms of the GNU General Public License (GPL) version | +| 2.0 as published by the Free Software Foundation and | +| appearing in the included file LICENSE. | +| | +\**********************************************************/ + +/* Provides missing functionality for older versions of PHP. + * + * Copyright: Ma Bingyao + * Version: 1.5 + * LastModified: Apr 12, 2010 + * This library is free. You can redistribute it and/or modify it under GPL. + */ + +require_once("phprpc_date.php"); + +if (!function_exists('file_get_contents')) { + function file_get_contents($filename, $incpath = false, $resource_context = null) { + if (false === $fh = fopen($filename, 'rb', $incpath)) { + user_error('file_get_contents() failed to open stream: No such file or directory', + E_USER_WARNING); + return false; + } + clearstatcache(); + if ($fsize = @filesize($filename)) { + $data = fread($fh, $fsize); + } + else { + $data = ''; + while (!feof($fh)) { + $data .= fread($fh, 8192); + } + } + fclose($fh); + return $data; + } +} + +if (!function_exists('ob_get_clean')) { + function ob_get_clean() { + $contents = ob_get_contents(); + if ($contents !== false) ob_end_clean(); + return $contents; + } +} + +/** +3 more bugs found and fixed: +1. failed to work when the gz contained a filename - FIXED +2. failed to work on 64-bit architecture (checksum) - FIXED +3. failed to work when the gz contained a comment - cannot verify. +Returns some errors (not all!) and filename. +*/ +function gzdecode($data, &$filename = '', &$error = '', $maxlength = null) { + $len = strlen($data); + if ($len < 18 || strcmp(substr($data, 0, 2), "\x1f\x8b")) { + $error = "Not in GZIP format."; + return null; // Not GZIP format (See RFC 1952) + } + $method = ord(substr($data, 2, 1)); // Compression method + $flags = ord(substr($data, 3, 1)); // Flags + if ($flags & 31 != $flags) { + $error = "Reserved bits not allowed."; + return null; + } + // NOTE: $mtime may be negative (PHP integer limitations) + $mtime = unpack("V", substr($data, 4, 4)); + $mtime = $mtime[1]; + $xfl = substr($data, 8, 1); + $os = substr($data, 8, 1); + $headerlen = 10; + $extralen = 0; + $extra = ""; + if ($flags & 4) { + // 2-byte length prefixed EXTRA data in header + if ($len - $headerlen - 2 < 8) { + return false; // invalid + } + $extralen = unpack("v", substr($data, 8, 2)); + $extralen = $extralen[1]; + if ($len - $headerlen - 2 - $extralen < 8) { + return false; // invalid + } + $extra = substr($data, 10, $extralen); + $headerlen += 2 + $extralen; + } + $filenamelen = 0; + $filename = ""; + if ($flags & 8) { + // C-style string + if ($len - $headerlen - 1 < 8) { + return false; // invalid + } + $filenamelen = strpos(substr($data, $headerlen), chr(0)); + if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) { + return false; // invalid + } + $filename = substr($data, $headerlen, $filenamelen); + $headerlen += $filenamelen + 1; + } + $commentlen = 0; + $comment = ""; + if ($flags & 16) { + // C-style string COMMENT data in header + if ($len - $headerlen - 1 < 8) { + return false; // invalid + } + $commentlen = strpos(substr($data, $headerlen), chr(0)); + if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) { + return false; // Invalid header format + } + $comment = substr($data, $headerlen, $commentlen); + $headerlen += $commentlen + 1; + } + $headercrc = ""; + if ($flags & 2) { + // 2-bytes (lowest order) of CRC32 on header present + if ($len - $headerlen - 2 < 8) { + return false; // invalid + } + $calccrc = crc32(substr($data, 0, $headerlen)) & 0xffff; + $headercrc = unpack("v", substr($data, $headerlen, 2)); + $headercrc = $headercrc[1]; + if ($headercrc != $calccrc) { + $error = "Header checksum failed."; + return false; // Bad header CRC + } + $headerlen += 2; + } + // GZIP FOOTER + $datacrc = unpack("V", substr($data, -8, 4)); + $datacrc = sprintf('%u', $datacrc[1] & 0xFFFFFFFF); + $isize = unpack("V", substr($data, -4)); + $isize = $isize[1]; + // decompression: + $bodylen = $len - $headerlen - 8; + if ($bodylen < 1) { + // IMPLEMENTATION BUG! + return null; + } + $body = substr($data, $headerlen, $bodylen); + $data = ""; + if ($bodylen > 0) { + switch ($method) { + case 8: + // Currently the only supported compression method: + $data = gzinflate($body, $maxlength); + break; + default: + $error = "Unknown compression method."; + return false; + } + } // zero-byte body content is allowed + // Verifiy CRC32 + $crc = sprintf("%u", crc32($data)); + $crcOK = $crc == $datacrc; + $lenOK = $isize == strlen($data); + if (!$lenOK || !$crcOK) { + $error = ( $lenOK ? '' : 'Length check FAILED. ') . ( $crcOK ? '' : 'Checksum FAILED.'); + return false; + } + return $data; +} + +if (version_compare(phpversion(), "5", "<")) { + function serialize_fix($v) { + return str_replace('O:11:"phprpc_date":7:{', 'O:11:"PHPRPC_Date":7:{', serialize($v)); + } +} +else { + function serialize_fix($v) { + return serialize($v); + } +} + +function declare_empty_class($classname) { + static $callback = null; + $classname = preg_replace('/[^a-zA-Z0-9\_]/', '', $classname); + if ($callback===null) { + $callback = $classname; + return; + } + if ($callback) { + call_user_func($callback, $classname); + } + if (!class_exists($classname)) { + if (version_compare(phpversion(), "5", "<")) { + eval('class ' . $classname . ' { }'); + } + else { + eval(' + class ' . $classname . ' { + private function __get($name) { + $vars = (array)$this; + $protected_name = "\0*\0$name"; + $private_name = "\0'.$classname.'\0$name"; + if (array_key_exists($name, $vars)) { + return $this->$name; + } + else if (array_key_exists($protected_name, $vars)) { + return $vars[$protected_name]; + } + else if (array_key_exists($private_name, $vars)) { + return $vars[$private_name]; + } + else { + $keys = array_keys($vars); + $keys = array_values(preg_grep("/^\\\\x00.*?\\\\x00".$name."$/", $keys)); + if (isset($keys[0])) { + return $vars[$keys[0]]; + } + else { + return NULL; + } + } + } + }'); + } + } +} +declare_empty_class(ini_get('unserialize_callback_func')); +ini_set('unserialize_callback_func', 'declare_empty_class'); +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams.php b/ThinkPHP/Extend/Vendor/phpRPC/dhparams.php new file mode 100644 index 0000000..f6cbbb5 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams.php @@ -0,0 +1,77 @@ + | +| | +| This file may be distributed and/or modified under the | +| terms of the GNU General Public License (GPL) version | +| 2.0 as published by the Free Software Foundation and | +| appearing in the included file LICENSE. | +| | +\**********************************************************/ + +/* Diffie-Hellman Parameters for PHPRPC. + * + * Copyright: Ma Bingyao + * Version: 1.2 + * LastModified: Apr 12, 2010 + * This library is free. You can redistribute it and/or modify it under GPL. + */ +class DHParams { + var $len; + var $dhParams; + function getNearest($n, $a) { + $j = 0; + $m = abs($a[0] - $n); + for ($i = 1; $i < count($a); $i++) { + $t = abs($a[$i] - $n); + if ($m > $t) { + $m = $t; + $j = $i; + } + } + return $a[$j]; + } + function DHParams($len = 128) { + if (extension_loaded('gmp')) { + $a = array(96, 128, 160, 192, 256, 512, 768, 1024, 1536, 2048, 3072, 4096); + } + else if (extension_loaded('big_int')) { + $a = array(96, 128, 160, 192, 256, 512, 768, 1024, 1536); + } + else if (extension_loaded('bcmath')) { + $a = array(96, 128, 160, 192, 256, 512); + } + else { + $a = array(96, 128, 160); + } + $this->len = $this->getNearest($len, $a); + $dhParams = unserialize(file_get_contents("dhparams/{$this->len}.dhp", true)); + $this->dhParams = $dhParams[mt_rand(0, count($dhParams) - 1)]; + } + function getL() { + return $this->len; + } + function getP() { + return $this->dhParams['p']; + } + function getG() { + return $this->dhParams['g']; + } + function getDHParams() { + return $this->dhParams; + } +} +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/1024.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/1024.dhp new file mode 100644 index 0000000..ed32074 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/1024.dhp @@ -0,0 +1 @@ +a:50:{i:0;a:2:{s:1:"p";s:309:"129568058281196283485969852045082973240479662299833649655915078881064134837274587910680098630145331833314073809374103784577764371196941250131234226069290860531036282954125295253065782312888837858123565769812895344947719425674132117445174120829192037368513888110324906224313165146847550484828304476957369485661";s:1:"g";s:308:"74412411029812389060767064911429672552248323538380131684788386010483894594411356094583336355490245501438293594829741708592904979946709371629796413585578141928082616135469461600898538625232411795670398765206603348868016930193300395280159142433716706006511660846845763458752473756129210341944622900425176170770";}i:1;a:2:{s:1:"p";s:309:"146193716869508619647305139679263213856542375804651729246358043697244513997202825507519324367123148648281879781307709063806446534378531476829417062359168328754542266700915025319077860004928830404502692827043033744869104026437533251268433855993485126622032912525153084481026752912774722114259386768298899564303";s:1:"g";s:308:"69665008455351035902394440968350840909694548939696068493230686992883959134340037657032165407927257240961367927202156451938187477478359634699944054421395915668737939732656947241547267360211113199573477019756112574891965201688300035561288642801756915210306669313742136966503710236246509657858186512804588405518";}i:2;a:2:{s:1:"p";s:308:"95970011504465972968216025516056735009523168150391746798863350750628487022016558740903123981082492162615783238679595252201525891309321115574038283300200553527545213133632613244817126822324712292522172514337488336034824554888257812134279471335077413101896300746428316633744784706951717209185447418443121828621";s:1:"g";s:308:"32001234390591214193376879256032978095845138099384488396534938726527801485162551386074446838732561408327325537297587819822423354587910793955894800881058361532317172632826489329393036463815876353502280065088397376255064545313409639353330402859010245535643271582946371682731202352698451064261945530458419829640";}i:3;a:2:{s:1:"p";s:309:"107367948657744622403351910382294871172660886134042766184588950504191167376012553664832448482914453405627212505369017275057422865739635860055799977469867384589433510482716878025125735208146717913693754643825156388993040417089240042847866172996856390845604134659166867638714932484445695129717762215323852506223";s:1:"g";s:308:"35432052256872063868380956371395369446567951518895107007371489162979699703174160026603508244941666811604433385191485350533989707755652344700251327330272344163390347214659013791982459809652840042138137711943397019067880567618517864203333641800939772871309165704182113537048788646733770754235738140765119642861";}i:4;a:2:{s:1:"p";s:309:"165076179689180236399041719787853905509559840110034542544821025282142300182647737111192078636521696281849625331314634684082301307117056917096084810635909894266458257170816689088720750305011783930982287890608917322401215758373776087180348344303687659936705613789033223734686153637245444289163498175528538355183";s:1:"g";s:307:"7257097778465434411970060755441602617276464732216022873078841090902519498242797047568465618978053870338781634251702056843711528548879065633440550225057048183819140181212548735400876351188282105313257390821504822836725204187551346143027851261294592312829247674258710064400797532984515687719153634209645797992";}i:5;a:2:{s:1:"p";s:309:"138802088285708272974606443360541903346755775272625641090315912444740167056631682245175130288849653779718099745685973721625582881257253471469912033588275732534407812075504114028885001344754657979521240743598222852482713324944422564190132042911693426108095636266310291976312275051127638653255600619607748768161";s:1:"g";s:308:"68417768739254288613606538235899747640172953332166946096752518553591767961690284351247936702095359234884835162554920982218175460417056547752295163372680384373462615386345790712015724670852234108269209123765999335189635261342502383470729223332462342297600651014620539252087004543259974622328979031296782522180";}i:6;a:2:{s:1:"p";s:309:"143440408822834063256304001072379447612928758831014798604598968475998050944779945738610267109704057122027136269142323992275612512625193416837116502688466400091418946141409771130888652460438203432957802868229911319337716618772433262235445217129634258191904843258295950976235881931957544024858700764228870924421";s:1:"g";s:308:"61885916543751673602854962504624587475387355618874847004083364702999025366671327986702041494614967630576074420375515923449100469967023926671469204064186238960923581265396747860313554113531614635769731691080040797055303045109323006390999930220320481566672724416853132332620783770495166761662347109658807273598";}i:7;a:2:{s:1:"p";s:309:"157252810195046895262106972751573106014543521514519685514526312280470173673406217073362718196542447054177557777738853814564750348460292213548574898522849672157043162206681839289942712907178681480637456651237911559217788828984121397898667057591070954484991528199933918709759507489576582524237672309515073016337";s:1:"g";s:308:"88226515089489108825617534479543271381941380524155142801992166781725218337072902847660176074387609831777431786756574825615371213334332751708239568948591365196022411207206473125172401071031742000701493998811906302094840062532406089297779300213805172292794534054882548609113290200502606862814087039389398551133";}i:8;a:2:{s:1:"p";s:309:"114985530386639637192010327425709343494853838706808117399040944819410823551476787051890386585662495343435908127066317727387347589667037619326044414841194906165233165057587169819071837348100721622631027068393757028075105078368224325215567994990905693082132591256895393626358055498114303429757135090165754244597";s:1:"g";s:308:"91954658886623204543428135320064913668075738156343770210065195276894435619024576837084985906949383771834865278634709820758891770161134832009386328837080524363696464802456836386619858686421228303195226824855233384173023438331596052943262733993003608039164968687338024645722948542213129080275663447923469190543";}i:9;a:2:{s:1:"p";s:309:"109636871523409279767790340972634754329051398909884556956779733482149548929953420172455820185754193594396218755018820210816939914164446953253105835196134775430129532317887497749035659147652091944602377709986911544686721669749555303104118253472318080141451307479645737852211400120068770412867048403875625444929";s:1:"g";s:308:"37818248395638490196506083616037424071497042139318912208572715518335166153504034280853968065109925945696374241300596948545678886278292730681088749422984938877674324593818392935665057102238497543046661120593623474923808390078589110389438482877938086514382910775723604677940765395739691577027916901419974181668";}i:10;a:2:{s:1:"p";s:309:"171730493569370019376800099225484177890965402584439879262134362090208780017825875746914723522867989271423524805865035183047449735154919305905173130906979533370250036154805449250313007756615641578776997081126674385739513158578666666475902928085117932562730012747788409809904847316965666667562299267227963953209";s:1:"g";s:309:"108416022315624195962025023721429686956214474671377630577595792182130934651146546536934806785055934780756022131579568185897105910304336666966603269784935938299676652324388066306399902577207000810316610396941802565186861722182315811374339068009895153890079993046590210907050629248793523019275731677163852103278";}i:11;a:2:{s:1:"p";s:309:"122106850849876812974026248474577243429513625504577859983625726463984009864701112373037766966449574405643986501924059709161200764018639946475182619842398415505427880887419201361794547676397333516971649037394750916047253475385290090455656437086867354170238521151796557315029217026885863606073266370855712820719";s:1:"g";s:308:"24735148417562057840168476236802864525918787478183767549255404873115071566410820342975609285551159637301964099270689346814428231138259200159783611910129880506577636334045758775993631403235839108647573874932088398186329326859338337177512287828022266115337530677346513192023934283754416757903570244925408141124";}i:12;a:2:{s:1:"p";s:308:"98563064041855485547203709600999976616419318617005972312351844359425573674247265938234295573987429665676307716147248366503793293946473843863821094112041842163433187820029643571486513623012617552199332014038456603155834453649363234466831889556280793416223207898261294552530862813499919423410866004801362984157";s:1:"g";s:308:"59438969191433206885160654546800973338113955254155498154081588424773915117978710991458854168836846149574281831646696983304381311140860938963799520039261884497369538383372456178914971487015682793424582209855322967460266300754823895771337403292656106744806123861995705604402095631107844241722972208149696069901";}i:13;a:2:{s:1:"p";s:309:"178284570928419116251879511232308570183768336425183537983900704602870837188332981934665351235828833856090429560178119229215140472009400606724448162311527189376668655398871211015154270102539242482291841778242319866102591751437519616120511427151657963001938761731491181176323677631190765849664845153959486560283";s:1:"g";s:309:"148866999117635919417654566555696301710898017486560869603508728720369000308011510499499432872896469950541973497581527050700259381170969069051888183343314713029719431048716245290397673569650907200574767862492308652304273160426175251156907772789224555079381452284087020498494077430745587197689507967768857105956";}i:14;a:2:{s:1:"p";s:309:"116738580923175563597852946259942668774376741851243739225112168154299319378570097819002752583211279288010166314376092749452022693090749405496712595173427088219917593978092666816371487183342540185349140910668072044197068187531521505601089090756898828738261874761402398001673390547712523143844149045116052320447";s:1:"g";s:308:"40034019056813540582152025088875031301471554203237488324792191579491686866385133449374555241477936777633651939990968648667228424361281957258281751622971833684652653172758624480857897678112312636724089024553363699426562753044909465441006363024563493791311183967053810493340062539118031062536501032727371656556";}i:15;a:2:{s:1:"p";s:309:"126416923016504794892262733817762961386741581091282927102847048681387859009976911891213445835335683685961824220040945930186942069653866470565058006364859508113271188926837922616983429432971047367039856437192480727203019675679406394279531743601364712279259153955168108639232674771097755353305522755827224808783";s:1:"g";s:309:"115217983612815221807881039047616510833937677746347677762674420215129457029965858858381020879648451528607840750667922014522507961901103522126616783107408227640178996788031640423168737789746950166860880632363377442064306092590337543542962209423238876035647879264300565404605950968938772318148521663749673131099";}i:16;a:2:{s:1:"p";s:309:"143625235691679173790886628527372299203036999068004043049293157737498971333598566984526746417282853572231806173640623863668011175162069116291184420978114679218220215343843707983230876997357140567082288451238414474598947943184854685135804783998570746961957854573146698096808752435056693051401194762660928100291";s:1:"g";s:307:"2811906146542542544508099935802560496259761014277619841236735465830246544879946190087219311700423280133249036896828576018583549158462866232998364790129911777154099906740274868660919875297049045056201762749104047808011371830286824154334564178537171875355764504606152138545087944095720124720892297463471228703";}i:17;a:2:{s:1:"p";s:309:"121993314148770027219037424907576269470769429753193286495985674269623203562674630388975936634497963788324829621047210948121667489694438986232246907066349832212292491390918321554381941982921602817218049875411538677739007395791700194829322235503670960059494915298990576486708275549417539146086251251624135349939";s:1:"g";s:308:"76136756831073177744226997691236148872628027575601681328786412569385300051842743182050455179596968765127239279852680795886929553043311383681954887233978473067877172753495304640131160100079991048334006169655578631036144643965635995290531840054826540373743555549720623816740175043396340429759474512569110591151";}i:18;a:2:{s:1:"p";s:309:"124507994067600742618074869849502068365304040789212000487597154884662225035334860191210068989342872209246000032800019976883544484524411784905306951476799686163700601896271250346743329785269061645715826764256180887461136011848692557042253327916990782493758819566513663718823981060679554727596357143528871317029";s:1:"g";s:308:"35482091456711296536619960625191304461320385791007440302280000459820091544274446698718600582729456595724243302196867721560781247921581506087934961217320172517820436375036025679986744433993300325533389319578275768579785520050047676029798921290638765091850128922108253967600366949053220716093204424923866639659";}i:19;a:2:{s:1:"p";s:309:"109064911958670773649835739607804087660086265501176811018327103461487668225519906223353251760111190939688515131932304441638992866400411226029802671305803598781894196659707854750685867585938708782669538095831227041248283200630619059108032196443898570993622064280958838616123797547223348352709177595311511599127";s:1:"g";s:308:"19319085215957110536116059458132145601846897698032302263421502982575340197281074377754938122814767436026933811580737427951112223724536263615505177029727037084943699236718859061711113087160230654888547614277944690686053963024350436971089168545071233076652921578379142066648762537208150629974955548551496035508";}i:20;a:2:{s:1:"p";s:309:"152906937544903906500158994700987429025320104102810683664637770214766670911595774070719831089658199116354030446402893709562506135087569908102297576309390792224913162999986166517633590115811057491043292747990827411008636071214350838529749370926702854124191129277803120854478952648197409338821905891673530410583";s:1:"g";s:308:"91187914216528946835934502389977046892487031834663291019963344959483826794791886459334460883860381266880371274752391802612238136138804906007128976482853796298630067218594097450162858199508629386035676253140564960068420655423166899188074787874980346006766017039274380084312606630473497196077651554580178899620";}i:21;a:2:{s:1:"p";s:309:"120086911902590349366454763756514126237708714726873488009496335335637189915037279805404346623857583026128779203569864388549114527319559676012081995869302301188337042796528657367058068666482059979304786341533831397236939898922005010598725616120953311774451680404822020000603731144436784446124165276717107943767";s:1:"g";s:307:"4424877313153692455459160010045442376627290942868240892963899133364693215888804616996451658036573295042389069650630298172240061707271934897152643400497308474473895781338189295452861594891955327070306932371961613259631255464856486062618144044590877854971649831663385524916482609955557119733681027235051394932";}i:22;a:2:{s:1:"p";s:309:"114348651836506523500945935233374922736007775412847938214326113685832510534729952115503013208770982688991421802461695224699078655218430623713975694946030893977655752146594815185747948759946130185443646234087578887495356406232198663781066104307878855072887544156539853609255635001994884140842596116557739719339";s:1:"g";s:307:"3057093897497336474088939848688661425207560147177357671574081687524315743030139763595840116604296424154647944641166825852937323648159223225785426718349765948296485966934692317251464598254426752313531074560614623259760117723367044048992743223355384969321694573041256516497658853328140689287015483841963198485";}i:23;a:2:{s:1:"p";s:309:"151327650171178840752159959652360320262504680172183688626941326142323285313387175965893936843422387583059747539217294800332826680621899964529924259987091710340379569950289775771095947259209635172546634980224610800461576519968535309440918178046872340066339103756730010311335921411262306273623820892604544491083";s:1:"g";s:308:"93698947898542625080224999126897954039977816399726641263795164630099055943251781086266175948233460340162387832326085867234397994791219403143430000582587477992357941677427763758041941957575706031515765338579564903757662164614536867472674838978395200565535988130855861706547826534924631265525304939324782653714";}i:24;a:2:{s:1:"p";s:308:"93521349632285344521892805711041617086177867320264156006082942266085555239430140082892856429101554903795878410700096375285554712092378461187415152844263072615812187854557693901260441992278421683913551405640379450072927340627546240607073580365588955121454018383348564233577572631416908081675968109054718213651";s:1:"g";s:308:"72771444498359995710897378671512916022955775236629004788865109476298715383451615148812465275461129578179286998456555171089504695435937979981487681863800662090010955930732523942155243068394783205736383507489827275947913244113978685677151547805378500227336458209605695806261274104663472071017000731176318137622";}i:25;a:2:{s:1:"p";s:309:"154538027567571020051211849456110781402373992733880648830768917597755638265440933232881652059213857800411025814190629364180958088042486785080095848649421973721170250640044907161165782781498829401355213704798178816875963125988553036855252471477479214335533104910682313679864758691208754871335938134146570244233";s:1:"g";s:309:"151878268383910627178775626075769783354408670111552691713603803262208268504534598144185757441663543391767524850440098706725577284510706316706784129116482666131665290402058351722910804879096297592649548518592704064553732795220929615663992939631806717400234044169768626282218689487288304150755186241724898111829";}i:26;a:2:{s:1:"p";s:309:"101653566005311023925476332074740680760986376640227033128030649304832500364833045686179637239812634502064069571359223433072628429786421692593933101196289496232554055527830367596771381014857286540650623892767418966585533940466064017851317632676358364053937566259716232595107740160572362341096507417302692903861";s:1:"g";s:308:"74513607929035958667614526386443731970505034893688087329791851500228238599981508473298612939972711716486678692030303405741746145559282283162063549999965122587859070966516041155490470664682457776474615008916731802079841562892122761530124749566709348258961907082769282945089628529694000014717122454967698917460";}i:27;a:2:{s:1:"p";s:308:"95013960730537646945707930117033259716425250443303065109257923132885025742351896240153856832266522610218042023001720718571959026083577683594238991046216761447273850529095670800239812482889546714995990857314170023607531299056678286770352047754090948625051516504247244141244971934385607741647807871939423643417";s:1:"g";s:307:"8865118845127243015967838648938431880490166248417614215833772532595068334088382421370444972119810353915368575955429426679051753997676166286454497698339421653032306173169181980560322753725269776395160793563057913381832550741293157158306307662293960121073170223223526549325156207936691130571839423818348804874";}i:28;a:2:{s:1:"p";s:309:"165171568680967123886817133609555478777376451381185880118392760161526195696056154677234447980800025307869740068307389118220255165799524209662639178475579984315366245832285858100155088238540583941028875367935393602555119105296112422147861581513097413687377533516651030313147659549849822429529620533241957376461";s:1:"g";s:309:"125035932268322111740442907189656967999398670741804679117991185625792797440733765792321494160564108005199651911011206634432661255852804587565419942716241432891303926297868064874944963552504922882417912648147956818566297482440510358827099695306382023608097107907616454643867088476820708208837260972148368028666";}i:29;a:2:{s:1:"p";s:309:"149426789853068576691755408517052689479631486303474855851435537819356576423401695805659694193339781938404097894957535566502875170679660046587328388332483673210946843879963235153300984461866198864922318697292136026813009299028730482141451343653633845072186024898362005994170295241610203348654612524541396422397";s:1:"g";s:308:"73049073326296538965204086376153534487090415894032911283800130298629512997442525640837238968619479480629231884187445441225287944042744290713844591778499386520701583015778604634989765861327662774146166059025009694822186345094204748823299314036557275575979692921442204327068917190507323721173826594618769385979";}i:30;a:2:{s:1:"p";s:309:"135576329950386319783588278542132482993509697780105687913763037715299072538393798842105766084812653813647207393906971415039384965453861783642420021499035478002876073188931021393616989459213349405347142133542309416134384844351939543623768121011240069777383730773881088056874192238013050626270026174182267430717";s:1:"g";s:308:"60290997726824005308014865952860150036003597394047065883797290775765998303031531128172348476104602100923880751224159249009015002013080863909428509827722962421722642840399830757903808956875244743719288448455233739472345388057408045449495018163568905120714599842949385074246992032986074584000551188391542767463";}i:31;a:2:{s:1:"p";s:309:"159065776098323310441379296801791022455112191137870334479728771028751912269616629460900852200402421009307482473450428015915046824869147855243477769734130917997450446203411540494770348199589203378022151536992114137202513049016111036147137494187423144663693903693069118404837384424743130353522620387505597979359";s:1:"g";s:308:"43262178902448634370560334233060164330909659542673106272550614113862676255101507573561918404933225250124875942010295679192073921803863446466704825450009940939748827765323598689766356218791822315938651724944088733794097890759186493099112538275600413748100124980228285409612371429943359045997493847309113094420";}i:32;a:2:{s:1:"p";s:309:"160394941658450930276801031843077823785507821874720567147511483933208719668066705194765948461937550873363758297677780099637494770481353160979298177536248116532480392143334998523558523755864576621025753190170092723744034008237711325789361465741779607652217503455195004836525957182459455212695365562397642327793";s:1:"g";s:308:"80547204427645310086317970329606761433064424399921493097938200607767280488068285659681897406984483932897624033557910172823554540190625306750715210905207903368482988268690529944147507714249162654641932802591997206826192545609133886659250269751768696058736169665371823013501660148951330528409739051259717561690";}i:33;a:2:{s:1:"p";s:309:"177204881539784382588587844818041975965303560543162630455910056438154838593138830187319688900891313579137735937814467432633223178967482608482890993831012978464354436059856781658299553545037014282810727108082122588695746040219389387811199278574283486984537788675106695657576082357971493731577296175232034436141";s:1:"g";s:308:"69235053132347779619993662979522806857339437477106976840223821553847294669711048050675068877860119501392090174568568049659762185187804664573479845315366181247065012559547353319817063459644529835997237851200186729133930957640120723326425914499963919940154634598957978320326819438511948953408983404730431346679";}i:34;a:2:{s:1:"p";s:309:"170632450386449252892177651707784510677816625351105295529973803089643511952292071117487088243581854585627834705143965097010002760714509270510175372080209246944381024402704210823368565134636107733496734242350149868764032016679575323249886774833276221888180845935536877312614375117430059888272016549986096298381";s:1:"g";s:308:"24472385768968026997798980591786418974391665216646569808610375270769405972123783498459702414787564780388487976158770080827973184539797280411107573023349088116818340517293319973443760108032296957122632603976045312015768310687201612205589952908786210188329173621466708105183429140807264065028128471662573361600";}i:35;a:2:{s:1:"p";s:309:"106658122355520675039628277711696683144582739154934203137085123160221461841008030522414574684630155853821380331921319540272434071011591133318016562285627539130389090569115783107308483014499994503494308836196758225421785889774862524445335359696266057221770535448860053645733764498088036270185537882385482831183";s:1:"g";s:308:"39783652361002485670275466730672530969147764387968401456017775771979782025778665517161604038096192323204967577144624873089805078877923323600555536296131983877118252913078053205536795585717846083877586544103441059828092151865494642451758943378392029454891361242185344072415082423303093417563841046684352151448";}i:36;a:2:{s:1:"p";s:309:"103044743450356815717280629987073025863731845223317680836739897408078663728915414987974010186550546586595930233874188379117304132766900332673653606876214967343386204242329787067659113843205186608833761820128296608284953666985708091388382863740453928554110827130493742351284285532384147373799262231569250856959";s:1:"g";s:308:"90090058479749571428201045607912930124405620381996502603882386590496176073989569208448372732705389891721609719648629186673350918601783194334467381010968712369734326596190517082744138100466263787508381087402925634188635370622908873072815732169546219741518638971435909681793234308560167890325451296165583963178";}i:37;a:2:{s:1:"p";s:309:"125388209275868954338919318322433241106530307022343221377908573761945875896771826464040700182523361756959326040847908815078631193501532095938945095221093193286494713316096166068936244486440645154697824243384714912745011963991559904054699172169083499465381741721552580299869624834814200547479930954834702869467";s:1:"g";s:308:"88667109474041919409913794223971780303805302466161109886012349328724495178758113804709357734253441488703362846364137262391434253925210240752446097480963427198378575051635750668392116625679462417025783392797833504899554705232341840759599879188837609823053497744463005858819123144669211197475473256421788902998";}i:38;a:2:{s:1:"p";s:309:"143949768931086061604940118166532662934380945231267334574786086591887870050187582969268702068457305227173986915861510012707751007961140008160896148194781758723093984226682835875932742978257118050540576674378910935190769292316700539205182480917522964863427122871625517021839596567122012919478156411734686915977";s:1:"g";s:309:"138466632730009703263604483957935077591344930459555672237159749136157934320422889392131771025368995584492516955806991516958678527504262618479774885187067450769695885037834750726818277199698417657533016521761911424894327191784411447815745375877220891536113807184440318107567817825269486823752156243704505549697";}i:39;a:2:{s:1:"p";s:309:"175420727176478352783121714923416552881222745068680163347615288184223170132146515858071589662128422601876827315329015908922123050339231472535066426849260567046474903451891613375732255710996752666666429634222976593100111925186060523566568836985586751950683018244960710294161130739354264999973915392300513010669";s:1:"g";s:309:"102214296436553733388725636282118899490816111744922220769692374117300143278361415759909106009565248076781429421870924605232528811484830856869108078614870493726394947463288917149234179718831259015495904087236508316630128687330799396156049244218724291725012201270174939120336334613215053968238776073474709467334";}i:40;a:2:{s:1:"p";s:309:"159794800055348506571008906374836701462998540886533040353197135807163688421982933759743988362547882565601903919320227504216575700066744239387795654881352389673948479450887254384341226868981920609707096127165751516392484968378483701427198667309154393238401926688124380137237516707820272504228443061371360165201";s:1:"g";s:309:"125545954061807909213440974725673246010848665665902291111413828394758575587589962734315460601269956757971755540646548110374935166026100201454535822567189177241543789524176158023868303335124684764707826312875234354490525831170982282949580832090899553475185463231422993237487770186065056142320929583755264509339";}i:41;a:2:{s:1:"p";s:309:"100539882750827218683038523645435201793549230666573329915693212453304697477172915665745340230392862173855829201370306578877441376204178128180077679525298804707605907524492059908201893059201739409946592544808266797888266407195817995198097047681246712771143508501927477035153907568921002415521626713210871346043";s:1:"g";s:308:"35502053686226969950955336189827903558684377002850015450754413739937497087878601307174154780066555396845534338310205261283992241970794651452902383865029730265568871805501296029304576201222119877387937815777937271202653885649169466455244309442119655722851543473700201461896508440245001817562486228545596343608";}i:42;a:2:{s:1:"p";s:309:"163883088092169708750236298536140720039687203494799123680434192685621955270090430640683485012985988431013394323683780842964037507442368800026594927494950463285267496279525753657775606544352907707733174181132340012100157483379593750752972189141532209198932176506722571756928339227587633423995901120004952354761";s:1:"g";s:308:"21165897458274279623174933098408694536958819285248101600565840156627556793518769244526228428619827425694586345400323334844888827367491379029972237832974198947482513794112611577346475499184088771263690674973716665704216023869046245629889113229885861874638379352584818782358324175120814914412282487903605785953";}i:43;a:2:{s:1:"p";s:309:"158310278732715787022902619395810013339735267417224324445908572573513416852425846360209440725706619854191344489651342220702140566155238540802871753904947103638583986388285621112626977421886423502443003940413306887906083091475336779687502256926095204824702267835164082066519548090177807665844915376119641694361";s:1:"g";s:308:"10843632849807178081621701225073955336720497461666456417094069730548352280008748877225736209050583172763152571705900002329657804689214917415555838692658283058931020733361636160389821172444581043732406612290988648168803751381009032812842751877417489545282283613937636557019594975816844435163566172375045198580";}i:44;a:2:{s:1:"p";s:309:"153347735020776109672598090634216407499745284347480917300658818545198675701611122459685722367884460242515317436949386602816072625929743971764067680916616908761905707081856774209123031494295472642947392714965504325544410178836879029320131059764623341098464482119547364444225790414659989577180817023099747806219";s:1:"g";s:309:"122954310235084188725866074640958827281122476177323936387469275802984759490453353855653375904411138407476003678979649372393814463080666349613725044716044211530706906010081396524233937871139226812356391818759073899430860506374698518561365425436590854680442478600581253443022679747914324251713532666663803955266";}i:45;a:2:{s:1:"p";s:309:"105119383111574947555756749613427034115871685365338216999216182362104799407352348214405998777527422827499905338598543186574235633401319346122740730194104928531642469747870053113686583094237980081517574187423239107189826416021743315549437633596207434042084300173060678340091298306743614170285022383892833272317";s:1:"g";s:308:"67178980779596302685699276457331133093242115605891944037453156935974692034220792130263273292844686981258966134995193845401621693196880186953298375654676956749648419727313952831168688324511752698322454731426431593820106946644202118100133887201187978438871644005504337273486695678858525227931317595656959050814";}i:46;a:2:{s:1:"p";s:309:"103032591117379756539799688773679250452536252275580478745302392328252396825436802273785825761894063424135369686372016268918702883198596320220024055090905544130543248384556888996699089102078751994102466915262697550823095429698807867041857056199662639242062280833453801650111530359676277918138500762149217203791";s:1:"g";s:308:"77132801423319304165796207386958946320042494252108286515106992435042926191729318949722863127204416805833659339064969009910067600668843619911038984483433433617169906588079273102517397432168428053712322220890666083309668099651430019267046493644946772357567590144667581996075280334527222547528339859786299081931";}i:47;a:2:{s:1:"p";s:309:"102085155627955815095542920619146526387782679507307151846526493529130800012104779480514121921687848167194688460305927109149559545461691767269495772073701759547274290545646610000657936697419432724419115249685635339910931149030927018431690660081084386412665095805815028555042991555828923349280187447568942620549";s:1:"g";s:308:"27454324351455464224886256988337512968951014643818071525638765600705727743455262346758378628869548773191699219835696316409465156796657956179447196850180340548717017879359249274532768288404896887877489800526718802490569932601316656411893344856428111523823705865338040702336541777735189187460764613244420564133";}i:48;a:2:{s:1:"p";s:309:"139300783541692859595840908230318717324833616486825199849963109829727143946631572973434050282537779419439403310172134664925360812720995043013071012554656861162082506619208677576419320741818481236877774498337260619037804797461901823273337809052154052894849643006097478216997712928420055709178233445255308361101";s:1:"g";s:309:"110543956085772475876488567113525531945490203248111771432474506376282741746886768658898900409682098825014100780195520527561919350237842066983251165229178651412242741196039787820589590428519549154581837021452969522343352353534257888745437891875564792402023341678616463369894744400700376676910140567752536422210";}i:49;a:2:{s:1:"p";s:309:"140481282042623513171757047048340154221489789742748447730567837747883807070388996878704463331184460145505583061254384935268451450084968799400716266246866822185422597411114352295673685607245117959083546383457343144702896784371346366101512480777183669620433643591158243003892756293342479583829460630913480276589";s:1:"g";s:308:"75251167460967282352429912701249403706989070317963542102818801005423115111161788531265287611693282776684802138420198727319983028866819384860839081670321428144683302615744779867229499830239463688840840537403755994658696002903600035111943070257625695218188008419573921013401986992437874454517822788002411777111";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/128.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/128.dhp new file mode 100644 index 0000000..12ab5fa --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/128.dhp @@ -0,0 +1 @@ +a:150:{i:0;a:2:{s:1:"p";s:39:"292056242036581752787140391622158091519";s:1:"g";s:38:"92195130631865270616756943775010543543";}i:1;a:2:{s:1:"p";s:39:"306974919588773364832090085053788336623";s:1:"g";s:39:"114777600433746811424326551581233247669";}i:2;a:2:{s:1:"p";s:39:"293639007200039809639032425563054392623";s:1:"g";s:39:"142581017277461467135688328294730434355";}i:3;a:2:{s:1:"p";s:39:"196846296865248186540320570524502677427";s:1:"g";s:39:"151521785256606845258315346858388704159";}i:4;a:2:{s:1:"p";s:39:"214058314731091729962462647631129015047";s:1:"g";s:39:"157657285759615277755120995221831770183";}i:5;a:2:{s:1:"p";s:39:"211544627828281195628005482334918005743";s:1:"g";s:39:"164526962259030671035597644393561273977";}i:6;a:2:{s:1:"p";s:39:"264374153248813750338546404933838455927";s:1:"g";s:39:"161889252888199530110939775462329045141";}i:7;a:2:{s:1:"p";s:39:"250744024384599107683215360741111008699";s:1:"g";s:39:"118285577307522764878235247551273436525";}i:8;a:2:{s:1:"p";s:39:"203253285951672991854853186118633154923";s:1:"g";s:39:"109635202434828818623372966675160073683";}i:9;a:2:{s:1:"p";s:39:"297230087236684619171820155222807526239";s:1:"g";s:39:"151698002932284917728519787908419298293";}i:10;a:2:{s:1:"p";s:39:"183928564855833010909727349867640971323";s:1:"g";s:39:"162553618575521753939201816833697743889";}i:11;a:2:{s:1:"p";s:39:"282116071387851542448859292585051222447";s:1:"g";s:38:"96195080035033034987512884449304800701";}i:12;a:2:{s:1:"p";s:39:"323821345162263657163869210284973385427";s:1:"g";s:39:"165647931357595553282108059453854618133";}i:13;a:2:{s:1:"p";s:39:"325782265605496815296945192046960828803";s:1:"g";s:39:"146673523487430798803433071896683677919";}i:14;a:2:{s:1:"p";s:39:"292656882446135308138325253216560626763";s:1:"g";s:39:"133750897967258475364439141350154768333";}i:15;a:2:{s:1:"p";s:39:"326502508934692287898138354588749827579";s:1:"g";s:38:"95055028992751783265751636323610219169";}i:16;a:2:{s:1:"p";s:39:"238737081982465824552117175513390104503";s:1:"g";s:39:"149717268104904047668959026140422455329";}i:17;a:2:{s:1:"p";s:39:"325520862010996140507951562729031642939";s:1:"g";s:39:"160750290369379144250044243773210944781";}i:18;a:2:{s:1:"p";s:39:"284660075545249738683462999870017380547";s:1:"g";s:38:"93610554989070752708257914727841862017";}i:19;a:2:{s:1:"p";s:39:"216624906373462199236239231733765471247";s:1:"g";s:39:"147533447450211848127450101532248247737";}i:20;a:2:{s:1:"p";s:39:"310957194217588922918999164668665752919";s:1:"g";s:39:"149940487727634664074703848896592397309";}i:21;a:2:{s:1:"p";s:39:"223668363326959021386397963580036366123";s:1:"g";s:39:"107617531844346373239590352039307075491";}i:22;a:2:{s:1:"p";s:39:"215978097038720595934062824264229612527";s:1:"g";s:39:"159683714362048234485774830980270810467";}i:23;a:2:{s:1:"p";s:39:"254574157135387128396125954269859179739";s:1:"g";s:39:"152701269536030391318337642370271369325";}i:24;a:2:{s:1:"p";s:39:"285631418265701142797921983323494263559";s:1:"g";s:39:"146069911336721121221056226300966199857";}i:25;a:2:{s:1:"p";s:39:"338159277198626832869677887277616180423";s:1:"g";s:39:"115921496078116668896708740833402711065";}i:26;a:2:{s:1:"p";s:39:"216947143156151209031346105444363017339";s:1:"g";s:39:"138824874907565129063997286858881153973";}i:27;a:2:{s:1:"p";s:39:"276066866652515571839979520442563284323";s:1:"g";s:39:"128901507729551455645968559013908755883";}i:28;a:2:{s:1:"p";s:39:"285669464286230064035191348420068105563";s:1:"g";s:39:"133687329906681409517596983499858741779";}i:29;a:2:{s:1:"p";s:39:"191091625204338316951536541367974663739";s:1:"g";s:39:"115858048207727468438106103077246560679";}i:30;a:2:{s:1:"p";s:39:"337515161669050885294632549226272979259";s:1:"g";s:39:"120854804811508331843161695166187664953";}i:31;a:2:{s:1:"p";s:39:"174917215197953698624444001586175836407";s:1:"g";s:39:"139145545032511871649890757539716139745";}i:32;a:2:{s:1:"p";s:39:"286385113219804783667463282575249335643";s:1:"g";s:39:"148416238100899996847378967300424921461";}i:33;a:2:{s:1:"p";s:39:"209708268755657765718168447424437273947";s:1:"g";s:38:"89390121362982706116847582116053792661";}i:34;a:2:{s:1:"p";s:39:"225466796807811837787826426622847748483";s:1:"g";s:39:"119671516376904551623274021751719706435";}i:35;a:2:{s:1:"p";s:39:"230641118913675753332052029881543537319";s:1:"g";s:39:"106904796246200906002843413808899345201";}i:36;a:2:{s:1:"p";s:39:"320356446694223075350802268074194516883";s:1:"g";s:39:"110058673619329486246922731333508660107";}i:37;a:2:{s:1:"p";s:39:"196818317043011000998928174914246107563";s:1:"g";s:39:"113324249626145305887996118612518826373";}i:38;a:2:{s:1:"p";s:39:"224525332386128175478101630046930189763";s:1:"g";s:39:"108794399937298102548174167123976936181";}i:39;a:2:{s:1:"p";s:39:"240020159051805416566835088425214246683";s:1:"g";s:39:"122682169319663959002558338806306526673";}i:40;a:2:{s:1:"p";s:39:"194462122760796075851727083710896064019";s:1:"g";s:39:"125773984560640978959501682731083867083";}i:41;a:2:{s:1:"p";s:39:"185409874317812986685079176545573532819";s:1:"g";s:38:"99333837867312477025526770551684789929";}i:42;a:2:{s:1:"p";s:39:"249577380183382163061926592594820452239";s:1:"g";s:39:"145358444229966857167759564629611560067";}i:43;a:2:{s:1:"p";s:39:"175893673428733191813784481998618328243";s:1:"g";s:39:"132841634307591201423154416956579429157";}i:44;a:2:{s:1:"p";s:39:"307677647975104863327346573139531157887";s:1:"g";s:39:"165281368579891364595473211906122097919";}i:45;a:2:{s:1:"p";s:39:"325531007121336077474467231244998934603";s:1:"g";s:39:"113453603821265113678470265129170917013";}i:46;a:2:{s:1:"p";s:39:"291853334277762332165460454523197195883";s:1:"g";s:39:"112304674628631114572271595370414970737";}i:47;a:2:{s:1:"p";s:39:"321095002670328264904742293131676711247";s:1:"g";s:39:"111234333539460488850936780994186665521";}i:48;a:2:{s:1:"p";s:39:"327904717403107858772768435620257823703";s:1:"g";s:39:"135928358598869100491972026891044903849";}i:49;a:2:{s:1:"p";s:39:"184167219998611207248355443296589162623";s:1:"g";s:39:"157493611435172681271008684759507092185";}i:50;a:2:{s:1:"p";s:39:"214547513104198035614282222084852692283";s:1:"g";s:39:"143129048934951872319248661290580415565";}i:51;a:2:{s:1:"p";s:39:"180935587267248385659347192451794341139";s:1:"g";s:38:"87403976648407948326670717447739794827";}i:52;a:2:{s:1:"p";s:39:"263818812910108424430492542012743121123";s:1:"g";s:39:"150521173398666971792260292936530681753";}i:53;a:2:{s:1:"p";s:39:"297105925338731622311494789834838923367";s:1:"g";s:39:"105412171901317536491270709831194772423";}i:54;a:2:{s:1:"p";s:39:"243477408509935222548750912761663403707";s:1:"g";s:39:"144281761591161263922410500392425300369";}i:55;a:2:{s:1:"p";s:39:"299510309907221406889358192415160524359";s:1:"g";s:38:"89872008322088932958761182838622988425";}i:56;a:2:{s:1:"p";s:39:"304910526413244884233459829695367833307";s:1:"g";s:39:"161607538803038797936035617030686594595";}i:57;a:2:{s:1:"p";s:39:"203291411173723738334374535456283611867";s:1:"g";s:38:"89443086632858787787237362893463069233";}i:58;a:2:{s:1:"p";s:39:"205944278815676907758242117465652266619";s:1:"g";s:39:"108018077395004037033024244150011486699";}i:59;a:2:{s:1:"p";s:39:"296687706241624223629592967033355602527";s:1:"g";s:38:"96745488554386356827679857768107368081";}i:60;a:2:{s:1:"p";s:39:"293550116043549804890822649451111414703";s:1:"g";s:39:"158806215400749784831080725121944668243";}i:61;a:2:{s:1:"p";s:39:"263428134653217195777465522428064821807";s:1:"g";s:39:"118547891080671339398050662124658121383";}i:62;a:2:{s:1:"p";s:39:"325923864457460442868064053037621833547";s:1:"g";s:39:"150617615016200927618807658935974292457";}i:63;a:2:{s:1:"p";s:39:"196476504632822117192236200421668858239";s:1:"g";s:39:"160523445701389768553272859591184805705";}i:64;a:2:{s:1:"p";s:39:"176583442445218673933803855316690739563";s:1:"g";s:39:"132111065569185005904201982609461776533";}i:65;a:2:{s:1:"p";s:39:"208026268064317066201094177474542461779";s:1:"g";s:39:"129201867469581710101028427020543597815";}i:66;a:2:{s:1:"p";s:39:"334723033531927024498400970288217064519";s:1:"g";s:39:"127487291993357723200673873414989528691";}i:67;a:2:{s:1:"p";s:39:"233829356466320610519071132649157616807";s:1:"g";s:38:"94860858528074519022402472317646994195";}i:68;a:2:{s:1:"p";s:39:"188691996182260359105060338959757354147";s:1:"g";s:39:"162385010597491525627389624230217003233";}i:69;a:2:{s:1:"p";s:39:"226897261159415273301339620896213232363";s:1:"g";s:39:"156442352209872496712773155991679649819";}i:70;a:2:{s:1:"p";s:39:"236583358352137488729569337157796756399";s:1:"g";s:39:"152581941462805442071888683283182954713";}i:71;a:2:{s:1:"p";s:39:"201191190567504115316899173583099194503";s:1:"g";s:39:"103194169583174226029359181901898862399";}i:72;a:2:{s:1:"p";s:39:"283922273486502260013681112736384903039";s:1:"g";s:39:"135753190954064714225129600901141433767";}i:73;a:2:{s:1:"p";s:39:"223678587798519865477081555130490930887";s:1:"g";s:39:"137587074669296278642987846569068217767";}i:74;a:2:{s:1:"p";s:39:"223668244430177551435115121204793146587";s:1:"g";s:39:"156320667147688293051263750282389084613";}i:75;a:2:{s:1:"p";s:39:"194289571790886902139380720985511224443";s:1:"g";s:39:"107945851243046988533476937950371933915";}i:76;a:2:{s:1:"p";s:39:"278775692009590991350111858729107596627";s:1:"g";s:39:"129657043560683363524105717085311868437";}i:77;a:2:{s:1:"p";s:39:"319979086847889596207807729864047286663";s:1:"g";s:39:"145322816086479761996731697936810408423";}i:78;a:2:{s:1:"p";s:39:"198304778645918608926012835033912241723";s:1:"g";s:38:"92721662469836619760966684666997323119";}i:79;a:2:{s:1:"p";s:39:"248958430506627478869847133684906264999";s:1:"g";s:39:"163946236115509075218677438118567021097";}i:80;a:2:{s:1:"p";s:39:"211126209972926688870595842369993071207";s:1:"g";s:39:"108563592364604435542369366145242235593";}i:81;a:2:{s:1:"p";s:39:"239692691796226521380036414431702787147";s:1:"g";s:39:"137476683692977742290483495678290382501";}i:82;a:2:{s:1:"p";s:39:"252311610716959305132008843115717379139";s:1:"g";s:39:"123328978402999139145213144352371439599";}i:83;a:2:{s:1:"p";s:39:"174047087138041833610836860678128035299";s:1:"g";s:39:"170009271577662203836398662496227735453";}i:84;a:2:{s:1:"p";s:39:"231348363522122086066280667498528389519";s:1:"g";s:39:"141093524922727559438821864373557385467";}i:85;a:2:{s:1:"p";s:39:"248864664933152526411279596376158030567";s:1:"g";s:39:"123889374381029290108579278155184768689";}i:86;a:2:{s:1:"p";s:39:"224462201405966083242230789750023192919";s:1:"g";s:39:"158021232799967127661274365236078929611";}i:87;a:2:{s:1:"p";s:39:"245879376734021512682830793285031923579";s:1:"g";s:39:"158046576746250718282268617313434731959";}i:88;a:2:{s:1:"p";s:39:"253637925905658982372489538655726599363";s:1:"g";s:39:"149864317488110155844324751701060009647";}i:89;a:2:{s:1:"p";s:39:"279412238023962995721371699198188829207";s:1:"g";s:39:"155598915764501153026223926768958705767";}i:90;a:2:{s:1:"p";s:39:"304106342193803880773594320966748339927";s:1:"g";s:38:"92322047090452031206421560601306928951";}i:91;a:2:{s:1:"p";s:39:"322913290480087002459462604003828469603";s:1:"g";s:38:"92524856578633519411437518532800131563";}i:92;a:2:{s:1:"p";s:39:"277089057388309352780642604697631788919";s:1:"g";s:39:"105249705735663037159358894119941901753";}i:93;a:2:{s:1:"p";s:39:"280236513995939039844557210758532708147";s:1:"g";s:39:"158306374689206241016162477506012836773";}i:94;a:2:{s:1:"p";s:39:"234719020513353193747658715815920552619";s:1:"g";s:38:"91223745999232718078741004083061517243";}i:95;a:2:{s:1:"p";s:39:"209990000707927251175406243525264022623";s:1:"g";s:39:"125642114179469428756488157507005128403";}i:96;a:2:{s:1:"p";s:39:"275737100760368939576948745650805280043";s:1:"g";s:39:"167145628416726604176821531341460996895";}i:97;a:2:{s:1:"p";s:39:"213783951740539117048794197148144657227";s:1:"g";s:39:"109417094981752227864776346864591549789";}i:98;a:2:{s:1:"p";s:39:"318677936852074604097023986317860558759";s:1:"g";s:39:"115037656438911641363193487524231340943";}i:99;a:2:{s:1:"p";s:39:"222750162478363691468158822602615735239";s:1:"g";s:39:"113556306002604103800443505592028066063";}i:100;a:2:{s:1:"p";s:39:"239051669069722927531642869778838542343";s:1:"g";s:39:"159620246209558910663028687970469241585";}i:101;a:2:{s:1:"p";s:39:"308867039809658627190349828399950839963";s:1:"g";s:39:"111777033404344242825393328519333723859";}i:102;a:2:{s:1:"p";s:39:"191578329058918619482978110290472855563";s:1:"g";s:38:"96920536616578690169019365830583899443";}i:103;a:2:{s:1:"p";s:39:"325447228570210752496684536118034998379";s:1:"g";s:39:"129437827816980982882065741607934187687";}i:104;a:2:{s:1:"p";s:39:"199496827021205922362423961503975322443";s:1:"g";s:38:"95449372423705665601914584672984436985";}i:105;a:2:{s:1:"p";s:39:"238204010443217252139505257991989127187";s:1:"g";s:38:"91317591567351091929487842436160672987";}i:106;a:2:{s:1:"p";s:39:"210575582741342359714046308724434638407";s:1:"g";s:39:"142543190721741958237717199151161265865";}i:107;a:2:{s:1:"p";s:39:"193835921830776847504350847922101912943";s:1:"g";s:39:"151813485796154943234684032504099327579";}i:108;a:2:{s:1:"p";s:39:"178427490906676735864591330886670926819";s:1:"g";s:39:"146413567376325921761866049795179195397";}i:109;a:2:{s:1:"p";s:39:"299716072306325255352875980371073738499";s:1:"g";s:39:"157210887501582163921135958059988460769";}i:110;a:2:{s:1:"p";s:39:"174501134484857074197927837838115864819";s:1:"g";s:39:"146752211101339794211955770327266075471";}i:111;a:2:{s:1:"p";s:39:"263141644198405815082265954631245057027";s:1:"g";s:38:"89010976094266637055743371326639574349";}i:112;a:2:{s:1:"p";s:39:"176466451619066725947852784079425521863";s:1:"g";s:39:"152509734985991674456496918102451358687";}i:113;a:2:{s:1:"p";s:39:"292682206572230534435344520034906633599";s:1:"g";s:39:"142874105165878163065284219612333009551";}i:114;a:2:{s:1:"p";s:39:"201328074386089494127672485138355071347";s:1:"g";s:39:"139056812479572385637122227340971141837";}i:115;a:2:{s:1:"p";s:39:"229826790296235981066004577347766874047";s:1:"g";s:39:"124485556392824999787963979933226961505";}i:116;a:2:{s:1:"p";s:39:"332795007680636342427162437048877824483";s:1:"g";s:39:"132371062218285402701784934167045475545";}i:117;a:2:{s:1:"p";s:39:"264128365565511611517695773592609678303";s:1:"g";s:39:"114615254022882630385756450073964824147";}i:118;a:2:{s:1:"p";s:39:"268698717748706869710939835298615927267";s:1:"g";s:39:"117152896705025823674979508347665141611";}i:119;a:2:{s:1:"p";s:39:"302105198709942553044124021979667091103";s:1:"g";s:39:"115210049253772003791162765412858545515";}i:120;a:2:{s:1:"p";s:39:"244101232788334692748605391991798485199";s:1:"g";s:39:"106653638158862023536690078428324579011";}i:121;a:2:{s:1:"p";s:39:"230273108057481536883566583583109559023";s:1:"g";s:39:"100481439316995264801026403022097167371";}i:122;a:2:{s:1:"p";s:39:"322984349144126882101119659857800338459";s:1:"g";s:39:"159007973907722446137944813244793447289";}i:123;a:2:{s:1:"p";s:39:"336551506278300215412128472087071431523";s:1:"g";s:38:"94575518869614444784555444648323179985";}i:124;a:2:{s:1:"p";s:39:"325853084786159562250150213907913293147";s:1:"g";s:39:"165854802536055673479990720116207791091";}i:125;a:2:{s:1:"p";s:39:"267169176591038828428461564163619391419";s:1:"g";s:39:"156305369077672218039563577497885459563";}i:126;a:2:{s:1:"p";s:39:"239647394471266396711562577661521640079";s:1:"g";s:39:"135150945658333061448039765686757664557";}i:127;a:2:{s:1:"p";s:39:"310272220468352202006936575621174675363";s:1:"g";s:39:"149183267477594191196034583076725103145";}i:128;a:2:{s:1:"p";s:39:"282045133469485047888914986480632943019";s:1:"g";s:39:"125711764274064417833132422105222333643";}i:129;a:2:{s:1:"p";s:39:"234599771405208353221227496890421334027";s:1:"g";s:39:"114241200628618711658613583227486232613";}i:130;a:2:{s:1:"p";s:39:"228152795513450511034942449472495573367";s:1:"g";s:39:"168398706283838543234401695778589281927";}i:131;a:2:{s:1:"p";s:39:"212097593073542307065347538486191261919";s:1:"g";s:39:"149940368580113076918890078852679018041";}i:132;a:2:{s:1:"p";s:39:"297412983264745482861745631486523413147";s:1:"g";s:39:"125354297262324596636132561377813415813";}i:133;a:2:{s:1:"p";s:39:"294153649598454137023569177048904340663";s:1:"g";s:39:"119618232671986101725255082853317991993";}i:134;a:2:{s:1:"p";s:39:"175487816341984471056566550210858970703";s:1:"g";s:39:"140601690952468213621103178853863520569";}i:135;a:2:{s:1:"p";s:39:"176180359739294489581394694681108500843";s:1:"g";s:38:"98077114592993318593790787139676895321";}i:136;a:2:{s:1:"p";s:39:"279572267891227674183294094072204319543";s:1:"g";s:39:"141474017873114223498048340610357082035";}i:137;a:2:{s:1:"p";s:39:"239629442130765299778978223853239788839";s:1:"g";s:38:"88754684643523546470289505769224285729";}i:138;a:2:{s:1:"p";s:39:"311261240312331479969447936407219323047";s:1:"g";s:39:"151343131310288676643199151763364576911";}i:139;a:2:{s:1:"p";s:39:"273396005392900911093204799067494731419";s:1:"g";s:39:"106778038879588069377890944288814468931";}i:140;a:2:{s:1:"p";s:39:"261721287666608603538123341686220061467";s:1:"g";s:39:"138711968008728462202723866189802040861";}i:141;a:2:{s:1:"p";s:39:"215937395349495995166858415892962367759";s:1:"g";s:39:"155398583112088458001793075753882872685";}i:142;a:2:{s:1:"p";s:39:"212936571128682845071308878878059010067";s:1:"g";s:39:"101442737521645273653232103903447910079";}i:143;a:2:{s:1:"p";s:39:"298838175786452844147867416306769452987";s:1:"g";s:39:"160565315644879191178274475105507742033";}i:144;a:2:{s:1:"p";s:39:"316176852999320912845222134672775131119";s:1:"g";s:38:"87523304206694080898971766076264143747";}i:145;a:2:{s:1:"p";s:39:"202013126308834551658071627160007872163";s:1:"g";s:38:"91110917788528883796996360661218204029";}i:146;a:2:{s:1:"p";s:39:"310457373590695815028028265615601682987";s:1:"g";s:39:"164392575017790858253925716306682762491";}i:147;a:2:{s:1:"p";s:39:"233494437113899933858624559487545643707";s:1:"g";s:39:"147087009669715116027793726225269012183";}i:148;a:2:{s:1:"p";s:39:"175158366760549586270815259855245814027";s:1:"g";s:39:"137880202528675896604634215375162273381";}i:149;a:2:{s:1:"p";s:39:"200440310559660779805280958200078988363";s:1:"g";s:39:"142805624090912627846213953550472112815";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/1536.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/1536.dhp new file mode 100644 index 0000000..38ba414 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/1536.dhp @@ -0,0 +1 @@ +a:30:{i:0;a:2:{s:1:"p";s:463:"1484321112960587045156307044653452978091514252781732555377115872744370782753532223710520596651771862094580430622810781137079954026654443009773353316487869110581614335387257791372300366363986959520162727301094381504710539122423215449953773749566665075390663795515064927524541364929410161593571002665960511042368404720007227185351442857133729332461681414076545413251514012799785726764386304857603161524569772320497781834398411353556378812114248426854017223765792447";s:1:"g";s:462:"635774037287666756005286201992926844882049694229071109060527214859683349345634244908520777317972311779819169417124227454944478231493944538362566784762524159848118679198133615209134587519203999139059358147991164119330583496102138414754471736404205776201609984433151539366053179678590829297151308903314368108491194375955538280261511309639674764255718253005505707839857874962943779665415343296052187866967481027372096404738753403721555758189272826817559193637462120";}i:1;a:2:{s:1:"p";s:463:"1319436802072744870627529725982335407106255106838769259080484192948822006093801447135658971621913672383780818570900869846109477900474351617379125755158877287287443914503331845436479622427887788221295041360592939442869830231851542580082543738933690647798111929121232075109013051084277527846507106765265691741993543124300304586965031520186535035306131873674243292213566694074549356897012038902793605597813873772107032094774604447038888760851123996389333697066500089";s:1:"g";s:463:"1094948501651870927866408997875807332362132368280764746635102906522376980935616408160803921204390676267735235340675683774918584046129467358536658452112779035005246945500990564970828900915876183847784477372105600610181992912866134280979202520819598729274804910027149270482786962118597828865094775152221808068814764597063219931910461862798242682996856821691502783024562237507266046103319637879315130332069878279043189748255613212869917119499585630902196048518389141";}i:2;a:2:{s:1:"p";s:463:"1640222121300873590885740903711612856053216234718072467371799710030209040805232294429104366467106949818620126839460635110688960840211274066511897330827987110967763711157204318410155927749323139656115284192624456851102305115967064988358305606231181648345630705027165974291804661428533435957993527621517312013100947564241032286994712995946793397929587066127500563005307122895245755325339947878136458621529441597532795180908459053645027157995663081045092178737236951";s:1:"g";s:463:"1091699155014785793699927849492118315207217763778609939374849137247626111244977609635966506015908867479947153952351409289738203198557207594461117445750302094758880324908956395448076571856589921995881773374725119459511313687786646810555589375887009649909789659937861969554238484131951359065310736811264948846669566484058857698917573131819117850621387652382598432460267007035050505884971612126049437914803225531487958278531161911691953811685277239553704185614100254";}i:3;a:2:{s:1:"p";s:463:"2042201993843598159468568251727021381151204860153180105899105583856572114957522535810934397491695695827381512620409599315961608902985092050021488412358853723928122649403442200573138328100885455439417892396869322127744220101094644670053440714135390977909178803486242950685670919693087337352955059110458693240470974292348857021512713811450682539944478562513964203257401079664973633503395515416018593081165879055440039280270143172237165005252136496925734559160180063";s:1:"g";s:463:"1500442284667586192076348842045301367167296162953592222959388230854684580797148712288866802146615945078966804943095812267797017849054865779802801614224624014374538152627740263805739007646764205976963263146061122561909911419750642286362084298710720418238017005026967541716370169549583274076872905500601850314761635440475203807971054187862037414097487067989205898779614632989928913601024677346758843158175861275923151746018118718105464617356557647207655221747328074";}i:4;a:2:{s:1:"p";s:463:"1637153014024763059444878705223203780681858093138911571751979728838657707993054069819608775778753857062986551340167861371895956608008303443247254570296681365466843835598991865198789305509785381105738587250553832156097575877088631555130354903285869176634617910439198251693833897364578795592212671604970740451504483168483241814403323016500573560687048758004696815940230413780398956047311381874244761196793125330727878608765576917373701666692053785475387091211014381";s:1:"g";s:462:"253146196079304316266434733768872749372301038198365665590883109674350222564840862236916235404732761220504241323463873735246003784699325498867656640778717821729675220766842521488720124623809011690475912948904742512957103216664404537195645503873467006909218174832003149223675383918994291709588651481979088751673955939897523459289418812245730766260986806015360755507568343631994201583412347069821756072284985530614961162489684943738005917848451625837740216654238218";}i:5;a:2:{s:1:"p";s:463:"1219739395129421980986817581093875899847343408305888101989901813253982523812274106436433323689615865668476392367734814970480804904428414841429633998030501300762701392560716063753422306285174523408337113228268818879405961220480195573703497617321463271891741904278861642257906422159298231098658985526457662170038010292931860549511504497994128931079950747868651823087004354747165956919277426382129565650723679401668983210698395935172256570765605609849286691377452069";s:1:"g";s:462:"170749392644970811287030749108243672722681483625922470846523134882486580425232339780276174257909030458715830716692588702557598044687908844893420066097048011582288383239010520033914489804041483203577102579487035826567669554277956785062140672417410620876815360564263566630149415924467405717903800222598776815469568149017143892771598944636450610659476217733997741232959262233276018211413849373069396149673782042636144584577674185171593340362723828343131348119216530";}i:6;a:2:{s:1:"p";s:463:"1823795465713565701278315869400723495457475261130852713977770426795435140015065407392713025910005837170602206359208592843713477109036614911956946724377495049413103985503099433241790626512151502197550302263168341159195533492294383405632570116732818018836333704092194728943213064115454736812855110357810165024286142395540987558177053133376862609281101196043894433574854253390690930850852001602168837076660408735360137300780178764720747999733920473649502672753029133";s:1:"g";s:463:"1442839829947671234369496200676072588081612459677607985530300351859499357749262146238588298044263018187404783155947200807580123587074809026438733937831837276863552797962633391437862262487983073076526197006774206392599749277196760629805690702748736444555470229978387347874033267703600471989608673950742255064321002547976555706582185670106509022326628674460174579619942903604626192360640005219137811717889441546118271454105656302351748483598142884252491906462551344";}i:7;a:2:{s:1:"p";s:463:"2330987243466161089189453913980054878244548203271516593454871586865008572865835925509538466874454336703982083570636604988092181165159923670888163875699666429239768275554084525673152372358619029724159564367314059390020704727416486501641650913127442368735560126459032806262580912363799758293882503234653435264501039310901361922396293916077012477020084343090921096158915280800532439667442662661436491373212982496729726298927418474654567058464055252208378074662306911";s:1:"g";s:462:"386680618508384973423672062850508522397135947113284374965100744322646472653484962944409055998358573494424314461090206662182780860368561763485570382561152186069945568506098043823478071525306398614029486640941099890329530883797789468233801063149372300345673355594678489190792290553970578096255571413645141468699974372196819473802551597223213318243705334542362861643744710123296535080834831744256642683094762389663106543125584931608216839951706680087663895979524043";}i:8;a:2:{s:1:"p";s:463:"1262620669861477839190844459069625161157458691447808343984704184159371136895931239924491606146944991489400086233879378957339498118133191256004545753457451547013077389884363597994672087814969621667075874313137230455646979150907696693252095577556652543710779314562280787859056548289029664793556128094449637512640549596088042279135346001711726938677020098004905539793932511494769831294545941118419853855421666428039455145569228072097189891576088267457892585617327537";s:1:"g";s:462:"526663796116646673994851998981201669178713058539445963858436667089710552476905374236164705691170375947481081607610541303274006827378957464313549841097789508218946402515689199903038313446510101310473849351954858966871650717674123149287955406174093369789719324626912240862929635523839987379204148425806480078269046549263204392631011143098816027493919238398815279095074992826115644273740497748876160953621171789407359553722390062142143510560327171403556962711579228";}i:9;a:2:{s:1:"p";s:463:"1802806247618212052847139445190286650067259060192535756510698193625342451183591635366213416695234519378646880682633767718314783369603831326194387419926531041225952412795286571196321300818787263025582858179591437678991886851088704122896117267126236018088255041959547292291014433680944304432469776645236818313507336442478521079624340532244747798364495759367518444452373370920933200025543833730541849004863942871483124484895889874086358389451367377636915283155601279";s:1:"g";s:463:"1284641594416543525662036145628946288335762230298381205343844315244784563257207376136770309765261982199619179919538857693102793738277562060812035117250208559853314039706519792948991125592723028835849628618414032901893842763449637332613735729524022145278901762445067158581783058804762286976909689060845327084055603617159850945703843763012315352891860697254579455882005066597307381839438396573376674188203126522446102248606816032797012113930789171978183813977343611";}i:10;a:2:{s:1:"p";s:463:"1582811987242397018030371731694457345235827088681427679697116889089464714688234072738746320838265451104885880125066461941990856320096604611671565283402794876779139028522997427206721007041029858890516120432680771700972923994634541796145230018505355925572838476051871410554406298275632980176315170349424989011480109942413662675414441427096441297934858425355818410353360190492203797797818306162889687552448049037239909742012439530936824490474509059846737144151122589";s:1:"g";s:462:"904005487385713022379621349592992471612880301537581879253733082184761289667473824498027399895869972592947693035054381286316769789684527733801483110012752797833748591601744372689718751357647506175043276817062912956835261917728246198019654354323587119778378183866021920352464303862458402855590059151030218669892369596629436855331014343306882939528512800958166479957444885999360235000004595914301695408522151397314039624683984435249704259386328592373210860823431745";}i:11;a:2:{s:1:"p";s:463:"1751567140177216355913464714923925382303386077987286661087016520920361085694926448713658621586777889815549014628902654175565156184204401359255645222938554308180406673877599066706797648397605589808600115965605825074379462812206558724269393890032645033281680588349893461463965184465169874061908663284055226215854545962327006625887546931982197079318292414797922218674375886474872777173052121315637184932090274167091399081333368914449195411820479987084002907490075763";s:1:"g";s:463:"1728933896829190229135447673930534573193230270896317083457020113596793657167810111090059614779411353579891050636265959009334790354242367021222694211284484143733427402392439443059568114957827430341392137236643159465739007046315676182953770441979720779755837087984309128307509317093013153746661996696823485906207481328520018097291489862365101433457635101786564648836715943624165952560449579601292473841876104693571448114740692851519203213185026138219553941381566465";}i:12;a:2:{s:1:"p";s:463:"2151630423012647537844703576294810579565336708199678266911187790505880932879424817434691270964383838946482745460110687378195032802933406049645640068316727857023948732325344487226996291312649936737107355368206848804098606231594113432864566561818799062515941354699429199159774308376691772761126331126068157104422783733539530755190226719384389650570576991103463111113686035442716666605835661122272855402177927187769060522635806443701402511727404912236646468773112033";s:1:"g";s:463:"2121000333525367470091854954993095574153670551827036751868266597572256874667759117352446133965472453043969463344538546533166991278117936837955676339645546669209260506924224811209384588096653947044134595805874397580120514968802999183663119396415206905026521518610277469511452527761346355780035751949172413793085089893406122320590054677391074249022019433205414681586553029386620571667778599880374927413315499007958756221913701138872501077944472074702822713887024468";}i:13;a:2:{s:1:"p";s:463:"2205070084150365578520443567286113338063494441182286711879349386447420617550082998305163124583124659968411565696253507239750319335503844156433325217320099646707812531275013377115385880286002737298380907436927575080574058027459561347795249533536110306336676674626272337164368057238635634936325623385295555008743962525297432660594530824633717776372520550493992724995773138869871133949848960548326013413861077038851781317075929760883962338374431825689935375843218653";s:1:"g";s:463:"2164986491453150181997307394732315140614298464027330379977238121790004601675170871987978031576748094029228652746235016225704766983618671573830403937213847957627426849730795717992909097124266785777500451244045698059566929616174668460223079201751303173880459434689685322490463699023678343346462747706418014566753958287780845925077591239643442031042118280194530297714211983675755199763003168178308438929299250986345700682377534935196768002884135000786173463676024879";}i:14;a:2:{s:1:"p";s:463:"1521251664255354648387650579429147645003851430901308819073432965199333067089633939765298667366222286385404882515876653909529252398129005889801425507724811977996173982929147187904902391198280960871297119665598540835597034200064446205943817755106610845073388515419027205081211825491636302401445316595226697481153192188703355175647181368777041455082796264978831047550011469827974208535580950629540118699486070742792447196201207794623773356284583460065990997086238511";s:1:"g";s:462:"965193605452145797059670328874441819155298622619297053175552499937680640644666445940944882855932307148639941581084597423672394906108044956969878533384135603691286438773265879206361085382287378400275018398045193374212541331042637252930194708676430354898774667565187596063250380298789522845687589570438674857628002717877707884455323523299181393442629310322092655889918930430566295027767644067297428030033271832881357044821777678830457933953075655243142288927175592";}i:15;a:2:{s:1:"p";s:463:"2359088529688849695976172882354276186572333793676129238480483310356338119512834416470889516824103143013456265231779354325107949482185103514573493123174776224113354923823459005285100692068081219492746850787514937711005894611615247331157020496376924834185574122667041507752735016917771570908300383091007334114696800556196459897399050681446783294994048701546990851161672721128777031448669634022236634171162072443925053239893879803599386757951784662290977479728876099";s:1:"g";s:462:"531712821169676924995279008450573863171422718303644923801999592407585710289327315712811203262677550193268920385621678284963439199695456438890216930330152156118253891030820312933931857809080143365111231914817537856093519081740430912993465432826979612678871678391441229601885573783843423731588207120032647787887396014960941864835572694180911866701771212825132326338693544497332820354308355809281971835819585009137470469515712697555045631883330889364226786485235267";}i:16;a:2:{s:1:"p";s:463:"2263415250426790488990021998541593923985939453932066947986968571160941622802612177769141891039473489070175302867802751596946353154172125528234191468643981304299429091395959809710836541720420021923806062020453686237371369098960991935904732896776305367149806546520869591216966307337101655332797619207182444936519569732492987788087886323058898445366441139143155332695122745405143154390717222686607255170420221316368625610824961565878490680157211889540793859511314029";s:1:"g";s:463:"1592300040248123484343304872412609674278233000042429776065779160677830870546995470357954916165832640025797321967048755775627713204352714564717585266051163773689777402235485084734939182825652015026616241954245365070589307618851173791011445842933302480677887284019554610611546717089545421534402349743077171151964768597699449831915488170530900787436161510470323524667270065908642393725707849007244393660272712704257485664362080753091384435793689644134869046685439697";}i:17;a:2:{s:1:"p";s:463:"2140021758751023276840079207042484968828483938990224910948092870606013654041680930240672408316776269908489537157093230523921913791933713307571209743090663930053524182963000614494056181878721267909181559101467357866435493815183307483633613451238642152941855619490861935672760757676221198639329013244377526408249320935076623838134966951658604802937666471551992167087938734246741266040666007877163204679608400933144213094457105599599278002366948889603083533991484951";s:1:"g";s:463:"1100233131056620948296063080261400071657894915014156851614190078061725775652724042802252052520540922949797249690960522349654067595799262331593777556819278792085357168985669988636673921131639681240048032250759952721270517316659925423462247942806786822053233647319893585509026604836599081906066169311006342005206909012755218672694523070884738297514453530775609726869693934264786610643627147185023994300750387486846804192790799167713142235625081920945676492185259837";}i:18;a:2:{s:1:"p";s:463:"1551038949501222691978272893261175182106190568814977369412264479269203984617935284649271672983221996009702717185850835368097716239680362427876850240608711832907992991904207080846078476339794107796679682792702952426396050690103152939322069717802959355097917068461854377217432372587859666863879175341220281173708131767332774632477155184400678077766817498132455212226304905057355970071577431782390842748315762830917398894909591248369951918144444569327038256791412189";s:1:"g";s:463:"1122743139630282153879868251492800292369119837055724070863937958954275141004659287445630535750518696420133153588928570581644864109649651087502307048496388930886123022314248669533791822102495449596897585018024718364807118889886919617488854825417330211828450024519870873403366339898166468075791590348995064663082411049461483459672090493049746342023873181820458364596806245316113771672923399540575780554223789112003339156911840140412416044701352663673472942552084352";}i:19;a:2:{s:1:"p";s:463:"1356275386127542659017850102084213162793783886645454180765334717833233223399711893326242349980495053147731601929882665213599239957578370346016474113462672990475517633062742504791277452523124568556338228152297085410743499668547067578837155876739204833738979418284421167514815201003427454456488029773197444587939264563226841204796270250197007137759631209198185435416640354634993592234914740333637656688867749691551325073441320772525747422461099343214212606226782837";s:1:"g";s:462:"196158088095289507282635289372105179799925532380890601501328888911791240059921911676135260880026187732965333332154750913555772522540516226362849912153957919289972463443703634672828466780953764986723451520741685547186167518702308476173818830280887990050604198896217462931059031114540897431967632771864183496847755209674316498138796078477827464190973060848610335479452576965859000719469049864951119151409590349552233657722495217934957865156668731479214259056401619";}i:20;a:2:{s:1:"p";s:463:"1791472286915428465800935822692265439238355517646096021981341373610022332512685662672947071726756151791966985572565143427965511257073988222706151587711707922926145814850587537844646412281461515307166194779513849936528281689522221763047607949743506742487857989673563402712460260035284340298722075617413469890846240032571221443912374997991636958525327747208883933428540123519800669703170185597472417427612584127771897699916422137284895495208176450975703263813324361";s:1:"g";s:462:"812472889838316626876044476525910659797355846637807902006476703903476420879104141089450116597850471591854168698938145448631879864081920890692042259147592692842192344636910396472895957516670523402513152790835262569312900065055814220909837365727450527054620162030353510549825571076047117901301818937913974245991960708251362745962177597540916436370662595856237213188011429189642229756130467882589450794829062521138060916740805890466164921142302272783761185243603093";}i:21;a:2:{s:1:"p";s:463:"1366833399447889457775990207973615802619259554875634153621347812296968814287533898166660206284964915570047939236738102337370803059310419972815705036689363773719211310818018266452632959459163662445386701608870658012250012908275516846937941749608216814626236706133229312021626209945109912604144285299956864973471892748876868743616995712656203256727782738514688441353283479027877383331448042965099734616412228147115211289999408629682850400139227689027478749749643129";s:1:"g";s:462:"907557415940991513285090149273768674738060366453456203997124609929673130784634611327985434585529146305092377176336004581435837526756015176571782139094736301097343760037832143538056782557460948471665233952196990668005720646728143894341643654773015046788101057446846122595778433416647442456793837598177060389929898700066416155469357326609097459960392457609590714208063472803992682255477495194457805322420281681213623504075777095465460597665129371748683785603721006";}i:22;a:2:{s:1:"p";s:463:"2235728210829391857071877580387511359891390738738547942772210596588328209288888619866661081922620605650811252760893976945841607232634557684199493942964002252162424504613619431329645308417700225310454244837374950644090517139907683618729560064949837356919805580405898545089057377346475412311999128342123657940599847558896191574146322896441284187120358475517988223178353246518708051100480174846708707357073697915628723229994725004763047252056120943361187825791150229";s:1:"g";s:462:"637312041409355177411974853221109947515744101798389146528774548932214498916777092630192887092630101160548857054003728871186609001785761461978704016797748424302136028903368917925007154954833444321746626415766303651171977419175936950344617277881927411604172961404838392604376361557623813071848677171881812344396160401179223323005436600038362498640753349274380695107444847658991166255571478370115034110598577092991547493707110073804159767315333427952395510117923986";}i:23;a:2:{s:1:"p";s:463:"1230402277951024128207424741876734394235328971165405947947309299701490787264435301233695030361940893216739801304221858099834185444907555321212424523500469201287869965553274789652940874658275644861206255728959954319026799091669216522927588979607033270355519456618530483628821237748037726704478448642599776349590126053959737752737091372398004324976961760898043643776494456825641032767428880516321734928192412624057914470785381494106990379306675385876696847389286223";s:1:"g";s:462:"338337574239177317877461820340406296118689570674139174934980557907797512993831045015071764512723465929820824827380230251055682801255297225194129788221954886452049216535615519736643436909474283900148561820437578555501524700402534304860476771494314549265082281559541403101063023463350081318114948129018156823637901049100325822416263781450628275355097055535634266452391214951018991141462795558102155975109587453970354234061405806819338677858746939660250096487381222";}i:24;a:2:{s:1:"p";s:463:"1911767397217174389580635454501278451662399330679149216825063753986107516887627348972329152716670344012835523361399914204681188251842967025811126913965113226481849273439748670394027983781685504896105459795325034776516327708392082217034648247322633497779699909897101710745541317469488983418685560845904692510588194960780198750170837577339091255717698429947336017783990981810701228856804637301843263146401004874083727217362581520156327048282377140355341630648456103";s:1:"g";s:463:"1268080483672427216958224975801292383587547866099684747810305400482861740550272965009363034958263517021319762496237599899200861869592948185998662594716738084240326115111554194231937679759491622552543609081009157285370194938894887072173502498902751488787514342330471293536467270061388282245612044342368852132279034623689831591544404552563026490733134267915461931000181987531966569228462873362813573826868674356654050782457393475684373296479964951832380516920006289";}i:25;a:2:{s:1:"p";s:463:"2384935185013046067220035179863998606999812912034904502807061575246271675961542850429667517360449796538685788629608299911037304799677705521562064126448310662928476680131793925576111182979091807631918029238440547258773202993568005355415069181820061179910375968834527608205575122828826565040222250604808188617658493902058160064391648525420926805258250520000765029746606323909864960353779235018441612552606347709443678131979120380997560640005810607751789857065091451";s:1:"g";s:462:"230062907685243780452883658835151462600168821285212753199061160240952213288476497310814110927786162764424336746127033997732663996065843294573577068538063140935014911132098778420167116292666336310665075633034800774149967367198046709558691946018417849690027139977567315959230391862191299426094157615629906301773814641864682077331169324528132423969523713789011223825672691018959906797878940942325987433373308932869795904147206530299908785287056288995547797933032443";}i:26;a:2:{s:1:"p";s:463:"1663344306655279209292925933415166673010218801912608607453659111186281765127963906747334142803861207045175907185341633566803131965665187241347507240355184503320145325035527549916946203208831099788683360925692343298292440438383759779170710699485403197390947453941054427159513193680633041344238030245452902236794214288355312770188493677390972819610775968168652115902497717012047496016490638636145149167033047041445335801731491846790475339025877805955311338540934627";s:1:"g";s:463:"1348517767365160364561068532904450579389328908173180354117747600022821268147921395670753439266957892637547548008485068735206283651393859868620973098249719756384276748664816488024695266868296400105329740343009341872599721665814103616635578948648432158793708382891711073045093444826262905305696088996707838189289814208503263563885857974203581050042104854142464557342916467428964426721186094462371984492943151324037650392852237078007527006264829593973374800503511630";}i:27;a:2:{s:1:"p";s:463:"1848896919173844897115484621965301937359468417329851937907613498405516616011344671755604661971819633223199683969701205993540557973998057014209439444926623445981416341404885878413044311920287373049322289489438247126578629730258903184306797687934935350338100288227740150503007566329840870600743965247269417726969943195718972903432914079036061575699149971862372213649397422747198211710272236417380710992790034751870619005138531869354200728018277815675987411571131107";s:1:"g";s:462:"429289696470275857775530951197073972688947870516364972269559535627701213069259530612419679756895227063669544280791154240670740796327818039237257228266226324946015459066054920164656517497021576366860242621801116329987278409508133315146909097111808932821633739861288491142391412283558567587612085914476484689127470974041956005153680024608674762079992623386827477985783098347117926214711810179658634316931882010723029050458260674735096275563410284828547714615788587";}i:28;a:2:{s:1:"p";s:463:"1890627014913175910326850340749681958428380980658681063341993939499758659173497200321459369998720011914355660203102403990377765814366385664710421582183545804000705271168997410589122642202301568560127610873466167697468942968722497122944122708091225065758185048845958631514107208078217188714984825957124996155345718832704656526384220047044919842429499771982984326066654442486078088122441757917824305647778599411466539066279681960968021776697929069992812086995172789";s:1:"g";s:463:"1034169370222927208782825986578728083410858536450578282698009964268185939867622641861765948506913540342157742240963716977855562177703039976409349173614991743536434594022269319553704422130919086785254310146515389889792593033954067278811337387826083570183292948307563695335501352996895214719576396591180371565611649224388919323192934331934511203267468141351305137769380687345028766066767615175846034605155402960198555165557055819821481579985055010194120972583631597";}i:29;a:2:{s:1:"p";s:463:"1353376715698694849416351054567317097442253008810215280534973591952340453592336519345747889023649593465096755863361196728613726954884457107103432300908272357398779044553771760203942803845422237037780075398705912790942805326030680104878331383092211642487952263739901176183050028520343734351006071449564249238382691445895174993577066686591254578612760844748234214169371540250401278015897965301864679606231139850512645245671839049032702402176156740309810593611782337";s:1:"g";s:462:"305210523129475840536236800901702737664215769845725796264865453089967287991947101293919245527199033267819594245571745616219504679083065675697898466435089350029442525196013314642200460699909921210419450041030462063057375054885732135352452147932369599618025917306836513163880414992131359626837644091776191785661118303776333488611066656526575787363225807387004783769682322145335656768853220570786204450747084576926149782903428402575178991488369822354375043423248544";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/160.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/160.dhp new file mode 100644 index 0000000..b038571 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/160.dhp @@ -0,0 +1 @@ +a:100:{i:0;a:2:{s:1:"p";s:49:"1305369760393067573903784608000086685092429430939";s:1:"g";s:48:"474563639061072388724737904946142937816029120423";}i:1;a:2:{s:1:"p";s:49:"1144635340808941051501659871557102316521726101183";s:1:"g";s:48:"619759652154730913011023153136163766014870982079";}i:2;a:2:{s:1:"p";s:48:"988955281135516012494592134176727394285740835259";s:1:"g";s:48:"661721534235998300528018590812024177782995358121";}i:3;a:2:{s:1:"p";s:48:"831054466535764214539847067184849497020622445943";s:1:"g";s:48:"602568635360210647114201968475098190709943951119";}i:4;a:2:{s:1:"p";s:49:"1273451162499824010415840310357006535387759756083";s:1:"g";s:48:"388940627425287673610018679790118209342077054037";}i:5;a:2:{s:1:"p";s:49:"1194158228146097682568743682506593014684819848887";s:1:"g";s:48:"580787644966973602366617775052430689914269385029";}i:6;a:2:{s:1:"p";s:49:"1250825835634860199205277909400801107314922391847";s:1:"g";s:48:"581587982876966650518121867963233577479897748201";}i:7;a:2:{s:1:"p";s:49:"1133337270744463694484988529020735933451408606039";s:1:"g";s:48:"631442441351111432384530483916287036387111747321";}i:8;a:2:{s:1:"p";s:48:"804221707628161205330927629041516333589063181087";s:1:"g";s:48:"631006589253137060927543237371342862321104607941";}i:9;a:2:{s:1:"p";s:49:"1002191724199846857337324294157355803232206888867";s:1:"g";s:48:"483655550172758115887335144054596363427233334927";}i:10;a:2:{s:1:"p";s:49:"1394184516879107196137044604429830692800149361183";s:1:"g";s:48:"683437286820195951723981107586029551808106506279";}i:11;a:2:{s:1:"p";s:48:"961405043336466250012279555201953463057072208663";s:1:"g";s:48:"548079459627278793375356546007540397027073822501";}i:12;a:2:{s:1:"p";s:49:"1386832263378811893090905015568465530933732830547";s:1:"g";s:48:"604192202606404180885679845081675292033551734613";}i:13;a:2:{s:1:"p";s:48:"783786288502740985223534835310606558783982116919";s:1:"g";s:48:"500926370623902489501579323312356666918032852369";}i:14;a:2:{s:1:"p";s:48:"782621235048592548743271821187900290544473673119";s:1:"g";s:48:"596692264293782688278359189116397439489932369599";}i:15;a:2:{s:1:"p";s:49:"1367746360017583392658813834721766340000578997379";s:1:"g";s:48:"538797978419712469408715343382303371532760124217";}i:16;a:2:{s:1:"p";s:49:"1135354155681947332382326494639504774124357656419";s:1:"g";s:48:"602214275291935588667865684153452385069344891247";}i:17;a:2:{s:1:"p";s:48:"790833869591119782666903580768794672968217564203";s:1:"g";s:48:"584158672869014766593166474252578740731182247631";}i:18;a:2:{s:1:"p";s:49:"1097291211491744018366481025948305908720865493439";s:1:"g";s:48:"439509359160916576695841620747699133810064517915";}i:19;a:2:{s:1:"p";s:48:"918692550503510060358872429607147446953066891283";s:1:"g";s:48:"654945249942805992787768128395123781115962625817";}i:20;a:2:{s:1:"p";s:49:"1332092254872377835477605844037036203458943086819";s:1:"g";s:48:"423679953504051996511091129522726961838960898025";}i:21;a:2:{s:1:"p";s:48:"933877274777927890528040884397656631578329276887";s:1:"g";s:48:"608217136583914041823260551340788541238317810097";}i:22;a:2:{s:1:"p";s:48:"859725203063513692512603341846423987592762126743";s:1:"g";s:48:"440919501974522445512311709528159976986712491187";}i:23;a:2:{s:1:"p";s:48:"837664251768125986868150132183481466127924307047";s:1:"g";s:48:"555285975589793727593496223597124870607008893367";}i:24;a:2:{s:1:"p";s:49:"1327569384563655583886043185949541133884438458323";s:1:"g";s:48:"613130346337979086911714027415445562125235878865";}i:25;a:2:{s:1:"p";s:49:"1428411692032230775295758088618237721277667517983";s:1:"g";s:48:"535225122050760327826451080434600817792628009249";}i:26;a:2:{s:1:"p";s:49:"1223896787241177872573145930611964429377687205323";s:1:"g";s:48:"595494123131028191906314657449402679736765235803";}i:27;a:2:{s:1:"p";s:49:"1086048631695619847613317770068005258168656629899";s:1:"g";s:48:"572284264033707549413957863779727001669628388815";}i:28;a:2:{s:1:"p";s:48:"822022638232373521110350304334064578294406009867";s:1:"g";s:48:"657635385587761135663653068076150080262596376919";}i:29;a:2:{s:1:"p";s:48:"874932399873633702319139314690832967223336821143";s:1:"g";s:48:"599534542056608408276116956516745768064851371255";}i:30;a:2:{s:1:"p";s:48:"843427967333716318343697147670009659629329073039";s:1:"g";s:48:"535889566902096730048601747743521871868718255559";}i:31;a:2:{s:1:"p";s:49:"1024009511101153299776517092199472217626850026127";s:1:"g";s:48:"466596086730216509212034465709587270534916154537";}i:32;a:2:{s:1:"p";s:49:"1320980696430805902000359363849168914081628941619";s:1:"g";s:48:"610718039359114569724584449995403893298609474271";}i:33;a:2:{s:1:"p";s:49:"1092432640209269431497453399910526986961082646847";s:1:"g";s:48:"463049212539097020105319388432709824833485998251";}i:34;a:2:{s:1:"p";s:49:"1379609959417773161390936687752808731631732084783";s:1:"g";s:48:"523798400483215508398847538082598935117370208797";}i:35;a:2:{s:1:"p";s:48:"921078024075785201943929096178126751669361769839";s:1:"g";s:48:"490512063141551178776615087664624573070816149093";}i:36;a:2:{s:1:"p";s:48:"989183702275163955646438143208065558843002781563";s:1:"g";s:48:"634089170820543168467541507246098164427596903717";}i:37;a:2:{s:1:"p";s:49:"1275967997029234336396643206755914224132707033899";s:1:"g";s:48:"640788943520119214196146942744877589585775435683";}i:38;a:2:{s:1:"p";s:48:"931840992701647448146789164397900838241044885903";s:1:"g";s:48:"534315128594159356486413265871709172887173141369";}i:39;a:2:{s:1:"p";s:48:"942069618564062766077167557363733874684068976927";s:1:"g";s:48:"485898747279783894692037240129360297792095013363";}i:40;a:2:{s:1:"p";s:49:"1001789339197699052355670128971121065627297992007";s:1:"g";s:48:"595155718255698292695322354602201327756898470131";}i:41;a:2:{s:1:"p";s:49:"1375600571680089498740013276064864072342162854983";s:1:"g";s:48:"498415279224520972219426394139746930392949512579";}i:42;a:2:{s:1:"p";s:49:"1303779257813293468830624797057168306311850997203";s:1:"g";s:48:"403451059131446434613889922097963893429478142833";}i:43;a:2:{s:1:"p";s:48:"800005908639641965569689452284039674108265369227";s:1:"g";s:48:"402323816163796613170618111976343104099001279247";}i:44;a:2:{s:1:"p";s:48:"844583281698326903788926899664249893532888110447";s:1:"g";s:48:"517528430635008553688766531790077155586957536869";}i:45;a:2:{s:1:"p";s:49:"1094285529414095396966242208681559809227871496263";s:1:"g";s:48:"551358249287881329263799188692784095718943179907";}i:46;a:2:{s:1:"p";s:48:"983660711222388249045315062345897636170761443663";s:1:"g";s:48:"530552213889630252659015358537515844230369285207";}i:47;a:2:{s:1:"p";s:49:"1351013775227766136479340311908217998210575835363";s:1:"g";s:48:"610369552440185821513978440751416631043249970137";}i:48;a:2:{s:1:"p";s:49:"1354563829742534304843697230885200452462665538439";s:1:"g";s:48:"406800662086513110930754334679064364192661267367";}i:49;a:2:{s:1:"p";s:49:"1398563347597624601077663460163417305420541555143";s:1:"g";s:48:"619655395370666441364849115839740936961386486543";}i:50;a:2:{s:1:"p";s:49:"1387517700339083788987800628137655557973366876907";s:1:"g";s:48:"538444384733151203412364008770185341348899980491";}i:51;a:2:{s:1:"p";s:48:"846173836479196853651659824753744331267546831199";s:1:"g";s:48:"650935589280629646805939830602148789608779985997";}i:52;a:2:{s:1:"p";s:48:"798285016588165120883258650093433041877186987219";s:1:"g";s:48:"441529709876893173588604889016439199867969459331";}i:53;a:2:{s:1:"p";s:48:"809397346401439086740185140566814806808684379967";s:1:"g";s:48:"538236957911425614153489245348547397710621101513";}i:54;a:2:{s:1:"p";s:48:"809952999200455191901540837089805778142345835223";s:1:"g";s:48:"487385441754309571397412911571477016204651475301";}i:55;a:2:{s:1:"p";s:49:"1237709265001243211076717714981240635777036971019";s:1:"g";s:48:"618784272482379871992008983619376563093070592813";}i:56;a:2:{s:1:"p";s:49:"1025700231883796313398360726901170861727266024483";s:1:"g";s:48:"598151296213247324217168913027595200303295217225";}i:57;a:2:{s:1:"p";s:48:"793327128551442023767444463890995300870522218687";s:1:"g";s:48:"539794565569805340039859573323545355484274999091";}i:58;a:2:{s:1:"p";s:49:"1147402390250712399306262523075499402015636746759";s:1:"g";s:48:"626507572659492347430889119427988244627761972155";}i:59;a:2:{s:1:"p";s:48:"757314137648932572630417643460920752998094447203";s:1:"g";s:48:"529283349041682923530633778652165533595093720655";}i:60;a:2:{s:1:"p";s:49:"1361950860510200593841383238144379709182596697347";s:1:"g";s:48:"584714604603156245090438264122564252115723640809";}i:61;a:2:{s:1:"p";s:48:"776225946963506180259175310291119749813149477423";s:1:"g";s:48:"383570041528464505301304825748078346935105119677";}i:62;a:2:{s:1:"p";s:49:"1095615178700277152695831820099513466482620295507";s:1:"g";s:48:"539625950517641194035243952302416933336756627853";}i:63;a:2:{s:1:"p";s:49:"1347136297248479737442676121297888888430630212907";s:1:"g";s:48:"566059213942829857928591483029870033388619728299";}i:64;a:2:{s:1:"p";s:49:"1093293569259645131193126647642958931622598722387";s:1:"g";s:48:"594343997827841315653770570204548979906235062547";}i:65;a:2:{s:1:"p";s:48:"887602414535217945702184615603540100183295065747";s:1:"g";s:48:"662347294674167895627463959587876305268045160149";}i:66;a:2:{s:1:"p";s:49:"1010557038806704847526311588973776853554356024247";s:1:"g";s:48:"532893541909339954576938979713865521494468007783";}i:67;a:2:{s:1:"p";s:48:"829844939396446076032841069668619300178067878587";s:1:"g";s:48:"631998266108121979610799989316873576683309167661";}i:68;a:2:{s:1:"p";s:49:"1046494928460345758716197297416292696746658575579";s:1:"g";s:48:"615891927105300226068825732290141791815544028735";}i:69;a:2:{s:1:"p";s:48:"834135728048076165111266946917275399239031768439";s:1:"g";s:48:"389213395234196335590445606749808103986455524927";}i:70;a:2:{s:1:"p";s:49:"1154700011458848510187096294835728566622120955159";s:1:"g";s:48:"548503798393624074154942230942131583774664088813";}i:71;a:2:{s:1:"p";s:48:"978672053754186026248750553289218329620184542299";s:1:"g";s:48:"641055835629088201611166793394301543897343093531";}i:72;a:2:{s:1:"p";s:49:"1070102503643189144647061857723130426933962673999";s:1:"g";s:48:"711869563468284271638708344931033641934315745625";}i:73;a:2:{s:1:"p";s:49:"1323812811328381869130694828828061281852276002319";s:1:"g";s:48:"487053656886806410763695828754103165927486554599";}i:74;a:2:{s:1:"p";s:49:"1169329801421612423199318261807267948752947753967";s:1:"g";s:48:"408680246627811380564801297727106398902783872371";}i:75;a:2:{s:1:"p";s:49:"1384652955769809627275543328404332791741666272363";s:1:"g";s:48:"449672474457280124868466963066446412571192105159";}i:76;a:2:{s:1:"p";s:49:"1350000196205739429961458014370965793276931747667";s:1:"g";s:48:"505425622396261383117666278099826061597545042231";}i:77;a:2:{s:1:"p";s:48:"894705447065273442961638823541618192797889809703";s:1:"g";s:48:"510741338778056615339728592753920772472096642561";}i:78;a:2:{s:1:"p";s:48:"891337116692625714018605359651236312842104375007";s:1:"g";s:48:"413522626116106665014504432665726545091134259373";}i:79;a:2:{s:1:"p";s:49:"1297939713670228460811861978176871752377877828999";s:1:"g";s:48:"647298056544131270364838136232559701869206992523";}i:80;a:2:{s:1:"p";s:48:"976351259950759294642978741592083950506931483539";s:1:"g";s:48:"481165731343196004629915370853114428787031678927";}i:81;a:2:{s:1:"p";s:48:"980764218473209598929377503670805572400056847187";s:1:"g";s:48:"462874955150610793645950273938064092414395927293";}i:82;a:2:{s:1:"p";s:49:"1078402246449839832492595497686341465770525338447";s:1:"g";s:48:"510022575873437628725501442440267016121819348391";}i:83;a:2:{s:1:"p";s:48:"822926078477097486444962323277458446756022978259";s:1:"g";s:48:"589910875783545994219126942930975255660655801503";}i:84;a:2:{s:1:"p";s:49:"1431038025067691058996244066273531476107919268967";s:1:"g";s:48:"646932847368644396052277873258548552204273847065";}i:85;a:2:{s:1:"p";s:48:"748914983317514213116978697376736239495039622199";s:1:"g";s:48:"380231440226574322623857841433603704817502783043";}i:86;a:2:{s:1:"p";s:48:"746072024360294846456065926995318746311968317499";s:1:"g";s:48:"447450101636477251499694410520804920618515586095";}i:87;a:2:{s:1:"p";s:49:"1187131965479053580515236709652828301619620145103";s:1:"g";s:48:"497069754034640342738232452898528527704513730253";}i:88;a:2:{s:1:"p";s:48:"960772791831553183940713554045441733504839855479";s:1:"g";s:48:"467189892742053032374040989028169931254382194485";}i:89;a:2:{s:1:"p";s:48:"744720969935722391016885990661932354762971107847";s:1:"g";s:48:"672892260298249149453889871675067812728254959745";}i:90;a:2:{s:1:"p";s:49:"1284138085754206095984621825714666759051533360447";s:1:"g";s:48:"670680653213753375576284488437938207972423819365";}i:91;a:2:{s:1:"p";s:49:"1219703410168163907606714523859829978847615579703";s:1:"g";s:48:"677566000162233783460796007673293061475277168933";}i:92;a:2:{s:1:"p";s:48:"758709279959164862900864570318174449302613241339";s:1:"g";s:48:"452090953215317329319057610469368245672033968833";}i:93;a:2:{s:1:"p";s:49:"1071627691050988181827045931713008063023490617507";s:1:"g";s:48:"395161002059489287272140658032643593929127864197";}i:94;a:2:{s:1:"p";s:48:"747205427461860752092585693183163490214259858423";s:1:"g";s:48:"417612284638201080293586217380241875657446616109";}i:95;a:2:{s:1:"p";s:49:"1006525224732904380987702972930703364127273860867";s:1:"g";s:48:"577545982783186527062549787160719734065840781741";}i:96;a:2:{s:1:"p";s:48:"913028069291155898874907016169442803156338579159";s:1:"g";s:48:"382328749628965365180053208087496476372826871403";}i:97;a:2:{s:1:"p";s:49:"1180257192448033707067808765981766151872541980359";s:1:"g";s:48:"614672147155176708479881170756885404265660714751";}i:98;a:2:{s:1:"p";s:49:"1131049454834123578538951980844254468954332837143";s:1:"g";s:48:"516237691590580412638232604519378047537778117673";}i:99;a:2:{s:1:"p";s:49:"1237424753161543304728304439687733366979209986923";s:1:"g";s:48:"443245341306104571668320672937798146976581923033";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/192.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/192.dhp new file mode 100644 index 0000000..b5707e4 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/192.dhp @@ -0,0 +1 @@ +a:80:{i:0;a:2:{s:1:"p";s:58:"5079153797574224533127650903566678124394292110246160120503";s:1:"g";s:58:"1775655624786036047244981958605679297671494641475669966087";}i:1;a:2:{s:1:"p";s:58:"5280951490903349944274113198979805160361532116756714331587";s:1:"g";s:58:"2750563206691870569645796674371212328334419605349825272301";}i:2;a:2:{s:1:"p";s:58:"4908566683395613935027848474793864939536478635831425790279";s:1:"g";s:58:"2217539231350728286886430339426948674052631001859542132203";}i:3;a:2:{s:1:"p";s:58:"5703624436271395096304848287817139341138468504063713187679";s:1:"g";s:58:"3022750833775105018689926348454114058182309558353388910967";}i:4;a:2:{s:1:"p";s:58:"3408373670273337858591681243643970689646571912179487614519";s:1:"g";s:58:"1758856341362672700409627738845335577349659073518321527443";}i:5;a:2:{s:1:"p";s:58:"4287320311873603445306168782852197886252881409583514378587";s:1:"g";s:58:"2443195977736559684026176246109530132630326857948446510283";}i:6;a:2:{s:1:"p";s:58:"4761797641028563107617146852177956262274271252575050657847";s:1:"g";s:58:"1967905564901738530971339075129813513598845172896595290077";}i:7;a:2:{s:1:"p";s:58:"3404255621100712761608995448456580112050385881116515218743";s:1:"g";s:58:"3120045944636737237456921814814946983811560917318686693791";}i:8;a:2:{s:1:"p";s:58:"3518512132339784039367856376100548636855822828484663862139";s:1:"g";s:58:"2936406192235066242230149165110575455148803961090995968809";}i:9;a:2:{s:1:"p";s:58:"4520842854376900535800877686817612397649559103675227962403";s:1:"g";s:58:"1874657377100137046702279108249554882052905843093324820341";}i:10;a:2:{s:1:"p";s:58:"6203733978483113711573047161762684887620736693334966038399";s:1:"g";s:58:"2281917699991259331857077643208127496786819947163020051699";}i:11;a:2:{s:1:"p";s:58:"5214094012046521402304871473025167219554075012879966514639";s:1:"g";s:58:"3088934086307430848999804849857781760708880102815101369475";}i:12;a:2:{s:1:"p";s:58:"5265787227241273761511382896841225398989161548919690936399";s:1:"g";s:58:"1712679489582782094723102988233060994358404878702641326991";}i:13;a:2:{s:1:"p";s:58:"5067782971873137269486362087896632172119409421624139384687";s:1:"g";s:58:"1957215522412301847352896019837878268005516128183054332167";}i:14;a:2:{s:1:"p";s:58:"3879943934531405521219894064328899150202248043781792741163";s:1:"g";s:58:"2689322241684381372458698909603283328674743428685220509813";}i:15;a:2:{s:1:"p";s:58:"4120056568851266360689374732995900645396167325280679087463";s:1:"g";s:58:"2739056964678871613984984850786368930553006484449754894415";}i:16;a:2:{s:1:"p";s:58:"5290823285697561402595250303494270872946043138293779317867";s:1:"g";s:58:"2999800290205863127707463942846916629036584233489088821049";}i:17;a:2:{s:1:"p";s:58:"4696296982773151008599445288256643884813021679236448495543";s:1:"g";s:58:"2408594073193339386366580971829213213076930843022656561407";}i:18;a:2:{s:1:"p";s:58:"3998268366250968840287647928335220016278201614040738565227";s:1:"g";s:58:"2595910859797751097123521430486225763957170171506802652187";}i:19;a:2:{s:1:"p";s:58:"5105069304661883494321382458240500613472126523513595557707";s:1:"g";s:58:"2825214821736761039502493498877270698148881800422346821893";}i:20;a:2:{s:1:"p";s:58:"5939529852124350341005590253411362002186693503432217871263";s:1:"g";s:58:"3137030337042042092888657799036721412663511814250070150533";}i:21;a:2:{s:1:"p";s:58:"3735981060035319331704321434148243550135576868950902098459";s:1:"g";s:58:"2989931789688807377997994070703231972926299933593627385837";}i:22;a:2:{s:1:"p";s:58:"5230792378968521455498964433594802701706868629126441715183";s:1:"g";s:58:"2992268420669971207665248346210532238175082330707685959423";}i:23;a:2:{s:1:"p";s:58:"5749526646585270332971754516348605824542707999962994742387";s:1:"g";s:58:"2573170301376768608263799013605480737285869306043252438563";}i:24;a:2:{s:1:"p";s:58:"3699527020894248790756291220971126715267429809359417078203";s:1:"g";s:58:"2021241263496862637571247756030282715635367895206297981837";}i:25;a:2:{s:1:"p";s:58:"5427626576291640178697581041470814432676853894644639708223";s:1:"g";s:58:"1848499510997690637725982471703590963955757498487817240199";}i:26;a:2:{s:1:"p";s:58:"5452425390533601550543539501601743784582084084867811688443";s:1:"g";s:58:"2199548899998832053779931991591849993353619475860404941523";}i:27;a:2:{s:1:"p";s:58:"5878470339621492376906133148257205717408902857792669244327";s:1:"g";s:58:"2910743244761101832680480464052389046853832954372521194003";}i:28;a:2:{s:1:"p";s:58:"3587801443783379284860115673588846335881679053068010151367";s:1:"g";s:58:"2315160945585969381035789749922662556153810767582805204681";}i:29;a:2:{s:1:"p";s:58:"5653795417450857251329458236472236527706349566486470589027";s:1:"g";s:58:"2802943059453712266640356788067020589920472674707906596571";}i:30;a:2:{s:1:"p";s:58:"3457732635912905545926589910894036857464442278032296155323";s:1:"g";s:58:"1903129017479274520911249166986172071538526145448641719123";}i:31;a:2:{s:1:"p";s:58:"3273859658245405519746765698873884234918875187826838068579";s:1:"g";s:58:"2929782824160658072753520803173577956848457241680756520565";}i:32;a:2:{s:1:"p";s:58:"4761700036076133445360827240122621071147714758522838080359";s:1:"g";s:58:"3119507520206605362692770863344057997665729918422544613457";}i:33;a:2:{s:1:"p";s:58:"4405233922665692538904792642661732972090380014017234871299";s:1:"g";s:58:"2156108555163829703349347996634361253078629587693591085311";}i:34;a:2:{s:1:"p";s:58:"5434930531607967663872622555642175923042733006024997147363";s:1:"g";s:58:"2390628958788389539882354377548156413067155083898369544581";}i:35;a:2:{s:1:"p";s:58:"4344406185108632577312980841629309659365783238791736671263";s:1:"g";s:58:"2647210942852956042972151850238629788613813461130912113809";}i:36;a:2:{s:1:"p";s:58:"5278098580436144905030665703594552427147893589111423504363";s:1:"g";s:58:"2814874609333584535379357984744374068073324062962155810123";}i:37;a:2:{s:1:"p";s:58:"5508427450523598806685760544636322560098559536697021132747";s:1:"g";s:58:"2761184507918258267367204938499934170019870825853641891507";}i:38;a:2:{s:1:"p";s:58:"3197969999493675106847802004872388076312076345632578632803";s:1:"g";s:58:"2764533290029322821411173465515504778592964392854621620083";}i:39;a:2:{s:1:"p";s:58:"3568017303357088501066971162950692936521340156006663981979";s:1:"g";s:58:"2462095370676111544085426676206766871866947565184370207309";}i:40;a:2:{s:1:"p";s:58:"5008365436214491146872187578253187471375499980831929272867";s:1:"g";s:58:"2004937842465852411676297045663569672559418220307277093907";}i:41;a:2:{s:1:"p";s:58:"3660373588674338114259459300737035072550434338346265097359";s:1:"g";s:58:"2991636412905001507296739812030759919233136578804181824709";}i:42;a:2:{s:1:"p";s:58:"6157975818295494991242524096807318074150442170944799777487";s:1:"g";s:58:"1912881834041571656233505839143523520426242139511439944719";}i:43;a:2:{s:1:"p";s:58:"5337235345895474227895552498603823319310250209297678658503";s:1:"g";s:58:"2004866565219588730716376725495942807885729550763014887077";}i:44;a:2:{s:1:"p";s:58:"4371864179460543040008442352670502630060546908322397366867";s:1:"g";s:58:"1935388976841885638579286522024434829194894520675959876927";}i:45;a:2:{s:1:"p";s:58:"3414083549094939748645823179851604517084752156079674932167";s:1:"g";s:58:"1816546965247162148701261384470515149792513541950434437581";}i:46;a:2:{s:1:"p";s:58:"5536741182273059380739258337848493476934305752266586238483";s:1:"g";s:58:"2634952255041246307511360974017554325693333324673254108479";}i:47;a:2:{s:1:"p";s:58:"5775171283053461281137695211327289107677094643699899519647";s:1:"g";s:58:"3031757045742291978953154643467910261283123063435248617143";}i:48;a:2:{s:1:"p";s:58:"3660370278097827798512899847051044607487572010565769322563";s:1:"g";s:58:"1871171166775120299644215319226940768117395474691743314505";}i:49;a:2:{s:1:"p";s:58:"5912814201192481980980973291370859137726857826993424267459";s:1:"g";s:58:"1957331954178238262489699534050120077442696109610799864601";}i:50;a:2:{s:1:"p";s:58:"5184758634017280989737969096729809423029735654784172479563";s:1:"g";s:58:"2747826512297974451893717897444511651643434922118473813467";}i:51;a:2:{s:1:"p";s:58:"5016554360555320960358874145319693037228385506831515688167";s:1:"g";s:58:"1784356253939847363273820130798312708011366157682845326497";}i:52;a:2:{s:1:"p";s:58:"4824111221728894496275833910627403059802694666016696093139";s:1:"g";s:58:"2662092108701388387028814515342811320842361286171226121265";}i:53;a:2:{s:1:"p";s:58:"3542653376711233154532437989275009789150906759425833977107";s:1:"g";s:58:"2993413985944641497043043994022562701684915788578786069553";}i:54;a:2:{s:1:"p";s:58:"4187665199221743303574139512590690486755802614141320341839";s:1:"g";s:58:"2510543985310768653707854276415093099545041552566817022349";}i:55;a:2:{s:1:"p";s:58:"4346276948576799819411680068399983993443471275733281789763";s:1:"g";s:58:"2442402785838021648812881999905665222333408565418673938453";}i:56;a:2:{s:1:"p";s:58:"5941963164742000720764400502847295414251200623156896167063";s:1:"g";s:58:"3109075742957968243564487898153518334570588261995161851867";}i:57;a:2:{s:1:"p";s:58:"4968360668694082055763517916799832503511627402142244841019";s:1:"g";s:58:"1631103685513385955188695844999787805548545198875281032329";}i:58;a:2:{s:1:"p";s:58:"5352110123307966463863605353613413090377648808052386739639";s:1:"g";s:58:"2750049649165087696925391766691408509531457761506337220083";}i:59;a:2:{s:1:"p";s:58:"3492541419748637892497432009505335534778776020683091511999";s:1:"g";s:58:"3049208593127223291568667028585263138784341270026974399485";}i:60;a:2:{s:1:"p";s:58:"4861492597654350078184874961008205492784601986955728398347";s:1:"g";s:58:"1749429043719289142747830392455920053316428401625067853441";}i:61;a:2:{s:1:"p";s:58:"3409541503404917386768832654354691273018080275627195068863";s:1:"g";s:58:"2845917921644585587482900072159268135689400842569349846455";}i:62;a:2:{s:1:"p";s:58:"5001587109106537100754211008462547142888306106754962133079";s:1:"g";s:58:"1736190567706663129392257076867802867666208577891613530111";}i:63;a:2:{s:1:"p";s:58:"4671631568303408929313557979933219261990730864997882387607";s:1:"g";s:58:"1583827872809517491425531274727857065425946452716427187595";}i:64;a:2:{s:1:"p";s:58:"6146891969648692994042239520945566269789751886818035128903";s:1:"g";s:58:"2727147900282056053406651420169531118678689909616560664319";}i:65;a:2:{s:1:"p";s:58:"4691567770908195706485352720805469781946194453032677202383";s:1:"g";s:58:"2236768896068337176672581634512929610734819856751870275011";}i:66;a:2:{s:1:"p";s:58:"3872368398279580027726321029226746610541428160314301688863";s:1:"g";s:58:"1608040030265058297534235316667763045728366641295263678285";}i:67;a:2:{s:1:"p";s:58:"3203632401065450194024989211370201773029103146907460791907";s:1:"g";s:58:"3108490534046256038320616158880085899798273995837799898229";}i:68;a:2:{s:1:"p";s:58:"6073671011810509460429303954978560171127887337149697533643";s:1:"g";s:58:"2957181103947316246707372225424441718695563269317354251891";}i:69;a:2:{s:1:"p";s:58:"5074938515907596155271435330326725395033521551806939456543";s:1:"g";s:58:"2485585061148875179271778918652789326197814093765863878501";}i:70;a:2:{s:1:"p";s:58:"3597117650406458524784844736459676469944049182578914376967";s:1:"g";s:58:"2257773347341600753179198090802149292787501545042330325401";}i:71;a:2:{s:1:"p";s:58:"3692791074237392866630655248999144283662143204054214329563";s:1:"g";s:58:"2534194325117231881996721493067203343094197216768153045559";}i:72;a:2:{s:1:"p";s:58:"6135290864129465394143806935986184464296313272645041006623";s:1:"g";s:58:"2285613745291849023050799771859696833587607166899781802297";}i:73;a:2:{s:1:"p";s:58:"5106945177113923512700853358787168136230226375108347673543";s:1:"g";s:58:"2936475085379719192967479751088291541575787778419060330529";}i:74;a:2:{s:1:"p";s:58:"5181718537893973578476916094185424173615729216146516666819";s:1:"g";s:58:"1865764650967895204996751102080042379553463091437317170481";}i:75;a:2:{s:1:"p";s:58:"3531421829504016980971043040659044882221181410827188828199";s:1:"g";s:58:"1754788776989782747965652935525104074154211520611110481407";}i:76;a:2:{s:1:"p";s:58:"4161793909460184982769028720635087392704116618587096387343";s:1:"g";s:58:"1981894828271550034470871640268847167031481222081314887149";}i:77;a:2:{s:1:"p";s:58:"4649508772336796680142675195864617980598769529445092576119";s:1:"g";s:58:"2060260193469253389049874052470270879843305419455903720777";}i:78;a:2:{s:1:"p";s:58:"3794461735620721528002956624730277693135123278831773787983";s:1:"g";s:58:"2189746373719240792072113566225714440698072247775237220387";}i:79;a:2:{s:1:"p";s:58:"4259297905676945125094110840005802642699827572246773326227";s:1:"g";s:58:"2109550980417331068335665282608229962431326830969146948525";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/2048.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/2048.dhp new file mode 100644 index 0000000..2b42490 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/2048.dhp @@ -0,0 +1 @@ +a:20:{i:0;a:2:{s:1:"p";s:617:"26119538730417652824386042875531065645936518917298962859898441526145920544648057315613454013347891735147825801670444929736964945371870320839420114081211312040311426747341924926796064326790154135416828824406498127049192207991150849791263466384758021041373648403002021019670485486194422368037809226590462008768240610399792452398657398016040828114270291337378645720426235644484515722968943627611602608942224415247853186618238500673174946668053663930012369427127054431907175454668091517702372418355188739885994249239971879046563843965996805199808782303607940929503059770051997236902131942802683449268228989972965647643569";s:1:"g";s:617:"21692939338493471757047070972142857798654655518644033814839259110511954364805167016395345229599656727059168581562814761049085679655778308409884937999942260287379782711541364254190475889453590033170167544793765866452374932516116637879718064465014425017927830556064617293664040306920668006143308702764719183733796439597113613238493154190242995109778425085299465944352613372309093551104453581823748016505746665915971846990430996971870763550674830590105744057158734865757657025005213833571438489370197722184401250800148831017627655890275298519934855829463439326391192412757063584883487921219859606832338748797027614904402";}i:1;a:2:{s:1:"p";s:617:"17494852415029253500263451635519645209848793831494844994025633838817687049071127640459187917644787835777597552920325283395311336348831223620733928313170193589173111165038138057869913225151019592978760413756939078573486040073633063605591180413506497786330721001074819795357862986504220202400959786152850399991084732854557124231380109637676272229893604175498706260833666050908881082936323794606250012464077347589487455541114492420426914154675480402370321252743256114353020297093701386337644658626048585971064205107100595069003802366933563435053584207760412338330625134515253507734839954484610005303585268020855550319783";s:1:"g";s:616:"2357536766000763120599640303735871022142042544950223627657783713207355119762671384828323528942597724321262315162871435756768680295649894617172738865491552395499945910352628711737711459272586894150019111123607450240818973582127295016918052347511023159480848100006890622723727515688121279961377206539154059916280008591560324035228208297543602421189229162987642842188359302005359697956742412268879330969306518512079332500066243775980282601895703673233538458812861112392269922097185505956010310178122235450911471276428561302761444822273287825322542011844279562807283571980685665180825337747868563602172878452348907437991";}i:2;a:2:{s:1:"p";s:617:"25780867781251628440065459712673652906933462699778652742815597485375302663371634433740749781750744136364458591061494303870283828393634179033789064740550017980781317260925771538480299931323791768420861462236431178976601993346954114130438797677012654484168409283271118338570398965911311009082335022460593522080995913669261644367315202030128086666255165421549254127930200196693366384905335244383579750798169063385118039839822333156433252043549232431896238765093602816646193711914401964588912145258045516400610180499330382140474862865622175503314183207026529522245115643165204301739301808240344047865206921844783110493619";s:1:"g";s:617:"22913453542498739351587679639664856992870400001370134675523784914387955771143444917571437755672602988500046796113264805842672819918732572442945319891001413155624746874608973595637299150443023015326933062381925416214430378088998324213270254493852316912687655115745315976037232162037286469731505569162296708698849815888917345038284831130181824975228023218421467353208181389358811631765874415954696258724127120397639098550964799825663331326239274792397246407429506415811807258362151079599569033578071919173833344990717848768176043897116549506982186347999780034352488975732137271158144830900377154823625267922843930480163";}i:3;a:2:{s:1:"p";s:617:"17108582037564624674917207799802832391965005846368564001912347974821312076704202022935078231527320828683510069559020007567337030036847653897258184670166659043776952835342581597567057883537012431671450166955634401920313853950838958877425157189757276240508367052156667477216311297002905488180123637261690402759380674542437629380601702878071821789801803270225500263470954518609603257770968427427507711325567168791246523926693942270053153316006073740979789299514536832553631600448872021864884160673857409747182631139916196743438986143545276713429020032900149638305213353651861654548990616900439392404675443312771396640963";s:1:"g";s:616:"5975220509433032675041067739982972692919188487073925726726373313534662751942478165577276960038244273703352381665589951065977292053614500099134443316919840135540845038879240858995341120504930299860699717125398702129847883991122790294702383642451156914176785997702247519476072621264654943534650803561957687965391725682747412106679696055298814300614513661600544039166554398548785771944233727265781414899110258870106277094923042460709047677122331805345608634843554102871371939362771130643332944065664751524937870301121933464463246140428792009737393899405409293013771077653754980109244592589837015805450647805669046754032";}i:4;a:2:{s:1:"p";s:617:"30717950753282822134060274292481360551691413121828212175823741839241549781801345288079837278336315658072275041792278917609278903215044319053321254942912283926424925303165388602101369690100151597114979236011549040048767798924665432539893102285148132138243288344387551553735318445920954909506524809009977259661816549852869076545111065438920376549122286806153480198930510896590461984138938291299620745126683744010164416765756555097048566964051391776874919866198779721078725961148626312942109765123843522548437856492683402243565586864304705385604772276167357697786949526357219442530907854345605378292997710443788101928509";s:1:"g";s:617:"10664565789660490202298837070717675886736269910227069585599819283749390051779567448569637299937235265670862351367215197727816605187136471289814225238589787798288892630743957045107552613020882669254784592049108026598927346597271935204885557927508364640631111649815601503280096710752780360644355184069964880671356047707747432831698299934227246554005301084080880453975468135327329091037112567370668621377232969391777852701506421877424723612998254707022420880929038255877994522028632025963236345524733702080124131982159125526983451439267827560813655547710499889559501382446978742844869796195915570043693514343922418952540";}i:5;a:2:{s:1:"p";s:617:"17824540401688806758789771896071225083587012319363998191617936849653181551389106695047499662667967291625581739247113239792813655844528068687604946381553759091614945221410205365009632299490330030743034592873488196530343761271503174068102203374839746210075299309889318599726887738428054051601011972157572579321140979949387997453722974702415785332940537370596257985385177683159554405404123424672225807041157719414211000240941151112149989476447852776665859451162933640847402800234226474660637032612891723759060756931730283712399193482935639272951418485408140391847864492821971660080653487293932836946944136521465404250497";s:1:"g";s:617:"16270475540244008116184585752778689991248014144157341857630851928118586042015777493384925564647551896410840985215558245916363762734559266526213847217597869257247057011178185341066439942025102868024300290055851586251224372269673506910096840729969115630538026953603715119989120184962065253802795940639181332522689973724641004788079105051116542692460473554873410716389242666154728393218313118118406398989884581832628532396195574914320097464158289655615576483587557151914583877087002898507007877917751525353738520926876932264221223270925546352675517006263788102948929514039399067600275172739530270181974973828950452821163";}i:6;a:2:{s:1:"p";s:617:"26296541223964919760168059530334570885931534159346927274646606919982025952484337186039418912581476534463653561216509719479381053176684855749980449821690634103712306845089639450245895681254698231346381048999674311066168967221836809132774033058479473511929613700963171492882041969658471628084862296614689763559416767420597105445926395306014712602368798792070456787547357402852952716350973192781222867061265663188204551121616232196786533549406074301166048247937522415623504126765142089891926736558098921482439332224715081568035947703433373054349275731306378072487032600877157066181584066648043385348780258366341381039503";s:1:"g";s:617:"20245064513421081672907499417270373165374993596361839579769428949180631359713525104278983408046767381549351368804724075603972313718652589273580418726681940935429978945328837517669894683202567520983954981482700658614407104539781496091529019707970808126673481202951901341090515405122549648668564031419070573673075692741103463991210517062086632857878380093746773630605663125442075610285516428487568040493243899961471715606477290256637803334729918901038097438118954412644360440903940454111104955970051371388583374743634476943068102699066226605163496367446957915588429891698437584852521630657930214723677944070438116045469";}i:7;a:2:{s:1:"p";s:617:"24022994888213612729867097153159489863796760878636990746219660205649898621390642573759009418891804310813653013832818801183450912563726218725349021897580704338568278000019615459132633821605975626413805907014019193876676494728190737866777588109580505401823207283091078285105989405265851649576741649994378038616418347053183638209158265693304947428873206654237011507823308167792632150344918598864834554245939189283437720190979383402835863441249830065088109408522132789686163566158101743287893869880671902412445418124423229540545176428391408627743403931489063787699934557486715229490493258244148224520887812506822249429539";s:1:"g";s:617:"15678480265412800733944492186437037182707529884326735097121447410399826968420553856830859651354914793482794886843456562720138670995286947463967042610750193460296792282058991180863764589693616599436896718205171675944873415284970267586420972091500234700259041314722311096697012899487002459357488089950393843625900001981078241171710748533509781217310128183350756575104004773859267324503648554413357662859641282012089994022788874891032192582004035250870868552993001550637269383026801304603350993608652909153403397051874534815752300653963021337866508400173775688584459109409363861081393338196432750140305711090376705911521";}i:8;a:2:{s:1:"p";s:617:"17083955432364090280533366102746720945982105621761336600070465958323396972881469403519543155239819620859194370028989288057523170198820482837073270689355245228512567098603210383977491443914341618615645725451024486051612004217893492714245981039604396229635631751833639174614993002993629374228068268504356303017948571496867771413891972482336248648581356279979915549622011422496674683139397429048285638804862404243827650990125026074135379573526469868687788484267220583145333135102887002688284926311346027425969194262182288607685222886823791242675124535943766023129987374186943906004265733055482162823032404897008638709489";s:1:"g";s:617:"12261234691674641709407438861728481101674950650359345083238884715719434368649199286826020022876464290948119474546308321123254175100004821757208768631686271471283892085404640045175987297679723014286459620532482282374024512847784380353023734692492663279003858305861949005817377728600448722524457618798241008130944601573891808345338306588166841117840949087313506761214152652649864023892781683429143355875872143036089635390231181686164167199603978001780011953093051148910850001653642083816866537367199013814853150666286608827942041850714980974747352884836972297673635076130465096348662086839526317882823690060833316121518";}i:9;a:2:{s:1:"p";s:617:"25204476138284467855670453742205091544206927935811391970379875845925341542816814592972482175517776292877803060312282683057673887280171863404039620181938052133263739488514572047094655954023089583401121552716825102824245089603523869015914976008594784258015509292801626580908040067127059423251656372753685608747171457530204828520955350885774522412118938249637383726640228002691450698618877022629430660597324647064876949362319041249591609232234716766223276932543328705703598431803088575036192723955330976791603168213443104658956110289005145211221506492748124722595764125541652261925897188877632144503729500847899162487293";s:1:"g";s:617:"24470380828092171830607640675307269842934271351057990119472060393765189808175375460336691328427923943061209748614966054260866042030491028094628330791617270491451679586070624647214669151124663462616816618278458332102224612471875661847572035426271967106152871750183790750472633379980457073939646744071844097027505130835932272606999975749253911402372736522468536931939555983440411944997387444842287619087631352802755805134214227572364500740868338334180446779244274684101127564951437506337872796885243225511197939032115243566176064416399644452111639287953151152283661969561179612761064215331184337200817410228013012815215";}i:10;a:2:{s:1:"p";s:617:"22849460047804632398448747334192571885220871329972534210954947581951666060547985334167486681856357757460114635134954573658082358845539735278580423082123931373208796139732802045985276620997127798853678505071244613000934377737859392412691661273736740375485316991267484188256664287312744138816442964815805473226385201474782318459805435125108038706696302574616946459702959134346029698514766348904241077025385404804431202010332555268586051143130818532183288892073337677669462830398135627462917042631034659974404647502885769859349150518263217937151139653745940505432896722087326115128679012867920678944411418261860631429193";s:1:"g";s:617:"13348138446721657089630012558844652910382267316024344211317185221773269246392374758072029526288163619976687471148401063666650529131734387772547277912767019892091405085546024081290166317121965135731523404800558013020137490216776128824652409837770063691312561489888304473140055749560988718836503040853002145255793919808930722368419221663001775239907136704227153865398879262468691524381141127515887196789195504406217373337864420211704031143442387747687436399787007564064433407818094211670914708907567291746261122103561160648080311292253951964886079196911189940359203107056306519670126645661147468673028841078212599422387";}i:11;a:2:{s:1:"p";s:617:"31338823808328910030039189736747412767934749985120979774750656232315188517412996431869533670874523236506095344486318916128738510547271487301629733012645126112498494837873510962613906720395105423345696133501168531267479752944739576745897553250620501347859376611724762320770615408466753235707776687064856460812255814585002695810118730421429331410377462334339309659699186654268542620852088199397227812555782980142369915873664366261623799237710733709363641919324417365535560523680225962259801453373866070142295896144627383558885424151975989188203272862741597698359922271892774527924814448590085332431320643929061731101951";s:1:"g";s:616:"9244265426989189771814939991669243957748740903183842164268478744253017075992473802044696109071297007354420472625602806611080450814213109420239453967309288617745014104035838027804629485250918376876630332625045211500185584005538683904806015146917080419014138452138676952964670289110065893199216408172970617769948958057624438113114785977222898946940751719007529545723841152648078690343209939496342721851948377226748909719230993095239015507357234175387231426890464735514048452739457488549618437769362624641802065425556060699697034837970299896246378714455325609840424540997999174950970499493632310488630948722459761331238";}i:12;a:2:{s:1:"p";s:617:"16720011003255706113542533606567817550154977290327341685222505526573898977078683119417076323927302182238875008774846510300284799199809076765861588224343304072595369156757416312139864889452521559749463663197267698729151348390397049479376093343572901918439800962638271229803825595288317054627390900627955191106470683028331619882250925001777457287598880159325943026403028710302505474738862997006103128487776056340534495054468394659034381740575225073994349667872488974021301049946013876074350344727733532691108462203697035662350166633970402791313885464164756357492157962521289407696476321940071562093155602895661489660727";s:1:"g";s:616:"8392549857641312164454309373940435723590421663279978069555127083582677257780262498752161403608771364645564865559596200803263820963402481442852937071497875582873453734524770401215851485463814913260581874888729922114937703348851445066316990994716597429391207315680448738459977536648358752488744579272567717490797318379401666836389388815269231571648020465125802739997512741984174379317449696467694331951860453172686792834397700517360054637428943005447586488819050418799440935988665824222808271742893820938468194415642476156380577849705310979308145356389925732064483915429084436934935530619828894853018765861416844776438";}i:13;a:2:{s:1:"p";s:617:"18875760971083209961885190059598721536385876257385725374837530129382586086243382935243973016095834416470415049985931441352969506342859331487451321440644185970762508184028359569305280339801922408612236736096586209436455066098437157049757171836542290377568267264629176969075668301397417797762391880806604540802358357273422189043950195254062471915353959389101213594915524766080852049810468225847178041179462795804709284087874701166025765058651052595190693164918437491064045608634977527209186371829864710057268355405434016180724414588828894423442390301185665478042155226826512674948772583334977420644109748745496717956161";s:1:"g";s:616:"7831956897688961168585556861828822320686818447121831468325331650719661818670456229905256692890429862578945073402841774396892137360518705835947989741723445501270103038310934960720438693310516616091846310929399159391021583737179951182014058853520535002225341000259003057782221326379046777635654033845038695143831406214163177624050429118303678368949300283954340675165271848269749284009942183037928288215934744269230891498878411296154350712230783593506210329194220505403024776317988240018183929230323644668404305143872615370553030474103851064003677655379017189993119048579440984740754303375459978660957509505078490657995";}i:14;a:2:{s:1:"p";s:617:"28395820039579334836161387898649960674439247233622326211768280334782373271489931817979170890916055413302754245705557686741053065719308409823785829762995052524756698071971324411047312398267937917755702206261019714309083266666414013819615504480631886547648812227018792688441405307391232086908175633468071220469138604413592100312699652255608890441454528772318259437737566237789142089147587149245666808919002145823882578568437856570025104248895416549110129209195950707772095941939502533593689204857946981366537873479013251033128358611814923150665511824175891786378056975816035141738553582850943558631898695157518195312479";s:1:"g";s:617:"16427696982631268353903581225487755231705825946830980554789105372858716026038249111748904084081293969196895304847211869328781733531414281143425893004105097751232768970984365526090081727509403174570678697235610442079339105174193043899078868617483572838448847050555823164133758660962030044720163750716900891345546349794702104874846983027182159351657363294959859277476894577221808034066234414030408976510603071601513517363788768298684299375453231513250932016545163534328516215349904742837283723209984958135686659791911743400514495756511965490801110027623968106155034268853690378943253875810016843764682678137792177387441";}i:15;a:2:{s:1:"p";s:617:"16895876560966846422580484060632250344028279991597239700516020270083505598828800684402957155723638097932477009949561754503437018270655438745051104890013072510900387354248033926081481144447977165881754984892587524293467054670099323627271126243617375076230412683004370870720615709833281491587978704142630411596015418966637316097621942031121320633348486629505904113642825954743114590462937823539960421789947873999540484355570332714664178766388598601416594705788731741720803815778148149915425982758373977150668814201314016383576950334588270980042692711517774085697988618241677212947115800722377405490644578427754272325391";s:1:"g";s:617:"12562425989524907011004691194930986388586219858834665734575703272928936583401256775823265404348532608420240136127635564158186788142328847636504871057962904215117688239061667196573670142209844922877950379017542816985916147729138565271594417564432973234862372784752905433168074513343092968302846347041479914197331038856875369435991929275281451056919524358717865600391488606051625691960488484376362242765534345818340338768105915246819027304718641846705039474566934921726821449830829026173348866560596158471286618187646399500911928214808061786090706638481164230762304017836419687357912810324817426437138236086098747016365";}i:16;a:2:{s:1:"p";s:617:"23592516043230669381503209490463912141922639479894331542046867222724097666751148038610606011023871126488378139347032265001525086624363691819566899874833940140774643220129869846896515297232189140046162539824550174277368181841675294015687041610499572801215455220349891926229111228496773169280096432503725426296044037202286060887783039639522594117165502962065742480408868757768838322362817278441563946363935999706919254014616515903798417454432404825037513060873405178641053793336989996203721941343359406537926727709530631693065497367776349495501129472988620241004182664916330461587088288889551735860187055513147589776493";s:1:"g";s:617:"17357673844145177985350497915290742733468722287987801951177917367151312063340417933200596968143253358846521516037627485604196935838705991263693782128577977709815774507145803116356994495454865663246386089298609158258807885879398788921730122192063919930212770027132626149464443611825908303647374448825352684868098359426367908573139014507718513977629877766985377237524984172786250947660639174591036609831051955804915387372318428626310296812710753916023514838653465725580626928490042758170754692218386311983461067928388581645238515980737145748441346604551781747077785610383458653905239486828967469096880969795814241762575";}i:17;a:2:{s:1:"p";s:617:"21562752817967258993738108906070579852039284843199885400956208534323430625671418204128340587893746628147431644603790908199613136574754933913669343614603320177523451846097320277092600327653947194375390514003381380358695023465638052714820184091922966583876523596682349437357201109301308068214108864523456588480732651538356551882147183933343705677706433918043334160712384815884738870777020254836544550884904493519865517553323545274678672504574933053194683269178875640249625236659968381130308537583795589786484046391067710957489457666862306475754083459177269427077232481488264522791483632575447236274170676788449453054921";s:1:"g";s:617:"13279794357248225509268913538229148538165475069688936294580710760692619281482036517026872782539307727254420990210098545082069190602873006562154189669783694568358461408837175649218652220054674691087268179615232683465153579526387421315074008948599907085908216891149444162354267958924947208835973759341257881529439709224745462220138240933234290694196662053395846738948018071824632382236962943562507267190805674962625665753157699500275526405757056345749165899750806752377097857904380121265291644313347878017446362553944043862600781821033710406992613690878474651267128632826192153111804588684259077012631873975836172554671";}i:18;a:2:{s:1:"p";s:617:"23417496789833357562672978663019776511350475549993441033999842954607242935212201031177981126608192726681624256142944646964904043397803054432307081104126067134609549096882870571668507906471183209340875647777583501325231659669003773894230363951801663030831715910008600763835254655919490884334756073413369232416903958581403112233968734299630803767064369833523088084720247752560471992092988134943153629918414448683818715382811469577322425419540944846275781757188812631747645756254548348427432379275629846811194041724729581004054697881971598136398819432205891530514514726611596081712980455525677515953671132309404250071199";s:1:"g";s:617:"20801071262499851595618900578716319162176934003597174772636998352276398183882683316341580810228964692272006726151949111073090755703941623831598136461709241110761094009335679988218697376766403851957621931308873298652901263458555140525167016139424806902200273871261469449585864822112230671772272721833668808110440729098213448660334235171526815362020901986446409677613239293176635891891319223839386130383508566659068285370921370541204738605732883427996902307444317957800998331868014970214411060587106746040466748722317070439516836852348646076122345442869711806916396726025974030365623397644963075893322652883715123188707";}i:19;a:2:{s:1:"p";s:617:"26655296424058595179986310167103331472267584754721747665583558010617583798047063548558461532129138907195342606110500349726687564826777141466985678647752168685567480284858181931720530105350597193647594741653262467426123591472855807433972434979985325772504767253260906629707641042348493651989852298534933743195004975569908108431911918638926288237978982598438700759037925271408599142662922835078178738643272649728478247566871859792919842613041352050717122901728364945875378901071105043291927088234618466029720808811991185259823221295116563650637764805660046730198012519725055260313657762658163200991646911578427368876981";s:1:"g";s:616:"3450823033011284474361537763550411076975443192933065649612167536169211540041636498142282627876628156505178333636935643072260250740502145734190044105686943952320477597940678735631410435736451636301010458696341853562923909108829395191132711128551212911250649213549680593026315051719575199856616040525994791083856219112881366064925789959328272385929709200935493143170907071110731944588385661252268822128197419702714537239233622482980084952685844765339934318859731546823250794044127845644768022363051861287357902125164259399180047661173479655586363283681496036348778999849460527637675466013111833098388040937586686177315";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/256.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/256.dhp new file mode 100644 index 0000000..f03b53c --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/256.dhp @@ -0,0 +1 @@ +a:50:{i:0;a:2:{s:1:"p";s:77:"73832814678298170902979872884647941029284901545874925549746124366827544612339";s:1:"g";s:77:"51476058807219506610998206277345283936107915931731587440850063953203701691435";}i:1;a:2:{s:1:"p";s:77:"76972593405890136659846148581539967395400916262754679122033512090683295261283";s:1:"g";s:77:"40536177953614732865121461574338976193053929823454386769938537329223229736419";}i:2;a:2:{s:1:"p";s:77:"90678222772517737182669060100267690524517282587753173849354776070207136203987";s:1:"g";s:77:"51295217023324020085270197655410071441653549099982249142115152656556847133535";}i:3;a:2:{s:1:"p";s:78:"112035122549801288782735656181280913656716016217876691011809129186010432958739";s:1:"g";s:77:"54371647042380146023378995284862875333915973077834564744526683766342076225283";}i:4;a:2:{s:1:"p";s:77:"62194158582069859477188305359117210570164466813769290906395340312924423091867";s:1:"g";s:77:"45661079503690430027932894824979383218303184398768700725140595279401162955627";}i:5;a:2:{s:1:"p";s:78:"109887746949716562289488448980116120835960943658798588241040366306248937186427";s:1:"g";s:77:"40672948438740970862493667894582355273445817592820961034026786923017405088605";}i:6;a:2:{s:1:"p";s:77:"82856294712020982243609092866618447605083422559355627663514629271554457332707";s:1:"g";s:77:"34416040662169956671456751385517722858193479998165430251652844004160138167335";}i:7;a:2:{s:1:"p";s:77:"91504228250396371847303553559751396185779666715439286732407466045990416051879";s:1:"g";s:77:"39857698433618226727810093242453642286951247805632328011233975273133854259843";}i:8;a:2:{s:1:"p";s:77:"78914515436533736321800021501068621041000513624431796114155043029970882928863";s:1:"g";s:77:"37699575057133597258692445612773858685876622718395748221455772617196222142535";}i:9;a:2:{s:1:"p";s:77:"99887264459001756020085033457071600892669533881405206061916150024685965253607";s:1:"g";s:77:"38578248010462555085958074389688939528012418780656386569766828292349114252043";}i:10;a:2:{s:1:"p";s:77:"71982351514272312570866502020135229955879457662805899747226636086639670593607";s:1:"g";s:77:"54577099835257042103340960450024007160493073561557576008109301120391117266123";}i:11;a:2:{s:1:"p";s:78:"111348005627100700173841228663272359096490475124040160395478639652684669000219";s:1:"g";s:77:"31457852095708016675951983917720277445060540653267088126635758197134362138891";}i:12;a:2:{s:1:"p";s:77:"92953401211845673182089220656569865148723807400500147073569037899535512033323";s:1:"g";s:77:"41697366699394586852286014598140272134473146487972754852099109223623378584697";}i:13;a:2:{s:1:"p";s:78:"115301894620266352952032164020027501572840286962376521701145557816371554998767";s:1:"g";s:77:"32871160431857151288198737173860718706139469895659824990992316603505757759857";}i:14;a:2:{s:1:"p";s:77:"96343471923498879084781358157613313091411861663579598008154784412360514421723";s:1:"g";s:77:"55471240482349354180574404954922529811817125590976473056110888054444317488871";}i:15;a:2:{s:1:"p";s:77:"60729504492067278584961924278016428606161139264005501826188762335152973539579";s:1:"g";s:77:"56444400025969977990713140047023590088408912184719130874280347851728019320481";}i:16;a:2:{s:1:"p";s:78:"113900325385355187838261275529566875388679911394853338488557608315621335675047";s:1:"g";s:77:"30375972193127924942262888540925064582100876646765197303659879193919125525653";}i:17;a:2:{s:1:"p";s:77:"81095496549283199450987632777601843345505533571552820491363946821274768596407";s:1:"g";s:77:"51869176606892317236374313168422430251338346091156761852451813909920509557627";}i:18;a:2:{s:1:"p";s:78:"101594484068704391452871318220948198964937558656012060633086457558349057524139";s:1:"g";s:77:"36521940857765148936706502186673044141636067645496695747248640910066892220227";}i:19;a:2:{s:1:"p";s:78:"113344409968890085710229548598885666582507318886231068563168211690913303412443";s:1:"g";s:77:"32565192853647007661066738760059232931455020519838477513190586740622229447869";}i:20;a:2:{s:1:"p";s:78:"100865157741942714006835672578320572215808688934162933948109189253969530975559";s:1:"g";s:77:"31353399506013880294099022097074882435311645322088758615920268562945159134875";}i:21;a:2:{s:1:"p";s:77:"58987748040478408081756831145947205673749409643180447005095787056716058221367";s:1:"g";s:77:"54681552249621678212318335368320692079388532771163109014194315264322059702023";}i:22;a:2:{s:1:"p";s:77:"66835016684038007440000941566894284049036931784409949699003105152793759605219";s:1:"g";s:77:"50881796590678410195198715025013574158095573900962476288005944437157669965905";}i:23;a:2:{s:1:"p";s:77:"68569773570402015506975522611411067971033537591125717654141616891912891462379";s:1:"g";s:77:"32084061487875388589170475560472261801957843058408561030464427927344624397317";}i:24;a:2:{s:1:"p";s:77:"89041088472716011536983496934725702392491528482708037595583928300741866320783";s:1:"g";s:77:"38064663462733312563721773041650262730115051360751432386782313487662169550555";}i:25;a:2:{s:1:"p";s:77:"63506885046592167433260234006962661577294376048832300254801217057060187778567";s:1:"g";s:77:"49889663046133352178991367103241000151089916129350960530695272841039003186923";}i:26;a:2:{s:1:"p";s:78:"112849893518043495404513869737282700616865089034331683427155137156329228907867";s:1:"g";s:77:"51198963761086864384430773699594339100576142234411897622813713340298644162715";}i:27;a:2:{s:1:"p";s:77:"81379543081685837790443157894616584141037060815155365981883579985363608950463";s:1:"g";s:77:"42614776409195525157609422485492905089299192373448738791332101819922775909431";}i:28;a:2:{s:1:"p";s:77:"73245936509718941037107456038166801410799170427973092989082747001086626266419";s:1:"g";s:77:"50625914415280232833987886929254839755338573972368676118496496226311022209679";}i:29;a:2:{s:1:"p";s:78:"113777768884465651623652520617441431650397695440681571689213021935525307889207";s:1:"g";s:77:"53230261964441050208664489018248680823016821086100228556881376058274887677429";}i:30;a:2:{s:1:"p";s:77:"64182686965111979612624371637207151576388157490672453099264795411237003991127";s:1:"g";s:77:"42739113605751145415527077990412533655324276070946090181609734493453094017981";}i:31;a:2:{s:1:"p";s:77:"64389758512247996595870401541350246623588091081581706581580796562736474659979";s:1:"g";s:77:"35027570949311106951646776724538831430146702160360275048978033699268366887959";}i:32;a:2:{s:1:"p";s:77:"80171209426362772759848178439308899617715023764855386038084235620615003353847";s:1:"g";s:77:"43695422597465267267136734648314440541023062173689900067656462758471318476127";}i:33;a:2:{s:1:"p";s:77:"78661796419493527928157412810459909523754144396497390147701511341329482510003";s:1:"g";s:77:"49752898964251876428709802877726537855856916332152631351710777602902687301333";}i:34;a:2:{s:1:"p";s:78:"115526308257340400930726289164227427500977970696409840065400171497064778851303";s:1:"g";s:77:"57455831142226363977301804360103763384570180363822590025633870121824156777509";}i:35;a:2:{s:1:"p";s:77:"99895854914975530338182226257990200078997854990974668036162249218262310892223";s:1:"g";s:77:"35234291282377508941734996504627025488242912267279150273638077828536817312337";}i:36;a:2:{s:1:"p";s:77:"89463065045661035231551266606118011957564752892942638731336758478484586730727";s:1:"g";s:77:"34476840145197409328284674202809241607868307470606051731302010755191365289489";}i:37;a:2:{s:1:"p";s:77:"64624582433843940196782532037106474516282625858188798258052359753710163749987";s:1:"g";s:77:"51907637552590521292421620324219346043776599340727611728777487195410015119421";}i:38;a:2:{s:1:"p";s:77:"78551241184092016983148992408241606401944659592242270145850487925990724687479";s:1:"g";s:77:"46347657232133823282496986294357257279901578280128017968110374222063339245955";}i:39;a:2:{s:1:"p";s:78:"110454815842135026622014358618557565054874733818955200746804642117317104098319";s:1:"g";s:77:"36484417303211228180239343081660681048447119211446094732347020240865174121193";}i:40;a:2:{s:1:"p";s:78:"108632820637647054517954687133925163880485688322613052629730339391168797942159";s:1:"g";s:77:"40936112635569071530887793547822555014118053761125242378490069684895929829529";}i:41;a:2:{s:1:"p";s:77:"77384308083436791525512502830035429654641530154237012658177043914982366384567";s:1:"g";s:77:"55266239559717320485762938784631604896441023536093197675797124339337266057181";}i:42;a:2:{s:1:"p";s:77:"91486076718429369045114077207029983275174180496205286263890757368244392884903";s:1:"g";s:77:"48796657615906031864159766245092760843396983449401480155814650683131578645867";}i:43;a:2:{s:1:"p";s:77:"72102224509363634446570802115759927713162729477388965613331493695110367533179";s:1:"g";s:77:"41338353646772388776408143300172508262741803968432848378357177766068794408805";}i:44;a:2:{s:1:"p";s:77:"94893543718943583226837269269711919605950724153318813366438966165684305916159";s:1:"g";s:77:"38199282927838495009291933322760804607026986374974299862170665602978303904209";}i:45;a:2:{s:1:"p";s:77:"80059845045249334967430326313246226499113423192254298079034172260496369580447";s:1:"g";s:77:"45202772573555806321013920339438762194895562399493007564473327311269546531823";}i:46;a:2:{s:1:"p";s:77:"64583990953768472760679459616315123765296280162588354436500849819674609757387";s:1:"g";s:77:"44955507918033524308531963911022162716703307186357435333598757289790265527719";}i:47;a:2:{s:1:"p";s:77:"83254860662706746455845571422799438616170338867584794032169432243745310866483";s:1:"g";s:77:"45685643686930303771863160720615786661752116869179660967345997698324429835601";}i:48;a:2:{s:1:"p";s:78:"111129822697130897903264343602791707637087284640784825057418415411648814509787";s:1:"g";s:77:"33126138893831271012720592684933302917306863243253992047196592803506800432571";}i:49;a:2:{s:1:"p";s:78:"112628096381776405952312106536719522382375429360429462017871313236853832958303";s:1:"g";s:77:"51091975906557044918432083900571651694499066453285507781185412784968687363375";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/3072.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/3072.dhp new file mode 100644 index 0000000..424a881 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/3072.dhp @@ -0,0 +1 @@ +a:15:{i:0;a:2:{s:1:"p";s:925:"4315132667335984456963558712492060257344696532540937013667412533700786332247247258786444946331529425538693841794686692621963051684018984641660725584842468599352742337722223201982634595644711492725368912027507353121978199347820593108558415379514513595105258771165222489083806690898826212723823447178708312310015373887298513452146950026717495376030244091940242203446809569885630514161505356898334636153936070047367220821769019996145996674921856277925251065184565233969540332955418598061766148428574177493374340178989369402930754868614979883166971458256934371493708837542870985695478010233708013626835966959313713197362623356634272123467707869487094589087968990428445989462460406369348689022330895916889128558466106229221162192180749978628677142243021374310742307679557586483044238163020079196922979237255175192476288945150100440813256326420527963791569079099711040208151967784056080661234151722826312967586919459049069544595121";s:1:"g";s:925:"2350119018539224581317183252415847335247362909293949583819480136047741271969210563596649306799079103843283712608283697540038743924120135958735013054518494349752063516955891717508379841175911890322417721338576512047885798171488037467431031588786174344182791056606242306674694663506097118828767635753167597448122585958034103275031127729578917036246768917035692891012572814906540367640104398319921957224941616190939982690849656828763901639933734397922127816773424555700200021019174059057777026847966427467057235198647389332182881908470536626080808572135189622957429698028030428044157396315681162976893222692006884962413038607537527910664266091051241366061457243810458757721091006903760284025909160005959237519051794063104050293099371887370635729203845201869557256890658540204361928706031866241870843244741068763076973016656112599802181801697016020371090086607874674384529955316111291655883982681716521633771282897455399026015616";}i:1;a:2:{s:1:"p";s:925:"3661665842190298063828176732846293640919222353827795349002605449065557880062145536666215271148836094458623660611328032195792228919690193380500724986215448719904848955793022993600439169495143330203461054069338359490025694157088096493504605335762051029513597551864863947693713477128581978728520431114298665949113705627108090586184073139382258224813404010706205790642551006296863042075254071665147777776707740858091301988442189198081921256690114717697424548845597164325066843431117108985133946191000161228877154348382442536080406753876146079547573447857543506316262040659783540306099921979385195412728403628469824785302447054055747600216083577156808284736341326726682474972377807552581603315824036960973343372464052392517539250145685441328689733886997264420951036267016242264588569127122203684662610471625628303236191647272486039447610039980545441951351603094273112696986635159781389581049218077713772074296953986550297559008921";s:1:"g";s:925:"2330013033015140718105580780000814417623950544622555681637035317524295725985949517727962022017580560547563293597480791009886152631504784946677322944135615155582592846014602079733324813222482088145642952216221395168852932599656493754737300222260887305133391964292346610726404829045255391259296098591725039219968328706584519797363720774340423627001446486074699770450134070947337857854387198789919314090619138465361996989373011459061160925315340539701819845358607233491365039690895811239620227497070217116286298965147073584201527403505009593615264975257954666738146127058521902348882467540296125841019084888051918146042420278637339312514698888677245842128922453684441718030263138973029024870038115729105821493725577229509289318197508146609933674599620814192772205023194161979027879633561410655349209310980358414894722460169598481382405650803898146510326139881914420114730680235864699472699337179513801157570860074154514000403217";}i:2;a:2:{s:1:"p";s:925:"4620590045169368554532593574486202350245249389315730607028389240974807061808989952188740674157236839851469650650497483374139797687030615339039402226480050369784359208554913778269157347633279686389091589520171218211153475774540415272645552458706556134264327307561935711474110720994428353060180736512077595956321907309914463979874348215571655054910359837251879109577142329727462223158307264068910944642564267328731048817042467565187797605740572389597584518183277729416430429630091936961437746628672624310534088245570212333926703546043476499624595458682817300820597092118377346583224950405123201291176579571288281289104180962553921641572678604773303321625513910966201143598343781696119013034400887449687812871458717959883805006700972858977252426902453658446267639459438200247621387492006492376809433765553636040874894552140340528827784386517413645617181947670553072125045523316044242271231323303187364368484947845489395421734929";s:1:"g";s:925:"4366118718728026129585368339757372747812283277679825792704429091458791780869289357307128615576667018996813659099222894673691023756762981972867802440998213988459504727363294037678614751628490500713830852051760642762831242205244282977478949802790510566492875314319012587861033111945258477032234584165020634787063563060226904559488259306239403942858014394292642228798899319433517328106045603152714304240613974941203373109764879019335121960200008382571226974231358956539289857770194403260628288818158346951295856345578190002005441993276348035896883906778534112627726343274478915237297608006692168477579982259987288186346003808143068013463951511936961124877635383555597808864932642690164727423911499878793170724403696380993997906824723746511442380237096215284266757159081815684624425650789580133463950720950707773341517945032379999366468344661073766262067221609371947035046592874149724312790523190033822151871604750768215833346301";}i:3;a:2:{s:1:"p";s:925:"2938996187439733278190929622522349944345060330946373463011322239057071445903273028665349335001895437955186644060767951101216675384067312297743697834773338556625400217742556174036456199954355031134394408805378315265066615370777047296269669781228365702751437327044218920674379042960278113164522885597710245635397480146223856309389521917307236756459113545853621634950936911142251242228542261800588746461446890339913379337949235490176799076102212171841211590921810552092147568351052877446522006565330079402644310865663450779556049843233202465628767590866799950861383808769840495381903661354708277489471381562306610182683334111925952147645515746482205266484657014142278865721433985338001729049063402403614948416123352207951387320155475974153744398545712952250022395899483389410938264851959185383988391347681515064735631000919755110370081239209119611210717600091760641914294069945948628410388786450298574688846037117458099372003627";s:1:"g";s:925:"2188180360592475474255511510558254820951280142973747406967025596302429430733726484610414308155762329822727719986011952045080143567144989598532990383934540349664426078338531224748892840652053289950123010405619591397905078626903456138814817195006903802298782223061589795938940654403773897504364770149759015558282613426827768639469348445280997717425425821254531982205265979720559293842189517050726819531061697207390209500076548816157640005607651402255706562491859135623242147151448088299859950249040363472544692449982136960186451329556524342413573462314348428383404582280827585580746192926542393278725777224013196865983526484755349857827193710465770127820637602199711325838042273973465637657021369104329753017416777442203610305126338263203859718497497033721924008342606583384236874030750708458957210268975685066365072240616441632985559271286231364010642310503874912295276279464065613912114646430165631609556704960606196917356495";}i:4;a:2:{s:1:"p";s:925:"3204962240800723816455471772500630089000997534792113265087913534933976812754741314152333161722136535323947418298993649955012010494800707515359305183271567204804336793561943241504957646985792902563473357563351154295683729740121421751902177385001324509438971655716930862114523297055235704266831648792801588667356727807779911488187335905720474875954132537802816473672247617675497279606357395091411459187790088423865644531157986398649668993393419306383003614731055174134147265802542990950181076842959362090886536566361672744257109196212197301596711897255025124713698133763282484725224264158953521633609828865037504253513222648530444623441214553533356064814153695805473899049725283546166491312381083067579387836842892134578905238980750575603676463825053338003879697106285582414982603208225997483259925008443212949824045922036211598364431099546267769245715271619696571301564489744087831121278703474351166052668283302487804660723399";s:1:"g";s:925:"2478210824019551512320915125791813539617224957203021574806979249207018870886399224961077393046503339639638016501910140228410535010543227950645082702730670128355633599633043853389737970884200828312283306402427477457013888098152394453630875646221684016198476297387503877720665978254224708974837278936309165678785757023904855038581289350871058547109434639163447822004571482221163644264512696822041373244545734333000574397644794101152145506432007404691930795867589553966229970199464105294872145069453531632860004871327511300984654195341632795521954496300167312104321888325452986799014818028629496909381762367856301721729884500546156599040930590095260641171169582643120839660452666595703196302210006721682874519760535561899529892956153506747158975716774130631381604630449687840599933523401758295813794558297239292235091793389815370710029502740492588285871904916835615638686399306444319652719565021842372271724191724564878652899605";}i:5;a:2:{s:1:"p";s:925:"3858495699596293898688375773110502441666969420477863823398805799498715509641562514051656731242905221702517081547027427844096728462563747228147262855326430782781133768087051811345578632161234632529176390004908409005592450781741043991144437364416255263991536844100492335985214082240310081219687923906385177494626411448945508588432558284500479260995206412930429039508366816784869690714512146751344758083063138616759346381314079908598351217466487073343070055106516938750299547561712449231665818370557327336756144407998326862734127162566508972390201780064268781728836864341723391269404459991801391241300508727898273827505495076344038735675175327462642474409362152783304320466458748710388940666897294271020065195620828010332760249112589154219333978627293681202156105282137065180043669859728816043574692794562625562528990196961932065149331559939634377062532299875002483921931262911101879746604320555198841530133860397746299378909171";s:1:"g";s:925:"2886770992828075697537865453212345955877233763458923987749867122711936037323569999431920041463158985162167680556614923476438031572260453739278044543413267437317254963067126570493942182096870591545209873122677040821918637446656321776278694479543818356320243755830549186685055812353557718440720576848387587878449845543328582856033075009617490657544568050050627565735736537270305317220182851115960039436216682573899064906440041083076258169673094384007249539021638076358510803567039584750818577942782544780707619050944193479637205469754870583309276257546564407814918646615385884198525006539391582468689218016193841581859343402584321850321179203289140890633308745187336976456718386359814499595610986638615944560401277989413598915531901666808033711396337479563958570717739601600436466348932010006348163460342190614134424271117916987578687455994528258348706062007249333872007231347444454900634426076055451830224745288581360845627478";}i:6;a:2:{s:1:"p";s:925:"5130943436634738151705983389375848779869639921630081642526416959069902317114236046229660665455811266490019114464604946115159213191020031168168934260240370208638654661224411266801294059930023003906358110167332559834781729140290434226060866720241002885723300338170136670588251919750642109993266694093638580072006610971738091420452065294660969649783031963891317158100456532483035292435217535729908840133045505215372042519294173893500103351214593883943376369844040124039643965754086308458900341243079112441910048778603970492763910684557407948355396339668534357389653826573386393829228181277223985599852219898165629315031588362818823320107829227064897785017442539383052775003927202548433739462447033947909704568378992953469486988508785729088846061201035920027461970780780005619342436344516177296666848839057209008013560985064308437927467930182007480635819670195139144192726361522119994919747844325562336361309373139438239770340527";s:1:"g";s:924:"260934354532320981603346232635496122387716858013756396769540150915775328937528977396744326608481588479441907495821544047901506468212289539823406565234667220744710916377135092907432145546725586575114564276697681144703692013998160742003993464829802606364074051703138197052383691108529469174089994578471577368442017913387128969303763416195571202078647334505305658123832338834320953526264258001677880912206470170147306962815949002226615725629876836187127422017883188599155347419412766452003248835237735383926323738507826527365200159082942467837860566008919490947094664770207577205258215568849415857873018813254495827577038620419781260925766984307393735044861803885064315173715497646285752656365376330908367814242240442396593775595814974738181268072163021064089047877008188717956674409081793607850233146167883025620608270429316190958126029128628146623463833608957824959491480916435770824635224049032746305841209922133966435713575";}i:7;a:2:{s:1:"p";s:925:"3998840508039755798914320501014490629633052238467381119305554316434989486292068483947090716493975560622301669729373235071025195401078218707185420229393875101630399207091215056995992392328139307281469826040928322742255751493207399051987012084305120865669683305722438138119183724588731142858758353815441063774921032770684639251029994539546020279344296398617212421068732532036375421965908920123116181078143585688105962725633632132975138406008174984532184852949383093432062210148181318477580417338770460510155595650601653410411127159435659493085820168746161620985855719309306349364850268313653433450566430609172187269909560999133704305458710444090927702514998592430411602512950950677351211101786937984336899535946914086866004703969257088260831279147313068118927684780067602116963127114169381639014582713965741737756250918519458049220786586497590905817765259053986430610205459529957290191421398536494800885250298043501610812086059";s:1:"g";s:925:"2057658023315995837814244302674473620221265305450883707220933348948320037525210388745649180389426087096994265870161669866990950147659456065103511412373045200462918715811677244100468295446635609971623835314211125623908520420064733901198155337704396419102815759539371784037536019669543759503815444881029800352829496591835802768152878613096427522151951742326629173003090596367204419211777304661019230236712647127510964074174767247775500850831099969972081398582452465813485109958498709530160165023164241692106229959616650039604984445666426834802188289028501595761306529808221137567116017979084922372919440488146672329182636452142505034221383623140884633533656641179188863902408723787496018605874598641384694800760826997534273409829898340972241507784345241343119164153030997554682570323583980126844499905435883099703450893660347945613657017744862281043902594543525498698273068656471269751607765332642113390293039115043238564103012";}i:8;a:2:{s:1:"p";s:925:"3052587646542902635517226086530951609778282038835979836249050671063535821665881064115534194204580934832939396328177556330734842749443237143248792953029921041776669549143453117786515142880425148009081292117059998939563969347201402547392105917250085128493129385727535383102647220914444263467589044844337906239611382825797699113671584199753687591287631042586031195659928551456680508412407670669265264088757923152615347875842767338023502709093266175409535257184444620178546734871467900590765277006865565930758293589914804946915189387085191740529942130147830492793703181070245326162092621723033190789966782425551751916096436898391698804721111476077819753921137870698340323664493890573693833039924707736103693436805757466587652144690484910903191505956908906533026489365552879965712849384865313762910366975745166199472841164150446248515130746369706711873108862393430213900655618183304463659316938365139115981162958182988581222516927";s:1:"g";s:925:"1528970316478521813353997032259747601735191992648561865246322395311799713363100683965723354220895113167576481333105953735058063391855371198236588067407381815001036506237172664629862905959335540447703914728848630930034014414897925940698068311756073899855838490954565219020692805027055726873359828123353015856374380126481052959369002908628607232632399137305471086503099495978391740843530399808236564911758061281813986256460744423707435462682152330795942459476567607367164628721363594929691377187884244564552802877253956518878163768915048398159522668854881683427429061145351151903554349930235654986427715339756801878218559049944808960309764150281309751390601707948395300869715492190359748972888505045582622937580005700313037128036774300920485981598441497630716284566747825244929014090865919371992307502418429354359868713615948277531724520475602562297248371114923521826670568579338836795789101865793989006496968085530346267918952";}i:9;a:2:{s:1:"p";s:925:"5531849879715624114545398644990869738005678685505540581620042935370633299520260313401427768894146216872345400617660584943174470760956880835234467871497601411655568407303235347829600176104883692713487675318046495160134259363627993949633466784575181041587431530962681787466582441133960809822774283217984130286952934282805180703291046761605129877507724814121136198583199545178203257717235268348901238327943885189227904444196292052543399633947624052389642080706804402135633670642032342495348069576043782932720813101062926203420693682305253390383204671688886280531577438389453577025982803872867504594741277557443656199282929180417954184489501788428410224813973812875429988763466872540945881435267196803982267101116870704184342151713958770562162236127406870017210783442933149316190678070324462159427454290303869639001018013226081887979930030978578604010432508341116317743577984812733454143165340372816341180317379877319200301319667";s:1:"g";s:925:"2917203507661957440212871046481478943727282842611244779763790996317687687796653644637232299359266378464863671571808560817232238482565725501100973646925473408457779074219592120515053181961738402943826605763153695887609945228222137505734408414619308585763571774670754039876344991582623796377907891591585728148008903192190841789422084781332813849714793603695928341589810634401241616185097559026709733935153380643027522004141273257092132215475778754534758221475473429898883941849856488515465149480083332210865241632308051267913594510037802419825916838542556176217263933025009075909913259028976931672933709617760701659850089187121050442463220999583880976029754820397051904842386028835760327721598037944871605455638114393194929619554005022189733574969109237418204065654064456677392819888022252866367583881778675828738176280257941491838252446519301369815272120687557955763759094560889666704564956244599447217316300475463318513732796";}i:10;a:2:{s:1:"p";s:925:"3780562069767071462751322994770531351248326639139746208661386875034130015506630130354418097645520065657264914599050724477554706479661847220716768382857055005905302806412621168013005582588626824922052982755725555701387925243647831685319030524024371191569096439197899084877369353216936786922609541760719345429409766670866201565199261221853312704476568218496413509455308603318378296585201025188261985236431551746143598777692007988149131442040972036431906297580587606656327482072932384415225423905971270901365306034795404320749074843351064279683995518828679129623086949200669166019135890040877501907773598692818560350813670479817846008080880279105959456444566616656244687337953491906818279020434273168222187571812479012408132683674329632467563988095817585564356500304964862642571724722567217202489476816879092879112960700569233233874053585011615125908594694514165251341082992440179577254889736354944330288242522604298568218134263";s:1:"g";s:925:"1133287961193943111940342976118103953191957737288544130733159585583521695386538531116451012469637228291577079786129597894401720014158983191228672539807231618254286238108067446684551660646160650174057287185737727852149737778835119754106612692045654868897144051639321003403494071891433447103764027502646743853264024332835367920307722291151158519944255275084346803184632183174584156874227281521959717127362792889493841915783229452311712061737832597541029083298577988701022878289226661362663559803846378086132409935377291038042135005772565193607513077196748107849775169080596426552738120866831206312518873271453348551519887940616728190459956271984259492893170174757364668932703190921245410930261770880416605148022192685817806998238703799851284384393863608999974068468543901987557271301629525606959098052879304707973115293685698041864520817193468017063053778347860274934684964825463007204444869127699425044400604879544466093146713";}i:11;a:2:{s:1:"p";s:925:"3068095411998188584974295316826692234024209804719859764484108486572281679715071972548018617288096813401480545524367104865019364141719603211985383019388112559693792867918673138698433559285788103941407025538360390102089759681221369654397361044046355244026937545760739874039629458690284054831150144185217308188816082422196756222298053288160968786145333347037314844621246589018144013343953044545365352430766116812302013752255034493601043513298413210051345468193554254405709248085595245129593291443750091309171217758403287393835473936600741503786458631805856224113637086263988893632533383451766915290972161134332112947134792182158732064375840274215592185596628615489952577220097912306990091072175658705356067742048210386333029866371918286690399669681268420581708391550751044332001829026704722537807437823148325746846108596888514608080975020725871152050625645593846665828851876972185832543501226148782144492486632994901478570353477";s:1:"g";s:924:"159646077674815541181898471066991220537923963782148392287829832362514240966969525519270080706227499541479736397774272092871694088307637303456504900062713028949632514722351864440063698772176239061729207464996707945061729052663143361100233236046404449925208877350949615956983649392618970848410825873036033300136570007232661091399138793011759863976689419880440899963172456623782321164251274211971525927466329495674836200825606797638605022890014528854855363018329634481021113432968961232928182204812380173656975430286379350298654148640494598755820163775986641678506596595022674979754860369451813519030992570439885496972635686145130069609803924536847652164217943217391745627063861047656164990738165079744545323407641370244403751048259215795551277457068123515482374905320163065825080982452050801388367845963408590818221498979145321370138496712399590229047470037324389568512410801751728974904386709610858450879303893490586965176715";}i:12;a:2:{s:1:"p";s:925:"3367777398549863878345148780352792636611560568521571798049082045574910180885005793793126728459986561469235955566557139518336437368333358883318717635927678803535695555323846136098940080055660899782228359404434364204499739606477885672504384363680596103574952129514920432473116170872538969443310045437643992750804155246600739318381291924919382044092161074120741040663613761033649123287522847647043591147210241686928207042782865374261029266594448565161093433189705423188761808597916029005700389907296602885569165456302470201268341211857068535407463170382217821960728467862059761591092988384122498077996964718801898349667875615762194002904054620568439838282971943978910671633779795730872091204472155035861162792711306166527620004280453286569709407237219146368163001733562186610372433135202274242049506939264129559752737618658036336838247421419934890192209984634346973630788615414331951553807993311827232462663277269893274834815771";s:1:"g";s:924:"282566234821537490920271629731450751791326010830798582697602986370304196814692766945954814860495621040028265936431536156879768298268960424693075179327931900024792860752655474492139099296487961820716320660945382657603902779098216755977959044903615939284313278343537748123737565833900347186254806630856242758854544959974682405386328237045158616666490226285723259258560242438631173878709623850577125771772686579589896392478577404691200860585558677662940672521119454346512864214396333163525262056860462309077414777119126023696154521154184782004242582268895380068841711410787973048412003387723653218024570006248657732179556204944548185385219665849088495644860518610339322248090941354949187351195497168258030226507789218244254891196207707938136301397036071407986259710377170196867939904460166199673807049914536675707863908920489544130315256957639292300855511885137578488817087453901342539712110297865118918707118619415424775167895";}i:13;a:2:{s:1:"p";s:925:"3535384272507739371390456127135809600186371214324741418254646290954611392001303754670712294728733042167012780609017296164756809496173833266096270418632868985081715544299268631523609112391637166781088782274258141895327019496527187074403033663813523275310386981896554353497215916757908905790000167941188609984283480670859772957173439728154801756764969458163972781505343070182164319814653992820925111164323411776021534453827602054973434524749158514070173127495515407230002708401984918054805901149617888660796149248646762329259738670964578005232274408294658881682648095451587024978642353217735565744329057331274791772257390900108305959207275594924505491121911140571784508204909027105532907233569037974155947733655073558194831009338166409805336375694237481350665052137267368520421694282722206354086277014005346758155612783267077100275255177466584853168927390561841803896678741077551600950305942328420975221043027695073323234751603";s:1:"g";s:925:"1119627094127766829772500517036991083568576798245595498908286128578771869310573796614318558965773296738305720838059734422117498175277568498453999381892211638822962310789626180531534551448940276333857738877417497428774052153210839843293436387816119465485788462895141683934018108493106429309515246847317086612993115379179025962781724441313149237529166235928244893851718231946382751850142392414570892539596941566408655018573202199515090796201983901641953539712987904042812508073257182740282233206806436874681946401374885573281075164038391538943538739188358560267747478564509764088420575072117739801179730824156119304707225171826233403806127524192427836830907025371222786328472434381076462861211218005577398906174154337267095852996974622601430030358592190085397222144581217030220082685020732184769583309535060349556169532211738543599588804873402286879771608421072017103605372843541753819986226059435555938653678169271805135072704";}i:14;a:2:{s:1:"p";s:925:"4562194176144915101277745005681642835798897873495474402608365237746498633370539910997482478061801133410931468922790595608494725996965036959348492966696919596490096103508729764011492174796198191791155909955522446405625791491856359473844755837078803270025112823181994772241566047803179666255388737745465556951461374666502425494234403038996248077021695256107962233981604735599024291065871109632150139360918869800254974719289688500762129016450664740707011409451726661221355954521623690646442803371069043169161235234437004307481376146993512198303964849240704679431973961042676250710936961739893678332170744300669566464498778887300216296271182576972042027189458709055591030587939226922668108333380026928880780276365283307970658783557815994186092589841511323470715371300115114933930080499531110461367639031194670553552560568219145338631131587315044373227862105549876394176147796261524892767754722603204009262024345120417781993357987";s:1:"g";s:925:"1783063526443200787273402874050505315277582361331137583023716558174565654507897825561438236925691082458055937563291294701190532975370225129732306964365080034548430202086336886848043161734619160097756477070297570704155217306045516212846557646681696236719960634662894256288317478659187183031232562007126356278206248186444217073475086995834637378490918740251676685852817074972991205125364956751685343096061867387727716656368534256629567828308240954068285866099855203072022472167988681527977696446376869763607960806831605221190526541560948897865708484402569295854151464572749555731165228888295734781820361816426917777384572381759890872795386961361866080348000867683127021931442615911255342253637272123698141261912663138878997606751018377263447620039560096755190075892714993610328525690603097687100475706668399890981671741816861639279982388272019437387929568855179248661068150537105516997412483935882350464469157999820932346920856";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/4096.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/4096.dhp new file mode 100644 index 0000000..501ad34 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/4096.dhp @@ -0,0 +1 @@ +a:10:{i:0;a:2:{s:1:"p";s:1233:"583497364515534144620769172000044730923697202031727504127123210239564479942377515134918927524784673980579074340461063538391526339824976232063025052904924470995749954074102702957089466315511530623356782205508248825740639624859740089902822135926045166645045437903927933697296195582696814881142738510663498379289235009495727479310527226263007320787605409676476477501993212002640038117065851293829333612131166916933716569722193363513937135458901235668624388058292432629862283052489837307563350505877460138509873965637006792230289674917658023203501223032739662361448420491881958859596930485891068704262657955024300362541802845350103517222898174052640851695040454504836166630292948661375262574940854275967111471071853533381721303713908516806907549838677153020196484939843082018694927379607360137717235291722860519561948094257242530620881851290634352815110863032193710545113797755493485240688912927875280880745272135687311489219235308680262020676069196477067527653004361116497758712463399308993868628203477781594080634974306163916058933220903803140690960293459749358282932918972189491185206934138125324705008321948673334974315329955486619636903641180912157388909885148546517263298358704668849000317658586232775537242080876793052575872164717";s:1:"g";s:1233:"127968319472475344331077898173865318243419891774158869711828718403058272519395942847739630843783440496570407521226003155993983926846566690798874858577718455391682455892223888282652593207801696315984482994206748236808639469753159247631285968088512433340338448500647218310014726139052545519914995413409746565031526159760387848380067349701191760120575688747503588506736225221765446130332518196101187986453740722500270894816925266412425389536471469381597650467785082390406765429913443213494185648481561518743324935186205282661338295676001165228783434910786281187086626642658036158298936580926944325449474152492970083106102594548633509876112245624678116554682380902585210405140435485164389739462713596222796737961866604089345760320729771435028743520537401721331612703333892591161293038864926815371098779656090361303929418714804579407604727579892304347250984412867344708385548522005435390223733841611446899929639968855580274150749251312698516786442922382658632826376729122687489867685434294153633514532824081517876628181473257432770817442813124369799504124961040791138045479518041848867260535046612877228124634309948497345074597014995577791207765501863118075962822337166339167526666330102483819574318799006786826531261489174152125772534202";}i:1;a:2:{s:1:"p";s:1233:"644095053480099091939297858118510986022393648400040771848173413661472143191699322140393580778380090670032891398559036461541070211706428701541351601818900768330398818096052423231077739122485148413641340967644528288501235057628326779619886675978303145968323618694464033676551692515615682460530416294904707165146157144987891911761808025802411091538918844009954268729819844953069874476050900529268165258481055331546080631033547922767585983393765655588560322256827506194710671637768772870769834318509381421150469657835696842562300393152113399655413282551477993943983874755875008370601615893956270286590833324338386236912861203288076957651978605993345863806728255193575092771952494482786247355235879276588474691115246553942882015825194543304753856233378559305533559337703203990700312254477385660339915073329148910781131702800669269692100691711240004144672213498457817651708910320204007053298973019806994514666211161604549258750171462260682389646997128719501642785472857904319090448452035015310192384694472666994345420665249463182056689421284257367184727426519626237050683000133883319859749913454557109977645943797147207761088834575973395913233371630670280400262776509177911655348771924491186387978628358113653228880012165121850781835748133";s:1:"g";s:1232:"89768691123282200273250835302117971048482773917025710167907764833444870099082491710125785724737126849201414977998097793428716907619355631215464414042029665794351873443581002311352342070262811635855982355133446221245675640049081025694562439753757674961542906344974660712521171173708467699171410627857113329247881584047267375568447173390760619832999450149891575517887784502344444374191979674278777530444755493588772031447750816361643891131010868034955637938063643040258792797050121847588179905543200414522189803497522647940506521080392705055063912326461962382542669924669626783892289923537801933181809583637334195726536873813665338365672744499977500454824015782399115735050243010932135563292304832389356097634421958844359608592817067687298260497048355701221546321392944037624125460251388411565536044959602093101251148713082901120310712110250945846908369537893593889855910577138915381937493103881427691939365101855663162968517484827254803505472068266675648883873179408126913733762685173740771676195913722840849674515884752692489338505861489008608258410033759076296295109067248910573099437033937947587453092321168613438797472805045901054080309928241664811040669679366909370512498557773486141885686117459727194901102461845307908569317600";}i:2;a:2:{s:1:"p";s:1233:"532066646043903430528531198799450191282175598742954618921250001448735653262660514078933937412646564856328300432618349074670575210471137479308656599676782686029867744041341499987217319442585733211108770872807629457693551738273743163912712947991902397196643426249471123290349309622852982951431128523211363481720767632275409727094997652747425555700771203910408057673037946948980015289661972528916471071786814695958220834200499919631633188207596644932186099425834405442983403992952942254049551275570962621513810901783576680109840078393906038555579747674469371579619364205996024551188123841158209735986236108133045601317981547026784181436533153185277324288880485646894594421478688603459165479261860263389086018757182921909991153043223366670612538754356707473045271074357478392653202116322497521243644316279469134695450721130875739701496153521607873295760755658643712384624306497896190995965732533939539036696648605012419766798899358151978186058585681072604170889939882081887687877039553196786539987847117171555789374202715508790677648591509775834020846216973047985050084777424619778972017460676420407835912828488139160909012797820681272024981216651882886167197915950461158262571666050162064889928434160092071622433349237717394286981570903";s:1:"g";s:1232:"88019875487376264806598595177212842685348996819137453891069396270876361332627678497976776584898521161583263213197650880795825901107200678516836793986000818559956235836401420020977196840780591296240289055489684623759281051849436675569974566414464349186834037665098011067297024633109006155906972081508954416530556429749768193864239792490253166528742357729061562213019250198539794737195535209094996535044158932610816334246967178866460038531092201721314640872055917692442887757298906896573704281644069767924051562056098464867189799317199958325251056019942124663808656713656134457210444039223292181732025000379136084470942258525079649944952250491152670202869296763020890767014531251289534932496252825710973791866862020857292162810797821091684253912935784170079547394373669953308727375174305241288914357603751765176389654002208740589896011833020113850756049943560630211773283686863803328093696753873577409164572030208865429768237857155625447721967446539430209254438537200859359258164821236947828318320963877520932615943026573345162336913924436395993083326298556575480690128602849466373950375115049719716275590942926575038366658317860397980294415354782753673696615563230160745561136671629331140944061868442787441624612522802729893757283467";}i:3;a:2:{s:1:"p";s:1233:"624640865987867767216987778458789932847491075900224719877838311942749587191696555082537209810057247919185478634348223780741315957546909458090180531717911688191999329526846600555962065000508819021170102714756948429438721648737316448601804780420441612158994209226255131770594803399997288996003939416523946117016867530503628253748816823450873875385453973144581900301687739073722987515945552803443310402531595814541545187577977368505796408386197398340547063464250373460631392626155464052978092560822082540325765365576339965842818719306496724608929188363903261414902415556654006254232801406980895747585041808294354531554348429999919862150877020145670979592596848846447075213356249432578869930774335639823617193789610082309896552192367995866012240549883616345621459568480420037929052913195278081936958815044325239544082449262392188319862353535913518387672568198494110767287509097955588954933063386463158308071591805893477233574065816771174268570465832008357759812349254524175799285519545046477977667617505357579209790247796018912987245094247419473335965201710883238258536291075156906339370737434861404241686509780076365867254408634199338970593379961068090472072015144456114974956845793333134680626115671837639002307409714290088642141822749";s:1:"g";s:1232:"35191597041194826078562114780735309741604982985754459309396498875763019560692191173444976369639938166654451464209462496790872478339726389561848827197210702807234266970285528968148481205090704325620718921392127415038829344379920313399999013610665878283652899909643113809669797186334512616600176863374919988913482054118933708571797485328542935271364769590869366320928740568596567333625016938554865984246979429032911993244701343036076327077895570105943801518710651167585799950694909721052593057462356318582261615716693241644865070852894386957557579428336821004901863993150157499885441315836629140378243424067292782630058302855623369897584166680378736284119663412143881742140461361306675672118375561684500807533830524476726884266191054694962751113539655435727972521329610732240909280735708228480750930150226583351737696182711639764958097426099554995921762324764968387367006643004037013593837742552778489101189681998263134753899520604701313718970176018289465390649251732561908034755392979210100206706354006448135056428690542195439592042574114357901559386110762176368326458844181123228590640318361686697305408158142536747065528132296806468209807840457105675518612470245610776694393440418377981015311170038436924081564055374311557417607093";}i:4;a:2:{s:1:"p";s:1233:"779953292877005240445360456315811451093989451217452508030860903937948632517232564194001045906512442404742197613232702463671198472445385875490629026457545647187005442021788241311030738017425249356890025141343078528260496749924672452406075112878301736302556131136239278896535599312350677308329009917219230134305610628444344974394549039153542562509186659886824632357316157354854634051235545971442610744661953164839483107009009346767308487792275155082094139336899974160251049700780808146182664975496208843797554327815374841177775475470753571939373950219057601827618515306432330286536605787954416979600982555100385472096930721178791752512391165009133875211243325504566536842828926470993456873318478637441852889757460147342402972838846960221083308995652368217350359415335244963047436742701143102588024677465021067291625650479124825035107916165897366503641946561566575735977405500547013903880111234392336910724291341358824517576159101324393315463915516386113738376991694655518288249372828957784415843462949902880245560891397892739131312020213605637230016009180022550903701034602194339314782797872803409177330851533187493953193297474038559751525473131866371264573532977654516287334052810240609848244155997212833756639636272174820013396312043";s:1:"g";s:1233:"294584733932594868401273947792664024465639212321256126491249920101434779155955057195485698239924329017461116880418431580860690198256687586504932112771781527472902014259770658191419896802154650562294560755398906238871084453999743924751028154628422747846829629577342744556227521070771812923096114099805415935489724190764717281018532343462505964115811767991916636980116921636821712757318995497860585675395280337515465551865043288028388574578233488702804947437573881111837814063218842724966602537516781639806659721586014263202580079042963974436751247205517597185932576168824250675087889692132232635851385770662503832152064206896620142668420989011972190212487528435737892772025331837080715980029846159723498651207016895785824663915902233384231216633900413873894642363848877283294953641356035768665921262293701560382755702158565436541711046082853970334353019909184715426280874888137220636901674190665606039457943452297962490049336271214221544690306494924629862233459637759750174777290138782233739753168070900498570457956229850707058644987113995715716956163428588853996972713370837440713495127681927259759778516099666631791678009695621161317044066516618587362656131183202101424543589024791455207942352815475983543287919183904371032203398339";}i:5;a:2:{s:1:"p";s:1233:"873380532309522498799467076047576421250122925013979664660390100404370691501616536937612181194210215385094308810935516453355032436029463448084830096699391779359746245438975644149556989758362910981654674205999214419876320686094257700096069549948049688283122733439454755828610162659438827932114026255697266960943047298243914159409829140192254875858839248819066768167056622706529514987599954487323063574290224195367474347078198738515038011001166838478656586521264779718412671705536875203786037169126817703863736311251017581772657197321869901340255518927881204882068953687123405069334086588782698178808285142618320087139859152633355749618171526326904396259187880016434290866497808868783791697806208073482750736837746588717407322376245045837690624895530548374670357643053563615977343334778531626732690936180455182800428340931549713296236365125878591019218639946060377486219755483934599502713465029361440021225215190440316806913581079429713281130920337109109968340294505380581259509433693746584299063405276989634968695476794323908106754680577112440836162750947562118744950062391998865341718636027261902570877972713001428190326234549687999438140714044285074849887079302464721442624737482631924677458635638691593298803949298092379596527831341";s:1:"g";s:1233:"758266979649634750053202088910057283279263674287329988444340052724311389269193009783562375537401202888776496447338931775147711904920703696827537283963175676021760865387600870343858294395979209162411359873732107330784778462979646046298376965266583951503187441920319736964543046884576005781229328830643625640871783366283976625042564380610348916186645415586569404224977599824833363040472887288347263098569508253342424423209373267649416084905412233426458631222763815788848444066371125839088516151679822191407136660334337085286564713698597688507583147689563443525745241725604049001370465316856947442952510085242436423219864605864763869175481815324893258776941928679506214789932269935689301480992417308141107873076609787962472466286175746092824143957343107665553282526810645239903262112859746320942900955250909496627942784608117271955850658074366406923494387446533368326132090056539030150773913311392872050216434914799631303309024899984742422197090631532551201284028292062615924708408971882417466702084021943910519367667033612963460400727150084937048056426226974685862850060010300637268188682632116677120260511128669920683716643222316216784775954581071726728409507558648533136253212792396324990814732244668277612263108239074228022837043532";}i:6;a:2:{s:1:"p";s:1233:"820540721170757832244069162337471103623476021288701868127073481020518513764059295767556478640853661563409236622968593726091778348462161731928507571220398659730404245516726938439362479434547886117679293434155700084261057742021144960140652439772307624387556511736993557966682791065844618716738649097502276329615062219346852005641718697097097782883420200607919883986913139144488591155433090758531204379002847725666813781986224875075525417662853261153741581543945607777600697564688846706055314188654847180395320729670567990844583186709378281514284364374502984746208421004209976855078742522453310734735737052136742501777211668640816493194978901543793480749997538280229075960668940280718549909630114855675970884623264971311921109961141316437324535007215935055397677052785648645456667555930612714054437409386635240482069841343284036219292970440424707137408141216995364660839297129208485540357564963189115710411734704844257579489044129249646178130436474309823211871068594090095315504146217773952155598284329651162900872622016533557355773655411235665998996830829344059040931938851410102323668534202404592220853769884490376176406448321479680685841476647314282691628643791285643103333090834485277249291561189117394793678546127171798204363654999";s:1:"g";s:1233:"118438406554222995490123100896296072284476073031088381488498100505936955217546145811103101447658588862960079461001008094514531078825948036459975111330154054589791767944033714605441782562062020628113612970028611082098688775801631829875718508746607497972977201262883699047004148818835420663835134558082957066615924062809011642757377022828878035666649119894745815340510628666091903865601281505273374757023093390516848399591138012630325640069208002561071381333590271743989866484109505989403140432055596491271598758797334321842809180542487085303934698164071964097112522597852061996053697857136401134388466996155470013029782309435510931657620253973452521674683005646717477525282015675525891059896139716992911364488297600566543965925779727906128807922294910498484009364961002440413479277055779323055505652009751985075907895769541993201483122796667893573417690154430534732977024551262494631887093900032773648298216606625817339752505700287724821088277921064166742115930436091595435627279838726210384248484480417510561899496786492261565385112614452310735454140962760476036700738713148978258062283302094173393505567783695903421445729783145650782376241212257460283721766165927127583979756408547158718516467907168314631126296626106399012896760922";}i:7;a:2:{s:1:"p";s:1233:"548880106916124787718235316361844096017242216603144403144526114223097660636847718806216931324619711022631163106062959212363723195381526736692774612020061813829653306315587138945343717432435992013532097990394527621633009800856598983072366070314358447119040980012948724628709116117189707683723307181824637091772814755053282879511298615833481306573426566522411619387127602920750040423798107009014518741868275044792965816427462488022038905991612182102118898508410762260881010537117030246596093467647073714239550895596975301156766220816241309120866613668394836626003142720617951812627374838731012619830807432088483035236114552081985134001686616174564504848954594625921009676332389570256971117088453225374248443883042402429145636745540299177416612931459661220551034168122804916804973490302014018421895277362958656026655451235268564523782734034433508796366066821960530130189148245225555293455679309843404439477749993477957986644877057108538055208598606328427797655589145872355278700781305267826336108224166381248845658241915723389086597462010302103075341521420559474409270384789400219607597088319673340147157104022103303355849529821376234368920767987306905602181039769947710244590335945964599542795685010716255387218781537486891263221112927";s:1:"g";s:1232:"20223802225175087390897343320850575259412414582365900258163921641616379893820296366341965682900284907062971541417669673457029912905561753659662613613090408043698061279146209902763900423769234184733822405191473776496356217897290585702815784533532924728422271924212069389174850591443519005141285468141936966795748739746034248358086369040187336416304433089873610665670760525566546042619321022059403832424205289997775771777077392551377964858245304204808213786438590268481000586378941835211494995867689519660734121997341333890748026237318380388536238585862179559150130910003868306933185293566103091846923761609579853197184300628029650990023543293857997327465196890887099397843846926207481876351313608621717072924306713736639971952766086054530863325280899405617010066755700194504014455444107107295775375562685525186934121122525113890027141897356852125711989263516247264495095845712242968433910070550732088599140024829886653846928059492507359211886677228369134480549783244558011064095569606042620727213670092676737971036510295651529169480281747758154694909538028297129220048405979644814548919795425345058267606850114959452152274444230498221536709933406148397862354884914628348944049381266955798315160936114361289570654433854369533954705453";}i:8;a:2:{s:1:"p";s:1233:"859827209309634451406960567644664073608247843009655590438711626451994237792146991300287173183043087832637627357885878113425166419391451008964253017859106980949574755089062271358548272263403399922978216835737548298249861310607947556415556034302868558998860823948248446165422188547363376777494491479001516098330954311057697326851394720625724257100394328957986761641854606124802840570257773148816822354261738259531039998883429898993869241428003530214497814160450219313370173133235288963953099531623951947942169808487031628056100171564239864604031521909623635333747729708835356234693587117939763260100382872254128184803886900010111804500416269361475869077112596601699591963646940856023853064774037109855507020286576768786457719852203457601105292701917411355358360008180915826892620146216804079957668181231970467450738195144959372918201556192737905591268849748076849450465624438990383848388275522080203010234806683065220626452401491930502782559647732413722125655004274543457237315659249933066729897683797374439150414939169958117731633454400030620745723935086781132522371020701818644268478312923624781333343945370055592257510945893105577926435083566227773496745193530155189970622341845201168222461416348334380933548210599367604096086090031";s:1:"g";s:1233:"230387772378953200845430198621167578746427053857106869552960647982050572318224374962229729318382112349267315650146357511077064239693374841128343219797847769239939047378499174746908607350206935258194400647418437285235785666209175674200174882847856952420858925389347085326991590694347827200509909061693873973915463890445184012205857463974897571179795852429001622101699601936358287818840162748385632350581228272919083408646468775495034986097390583012810402185490450971630710284503910731398608923153350898329021751448849831559422869933412530221683796013852820003288717846727373190487598011276739172626606757714413110493418580840734528671851885868087367383538346546521370562466473234525297808335768819817289553483678988238007207218147310439910350927886998040664415744527590859368946235772414353195300301484941043822716434443980686904246525697288828638259424314558719281240513234226046446424926580782853900132686543224891646005449948001898781977906166963632765136243677729469730024277517040955568038819858727398039755661112182198876426968341181157078405926004559691091955506127027570276433391539963453802988248330864677240591327448955479631777762550975509046811958142442397739295068221957839946052657640258744394034254689987292652633118456";}i:9;a:2:{s:1:"p";s:1233:"888312033166526127955988426442422678810001433938919113768864201691207447938480718447651596351146287878452273934665645649043859986405865705632170182974121295125900973569951205769031511097530139546014516646694527186005154450959470448708609704385453144250688731002305363223573960088284188348397281059466430645442685657932089330915980881062245603052940096217287240951726953877714773688854411975063331656887351628173396825718989000406598772820517406925327492499704674327124273792263395692578753695346195761559571297125107450248914179643699672490810996603297769572128091365013688121379583975298121444209456702623405799745174906419004760101184026174045940728766575978641441869213635347993806018811545320063737880875998517629287431368427977011917627530837172234644438473851135151107087912257495260349195961101296828898638793317970645342060752102752379914647648982128417274843039283608661648219026592816346785321387167878817414981419419109227388794463755064739517746832189499096571596122425045771877069000145569547426530405158751547675856005170654409360257831905487455222746315928001559373872546190045505532925733851120210509137898153408570417636527268501290792622044295041907691504394440632534766052125617415332728563802110065175938856406169";s:1:"g";s:1233:"179940007155666987540991580117873048905237006140702783008925780163608019168731404115337759870972800567200300584668821703145485990166058723838370280255537348989331971098418891506333674538143418541493307265504601442115644860526047208656065911053559381591829532675505389980301754938963454618057645963093135745943859171388965425195072355354734862364577087825126597061480149259128737757766041549277714314756340773240381942891036795710496353770795880255238193193675461414418611062068106108271650728114837783741653035474438882611428736402606930331744059645109969995029237833676333163067205389180550109628679575668654874209389529098631801939745991166555358616979680709353058264948062368326747488955208117566150951474211785455860405703903272401304341357674522616532901106765444186621390538280943833741378449548964875421462545231416352716424331619372720208068714785982701636016598679429739914643836865937850288574299335867496560628657668315502567636043263564061553699381494881150855325182573643444832676577058036350069847284842579105276011204912451316096773591061234269638903316146162987031233087675096574076556129770577395455575930879255275337135879635066597533030050445119968176495966420634121515158768748603982389691514447198255614191166257";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/512.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/512.dhp new file mode 100644 index 0000000..68bc1b3 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/512.dhp @@ -0,0 +1 @@ +a:100:{i:0;a:2:{s:1:"p";s:155:"12635450358293578591800910479487777169852570312773787057842183813945647605523761696818335430966522345697375443936716089896542284956173599541622185697564549";s:1:"g";s:154:"1090854334822591173512321403882655677941000410006358584565839627906165764285596682714148816933751400742491135486102083999660532436748158623509010992217103";}i:1;a:2:{s:1:"p";s:154:"8330760522092340606922532684920340313503428366729540863298817169536290179928809471721822951210171987458145792759861910013392392898179284657620886263899271";s:1:"g";s:154:"6322863474611806100787478309308593694232218046926780926157713238112945658789791537699650366897949272407498804399412240425281933264987477691262814155841388";}i:2;a:2:{s:1:"p";s:154:"8467874047342751270076186270294407678529363428805356804220110177077751064916093040050731559077353309166409798407787828591262171218833842208747332259453521";s:1:"g";s:154:"5298156252329153668622137014101607775181856989956252615676334754324796406326471396781499484185229408185326895046610970301850604221548807384662295609490180";}i:3;a:2:{s:1:"p";s:155:"10026784872744220323680724914118782861052640191389047036503601439573675679926077705354387433852018744814013072404781629568137348655795687816934596058584847";s:1:"g";s:152:"10063798484541132819515158210832792982361584205561672291343208772351650842776011486282636652726979910012481237423361696310602577790362811857800630406902";}i:4;a:2:{s:1:"p";s:154:"7500541218184559328485097477496345783681177646248979806799560614429932165977127468017169371472813198043940205643917781543605453184159881626674120202563821";s:1:"g";s:154:"1020503261486206285757006767534006757324059372861763647088747846559779377341132189129602840152879970678542409250058810084771680171886011520305323008135467";}i:5;a:2:{s:1:"p";s:154:"9421424414532091516477140058802411356679254508253599986943994499257134018040507972559527177142254594456040810388699415500836699209428775701629705371860561";s:1:"g";s:154:"6848477778913663314918103728441691200537498044773698707353425996552338816856928517120881637989820983228451343864443751233482918115252865173481588049824707";}i:6;a:2:{s:1:"p";s:155:"12625090184529797788931372343452146117342437828850959777918103886810506314889293815712889526766165497221632236033223851827026122988601152832751089193361883";s:1:"g";s:155:"10727140325921866071434631280644720707882009137514697813586556234846801257052393459470630845660422299001774260577487303758752061121714260768222777853141984";}i:7;a:2:{s:1:"p";s:155:"12898044345941449918247148733336961514367567256908845520876783894282207825874366689032248149016261412283181183189727919676912955124747513289770528539211973";s:1:"g";s:155:"10413358542022125014673481723329455076572467663802388402671853913744650796933624754409034882623123290639423561484943927800989572190732045719446742609758671";}i:8;a:2:{s:1:"p";s:154:"6777052041803887915352631631866770331853268073456153981835163788577587447533080824375565106867410180683860624984416024143310816156045498552624818782848227";s:1:"g";s:154:"4744373199110323775270810304030071313547127720868525858779013596635157802120581249858087010372177600991104126554407085337043555855358684723544564659511053";}i:9;a:2:{s:1:"p";s:154:"9769160763507178719431472328465896638866070854349262585438598729016988304121111106981091374450169009893186974644229636740814505506061744049970923730299363";s:1:"g";s:154:"5306950778367740573813655888374071857932353520721926940261594787573952929063307075086373819957150491162555430648336446419164220175136517200280804575851945";}i:10;a:2:{s:1:"p";s:154:"9423922356452712235926431203949703505484363837432274466344263270397520246404630427344391380890647616716224065056313395456217365823611766528652509334779731";s:1:"g";s:154:"7284089318298927178369679475673984622736731890983895175801568163798062623992936160960700756266264018534324483109833512513653743438058543564254601022875131";}i:11;a:2:{s:1:"p";s:155:"12158697138595912393903417958876572941964664917580175572374295322020219160425436741258520156480547924156012167437702643658539038327940197818126321370919717";s:1:"g";s:155:"10485764511219481318245074108282617920786103320852119973254883572198484400820180431398785006356928094262884549838937090554887145629516730528770021601199635";}i:12;a:2:{s:1:"p";s:155:"11288262951687963487272915907738107756098899363507394921290195349495485564247336439679451732281925028547373038129368449917374094191854311957106769832324739";s:1:"g";s:155:"10795654841855911955259186695756995006845641223782829032357886836809228255968988341551185869422037966120448459311717587218376381600148084639558977870096502";}i:13;a:2:{s:1:"p";s:154:"8258013926861608902693666790435473901190984397470193086801654424096172395830149441450824019934937921913900532126490754455661483636320695940894486309100319";s:1:"g";s:154:"3008616177637279133031542021757712428009438095597380460281736563913664528107115803598843251661751953577080050168764629090444516020745052468254714596181839";}i:14;a:2:{s:1:"p";s:155:"11160199081808027573810092136307692486080233663688728390187641807815696851217963593844145812064574876563510827726742554179620355048682142887956081871867257";s:1:"g";s:154:"1619837079954439123886151787080634070642968038154229204074646704930777938542872128065694227567105405734861674388284235427031786560892701529567221392315960";}i:15;a:2:{s:1:"p";s:155:"13374835067080888087044052135412597686006650587670271902738259960071812996976288241935082708129322038538611064744176497997876042066574823204776272831138301";s:1:"g";s:155:"13340606588501124076628104969616489544340701319544045041774387943804131532921423414596496104136847181815135596116949133855703919233075041766993096626479925";}i:16;a:2:{s:1:"p";s:155:"10259417180829818855720989528633519911845188087062317995276209738349065624107483004472651091961152483138484988620800791800438426039507470091955049905098653";s:1:"g";s:154:"1049652929312544377789554948223774743652295892011706941762476151999449680073160873173568005327063467021157128914200838440820265756300864573046947221185244";}i:17;a:2:{s:1:"p";s:155:"12197220246712313066260567471862904022363676477669859142286893009035744818051867274541212248368880572818329283821354454749617732729091957316225342433619041";s:1:"g";s:154:"9195882220497133783800026095688409134361538650124393293576388284972490669069409211646836028007865847926082128016363741865516430294771664900425136610454335";}i:18;a:2:{s:1:"p";s:154:"9407346240609426328525325968151151707707014342802748859768109084981503050961487104011635924975034655436053968429389536104159388654521942683831677615143401";s:1:"g";s:153:"269136289076872637342985277973758915672118214120214013887252427702020902794047992188076991724974378053740684811995916618340797583549069883395774393139072";}i:19;a:2:{s:1:"p";s:154:"7198840437082474958207241444655495440658341081388025505383172136119655067017904561231782672226505829024686555846885360605543609008217831214021594962047499";s:1:"g";s:154:"5788294064840240997000762465796620865513656066684696204990143434694734867188136493805370539272824995064240621448505859749288014816751791686163112546388721";}i:20;a:2:{s:1:"p";s:154:"6866194853453717341652339305994187321675925277246174296458603441198214649943543117403779339651067547283653344557161527531330217059862310916864636517316593";s:1:"g";s:154:"5759497540822961789157724255057129836025195265915136491003288014804506784127978064787500439359522257641902804614292542461889892712639086813735742843987220";}i:21;a:2:{s:1:"p";s:155:"13177952285079954289288219353117192697114703824741144116451428873571791737905505015012885197099252856045557518662942292101548687388076187108958765866077683";s:1:"g";s:154:"9673226746946894107616895821956872413994230660337172037720955022401762991975117923943964348541091994823989550807194860840353142963521466169754804620360804";}i:22;a:2:{s:1:"p";s:154:"9726690844491319103464486780397647954048751456431741632228743401184876861409583494228681662837684390382414485868883077196073018443343045173438676499145757";s:1:"g";s:154:"5966967110739915435125301545444105458697696178343475816618093998403883224416672950999788756580845547713539753295669176121976165846909930535567762639907762";}i:23;a:2:{s:1:"p";s:154:"7538490325284511136438120514170901332660801432732962496569525567553027443874560165216900989420584310969224440183000809313672232345892876810847904438727641";s:1:"g";s:154:"7398588641647314497767960339642029855458293475276281320039206004717386057103164853206187216154556795890067697653797260673588174257620930150234941115115435";}i:24;a:2:{s:1:"p";s:154:"8227511957622243129017210866215270808821806440628186306320707299109228484124050243443975192083115132467163269110566007486521957831863442617410859421555047";s:1:"g";s:154:"4645421224570784791175061679645751599175479926670667316335993032125249320593256905424556589769574858326427536748350447673974863425217426168147452888822540";}i:25;a:2:{s:1:"p";s:155:"12969731233552734399451955813691983006489496437250879046404503333930582291424470873903975608202652169345016278675568320752211824525170925811649178464352817";s:1:"g";s:153:"938872877916962648295701614574225970657013623191360283377917514779152480150022786122976960582953179872490158223294764793608858216085744934431578995451202";}i:26;a:2:{s:1:"p";s:154:"7065101156612109850175396041310880729801403367529402357084968849490927526243609086812440603700483174051775685576622326237843679578065068993344357800448217";s:1:"g";s:154:"4937530350574774053213016732051414773210465511366329302510484430930527647927154764700569414698805939709289334712316369800090809356945979615643622500590944";}i:27;a:2:{s:1:"p";s:154:"9253655433153614643720842168059271343705755485679437008857639916129766802372631673001875065759695231827514244486797815745404273060777672453756043236262029";s:1:"g";s:154:"1154118437300934998774227250622044065593929966410917431580654245142293172499153040764142683392788982103025598341743372297052182135492043939517398219789131";}i:28;a:2:{s:1:"p";s:155:"10848941227439606569547554892393736362241960615699022840700246817110328822098080048132085826242837084787893781138643085998469452494458843729328332326851689";s:1:"g";s:154:"6902859949879581005679923246898018564599068520211447542005819640293730028077262822771725498401630419852070831081835541856719611229878798733541142943533883";}i:29;a:2:{s:1:"p";s:154:"9200077333219147793521004610524679062674643522045639269053512698250176480683986701289170789423917221585133322649795623553739174854764029015889572200454847";s:1:"g";s:154:"8977651412120081362159327030461431226433763741949269801239273477011043868326857881822604759965174367075681004085055927709618738280729348684607803671789563";}i:30;a:2:{s:1:"p";s:154:"9845889841943809768314162240613991788670164846635075878467926914087289824203165472268700243871440856079801440647968535378326278137434266496758552114149441";s:1:"g";s:153:"768380127191918588451951538282124996101009829676972691355190870417233807246391392262749483247926691107794065287711515912136355133371195330982913655254406";}i:31;a:2:{s:1:"p";s:155:"10851556038116464699070134743443581537292976439813478958179597826025549256396071124532860998691993456204739775754896353442062816032468483695456073098224443";s:1:"g";s:154:"7154655821774317099112947480129446469943441624481944724248657240117509097398430349434092257615286785331672319149988169019804485357174356309508341925581460";}i:32;a:2:{s:1:"p";s:155:"10869657909548234771846150650291496878012840512716551698067888848900961777039246759408527968486607410691927237604274521227153796970138251173504729332398789";s:1:"g";s:155:"10291105559439086106068351955856024921898095091811071928018974509667715608106121602415100275088724582034560187196479349479678559477870893719603456159195978";}i:33;a:2:{s:1:"p";s:155:"10573437696614927150153411773598147086432503243232815275356047074061503243825728675078417236624432478965385334323514782803366272650302790803029448946823233";s:1:"g";s:154:"7936375668886672118414744836005695357413671975252348835029285378278952434975164206158622984806431933596144888246146817078922796519730755404856725404012843";}i:34;a:2:{s:1:"p";s:155:"13143171580350380026719039436106973235892599539038891512396032568425711518490270801218225503291537102818964594215730219661054646928963320816487254976744691";s:1:"g";s:154:"1836103769949406432524468270712251041529485560856485759774657103122616493367981405292392684433227262493977758149124464359857054953465532851417935109678443";}i:35;a:2:{s:1:"p";s:154:"7817302659432711774678271020951750661333508545555444370199324820069061693710307039108112542055446182951630431053517684537459614899603725855479805738841609";s:1:"g";s:154:"7757617168595337488906483183749388091400069439975888530757208331533789508118297894470372310437202386279701677376282517267115753765256668381319564910810130";}i:36;a:2:{s:1:"p";s:155:"10267638897003329507809180547127091069117459439131395063369822073974994025258244541686493148512939652836981483431348406971826886416596041868882198252892619";s:1:"g";s:154:"6318982256606638444633601562064159489075575174603097104256876934574261058223900542813762735674188095550436482427083800544277529320265932517969479395835823";}i:37;a:2:{s:1:"p";s:155:"12782270167325061135937860317489559265180586717318292561188420849531526268171146656351667953024693325314361045908253754108944361348578267392530709664122899";s:1:"g";s:154:"6991882797209611054389481268465012367881121070327860241481617497353801116278255059623760999675401035064358235967669879053837015278936160705861718207391121";}i:38;a:2:{s:1:"p";s:154:"6731746378775926601744707878575045310304903984312892750608776725022937461467670920174839890356560754884661025202766992467602158995844691889008414344224541";s:1:"g";s:154:"3107823960825199229883719178521718215890020223638296208432989834142924789012938848961473436854962539008488662480251097171768707780434454808586850672001591";}i:39;a:2:{s:1:"p";s:155:"12936328803238672147187839312904518164662082232222521593614447250268808716877423911517851087146464538417134244477088458475508392413636215020245161324258907";s:1:"g";s:154:"7447543722174178404892869118079799709872555147821056050425166323624947980165009189566361641678758361204234599663455436346048698885722709733355889383997433";}i:40;a:2:{s:1:"p";s:154:"6805235710264138935232477664965736357729175546690091123374832408969916363561953404703570650183363313073842129895601843542765271167068143846210532109518801";s:1:"g";s:153:"241967790688726611630572098692470914343503786718983020603841862948415175119950819174453647688760067799745498226298934246248652993245529368369008676676018";}i:41;a:2:{s:1:"p";s:155:"11925844197021754713938625724053020079683404084430371438453593710522808327354502713382757227379820472738869202369687644194388842222036179834354431378938783";s:1:"g";s:154:"7528176863391682294380713557224125923359959500435147592233747105062733195022505163011428173748825139929898679320548103280305894663549403454721549617429358";}i:42;a:2:{s:1:"p";s:154:"9382690276990287517827126224244262351114680532057242635224428485844700880422684769081831064853813380043190717893849784787292907965292841355010043199008079";s:1:"g";s:154:"4417964586244527620278956236372028881588988136518683014571128129892304376472643463030713416286758895907125650825241924308538473496809076762137861615651529";}i:43;a:2:{s:1:"p";s:154:"9471154462532162517766328483693871604313875211507659394402991024218819931898363174393334319225827831532975054544822369032247496657955428463380077541101259";s:1:"g";s:154:"5965538882821744183392517506266542138569200983176623099845801353014368375173891122156750085268413198483559096542177405738857144779702351290712050408559721";}i:44;a:2:{s:1:"p";s:155:"13072215397944695079140981714451652254088635540701039783436079695923305049093068379991778701466866177972543194919692105571905528567819232740033043049638673";s:1:"g";s:155:"10905047221675573837388440719936929080266693676579154214910634308080954138288436777167832801892265852331340567765314113894641600068009717791667699348623183";}i:45;a:2:{s:1:"p";s:154:"7480285736902516363853550609483667417682147640058517333104942696093838232353278893275640726749652243578126305790444323950427003985719449351376634278699607";s:1:"g";s:154:"5759202574113108282378074864789677515288689767373583038782636582841406886112443573385070089778091622751224484977426735366091834116401247133594381805961184";}i:46;a:2:{s:1:"p";s:155:"11210622732047339404024840714095057225603221198681717167542047064110330442742534046349520884675080911296315861922768327935094937187075265506822940835040491";s:1:"g";s:154:"9937445355915956411250765024373279892128473056016564280984522288370978119816479851683244809355434342145980557652327529849111557653417852722522293792146120";}i:47;a:2:{s:1:"p";s:155:"11801310588884178766890310177272733983571198144791811277406602857753312000312219119681403573834767631910269527394416551781151894475252738903890058726926057";s:1:"g";s:153:"115233390078503737760155084175025767812358241323488230712385298533454103554091397194104748384437484257038379362772264874126271752877697308310940114682694";}i:48;a:2:{s:1:"p";s:155:"11529048347164441615241543804181726496687154791825255459491001491738712611956789755646436546778690115202840049658389496893606046846968559040105761862357833";s:1:"g";s:154:"8676718751750512425139622349225124856609904480931707180008538338879230401203724388724735695303409750333477100875898619258877552431088298574108470256276651";}i:49;a:2:{s:1:"p";s:154:"8827072361630078640503677481298714879520924565274494318798943013516047380949992422868188730738867101711789222674209108748980222387508987065854715881696721";s:1:"g";s:153:"710141650554525884265578176992152766513903299812535725888133858445135487452789266334613419128201502959244491496639163675200761790924208942231383545162770";}i:50;a:2:{s:1:"p";s:154:"8630916941594181725869358635738342312528620650119957199177838952748463935323817770626013179178189281017124138873993517599531749107153800962022777179165821";s:1:"g";s:154:"1986336010793498690402481692272896313437282310385967728046494523738961523190690879475912743848248541173027205997086416780584203636037838333529483182130644";}i:51;a:2:{s:1:"p";s:155:"11212951383442456895282126037644720256410394797566689500132827435994463195592391547284657499757312898540967392508953032317946768141214910975547388177983241";s:1:"g";s:154:"9102763753785975341238925269544891354476061894654740774463306793322852969775784700232809270884694129158803996346082108913891287705031439828185656228063664";}i:52;a:2:{s:1:"p";s:155:"12767327655173767525498878790016442622970607684484683803036559177746978436941358536992037285959314311977766975796863190178719754731248258583037178093445689";s:1:"g";s:154:"2321508310733831420610044896604432882237136641393324233389255445534691813740197943289557007047153528108310525898070249540038163869248765133282278627312806";}i:53;a:2:{s:1:"p";s:154:"9392193574475555116112128582962411207901765366075980992046837483678270815467145329834399000077307436597284520617068141836081640163188636250835029441308703";s:1:"g";s:154:"2053414734576510953913507168402536572703774315964363121175715888088663285442201329865875872679876866070636146795229156844380127153406257025394411611466483";}i:54;a:2:{s:1:"p";s:155:"10376053565026787172160955177540422890317275023121997466989774697279488503166878624289513515797363103732517258578762034755462542106414254692746603234671043";s:1:"g";s:154:"3091638708604907776624878044604867414422955026474038166435429554732769040827969143023705222880907519792943547859810547871406751310288694469049761930481334";}i:55;a:2:{s:1:"p";s:155:"12127207345651068820086441964683009352696585515224185465037336419371181638231683584846771580814035091125796069601976365004662474480234541458668882739890721";s:1:"g";s:154:"4438836866160593665451702269753991637431308452920369244447683669705293185053449743730564137227007292403789550790345961175603642284391097450268685443319770";}i:56;a:2:{s:1:"p";s:154:"7611469932440564952211781130439214876690796015869296504681999249251840940704296297777681008004821652510091526923191561988463222032574639564147602004747471";s:1:"g";s:154:"2159962031347381166014669527596408113229438638278373884502632954091486600988300593639831501800781269214755396360742040873940950396505283507866134558622775";}i:57;a:2:{s:1:"p";s:155:"10333552284492177347867767760312106573829849938537225897708798295607254551687795282788443586091756110932272161971955610887088234617195976811351238892296089";s:1:"g";s:154:"9432120129743475799160225256016334679238139039814424474076543995916056734666699428293793667992690869643795593704757276260398200754011455643399669925569067";}i:58;a:2:{s:1:"p";s:154:"9186129481949759777879325927009938672103591565760527415665011657111222110694633491007638694742477745970521733215626485356625921552251305212419767357335373";s:1:"g";s:154:"2964982199072437563747659648788199572625987178442645806407700614788045759520791282226234744641146133332755273683835703308793243169629688414830111305979008";}i:59;a:2:{s:1:"p";s:155:"10797613104193760920872576604739145039329493525174523870041853152276384156721978899427111721321741929488686066256034450841507862907390410840826008764757899";s:1:"g";s:154:"6035241474954122155355449752310815638886484205153452965392586944818152870488968107547112916728102929919731151220028636538954686722015297434712965657407685";}i:60;a:2:{s:1:"p";s:155:"10869947620920150461498689213804104931914857611354385578667238439616260825731378948972250757311923193938060849629181090857995395344904289508598143935730533";s:1:"g";s:153:"481312849012587203492378145862322149972797039844724273303827814567785210878799018651223527634096916030584780553484801818224446855755022386359742338412793";}i:61;a:2:{s:1:"p";s:154:"9231592881895960498562751568063478751369509815551906815114331855768090862166893258661806160199329317482836122183454449679798480059718481696000432015512777";s:1:"g";s:154:"2829892719013480169078067114400764737378051603195046862786323332593085589593735084661704693548639293287833918450999392896600385474647941243068301494417304";}i:62;a:2:{s:1:"p";s:155:"11535970726511268187759588980352242649579274403126372273895202586422537522913796551110927374939006827092569052666629425089018374179426876981117710901583973";s:1:"g";s:153:"720418139015023065849163498841056558473934556153974761688050291079916546264726704214062787471591074325994224916038425383512487158259629457204721553853210";}i:63;a:2:{s:1:"p";s:154:"9861250489623369880082921468628592177502408573205130594265711247497202978021917937037715397969536963237006852718089567889086256038105803931322547406120933";s:1:"g";s:154:"7928607398515301999160672014700122456116839205946040598055281578888827533359690175257847840316486463480345797985196608946959190295352354947490060567259474";}i:64;a:2:{s:1:"p";s:154:"7037162688438216114665334358856972752028696375118432431917708234857066416666136221875422755517254911565532179808653486394916493658234167039740176267876757";s:1:"g";s:154:"2561520364124680347691025622126585934254249847396300180215790279361782291723253986299677678320409185303548420368698893869095720049051592101538317786377366";}i:65;a:2:{s:1:"p";s:154:"7839643405862034358064924109902483930026968378388305680529567643551318111486398801706102322537326685360160402095895265466777644277194315986891593712906963";s:1:"g";s:154:"1754075447965545218123602315590932259411312929973677438266981091131327486934951256423337377824430217299559456308536359696603306575468489620694606039087055";}i:66;a:2:{s:1:"p";s:155:"12276557742146258743545700501290339960587405224847731100110687472244791172620101100818159279506090655569815738514019088680091703230258555911540799511122167";s:1:"g";s:154:"9763861375914985702545750159977496193065161335864817824882497327027580874802416052039447133239579968682408646209369969884977946436819534940176606699371008";}i:67;a:2:{s:1:"p";s:155:"12230683487619319961944453143151691985882065041735379665065641906865391780863710859120672643315553046872854392378120553560533025057025603898136116862293441";s:1:"g";s:154:"6820995666984101001799315333640660517853397812362325663701783101362074754987943224840937197351438492534345149997665796889093780332154865629423497020827741";}i:68;a:2:{s:1:"p";s:155:"11000033292226348930593094035262737806366027110884679994121757708192645734655143882773568769558594544920179117149359550596513178815154309868775410035186063";s:1:"g";s:154:"4136862529753947481457983021388601715848766598496715256706293038171121046049608132082841396600193873750375804495745944144901236241777071843379368664154275";}i:69;a:2:{s:1:"p";s:154:"7932184591100186238463385027146880324850417985223577208693360112110160571988870890366119973622332640258222800907861231078259268751127722069064114137860677";s:1:"g";s:154:"1554704138876266517226317671429037357546114985405447916960643643463787594693776634564098027315293480200461149296363025299708818954818475510231838798211630";}i:70;a:2:{s:1:"p";s:154:"7247101322282048034402027899872237624187875581686127113817087170324333761059623129858201374439632028757144826193998183802269340811926184660871601027538329";s:1:"g";s:153:"419876311823553421268573169216133898499120781788412225525682613256066295537141806360606590621846965864647042488385611805166485002563960603496293345101151";}i:71;a:2:{s:1:"p";s:155:"11142911398132179783773554123504917208536218755896547125640354767247161949984883149299386304638615888680135284173520903886505390416092111250431821534935139";s:1:"g";s:154:"9421238208594055151718951084399404180843115860565558346086952546158235884494503159881996700939897153949279617132763495108273288888130277440160448079145244";}i:72;a:2:{s:1:"p";s:154:"8422680718159927137259727024146506754367065291787361031410637379107607885590191645491292131243858308336644590049873216313480699042782181741026895310726173";s:1:"g";s:154:"3037225857906067024969405118120869481652099716781816854621639587769381797676248760487654420923330399046475888790029324331786276809507475888474809786093936";}i:73;a:2:{s:1:"p";s:154:"7528768306671922054208185893735786263892447977854351454834071543608211520188226424532595091748227597163991455896141393802353880913727252686305028424161729";s:1:"g";s:154:"3931350151921122314780347621781962310133031238916497178404726881167123558977180174914812344106371470279071072405540448395936097566056878790069126677394020";}i:74;a:2:{s:1:"p";s:155:"12030526433315035140469306931173541509436590353351614316003049833737604937265864191109079597264155746863781242435386938773196553243129970574108647558122719";s:1:"g";s:154:"5262551105713048931818840437133090849709297129874432211503996380201846241562025926981819972075908236266338069212044270892600622047959414321970797115421273";}i:75;a:2:{s:1:"p";s:154:"9080171192643214261502891314642398886325946367848695539813162167683393701564678191652727167179846621803625336395576968061663125749886477301402476057199011";s:1:"g";s:153:"709789037747438551471403268717923397174465497703413510328687265086023430744334341908605956975980410030779626052223052305886135189506754645049360807055388";}i:76;a:2:{s:1:"p";s:155:"13357314213295536619231005838964463646886546298482519410136443596212432187577086765634310652333808405384086750529280259788935338817609169763288472875576053";s:1:"g";s:154:"3008308424927763972465840465972683289043134099712501524187518687952997991630181328065646578654263728776643235789250693981259674530838112112997801930783959";}i:77;a:2:{s:1:"p";s:155:"13306050297284487023040709070162991797222204615032140186218147999553682592488789343049675744599654166735159045082795547527989076358395782301307563843028977";s:1:"g";s:155:"10586434249601338827897130612953689058628048902344954419096716484144284946171236587914481571624702816408228904538974499497771977827631330618983799976606289";}i:78;a:2:{s:1:"p";s:154:"9366504107760787554107889797349668086646215031128274756817605248155100041596743704559665807463008332333531511834473256899818275789020152578564909838966939";s:1:"g";s:154:"1296890521931304524803874647584175069243347320269646405477433715522011568052186590990840829333541256081030481999426230636941661307954606245382960948452042";}i:79;a:2:{s:1:"p";s:155:"12370801442581130353098080816654066418563119020397739942200418473089819692358661047391874663049174382551577117787540448439844491154738143099045780558055617";s:1:"g";s:154:"6842040296510517190110590627840671391670907107513510853159788693248967480920130462096308897538750871495832060995658519648610074675887202669120166694080542";}i:80;a:2:{s:1:"p";s:155:"11077894732742539228461178737611889036810177914415299462002747018598080996762211677501351595137719755735664120371063604922683564552553799605879666676828107";s:1:"g";s:154:"6225665728035878018071502041848578377966752563525174352306433083719321102952407547688689903755913174694857601501432370542759467220859644790183397797684019";}i:81;a:2:{s:1:"p";s:155:"13145416241730004319539031165266146823267243986800900249243141299249692643707823654148739035496268454712317187086057636031267290835062035878246528419253971";s:1:"g";s:155:"11050160386771600486586208130647596663138967212707349660963449143590468628618046744668548025343868972693894338641508038837575295198723184300502415519901282";}i:82;a:2:{s:1:"p";s:155:"11611568192755848405358023732007679695516806149908855592995993275357312141733012806119815203057519665797881047495560403615048245840900249485135048857817973";s:1:"g";s:154:"2172894898451447223505998543289583996691401210736051190210176057916495037526136335918007793521262073068109566941968675779870206983436603928903594965384965";}i:83;a:2:{s:1:"p";s:155:"11081251290209313486762589003942067507294386109493000614708203861884888898398271826165859824008399524198445364973890440885137811409580589713737316428932921";s:1:"g";s:154:"2341203960244595837213070499094603366869960798002532578372599738831741047504816215572635049607899579047269831194426528602744165709752396574329560197504887";}i:84;a:2:{s:1:"p";s:154:"9794529356504350260404907807235199976002130997823212274470101635208030092724642485892237240499775678153498741626506100441198709272408997435145522469814611";s:1:"g";s:154:"4344904416955182816773869473067344211044878507239085540617345084857514867492182044106545330382179727507839983152349813760661281772974710240204268429761579";}i:85;a:2:{s:1:"p";s:154:"8179725484707820411949587770938632194412056798385983337040993681088549942564780789402826043416929282601970567097871918694564510170940044087117293841610513";s:1:"g";s:154:"1968397542995586956640270479775802044571639049081148217555793019585806722702582989925336399488001038506518632099733588396335941761339893103671679996093428";}i:86;a:2:{s:1:"p";s:155:"12087064726834740661902750716902641652260658517688573518871909700616089898549798686986902911827362620660139382723084805850119084200144363662168266918678043";s:1:"g";s:155:"10143128949548754892164655340639862222487020558978119369114321136539759978238238549616976854216342914704256587847974237107728402138497359582900931753150340";}i:87;a:2:{s:1:"p";s:154:"7029682085043851174454067777276288756188737504360927396230568096724183584772341319344047251994723113430875282707294543179001234168984646917770014120959747";s:1:"g";s:154:"4793425727317897442176619553703271341958074640466020143773480645279277087286489116954664501609095871678716832290085599924471974813175615478171487329912038";}i:88;a:2:{s:1:"p";s:155:"11751944887853172690320837788719217620434712863775635748903292970090933885012275919749911820430855929141981640859493347105230323356063850671233945242412501";s:1:"g";s:154:"9582409285060411792170252952646051889530300334780762047880884513762363910409695547459901317732986407473204516314483633161449064045710936889521255288095464";}i:89;a:2:{s:1:"p";s:154:"6857242503272628812624198660871703450024969140119354771706428426493307506557602183087871260836964690607891275115676620226659587257083437212153260711770279";s:1:"g";s:154:"4154176614636529038047455462840427597900131364691514918565903217730506684392008642129862713125121528379202819818759480813600225543386651723083282463528910";}i:90;a:2:{s:1:"p";s:155:"13115086998220969838551534574336259426013013813655672434628036372288827799419576677363079570500421375377429272681906309654330290360291887877051639171311351";s:1:"g";s:154:"6891448071394823240466483662164181607435055970033730150995462293778784684581116262176470853429712481202017088873582225144821918813814521448443862620219142";}i:91;a:2:{s:1:"p";s:154:"8510893906328846244399198669826810612145463386143494241344898024159008867802113613038506831355149788338718550470445775096341446065194196232469619078573713";s:1:"g";s:154:"4719394317458501452628803829232227857042955736811107024588547171771101148737656411606180861478202429084115956817397010715814289972388887344042708309814233";}i:92;a:2:{s:1:"p";s:154:"8196571472465634150710357092777366857982237408029060560236952461265863131959217332523315458373970512148516043820292260787541295332849890579530595347949703";s:1:"g";s:154:"3437715159187221214391366230360038167885711577338021347106416964488193295288404157463558405404279208235567951416122490240147818951965891782937248453137469";}i:93;a:2:{s:1:"p";s:154:"8450294490269241183361812103611893228339652390157337597894872109035465793517753716542229018535050043417505545852639183614639954904116126769099901623714911";s:1:"g";s:154:"2888014306503502758072496640166596674896406120299827826475830676072466087934865509880125697107944254828014207864859572201140883165205473601065103936013655";}i:94;a:2:{s:1:"p";s:155:"11703024906185298810265683615912076101571205851245019004095853861674944958540779094519988491697428205927709507267814990927761125062629298343090366806859713";s:1:"g";s:155:"11125881782324660340685567056782318502630553007218646702194031293015361721973968471899663504370476122752833733771740023378392848654883871239424202536963707";}i:95;a:2:{s:1:"p";s:155:"11633995063491596974992159233441627337491540537056061974579863559637399000043290646127303473958433521042069509695166002929024179229815912787160500228543933";s:1:"g";s:154:"5779716859933543679336004575891528709661168013484215512953570366477029110037380705269852102039382480691593905861950267640597260471662190053628708944293792";}i:96;a:2:{s:1:"p";s:155:"10667411102370081426209854218278625522500220146272991772930143668007669641923818842838987021376423579429682884160787015271663155792992067237050696610802803";s:1:"g";s:154:"3279140280644715139321247161992749403889139000835115394739495331799618231418338265792754929717649735647981445732899278350937379309464302481950856909469903";}i:97;a:2:{s:1:"p";s:155:"12262245462256089092233173409023375655175021466746738975484018042510893911713337463824358605982014894541303198417182824980800641603290435497640012365351457";s:1:"g";s:154:"6330963621362363210369473585040347344278962099805211292047845261983817579073921701279060419242132775223605691558296991488834271200429761204699646704066949";}i:98;a:2:{s:1:"p";s:154:"8411654103823275724025827646019581791360301812783543923051336819177700468260635956242747720616517561011101815431131324637960310731981069286216133688130173";s:1:"g";s:154:"1684947649509417239135260806264943252268526876769637194735757909661839491299132255354516845127033345104113796896495486662449701718944268945929267825040670";}i:99;a:2:{s:1:"p";s:154:"7994373833628150530849560920652401745121012535777349068601400269551607703280823889354692441372173043657158510740536487181611790985457287325461732674487519";s:1:"g";s:154:"2448220787443437832886976788088760055780466231459849980968718478131876017940927162384725064179838850731540842678866145729291113545181168269781059181980456";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/768.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/768.dhp new file mode 100644 index 0000000..9ecaa89 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/768.dhp @@ -0,0 +1 @@ +a:80:{i:0;a:2:{s:1:"p";s:232:"1175701041445302708884945410438770138623067783317783382134975004979727959704321238474087887774649148807392806869952586373772996619822483837057669783131284061360637806319674004728682099113918536008368232973412864321898274530817968189";s:1:"g";s:231:"241059629172068314126293770290309301680725940677268507448005614612902261835370942874314458647451521037890594260859348356283043421942966080214069747884768462092667557211293978755476816099194220284716669499047268771469853565628917328";}i:1;a:2:{s:1:"p";s:232:"1160463397158849527701815009148900197203162958966145645294147435088801477477484675803756332910607813978135261745343212153393703549631957403377304943392443243634274835161523289211102958000522891895552407402369897099778261147415171269";s:1:"g";s:231:"980156576150670554745272209446093662673949888301777582456786615364967955309470589404357349856716186753632817170498703268152900072938066234439475476067541450491769594850768658457448054108176835484453712576430139797796209265772663336";}i:2;a:2:{s:1:"p";s:231:"869999655052790320182350879045566736728057927646570055315646015266889408464221761823392111747178285002452996028958821825296263253477667770414607110824676682799212933666255993136017460383512392289933438630148121391233061157366871701";s:1:"g";s:231:"531763689104538271465553319393201608727104812448097152771133836552981504434572817723821778434687427886222311184464695443966276476945314413633593925811893001531543956477544738605170657319973614928713461347939896531084690457109650538";}i:3;a:2:{s:1:"p";s:232:"1104471889917750884804303993065688883460119170192152304973430999181490471008618869217014529124101277320656445061298881090946549506374431201142490220604127775680178415983020357612677183004453511304179415112545948191905746719765023971";s:1:"g";s:231:"719561347460516300588925619954785617290282281788521291729567441358628645361645381334837281113198173842448560915544949877434810676286698239725433272740122624262661895167489136995799620964581060100972409665350810198636958786254747490";}i:4;a:2:{s:1:"p";s:232:"1349145662078107774697800025503472204512905629848848700956023551865702249533990270152932113986569777681227891868121513976119300639330914333691142005444358532420890176900408029727790838187380605103464551821327354724729985768270850191";s:1:"g";s:231:"817085937396555832326475670220555563843648577688094711201174384260146179381647529871294528787843636664507424097114669660596077372446980941338825278574512780193224362876869434622142663392849627956987124787736307353546621253742287509";}i:5;a:2:{s:1:"p";s:232:"1170084364716675098903795547318887975237486234252129979677466784031218735736488597399497927160715706835015347990348654937293942669164759764598645992563931384215893539087431665099853189753569853096609453066475645389548368518437588197";s:1:"g";s:231:"498080361880592469439063638713191901297721661284941285022996514959223564776280647472546017014715813809968461324738999250055959772268068142135772249196678702445566155036883056146139967731957697436506541599654345718063563028972250369";}i:6;a:2:{s:1:"p";s:232:"1147544738129335691604098236730065784788828984596526639862250998945585078140238290443084080683130116915329899951133515821647678968164144342335104557165878713295306253892140879535183775025459645089161687541667257366152969117453678941";s:1:"g";s:231:"412298807319586531927775096039364269362622496539129056371296014789130977236073468174577767813493223094260356964839594735360408897706250447147501482137328257143660304924424450171953125212533826943218368301407163603147920282182596717";}i:7;a:2:{s:1:"p";s:232:"1251459840625677580659022626732309463308468834562009677880364632310999147527635865483353995214612742318909034188785280532570232794971791642859147218442516084809570095064546523413155269683156065581632009652278258806379535582737762439";s:1:"g";s:231:"369275760058498636550821251653721941442653004141698753680557607690072573886381652126744134536579494435975916488308172082808894369383211230497977817487039647983869030944776494172985030680988398447132958596730936802066575679222110687";}i:8;a:2:{s:1:"p";s:232:"1535344116805682251385675308663093365934297896066448534028022589326515570217831815544787810722606137484824036899107844848252172542880816122541957184557662658297375641247937132253125479510107374276342886367827644575164585705594531127";s:1:"g";s:231:"202836557466759687825659737460642134720697159050648974083932411076616195737116617071191469532222258845229927616307896158504996120614481673047823109046745202089921378952041816061571352779203853628752794105619209196352667523917697914";}i:9;a:2:{s:1:"p";s:231:"801113943908138806999867337723460760488142199250918895058021150316660815957495356670553887727269523631199056949598706103957872673978280763594133212715877891856789747790840641401586443741231064114368395492185857995949962876303129819";s:1:"g";s:231:"694309839379795774267237792764059999533089749547084673316777130906803928668917048001170478345436377296099759955259854815454970932669888732648849422308339634969926182612207089556708827147823506521805267697148146750261179747100470567";}i:10;a:2:{s:1:"p";s:232:"1436624515829922564180170325068347664639760966514249926047688645549597081524232509986327946145949801557430435901646275377697865257323915842905395151585185690389154314744548082422917984187888469919698940546837871940455457802508004277";s:1:"g";s:231:"205325877335834092709861971701407633902492068979291865149734239121982052938975442395908996863058497445726401815399250375047854878980218929298866937343194631341284412844415869883011288058945445382098951175546809496258592828861049123";}i:11;a:2:{s:1:"p";s:231:"799258661369648923916854481905584467963020662311600047520263122726594370519134294878197242897014434488291639184983931668610540662986407313612714348657216832542836246974474679372913895615147392935709768202139559220362017676087042633";s:1:"g";s:231:"357496241504622526695256924227070348312584166065591818310495130471771371727676319252239046969554923144431824429107063633022798934376238009863920419615976338892569518919491671554567567595071601125434766044367945437812431577687923968";}i:12;a:2:{s:1:"p";s:232:"1051408107621350416126926966389976088507487923772801072190786195092112727024301845321543595601559395183495596751958829496260061355920165832559530362684335151735209162390479085930229489502392686579399803214956499703143786196204087613";s:1:"g";s:231:"403603290181277813589663904398385576089358601023743478467711998534924767309275480053287177322410214951726276870415986964145557802768512709681770978620460340923362599910613902980015730554712218603641991712678463309015038515702944505";}i:13;a:2:{s:1:"p";s:232:"1383051313976534974297187974892829648111401197280398169875907668864794188173011090159574779998626193323101562395390896954895253755334899465699105444492348571629049556431145697351760735250630906738856446907072009269784313512185855579";s:1:"g";s:232:"1199735749926534010840481862177421035685177726400143336339476245380207334625197545055011590389537565182644918991313407815516855958991889145001076248919695783887819360092481535762046310624503499974634928082949333536057916703190347670";}i:14;a:2:{s:1:"p";s:231:"910410410031466046008336894253730842559542140395295979211229205768982423176207332543996039251025283987942650159091803684000366302121506053327876979040128253072248521267759503496367422588289312994916213434282179649133744633212663987";s:1:"g";s:231:"395333968233767507918263855813385365725937802861175996425345239417614560831767568032540531242363110450207527777984721790110784642570120251382701537646699019465645659295689919040974065325120806449585538344380252947524183463505710118";}i:15;a:2:{s:1:"p";s:232:"1529776512580798243176095530405074419290713556314880892947927990554803460910611713935840752123509682810306593293156433397002521425768945733982728045250387111578481164344007611587021198066250169964931138878655459215861198402408752241";s:1:"g";s:232:"1519445383034831931517483004442912436628806433888857538825450472920479943253898537957628551027851368648480607418026659708334282843471559480798797256421924871804179230900235354724271167196448484462496628734555064125761767269533924788";}i:16;a:2:{s:1:"p";s:232:"1055268106948316845820037199650696972262803907698438854383595488438595533496939565236257936526517867592674209529034768116657200825044331454286057391906528610312326048723296678566840409480856556538022261783249175274722313496460997393";s:1:"g";s:231:"206199432446954854501155354593104258705023646498347422866452068277855761599832823029544119042795306106607255641870488124946938722987479414009442558427811133307239255777567609322375398053036527630800505594868640804750267329497212019";}i:17;a:2:{s:1:"p";s:231:"927107232904572327802253196907414522890401198741432957033542471901660060735503741345053740426201523001385615965320925417307275335888742645568035113779553434911899954660857153019756367569217075991771367419354564510954569387686781801";s:1:"g";s:231:"151190234644925654338468905080174282428312425171620491840896135001550552505285467270405831837663599636842153464661142497087602166399039180218595856073426378582252819789107700342324125115418517879031733765651876530588736801131823295";}i:18;a:2:{s:1:"p";s:232:"1230406903627596355429630307357961966927902661330733966048912828726210489203733166524900751937788479926740629911174130814981095818248169716756507268089985544967870065234054865704635592765032821889963045586853603924313034646459830073";s:1:"g";s:231:"668999769164149606396391905469702907438198195801890018257916180836998246805109153504822600959837956452433436824239329746422896185329845719328738674560224401963220334020504352748647213145516787548177208958659785899244375716592236867";}i:19;a:2:{s:1:"p";s:232:"1343141590028980421073350570601903280290621008374784318649055603896772206627855071664874368580315902485143692539969771358809943653645023853698628652795134155359182055321034854859987485434971478105676770508757702487134643905697728033";s:1:"g";s:232:"1062492326293435934559743139342998676882453034582556699457385659062085223848520214771625029649875938957628105282196786328457477581581392517919765722570685022794786407108203606530037801222131349049104920985866100522223483258865794132";}i:20;a:2:{s:1:"p";s:232:"1098403501638594864875213493901656255041240203343882113522482831939345936346184333653406769548850735726528069984539165555039980566126422074768571246067148292089464329701721589403155070691338254029973734622567828509785817071950605917";s:1:"g";s:231:"310707833062544531467216844645561943098962370578916742760756974233153684446241745616739754688573566249846346213810020620706035698631735705193177208634153280990743680897033291523201037446504027887000748503867934381496920835149838635";}i:21;a:2:{s:1:"p";s:232:"1043838138616929138101811508697535923531994446448500728653891901609619113945535663253153367104375297723741585045382617087805586145467240001020812882375523417325765257159570623394415973410607015885926973240245828769638767158939735823";s:1:"g";s:231:"211284959053982880949257420097104560359997038327161027485101114225857008653586904671967082110943338617508039824126355934406108355113694160236445963650468176887494420082682469687380851945881864137800975727598046593748961975872182006";}i:22;a:2:{s:1:"p";s:231:"909481145780067907589091924270230177315783422840482719065855137220873943019392515645706882821956626647690572635519707871148396286852157642254684138616573098568906464473751784860772188993297829955265667930698434525595917268839160831";s:1:"g";s:231:"411306373730682918768088046461658053886047523482256086504433211926229153450331574028979947269836313494655588335578201035994494545773927011311403549789887334144260346261933762436411397706540542779238658495048143846325391633700408339";}i:23;a:2:{s:1:"p";s:231:"998772161604674730427208474561632709989449061544052364704570742358230797373567794007176639781433176998472046787230276993430790779126524790324206509581430785260876043040417441909101570474744218186298119505360616581421482343304505361";s:1:"g";s:231:"184733937063612803361298769841757157417723900158741181107006790853944625842943795481039244412016877898192770990773813962037207347519355631352186315162236644592559703304341212558034558069171398380113273099853523626005475129103034636";}i:24;a:2:{s:1:"p";s:232:"1211631790987909065279106290645741658732666570591761876339218049687009689063703460852927094478436804703232418641595286790833128247242322236659720330399908817197999763125434214867786755513779482406322331051070406373162250047920250789";s:1:"g";s:231:"133464538617751712105475405020034283166510480141148453432578028498474033289040983933470799356156378878000022691320750490030719324585709132852224359186694804553298879192734852754173248762941163867013509089588026892511564829994204431";}i:25;a:2:{s:1:"p";s:232:"1480888488064451833774956808070244282669247589809971713206520764621641705446162614681155410627412992481879670199414987542533382624645029313151496617517954653413410026066284178008253584891588852045810626847039641755473089536554922773";s:1:"g";s:231:"913189690685537274491321511987396961330148258005655893526179749241633423973343337308946510334297747881793256525675559159610647568566050735753323597640433431964439800847620009583803481087410232791728210821760728996331203279213947272";}i:26;a:2:{s:1:"p";s:232:"1226836596566030285671888769672320821039004799655006554366618638637080790239128907289006853315149550819913671825983025640271041255260358294952167094606385035928653956687684571574517682208206011184632341554573212143424439340894536707";s:1:"g";s:232:"1165167826252532206764102608676934821873844628569091073440126408824517260489370607025426954145855274315912579810136126737938857566389260232456536101214898786965422243604428182899785175865041677120867451350549315484291937166136764004";}i:27;a:2:{s:1:"p";s:232:"1299126867636766047256602510774249303897946838507797326381539542959828986746355819063983912580034597435296309466632887629584754859249612032021106825967545400294837414879858419551447679126128541532092139202509474234237614792211320507";s:1:"g";s:231:"557454771562979112928503109388852680893435316641935992058431451772623760588666541249846163311300085316181790874633653741197111690133694320561807770330887656762203562703745220895210253776537073041329766823041746432316834986737922878";}i:28;a:2:{s:1:"p";s:232:"1126348355679296469364456200534190821415558122462203950222173903971316162001039245110015744494619630001307006082897548431481233236573807001400784395505656822302868325141067593935428572148431711769877790056770349398782273732033932543";s:1:"g";s:231:"992021673708868582769366906807993213154273305041047666103200722689673139917893393228140356075089227443283350105873567260204733321860706890148864345986528697202036125039604459943243445725478860982681407323820119155437657100371338526";}i:29;a:2:{s:1:"p";s:232:"1008634401758053187128277736528417410192034136519415574669256634516119096233828450468977538112572526973392323180933841232544505680400539244347395331585330307268440666331715982213274229183991204285522535330619906085375274079227768459";s:1:"g";s:229:"8760572556759866083474396024852617365462326797230737921542173365405997497535302354545906342115080155661950187754873201977061047090180215735138055522021787946051807192598998411896616854579180955223805032820165391468693386400272571";}i:30;a:2:{s:1:"p";s:232:"1166978258595089617844403001173506915012122138015839804357937568870367230913358081275686767951974838107971386291410611977806257745948360325814106870379818730302342961515325103533493599551258196409588500690548494831769467819283926657";s:1:"g";s:231:"812710962266620243090428292895471184148359621440469875551097327425018412500712903590238262376264809756735213909943793204442223237431481867379981948700612089289422272562312522419823664998813366865358855830307271676644906505385900486";}i:31;a:2:{s:1:"p";s:232:"1302298468784249119897859605635105295493385466221287850101629491320472840125840398596019110842184371846880449698083893020753859720550094093407591344533647559507312410611357312646674683805014786093994912628676036696224037212157184447";s:1:"g";s:231:"554178797388666049055219638833783155765529248078367747326034365212425526271152990752929505555825569368390318252869310697577810339822779922460591657816810807115780260523476282093078547455605388274840263108672842888701583560113414480";}i:32;a:2:{s:1:"p";s:232:"1442931000879495418147830571703209032868629219398975970234579619558717538766726952628317588601304783460127319543298710724327794361540627879606358857914590949147783774965728031895515384676429380074454381434982743851365372673084575821";s:1:"g";s:232:"1243370638952605893651352051161751789940342061323296322682621985360092310205841028660332063743955170031003140637380278930009235738429325643370078390617842484869594029175229248055914742953616388093671357850175664014116837534257901300";}i:33;a:2:{s:1:"p";s:232:"1148631939654604996206773214574552575711307896990934696385104190030217192296044952385521649166190675676640218110404003177982075271795264830578900777976949290319265960261829395103171222603537402278457239415980314123796770451452349777";s:1:"g";s:231:"448023484821032996636639996750542199189362181239231401153219754636555491419612590302217492863117647800708873851242669804470761410341377037489017852304408246918090055485282225739486541777100726481671909427004627146773220357766465353";}i:34;a:2:{s:1:"p";s:232:"1393523907386733639196096063316267020192297325243477671179771572687950474193652521299745572736639931999553943306828133031329380137072125223794530447655767869824129331827371927406431824314926409286092407615670679430786622997473343069";s:1:"g";s:231:"158382239332012361059586498468810507761951071253874327107989888294225407513544700530720873616427478949372862299790858389591473207674049859637536330846828044918745064598396795657590498426743196990965328660346415613444898158459599150";}i:35;a:2:{s:1:"p";s:232:"1222102521241577470283074206070854512365381505703044952665199901251711264414931392126084324385248931164740262398980646038543572389444975748645047292454791849985041434539105121366323608243589248572317936672902512257895791961279944753";s:1:"g";s:231:"169474809564989953084527210878254013750630191626979057975836242572371875202170178801841933921565732612820027939995759973638573492141523255284416678413548269429265856232357410256501085766083506944544506248899177627896120912756013303";}i:36;a:2:{s:1:"p";s:232:"1538598708742095545080369228198463718092167812089180539057575039024868762502691630260434517572758932344173922950898274079386406523439552919172580086565148679698253538312693842622352860900237758454513286076544847373869014109979321933";s:1:"g";s:231:"487925873109303632774725988789554372098246151110994418866475560449103780481232838975655743841665990844058650418668869837797071102539887131618290573262237167406538025787225706255030517039749286358613977923363625043888262053791745638";}i:37;a:2:{s:1:"p";s:232:"1097899884450506484051905559182453553026916821622290305706630776055467106423904840844285706479146578446144665891581111216357975998894809415473529916388666801399881277039020074770237098134085307809567159080620682178430449377712188961";s:1:"g";s:231:"713299421426006881519029802202576054402261377160137162915585056231624159229306230285934068619440801936519514470570753298571802541176133350536243875118339091016873336372808782754280946665027375040616208507565862750376128043447148301";}i:38;a:2:{s:1:"p";s:232:"1444512863731935483894008702225378125585842694087894886366183274520771087738191267827986626161760688063530784261619654246386352435824102332177609005234887329162299752906328015345611754396942570774934472072201469346813666592126095319";s:1:"g";s:230:"71022242294633908238161350667189909739686489589295601215049118314301866007824223582964959139713235801443895454852929563171050201408606095135442608708015241740051890609221031027343612271279397254089991308258936096567240934245572172";}i:39;a:2:{s:1:"p";s:232:"1273921505529135134619471445603766730070275266833637077209371997021121191847495299878557836242176015913055701620097068240553902757712424908402825274359798411845571574397305804394784399551447648769938063688585195177797469676117292707";s:1:"g";s:231:"172283541835681082917921474708343318584309604663465791287861400143479265703505789482265599399730053181227908951029046784839847417910485792238689678397452497349792694795337120509247353125741777608749797251283134349847071985419946945";}i:40;a:2:{s:1:"p";s:232:"1391094208269651754228863172916777407766029968601221814793322964684263639354664514894064147017556309431689085598248754658855730462315479244796403513137082524919056979840050289629913330468113348066024861551070516586953578831954940287";s:1:"g";s:232:"1064795025524333155217046316426725709816790957250825507504827677074388754937495371228984429697045350593451967952162867994241570961967536898334578217100559209235672050677519860167586961789899607637975559733514499823460278430037576476";}i:41;a:2:{s:1:"p";s:232:"1326936468445641417245559449259189655277275904688276735759218876459280665414495776416728982820158299493847435395556882477708348526659451871434133327657573829220249539269158877916024342331304627334533741000563961956005708488896022881";s:1:"g";s:231:"560160325520918160311489004538756330652584142975803146221680066558825151966681835216098707623810048671320310293566100399843705481307636868232976533478296776776351705941749079437351750375489046635461241491940079270860197965945416491";}i:42;a:2:{s:1:"p";s:232:"1218560238812030632047384946207677724376675891003367919894642606676193534699851752823852750039116695047951403361183030635500544410234555075253604602470552567206345873731073012853104591337510965587671909822763481187950084516458148541";s:1:"g";s:232:"1116212605793882361334980508554999764613524510673113925014454336067379611972575174811960004123114872049074376846221629670991490051690110183964326474055506681823977538787010733251705995435908223148341012046785733295266820798998534733";}i:43;a:2:{s:1:"p";s:232:"1217497188427651645518008010219704097963219997072947918220282510627445392004815995384575298457524395356495753067496167745895373477700386523537698186007914458939259790774208461717994689738008876315744224012847133799009218346684830859";s:1:"g";s:231:"770511130507901438600412006983112284630991371571710484001330082877838444871356535886313179170160624860637206210159889225802967508583219897305328840950801900907190541603972767759028215668443657472137164937170393059374657350234172588";}i:44;a:2:{s:1:"p";s:232:"1384805737644402001602699295819222115889640213864823739426626748938803637018791449954061797401595116354246963498875102004687010135881571778446362154004089583318355206463990307092106845161235823666584330910755849289622581381706219763";s:1:"g";s:231:"300549098900728120997184377962666801713866244121245602255994692891031308924882229511798285554574949183744241271474954854124567793780282055959022388578786674058503642047846767669358674513850356363710515458249831883431353751436640473";}i:45;a:2:{s:1:"p";s:232:"1492587067635046724641688792619770082885080916623128596190835123187399555409237704094491882424098429004582220181182619740784070606699855534865664985479518843768489466772177132445303667209841765020506725096570944526583342827976693139";s:1:"g";s:232:"1325875501024611168460651086120280057597417113099909975171178841675907943309975119263343672690373708947175682795213117068208929462717160334883318825145705113989022565051297121267153447173858992622609588411242729579874123397975266138";}i:46;a:2:{s:1:"p";s:231:"906847226862001776111816505493768281038044494397978048283918521997355784196400638087866270344123622589898850349070632444514905302691870958199771371762471423025985936761842533697767348529899029836077448253984658354566967653666300291";s:1:"g";s:231:"736322087778788782539692146029647707897059850806268174498405656773634130296338358454597944410361988992697524598389896851941261557414721510027421303659079837206638916639575833006393233205754151775657992256732326725637747229302979816";}i:47;a:2:{s:1:"p";s:231:"890185901266080927782491491465517354612445249578323933865882607342218018045827339044063305815560761455409394432525412061214187429139579299492400591506581665066538172120639471965430764234311453555561931633194236909247720214805118073";s:1:"g";s:231:"124603950693163204561006130618370613293543114866078188752893479503564944442854829116472795873813395868608031842115370116074318303022427922128279623081129104975610062908095108555177761931096196714149047005610934112009256489171764836";}i:48;a:2:{s:1:"p";s:232:"1022859944913338265513498287914025160760413428632788273312840355167309743967660343293231033751474736710985228291770444169425283751203244350644086644312399632846696705942260278260962694665474670638153088334885364597590329213855838821";s:1:"g";s:226:"9300900657434489047696932947576507254742485851137640945740833346773894336289041369843665650418554527779923950617936614501875553729924367471021774760018370202907818481345597919412260900264979732317184833567650883567557893375062";}i:49;a:2:{s:1:"p";s:231:"847503998296101285006099790915650900236373726614141033690527723241117720398089645943375054063733472277302479655583554156249145819849151070540753896248678323721722706542142778548044002424582998724519091068547416460817463290942699611";s:1:"g";s:231:"331234074300921661629671326001536898454736192468494763379095145727215648933648617862566547316445817232073025874507971645175373540892437914378209189920515870658932521438504082293358796446613855932588162795845812833576149004264344863";}i:50;a:2:{s:1:"p";s:231:"776854996694680870329679766090923197499320601174183889649293954753262824403489810262166219938884720481651530046864995498795712155925117242820332769004044593138155353839210071553589166493553905531071130000245175488500608606205250473";s:1:"g";s:231:"122615309163484352435178123040514525950693264760022890223935351486389853053969215583729800598436270172453250408297048292547495756555972940864549104698760360917270926737887015081447655824274035565458153166275374845431297392097414896";}i:51;a:2:{s:1:"p";s:232:"1014670995663321290921359608373778357137361583080950879880689089887602978213452338329707495620559212973320829485461881514443972718327580018986415671475880393790411550869335287644265510938928754450088809257531645018845849163898576281";s:1:"g";s:231:"226285175444234122973784619180694638633082167482716005469342385327449875897886239234305738740923272773737253575122862208019661137330217557014525226385441537374271233018325429043614739444592408722828918457330769483139912858752454089";}i:52;a:2:{s:1:"p";s:232:"1513169936271423788180663828796897482214859916394590058813086550258563947455823332252203732874362687681400458889518212204992499000169381984431868914565922342454309296824550072503920915320186996860296769236804812815276715833511954449";s:1:"g";s:232:"1245465226405785393052937621442782210068505909794754716840697886490038597351985032447069389595318254694322269386159967688303058763948595197780433162530139509421500448636935611542180856628655340298116911739813872332241561279520583037";}i:53;a:2:{s:1:"p";s:231:"856013253876479059165623628305975849448863358527134908680506386730475791772900044328912984363736340417917938534652131715858635313983806851931477692304414025858982778155821878443831228714625883654404089352024899372025088563084316869";s:1:"g";s:231:"552321690037661308598423371621414370654966204550026610831501356822096243392290173211006773925495007312637920045552352583841618385583528133106087248629846785238349605708729343227241184823126680553458580263594415232887609278033875784";}i:54;a:2:{s:1:"p";s:232:"1334480887559536589949159249692733945384620792290589721623105750400119965602313717796597363544359710470206140367740972924185775527922974878933291445658045025445697156766756880651352317344857640429287980516377747569226931211212491243";s:1:"g";s:231:"831886041645277013617989310710106338581632774794225204139049756217555884181929382441547915129521121883033469509223234782099800019424095140055702151953921493983956381659390147459758077951959258488692700947152076829209345127239827417";}i:55;a:2:{s:1:"p";s:232:"1409778745614943123059960637458872383143362660474711587361838099172264328103771279599449433452471625362257540153827777349113762556225898756006249367026194953264828964987050273980148263779979224131073491468700936532944198371641899977";s:1:"g";s:231:"209776098029275436626677833731169078886117278885071715114505435642385983294326851305920611380028615674022483844583563627952192347687309821075096153883293433371184894010144321609833671939957316414645692604141259818517456628329910873";}i:56;a:2:{s:1:"p";s:231:"987430516189578827941284205088054611661620082263300587768516778434122699181082412846271052727003571281820389873181317063990985395433365942896367875649986698124817476989968806919034781078588254781147833741809007727914947756658579719";s:1:"g";s:231:"698200987352603681412105271807898748738354178489091119603323819681401784039318713333863338169737494530635558313935752562046668296212183293510873749175392352219364557252076204906131397081041002324767066945164857926826022730881675404";}i:57;a:2:{s:1:"p";s:231:"911040560362970417223048893768139389628988085687664013086009222099987221610406175395791423343767969898453296762333521288463623371559741795220949359469991966317300173096203451768448458436821759854332302902207049123095122563165328307";s:1:"g";s:231:"812594270498848930761688601344147752029772770381862776843635538689863728582355800020232123686093611039261541242167974286295835132480307822937387971672370687322097986874325541469317368635346834600976441766125378899144114323921195586";}i:58;a:2:{s:1:"p";s:231:"842219267974145775932989123792894671784125999773632266618794032004279619619519039224988473356968580745314383284533399642966645022341924016346852389496721864434033649276503114432343392698641490910905241779155079674669501466846833029";s:1:"g";s:231:"782544487507669192797122586247172939394023717046277995090644632052579755536328116096809168402110105266197800519534245921413986378461638788404319078240480929658281653750321747004440253112416813029050528374146052783221176298960313565";}i:59;a:2:{s:1:"p";s:232:"1525092809935288563055571570345820919524510847559774771965057561434975140299144568375358794076795210329084288787580378624089653481424466572254329602363278560207486423630141957923693225949486458225166351939026738254383383758746550647";s:1:"g";s:231:"263159922809445009879913179233924861644960413198762736113157873838038016723475464951892708348898454780740614412260641141522795265620349407440290686043887300757338238371334215462378864319590332417281238178704191943671667823961166359";}i:60;a:2:{s:1:"p";s:232:"1028460944421678739403869648025955612818770271689302644136310102933827246458867980827164258058168388339497134835171980844721573217633367276896282397205968182286615164389206641861298761008845793572995845616202743253555140748983244893";s:1:"g";s:231:"819672765703199092579137249865392990239671440769336584897585625379019575251829873924916934853746122876727468334182965088796386124896485109134891396778358088857805529756796787244840685815947720996926500076399919959153319935883154000";}i:61;a:2:{s:1:"p";s:232:"1116618938793971635251620742212333252084112686089695775091783024606337481417063400046973984308140430505905270470079059953893854704527630489326325210312207750227881050817557461457444716365677910986604362917828660471351341858494096857";s:1:"g";s:231:"886495389264431043361764083003188433619726956091423072234161147317167112643474214952357022594163640185279213659123211404675499610319150780444047197146211575454186803578750421194177193308281034306938461424526451109993556092290605627";}i:62;a:2:{s:1:"p";s:231:"797968355931248443337687572785194531681078668525894869616504982246134880136103339282591195913229534010078819186752873549484555106465378939218557464942306392378439519858664609681412161147401140973953299911521409960106976112377369951";s:1:"g";s:231:"640761121637205911582584925273104207639077147629241246006735106298865340150464943301800944597332710902710744600875720127926074244717989293323153036139147904419148401305887127992654239622527132611342941954632024239990149310032901493";}i:63;a:2:{s:1:"p";s:232:"1149737784597196134539684844606836077174184511853637046817912791784871386886645941003768607272989916774461791399081844778712220484980184567429117869606255891575455994880709403094980089125184082083924323339390199617654884285790410503";s:1:"g";s:232:"1039603101125034957436037513842799552783264469564219071603467222335050285123983992701815389502802987632956762276871132501712957623514952496732752114440497953627338896088394375658021187362290850795614408283008309971686190025693722153";}i:64;a:2:{s:1:"p";s:232:"1329797930634761192880862076059880539596186910848560549671049265461292267955242454490202990291540780566466579950852416159337549496195757247640919986667450812966261394943118725669861905621692926696165004880010479874148373172971610213";s:1:"g";s:231:"635837337839928249217276793990419059939905043474162074919430227356353695989613476295402258138887032051601585713030286174494298044263992707036482422495872394392828704770207161110057952905919230753270304119362774387785321873795683546";}i:65;a:2:{s:1:"p";s:232:"1448623913900261434798685222085379218669160577429273882531357393528490254936279125033819527984087800012125045586904590500187521846246409655319426639918743490196370521969556745886851634696767082843480238683377832803357594808338808789";s:1:"g";s:232:"1242441591251870653887844129258287272477292810570170069081695319311953376562545356798018649099374884003456979182728581452667824918519630973802906602011582350683406354751790448752315826286714466252353285493390468597894860032976159350";}i:66;a:2:{s:1:"p";s:232:"1529668939507791128869844490648290764124365901674422927387106692234341029103618077258533057496186461743031022527500511541916188830355814266429015729983198098357862460965845074171515400861687303837201652935516988746262569004563481137";s:1:"g";s:231:"360660974134492254118200341405376185297344709314085805544303296461805947453282575608141632805937006031503783222427477376904080696378020878384062503501827900451149127843292557616537602904756471733366682875566612490823990596275677543";}i:67;a:2:{s:1:"p";s:231:"964349802834715627091836311947560216190347334606515569347370133774200574976490727345212588410713504041991155364894697098411252472334205496527965699231720356863841683017206080615358842110850143586011962642589946348492970286665407969";s:1:"g";s:231:"929730835796228663589459296460175286247231890720354407494506948655435307304668112405072832284354983725176870181434323215671241174830416791009058499007576373683247657428144973843695554591048285334385411320546482122096833997170957438";}i:68;a:2:{s:1:"p";s:232:"1200697114919552440328212662493330951577090633392906181267524661711427686156563810555704977987849019161562995566572698389243095893050851873199166970487411925149684342035613532992590627108705912648804940551798506465761008844124620843";s:1:"g";s:231:"210840229717284786647061522612464250122170021966599147979091696189226789454714560674351814215640043731623851038273701713941465042304615442622261378902191416557966885769781607850757337283990327310991779274500108940892706318414163737";}i:69;a:2:{s:1:"p";s:232:"1505605269824790243792831609706828893984166952005042857668330387295629646099176754803575647869364684706773658989884573187558931362886298063556945978444360603261808118452381586301369212317883353307812109682258121601862761142502891243";s:1:"g";s:232:"1084946940052009414079442134492764126131699233360610931749616742969406318399538846909634709781884746606435633696011708795848205691494703339546378266099151348812964157880959214875332081239995818554049622469426669215553286217171990197";}i:70;a:2:{s:1:"p";s:231:"816293659194156584393426852964866212253294848481848239113280525200956078812795725547016870053079733390521590030205302119472344262085862246534098409593188906922670398233793986685054688205359526482886045473996570950709767907766332287";s:1:"g";s:231:"125543207479359049664289679776762548350219021118060184776896419904091327416143098271532647423069203715703939418436750054904161036732607263073370671224895462307089820071515048928316155155106995471046247116304202948872057424249829306";}i:71;a:2:{s:1:"p";s:231:"937909358947516337782226369107329834813267396990696800064373114984017087896265925553479913936810219544596193425124759913401224821463162739445133029127703779747659708487741259835192876317663968642084022533197690267855480324556527529";s:1:"g";s:231:"578517033963429110326177951658909289407442324189047815722917009976102126212418383103468613086046773738909381129731628643776381606497183416474147511436721740867586571298578391173413176636727370915614428453897927588536871545070706826";}i:72;a:2:{s:1:"p";s:231:"911550272168591326631587048781719864290181926192452902515376445349683296263628887572901987291151834516528416694948433228654143979995488104146391642798141995369742621984998796392603683788185226673225012070762425265022227280304690457";s:1:"g";s:231:"435611523987279849779799983928466846964355559414907696183238122605651893912177175547925756858491577574088472465417508238273767046169709657388574379877072876851067175453958959942263115528642058698110491508470757333448223479152968166";}i:73;a:2:{s:1:"p";s:232:"1402332241612496649303040369601818876241754896465490665184937776221374345017898846195563177922807182568607634848789855347331333564677335684945270608142923662833369689062726669830621769891269806986781199834351242524607209182727362697";s:1:"g";s:231:"788295437611846442150468706453593520179759913221608649431645370830934491660511057392020327584205620415434194214357441850022798625239262202825957968879464188504280320734830085023023361870953080951460626858564454404757439725700161728";}i:74;a:2:{s:1:"p";s:232:"1385588118482316945637342314640019438423845714093498454736894992477851611815122782181701750401675268595756082471037251485773810390075324501594034728931640633416343793046633227949070383016793194462388968861476522738244028507831412807";s:1:"g";s:232:"1051407953951842293497025880784993624653296083738495150909318042975954326467188611760483303718017506605889424046908175461440744704653882860969939760977844939897006735758164931979823290042430064727472581445761138927834062800381857331";}i:75;a:2:{s:1:"p";s:231:"978710653878765138245032780973262837628048824442834741766271800856407798633040866018143219855860066364565173258532133152860794957108413774041864442703022361098911014546932838970841896265536654441302583704650549691544524094461072893";s:1:"g";s:231:"828596696507489340388194242739437030691368481839839233808126012449055532045083652206448595030469705312890921141157727976947093518174537867725716826615058275916344778889368940911120325529008412131628881439241085844298695161516320553";}i:76;a:2:{s:1:"p";s:232:"1207869050442265806743029955005671272145050338468895879407536822447006913893944092569221761456800766031110931886064737811279146170983187046931749573257412308812343263137605940218514764728941135936260457381443965473446727029606288087";s:1:"g";s:231:"901689553109755299724889749491986982699260680669362599014476634410057613935478700557783089065666154315108435551124047123019756359394197131705864747694817007428554108935506622319753907531599531406412261181040137293635457527629166928";}i:77;a:2:{s:1:"p";s:232:"1253843053454842191496073929229960442713137064902092063097530760375305147828977522103815652822832423852327957157323143291242551095036701741131995598289925801806713520933881311587031812516333248233614882790453878318165294686629013069";s:1:"g";s:231:"792544431306829255892236222953864313824441744771937100881849165125912187035049340690583274721296595436406556486333849801845868860653775711166921783066039453091902252131197402979987834131940589379261131585088009418040811296418479470";}i:78;a:2:{s:1:"p";s:231:"888292115983090727383050041245510071901205022923621728740399250824091752574901194082071159280092849203038477423626851997364728759797869144784736703853891927718345111493348065946995574844270360480831713923673933284454590573945117963";s:1:"g";s:230:"33696947092788556772122343063346211890011409922110209522470356049181924373620706813436426151964317250350038187149729733343587721985790920558911543375733639941083283192766726820247487603481905775948491707522483335714118785605159459";}i:79;a:2:{s:1:"p";s:232:"1065050883104106794605549148848582174187670490934739354153582360382562310727039426519192822266718204976225715166151783557831632711336128952563917986548082358394005487114249579063266368998061115536978960094975378583758814372365078093";s:1:"g";s:231:"502815052869438460385725830457308481580545642069196745882872961945446262964900004194947659458399804093287259814745811856081827167061262636484787575169488738796518181394798689913840456698243916045055951843096761093530731109148515060";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/dhparams/96.dhp b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/96.dhp new file mode 100644 index 0000000..9234967 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/dhparams/96.dhp @@ -0,0 +1 @@ +a:200:{i:0;a:2:{s:1:"p";s:29:"47738868853409368611448259423";s:1:"g";s:29:"35731344447278389373151857379";}i:1;a:2:{s:1:"p";s:29:"54398515560371522763020384303";s:1:"g";s:29:"20945390328056174207502186797";}i:2;a:2:{s:1:"p";s:29:"67021188426992950294948561547";s:1:"g";s:29:"36939587946899170933046198189";}i:3;a:2:{s:1:"p";s:29:"39859896287770890834674542079";s:1:"g";s:29:"19966841823306563175123220931";}i:4;a:2:{s:1:"p";s:29:"76657699145424535679587536947";s:1:"g";s:29:"20742767732542452380807121413";}i:5;a:2:{s:1:"p";s:29:"65654697177391396856160066287";s:1:"g";s:29:"35809879532657391287512652743";}i:6;a:2:{s:1:"p";s:29:"71927430958542190463081134799";s:1:"g";s:29:"26380996146846587208902265941";}i:7;a:2:{s:1:"p";s:29:"73851341904947983664623532507";s:1:"g";s:29:"39064041849461247852710130779";}i:8;a:2:{s:1:"p";s:29:"75150031586910716586432162263";s:1:"g";s:29:"35111296103975510649443456551";}i:9;a:2:{s:1:"p";s:29:"48280401911664030048950789063";s:1:"g";s:29:"38708265162164817606775753013";}i:10;a:2:{s:1:"p";s:29:"46486903440519245437076708207";s:1:"g";s:29:"36853353883341331838222365225";}i:11;a:2:{s:1:"p";s:29:"71350463299297291211905999367";s:1:"g";s:29:"30011679077810814610369448397";}i:12;a:2:{s:1:"p";s:29:"49244741619315455361043774787";s:1:"g";s:29:"24808662195374590974786927029";}i:13;a:2:{s:1:"p";s:29:"75868764131932808789305748303";s:1:"g";s:29:"23008143271859447381803035283";}i:14;a:2:{s:1:"p";s:29:"43420198456255910520716195903";s:1:"g";s:29:"31396179578286978229414861957";}i:15;a:2:{s:1:"p";s:29:"65808217191785471358210112163";s:1:"g";s:29:"23010755437237062565991743601";}i:16;a:2:{s:1:"p";s:29:"46342915312221934564147401683";s:1:"g";s:29:"32030125422857259700058924785";}i:17;a:2:{s:1:"p";s:29:"64829190293054464121774784203";s:1:"g";s:29:"36833856892751915776286945241";}i:18;a:2:{s:1:"p";s:29:"45607701182765248395197208983";s:1:"g";s:29:"21399768901521056627247192929";}i:19;a:2:{s:1:"p";s:29:"44017242699060517442490417347";s:1:"g";s:29:"34633247284653303079399909831";}i:20;a:2:{s:1:"p";s:29:"53625999794377826447198971007";s:1:"g";s:29:"32287604526928583732085092887";}i:21;a:2:{s:1:"p";s:29:"63810410075798796194546009783";s:1:"g";s:29:"33103148562186353466279530571";}i:22;a:2:{s:1:"p";s:29:"55031538359753114159858892227";s:1:"g";s:29:"23141307673487499531413743651";}i:23;a:2:{s:1:"p";s:29:"69434150571492934132889103167";s:1:"g";s:29:"30086360725418560877456120447";}i:24;a:2:{s:1:"p";s:29:"74441928984373159899495560039";s:1:"g";s:29:"34511570476422028933751385293";}i:25;a:2:{s:1:"p";s:29:"59997318947177039408737791407";s:1:"g";s:29:"37250192862910145086661507129";}i:26;a:2:{s:1:"p";s:29:"64196128255368851154005218607";s:1:"g";s:29:"34000495373771857887090742069";}i:27;a:2:{s:1:"p";s:29:"59826698978200053030157188599";s:1:"g";s:29:"19964494685757012065098346707";}i:28;a:2:{s:1:"p";s:29:"62765736078018217621299172847";s:1:"g";s:29:"24033335135747484383237117689";}i:29;a:2:{s:1:"p";s:29:"51371314509993113368964576327";s:1:"g";s:29:"19894806293471511838941838425";}i:30;a:2:{s:1:"p";s:29:"62760444033308002378100678207";s:1:"g";s:29:"30291867805192457401765510895";}i:31;a:2:{s:1:"p";s:29:"53582209453070233186745035043";s:1:"g";s:29:"23236665247142302972696051523";}i:32;a:2:{s:1:"p";s:29:"58994643014783385857138676539";s:1:"g";s:29:"19937877643250391176571531199";}i:33;a:2:{s:1:"p";s:29:"48263329442960242226140798283";s:1:"g";s:29:"21427830008975221643678133239";}i:34;a:2:{s:1:"p";s:29:"62366601843842296162395153527";s:1:"g";s:29:"35945985312870131030534711981";}i:35;a:2:{s:1:"p";s:29:"72347374730426653226589947339";s:1:"g";s:29:"30316686633846692480439000229";}i:36;a:2:{s:1:"p";s:29:"66889481667385002256595238959";s:1:"g";s:29:"21467091715498685802445826655";}i:37;a:2:{s:1:"p";s:29:"57562601577612410905954202807";s:1:"g";s:29:"34758405076210401215630410679";}i:38;a:2:{s:1:"p";s:29:"63417186170491909088356422467";s:1:"g";s:29:"27136886202422383743778098461";}i:39;a:2:{s:1:"p";s:29:"76651191206554712261477581379";s:1:"g";s:29:"25399251868035504726174067835";}i:40;a:2:{s:1:"p";s:29:"39742911256893192535752596183";s:1:"g";s:29:"29759759175624969510221105241";}i:41;a:2:{s:1:"p";s:29:"53063241966256162112521986887";s:1:"g";s:29:"35220272870226041301738969745";}i:42;a:2:{s:1:"p";s:29:"64221489119473367767687041863";s:1:"g";s:29:"25840669648472436001824430091";}i:43;a:2:{s:1:"p";s:29:"60401269853569313228801931947";s:1:"g";s:29:"22842216079852083701198138345";}i:44;a:2:{s:1:"p";s:29:"50500264110803784895147849703";s:1:"g";s:29:"24516065342693939347117828967";}i:45;a:2:{s:1:"p";s:29:"61164830232419619474067092239";s:1:"g";s:29:"26352350231033249314852022313";}i:46;a:2:{s:1:"p";s:29:"51716169310525088129202326267";s:1:"g";s:29:"26869080532546514878512382181";}i:47;a:2:{s:1:"p";s:29:"62926434851243291755574116583";s:1:"g";s:29:"24702135412242925509885609547";}i:48;a:2:{s:1:"p";s:29:"63865341648786748578166981199";s:1:"g";s:29:"23148109461305702871386177549";}i:49;a:2:{s:1:"p";s:29:"72789069432219090760968655247";s:1:"g";s:29:"31725421034580831033290406407";}i:50;a:2:{s:1:"p";s:29:"70756969409504536529184861863";s:1:"g";s:29:"28734343666595496719979874355";}i:51;a:2:{s:1:"p";s:29:"50630182889501928368854656923";s:1:"g";s:29:"34567091595676569937103243609";}i:52;a:2:{s:1:"p";s:29:"45952510148678487096747574079";s:1:"g";s:29:"37518021674485079101709627061";}i:53;a:2:{s:1:"p";s:29:"42882857287768186855451631287";s:1:"g";s:29:"20526360990737333692515113039";}i:54;a:2:{s:1:"p";s:29:"50265722213854880338572192803";s:1:"g";s:29:"22320422205561467172183532507";}i:55;a:2:{s:1:"p";s:29:"52651538115728879925737034179";s:1:"g";s:29:"36248623767834351043173573133";}i:56;a:2:{s:1:"p";s:29:"71243579853974324810676006923";s:1:"g";s:29:"28678521167624470859587537987";}i:57;a:2:{s:1:"p";s:29:"44881273335703542822440685359";s:1:"g";s:29:"27890696956822713079463093069";}i:58;a:2:{s:1:"p";s:29:"54067724646431918836093765487";s:1:"g";s:29:"38671671346100133896621817829";}i:59;a:2:{s:1:"p";s:29:"77981751845097915350841714947";s:1:"g";s:29:"34109084447631028515541501111";}i:60;a:2:{s:1:"p";s:29:"41299579464656790538826461979";s:1:"g";s:29:"31559494063913514065552276299";}i:61;a:2:{s:1:"p";s:29:"43809367168096446620100258383";s:1:"g";s:29:"31617324402125986291976766901";}i:62;a:2:{s:1:"p";s:29:"41629110951264885953120606759";s:1:"g";s:29:"38406161804958433253138577097";}i:63;a:2:{s:1:"p";s:29:"63026171442062660193639618179";s:1:"g";s:29:"29507934963099337261103958697";}i:64;a:2:{s:1:"p";s:29:"76474084729118955201130431203";s:1:"g";s:29:"32171898945197339371170458907";}i:65;a:2:{s:1:"p";s:29:"78323059288301101312881667667";s:1:"g";s:29:"22199981962969777045604457961";}i:66;a:2:{s:1:"p";s:29:"48377222972554009039385650679";s:1:"g";s:29:"32614444658520497932785811087";}i:67;a:2:{s:1:"p";s:29:"49886103871936238106545100479";s:1:"g";s:29:"21092123691132028297201513947";}i:68;a:2:{s:1:"p";s:29:"43221299503205009879216909999";s:1:"g";s:29:"31490999503942396032305773621";}i:69;a:2:{s:1:"p";s:29:"72675669525257658331735232279";s:1:"g";s:29:"21625394843226904733988215413";}i:70;a:2:{s:1:"p";s:29:"60912699550998182788325971487";s:1:"g";s:29:"37125028105990641824493370751";}i:71;a:2:{s:1:"p";s:29:"41376435625834360066302056723";s:1:"g";s:29:"29184639342437770947343070079";}i:72;a:2:{s:1:"p";s:29:"75911859552795531794906334383";s:1:"g";s:29:"25591480945916785626340759655";}i:73;a:2:{s:1:"p";s:29:"65759239204590801774612362339";s:1:"g";s:29:"26155114179438446049102644089";}i:74;a:2:{s:1:"p";s:29:"65527216814120877501471071123";s:1:"g";s:29:"27930568859450263902637044387";}i:75;a:2:{s:1:"p";s:29:"70810182985925809810433127539";s:1:"g";s:29:"31957160993262417032979556405";}i:76;a:2:{s:1:"p";s:29:"57492899402310837998263313603";s:1:"g";s:29:"35724553374810107964858445377";}i:77;a:2:{s:1:"p";s:29:"43758636413285999568429004427";s:1:"g";s:29:"30488837552241539903120979149";}i:78;a:2:{s:1:"p";s:29:"56692097963982709200889953419";s:1:"g";s:29:"26271804900529999524482515699";}i:79;a:2:{s:1:"p";s:29:"77974047092081361669361958459";s:1:"g";s:29:"39126929749021168284193878989";}i:80;a:2:{s:1:"p";s:29:"78229682156975988879624724559";s:1:"g";s:29:"27911368145178527289382607881";}i:81;a:2:{s:1:"p";s:29:"62126252016749015886820739027";s:1:"g";s:29:"34055396134921086870545958899";}i:82;a:2:{s:1:"p";s:29:"67563355896875957624545837703";s:1:"g";s:29:"37486398928881331284746874917";}i:83;a:2:{s:1:"p";s:29:"50132370870533665921627496387";s:1:"g";s:29:"26059455883840798859750499105";}i:84;a:2:{s:1:"p";s:29:"39725206923751271728960689383";s:1:"g";s:29:"24609684584536618635376545477";}i:85;a:2:{s:1:"p";s:29:"51792948921405546760270684967";s:1:"g";s:29:"25995693514438136367087526063";}i:86;a:2:{s:1:"p";s:29:"55288338303675688577407630103";s:1:"g";s:29:"24223163922736270455212400515";}i:87;a:2:{s:1:"p";s:29:"52150198885087539120531512267";s:1:"g";s:29:"28166775980799901204464193159";}i:88;a:2:{s:1:"p";s:29:"64967370257521870837395382187";s:1:"g";s:29:"30197948617065071104206085765";}i:89;a:2:{s:1:"p";s:29:"57267259723766408733673540247";s:1:"g";s:29:"23386967103059011857791870243";}i:90;a:2:{s:1:"p";s:29:"52627911824296402395179157203";s:1:"g";s:29:"33293309894237358066888235147";}i:91;a:2:{s:1:"p";s:29:"71861809192052150172370739147";s:1:"g";s:29:"31044213605020388625039824137";}i:92;a:2:{s:1:"p";s:29:"70254513909085824681053192543";s:1:"g";s:29:"28798349198845097401709269813";}i:93;a:2:{s:1:"p";s:29:"41403540291961233368774818919";s:1:"g";s:29:"28798985963850612805220493955";}i:94;a:2:{s:1:"p";s:29:"48430431805183902912293107223";s:1:"g";s:29:"31404742280166410839686792815";}i:95;a:2:{s:1:"p";s:29:"51473404191184755474663299999";s:1:"g";s:29:"33843389600977412378505334397";}i:96;a:2:{s:1:"p";s:29:"70565571849996199202961193307";s:1:"g";s:29:"21716627740009390905807789193";}i:97;a:2:{s:1:"p";s:29:"78437005746991951735505214167";s:1:"g";s:29:"26924323797938784922617646411";}i:98;a:2:{s:1:"p";s:29:"43843055850061764331501276463";s:1:"g";s:29:"31987298334225618123314578601";}i:99;a:2:{s:1:"p";s:29:"53682770566445504403330150107";s:1:"g";s:29:"38927064063740890597015961647";}i:100;a:2:{s:1:"p";s:29:"48994954423636463292887914919";s:1:"g";s:29:"32652856528784949016397405041";}i:101;a:2:{s:1:"p";s:29:"44897157586817342996019100247";s:1:"g";s:29:"38840533683921393467308020649";}i:102;a:2:{s:1:"p";s:29:"67538483715108583872805797647";s:1:"g";s:29:"29919536376822345692569617879";}i:103;a:2:{s:1:"p";s:29:"50717592467559574799527034903";s:1:"g";s:29:"21517893190499507102203033779";}i:104;a:2:{s:1:"p";s:29:"70772395177637170507552342367";s:1:"g";s:29:"39434308756454820138634504439";}i:105;a:2:{s:1:"p";s:29:"53445905772090528659325390647";s:1:"g";s:29:"22551665344611641752027006601";}i:106;a:2:{s:1:"p";s:29:"52474468077274345269151992383";s:1:"g";s:29:"33352638404672259758390964327";}i:107;a:2:{s:1:"p";s:29:"67114005106800452560101178583";s:1:"g";s:29:"33084264118243593357598139587";}i:108;a:2:{s:1:"p";s:29:"58754852803087648151383432619";s:1:"g";s:29:"29086302567025374338700003541";}i:109;a:2:{s:1:"p";s:29:"63212231552431384571059657007";s:1:"g";s:29:"35530559402100927792425660111";}i:110;a:2:{s:1:"p";s:29:"42196611473333337298462210787";s:1:"g";s:29:"24592858785758227363491641241";}i:111;a:2:{s:1:"p";s:29:"44047438903651919269497203819";s:1:"g";s:29:"33075102551287629845592080029";}i:112;a:2:{s:1:"p";s:29:"52434265050670307985847764863";s:1:"g";s:29:"29887639044793235583920349563";}i:113;a:2:{s:1:"p";s:29:"54506429692472361223143536003";s:1:"g";s:29:"27693480481313114708529170763";}i:114;a:2:{s:1:"p";s:29:"72845129316148286033002738187";s:1:"g";s:29:"22179932387795580737090272661";}i:115;a:2:{s:1:"p";s:29:"71067088953897971478659333927";s:1:"g";s:29:"21865125582832109553224763593";}i:116;a:2:{s:1:"p";s:29:"50765915006154815563652014379";s:1:"g";s:29:"24925324101591485419008597689";}i:117;a:2:{s:1:"p";s:29:"41796273330675329512689479027";s:1:"g";s:29:"34498285623103961201616530779";}i:118;a:2:{s:1:"p";s:29:"71667652951249290315789870947";s:1:"g";s:29:"28597584821952440893599410119";}i:119;a:2:{s:1:"p";s:29:"40661876296207694113479633203";s:1:"g";s:29:"34618495347559751713231561811";}i:120;a:2:{s:1:"p";s:29:"75584625760448598854619320747";s:1:"g";s:29:"33825371145156064291302499673";}i:121;a:2:{s:1:"p";s:29:"72900646949748701155153254023";s:1:"g";s:29:"39056661372189487534797810227";}i:122;a:2:{s:1:"p";s:29:"39725262448989342209900586647";s:1:"g";s:29:"27012300571607327239173217505";}i:123;a:2:{s:1:"p";s:29:"70291076132593834744489638659";s:1:"g";s:29:"28287870352495913858579279891";}i:124;a:2:{s:1:"p";s:29:"68223492838054012745867773019";s:1:"g";s:29:"29812634632059772397466036447";}i:125;a:2:{s:1:"p";s:29:"53346092907654611928569785007";s:1:"g";s:29:"20380231076764775013716891749";}i:126;a:2:{s:1:"p";s:29:"42269250412327988046698168879";s:1:"g";s:29:"22359387614414132557852459585";}i:127;a:2:{s:1:"p";s:29:"57320431477944067979431873019";s:1:"g";s:29:"36389842917475191481639469737";}i:128;a:2:{s:1:"p";s:29:"53385052160780507951010260483";s:1:"g";s:29:"24906742945156753228249405845";}i:129;a:2:{s:1:"p";s:29:"77319125713145958575993682839";s:1:"g";s:29:"32250111047089288670189735029";}i:130;a:2:{s:1:"p";s:29:"75162993662684965129714771847";s:1:"g";s:29:"25661752946886423597912692337";}i:131;a:2:{s:1:"p";s:29:"45405625268025110880402518087";s:1:"g";s:29:"36319773469129114154499369695";}i:132;a:2:{s:1:"p";s:29:"59088448884756478306290294419";s:1:"g";s:29:"32191641691724471525681426191";}i:133;a:2:{s:1:"p";s:29:"48391361101895671980136152047";s:1:"g";s:29:"28674669966387337925758056971";}i:134;a:2:{s:1:"p";s:29:"60566037922797273575059507943";s:1:"g";s:29:"34215739467127691572238119127";}i:135;a:2:{s:1:"p";s:29:"59514789385135504034490479963";s:1:"g";s:29:"34710883816976378062106378581";}i:136;a:2:{s:1:"p";s:29:"72245746528041664913295702167";s:1:"g";s:29:"38377548355684432345447431019";}i:137;a:2:{s:1:"p";s:29:"77057467563788368450273635347";s:1:"g";s:29:"24241201973162188054931592279";}i:138;a:2:{s:1:"p";s:29:"43584371382806814935291636579";s:1:"g";s:29:"36659077432871194105682472635";}i:139;a:2:{s:1:"p";s:29:"53005996620921200751055268363";s:1:"g";s:29:"39257201959355896039903321299";}i:140;a:2:{s:1:"p";s:29:"42597100015430501275680415787";s:1:"g";s:29:"32728428281570006218679496853";}i:141;a:2:{s:1:"p";s:29:"57712518549539943687407899799";s:1:"g";s:29:"28523188239456579421576097165";}i:142;a:2:{s:1:"p";s:29:"57597321462679122556677087827";s:1:"g";s:29:"24238811025555864703506297729";}i:143;a:2:{s:1:"p";s:29:"52694154096382067677036327499";s:1:"g";s:29:"33003354138724083947013916347";}i:144;a:2:{s:1:"p";s:29:"49168587190281246808731914159";s:1:"g";s:29:"24787429202019511436089021743";}i:145;a:2:{s:1:"p";s:29:"64119909108206836355870531579";s:1:"g";s:29:"32491957206216938161091275705";}i:146;a:2:{s:1:"p";s:29:"50467793876433382124768013347";s:1:"g";s:29:"25130214130640956081967953409";}i:147;a:2:{s:1:"p";s:29:"58411160562120944539229614679";s:1:"g";s:29:"26984522061879150564144369855";}i:148;a:2:{s:1:"p";s:29:"40009347006163207215081987803";s:1:"g";s:29:"35770013420048480039829342671";}i:149;a:2:{s:1:"p";s:29:"70624660658773357720766101463";s:1:"g";s:29:"35824369666376333976531890557";}i:150;a:2:{s:1:"p";s:29:"64341975464068240469532696503";s:1:"g";s:29:"32530921439798458540338308785";}i:151;a:2:{s:1:"p";s:29:"50960275061167921310203607999";s:1:"g";s:29:"32132617625550502941234012677";}i:152;a:2:{s:1:"p";s:29:"56797267799962419081951774167";s:1:"g";s:29:"34288942257253430908202805755";}i:153;a:2:{s:1:"p";s:29:"58074017368865007334964216003";s:1:"g";s:29:"35729271862311203945689979405";}i:154;a:2:{s:1:"p";s:29:"40223717844890578002433478807";s:1:"g";s:29:"29589708703140870455838217981";}i:155;a:2:{s:1:"p";s:29:"46164472770902986360821507539";s:1:"g";s:29:"33305967083143761363730485247";}i:156;a:2:{s:1:"p";s:29:"51440898823119489454011434939";s:1:"g";s:29:"23297809258485493478497527275";}i:157;a:2:{s:1:"p";s:29:"69137161537503320226750697643";s:1:"g";s:29:"29057927675001690950633562415";}i:158;a:2:{s:1:"p";s:29:"70368416471670772916685973187";s:1:"g";s:29:"26999604070693000537404791371";}i:159;a:2:{s:1:"p";s:29:"63337430803646519385776522267";s:1:"g";s:29:"39568994791668376175953012565";}i:160;a:2:{s:1:"p";s:29:"44701686190263648211731573419";s:1:"g";s:29:"37932575585630911059257354979";}i:161;a:2:{s:1:"p";s:29:"67061963534677418365284083843";s:1:"g";s:29:"34424441366959344012129849399";}i:162;a:2:{s:1:"p";s:29:"73686066909490063572068902667";s:1:"g";s:29:"28555084362370984960397877705";}i:163;a:2:{s:1:"p";s:29:"67527858922200909359786778983";s:1:"g";s:29:"30749239501627454371477786151";}i:164;a:2:{s:1:"p";s:29:"61043739066730320355165466543";s:1:"g";s:29:"21595545896109312433802159723";}i:165;a:2:{s:1:"p";s:29:"45334723448893279488516029423";s:1:"g";s:29:"37137146908205066290903839065";}i:166;a:2:{s:1:"p";s:29:"56308214005582002693555810227";s:1:"g";s:29:"24843791296725163102719345885";}i:167;a:2:{s:1:"p";s:29:"67533150567370173925041652007";s:1:"g";s:29:"30782893351115458792404891185";}i:168;a:2:{s:1:"p";s:29:"77141896439196678834655501223";s:1:"g";s:29:"36061461453268822310804404211";}i:169;a:2:{s:1:"p";s:29:"53464136308124898869051497703";s:1:"g";s:29:"21070840867138524281210954559";}i:170;a:2:{s:1:"p";s:29:"43906866776363067808866128183";s:1:"g";s:29:"31371970727448398345771909917";}i:171;a:2:{s:1:"p";s:29:"42951929549489979042061459067";s:1:"g";s:29:"35303481350375126063754180319";}i:172;a:2:{s:1:"p";s:29:"55584206157809351576484752699";s:1:"g";s:29:"27521324978891503871880098457";}i:173;a:2:{s:1:"p";s:29:"64082684138871018024834206363";s:1:"g";s:29:"35430132693162906364375555257";}i:174;a:2:{s:1:"p";s:29:"72274680235256183639513224187";s:1:"g";s:29:"39323298720223462507539214629";}i:175;a:2:{s:1:"p";s:29:"50270465159644897332267799847";s:1:"g";s:29:"32162138971239505380120254023";}i:176;a:2:{s:1:"p";s:29:"71172742562279238052232728379";s:1:"g";s:29:"28087698829250168062118773909";}i:177;a:2:{s:1:"p";s:29:"58279975107815369320968409643";s:1:"g";s:29:"37477871871950017488642962513";}i:178;a:2:{s:1:"p";s:29:"76149833977762808075325714263";s:1:"g";s:29:"33495819233171658198843244729";}i:179;a:2:{s:1:"p";s:29:"78903549728711268080275522043";s:1:"g";s:29:"35575753121439896828664997439";}i:180;a:2:{s:1:"p";s:29:"50246227352468831277581528819";s:1:"g";s:29:"22165161926944506968934210845";}i:181;a:2:{s:1:"p";s:29:"40366543204773291628848006179";s:1:"g";s:29:"37491409231401195990400236255";}i:182;a:2:{s:1:"p";s:29:"52485686141888680631881366979";s:1:"g";s:29:"25008339028119954369958601375";}i:183;a:2:{s:1:"p";s:29:"75310123834070506632175194923";s:1:"g";s:29:"24911739307945577462298528211";}i:184;a:2:{s:1:"p";s:29:"43287453884743355180493459983";s:1:"g";s:29:"37431226064016553223888614739";}i:185;a:2:{s:1:"p";s:29:"72668048134235584782124599179";s:1:"g";s:29:"36083914805133754503902359713";}i:186;a:2:{s:1:"p";s:29:"42587035483492360208542295483";s:1:"g";s:29:"29425547602658008334973977237";}i:187;a:2:{s:1:"p";s:29:"48660742813847790093577802723";s:1:"g";s:29:"22181696030381210296639395281";}i:188;a:2:{s:1:"p";s:29:"43358224144805388273357480587";s:1:"g";s:29:"39214031095936595183935153561";}i:189;a:2:{s:1:"p";s:29:"78569919398561957497150141427";s:1:"g";s:29:"27386092272055272984209278553";}i:190;a:2:{s:1:"p";s:29:"71756187727640118653252286707";s:1:"g";s:29:"23705829101416778657726552921";}i:191;a:2:{s:1:"p";s:29:"51779331839710276181002026347";s:1:"g";s:29:"25380613792873774698286228915";}i:192;a:2:{s:1:"p";s:29:"57342881303922666441386957279";s:1:"g";s:29:"20848819641117789823622350199";}i:193;a:2:{s:1:"p";s:29:"70002251023023159545354683883";s:1:"g";s:29:"36610934624864460295158944359";}i:194;a:2:{s:1:"p";s:29:"44910825886538421594132535403";s:1:"g";s:29:"30512121148739912553086530975";}i:195;a:2:{s:1:"p";s:29:"75997480947050915451016792487";s:1:"g";s:29:"25177189795127991088001819331";}i:196;a:2:{s:1:"p";s:29:"71210454010817147751246783827";s:1:"g";s:29:"24081482543177517821419798409";}i:197;a:2:{s:1:"p";s:29:"48178222020174159336951481379";s:1:"g";s:29:"23875634060583990786793373517";}i:198;a:2:{s:1:"p";s:29:"41053972333108758025596811307";s:1:"g";s:29:"23250518637280344226689511927";}i:199;a:2:{s:1:"p";s:29:"65532547845146082502279866959";s:1:"g";s:29:"21702436153057868635835641145";}} \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/CREDITS b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/CREDITS new file mode 100644 index 0000000..4698d54 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/CREDITS @@ -0,0 +1,2 @@ +XXTEA PHP extension +Ma Bingyao (andot@coolcode.cn) diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/INSTALL b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/INSTALL new file mode 100644 index 0000000..258fc8a --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/INSTALL @@ -0,0 +1,66 @@ +Installing of XXTEA PHP package. + +There are many ways to build the package. Below you can find details for most +useful ways of package building: + +1. with PHP +2. with phpize utility +3. under Windows using Microsoft Visual C (.NET or VC6) + +----------------------------------------------------------------------------- +Way 1: Building the package with PHP +----------------------------------------------------------------------------- + +1. Create ext/xxtea folder in the php-source-folder. Copy all files + from the package into created folder. + +2. Run + ./buildconf + to rebuild PHP's configure script. + +3. Compile php with option: + --enable-xxtea to build bundled into PHP module + --enable-xxtea=shared to build dinamycally loadable module + +----------------------------------------------------------------------------- +Way 2: Building the package with phpize utility +----------------------------------------------------------------------------- + +1. Unpack contents of the package. + +2. Run + phpize + script, which will prepare environment for building XXTEA package. + +3. Run + ./configure --enable-xxtea=shared + to generate makefile + +4. Run + make + to build XXTEA extension library. It will be placed into + ./modules folder. + +5. Run + make install + to install XXTEA extension library into PHP + +----------------------------------------------------------------------------- +Way 3: Building the package under Windows using Microsoft Visual C (.NET or VC6) +----------------------------------------------------------------------------- +1. Create ext/xxtea folder in the php-source-folder. Copy all files + from the package into created folder. + +2. Copy php4ts.lib (for PHP4) or php5ts.lib (for PHP5) static library from + your version of PHP into ext/xxtea folder. + +3. Open php_xxtea.sln - solution file under MSVC.NET or php_xxtea.dsw - + workspace file under MSVC6. Try to build Release_php4 (for PHP4) or Release_php5 + (for PHP5) configuration. + +4. Copy php_xxtea.dll from ext/xxtea/Release_php4 or ext/xxtea/Release_php5 + into {extension_dir} folder. Path to {extension_dir} can be found in php.ini + +5. Add line + extension=php_xxtea.dll + into php.ini diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/LICENSE b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/LICENSE new file mode 100644 index 0000000..8d3fa07 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/LICENSE @@ -0,0 +1,68 @@ +-------------------------------------------------------------------- + The PHP License, version 3.01 +Copyright (c) 1999 - 2006 The PHP Group. All rights reserved. +-------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. The name "PHP" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact group@php.net. + + 4. Products derived from this software may not be called "PHP", nor + may "PHP" appear in their name, without prior written permission + from group@php.net. You may indicate that your software works in + conjunction with PHP by saying "Foo for PHP" instead of calling + it "PHP Foo" or "phpfoo" + + 5. The PHP Group may publish revised and/or new versions of the + license from time to time. Each version will be given a + distinguishing version number. + Once covered code has been published under a particular version + of the license, you may always continue to use it under the terms + of that version. You may also choose to use such covered code + under the terms of any subsequent version of the license + published by the PHP Group. No one other than the PHP Group has + the right to modify the terms applicable to covered code created + under this License. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes PHP software, freely available from + ". + +THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND +ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP +DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------- + +This software consists of voluntary contributions made by many +individuals on behalf of the PHP Group. + +The PHP Group can be contacted via Email at group@php.net. + +For more information on the PHP Group and the PHP project, +please see . + +PHP includes the Zend Engine, freely available at +. diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/README b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/README new file mode 100644 index 0000000..4a771bb --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/README @@ -0,0 +1,28 @@ +XXTEA PHP extension + +What is it? +----------------------------------------------- +This extension based on xxtea library, which provides a set of functions +for encrypt or decrypt data with XXTEA algorithm. + + + +How to install it? +----------------------------------------------- +See INSTALL for installation instructions. + + + +How to use it? +----------------------------------------------- +string xxtea_encrypt(string data, string key) + +Encrypt data using XXTEA algorithm. The key is a 16 bytes(128 bits) string. + +string xxtea_decrypt(string data, string key) + +Decrypt data using XXTEA algorithm. The key is a 16 bytes(128 bits) string. + +string xxtea_info() + +Get the version information. \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/config.m4 b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/config.m4 new file mode 100644 index 0000000..b9a24e6 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/config.m4 @@ -0,0 +1,7 @@ +PHP_ARG_ENABLE(xxtea, xxtea module, +[ --enable-xxtea Enable xxtea module.]) + +if test "$PHP_XXTEA" != "no"; then + PHP_NEW_EXTENSION(xxtea, php_xxtea.c xxtea.c, $ext_shared) + AC_DEFINE(HAVE_XXTEA, 1, [Have XXTEA library]) +fi diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/config.w32 b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/config.w32 new file mode 100644 index 0000000..63ad716 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/config.w32 @@ -0,0 +1,6 @@ +ARG_ENABLE("xxtea", "xxtea module", "no"); + +if (PHP_XXTEA != "no") { + EXTENSION("xxtea", "php_xxtea.c xxtea.c"); +} + diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.c b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.c new file mode 100644 index 0000000..cf0da4b --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.c @@ -0,0 +1,193 @@ +/*********************************************************************** + + Copyright 2006-2007 Ma Bingyao + + These sources is free software. Redistributions of source code must + retain the above copyright notice. Redistributions in binary form + must reproduce the above copyright notice. You can redistribute it + freely. You can use it with any free or commercial software. + + These sources is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. Without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You may contact the author by: + e-mail: andot@coolcode.cn + +*************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" + +#if HAVE_XXTEA +#include "php_xxtea.h" +#include "ext/standard/info.h" /* for phpinfo() functions */ +#include "xxtea.h" + +/* compiled function list so Zend knows what's in this module */ +zend_function_entry xxtea_functions[] = +{ + ZEND_FE(xxtea_encrypt, NULL) + ZEND_FE(xxtea_decrypt, NULL) + ZEND_FE(xxtea_info, NULL) + {NULL, NULL, NULL} +}; + +/* compiled module information */ +zend_module_entry xxtea_module_entry = +{ + STANDARD_MODULE_HEADER, + XXTEA_MODULE_NAME, + xxtea_functions, + ZEND_MINIT(xxtea), + ZEND_MSHUTDOWN(xxtea), + NULL, + NULL, + ZEND_MINFO(xxtea), + XXTEA_VERSION, + STANDARD_MODULE_PROPERTIES +}; + +/* implement standard "stub" routine to introduce ourselves to Zend */ +#if defined(COMPILE_DL_XXTEA) +ZEND_GET_MODULE(xxtea) +#endif + +static xxtea_long *xxtea_to_long_array(unsigned char *data, xxtea_long len, int include_length, xxtea_long *ret_len) { + xxtea_long i, n, *result; + n = len >> 2; + n = (((len & 3) == 0) ? n : n + 1); + if (include_length) { + result = (xxtea_long *)emalloc((n + 1) << 2); + result[n] = len; + *ret_len = n + 1; + } else { + result = (xxtea_long *)emalloc(n << 2); + *ret_len = n; + } + memset(result, 0, n << 2); + for (i = 0; i < len; i++) { + result[i >> 2] |= (xxtea_long)data[i] << ((i & 3) << 3); + } + return result; +} + +static unsigned char *xxtea_to_byte_array(xxtea_long *data, xxtea_long len, int include_length, xxtea_long *ret_len) { + xxtea_long i, n, m; + unsigned char *result; + n = len << 2; + if (include_length) { + m = data[len - 1]; + if ((m < n - 7) || (m > n - 4)) return NULL; + n = m; + } + result = (unsigned char *)emalloc(n + 1); + for (i = 0; i < n; i++) { + result[i] = (unsigned char)((data[i >> 2] >> ((i & 3) << 3)) & 0xff); + } + result[n] = '\0'; + *ret_len = n; + return result; +} + +static unsigned char *php_xxtea_encrypt(unsigned char *data, xxtea_long len, unsigned char *key, xxtea_long *ret_len) { + unsigned char *result; + xxtea_long *v, *k, v_len, k_len; + v = xxtea_to_long_array(data, len, 1, &v_len); + k = xxtea_to_long_array(key, 16, 0, &k_len); + xxtea_long_encrypt(v, v_len, k); + result = xxtea_to_byte_array(v, v_len, 0, ret_len); + efree(v); + efree(k); + return result; +} + +static unsigned char *php_xxtea_decrypt(unsigned char *data, xxtea_long len, unsigned char *key, xxtea_long *ret_len) { + unsigned char *result; + xxtea_long *v, *k, v_len, k_len; + v = xxtea_to_long_array(data, len, 0, &v_len); + k = xxtea_to_long_array(key, 16, 0, &k_len); + xxtea_long_decrypt(v, v_len, k); + result = xxtea_to_byte_array(v, v_len, 1, ret_len); + efree(v); + efree(k); + return result; +} + +/* {{{ proto string xxtea_encrypt(string data, string key) + Encrypt string using XXTEA algorithm */ +ZEND_FUNCTION(xxtea_encrypt) +{ + unsigned char *data, *key; + unsigned char *result; + xxtea_long data_len, key_len, ret_length; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &data, &data_len, &key, &key_len) == FAILURE) { + return; + } + if (data_len == 0) RETVAL_STRINGL(NULL, 0, 0); + if (key_len != 16) RETURN_FALSE; + result = php_xxtea_encrypt(data, data_len, key, &ret_length); + if (result != NULL) { + RETVAL_STRINGL((char *)result, ret_length, 0); + } else { + RETURN_FALSE; + } +} +/* }}} */ + + +/* {{{ proto string xxtea_decrypt(string data, string key) + Decrypt string using XXTEA algorithm */ +ZEND_FUNCTION(xxtea_decrypt) +{ + unsigned char *data, *key; + unsigned char *result; + xxtea_long data_len, key_len, ret_length; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &data, &data_len, &key, &key_len) == FAILURE) { + return; + } + if (data_len == 0) RETVAL_STRINGL(NULL, 0, 0); + if (key_len != 16) RETURN_FALSE; + result = php_xxtea_decrypt(data, data_len, key, &ret_length); + if (result != NULL) { + RETVAL_STRINGL((char *)result, ret_length, 0); + } else { + RETURN_FALSE; + } +} +/* }}} */ + +ZEND_MINIT_FUNCTION(xxtea) +{ + return SUCCESS; +} + +ZEND_MSHUTDOWN_FUNCTION(xxtea) +{ + return SUCCESS; +} + +ZEND_MINFO_FUNCTION(xxtea) +{ + php_info_print_table_start(); + php_info_print_table_row(2, "xxtea support", "enabled"); + php_info_print_table_row(2, "xxtea module version", XXTEA_VERSION); + php_info_print_table_row(2, "xxtea author", XXTEA_AUTHOR); + php_info_print_table_row(2, "xxtea homepage", XXTEA_HOMEPAGE); + php_info_print_table_end(); +} + +ZEND_FUNCTION(xxtea_info) +{ + array_init(return_value); + add_assoc_string(return_value, "ext_version", XXTEA_VERSION, 1); + add_assoc_string(return_value, "ext_build_date", XXTEA_BUILD_DATE, 1); + add_assoc_string(return_value, "ext_author", XXTEA_AUTHOR, 1); + add_assoc_string(return_value, "ext_homepage", XXTEA_HOMEPAGE, 1); +} + +#endif /* if HAVE_XXTEA */ diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.dsp b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.dsp new file mode 100644 index 0000000..1554b90 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.dsp @@ -0,0 +1,179 @@ +# Microsoft Developer Studio Project File - Name="php_xxtea" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=php_xxtea - Win32 Debug_php5 +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "php_xxtea.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "php_xxtea.mak" CFG="php_xxtea - Win32 Debug_php5" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "php_xxtea - Win32 Debug_php5" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "php_xxtea - Win32 Release_php5" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "php_xxtea - Win32 Debug_php4" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "php_xxtea - Win32 Release_php4" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "php_xxtea - Win32 Debug_php5" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_php5" +# PROP BASE Intermediate_Dir "Debug_php5" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_php5" +# PROP Intermediate_Dir "Debug_php5" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /I "../.." /I "../../main" /I "../../Zend" /I "../../TSRM" /ZI /W3 /Od /D "HAVE_XXTEA" /D "COMPILE_DL_XXTEA" /D "ZTS" /D "NDEBUG" /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "ZEND_DEBUG=1" /D "_MBCS" /Gm /GZ /c /GX +# ADD CPP /nologo /MTd /I "../.." /I "../../main" /I "../../Zend" /I "../../TSRM" /ZI /W3 /Od /D "HAVE_XXTEA" /D "COMPILE_DL_XXTEA" /D "ZTS" /D "NDEBUG" /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "ZEND_DEBUG=1" /D "_MBCS" /Gm /GZ /c /GX +# ADD BASE MTL /nologo /win32 +# ADD MTL /nologo /win32 +# ADD BASE RSC /l 1033 +# ADD RSC /l 1033 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php5ts.lib /nologo /dll /out:"Debug_php5\php_xxtea.dll" /incremental:yes /libpath:"../../Release_TS" /debug /pdb:"Debug_php5\php_xxtea.pdb" /pdbtype:sept /subsystem:windows /implib:"$(OutDir)/php_xxtea.lib" /machine:ix86 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php5ts.lib /nologo /dll /out:"Debug_php5\php_xxtea.dll" /incremental:yes /libpath:"../../Release_TS" /debug /pdb:"Debug_php5\php_xxtea.pdb" /pdbtype:sept /subsystem:windows /implib:"$(OutDir)/php_xxtea.lib" /machine:ix86 + +!ELSEIF "$(CFG)" == "php_xxtea - Win32 Release_php5" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_php5" +# PROP BASE Intermediate_Dir "Release_php5" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_php5" +# PROP Intermediate_Dir "Release_php5" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /I "../.." /I "../../main" /I "../../Zend" /I "../../TSRM" /W3 /O1 /Og /Oi /Os /Oy /GT /G6 /GA /D "HAVE_XXTEA" /D "COMPILE_DL_XXTEA" /D "ZTS" /D "NDEBUG" /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "ZEND_DEBUG=0" /D "_MBCS" /GF /Gy /TC /c /GX +# ADD CPP /nologo /MD /I "../.." /I "../../main" /I "../../Zend" /I "../../TSRM" /W3 /O1 /Og /Oi /Os /Oy /GT /G6 /GA /D "HAVE_XXTEA" /D "COMPILE_DL_XXTEA" /D "ZTS" /D "NDEBUG" /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "ZEND_DEBUG=0" /D "_MBCS" /GF /Gy /TC /c /GX +# ADD BASE MTL /nologo /win32 +# ADD MTL /nologo /win32 +# ADD BASE RSC /l 1033 +# ADD RSC /l 1033 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php5ts.lib /nologo /dll /out:"Release_php5\php_xxtea.dll" /incremental:no /libpath:"../../Release_TS" /pdbtype:sept /subsystem:windows /opt:ref /opt:icf /implib:"$(OutDir)/php_xxtea.lib" /machine:ix86 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php5ts.lib /nologo /dll /out:"Release_php5\php_xxtea.dll" /incremental:no /libpath:"../../Release_TS" /pdbtype:sept /subsystem:windows /opt:ref /opt:icf /implib:"$(OutDir)/php_xxtea.lib" /machine:ix86 + +!ELSEIF "$(CFG)" == "php_xxtea - Win32 Debug_php4" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_php4" +# PROP BASE Intermediate_Dir "Debug_php4" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_php4" +# PROP Intermediate_Dir "Debug_php4" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /I "../.." /I "../../main" /I "../../Zend" /I "../../TSRM" /ZI /W3 /Od /D "HAVE_XXTEA" /D "COMPILE_DL_XXTEA" /D "ZTS" /D "NDEBUG" /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "ZEND_DEBUG=1" /D "_MBCS" /Gm /GZ /c /GX +# ADD CPP /nologo /MTd /I "../.." /I "../../main" /I "../../Zend" /I "../../TSRM" /ZI /W3 /Od /D "HAVE_XXTEA" /D "COMPILE_DL_XXTEA" /D "ZTS" /D "NDEBUG" /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "ZEND_DEBUG=1" /D "_MBCS" /Gm /GZ /c /GX +# ADD BASE MTL /nologo /win32 +# ADD MTL /nologo /win32 +# ADD BASE RSC /l 1033 +# ADD RSC /l 1033 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /out:"Debug_php4\php_xxtea.dll" /incremental:yes /libpath:"../../Release_TS" /debug /pdb:"Debug_php4\php_xxtea.pdb" /pdbtype:sept /subsystem:windows /implib:"$(OutDir)/php_xxtea.lib" /machine:ix86 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /out:"Debug_php4\php_xxtea.dll" /incremental:yes /libpath:"../../Release_TS" /debug /pdb:"Debug_php4\php_xxtea.pdb" /pdbtype:sept /subsystem:windows /implib:"$(OutDir)/php_xxtea.lib" /machine:ix86 + +!ELSEIF "$(CFG)" == "php_xxtea - Win32 Release_php4" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_php4" +# PROP BASE Intermediate_Dir "Release_php4" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_php4" +# PROP Intermediate_Dir "Release_php4" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /I "../.." /I "../../main" /I "../../Zend" /I "../../TSRM" /W3 /O1 /Og /Oi /Os /Oy /GT /G6 /GA /D "HAVE_XXTEA" /D "COMPILE_DL_XXTEA" /D "ZTS" /D "NDEBUG" /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "ZEND_DEBUG=0" /D "_MBCS" /GF /Gy /TC /c /GX +# ADD CPP /nologo /MD /I "../.." /I "../../main" /I "../../Zend" /I "../../TSRM" /W3 /O1 /Og /Oi /Os /Oy /GT /G6 /GA /D "HAVE_XXTEA" /D "COMPILE_DL_XXTEA" /D "ZTS" /D "NDEBUG" /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "ZEND_DEBUG=0" /D "_MBCS" /GF /Gy /TC /c /GX +# ADD BASE MTL /nologo /win32 +# ADD MTL /nologo /win32 +# ADD BASE RSC /l 1033 +# ADD RSC /l 1033 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /out:"Release_php4\php_xxtea.dll" /incremental:no /libpath:"../../Release_TS" /pdbtype:sept /subsystem:windows /opt:ref /opt:icf /implib:"$(OutDir)/php_xxtea.lib" /machine:ix86 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib /nologo /dll /out:"Release_php4\php_xxtea.dll" /incremental:no /libpath:"../../Release_TS" /pdbtype:sept /subsystem:windows /opt:ref /opt:icf /implib:"$(OutDir)/php_xxtea.lib" /machine:ix86 + +!ENDIF + +# Begin Target + +# Name "php_xxtea - Win32 Debug_php5" +# Name "php_xxtea - Win32 Release_php5" +# Name "php_xxtea - Win32 Debug_php4" +# Name "php_xxtea - Win32 Release_php4" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;def;odl;idl;hpj;bat;asm" +# Begin Source File + +SOURCE=php_xxtea.c +# End Source File +# Begin Group "lib_xxtea" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=xxtea.c +# End Source File +# End Group +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;inc" +# Begin Source File + +SOURCE=php_xxtea.h +# End Source File +# Begin Group "lib_xxtea" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=xxtea.h +# End Source File +# End Group +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.h b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.h new file mode 100644 index 0000000..080c380 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.h @@ -0,0 +1,49 @@ +/*********************************************************************** + + Copyright 2006-2007 Ma Bingyao + + These sources is free software. Redistributions of source code must + retain the above copyright notice. Redistributions in binary form + must reproduce the above copyright notice. You can redistribute it + freely. You can use it with any free or commercial software. + + These sources is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. Without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You may contact the author by: + e-mail: andot@coolcode.cn + +*************************************************************************/ + +#ifndef PHP_XXTEA_H +#define PHP_XXTEA_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_XXTEA +extern zend_module_entry xxtea_module_entry; +#define phpext_xxtea_ptr &xxtea_module_entry + +#define XXTEA_MODULE_NAME "xxtea" +#define XXTEA_BUILD_DATE __DATE__ " " __TIME__ +#define XXTEA_VERSION "1.0.3" +#define XXTEA_AUTHOR "Ma Bingyao" +#define XXTEA_HOMEPAGE "http://www.coolcode.cn/?p=209" + +ZEND_MINIT_FUNCTION(xxtea); +ZEND_MSHUTDOWN_FUNCTION(xxtea); +ZEND_MINFO_FUNCTION(xxtea); + +/* declaration of functions to be exported */ +ZEND_FUNCTION(xxtea_encrypt); +ZEND_FUNCTION(xxtea_decrypt); +ZEND_FUNCTION(xxtea_info); + +#else /* if HAVE_XXTEA */ +#define phpext_xxtea_ptr NULL +#endif + +#endif /* ifndef PHP_XXTEA_H */ diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.sln b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.sln new file mode 100644 index 0000000..5f5a5c2 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "php_xxtea", "php_xxtea.vcproj", "{71165FA5-1EBC-4021-AA17-0CCBC7CD5204}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_php4|Win32 = Debug_php4|Win32 + Debug_php5|Win32 = Debug_php5|Win32 + Release_php4|Win32 = Release_php4|Win32 + Release_php5|Win32 = Release_php5|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71165FA5-1EBC-4021-AA17-0CCBC7CD5204}.Debug_php4|Win32.ActiveCfg = Debug_php4|Win32 + {71165FA5-1EBC-4021-AA17-0CCBC7CD5204}.Debug_php4|Win32.Build.0 = Debug_php4|Win32 + {71165FA5-1EBC-4021-AA17-0CCBC7CD5204}.Debug_php5|Win32.ActiveCfg = Debug_php5|Win32 + {71165FA5-1EBC-4021-AA17-0CCBC7CD5204}.Debug_php5|Win32.Build.0 = Debug_php5|Win32 + {71165FA5-1EBC-4021-AA17-0CCBC7CD5204}.Release_php4|Win32.ActiveCfg = Release_php4|Win32 + {71165FA5-1EBC-4021-AA17-0CCBC7CD5204}.Release_php4|Win32.Build.0 = Release_php4|Win32 + {71165FA5-1EBC-4021-AA17-0CCBC7CD5204}.Release_php5|Win32.ActiveCfg = Release_php5|Win32 + {71165FA5-1EBC-4021-AA17-0CCBC7CD5204}.Release_php5|Win32.Build.0 = Release_php5|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.vcproj b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.vcproj new file mode 100644 index 0000000..aedf004 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/php_xxtea.vcproj @@ -0,0 +1,520 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/test/test.php b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/test/test.php new file mode 100644 index 0000000..071b178 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/test/test.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/xxtea.c b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/xxtea.c new file mode 100644 index 0000000..a3d956d --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/xxtea.c @@ -0,0 +1,54 @@ +/*********************************************************************** + + Copyright 2006-2007 Ma Bingyao + + These sources is free software. Redistributions of source code must + retain the above copyright notice. Redistributions in binary form + must reproduce the above copyright notice. You can redistribute it + freely. You can use it with any free or commercial software. + + These sources is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. Without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You may contact the author by: + e-mail: andot@coolcode.cn + +*************************************************************************/ +#include "xxtea.h" + +void xxtea_long_encrypt(xxtea_long *v, xxtea_long len, xxtea_long *k) { + xxtea_long n = len - 1; + xxtea_long z = v[n], y = v[0], p, q = 6 + 52 / (n + 1), sum = 0, e; + if (n < 1) { + return; + } + while (0 < q--) { + sum += XXTEA_DELTA; + e = sum >> 2 & 3; + for (p = 0; p < n; p++) { + y = v[p + 1]; + z = v[p] += XXTEA_MX; + } + y = v[0]; + z = v[n] += XXTEA_MX; + } +} + +void xxtea_long_decrypt(xxtea_long *v, xxtea_long len, xxtea_long *k) { + xxtea_long n = len - 1; + xxtea_long z = v[n], y = v[0], p, q = 6 + 52 / (n + 1), sum = q * XXTEA_DELTA, e; + if (n < 1) { + return; + } + while (sum != 0) { + e = sum >> 2 & 3; + for (p = n; p > 0; p--) { + z = v[p - 1]; + y = v[p] -= XXTEA_MX; + } + z = v[n]; + y = v[0] -= XXTEA_MX; + sum -= XXTEA_DELTA; + } +} diff --git a/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/xxtea.h b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/xxtea.h new file mode 100644 index 0000000..bcc2067 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/pecl/xxtea/xxtea.h @@ -0,0 +1,47 @@ +/*********************************************************************** + + Copyright 2006-2007 Ma Bingyao + + These sources is free software. Redistributions of source code must + retain the above copyright notice. Redistributions in binary form + must reproduce the above copyright notice. You can redistribute it + freely. You can use it with any free or commercial software. + + These sources is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. Without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You may contact the author by: + e-mail: andot@coolcode.cn + +*************************************************************************/ + +#ifndef XXTEA_H +#define XXTEA_H + +#include /* for size_t & NULL declarations */ + +#if defined(_MSC_VER) + +typedef unsigned __int32 xxtea_long; + +#else + +#if defined(__FreeBSD__) && __FreeBSD__ < 5 +/* FreeBSD 4 doesn't have stdint.h file */ +#include +#else +#include +#endif + +typedef uint32_t xxtea_long; + +#endif /* end of if defined(_MSC_VER) */ + +#define XXTEA_MX (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z) +#define XXTEA_DELTA 0x9e3779b9 + +void xxtea_long_encrypt(xxtea_long *v, xxtea_long len, xxtea_long *k); +void xxtea_long_decrypt(xxtea_long *v, xxtea_long len, xxtea_long *k); + +#endif diff --git a/ThinkPHP/Extend/Vendor/phpRPC/phprpc_client.php b/ThinkPHP/Extend/Vendor/phpRPC/phprpc_client.php new file mode 100644 index 0000000..569681b --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/phprpc_client.php @@ -0,0 +1,583 @@ + | +| | +| This file may be distributed and/or modified under the | +| terms of the GNU General Public License (GPL) version | +| 2.0 as published by the Free Software Foundation and | +| appearing in the included file LICENSE. | +| | +\**********************************************************/ + +/* PHPRPC Client for PHP. + * + * Copyright: Ma Bingyao + * Version: 3.0 + * LastModified: Apr 12, 2010 + * This library is free. You can redistribute it and/or modify it under GPL. + * +/* + * Interfaces + * + * $rpc_client = new PHPRPC_Client(); + * $rpc_client->setProxy(NULL); + * $rpc_client->useService('http://www.phprpc.org/server.php'); + * $rpc_client->setKeyLength(1024); + * $rpc_client->setEncryptMode(3); + * $args = array(1, 2); + * echo $rpc_client->invoke('add', &$args); + * echo "
    "; + * $n = 3; + * $args = array(&$n); + * echo $rpc_client->invoke('inc', &$args, true); + * echo "
    "; + * echo $rpc_client->sub(3, 2); + * echo "
    "; + * // error handle + * $result = $rpc_client->mul(1, 2); // no mul function + * if (is_a($result, "PHPRPC_Error")) { + * echo $result->toString(); + * } + */ + + +$_PHPRPC_COOKIES = array(); +$_PHPRPC_COOKIE = ''; +$_PHPRPC_SID = 0; + +if (defined('KEEP_PHPRPC_COOKIE_IN_SESSION')) { + if (isset($_SESSION['phprpc_cookies']) and isset($_SESSION['phprpc_cookie'])) { + $_PHPRPC_COOKIES = $_SESSION['phprpc_cookies']; + $_PHPRPC_COOKIE = $_SESSION['phprpc_cookie']; + } + function keep_phprpc_cookie_in_session() { + global $_PHPRPC_COOKIES, $_PHPRPC_COOKIE; + $_SESSION['phprpc_cookies'] = $_PHPRPC_COOKIES; + $_SESSION['phprpc_cookie'] = $_PHPRPC_COOKIE; + } + register_shutdown_function('keep_phprpc_cookie_in_session'); +} + +class PHPRPC_Error { + var $Number; + var $Message; + function PHPRPC_Error($errno, $errstr) { + $this->Number = $errno; + $this->Message = $errstr; + } + function toString() { + return $this->Number . ":" . $this->Message; + } + function __toString() { + return $this->toString(); + } + function getNumber() { + return $this->Number; + } + function getMessage() { + return $this->Message; + } +} + +class _PHPRPC_Client { + var $_server; + var $_timeout; + var $_output; + var $_warning; + var $_proxy; + var $_key; + var $_keylen; + var $_encryptMode; + var $_charset; + var $_socket; + var $_clientid; + var $_http_version; + var $_keep_alive; + // Public Methods + function _PHPRPC_Client($serverURL = '') { + global $_PHPRPC_SID; + require_once('compat.php'); + //register_shutdown_function(array(&$this, "_disconnect")); + $this->_proxy = NULL; + $this->_timeout = 30; + $this->_clientid = 'php' . rand(1 << 30, 1 << 31) . time() . $_PHPRPC_SID; + $_PHPRPC_SID++; + $this->_socket = false; + if ($serverURL != '') { + $this->useService($serverURL); + } + } + function useService($serverURL, $username = NULL, $password = NULL) { + $this->_disconnect(); + $this->_http_version = "1.1"; + $this->_keep_alive = true; + $this->_server = array(); + $this->_key = NULL; + $this->_keylen = 128; + $this->_encryptMode = 0; + $this->_charset = 'utf-8'; + $urlparts = parse_url($serverURL); + if (!isset($urlparts['host'])) { + if (isset($_SERVER["HTTP_HOST"])) { + $urlparts['host'] = $_SERVER["HTTP_HOST"]; + } + else if (isset($_SERVER["SERVER_NAME"])) { + $urlparts['host'] = $_SERVER["SERVER_NAME"]; + } + else { + $urlparts['host'] = "localhost"; + } + if (!isset($_SERVER["HTTPS"]) || + $_SERVER["HTTPS"] == "off" || + $_SERVER["HTTPS"] == "") { + $urlparts['scheme'] = "http"; + } + else { + $urlparts['scheme'] = "https"; + } + $urlparts['port'] = $_SERVER["SERVER_PORT"]; + } + + if (!isset($urlparts['port'])) { + if ($urlparts['scheme'] == "https") { + $urlparts['port'] = 443; + } + else { + $urlparts['port'] = 80; + } + } + + if (!isset($urlparts['path'])) { + $urlparts['path'] = "/"; + } + else if (($urlparts['path']{0} != '/') && ($_SERVER["PHP_SELF"]{0} == '/')) { + $urlparts['path'] = substr($_SERVER["PHP_SELF"], 0, strrpos($_SERVER["PHP_SELF"], '/') + 1) . $urlparts['path']; + } + + if (isset($urlparts['query'])) { + $urlparts['path'] .= '?' . $urlparts['query']; + } + + if (!isset($urlparts['user']) || !is_null($username)) { + $urlparts['user'] = $username; + } + + if (!isset($urlparts['pass']) || !is_null($password)) { + $urlparts['pass'] = $password; + } + + $this->_server['scheme'] = $urlparts['scheme']; + $this->_server['host'] = $urlparts['host']; + $this->_server['port'] = $urlparts['port']; + $this->_server['path'] = $urlparts['path']; + $this->_server['user'] = $urlparts['user']; + $this->_server['pass'] = $urlparts['pass']; + } + function setProxy($host, $port = NULL, $username = NULL, $password = NULL) { + if (is_null($host)) { + $this->_proxy = NULL; + } + else { + if (is_null($port)) { + $urlparts = parse_url($host); + if (isset($urlparts['host'])) { + $host = $urlparts['host']; + } + if (isset($urlparts['port'])) { + $port = $urlparts['port']; + } + else { + $port = 80; + } + if (isset($urlparts['user']) && is_null($username)) { + $username = $urlparts['user']; + } + if (isset($urlparts['pass']) && is_null($password)) { + $password = $urlparts['pass']; + } + } + $this->_proxy = array(); + $this->_proxy['host'] = $host; + $this->_proxy['port'] = $port; + $this->_proxy['user'] = $username; + $this->_proxy['pass'] = $password; + } + } + function setKeyLength($keylen) { + if (!is_null($this->_key)) { + return false; + } + else { + $this->_keylen = $keylen; + return true; + } + } + function getKeyLength() { + return $this->_keylen; + } + function setEncryptMode($encryptMode) { + if (($encryptMode >= 0) && ($encryptMode <= 3)) { + $this->_encryptMode = (int)($encryptMode); + return true; + } + else { + $this->_encryptMode = 0; + return false; + } + } + function getEncryptMode() { + return $this->_encryptMode; + } + function setCharset($charset) { + $this->_charset = $charset; + } + function getCharset() { + return $this->_charset; + } + function setTimeout($timeout) { + $this->_timeout = $timeout; + } + function getTimeout() { + return $this->_timeout; + } + function invoke($funcname, &$args, $byRef = false) { + $result = $this->_key_exchange(); + if (is_a($result, 'PHPRPC_Error')) { + return $result; + } + $request = "phprpc_func=$funcname"; + if (count($args) > 0) { + $request .= "&phprpc_args=" . base64_encode($this->_encrypt(serialize_fix($args), 1)); + } + $request .= "&phprpc_encrypt={$this->_encryptMode}"; + if (!$byRef) { + $request .= "&phprpc_ref=false"; + } + $request = str_replace('+', '%2B', $request); + $result = $this->_post($request); + if (is_a($result, 'PHPRPC_Error')) { + return $result; + } + $phprpc_errno = 0; + $phprpc_errstr = NULL; + if (isset($result['phprpc_errno'])) { + $phprpc_errno = intval($result['phprpc_errno']); + } + if (isset($result['phprpc_errstr'])) { + $phprpc_errstr = base64_decode($result['phprpc_errstr']); + } + $this->_warning = new PHPRPC_Error($phprpc_errno, $phprpc_errstr); + if (array_key_exists('phprpc_output', $result)) { + $this->_output = base64_decode($result['phprpc_output']); + if ($this->_server['version'] >= 3) { + $this->_output = $this->_decrypt($this->_output, 3); + } + } + else { + $this->_output = ''; + } + if (array_key_exists('phprpc_result', $result)) { + if (array_key_exists('phprpc_args', $result)) { + $arguments = unserialize($this->_decrypt(base64_decode($result['phprpc_args']), 1)); + for ($i = 0; $i < count($arguments); $i++) { + $args[$i] = $arguments[$i]; + } + } + $result = unserialize($this->_decrypt(base64_decode($result['phprpc_result']), 2)); + } + else { + $result = $this->_warning; + } + return $result; + } + + function getOutput() { + return $this->_output; + } + + function getWarning() { + return $this->_warning; + } + + function _connect() { + if (is_null($this->_proxy)) { + $host = (($this->_server['scheme'] == "https") ? "ssl://" : "") . $this->_server['host']; + $this->_socket = @pfsockopen($host, $this->_server['port'], $errno, $errstr, $this->_timeout); + } + else { + $host = (($this->_server['scheme'] == "https") ? "ssl://" : "") . $this->_proxy['host']; + $this->_socket = @pfsockopen($host, $this->_proxy['port'], $errno, $errstr, $this->_timeout); + } + if ($this->_socket === false) { + return new PHPRPC_Error($errno, $errstr); + } + stream_set_write_buffer($this->_socket, 0); + socket_set_timeout($this->_socket, $this->_timeout); + return true; + } + + function _disconnect() { + if ($this->_socket !== false) { + fclose($this->_socket); + $this->_socket = false; + } + } + + function _socket_read($size) { + $content = ""; + while (!feof($this->_socket) && ($size > 0)) { + $str = fread($this->_socket, $size); + $content .= $str; + $size -= strlen($str); + } + return $content; + } + function _post($request_body) { + global $_PHPRPC_COOKIE; + $request_body = 'phprpc_id=' . $this->_clientid . '&' . $request_body; + if ($this->_socket === false) { + $error = $this->_connect(); + if (is_a($error, 'PHPRPC_Error')) { + return $error; + } + } + if (is_null($this->_proxy)) { + $url = $this->_server['path']; + $connection = "Connection: " . ($this->_keep_alive ? 'Keep-Alive' : 'Close') . "\r\n" . + "Cache-Control: no-cache\r\n"; + } + else { + $url = "{$this->_server['scheme']}://{$this->_server['host']}:{$this->_server['port']}{$this->_server['path']}"; + $connection = "Proxy-Connection: " . ($this->_keep_alive ? 'keep-alive' : 'close') . "\r\n"; + if (!is_null($this->_proxy['user'])) { + $connection .= "Proxy-Authorization: Basic " . base64_encode($this->_proxy['user'] . ":" . $this->_proxy['pass']) . "\r\n"; + } + } + $auth = ''; + if (!is_null($this->_server['user'])) { + $auth = "Authorization: Basic " . base64_encode($this->_server['user'] . ":" . $this->_server['pass']) . "\r\n"; + } + $cookie = ''; + if ($_PHPRPC_COOKIE) { + $cookie = "Cookie: " . $_PHPRPC_COOKIE . "\r\n"; + } + $content_len = strlen($request_body); + $request = + "POST $url HTTP/{$this->_http_version}\r\n" . + "Host: {$this->_server['host']}:{$this->_server['port']}\r\n" . + "User-Agent: PHPRPC Client 3.0 for PHP\r\n" . + $auth . + $connection . + $cookie . + "Accept: */*\r\n" . + "Accept-Encoding: gzip,deflate\r\n" . + "Content-Type: application/x-www-form-urlencoded; charset={$this->_charset}\r\n" . + "Content-Length: {$content_len}\r\n" . + "\r\n" . + $request_body; + fputs($this->_socket, $request, strlen($request)); + while (!feof($this->_socket)) { + $line = fgets($this->_socket); + if (preg_match('/HTTP\/(\d\.\d)\s+(\d+)([^(\r|\n)]*)(\r\n|$)/i', $line, $match)) { + $this->_http_version = $match[1]; + $status = (int)$match[2]; + $status_message = trim($match[3]); + if ($status != 100 && $status != 200) { + $this->_disconnect(); + return new PHPRPC_Error($status, $status_message); + } + } + else { + $this->_disconnect(); + return new PHPRPC_Error(E_ERROR, "Illegal HTTP server."); + } + $header = array(); + while (!feof($this->_socket) && (($line = fgets($this->_socket)) != "\r\n")) { + $line = explode(':', $line, 2); + $header[strtolower($line[0])][] =trim($line[1]); + } + if ($status == 100) continue; + $response_header = $this->_parseHeader($header); + if (is_a($response_header, 'PHPRPC_Error')) { + $this->_disconnect(); + return $response_header; + } + break; + } + $response_body = ''; + if (isset($response_header['transfer_encoding']) && (strtolower($response_header['transfer_encoding']) == 'chunked')) { + $s = fgets($this->_socket); + if ($s == "") { + $this->_disconnect(); + return array(); + } + $chunk_size = (int)hexdec($s); + while ($chunk_size > 0) { + $response_body .= $this->_socket_read($chunk_size); + if (fgets($this->_socket) != "\r\n") { + $this->_disconnect(); + return new PHPRPC_Error(1, "Response is incorrect."); + } + $chunk_size = (int)hexdec(fgets($this->_socket)); + } + fgets($this->_socket); + } + elseif (isset($response_header['content_length']) && !is_null($response_header['content_length'])) { + $response_body = $this->_socket_read($response_header['content_length']); + } + else { + while (!feof($this->_socket)) { + $response_body .= fread($this->_socket, 4096); + } + $this->_keep_alive = false; + $this->_disconnect(); + } + if (isset($response_header['content_encoding']) && (strtolower($response_header['content_encoding']) == 'gzip')) { + $response_body = gzdecode($response_body); + } + if (!$this->_keep_alive) $this->_disconnect(); + if ($this->_keep_alive && strtolower($response_header['connection']) == 'close') { + $this->_keep_alive = false; + $this->_disconnect(); + } + return $this->_parseBody($response_body); + } + function _parseHeader($header) { + global $_PHPRPC_COOKIE, $_PHPRPC_COOKIES; + if (preg_match('/PHPRPC Server\/([^,]*)(,|$)/i', implode(',', $header['x-powered-by']), $match)) { + $this->_server['version'] = (float)$match[1]; + } + else { + return new PHPRPC_Error(E_ERROR, "Illegal PHPRPC server."); + } + if (preg_match('/text\/plain\; charset\=([^,;]*)([,;]|$)/i', $header['content-type'][0], $match)) { + $this->_charset = $match[1]; + } + if (isset($header['set-cookie'])) { + foreach ($header['set-cookie'] as $cookie) { + foreach (preg_split('/[;,]\s?/', $cookie) as $c) { + list($name, $value) = explode('=', $c, 2); + if (!in_array($name, array('domain', 'expires', 'path', 'secure'))) { + $_PHPRPC_COOKIES[$name] = $value; + } + } + } + $cookies = array(); + foreach ($_PHPRPC_COOKIES as $name => $value) { + $cookies[] = "$name=$value"; + } + $_PHPRPC_COOKIE = join('; ', $cookies); + } + if (isset($header['content-length'])) { + $content_length = (int)$header['content-length'][0]; + } + else { + $content_length = NULL; + } + $transfer_encoding = isset($header['transfer-encoding']) ? $header['transfer-encoding'][0] : ''; + $content_encoding = isset($header['content-encoding']) ? $header['content-encoding'][0] : ''; + $connection = isset($header['connection']) ? $header['connection'][0] : 'close'; + return array('transfer_encoding' => $transfer_encoding, + 'content_encoding' => $content_encoding, + 'content_length' => $content_length, + 'connection' => $connection); + } + function _parseBody($body) { + $body = explode(";\r\n", $body); + $result = array(); + $n = count($body); + for ($i = 0; $i < $n; $i++) { + $p = strpos($body[$i], '='); + if ($p !== false) { + $l = substr($body[$i], 0, $p); + $r = substr($body[$i], $p + 1); + $result[$l] = trim($r, '"'); + } + } + return $result; + } + function _key_exchange() { + if (!is_null($this->_key) || ($this->_encryptMode == 0)) return true; + $request = "phprpc_encrypt=true&phprpc_keylen={$this->_keylen}"; + $result = $this->_post($request); + if (is_a($result, 'PHPRPC_Error')) { + return $result; + } + if (array_key_exists('phprpc_keylen', $result)) { + $this->_keylen = (int)$result['phprpc_keylen']; + } + else { + $this->_keylen = 128; + } + if (array_key_exists('phprpc_encrypt', $result)) { + $encrypt = unserialize(base64_decode($result['phprpc_encrypt'])); + require_once('bigint.php'); + require_once('xxtea.php'); + $x = bigint_random($this->_keylen - 1, true); + $key = bigint_powmod(bigint_dec2num($encrypt['y']), $x, bigint_dec2num($encrypt['p'])); + if ($this->_keylen == 128) { + $key = bigint_num2str($key); + } + else { + $key = pack('H*', md5(bigint_num2dec($key))); + } + $this->_key = str_pad($key, 16, "\0", STR_PAD_LEFT); + $encrypt = bigint_num2dec(bigint_powmod(bigint_dec2num($encrypt['g']), $x, bigint_dec2num($encrypt['p']))); + $request = "phprpc_encrypt=$encrypt"; + $result = $this->_post($request); + if (is_a($result, 'PHPRPC_Error')) { + return $result; + } + } + else { + $this->_key = NULL; + $this->_encryptMode = 0; + } + return true; + } + function _encrypt($str, $level) { + if (!is_null($this->_key) && ($this->_encryptMode >= $level)) { + $str = xxtea_encrypt($str, $this->_key); + } + return $str; + } + function _decrypt($str, $level) { + if (!is_null($this->_key) && ($this->_encryptMode >= $level)) { + $str = xxtea_decrypt($str, $this->_key); + } + return $str; + } +} + +if (function_exists("overload") && version_compare(phpversion(), "5", "<")) { + eval(' + class PHPRPC_Client extends _PHPRPC_Client { + function __call($function, $arguments, &$return) { + $return = $this->invoke($function, $arguments); + return true; + } + } + overload("phprpc_client"); + '); +} +else { + class PHPRPC_Client extends _PHPRPC_Client { + function __call($function, $arguments) { + return $this->invoke($function, $arguments); + } + } +} +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/phprpc_date.php b/ThinkPHP/Extend/Vendor/phpRPC/phprpc_date.php new file mode 100644 index 0000000..cb9a280 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/phprpc_date.php @@ -0,0 +1,522 @@ + | +| | +| This file may be distributed and/or modified under the | +| terms of the GNU General Public License (GPL) version | +| 2.0 as published by the Free Software Foundation and | +| appearing in the included file LICENSE. | +| | +\**********************************************************/ + +/* PHPRPC_Date Class for PHP. + * + * Copyright: Ma Bingyao + * Version: 1.2 + * LastModified: Apr 12, 2010 + * This library is free. You can redistribute it and/or modify it under GPL. + */ + +class PHPRPC_Date { + +// public fields + + var $year = 1; + var $month = 1; + var $day = 1; + var $hour = 0; + var $minute = 0; + var $second = 0; + var $millisecond = 0; + +// constructor + + function PHPRPC_Date() { + $num = func_num_args(); + $time = false; + if ($num == 0) { + $time = getdate(); + } + if ($num == 1) { + $arg = func_get_arg(0); + if (is_int($arg)) { + $time = getdate($arg); + } + elseif (is_string($arg)) { + $time = getdate(strtotime($arg)); + } + } + if (is_array($time)) { + $this->year = $time['year']; + $this->month = $time['mon']; + $this->day = $time['mday']; + $this->hour = $time['hours']; + $this->minute = $time['minutes']; + $this->second = $time['seconds']; + } + } + +// public instance methods + + function addMilliseconds($milliseconds) { + if (!is_int($milliseconds)) return false; + if ($milliseconds == 0) return true; + $millisecond = $this->millisecond + $milliseconds; + $milliseconds = $millisecond % 1000; + if ($milliseconds < 0) { + $milliseconds += 1000; + } + $seconds = (int)(($millisecond - $milliseconds) / 1000); + $millisecond = (int)$milliseconds; + if ($this->addSeconds($seconds)) { + $this->millisecond = (int)$milliseconds; + return true; + } + else { + return false; + } + } + + function addSeconds($seconds) { + if (!is_int($seconds)) return false; + if ($seconds == 0) return true; + $second = $this->second + $seconds; + $seconds = $second % 60; + if ($seconds < 0) { + $seconds += 60; + } + $minutes = (int)(($second - $seconds) / 60); + if ($this->addMinutes($minutes)) { + $this->second = (int)$seconds; + return true; + } + else { + return false; + } + } + + function addMinutes($minutes) { + if (!is_int($minutes)) return false; + if ($minutes == 0) return true; + $minute = $this->minute + $minutes; + $minutes = $minute % 60; + if ($minutes < 0) { + $minutes += 60; + } + $hours = (int)(($minute - $minutes) / 60); + if ($this->addHours($hours)) { + $this->minute = (int)$minutes; + return true; + } + else { + return false; + } + } + + function addHours($hours) { + if (!is_int($hours)) return false; + if ($hours == 0) return true; + $hour = $this->hour + $hours; + $hours = $hour % 24; + if ($hours < 0) { + $hours += 24; + } + $days = (int)(($hour - $hours) / 24); + if ($this->addDays($days)) { + $this->hour = (int)$hours; + return true; + } + else { + return false; + } + } + + function addDays($days) { + if (!is_int($days)) return false; + $year = $this->year; + if ($days == 0) return true; + if ($days >= 146097 || $days <= -146097) { + $remainder = $days % 146097; + if ($remainder < 0) { + $remainder += 146097; + } + $years = 400 * (int)(($days - $remainder) / 146097); + $year += $years; + if ($year < 1 || $year > 9999) return false; + $days = $remainder; + } + if ($days >= 36524 || $days <= -36524) { + $remainder = $days % 36524; + if ($remainder < 0) { + $remainder += 36524; + } + $years = 100 * (int)(($days - $remainder) / 36524); + $year += $years; + if ($year < 1 || $year > 9999) return false; + $days = $remainder; + } + if ($days >= 1461 || $days <= -1461) { + $remainder = $days % 1461; + if ($remainder < 0) { + $remainder += 1461; + } + $years = 4 * (int)(($days - $remainder) / 1461); + $year += $years; + if ($year < 1 || $year > 9999) return false; + $days = $remainder; + } + $month = $this->month; + while ($days >= 365) { + if ($year >= 9999) return false; + if ($month <= 2) { + if ((($year % 4) == 0) ? (($year % 100) == 0) ? (($year % 400) == 0) : true : false) { + $days -= 366; + } + else { + $days -= 365; + } + $year++; + } + else { + $year++; + if ((($year % 4) == 0) ? (($year % 100) == 0) ? (($year % 400) == 0) : true : false) { + $days -= 366; + } + else { + $days -= 365; + } + } + } + while ($days < 0) { + if ($year <= 1) return false; + if ($month <= 2) { + $year--; + if ((($year % 4) == 0) ? (($year % 100) == 0) ? (($year % 400) == 0) : true : false) { + $days += 366; + } + else { + $days += 365; + } + } + else { + if ((($year % 4) == 0) ? (($year % 100) == 0) ? (($year % 400) == 0) : true : false) { + $days += 366; + } + else { + $days += 365; + } + $year--; + } + } + $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year); + $day = $this->day; + while ($day + $days > $daysInMonth) { + $days -= $daysInMonth - $day + 1; + $month++; + if ($month > 12) { + if ($year >= 9999) return false; + $year++; + $month = 1; + } + $day = 1; + $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year); + } + $day += $days; + $this->year = $year; + $this->month = $month; + $this->day = $day; + return true; + } + + function addMonths($months) { + if (!is_int($months)) return false; + if ($months == 0) return true; + $month = $this->month + $months; + $months = ($month - 1) % 12 + 1; + if ($months < 1) { + $months += 12; + } + $years = (int)(($month - $months) / 12); + if ($this->addYears($years)) { + $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $months, $this->year); + if ($this->day > $daysInMonth) { + $months++; + $this->day -= $daysInMonth; + } + $this->month = (int)$months; + return true; + } + else { + return false; + } + } + + function addYears($years) { + if (!is_int($years)) return false; + if ($years == 0) return true; + $year = $this->year + $years; + if ($year < 1 || $year > 9999) return false; + $this->year = $year; + return true; + } + + function after($when) { + if (!is_a($when, 'PHPRPC_Date')) { + $when = PHPRPC_Date::parse($when); + } + if ($this->year < $when->year) return false; + if ($this->year > $when->year) return true; + if ($this->month < $when->month) return false; + if ($this->month > $when->month) return true; + if ($this->day < $when->day) return false; + if ($this->day > $when->day) return true; + if ($this->hour < $when->hour) return false; + if ($this->hour > $when->hour) return true; + if ($this->minute < $when->minute) return false; + if ($this->minute > $when->minute) return true; + if ($this->second < $when->second) return false; + if ($this->second > $when->second) return true; + if ($this->millisecond < $when->millisecond) return false; + if ($this->millisecond > $when->millisecond) return true; + return false; + } + + function before($when) { + if (!is_a($when, 'PHPRPC_Date')) { + $when = new PHPRPC_Date($when); + } + if ($this->year < $when->year) return true; + if ($this->year > $when->year) return false; + if ($this->month < $when->month) return true; + if ($this->month > $when->month) return false; + if ($this->day < $when->day) return true; + if ($this->day > $when->day) return false; + if ($this->hour < $when->hour) return true; + if ($this->hour > $when->hour) return false; + if ($this->minute < $when->minute) return true; + if ($this->minute > $when->minute) return false; + if ($this->second < $when->second) return true; + if ($this->second > $when->second) return false; + if ($this->millisecond < $when->millisecond) return true; + if ($this->millisecond > $when->millisecond) return false; + return false; + } + + function equals($when) { + if (!is_a($when, 'PHPRPC_Date')) { + $when = new PHPRPC_Date($when); + } + return (($this->year == $when->year) && + ($this->month == $when->month) && + ($this->day == $when->day) && + ($this->hour == $when->hour) && + ($this->minute == $when->minute) && + ($this->second == $when->second) && + ($this->millisecond == $when->millisecond)); + } + + function set() { + $num = func_num_args(); + $args = func_get_args(); + if ($num >= 3) { + if (!PHPRPC_Date::isValidDate($args[0], $args[1], $args[2])) { + return false; + } + $this->year = (int)$args[0]; + $this->month = (int)$args[1]; + $this->day = (int)$args[2]; + if ($num == 3) { + return true; + } + } + if ($num >= 6) { + if (!PHPRPC_Date::isValidTime($args[3], $args[4], $args[5])) { + return false; + } + $this->hour = (int)$args[3]; + $this->minute = (int)$args[4]; + $this->second = (int)$args[5]; + if ($num == 6) { + return true; + } + } + if (($num == 7) && ($args[6] >= 0 && $args[6] <= 999)) { + $this->millisecond = (int)$args[6]; + return true; + } + return false; + } + + function time() { + return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year); + } + + function toString() { + return sprintf('%04d-%02d-%02d %02d:%02d:%02d.%03d', + $this->year, $this->month, $this->day, + $this->hour, $this->minute, $this->second, + $this->millisecond); + } + +// magic method for PHP 5 + + function __toString() { + return $this->toString(); + } + +// public instance & static methods + + function dayOfWeek() { + $num = func_num_args(); + if ($num == 3) { + $args = func_get_args(); + $y = $args[0]; + $m = $args[1]; + $d = $args[2]; + } + else { + $y = $this->year; + $m = $this->month; + $d = $this->day; + } + $d += $m < 3 ? $y-- : $y - 2; + return ((int)(23 * $m / 9) + $d + 4 + (int)($y / 4) - (int)($y / 100) + (int)($y / 400)) % 7; + } + + function dayOfYear() { + static $daysToMonth365 = array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365); + static $daysToMonth366 = array(0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366); + $num = func_num_args(); + if ($num == 3) { + $args = func_get_args(); + $y = $args[0]; + $m = $args[1]; + $d = $args[2]; + } + else { + $y = $this->year; + $m = $this->month; + $d = $this->day; + } + $days = PHPRPC_Date::isLeapYear($y) ? $daysToMonth365 : $daysToMonth366; + return $days[$m - 1] + $d; + } + +// public static methods + + function now() { + $date = new PHPRPC_Date(); + return $date; + } + + function today() { + $date = PHPRPC_Date::now(); + $date->hour = 0; + $date->minute = 0; + $date->second = 0; + return $date; + } + + function parse($dt) { + if (is_a($dt, 'PHPRPC_Date')) { + return $dt; + } + if (is_int($dt)) { + return new PHPRPC_Date($dt); + } + $shortFormat = '(\d|\d{2}|\d{3}|\d{4})-([1-9]|0[1-9]|1[012])-([1-9]|0[1-9]|[12]\d|3[01])'; + if (preg_match("/^$shortFormat$/", $dt, $match)) { + $year = intval($match[1]); + $month = intval($match[2]); + $day = intval($match[3]); + if (PHPRPC_Date::isValidDate($year, $month, $day)) { + $date = new PHPRPC_Date(false); + $date->year = $year; + $date->month = $month; + $date->day = $day; + return $date; + } + else { + return false; + } + } + $longFormat = $shortFormat . ' (\d|0\d|1\d|2[0-3]):(\d|[0-5]\d):(\d|[0-5]\d)'; + if (preg_match("/^$longFormat$/", $dt, $match)) { + $year = intval($match[1]); + $month = intval($match[2]); + $day = intval($match[3]); + if (PHPRPC_Date::isValidDate($year, $month, $day)) { + $date = new PHPRPC_Date(false); + $date->year = $year; + $date->month = $month; + $date->day = $day; + $date->hour = intval($match[4]); + $date->minute = intval($match[5]); + $date->second = intval($match[6]); + return $date; + } + else { + return false; + } + } + $fullFormat = $longFormat . '\.(\d|\d{2}|\d{3})'; + if (preg_match("/^$fullFormat$/", $dt, $match)) { + $year = intval($match[1]); + $month = intval($match[2]); + $day = intval($match[3]); + if (PHPRPC_Date::isValidDate($year, $month, $day)) { + $date = new PHPRPC_Date(false); + $date->year = $year; + $date->month = $month; + $date->day = $day; + $date->hour = intval($match[4]); + $date->minute = intval($match[5]); + $date->second = intval($match[6]); + $date->millisecond = intval($match[7]); + return $date; + } + else { + return false; + } + } + return false; + } + + function isLeapYear($year) { + return (($year % 4) == 0) ? (($year % 100) == 0) ? (($year % 400) == 0) : true : false; + } + + function daysInMonth($year, $month) { + if (($month < 1) || ($month > 12)) { + return false; + } + return cal_days_in_month(CAL_GREGORIAN, $month, $year); + } + + function isValidDate($year, $month, $day) { + if (($year >= 1) && ($year <= 9999)) { + return checkdate($month, $day, $year); + } + return false; + } + + function isValidTime($hour, $minute, $second) { + return !(($hour < 0) || ($hour > 23) || + ($minute < 0) || ($minute > 59) || + ($second < 0) || ($second > 59)); + } +} +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/phprpc_server.php b/ThinkPHP/Extend/Vendor/phpRPC/phprpc_server.php new file mode 100644 index 0000000..22eebf5 --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/phprpc_server.php @@ -0,0 +1,496 @@ + | +| | +| This file may be distributed and/or modified under the | +| terms of the GNU General Public License (GPL) version | +| 2.0 as published by the Free Software Foundation and | +| appearing in the included file LICENSE. | +| | +\**********************************************************/ + +/* PHPRPC Server for PHP. + * + * Copyright: Ma Bingyao + * Version: 3.0 + * LastModified: Apr 12, 2010 + * This library is free. You can redistribute it and/or modify it under GPL. + * +/* + * Interfaces + * + * function add($a, $b) { + * return $a + $b; + * } + * function sub($a, $b) { + * return $a - $b; + * } + * function inc(&$n) { + * return $n++; + * } + * include('phprpc_server.php'); + * $server = new PHPRPC_Server(); + * $server->add(array('add', 'sub')); + * $server->add('inc'); + * $server->setCharset('UTF-8'); + * $server->setDebugMode(true); + * $server->start(); + * + */ + +class PHPRPC_Server { + var $callback; + var $charset; + var $encode; + var $ref; + var $encrypt; + var $enableGZIP; + var $debug; + var $keylen; + var $key; + var $errno; + var $errstr; + var $functions; + var $cid; + var $buffer; + // Private Methods + function addJsSlashes($str, $flag) { + if ($flag) { + $str = addcslashes($str, "\0..\006\010..\012\014..\037\042\047\134\177..\377"); + } + else { + $str = addcslashes($str, "\0..\006\010..\012\014..\037\042\047\134\177"); + } + return str_replace(array(chr(7), chr(11)), array('\007', '\013'), $str); + } + function encodeString($str, $flag = true) { + if ($this->encode) { + return base64_encode($str); + } + else { + return $this->addJsSlashes($str, $flag); + } + } + function encryptString($str, $level) { + if ($this->encrypt >= $level) { + $str = xxtea_encrypt($str, $this->key); + } + return $str; + } + function decryptString($str, $level) { + if ($this->encrypt >= $level) { + $str = xxtea_decrypt($str, $this->key); + } + return $str; + } + function sendHeader() { + header("HTTP/1.1 200 OK"); + header("Content-Type: text/plain; charset={$this->charset}"); + header("X-Powered-By: PHPRPC Server/3.0"); + header('P3P: CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"'); + header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); + } + function getRequestURL() { + if (!isset($_SERVER['HTTPS']) || + $_SERVER['HTTPS'] == 'off' || + $_SERVER['HTTPS'] == '') { + $scheme = 'http'; + } + else { + $scheme = 'https'; + } + $host = $_SERVER['SERVER_NAME']; + $port = $_SERVER['SERVER_PORT']; + $path = $_SERVER['SCRIPT_NAME']; + return $scheme . '://' . $host . (($port == 80) ? '' : ':' . $port) . $path; + } + function sendURL() { + if (SID != "") { + $url = $this->getRequestURL(); + if (count($_GET) > 0) { + $url .= '?' . strip_tags(SID); + foreach ($_GET as $key => $value) { + if (strpos(strtolower($key), 'phprpc_') !== 0) { + $url .= '&' . $key . '=' . urlencode($value); + } + } + } + $this->buffer .= "phprpc_url=\"" . $this->encodeString($url) . "\";\r\n"; + } + } + function gzip($buffer) { + $len = strlen($buffer); + if ($this->enableGZIP && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip,deflate')) { + $gzbuffer = gzencode($buffer); + $gzlen = strlen($gzbuffer); + if ($len > $gzlen) { + header("Content-Length: $gzlen"); + header("Content-Encoding: gzip"); + return $gzbuffer; + } + } + header("Content-Length: $len"); + return $buffer; + } + function sendCallback() { + $this->buffer .= $this->callback; + echo $this->gzip($this->buffer); + ob_end_flush(); + restore_error_handler(); + if (function_exists('restore_exception_handler')) { + restore_exception_handler(); + } + exit(); + } + function sendFunctions() { + $this->buffer .= "phprpc_functions=\"" . $this->encodeString(serialize_fix(array_keys($this->functions))) . "\";\r\n"; + $this->sendCallback(); + } + function sendOutput($output) { + if ($this->encrypt >= 3) { + $this->buffer .= "phprpc_output=\"" . $this->encodeString(xxtea_encrypt($output, $this->key)) . "\";\r\n"; + } + else { + $this->buffer .= "phprpc_output=\"" . $this->encodeString($output, false) . "\";\r\n"; + } + } + function sendError($output = NULL) { + if (is_null($output)) { + $output = ob_get_clean(); + } + $this->buffer .= "phprpc_errno=\"{$this->errno}\";\r\n"; + $this->buffer .= "phprpc_errstr=\"" . $this->encodeString($this->errstr, false) . "\";\r\n"; + $this->sendOutput($output); + $this->sendCallback(); + } + function fatalErrorHandler($buffer) { + if (preg_match('/(.*?) error<\/b>:(.*?)
    debug) { + $errstr = preg_replace('/<.*?>/', '', $match[2]); + } + else { + $errstr = preg_replace('/ in .*<\/b>$/', '', $match[2]); + } + + $buffer = "phprpc_errno=\"{$errno}\";\r\n" . + "phprpc_errstr=\"" . $this->encodeString(trim($errstr), false) . "\";\r\n" . + "phprpc_output=\"\";\r\n" . + $this->callback; + $buffer = $this->gzip($buffer); + } + return $buffer; + } + function errorHandler($errno, $errstr, $errfile, $errline) { + if ($this->debug) { + $errstr .= " in $errfile on line $errline"; + } + if (($errno == E_ERROR) or ($errno == E_CORE_ERROR) or + ($errno == E_COMPILE_ERROR) or ($errno == E_USER_ERROR)) { + $this->errno = $errno; + $this->errstr = $errstr; + $this->sendError(); + } + else { + if (($errno == E_NOTICE) or ($errno == E_USER_NOTICE)) { + if ($this->errno == 0) { + $this->errno = $errno; + $this->errstr = $errstr; + } + } + else { + if (($this->errno == 0) or + ($this->errno == E_NOTICE) or + ($this->errno == E_USER_NOTICE)) { + $this->errno = $errno; + $this->errstr = $errstr; + } + } + } + return true; + } + function exceptionHandler($exception) { + $this->errno = $exception->getCode(); + $this->errstr = $exception->getMessage(); + if ($this->debug) { + $this->errstr .= "\nfile: " . $exception->getFile() . + "\nline: " . $exception->getLine() . + "\ntrace: " . $exception->getTraceAsString(); + } + $this->sendError(); + } + function initErrorHandler() { + $this->errno = 0; + $this->errstr = ""; + set_error_handler(array(&$this, 'errorHandler')); + if (function_exists('set_exception_handler')) { + set_exception_handler(array(&$this, 'exceptionHandler')); + } + } + function call($function, &$args) { + if ($this->ref) { + $arguments = array(); + for ($i = 0; $i < count($args); $i++) { + $arguments[$i] = &$args[$i]; + } + } + else { + $arguments = $args; + } + return call_user_func_array($function, $arguments); + } + function getRequest($name) { + $result = $_REQUEST[$name]; + if (get_magic_quotes_gpc()) { + $result = stripslashes($result); + } + return $result; + } + function getBooleanRequest($name) { + $var = true; + if (isset($_REQUEST[$name])) { + $var = strtolower($this->getRequest($name)); + if ($var == "false") { + $var = false; + } + } + return $var; + } + function initEncode() { + $this->encode = $this->getBooleanRequest('phprpc_encode'); + } + function initRef() { + $this->ref = $this->getBooleanRequest('phprpc_ref'); + } + function initCallback() { + if (isset($_REQUEST['phprpc_callback'])) { + $this->callback = base64_decode($this->getRequest('phprpc_callback')); + } + else { + $this->callback = ""; + } + } + function initKeylen() { + if (isset($_REQUEST['phprpc_keylen'])) { + $this->keylen = (int)$this->getRequest('phprpc_keylen'); + } + else if (isset($_SESSION[$this->cid])) { + $session = unserialize(base64_decode($_SESSION[$this->cid])); + if (isset($session['keylen'])) { + $this->keylen = $session['keylen']; + } + else { + $this->keylen = 128; + } + } + else { + $this->keylen = 128; + } + } + function initClientID() { + $this->cid = 0; + if (isset($_REQUEST['phprpc_id'])) { + $this->cid = $this->getRequest('phprpc_id'); + } + $this->cid = "phprpc_" . $this->cid; + } + function initEncrypt() { + $this->encrypt = false; + if (isset($_REQUEST['phprpc_encrypt'])) { + $this->encrypt = $this->getRequest('phprpc_encrypt'); + if ($this->encrypt === "true") $this->encrypt = true; + if ($this->encrypt === "false") $this->encrypt = false; + } + } + function initKey() { + if ($this->encrypt == 0) { + return; + } + else if (isset($_SESSION[$this->cid])) { + $session = unserialize(base64_decode($_SESSION[$this->cid])); + if (isset($session['key'])) { + $this->key = $session['key']; + require_once('xxtea.php'); + return; + } + } + $this->errno = E_ERROR; + $this->errstr = "Can't find the key for decryption."; + $this->encrypt = 0; + $this->sendError(); + } + function getArguments() { + if (isset($_REQUEST['phprpc_args'])) { + $arguments = unserialize($this->decryptString(base64_decode($this->getRequest('phprpc_args')), 1)); + ksort($arguments); + } + else { + $arguments = array(); + } + return $arguments; + } + function callFunction() { + $this->initKey(); + $function = strtolower($this->getRequest('phprpc_func')); + if (array_key_exists($function, $this->functions)) { + $function = $this->functions[$function]; + $arguments = $this->getArguments(); + $result = $this->encodeString($this->encryptString(serialize_fix($this->call($function, $arguments)), 2)); + $output = ob_get_clean(); + $this->buffer .= "phprpc_result=\"$result\";\r\n"; + if ($this->ref) { + $arguments = $this->encodeString($this->encryptString(serialize_fix($arguments), 1)); + $this->buffer .= "phprpc_args=\"$arguments\";\r\n"; + } + } + else { + $this->errno = E_ERROR; + $this->errstr = "Can't find this function $function()."; + $output = ob_get_clean(); + } + $this->sendError($output); + } + function keyExchange() { + require_once('bigint.php'); + $this->initKeylen(); + if (isset($_SESSION[$this->cid])) { + $session = unserialize(base64_decode($_SESSION[$this->cid])); + } + else { + $session = array(); + } + if ($this->encrypt === true) { + require_once('dhparams.php'); + $DHParams = new DHParams($this->keylen); + $this->keylen = $DHParams->getL(); + $encrypt = $DHParams->getDHParams(); + $x = bigint_random($this->keylen - 1, true); + $session['x'] = bigint_num2dec($x); + $session['p'] = $encrypt['p']; + $session['keylen'] = $this->keylen; + $encrypt['y'] = bigint_num2dec(bigint_powmod(bigint_dec2num($encrypt['g']), $x, bigint_dec2num($encrypt['p']))); + $this->buffer .= "phprpc_encrypt=\"" . $this->encodeString(serialize_fix($encrypt)) . "\";\r\n"; + if ($this->keylen != 128) { + $this->buffer .= "phprpc_keylen=\"{$this->keylen}\";\r\n"; + } + $this->sendURL(); + } + else { + $y = bigint_dec2num($this->encrypt); + $x = bigint_dec2num($session['x']); + $p = bigint_dec2num($session['p']); + $key = bigint_powmod($y, $x, $p); + if ($this->keylen == 128) { + $key = bigint_num2str($key); + } + else { + $key = pack('H*', md5(bigint_num2dec($key))); + } + $session['key'] = str_pad($key, 16, "\0", STR_PAD_LEFT); + } + $_SESSION[$this->cid] = base64_encode(serialize($session)); + $this->sendCallback(); + } + function initSession() { + @ob_start(); + ob_implicit_flush(0); + session_start(); + } + function initOutputBuffer() { + @ob_start(array(&$this, "fatalErrorHandler")); + ob_implicit_flush(0); + $this->buffer = ""; + } + // Public Methods + function PHPRPC_Server() { + require_once('compat.php'); + $this->functions = array(); + $this->charset = 'UTF-8'; + $this->debug = false; + $this->enableGZIP = false; + } + function add($functions, $obj = NULL, $aliases = NULL) { + if (is_null($functions) || (gettype($functions) != gettype($aliases) && !is_null($aliases))) { + return false; + } + if (is_object($functions)) { + $obj = $functions; + $functions = get_class_methods(get_class($obj)); + $aliases = $functions; + } + if (is_null($aliases)) { + $aliases = $functions; + } + if (is_string($functions)) { + if (is_null($obj)) { + $this->functions[strtolower($aliases)] = $functions; + } + else if (is_object($obj)) { + $this->functions[strtolower($aliases)] = array(&$obj, $functions); + } + else if (is_string($obj)) { + $this->functions[strtolower($aliases)] = array($obj, $functions); + } + } + else { + if (count($functions) != count($aliases)) { + return false; + } + foreach ($functions as $key => $function) { + $this->add($function, $obj, $aliases[$key]); + } + } + return true; + } + function setCharset($charset) { + $this->charset = $charset; + } + function setDebugMode($debug) { + $this->debug = $debug; + } + function setEnableGZIP($enableGZIP) { + $this->enableGZIP = $enableGZIP; + } + function start() { + while(ob_get_length() !== false) @ob_end_clean(); + $this->initOutputBuffer(); + $this->sendHeader(); + $this->initErrorHandler(); + $this->initEncode(); + $this->initCallback(); + $this->initRef(); + $this->initClientID(); + $this->initEncrypt(); + if (isset($_REQUEST['phprpc_func'])) { + $this->callFunction(); + } + else if ($this->encrypt != false) { + $this->keyExchange(); + } + else { + $this->sendFunctions(); + } + } +} + +PHPRPC_Server::initSession(); +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/phpRPC/xxtea.php b/ThinkPHP/Extend/Vendor/phpRPC/xxtea.php new file mode 100644 index 0000000..b22f68f --- /dev/null +++ b/ThinkPHP/Extend/Vendor/phpRPC/xxtea.php @@ -0,0 +1,134 @@ + | +| | +| This file may be distributed and/or modified under the | +| terms of the GNU General Public License (GPL) version | +| 2.0 as published by the Free Software Foundation and | +| appearing in the included file LICENSE. | +| | +\**********************************************************/ + +/* XXTEA encryption arithmetic library. + * + * Copyright: Ma Bingyao + * Version: 1.6 + * LastModified: Apr 12, 2010 + * This library is free. You can redistribute it and/or modify it under GPL. + */ +if (!extension_loaded('xxtea')) { + function long2str($v, $w) { + $len = count($v); + $n = ($len - 1) << 2; + if ($w) { + $m = $v[$len - 1]; + if (($m < $n - 3) || ($m > $n)) return false; + $n = $m; + } + $s = array(); + for ($i = 0; $i < $len; $i++) { + $s[$i] = pack("V", $v[$i]); + } + if ($w) { + return substr(join('', $s), 0, $n); + } + else { + return join('', $s); + } + } + + function str2long($s, $w) { + $v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3)); + $v = array_values($v); + if ($w) { + $v[count($v)] = strlen($s); + } + return $v; + } + + function int32($n) { + while ($n >= 2147483648) $n -= 4294967296; + while ($n <= -2147483649) $n += 4294967296; + return (int)$n; + } + + function xxtea_encrypt($str, $key) { + if ($str == "") { + return ""; + } + $v = str2long($str, true); + $k = str2long($key, false); + if (count($k) < 4) { + for ($i = count($k); $i < 4; $i++) { + $k[$i] = 0; + } + } + $n = count($v) - 1; + + $z = $v[$n]; + $y = $v[0]; + $delta = 0x9E3779B9; + $q = floor(6 + 52 / ($n + 1)); + $sum = 0; + while (0 < $q--) { + $sum = int32($sum + $delta); + $e = $sum >> 2 & 3; + for ($p = 0; $p < $n; $p++) { + $y = $v[$p + 1]; + $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $z = $v[$p] = int32($v[$p] + $mx); + } + $y = $v[0]; + $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $z = $v[$n] = int32($v[$n] + $mx); + } + return long2str($v, false); + } + + function xxtea_decrypt($str, $key) { + if ($str == "") { + return ""; + } + $v = str2long($str, false); + $k = str2long($key, false); + if (count($k) < 4) { + for ($i = count($k); $i < 4; $i++) { + $k[$i] = 0; + } + } + $n = count($v) - 1; + + $z = $v[$n]; + $y = $v[0]; + $delta = 0x9E3779B9; + $q = floor(6 + 52 / ($n + 1)); + $sum = int32($q * $delta); + while ($sum != 0) { + $e = $sum >> 2 & 3; + for ($p = $n; $p > 0; $p--) { + $z = $v[$p - 1]; + $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $y = $v[$p] = int32($v[$p] - $mx); + } + $z = $v[$n]; + $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $y = $v[0] = int32($v[0] - $mx); + $sum = int32($sum - $delta); + } + return long2str($v, true); + } +} +?> \ No newline at end of file diff --git a/ThinkPHP/Extend/Vendor/readme.txt b/ThinkPHP/Extend/Vendor/readme.txt new file mode 100644 index 0000000..7b25cda --- /dev/null +++ b/ThinkPHP/Extend/Vendor/readme.txt @@ -0,0 +1,7 @@ +ʹ˵ + +ϵͳչĵطѭThinkPHPⶨļ淶 +ʹõ⣬ҪThinkPHPϵͳĿ¼洴VendorĿ¼Ȼֱӷ⡣ +ķ +// VendorĿ¼һZend\Util\Array.php ļ +vendor('Zend.Util.Array'); \ No newline at end of file diff --git a/ThinkPHP/LICENSE.txt b/ThinkPHP/LICENSE.txt new file mode 100644 index 0000000..0275e84 --- /dev/null +++ b/ThinkPHP/LICENSE.txt @@ -0,0 +1,32 @@ + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 +版权所有Copyright © 2006-2012 by ThinkPHP (http://thinkphp.cn) +All rights reserved。 +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +Apache Licence是著名的非盈利开源组织Apache采用的协议。 +该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, +允许代码修改,再作为开源或商业软件发布。需要满足 +的条件: +1. 需要给代码的用户一份Apache Licence ; +2. 如果你修改了代码,需要在被修改的文件中说明; +3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 +带有原来代码中的协议,商标,专利声明和其他原来作者规 +定需要包含的说明; +4. 如果再发布的产品中包含一个Notice文件,则在Notice文 +件中需要带有本协议内容。你可以在Notice中增加自己的 +许可,但不可以表现为对Apache Licence构成更改。 +具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/ThinkPHP/Lang/en-us.php b/ThinkPHP/Lang/en-us.php new file mode 100644 index 0000000..cea7765 --- /dev/null +++ b/ThinkPHP/Lang/en-us.php @@ -0,0 +1,54 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP English language package + * @category Think + * @package Lang + * @author liu21st + * @version $Id: zh-cn.php 3034 2012-10-17 21:14:00Z yangweijiester@gmail.com $ + */ +return array( + // core + '_MODULE_NOT_EXIST_' => 'Module can not been loaded', + '_ERROR_ACTION_' => 'Error action', + '_LANGUAGE_NOT_LOAD_' => 'Can\'t load language package', + '_TEMPLATE_NOT_EXIST_' => 'Template does\'t exist', + '_MODULE_' => 'Module', + '_ACTION_' => 'Action', + '_ACTION_NOT_EXIST_' => 'Action does\'t exist Or not defined', + '_MODEL_NOT_EXIST_' => 'Model does\'t exist Or not defined', + '_VALID_ACCESS_' => 'No access', + '_XML_TAG_ERROR_' => 'XML tag syntax errors', + '_DATA_TYPE_INVALID_' => 'Invlid data type!', + '_OPERATION_WRONG_' => 'Operation error occurs', + '_NOT_LOAD_DB_' => 'Unable to load the database', + '_NO_DB_DRIVER_' => 'Unable to load database driver', + '_NOT_SUPPORT_DB_' => 'The system is temporarily not support database', + '_NO_DB_CONFIG_' => 'Not define the database configuration', + '_NOT_SUPPERT_' => 'The system does not support', + '_CACHE_TYPE_INVALID_' => 'Unable to load the cache type', + '_FILE_NOT_WRITEABLE_' => 'Directory (file) is not writable', + '_METHOD_NOT_EXIST_' => 'The method you requested does not exist!', + '_CLASS_NOT_EXIST_' => 'Instantiating a class does not exist!', + '_CLASS_CONFLICT_' => 'Class name conflicts', + '_TEMPLATE_ERROR_' => 'Template Engine errors', + '_CACHE_WRITE_ERROR_' => 'Cache file write failed!', + '_TAGLIB_NOT_EXIST_' => 'Tag library is not defined', + '_OPERATION_FAIL_' => 'Operation failed!', + '_OPERATION_SUCCESS_' => 'Operation successed!', + '_SELECT_NOT_EXIST_' => 'Record does not exist!', + '_EXPRESS_ERROR_' => 'Expression errors', + '_TOKEN_ERROR_' => 'Form\'s token errors', + '_RECORD_HAS_UPDATE_' => 'Record has been updated', + '_NOT_ALLOW_PHP_' => 'PHP codes are not allowed in the template', + '_PARAM_ERROR_' => 'Parameter error or undefined', +); \ No newline at end of file diff --git a/ThinkPHP/Lang/zh-cn.php b/ThinkPHP/Lang/zh-cn.php new file mode 100644 index 0000000..dd540c6 --- /dev/null +++ b/ThinkPHP/Lang/zh-cn.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 简体中文语言包 + * @category Think + * @package Lang + * @author liu21st + */ +return array( + // 核心 + '_MODULE_NOT_EXIST_' => '无法加载模块', + '_ERROR_ACTION_' => '非法操作', + '_LANGUAGE_NOT_LOAD_' => '无法加载语言包', + '_TEMPLATE_NOT_EXIST_' => '模板不存在', + '_MODULE_' => '模块', + '_ACTION_' => '操作', + '_ACTION_NOT_EXIST_' => '控制器不存在或者没有定义', + '_MODEL_NOT_EXIST_' => '模型不存在或者没有定义', + '_VALID_ACCESS_' => '没有权限', + '_XML_TAG_ERROR_' => 'XML标签语法错误', + '_DATA_TYPE_INVALID_' => '非法数据对象!', + '_OPERATION_WRONG_' => '操作出现错误', + '_NOT_LOAD_DB_' => '无法加载数据库', + '_NO_DB_DRIVER_' => '无法加载数据库驱动', + '_NOT_SUPPORT_DB_' => '系统暂时不支持数据库', + '_NO_DB_CONFIG_' => '没有定义数据库配置', + '_NOT_SUPPERT_' => '系统不支持', + '_CACHE_TYPE_INVALID_' => '无法加载缓存类型', + '_FILE_NOT_WRITEABLE_' => '目录(文件)不可写', + '_METHOD_NOT_EXIST_' => '您所请求的方法不存在!', + '_CLASS_NOT_EXIST_' => '实例化一个不存在的类!', + '_CLASS_CONFLICT_' => '类名冲突', + '_TEMPLATE_ERROR_' => '模板引擎错误', + '_CACHE_WRITE_ERROR_' => '缓存文件写入失败!', + '_TAGLIB_NOT_EXIST_' => '标签库未定义', + '_OPERATION_FAIL_' => '操作失败!', + '_OPERATION_SUCCESS_' => '操作成功!', + '_SELECT_NOT_EXIST_' => '记录不存在!', + '_EXPRESS_ERROR_' => '表达式错误', + '_TOKEN_ERROR_' => '表单令牌错误', + '_RECORD_HAS_UPDATE_' => '记录已经更新', + '_NOT_ALLOW_PHP_' => '模板禁用PHP代码', + '_PARAM_ERROR_' => '参数错误或者未定义', +); \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/CheckRouteBehavior.class.php b/ThinkPHP/Lib/Behavior/CheckRouteBehavior.class.php new file mode 100644 index 0000000..be60d55 --- /dev/null +++ b/ThinkPHP/Lib/Behavior/CheckRouteBehavior.class.php @@ -0,0 +1,212 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:路由检测 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class CheckRouteBehavior extends Behavior { + // 行为参数定义(默认值) 可在项目配置中覆盖 + protected $options = array( + 'URL_ROUTER_ON' => false, // 是否开启URL路由 + 'URL_ROUTE_RULES' => array(), // 默认路由规则,注:分组配置无法替代 + ); + + // 行为扩展的执行入口必须是run + public function run(&$return){ + // 优先检测是否存在PATH_INFO + $regx = trim($_SERVER['PATH_INFO'],'/'); + if(empty($regx)) return $return = true; + // 是否开启路由使用 + if(!C('URL_ROUTER_ON')) return $return = false; + // 路由定义文件优先于config中的配置定义 + $routes = C('URL_ROUTE_RULES'); + // 路由处理 + if(!empty($routes)) { + $depr = C('URL_PATHINFO_DEPR'); + // 分隔符替换 确保路由定义使用统一的分隔符 + $regx = str_replace($depr,'/',$regx); + foreach ($routes as $rule=>$route){ + if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由 + return $return = $this->parseRegex($matches,$route,$regx); + }else{ // 规则路由 + $len1 = substr_count($regx,'/'); + $len2 = substr_count($rule,'/'); + if($len1>=$len2) { + if('$' == substr($rule,-1,1)) {// 完整匹配 + if($len1 != $len2) { + continue; + }else{ + $rule = substr($rule,0,-1); + } + } + $match = $this->checkUrlMatch($regx,$rule); + if($match) return $return = $this->parseRule($rule,$route,$regx); + } + } + } + } + $return = false; + } + + // 检测URL和规则路由是否匹配 + private function checkUrlMatch($regx,$rule) { + $m1 = explode('/',$regx); + $m2 = explode('/',$rule); + $match = true; // 是否匹配 + foreach ($m2 as $key=>$val){ + if(':' == substr($val,0,1)) {// 动态变量 + if(strpos($val,'\\')) { + $type = substr($val,-1); + if('d'==$type && !is_numeric($m1[$key])) { + $match = false; + break; + } + }elseif(strpos($val,'^')){ + $array = explode('|',substr(strstr($val,'^'),1)); + if(in_array($m1[$key],$array)) { + $match = false; + break; + } + } + }elseif(0 !== strcasecmp($val,$m1[$key])){ + $match = false; + break; + } + } + return $match; + } + + // 解析规范的路由地址 + // 地址格式 [分组/模块/操作?]参数1=值1&参数2=值2... + private function parseUrl($url) { + $var = array(); + if(false !== strpos($url,'?')) { // [分组/模块/操作?]参数1=值1&参数2=值2... + $info = parse_url($url); + $path = explode('/',$info['path']); + parse_str($info['query'],$var); + }elseif(strpos($url,'/')){ // [分组/模块/操作] + $path = explode('/',$url); + }else{ // 参数1=值1&参数2=值2... + parse_str($url,$var); + } + if(isset($path)) { + $var[C('VAR_ACTION')] = array_pop($path); + if(!empty($path)) { + $var[C('VAR_MODULE')] = array_pop($path); + } + if(!empty($path)) { + $var[C('VAR_GROUP')] = array_pop($path); + } + } + return $var; + } + + // 解析规则路由 + // '路由规则'=>'[分组/模块/操作]?额外参数1=值1&额外参数2=值2...' + // '路由规则'=>array('[分组/模块/操作]','额外参数1=值1&额外参数2=值2...') + // '路由规则'=>'外部地址' + // '路由规则'=>array('外部地址','重定向代码') + // 路由规则中 :开头 表示动态变量 + // 外部地址中可以用动态变量 采用 :1 :2 的方式 + // 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'), + // 'new/:id'=>array('/new.php?id=:1',301), 重定向 + private function parseRule($rule,$route,$regx) { + // 获取路由地址规则 + $url = is_array($route)?$route[0]:$route; + // 获取URL地址中的参数 + $paths = explode('/',$regx); + // 解析路由规则 + $matches = array(); + $rule = explode('/',$rule); + foreach ($rule as $item){ + if(0===strpos($item,':')) { // 动态变量获取 + if($pos = strpos($item,'^') ) { + $var = substr($item,1,$pos-1); + }elseif(strpos($item,'\\')){ + $var = substr($item,1,-2); + }else{ + $var = substr($item,1); + } + $matches[$var] = array_shift($paths); + }else{ // 过滤URL中的静态变量 + array_shift($paths); + } + } + if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 + if(strpos($url,':')) { // 传递动态参数 + $values = array_values($matches); + $url = preg_replace('/:(\d+)/e','$values[\\1-1]',$url); + } + header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); + exit; + }else{ + // 解析路由地址 + $var = $this->parseUrl($url); + // 解析路由地址里面的动态参数 + $values = array_values($matches); + foreach ($var as $key=>$val){ + if(0===strpos($val,':')) { + $var[$key] = $values[substr($val,1)-1]; + } + } + $var = array_merge($matches,$var); + // 解析剩余的URL参数 + if($paths) { + preg_replace('@(\w+)\/([^\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', implode('/',$paths)); + } + // 解析路由自动传入参数 + if(is_array($route) && isset($route[1])) { + parse_str($route[1],$params); + $var = array_merge($var,$params); + } + $_GET = array_merge($var,$_GET); + } + return true; + } + + // 解析正则路由 + // '路由正则'=>'[分组/模块/操作]?参数1=值1&参数2=值2...' + // '路由正则'=>array('[分组/模块/操作]?参数1=值1&参数2=值2...','额外参数1=值1&额外参数2=值2...') + // '路由正则'=>'外部地址' + // '路由正则'=>array('外部地址','重定向代码') + // 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式 + // '/new\/(\d+)\/(\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'), + // '/new\/(\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), 重定向 + private function parseRegex($matches,$route,$regx) { + // 获取路由地址规则 + $url = is_array($route)?$route[0]:$route; + $url = preg_replace('/:(\d+)/e','$matches[\\1]',$url); + if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 + header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); + exit; + }else{ + // 解析路由地址 + $var = $this->parseUrl($url); + // 解析剩余的URL参数 + $regx = substr_replace($regx,'',0,strlen($matches[0])); + if($regx) { + preg_replace('@(\w+)\/([^,\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', $regx); + } + // 解析路由自动传入参数 + if(is_array($route) && isset($route[1])) { + parse_str($route[1],$params); + $var = array_merge($var,$params); + } + $_GET = array_merge($var,$_GET); + } + return true; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/ContentReplaceBehavior.class.php b/ThinkPHP/Lib/Behavior/ContentReplaceBehavior.class.php new file mode 100644 index 0000000..0c899ea --- /dev/null +++ b/ThinkPHP/Lib/Behavior/ContentReplaceBehavior.class.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:模板内容输出替换 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class ContentReplaceBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'TMPL_PARSE_STRING' => array(), + ); + + // 行为扩展的执行入口必须是run + public function run(&$content){ + $content = $this->templateContentReplace($content); + } + + /** + * 模板内容替换 + * @access protected + * @param string $content 模板内容 + * @return string + */ + protected function templateContentReplace($content) { + // 系统默认的特殊变量替换 + $replace = array( + '__TMPL__' => APP_TMPL_PATH, // 项目模板目录 + '__ROOT__' => __ROOT__, // 当前网站地址 + '__APP__' => __APP__, // 当前项目地址 + '__GROUP__' => defined('GROUP_NAME')?__GROUP__:__APP__, + '__ACTION__' => __ACTION__, // 当前操作地址 + '__SELF__' => __SELF__, // 当前页面地址 + '__URL__' => __URL__, + '../Public' => APP_TMPL_PATH.'Public',// 项目公共模板目录 + '__PUBLIC__' => __ROOT__.'/Public',// 站点公共目录 + ); + // 允许用户自定义模板的字符串替换 + if(is_array(C('TMPL_PARSE_STRING')) ) + $replace = array_merge($replace,C('TMPL_PARSE_STRING')); + $content = str_replace(array_keys($replace),array_values($replace),$content); + return $content; + } + +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/ParseTemplateBehavior.class.php b/ThinkPHP/Lib/Behavior/ParseTemplateBehavior.class.php new file mode 100644 index 0000000..bae3689 --- /dev/null +++ b/ThinkPHP/Lib/Behavior/ParseTemplateBehavior.class.php @@ -0,0 +1,121 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:模板解析 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class ParseTemplateBehavior extends Behavior { + // 行为参数定义(默认值) 可在项目配置中覆盖 + protected $options = array( + // 布局设置 + 'TMPL_ENGINE_TYPE' => 'Think', // 默认模板引擎 以下设置仅对使用Think模板引擎有效 + 'TMPL_CACHFILE_SUFFIX' => '.php', // 默认模板缓存后缀 + 'TMPL_DENY_FUNC_LIST' => 'echo,exit', // 模板引擎禁用函数 + 'TMPL_DENY_PHP' => false, // 默认模板引擎是否禁用PHP原生代码 + 'TMPL_L_DELIM' => '{', // 模板引擎普通标签开始标记 + 'TMPL_R_DELIM' => '}', // 模板引擎普通标签结束标记 + 'TMPL_VAR_IDENTIFY' => 'array', // 模板变量识别。留空自动判断,参数为'obj'则表示对象 + 'TMPL_STRIP_SPACE' => true, // 是否去除模板文件里面的html空格与换行 + 'TMPL_CACHE_ON' => true, // 是否开启模板编译缓存,设为false则每次都会重新编译 + 'TMPL_CACHE_PREFIX' => '', // 模板缓存前缀标识,可以动态改变 + 'TMPL_CACHE_TIME' => 0, // 模板缓存有效期 0 为永久,(以数字为值,单位:秒) + 'TMPL_LAYOUT_ITEM' => '{__CONTENT__}', // 布局模板的内容替换标识 + 'LAYOUT_ON' => false, // 是否启用布局 + 'LAYOUT_NAME' => 'layout', // 当前布局名称 默认为layout + + // Think模板引擎标签库相关设定 + 'TAGLIB_BEGIN' => '<', // 标签库标签开始标记 + 'TAGLIB_END' => '>', // 标签库标签结束标记 + 'TAGLIB_LOAD' => true, // 是否使用内置标签库之外的其它标签库,默认自动检测 + 'TAGLIB_BUILD_IN' => 'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序 + 'TAGLIB_PRE_LOAD' => '', // 需要额外加载的标签库(须指定标签库名称),多个以逗号分隔 + ); + + // 行为扩展的执行入口必须是run + public function run(&$_data){ + $engine = strtolower(C('TMPL_ENGINE_TYPE')); + $_content = empty($_data['content'])?$_data['file']:$_data['content']; + $_data['prefix'] = !empty($_data['prefix'])?$_data['prefix']:C('TMPL_CACHE_PREFIX'); + if('think'==$engine){ // 采用Think模板引擎 + if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix'])) + || $this->checkCache($_data['file'],$_data['prefix'])) { // 缓存有效 + // 分解变量并载入模板缓存 + extract($_data['var'], EXTR_OVERWRITE); + //载入模版缓存文件 + include C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'); + }else{ + $tpl = Think::instance('ThinkTemplate'); + // 编译并加载模板文件 + $tpl->fetch($_content,$_data['var'],$_data['prefix']); + } + }else{ + // 调用第三方模板引擎解析和输出 + $class = 'Template'.ucwords($engine); + if(class_exists($class)) { + $tpl = new $class; + $tpl->fetch($_content,$_data['var']); + }else { // 类没有定义 + throw_exception(L('_NOT_SUPPERT_').': ' . $class); + } + } + } + + /** + * 检查缓存文件是否有效 + * 如果无效则需要重新编译 + * @access public + * @param string $tmplTemplateFile 模板文件名 + * @return boolean + */ + protected function checkCache($tmplTemplateFile,$prefix='') { + if (!C('TMPL_CACHE_ON')) // 优先对配置设定检测 + return false; + $tmplCacheFile = C('CACHE_PATH').$prefix.md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX'); + if(!is_file($tmplCacheFile)){ + return false; + }elseif (filemtime($tmplTemplateFile) > filemtime($tmplCacheFile)) { + // 模板文件如果有更新则缓存需要更新 + return false; + }elseif (C('TMPL_CACHE_TIME') != 0 && time() > filemtime($tmplCacheFile)+C('TMPL_CACHE_TIME')) { + // 缓存是否在有效期 + return false; + } + // 开启布局模板 + if(C('LAYOUT_ON')) { + $layoutFile = THEME_PATH.C('LAYOUT_NAME').C('TMPL_TEMPLATE_SUFFIX'); + if(filemtime($layoutFile) > filemtime($tmplCacheFile)) { + return false; + } + } + // 缓存有效 + return true; + } + + /** + * 检查缓存内容是否有效 + * 如果无效则需要重新编译 + * @access public + * @param string $tmplContent 模板内容 + * @return boolean + */ + protected function checkContentCache($tmplContent,$prefix='') { + if(is_file(C('CACHE_PATH').$prefix.md5($tmplContent).C('TMPL_CACHFILE_SUFFIX'))){ + return true; + }else{ + return false; + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/ReadHtmlCacheBehavior.class.php b/ThinkPHP/Lib/Behavior/ReadHtmlCacheBehavior.class.php new file mode 100644 index 0000000..7131f2d --- /dev/null +++ b/ThinkPHP/Lib/Behavior/ReadHtmlCacheBehavior.class.php @@ -0,0 +1,123 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:静态缓存读取 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class ReadHtmlCacheBehavior extends Behavior { + protected $options = array( + 'HTML_CACHE_ON' => false, + 'HTML_CACHE_TIME' => 60, + 'HTML_CACHE_RULES' => array(), + 'HTML_FILE_SUFFIX' => '.html', + ); + + // 行为扩展的执行入口必须是run + public function run(&$params){ + // 开启静态缓存 + if(C('HTML_CACHE_ON')) { + $cacheTime = $this->requireHtmlCache(); + if( false !== $cacheTime && $this->checkHTMLCache(HTML_FILE_NAME,$cacheTime)) { //静态页面有效 + // 读取静态页面输出 + readfile(HTML_FILE_NAME); + exit(); + } + } + } + + // 判断是否需要静态缓存 + static private function requireHtmlCache() { + // 分析当前的静态规则 + $htmls = C('HTML_CACHE_RULES'); // 读取静态规则 + if(!empty($htmls)) { + $htmls = array_change_key_case($htmls); + // 静态规则文件定义格式 actionName=>array('静态规则','缓存时间','附加规则') + // 'read'=>array('{id},{name}',60,'md5') 必须保证静态规则的唯一性 和 可判断性 + // 检测静态规则 + $moduleName = strtolower(MODULE_NAME); + $actionName = strtolower(ACTION_NAME); + if(isset($htmls[$moduleName.':'.$actionName])) { + $html = $htmls[$moduleName.':'.$actionName]; // 某个模块的操作的静态规则 + }elseif(isset($htmls[$moduleName.':'])){// 某个模块的静态规则 + $html = $htmls[$moduleName.':']; + }elseif(isset($htmls[$actionName])){ + $html = $htmls[$actionName]; // 所有操作的静态规则 + }elseif(isset($htmls['*'])){ + $html = $htmls['*']; // 全局静态规则 + }elseif(isset($htmls['empty:index']) && !class_exists(MODULE_NAME.'Action')){ + $html = $htmls['empty:index']; // 空模块静态规则 + }elseif(isset($htmls[$moduleName.':_empty']) && self::isEmptyAction(MODULE_NAME,ACTION_NAME)){ + $html = $htmls[$moduleName.':_empty']; // 空操作静态规则 + } + if(!empty($html)) { + // 解读静态规则 + $rule = $html[0]; + // 以$_开头的系统变量 + $rule = preg_replace('/{\$(_\w+)\.(\w+)\|(\w+)}/e',"\\3(\$\\1['\\2'])",$rule); + $rule = preg_replace('/{\$(_\w+)\.(\w+)}/e',"\$\\1['\\2']",$rule); + // {ID|FUN} GET变量的简写 + $rule = preg_replace('/{(\w+)\|(\w+)}/e',"\\2(\$_GET['\\1'])",$rule); + $rule = preg_replace('/{(\w+)}/e',"\$_GET['\\1']",$rule); + // 特殊系统变量 + $rule = str_ireplace( + array('{:app}','{:module}','{:action}','{:group}'), + array(APP_NAME,MODULE_NAME,ACTION_NAME,defined('GROUP_NAME')?GROUP_NAME:''), + $rule); + // {|FUN} 单独使用函数 + $rule = preg_replace('/{|(\w+)}/e',"\\1()",$rule); + if(!empty($html[2])) $rule = $html[2]($rule); // 应用附加函数 + $cacheTime = isset($html[1])?$html[1]:C('HTML_CACHE_TIME'); // 缓存有效期 + // 当前缓存文件 + define('HTML_FILE_NAME',HTML_PATH . $rule.C('HTML_FILE_SUFFIX')); + return $cacheTime; + } + } + // 无需缓存 + return false; + } + + /** + * 检查静态HTML文件是否有效 + * 如果无效需要重新更新 + * @access public + * @param string $cacheFile 静态文件名 + * @param integer $cacheTime 缓存有效期 + * @return boolean + */ + static public function checkHTMLCache($cacheFile='',$cacheTime='') { + if(!is_file($cacheFile)){ + return false; + }elseif (filemtime(C('TEMPLATE_NAME')) > filemtime($cacheFile)) { + // 模板文件如果更新静态文件需要更新 + return false; + }elseif(!is_numeric($cacheTime) && function_exists($cacheTime)){ + return $cacheTime($cacheFile); + }elseif ($cacheTime != 0 && NOW_TIME > filemtime($cacheFile)+$cacheTime) { + // 文件是否在有效期 + return false; + } + //静态文件有效 + return true; + } + + //检测是否是空操作 + static private function isEmptyAction($module,$action) { + $className = $module.'Action'; + $class = new $className; + return !method_exists($class,$action); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php b/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php new file mode 100644 index 0000000..760d5b9 --- /dev/null +++ b/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php @@ -0,0 +1,128 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:页面Trace显示输出 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class ShowPageTraceBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'SHOW_PAGE_TRACE' => false, // 显示页面Trace信息 + 'TRACE_PAGE_TABS' => array('BASE'=>'基本','FILE'=>'文件','INFO'=>'流程','ERR|NOTIC'=>'错误','SQL'=>'SQL','DEBUG'=>'调试'), // 页面Trace可定制的选项卡 + 'PAGE_TRACE_SAVE' => false, + ); + + // 行为扩展的执行入口必须是run + public function run(&$params){ + if(!IS_AJAX && C('SHOW_PAGE_TRACE')) { + echo $this->showTrace(); + } + } + + /** + * 显示页面Trace信息 + * @access private + */ + private function showTrace() { + // 系统默认显示信息 + $files = get_included_files(); + $info = array(); + foreach ($files as $key=>$file){ + $info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )'; + } + $trace = array(); + $base = array( + '请求信息' => date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__, + '运行时间' => $this->showTime(), + '吞吐率' => number_format(1/G('beginTime','viewEndTime'),2).'req/s', + '内存开销' => MEMORY_LIMIT_ON?number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024,2).' kb':'不支持', + '查询信息' => N('db_query').' queries '.N('db_write').' writes ', + '文件加载' => count(get_included_files()), + '缓存信息' => N('cache_read').' gets '.N('cache_write').' writes ', + '配置加载' => count(c()), + '会话信息' => 'SESSION_ID='.session_id(), + ); + // 读取项目定义的Trace文件 + $traceFile = CONF_PATH.'trace.php'; + if(is_file($traceFile)) { + $base = array_merge($base,include $traceFile); + } + $debug = trace(); + $tabs = C('TRACE_PAGE_TABS'); + foreach ($tabs as $name=>$title){ + switch(strtoupper($name)) { + case 'BASE':// 基本信息 + $trace[$title] = $base; + break; + case 'FILE': // 文件信息 + $trace[$title] = $info; + break; + default:// 调试信息 + $name = strtoupper($name); + if(strpos($name,'|')) {// 多组信息 + $array = explode('|',$name); + $result = array(); + foreach($array as $name){ + $result += isset($debug[$name])?$debug[$name]:array(); + } + $trace[$title] = $result; + }else{ + $trace[$title] = isset($debug[$name])?$debug[$name]:''; + } + } + } + if($save = C('PAGE_TRACE_SAVE')) { // 保存页面Trace日志 + if(is_array($save)) {// 选择选项卡保存 + $tabs = C('TRACE_PAGE_TABS'); + $array = array(); + foreach ($save as $tab){ + $array[] = $tabs[$tab]; + } + } + $content = date('[ c ]').' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n"; + foreach ($trace as $key=>$val){ + if(!isset($array) || in_array($key,$array)) { + $content .= '[ '.$key." ]\r\n"; + if(is_array($val)) { + foreach ($val as $k=>$v){ + $content .= (!is_numeric($k)?$k.':':'').print_r($v,true)."\r\n"; + } + }else{ + $content .= print_r($val,true)."\r\n"; + } + $content .= "\r\n"; + } + } + error_log(str_replace('
    ',"\r\n",$content), Log::FILE,LOG_PATH.date('y_m_d').'_trace.log'); + } + unset($files,$info,$base); + // 调用Trace页面模板 + ob_start(); + include C('TMPL_TRACE_FILE')?C('TMPL_TRACE_FILE'):THINK_PATH.'Tpl/page_trace.tpl'; + return ob_get_clean(); + } + + /** + * 获取运行时间 + */ + private function showTime() { + // 显示运行时间 + G('beginTime',$GLOBALS['_beginTime']); + G('viewEndTime'); + // 显示详细运行时间 + return G('beginTime','viewEndTime').'s ( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )'; + } +} diff --git a/ThinkPHP/Lib/Behavior/ShowRuntimeBehavior.class.php b/ThinkPHP/Lib/Behavior/ShowRuntimeBehavior.class.php new file mode 100644 index 0000000..f8c86ce --- /dev/null +++ b/ThinkPHP/Lib/Behavior/ShowRuntimeBehavior.class.php @@ -0,0 +1,84 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:运行时间信息显示 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class ShowRuntimeBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'SHOW_RUN_TIME' => false, // 运行时间显示 + 'SHOW_ADV_TIME' => false, // 显示详细的运行时间 + 'SHOW_DB_TIMES' => false, // 显示数据库查询和写入次数 + 'SHOW_CACHE_TIMES' => false, // 显示缓存操作次数 + 'SHOW_USE_MEM' => false, // 显示内存开销 + 'SHOW_LOAD_FILE' => false, // 显示加载文件数 + 'SHOW_FUN_TIMES' => false , // 显示函数调用次数 + ); + + // 行为扩展的执行入口必须是run + public function run(&$content){ + if(C('SHOW_RUN_TIME')){ + if(false !== strpos($content,'{__NORUNTIME__}')) { + $content = str_replace('{__NORUNTIME__}','',$content); + }else{ + $runtime = $this->showTime(); + if(strpos($content,'{__RUNTIME__}')) + $content = str_replace('{__RUNTIME__}',$runtime,$content); + else + $content .= $runtime; + } + }else{ + $content = str_replace(array('{__NORUNTIME__}','{__RUNTIME__}'),'',$content); + } + } + + /** + * 显示运行时间、数据库操作、缓存次数、内存使用信息 + * @access private + * @return string + */ + private function showTime() { + // 显示运行时间 + G('beginTime',$GLOBALS['_beginTime']); + G('viewEndTime'); + $showTime = 'Process: '.G('beginTime','viewEndTime').'s '; + if(C('SHOW_ADV_TIME')) { + // 显示详细运行时间 + $showTime .= '( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )'; + } + if(C('SHOW_DB_TIMES') && class_exists('Db',false) ) { + // 显示数据库操作次数 + $showTime .= ' | DB :'.N('db_query').' queries '.N('db_write').' writes '; + } + if(C('SHOW_CACHE_TIMES') && class_exists('Cache',false)) { + // 显示缓存读写次数 + $showTime .= ' | Cache :'.N('cache_read').' gets '.N('cache_write').' writes '; + } + if(MEMORY_LIMIT_ON && C('SHOW_USE_MEM')) { + // 显示内存开销 + $showTime .= ' | UseMem:'. number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024).' kb'; + } + if(C('SHOW_LOAD_FILE')) { + $showTime .= ' | LoadFile:'.count(get_included_files()); + } + if(C('SHOW_FUN_TIMES')) { + $fun = get_defined_functions(); + $showTime .= ' | CallFun:'.count($fun['user']).','.count($fun['internal']); + } + return $showTime; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/TokenBuildBehavior.class.php b/ThinkPHP/Lib/Behavior/TokenBuildBehavior.class.php new file mode 100644 index 0000000..cda80e4 --- /dev/null +++ b/ThinkPHP/Lib/Behavior/TokenBuildBehavior.class.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:表单令牌生成 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class TokenBuildBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'TOKEN_ON' => false, // 开启令牌验证 + 'TOKEN_NAME' => '__hash__', // 令牌验证的表单隐藏字段名称 + 'TOKEN_TYPE' => 'md5', // 令牌验证哈希规则 + 'TOKEN_RESET' => true, // 令牌错误后是否重置 + ); + + public function run(&$content){ + if(C('TOKEN_ON')) { + if(strpos($content,'{__TOKEN__}')) { + // 指定表单令牌隐藏域位置 + $content = str_replace('{__TOKEN__}',$this->buildToken(),$content); + }elseif(preg_match('/<\/form(\s*)>/is',$content,$match)) { + // 智能生成表单令牌隐藏域 + $content = str_replace($match[0],$this->buildToken().$match[0],$content); + } + }else{ + $content = str_replace('{__TOKEN__}','',$content); + } + } + + // 创建表单令牌 + private function buildToken() { + $tokenName = C('TOKEN_NAME'); + $tokenType = C('TOKEN_TYPE'); + if(!isset($_SESSION[$tokenName])) { + $_SESSION[$tokenName] = array(); + } + // 标识当前页面唯一性 + $tokenKey = md5($_SERVER['REQUEST_URI']); + if(isset($_SESSION[$tokenName][$tokenKey])) {// 相同页面不重复生成session + $tokenValue = $_SESSION[$tokenName][$tokenKey]; + }else{ + $tokenValue = $tokenType(microtime(TRUE)); + $_SESSION[$tokenName][$tokenKey] = $tokenValue; + } + $token = ''; + return $token; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/WriteHtmlCacheBehavior.class.php b/ThinkPHP/Lib/Behavior/WriteHtmlCacheBehavior.class.php new file mode 100644 index 0000000..42aff99 --- /dev/null +++ b/ThinkPHP/Lib/Behavior/WriteHtmlCacheBehavior.class.php @@ -0,0 +1,34 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:静态缓存写入 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class WriteHtmlCacheBehavior extends Behavior { + + // 行为扩展的执行入口必须是run + public function run(&$content){ + if(C('HTML_CACHE_ON') && defined('HTML_FILE_NAME')) { + //静态文件写入 + // 如果开启HTML功能 检查并重写HTML文件 + // 没有模版的操作不生成静态文件 + if(!is_dir(dirname(HTML_FILE_NAME))) + mkdir(dirname(HTML_FILE_NAME),0755,true); + if( false === file_put_contents( HTML_FILE_NAME , $content )) + throw_exception(L('_CACHE_WRITE_ERROR_').':'.HTML_FILE_NAME); + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Action.class.php b/ThinkPHP/Lib/Core/Action.class.php new file mode 100644 index 0000000..fef189b --- /dev/null +++ b/ThinkPHP/Lib/Core/Action.class.php @@ -0,0 +1,411 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP Action控制器基类 抽象类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +abstract class Action { + + /** + * 视图实例对象 + * @var view + * @access protected + */ + protected $view = null; + + /** + * 当前控制器名称 + * @var name + * @access protected + */ + private $name = ''; + + /** + * 控制器参数 + * @var config + * @access protected + */ + protected $config = array(); + + /** + * 架构函数 取得模板对象实例 + * @access public + */ + public function __construct() { + tag('action_begin',$this->config); + //实例化视图类 + $this->view = Think::instance('View'); + //控制器初始化 + if(method_exists($this,'_initialize')) + $this->_initialize(); + } + + /** + * 获取当前Action名称 + * @access protected + */ + protected function getActionName() { + if(empty($this->name)) { + // 获取Action名称 + $this->name = substr(get_class($this),0,-6); + } + return $this->name; + } + + /** + * 是否AJAX请求 + * @access protected + * @return bool + */ + protected function isAjax() { + if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) ) { + if('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) + return true; + } + if(!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) + // 判断Ajax方式提交 + return true; + return false; + } + + /** + * 模板显示 调用内置的模板引擎显示方法, + * @access protected + * @param string $templateFile 指定要调用的模板文件 + * 默认为空 由系统自动定位模板文件 + * @param string $charset 输出编码 + * @param string $contentType 输出类型 + * @param string $content 输出内容 + * @param string $prefix 模板缓存前缀 + * @return void + */ + protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') { + $this->view->display($templateFile,$charset,$contentType,$content,$prefix); + } + + /** + * 输出内容文本可以包括Html 并支持内容解析 + * @access protected + * @param string $content 输出内容 + * @param string $charset 模板输出字符集 + * @param string $contentType 输出类型 + * @param string $prefix 模板缓存前缀 + * @return mixed + */ + protected function show($content,$charset='',$contentType='',$prefix='') { + $this->view->display('',$charset,$contentType,$content,$prefix); + } + + /** + * 获取输出页面内容 + * 调用内置的模板引擎fetch方法, + * @access protected + * @param string $templateFile 指定要调用的模板文件 + * 默认为空 由系统自动定位模板文件 + * @param string $content 模板输出内容 + * @param string $prefix 模板缓存前缀* + * @return string + */ + protected function fetch($templateFile='',$content='',$prefix='') { + return $this->view->fetch($templateFile,$content,$prefix); + } + + /** + * 创建静态页面 + * @access protected + * @htmlfile 生成的静态文件名称 + * @htmlpath 生成的静态文件路径 + * @param string $templateFile 指定要调用的模板文件 + * 默认为空 由系统自动定位模板文件 + * @return string + */ + protected function buildHtml($htmlfile='',$htmlpath='',$templateFile='') { + $content = $this->fetch($templateFile); + $htmlpath = !empty($htmlpath)?$htmlpath:HTML_PATH; + $htmlfile = $htmlpath.$htmlfile.C('HTML_FILE_SUFFIX'); + if(!is_dir(dirname($htmlfile))) + // 如果静态目录不存在 则创建 + mkdir(dirname($htmlfile),0755,true); + if(false === file_put_contents($htmlfile,$content)) + throw_exception(L('_CACHE_WRITE_ERROR_').':'.$htmlfile); + return $content; + } + + /** + * 模板主题设置 + * @access protected + * @param string $theme 模版主题 + * @return Action + */ + protected function theme($theme){ + $this->view->theme($theme); + return $this; + } + + /** + * 模板变量赋值 + * @access protected + * @param mixed $name 要显示的模板变量 + * @param mixed $value 变量的值 + * @return Action + */ + protected function assign($name,$value='') { + $this->view->assign($name,$value); + return $this; + } + + public function __set($name,$value) { + $this->assign($name,$value); + } + + /** + * 取得模板显示变量的值 + * @access protected + * @param string $name 模板显示变量 + * @return mixed + */ + public function get($name='') { + return $this->view->get($name); + } + + public function __get($name) { + return $this->get($name); + } + + /** + * 检测模板变量的值 + * @access public + * @param string $name 名称 + * @return boolean + */ + public function __isset($name) { + return $this->get($name); + } + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $args 参数 + * @return mixed + */ + public function __call($method,$args) { + if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) { + if(method_exists($this,'_empty')) { + // 如果定义了_empty操作 则调用 + $this->_empty($method,$args); + }elseif(file_exists_case($this->view->parseTemplate())){ + // 检查是否存在默认模版 如果有直接输出模版 + $this->display(); + }elseif(function_exists('__hack_action')) { + // hack 方式定义扩展操作 + __hack_action(); + }else{ + _404(L('_ERROR_ACTION_').':'.ACTION_NAME); + } + }else{ + switch(strtolower($method)) { + // 判断提交方式 + case 'ispost' : + case 'isget' : + case 'ishead' : + case 'isdelete' : + case 'isput' : + return strtolower($_SERVER['REQUEST_METHOD']) == strtolower(substr($method,2)); + // 获取变量 支持过滤和默认值 调用方式 $this->_post($key,$filter,$default); + case '_get' : $input =& $_GET;break; + case '_post' : $input =& $_POST;break; + case '_put' : parse_str(file_get_contents('php://input'), $input);break; + case '_param' : + switch($_SERVER['REQUEST_METHOD']) { + case 'POST': + $input = $_POST; + break; + case 'PUT': + parse_str(file_get_contents('php://input'), $input); + break; + default: + $input = $_GET; + } + if(C('VAR_URL_PARAMS') && isset($_GET[C('VAR_URL_PARAMS')])){ + $input = array_merge($input,$_GET[C('VAR_URL_PARAMS')]); + } + 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; + default: + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + } + if(!isset($args[0])) { // 获取全局变量 + $data = $input; // 由VAR_FILTERS配置进行过滤 + }elseif(isset($input[$args[0]])) { // 取值操作 + $data = $input[$args[0]]; + $filters = isset($args[1])?$args[1]:C('DEFAULT_FILTER'); + if($filters) {// 2012/3/23 增加多方法过滤支持 + $filters = explode(',',$filters); + foreach($filters as $filter){ + if(function_exists($filter)) { + $data = is_array($data)?array_map($filter,$data):$filter($data); // 参数过滤 + } + } + } + }else{ // 变量默认值 + $data = isset($args[2])?$args[2]:NULL; + } + Log::record('建议使用I方法替代'.$method,Log::NOTICE); + return $data; + } + } + + /** + * 操作错误跳转的快捷方法 + * @access protected + * @param string $message 错误信息 + * @param string $jumpUrl 页面跳转地址 + * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 + * @return void + */ + protected function error($message='',$jumpUrl='',$ajax=false) { + $this->dispatchJump($message,0,$jumpUrl,$ajax); + } + + /** + * 操作成功跳转的快捷方法 + * @access protected + * @param string $message 提示信息 + * @param string $jumpUrl 页面跳转地址 + * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 + * @return void + */ + protected function success($message='',$jumpUrl='',$ajax=false) { + $this->dispatchJump($message,1,$jumpUrl,$ajax); + } + + /** + * Ajax方式返回数据到客户端 + * @access protected + * @param mixed $data 要返回的数据 + * @param String $type AJAX返回数据格式 + * @return void + */ + protected function ajaxReturn($data,$type='') { + if(func_num_args()>2) {// 兼容3.0之前用法 + $args = func_get_args(); + array_shift($args); + $info = array(); + $info['data'] = $data; + $info['info'] = array_shift($args); + $info['status'] = array_shift($args); + $data = $info; + $type = $args?array_shift($args):''; + } + if(empty($type)) $type = C('DEFAULT_AJAX_RETURN'); + switch (strtoupper($type)){ + case 'JSON' : + // 返回JSON数据格式到客户端 包含状态信息 + header('Content-Type:application/json; charset=utf-8'); + exit(json_encode($data)); + case 'XML' : + // 返回xml格式数据 + header('Content-Type:text/xml; charset=utf-8'); + exit(xml_encode($data)); + case 'JSONP': + // 返回JSON数据格式到客户端 包含状态信息 + header('Content-Type:application/json; charset=utf-8'); + $handler = isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER'); + exit($handler.'('.json_encode($data).');'); + case 'EVAL' : + // 返回可执行的js脚本 + header('Content-Type:text/html; charset=utf-8'); + exit($data); + default : + // 用于扩展其他返回格式数据 + tag('ajax_return',$data); + } + } + + /** + * Action跳转(URL重定向) 支持指定模块和延时跳转 + * @access protected + * @param string $url 跳转的URL表达式 + * @param array $params 其它URL参数 + * @param integer $delay 延时跳转的时间 单位为秒 + * @param string $msg 跳转提示信息 + * @return void + */ + protected function redirect($url,$params=array(),$delay=0,$msg='') { + $url = U($url,$params); + redirect($url,$delay,$msg); + } + + /** + * 默认跳转操作 支持错误导向和正确跳转 + * 调用模板显示 默认为public目录下面的success页面 + * 提示页面为可配置 支持模板标签 + * @param string $message 提示信息 + * @param Boolean $status 状态 + * @param string $jumpUrl 页面跳转地址 + * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 + * @access private + * @return void + */ + private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) { + if(true === $ajax || IS_AJAX) {// AJAX提交 + $data = is_array($ajax)?$ajax:array(); + $data['info'] = $message; + $data['status'] = $status; + $data['url'] = $jumpUrl; + $this->ajaxReturn($data); + } + if(is_int($ajax)) $this->assign('waitSecond',$ajax); + if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl); + // 提示标题 + $this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_')); + //如果设置了关闭窗口,则提示完毕后自动关闭窗口 + if($this->get('closeWin')) $this->assign('jumpUrl','javascript:window.close();'); + $this->assign('status',$status); // 状态 + //保证输出不受静态缓存影响 + C('HTML_CACHE_ON',false); + if($status) { //发送成功信息 + $this->assign('message',$message);// 提示信息 + // 成功操作后默认停留1秒 + if(!isset($this->waitSecond)) $this->assign('waitSecond','1'); + // 默认操作成功自动返回操作前页面 + if(!isset($this->jumpUrl)) $this->assign("jumpUrl",$_SERVER["HTTP_REFERER"]); + $this->display(C('TMPL_ACTION_SUCCESS')); + }else{ + $this->assign('error',$message);// 提示信息 + //发生错误时候默认停留3秒 + if(!isset($this->waitSecond)) $this->assign('waitSecond','3'); + // 默认发生错误的话自动返回上页 + if(!isset($this->jumpUrl)) $this->assign('jumpUrl',"javascript:history.back(-1);"); + $this->display(C('TMPL_ACTION_ERROR')); + // 中止执行 避免出错后继续执行 + exit ; + } + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 执行后续操作 + tag('action_end'); + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/App.class.php b/ThinkPHP/Lib/Core/App.class.php new file mode 100644 index 0000000..7442e39 --- /dev/null +++ b/ThinkPHP/Lib/Core/App.class.php @@ -0,0 +1,190 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 应用程序类 执行应用过程管理 + * 可以在模式扩展中重新定义 但是必须具有Run方法接口 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class App { + + /** + * 应用程序初始化 + * @access public + * @return void + */ + static public function init() { + // 页面压缩输出支持 + if(C('OUTPUT_ENCODE')){ + $zlib = ini_get('zlib.output_compression'); + if(empty($zlib)) ob_start('ob_gzhandler'); + } + // 设置系统时区 + date_default_timezone_set(C('DEFAULT_TIMEZONE')); + // 加载动态项目公共文件和配置 + load_ext_file(); + // URL调度 + Dispatcher::dispatch(); + + // 定义当前请求的系统常量 + define('NOW_TIME', $_SERVER['REQUEST_TIME']); + define('REQUEST_METHOD',$_SERVER['REQUEST_METHOD']); + define('IS_GET', REQUEST_METHOD =='GET' ? true : false); + define('IS_POST', REQUEST_METHOD =='POST' ? true : false); + define('IS_PUT', REQUEST_METHOD =='PUT' ? true : false); + define('IS_DELETE', REQUEST_METHOD =='DELETE' ? true : false); + define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false); + + // URL调度结束标签 + tag('url_dispatch'); + // 系统变量安全过滤 + if(C('VAR_FILTERS')) { + $filters = explode(',',C('VAR_FILTERS')); + foreach($filters as $filter){ + // 全局参数过滤 + array_walk_recursive($_POST,$filter); + array_walk_recursive($_GET,$filter); + } + } + + C('LOG_PATH',realpath(LOG_PATH).'/'); + //动态配置 TMPL_EXCEPTION_FILE,改为绝对地址 + C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE'))); + return ; + } + + /** + * 执行应用程序 + * @access public + * @return void + */ + static public function exec() { + if(!preg_match('/^[A-Za-z](\w)*$/',MODULE_NAME)){ // 安全检测 + $module = false; + }else{ + //创建Action控制器实例 + $group = defined('GROUP_NAME') && C('APP_GROUP_MODE')==0 ? GROUP_NAME.'/' : ''; + $module = A($group.MODULE_NAME); + } + + if(!$module) { + if('4e5e5d7364f443e28fbf0d3ae744a59a' == MODULE_NAME) { + header("Content-type:image/png"); + exit(base64_decode(App::logo())); + } + if(function_exists('__hack_module')) { + // hack 方式定义扩展模块 返回Action对象 + $module = __hack_module(); + if(!is_object($module)) { + // 不再继续执行 直接返回 + return ; + } + }else{ + // 是否定义Empty模块 + $module = A($group.'Empty'); + if(!$module){ + _404(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME); + } + } + } + // 获取当前操作名 支持动态路由 + $action = C('ACTION_NAME')?C('ACTION_NAME'):ACTION_NAME; + $action .= C('ACTION_SUFFIX'); + try{ + if(!preg_match('/^[A-Za-z](\w)*$/',$action)){ + // 非法操作 + throw new ReflectionException(); + } + //执行当前操作 + $method = new ReflectionMethod($module, $action); + if($method->isPublic()) { + $class = new ReflectionClass($module); + // 前置操作 + if($class->hasMethod('_before_'.$action)) { + $before = $class->getMethod('_before_'.$action); + if($before->isPublic()) { + $before->invoke($module); + } + } + // URL参数绑定检测 + if(C('URL_PARAMS_BIND') && $method->getNumberOfParameters()>0){ + switch($_SERVER['REQUEST_METHOD']) { + case 'POST': + $vars = array_merge($_GET,$_POST); + break; + case 'PUT': + parse_str(file_get_contents('php://input'), $vars); + break; + default: + $vars = $_GET; + } + $params = $method->getParameters(); + foreach ($params as $param){ + $name = $param->getName(); + if(isset($vars[$name])) { + $args[] = $vars[$name]; + }elseif($param->isDefaultValueAvailable()){ + $args[] = $param->getDefaultValue(); + }else{ + throw_exception(L('_PARAM_ERROR_').':'.$name); + } + } + $method->invokeArgs($module,$args); + }else{ + $method->invoke($module); + } + // 后置操作 + if($class->hasMethod('_after_'.$action)) { + $after = $class->getMethod('_after_'.$action); + if($after->isPublic()) { + $after->invoke($module); + } + } + }else{ + // 操作方法不是Public 抛出异常 + throw new ReflectionException(); + } + } catch (ReflectionException $e) { + // 方法调用发生异常后 引导到__call方法处理 + $method = new ReflectionMethod($module,'__call'); + $method->invokeArgs($module,array($action,'')); + } + return ; + } + + /** + * 运行应用实例 入口文件使用的快捷方法 + * @access public + * @return void + */ + static public function run() { + // 项目初始化标签 + tag('app_init'); + App::init(); + // 项目开始标签 + tag('app_begin'); + // Session初始化 + session(C('SESSION_OPTIONS')); + // 记录应用初始化时间 + G('initTime'); + App::exec(); + // 项目结束标签 + tag('app_end'); + return ; + } + + static public function logo(){ + return 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/9+69+8xuNtkHJAFCSIAkhMgjCCJQUi0GtEIVbP8Qq9LH2No6TmfaztjO2OnUdvqHFMfOVFTqIK0vUEEeqUBARCsEeYQkEPJoEvIiELLvvc9z+p27u2F3s5tsBB1OZiebu5dzf7/v/L7f952zMM8cWIwY+Mk2ulCp92Fnq3XvnzArr2NZnYNldDp0Gw+/OEQ4+obQn5D+4Ubb22+YOGsWi/Todh8AHglKEGkEsnHBQ162511GZFgW6ZCBM9/W4H3iNSQqIe09O196dLKX7d1O39OViP/wthtkND62if/wj/DbMpph8BY/m9xy8BoBmQk+mHqZQGNy4JYRwCoRbwa8l4JXw6M+orJxpU0U6ToKy/5bQsAiTeokGKkTx46RRxxEUgrwGgF4MWNNEJCGgYTvpgnY1IJWg5RzfqLgvcIgktX0i8dmMlFA8qCQ5L0Z/WObPLUxT1i4lWSYDISoEfBYGvM+LlMQQdkLHoWRRZ8zYQI62Thswe5WTORGwNXDcGjqeOA9AF7B8rhzsxMBEoJ8oJKaqPu4hblHMCMPwl9XeNWyb8xkB/DDGYKfMAE6aFL7xesZ389JlgG3XHEMI6UPDOP6JHHu67T2pwNPI69mCP4rEaBDUAJaKc/AOuXiwH07VCS3w5+UQMAuF/WqGI+yFIwVNBwemBD4r0wgQiKoFZa00sEYTwss32lA1tPwVxtc8jQ5/gWCwmGCyUD8vRT0sHBFW4GJDvZmrJFWRY1EkrGA6ZB8/10fOZSSj0E6F+BSP7xidiIzhBmKB09lEwHPkG+UQIyEN44EBiT5vrv2uJXyPQqSqO930fxvcvwbR/+JAkD9EfASgI9EHlp6YiHO4W+cAB20SnrFqxBbNljiXf1Pl1K2S0HCWfiog3YlAD5RGwwxK6oUjTweuVigLjyB0mX410mAFnMoVK1lvvUvgt8fUJH0JVyjuvcmg4dE5mUiFtD24AZ4qBVELxXKS+pMxN43kSdzNwudJ+bQbLlmnxvPOQoCugSap1GnSRoG8KOiKbH+rIA0lEeSAg3y6eeQ6XI2nrYnrPM89bUTgI0Pdqvl50vlNbtZxDUBcLBK0kPd5jPziyLdojJIN0pq5/mdzwL4UVvVInV5ncQEPNOUxa9d0TU+CW5l+FoI0GSDKHVVSOs+0KOsZoxwOzSZNFGv0mQ9avyLCh2Hpm+70Y0YJoJVgmQv822wnDC8Miq6VjJ5IFed0QD1YiAbT+nQE8v/RMZfmgmcCRHIIu7Bmcp39oM9fqEychcA747KxQ/AEyqQonl7hATtJmnhO2XYtgcia01aSbVMenAXrIomPcLgEBA4liGBzFZAT8zBYqW6brI67wg8sFVhxBhwLwBP2+tqBQqqK7VJKGh/BRrfTr6nWL7nYBaZdBJHqrX3kPEPap56xwE/GvjJTRMADeMCdcGpGXL1Xh4ZL8BDOlWkUpegfi0CeDzeA5YITzEnddv+IXL+UYCmqIvqC9UlUC/ki9FipwVjunL3yX7dOTLeXmVMAhbsGporPfyOBTm/BJ23gTVehsvXRnSewagUfpBXF3p5pygKS7OceqTjb7h2vjr/XKm0ZofKSI2Q/J102wHzatZkJPYQ5JoKsuK+EoHJakVzubzuLQDepCKllTZi9AG0DYg9ZLxhFaZsOu7bvlmVI5oPXJMQJcHxHClSln1apFTvAimeg48u0RWFeZW4lVcjbQWZuIQK1KozZfIDO6CSQmQQXdpBaiKZyEWThVK1uEc6v7V7uK0ysduExPZx4vysDR+4SelhBYm0R6LBuR4PXts8MYMcJPsINo4YZCDLj0sgB0/vLpPXvA2Tn42Cv5rsLulGubzW0sEd3d4W/mJt2Kck+DzDMijfPLOjyrDhXSh852B+OvflqAkoyXO1cYfujtc/i3jJSAwhgfFlp20laMLOku/bC7prgqW7lCn4auE5NhcXPd3M7x70+IceSgZvNljCd9k3fLjYsPElqLR14PXQZqD2ZNkkrAB79UeJUebFQmXpf8ZcAQt2XrMQdyNUVBqZoUzAFyp3V3xi/MubUA/mCT4Fhf038PC8XplhWnCmnK/ZzyC2BSTRSqKVOuY2kB8Jia0lvvRIVoP+vVWJbYarf6p655E2/nANBMCWkgD49DA0VAMyI1OLFMYCXiU9bmzi9/y5i/vsaTpHPHidTofzLbM65vMPva9HlovgXp0AvjtaqYMfDD0/4mAsYE92pxa+9k1QgCnRVObCpojpzsKTPvayPetTEgBdwnssjuc0kOBFX+q3HwRQxdrOLAqeYRjkMk/trTSu2Z9Lik7CfF0AvjtqAhS4NHobGXUnB5DQs8hG8p/wMX1r4+8xkmyvQ50JVq72TVeXbz3HvpWaQJi57hJYTw4kGbtS+C2TigQUtZUX+X27QQq2ePBZBru/0lxTm8fOOQ5yaZOZMAV+he4FqIMB+LQB0UgMSajANX29j+vbmly8ipRvHeSQoQOkM5iFXcPQCVwDMs5RBCQmaPOyvbNd6uwvQJ183BZQG3Zc+Eiv7vQOKu8YeDmMcJlt2ckyftVeMIGLBCmdMHl/tFILYwGPjXWO3zOfSq/+om+oa7Mlh2fpSsRGLp7RAW3FUVjNHgiMhyE6zBFjM2BdkdJGO7nP1kJXWAtBuBpPIAu7f+hhu7bFXIuC5xWrf0X2xreykOsUyKkF2gwadbrXDcXrfKxR43zGcSj4t/cCgr+a1iy6EjE5GYktUCl9fwfMeylyooGF48bN2IGLTw8x7StS7sj8TF9FmPGWQhm3rRR+o9lhvjJvSYAdfDUevI1M6bnX/OwWaDMOQ8RPgKRo0eulBTdT8AW2kl8e9L7UHghHwMfLiZPNoSpx0yugpQZaFqKWqxVSM3a2pN1SAhC2jf94I7ybBI7EL5A2Wvu5ht3xsoEt4+Ay/abXgCQAxyOeDsDlTCQzy75ohcGgv9Tra9uiymRUYTLrswOLlCdfAQf7HPDQQ4ErAH5EDXB9cMxWYpjtXApRncojS0sbV/cCgHTHwGNBJy+1PQE2x56FpaVR7wfQGZ37V+V+19EiHNvR6q1fRUjqvbjbMq1/qfHxbTrE10ePY2gPFk48D2CVMTf1AF4PXvyYR9dV6Wf7H413m3xTWQvYGhQ7mfYwA5mAX+18Vue05v/8jG/fZX/IW5MKPKtjSYlt0ellxh+/BOCPAwYaeVr0QofZFxJWVWC8znG70au6llVmktsF0bfHF6k8fvZ5esZJbwHwwnjg59tXz6sL/P0NUZDuSNu1mnJ8Vab17+cy005A9wtOpp3i0bZdpJLUil00semAwN45LgEViZYe3amNye0B6A9chviSlzXVsFtyN5/1H3gaNmMpn8Fz0GpYFp6Zw615H/LpUuRQQDMCL82n5DpBSawkvzIdN2ypiT8nSLth8Pk9jnjwdFzH3W4XW6KMBfwB569NdcGX93mC16tTflcArcYUc/mFuYbV+8zY0SAjAVoNErNgWjtwumJ3wbn/HlBFYdxHvSkJJEc+Ngal9opSwyo9YlITX2C/P/+gf8sxURSLR+mcZUmeqaS9wrh6vxW5zxFCOqFi90RbDWq/YwZmnu1+a6OvdpvRqkNxxe44lyl4OobEnpKA6Uox5EfH9xzPs/HRKrTPWdIQrK1VZDU7ETiD3Obpl+8wPPCRBbkbwNtpW9AbBe5L1SMlj3tdTxk/9W47JUmqS5HU+JzYymUKXjtWVmT9RenIhgXc+nroWLyxXJhmL112OdB8GCsk4f8oZJucnvmmtR85mBn10GZ0EKSCMUSAR3ukcXd5s7LvLD3me61WkuTCpJzYAyRurMB44EdEJzTfU271lUJC03YjXJXzYOGZwN4D8eB5jlfLrdWfzGRW7icMPfiSO6Oe7s20bmhdgLX4Z23B+s3JgQESzUDiMboSzDMHFpNMwccGePauhfwjzwnI2wu9zKGgEFg80jcZ7MHllk07s1H+5yojtUQTlH4nFdLKTGwDmPbIklOb1L1zO4T6N8NCuDLFLS/C63c0eNRimZ++s5BMBHxU11jHchI9oFVUxRh/eMDzHEzGYu0Lg8gJ7oS/tFCwoic44fyUtix0n/46vP4bf+//BRgAYwDDar4ncHIAAAAASUVORK5CYII='; + } +} diff --git a/ThinkPHP/Lib/Core/Behavior.class.php b/ThinkPHP/Lib/Core/Behavior.class.php new file mode 100644 index 0000000..86354e7 --- /dev/null +++ b/ThinkPHP/Lib/Core/Behavior.class.php @@ -0,0 +1,54 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP Behavior基础类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +abstract class Behavior { + + // 行为参数 和配置参数设置相同 + protected $options = array(); + + /** + * 架构函数 + * @access public + */ + public function __construct() { + if(!empty($this->options)) { + foreach ($this->options as $name=>$val){ + if(NULL !== C($name)) { // 参数已设置 则覆盖行为参数 + $this->options[$name] = C($name); + }else{ // 参数未设置 则传入默认值到配置 + C($name,$val); + } + } + array_change_key_case($this->options); + } + } + + // 获取行为参数 + public function __get($name){ + return $this->options[strtolower($name)]; + } + + /** + * 执行行为 run方法是Behavior唯一的接口 + * @access public + * @param mixed $params 行为参数 + * @return void + */ + abstract public function run(&$params); + +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Cache.class.php b/ThinkPHP/Lib/Core/Cache.class.php new file mode 100644 index 0000000..2fbda12 --- /dev/null +++ b/ThinkPHP/Lib/Core/Cache.class.php @@ -0,0 +1,127 @@ + +// +---------------------------------------------------------------------- + +/** + * 缓存管理类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Cache { + + /** + * 操作句柄 + * @var string + * @access protected + */ + protected $handler ; + + /** + * 缓存连接参数 + * @var integer + * @access protected + */ + protected $options = array(); + + /** + * 连接缓存 + * @access public + * @param string $type 缓存类型 + * @param array $options 配置数组 + * @return object + */ + public function connect($type='',$options=array()) { + if(empty($type)) $type = C('DATA_CACHE_TYPE'); + $type = strtolower(trim($type)); + $class = 'Cache'.ucwords($type); + if(class_exists($class)) + $cache = new $class($options); + else + throw_exception(L('_CACHE_TYPE_INVALID_').':'.$type); + return $cache; + } + + public function __get($name) { + return $this->get($name); + } + + public function __set($name,$value) { + return $this->set($name,$value); + } + + public function __unset($name) { + $this->rm($name); + } + public function setOptions($name,$value) { + $this->options[$name] = $value; + } + + public function getOptions($name) { + return $this->options[$name]; + } + + /** + * 取得缓存类实例 + * @static + * @access public + * @return mixed + */ + static function getInstance() { + $param = func_get_args(); + return get_instance_of(__CLASS__,'connect',$param); + } + + /** + * 队列缓存 + * @access protected + * @param string $key 队列名 + * @return mixed + */ + // + protected function queue($key) { + static $_handler = array( + 'file' => array('F','F'), + 'xcache'=> array('xcache_get','xcache_set'), + 'apc' => array('apc_fetch','apc_store'), + ); + $queue = isset($this->options['queue'])?$this->options['queue']:'file'; + $fun = isset($_handler[$queue])?$_handler[$queue]:$_handler['file']; + $queue_name=isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue'; + $value = $fun[0]($queue_name); + if(!$value) { + $value = array(); + } + // 进列 + if(false===array_search($key, $value)) array_push($value,$key); + if(count($value) > $this->options['length']) { + // 出列 + $key = array_shift($value); + // 删除缓存 + $this->rm($key); + if(APP_DEUBG){ + //调试模式下,记录出列次数 + N($queue_name.'_out_times',1,true); + } + } + return $fun[1]($queue_name,$value); + } + + public function __call($method,$args){ + //调用缓存类型自己的方法 + if(method_exists($this->handler, $method)){ + return call_user_func_array(array($this->handler,$method), $args); + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Db.class.php b/ThinkPHP/Lib/Core/Db.class.php new file mode 100644 index 0000000..2b8f260 --- /dev/null +++ b/ThinkPHP/Lib/Core/Db.class.php @@ -0,0 +1,922 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 数据库中间层实现类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Db { + // 数据库类型 + protected $dbType = null; + // 是否自动释放查询结果 + protected $autoFree = false; + // 当前操作所属的模型名 + protected $model = '_think_'; + // 是否使用永久连接 + protected $pconnect = false; + // 当前SQL指令 + protected $queryStr = ''; + protected $modelSql = array(); + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 数据库连接ID 支持多个连接 + protected $linkID = array(); + // 当前连接ID + protected $_linkID = null; + // 当前查询ID + protected $queryID = null; + // 是否已经连接数据库 + protected $connected = false; + // 数据库连接参数配置 + protected $config = ''; + // 数据库表达式 + protected $comparison = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN'); + // 查询表达式 + protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%'; + // 参数绑定 + protected $bind = array(); + + /** + * 取得数据库类实例 + * @static + * @access public + * @return mixed 返回数据库驱动类 + */ + public static function getInstance() { + $args = func_get_args(); + return get_instance_of(__CLASS__,'factory',$args); + } + + /** + * 加载数据库 支持配置文件或者 DSN + * @access public + * @param mixed $db_config 数据库配置信息 + * @return string + */ + public function factory($db_config='') { + // 读取数据库配置 + $db_config = $this->parseConfig($db_config); + if(empty($db_config['dbms'])) + throw_exception(L('_NO_DB_CONFIG_')); + // 数据库类型 + $this->dbType = ucwords(strtolower($db_config['dbms'])); + $class = 'Db'. $this->dbType; + // 检查驱动类 + if(class_exists($class)) { + $db = new $class($db_config); + // 获取当前的数据库类型 + if( 'pdo' != strtolower($db_config['dbms']) ) + $db->dbType = strtoupper($this->dbType); + else + $db->dbType = $this->_getDsnType($db_config['dsn']); + }else { + // 类没有定义 + throw_exception(L('_NO_DB_DRIVER_').': ' . $class); + } + return $db; + } + + /** + * 根据DSN获取数据库类型 返回大写 + * @access protected + * @param string $dsn dsn字符串 + * @return string + */ + protected function _getDsnType($dsn) { + $match = explode(':',$dsn); + $dbType = strtoupper(trim($match[0])); + return $dbType; + } + + /** + * 分析数据库配置信息,支持数组和DSN + * @access private + * @param mixed $db_config 数据库配置信息 + * @return string + */ + private function parseConfig($db_config='') { + if ( !empty($db_config) && is_string($db_config)) { + // 如果DSN字符串则进行解析 + $db_config = $this->parseDSN($db_config); + }elseif(is_array($db_config)) { // 数组配置 + $db_config = array_change_key_case($db_config); + $db_config = array( + 'dbms' => $db_config['db_type'], + 'username' => $db_config['db_user'], + 'password' => $db_config['db_pwd'], + 'hostname' => $db_config['db_host'], + 'hostport' => $db_config['db_port'], + 'database' => $db_config['db_name'], + 'dsn' => $db_config['db_dsn'], + 'params' => $db_config['db_params'], + ); + }elseif(empty($db_config)) { + // 如果配置为空,读取配置文件设置 + if( C('DB_DSN') && 'pdo' != strtolower(C('DB_TYPE')) ) { // 如果设置了DB_DSN 则优先 + $db_config = $this->parseDSN(C('DB_DSN')); + }else{ + $db_config = array ( + 'dbms' => C('DB_TYPE'), + 'username' => C('DB_USER'), + 'password' => C('DB_PWD'), + 'hostname' => C('DB_HOST'), + 'hostport' => C('DB_PORT'), + 'database' => C('DB_NAME'), + 'dsn' => C('DB_DSN'), + 'params' => C('DB_PARAMS'), + ); + } + } + return $db_config; + } + + /** + * 初始化数据库连接 + * @access protected + * @param boolean $master 主服务器 + * @return void + */ + protected function initConnect($master=true) { + if(1 == C('DB_DEPLOY_TYPE')) + // 采用分布式数据库 + $this->_linkID = $this->multiConnect($master); + else + // 默认单数据库 + if ( !$this->connected ) $this->_linkID = $this->connect(); + } + + /** + * 连接分布式服务器 + * @access protected + * @param boolean $master 主服务器 + * @return void + */ + protected function multiConnect($master=false) { + static $_config = array(); + if(empty($_config)) { + // 缓存分布式数据库配置解析 + foreach ($this->config as $key=>$val){ + $_config[$key] = explode(',',$val); + } + } + // 数据库读写是否分离 + if(C('DB_RW_SEPARATE')){ + // 主从式采用读写分离 + if($master) + // 主服务器写入 + $r = floor(mt_rand(0,C('DB_MASTER_NUM')-1)); + else{ + if(is_numeric(C('DB_SLAVE_NO'))) {// 指定服务器读 + $r = C('DB_SLAVE_NO'); + }else{ + // 读操作连接从服务器 + $r = floor(mt_rand(C('DB_MASTER_NUM'),count($_config['hostname'])-1)); // 每次随机连接的数据库 + } + } + }else{ + // 读写操作不区分服务器 + $r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库 + } + $db_config = array( + 'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0], + 'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0], + 'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0], + 'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0], + 'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0], + 'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0], + 'params' => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0], + ); + return $this->connect($db_config,$r); + } + + /** + * DSN解析 + * 格式: mysql://username:passwd@localhost:3306/DbName + * @static + * @access public + * @param string $dsnStr + * @return array + */ + public function parseDSN($dsnStr) { + if( empty($dsnStr) ){return false;} + $info = parse_url($dsnStr); + if($info['scheme']){ + $dsn = array( + 'dbms' => $info['scheme'], + 'username' => isset($info['user']) ? $info['user'] : '', + 'password' => isset($info['pass']) ? $info['pass'] : '', + 'hostname' => isset($info['host']) ? $info['host'] : '', + 'hostport' => isset($info['port']) ? $info['port'] : '', + 'database' => isset($info['path']) ? substr($info['path'],1) : '' + ); + }else { + preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); + $dsn = array ( + 'dbms' => $matches[1], + 'username' => $matches[2], + 'password' => $matches[3], + 'hostname' => $matches[4], + 'hostport' => $matches[5], + 'database' => $matches[6] + ); + } + $dsn['dsn'] = ''; // 兼容配置信息数组 + return $dsn; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + $this->modelSql[$this->model] = $this->queryStr; + $this->model = '_think_'; + // 记录操作结束时间 + if (C('DB_SQL_LOG')) { + G('queryEndTime'); + trace($this->queryStr.' [ RunTime:'.G('queryStartTime','queryEndTime',6).'s ]','','SQL'); + } + } + + /** + * 设置锁机制 + * @access protected + * @return string + */ + protected function parseLock($lock=false) { + if(!$lock) return ''; + if('ORACLE' == $this->dbType) { + return ' FOR UPDATE NOWAIT '; + } + return ' FOR UPDATE '; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + foreach ($data as $key=>$val){ + if(is_array($val) && 'exp' == $val[0]){ + $set[] = $this->parseKey($key).'='.$val[1]; + }elseif(is_scalar($val) || is_null(($val))) { // 过滤非标量数据 + if(C('DB_BIND_PARAM') && 0 !== strpos($val,':')){ + $name = md5($key); + $set[] = $this->parseKey($key).'=:'.$name; + $this->bindParam($name,$val); + }else{ + $set[] = $this->parseKey($key).'='.$this->parseValue($val); + } + } + } + return ' SET '.implode(',',$set); + } + + /** + * 参数绑定 + * @access protected + * @param string $name 绑定参数名 + * @param mixed $value 绑定值 + * @return void + */ + protected function bindParam($name,$value){ + $this->bind[':'.$name] = $value; + } + + /** + * 参数绑定分析 + * @access protected + * @param array $bind + * @return array + */ + protected function parseBind($bind){ + $bind = array_merge($this->bind,$bind); + $this->bind = array(); + return $bind; + } + + /** + * 字段名分析 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + return $key; + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = '\''.$this->escapeString($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escapeString($value[1]); + }elseif(is_array($value)) { + $value = array_map(array($this, 'parseValue'),$value); + }elseif(is_bool($value)){ + $value = $value ? '1' : '0'; + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return string + */ + protected function parseField($fields) { + if(is_string($fields) && strpos($fields,',')) { + $fields = explode(',',$fields); + } + if(is_array($fields)) { + // 完善数组方式传字段名的支持 + // 支持 'field1'=>'field2' 这样的字段别名定义 + $array = array(); + foreach ($fields as $key=>$field){ + if(!is_numeric($key)) + $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); + else + $array[] = $this->parseKey($field); + } + $fieldsStr = implode(',', $array); + }elseif(is_string($fields) && !empty($fields)) { + $fieldsStr = $this->parseKey($fields); + }else{ + $fieldsStr = '*'; + } + //TODO 如果是查询全部字段,并且是join的方式,那么就把要查的表加个别名,以免字段被覆盖 + return $fieldsStr; + } + + /** + * table分析 + * @access protected + * @param mixed $table + * @return string + */ + protected function parseTable($tables) { + if(is_array($tables)) {// 支持别名定义 + $array = array(); + foreach ($tables as $table=>$alias){ + if(!is_numeric($table)) + $array[] = $this->parseKey($table).' '.$this->parseKey($alias); + else + $array[] = $this->parseKey($table); + } + $tables = $array; + }elseif(is_string($tables)){ + $tables = explode(',',$tables); + array_walk($tables, array(&$this, 'parseKey')); + } + return implode(',',$tables); + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return string + */ + protected function parseWhere($where) { + $whereStr = ''; + if(is_string($where)) { + // 直接使用字符串条件 + $whereStr = $where; + }else{ // 使用数组表达式 + $operate = isset($where['_logic'])?strtoupper($where['_logic']):''; + if(in_array($operate,array('AND','OR','XOR'))){ + // 定义逻辑运算规则 例如 OR XOR AND NOT + $operate = ' '.$operate.' '; + unset($where['_logic']); + }else{ + // 默认进行 AND 运算 + $operate = ' AND '; + } + foreach ($where as $key=>$val){ + $whereStr .= '( '; + if(is_numeric($key)){ + $key = '_complex'; + } + if(0===strpos($key,'_')) { + // 解析特殊条件表达式 + $whereStr .= $this->parseThinkWhere($key,$val); + }else{ + // 查询字段的安全过滤 + if(!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/',trim($key))){ + throw_exception(L('_EXPRESS_ERROR_').':'.$key); + } + // 多条件支持 + $multi = is_array($val) && isset($val['_multi']); + $key = trim($key); + if(strpos($key,'|')) { // 支持 name|title|nickname 方式定义查询字段 + $array = explode('|',$key); + $str = array(); + foreach ($array as $m=>$k){ + $v = $multi?$val[$m]:$val; + $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; + } + $whereStr .= implode(' OR ',$str); + }elseif(strpos($key,'&')){ + $array = explode('&',$key); + $str = array(); + foreach ($array as $m=>$k){ + $v = $multi?$val[$m]:$val; + $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; + } + $whereStr .= implode(' AND ',$str); + }else{ + $whereStr .= $this->parseWhereItem($this->parseKey($key),$val); + } + } + $whereStr .= ' )'.$operate; + } + $whereStr = substr($whereStr,0,-strlen($operate)); + } + return empty($whereStr)?'':' WHERE '.$whereStr; + } + + // where子单元分析 + protected function parseWhereItem($key,$val) { + $whereStr = ''; + if(is_array($val)) { + if(is_string($val[0])) { + if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // 比较运算 + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + }elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// 模糊查找 + if(is_array($val[1])) { + $likeLogic = isset($val[2])?strtoupper($val[2]):'OR'; + if(in_array($likeLogic,array('AND','OR','XOR'))){ + $likeStr = $this->comparison[strtolower($val[0])]; + $like = array(); + foreach ($val[1] as $item){ + $like[] = $key.' '.$likeStr.' '.$this->parseValue($item); + } + $whereStr .= '('.implode(' '.$likeLogic.' ',$like).')'; + } + }else{ + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + } + }elseif('exp'==strtolower($val[0])){ // 使用表达式 + $whereStr .= ' ('.$key.' '.$val[1].') '; + }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 + if(isset($val[2]) && 'exp'==$val[2]) { + $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1]; + }else{ + if(is_string($val[1])) { + $val[1] = explode(',',$val[1]); + } + $zone = implode(',',$this->parseValue($val[1])); + $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; + } + }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $whereStr .= ' ('.$key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]).' )'; + }else{ + throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]); + } + }else { + $count = count($val); + $rule = isset($val[$count-1])?strtoupper($val[$count-1]):''; + if(in_array($rule,array('AND','OR','XOR'))) { + $count = $count -1; + }else{ + $rule = 'AND'; + } + for($i=0;$i<$count;$i++) { + $data = is_array($val[$i])?$val[$i][1]:$val[$i]; + if('exp'==strtolower($val[$i][0])) { + $whereStr .= '('.$key.' '.$data.') '.$rule.' '; + }else{ + $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; + $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' '; + } + } + $whereStr = substr($whereStr,0,-4); + } + }else { + //对字符串类型字段采用模糊匹配 + if(C('DB_LIKE_FIELDS') && preg_match('/('.C('DB_LIKE_FIELDS').')/i',$key)) { + $val = '%'.$val.'%'; + $whereStr .= $key.' LIKE '.$this->parseValue($val); + }else { + $whereStr .= $key.' = '.$this->parseValue($val); + } + } + return $whereStr; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $whereStr = ''; + switch($key) { + case '_string': + // 字符串模式查询条件 + $whereStr = $val; + break; + case '_complex': + // 复合查询条件 + $whereStr = is_string($val)? $val : substr($this->parseWhere($val),6); + break; + case '_query': + // 字符串模式查询条件 + parse_str($val,$where); + if(isset($where['_logic'])) { + $op = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + $op = ' AND '; + } + $array = array(); + foreach ($where as $field=>$data) + $array[] = $this->parseKey($field).' = '.$this->parseValue($data); + $whereStr = implode($op,$array); + break; + } + return $whereStr; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + return !empty($limit)? ' LIMIT '.$limit.' ':''; + } + + /** + * join分析 + * @access protected + * @param mixed $join + * @return string + */ + protected function parseJoin($join) { + $joinStr = ''; + if(!empty($join)) { + if(is_array($join)) { + foreach ($join as $key=>$_join){ + if(false !== stripos($_join,'JOIN')) + $joinStr .= ' '.$_join; + else + $joinStr .= ' LEFT JOIN ' .$_join; + } + }else{ + $joinStr .= ' LEFT JOIN ' .$join; + } + } + //将__TABLE_NAME__这样的字符串替换成正规的表名,并且带上前缀和后缀 + $joinStr = preg_replace("/__([A-Z_-]+)__/esU",C("DB_PREFIX").".strtolower('$1')",$joinStr); + return $joinStr; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + if(is_array($order)) { + $array = array(); + foreach ($order as $key=>$val){ + if(is_numeric($key)) { + $array[] = $this->parseKey($val); + }else{ + $array[] = $this->parseKey($key).' '.$val; + } + } + $order = implode(',',$array); + } + return !empty($order)? ' ORDER BY '.$order:''; + } + + /** + * group分析 + * @access protected + * @param mixed $group + * @return string + */ + protected function parseGroup($group) { + return !empty($group)? ' GROUP BY '.$group:''; + } + + /** + * having分析 + * @access protected + * @param string $having + * @return string + */ + protected function parseHaving($having) { + return !empty($having)? ' HAVING '.$having:''; + } + + /** + * comment分析 + * @access protected + * @param string $comment + * @return string + */ + protected function parseComment($comment) { + return !empty($comment)? ' /* '.$comment.' */':''; + } + + /** + * distinct分析 + * @access protected + * @param mixed $distinct + * @return string + */ + protected function parseDistinct($distinct) { + return !empty($distinct)? ' DISTINCT ' :''; + } + + /** + * union分析 + * @access protected + * @param mixed $union + * @return string + */ + protected function parseUnion($union) { + if(empty($union)) return ''; + if(isset($union['_all'])) { + $str = 'UNION ALL '; + unset($union['_all']); + }else{ + $str = 'UNION '; + } + foreach ($union as $u){ + $sql[] = $str.(is_array($u)?$this->buildSelectSql($u):$u); + } + return implode(' ',$sql); + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insert($data,$options=array(),$replace=false) { + $values = $fields = array(); + $this->model = $options['model']; + foreach ($data as $key=>$val){ + if(is_array($val) && 'exp' == $val[0]){ + $fields[] = $this->parseKey($key); + $values[] = $val[1]; + }elseif(is_scalar($val) || is_null(($val))) { // 过滤非标量数据 + $fields[] = $this->parseKey($key); + if(C('DB_BIND_PARAM') && 0 !== strpos($val,':')){ + $name = md5($key); + $values[] = ':'.$name; + $this->bindParam($name,$val); + }else{ + $values[] = $this->parseValue($val); + } + } + } + $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + $sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 通过Select方式插入记录 + * @access public + * @param string $fields 要插入的数据表字段名 + * @param string $table 要插入的数据表名 + * @param array $option 查询数据参数 + * @return false | integer + */ + public function selectInsert($fields,$table,$options=array()) { + $this->model = $options['model']; + if(is_string($fields)) $fields = explode(',',$fields); + array_walk($fields, array($this, 'parseKey')); + $sql = 'INSERT INTO '.$this->parseTable($table).' ('.implode(',', $fields).') '; + $sql .= $this->buildSelectSql($options); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $this->model = $options['model']; + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseOrder(!empty($options['order'])?$options['order']:'') + .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $this->model = $options['model']; + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseOrder(!empty($options['order'])?$options['order']:'') + .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return mixed + */ + public function select($options=array()) { + $this->model = $options['model']; + $sql = $this->buildSelectSql($options); + $cache = isset($options['cache'])?$options['cache']:false; + if($cache) { // 查询缓存检测 + $key = is_string($cache['key'])?$cache['key']:md5($sql); + $value = S($key,'',$cache); + if(false !== $value) { + return $value; + } + } + $result = $this->query($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + if($cache && false !== $result ) { // 查询缓存写入 + S($key,$result,$cache); + } + return $result; + } + + /** + * 生成查询SQL + * @access public + * @param array $options 表达式 + * @return string + */ + public function buildSelectSql($options=array()) { + if(isset($options['page'])) { + // 根据页数计算limit + if(strpos($options['page'],',')) { + list($page,$listRows) = explode(',',$options['page']); + }else{ + $page = $options['page']; + } + $page = $page?$page:1; + $listRows= isset($listRows)?$listRows:(is_numeric($options['limit'])?$options['limit']:20); + $offset = $listRows*((int)$page-1); + $options['limit'] = $offset.','.$listRows; + } + if(C('DB_SQL_BUILD_CACHE')) { // SQL创建缓存 + $key = md5(serialize($options)); + $value = S($key); + if(false !== $value) { + return $value; + } + } + $sql = $this->parseSql($this->selectSql,$options); + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + if(isset($key)) { // 写入SQL创建缓存 + S($key,$sql,array('expire'=>0,'length'=>C('DB_SQL_BUILD_LENGTH'),'queue'=>C('DB_SQL_BUILD_QUEUE'))); + } + return $sql; + } + + /** + * 替换SQL语句中表达式 + * @access public + * @param array $options 表达式 + * @return string + */ + public function parseSql($sql,$options=array()){ + $sql = str_replace( + array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%COMMENT%'), + array( + $this->parseTable($options['table']), + $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), + $this->parseField(!empty($options['field'])?$options['field']:'*'), + $this->parseJoin(!empty($options['join'])?$options['join']:''), + $this->parseWhere(!empty($options['where'])?$options['where']:''), + $this->parseGroup(!empty($options['group'])?$options['group']:''), + $this->parseHaving(!empty($options['having'])?$options['having']:''), + $this->parseOrder(!empty($options['order'])?$options['order']:''), + $this->parseLimit(!empty($options['limit'])?$options['limit']:''), + $this->parseUnion(!empty($options['union'])?$options['union']:''), + $this->parseComment(!empty($options['comment'])?$options['comment']:'') + ),$sql); + return $sql; + } + + /** + * 获取最近一次查询的sql语句 + * @param string $model 模型名 + * @access public + * @return string + */ + public function getLastSql($model='') { + return $model?$this->modelSql[$model]:$this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->lastInsID; + } + + /** + * 获取最近的错误信息 + * @access public + * @return string + */ + public function getError() { + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escapeString($str) { + return addslashes($str); + } + + /** + * 设置当前操作模型 + * @access public + * @param string $model 模型名 + * @return void + */ + public function setModel($model){ + $this->model = $model; + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 释放查询 + if ($this->queryID){ + $this->free(); + } + // 关闭连接 + $this->close(); + } + + // 关闭数据库 由驱动类定义 + public function close(){} +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Dispatcher.class.php b/ThinkPHP/Lib/Core/Dispatcher.class.php new file mode 100644 index 0000000..9da5df0 --- /dev/null +++ b/ThinkPHP/Lib/Core/Dispatcher.class.php @@ -0,0 +1,271 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP内置的Dispatcher类 + * 完成URL解析、路由和调度 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Dispatcher { + + /** + * URL映射到控制器 + * @access public + * @return void + */ + static public function dispatch() { + $urlMode = C('URL_MODEL'); + if(isset($_GET[C('VAR_PATHINFO')])) { // 判断URL里面是否有兼容模式参数 + $_SERVER['PATH_INFO'] = $_GET[C('VAR_PATHINFO')]; + unset($_GET[C('VAR_PATHINFO')]); + } + if($urlMode == URL_COMPAT ){ + // 兼容模式判断 + define('PHP_FILE',_PHP_FILE_.'?'.C('VAR_PATHINFO').'='); + }elseif($urlMode == URL_REWRITE ) { + //当前项目地址 + $url = dirname(_PHP_FILE_); + if($url == '/' || $url == '\\') + $url = ''; + define('PHP_FILE',$url); + }else { + //当前项目地址 + define('PHP_FILE',_PHP_FILE_); + } + + // 开启子域名部署 + if(C('APP_SUB_DOMAIN_DEPLOY')) { + $rules = C('APP_SUB_DOMAIN_RULES'); + if(isset($rules[$_SERVER['HTTP_HOST']])) { // 完整域名或者IP配置 + $rule = $rules[$_SERVER['HTTP_HOST']]; + }else{ + $subDomain = strtolower(substr($_SERVER['HTTP_HOST'],0,strpos($_SERVER['HTTP_HOST'],'.'))); + define('SUB_DOMAIN',$subDomain); // 二级域名定义 + if($subDomain && isset($rules[$subDomain])) { + $rule = $rules[$subDomain]; + }elseif(isset($rules['*'])){ // 泛域名支持 + if('www' != $subDomain && !in_array($subDomain,C('APP_SUB_DOMAIN_DENY'))) { + $rule = $rules['*']; + } + } + } + + if(!empty($rule)) { + // 子域名部署规则 '子域名'=>array('分组名/[模块名]','var1=a&var2=b'); + $array = explode('/',$rule[0]); + $module = array_pop($array); + if(!empty($module)) { + $_GET[C('VAR_MODULE')] = $module; + $domainModule = true; + } + if(!empty($array)) { + $_GET[C('VAR_GROUP')] = array_pop($array); + $domainGroup = true; + } + if(isset($rule[1])) { // 传入参数 + parse_str($rule[1],$parms); + $_GET = array_merge($_GET,$parms); + } + } + } + // 分析PATHINFO信息 + if(!isset($_SERVER['PATH_INFO'])) { + $types = explode(',',C('URL_PATHINFO_FETCH')); + foreach ($types as $type){ + if(0===strpos($type,':')) {// 支持函数判断 + $_SERVER['PATH_INFO'] = call_user_func(substr($type,1)); + break; + }elseif(!empty($_SERVER[$type])) { + $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))? + substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type]; + break; + } + } + } + $depr = C('URL_PATHINFO_DEPR'); + if(!empty($_SERVER['PATH_INFO'])) { + tag('path_info'); + $part = pathinfo($_SERVER['PATH_INFO']); + define('__EXT__', isset($part['extension'])?strtolower($part['extension']):''); + if(__EXT__){ + if(C('URL_DENY_SUFFIX') && preg_match('/\.('.trim(C('URL_DENY_SUFFIX'),'.').')$/i', $_SERVER['PATH_INFO'])){ + send_http_status(404); + exit; + } + if(C('URL_HTML_SUFFIX')) { + $_SERVER['PATH_INFO'] = preg_replace('/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i', '', $_SERVER['PATH_INFO']); + }else{ + $_SERVER['PATH_INFO'] = preg_replace('/.'.__EXT__.'$/i','',$_SERVER['PATH_INFO']); + } + } + + if(!self::routerCheck()){ // 检测路由规则 如果没有则按默认规则调度URL + $paths = explode($depr,trim($_SERVER['PATH_INFO'],'/')); + if(C('VAR_URL_PARAMS')) { + // 直接通过$_GET['_URL_'][1] $_GET['_URL_'][2] 获取URL参数 方便不用路由时参数获取 + $_GET[C('VAR_URL_PARAMS')] = $paths; + } + $var = array(); + if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){ + $var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : ''; + if(C('APP_GROUP_DENY') && in_array(strtolower($var[C('VAR_GROUP')]),explode(',',strtolower(C('APP_GROUP_DENY'))))) { + // 禁止直接访问分组 + exit; + } + } + if(!isset($_GET[C('VAR_MODULE')])) {// 还没有定义模块名称 + $var[C('VAR_MODULE')] = array_shift($paths); + } + $var[C('VAR_ACTION')] = array_shift($paths); + // 解析剩余的URL参数 + preg_replace('@(\w+)\/([^\/]+)@e', '$var[\'\\1\']=strip_tags(\'\\2\');', implode('/',$paths)); + $_GET = array_merge($var,$_GET); + } + define('__INFO__',$_SERVER['PATH_INFO']); + }else{ + define('__INFO__',''); + } + + // URL常量 + define('__SELF__',strip_tags($_SERVER['REQUEST_URI'])); + // 当前项目地址 + define('__APP__',strip_tags(PHP_FILE)); + + // 获取分组 模块和操作名称 + if (C('APP_GROUP_LIST')) { + define('GROUP_NAME', self::getGroup(C('VAR_GROUP'))); + // 分组URL地址 + define('__GROUP__',(!empty($domainGroup) || strtolower(GROUP_NAME) == strtolower(C('DEFAULT_GROUP')) )?__APP__ : __APP__.'/'.(C('URL_CASE_INSENSITIVE') ? strtolower(GROUP_NAME) : GROUP_NAME)); + } + + // 定义项目基础加载路径 + define('BASE_LIB_PATH', (defined('GROUP_NAME') && C('APP_GROUP_MODE')==1) ? APP_PATH.C('APP_GROUP_PATH').'/'.GROUP_NAME.'/' : LIB_PATH); + if(defined('GROUP_NAME')) { + C('CACHE_PATH',CACHE_PATH.GROUP_NAME.'/'); + if(1 == C('APP_GROUP_MODE')){ // 独立分组模式 + $config_path = BASE_LIB_PATH.'Conf/'; + $common_path = BASE_LIB_PATH.'Common/'; + }else{ // 普通分组模式 + $config_path = CONF_PATH.GROUP_NAME.'/'; + $common_path = COMMON_PATH.GROUP_NAME.'/'; + } + // 加载分组配置文件 + if(is_file($config_path.'config.php')) + C(include $config_path.'config.php'); + // 加载分组别名定义 + if(is_file($config_path.'alias.php')) + alias_import(include $config_path.'alias.php'); + // 加载分组tags文件定义 + if(is_file($config_path.'tags.php')) + C('tags', include $config_path.'tags.php'); + // 加载分组函数文件 + if(is_file($common_path.'function.php')) + include $common_path.'function.php'; + }else{ + C('CACHE_PATH',CACHE_PATH); + } + define('MODULE_NAME',self::getModule(C('VAR_MODULE'))); + define('ACTION_NAME',self::getAction(C('VAR_ACTION'))); + + // 当前模块和分组地址 + $moduleName = defined('MODULE_ALIAS')?MODULE_ALIAS:MODULE_NAME; + if(defined('GROUP_NAME')) { + define('__URL__',!empty($domainModule)?__GROUP__.$depr : __GROUP__.$depr.( C('URL_CASE_INSENSITIVE') ? strtolower($moduleName) : $moduleName ) ); + }else{ + define('__URL__',!empty($domainModule)?__APP__.'/' : __APP__.'/'.( C('URL_CASE_INSENSITIVE') ? strtolower($moduleName) : $moduleName) ); + } + // 当前操作地址 + define('__ACTION__',__URL__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME)); + //保证$_REQUEST正常取值 + $_REQUEST = array_merge($_POST,$_GET); + } + + /** + * 路由检测 + * @access public + * @return void + */ + static public function routerCheck() { + $return = false; + // 路由检测标签 + tag('route_check',$return); + return $return; + } + + /** + * 获得实际的模块名称 + * @access private + * @return string + */ + static private function getModule($var) { + $module = (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_MODULE')); + unset($_GET[$var]); + if($maps = C('URL_MODULE_MAP')) { + if(isset($maps[strtolower($module)])) { + // 记录当前别名 + define('MODULE_ALIAS',strtolower($module)); + // 获取实际的模块名 + return $maps[MODULE_ALIAS]; + }elseif(array_search(strtolower($module),$maps)){ + // 禁止访问原始模块 + return ''; + } + } + if(C('URL_CASE_INSENSITIVE')) { + // URL地址不区分大小写 + // 智能识别方式 index.php/user_type/index/ 识别到 UserTypeAction 模块 + $module = ucfirst(parse_name($module,1)); + } + return strip_tags($module); + } + + /** + * 获得实际的操作名称 + * @access private + * @return string + */ + static private function getAction($var) { + $action = !empty($_POST[$var]) ? + $_POST[$var] : + (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION')); + unset($_POST[$var],$_GET[$var]); + if($maps = C('URL_ACTION_MAP')) { + if(isset($maps[strtolower(MODULE_NAME)])) { + $maps = $maps[strtolower(MODULE_NAME)]; + if(isset($maps[strtolower($action)])) { + // 记录当前别名 + define('ACTION_ALIAS',strtolower($action)); + // 获取实际的操作名 + return $maps[ACTION_ALIAS]; + }elseif(array_search(strtolower($action),$maps)){ + // 禁止访问原始操作 + return ''; + } + } + } + return strip_tags(C('URL_CASE_INSENSITIVE')?strtolower($action):$action); + } + + /** + * 获得实际的分组名称 + * @access private + * @return string + */ + static private function getGroup($var) { + $group = (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_GROUP')); + unset($_GET[$var]); + return strip_tags(C('URL_CASE_INSENSITIVE') ?ucfirst(strtolower($group)):$group); + } + +} diff --git a/ThinkPHP/Lib/Core/Log.class.php b/ThinkPHP/Lib/Core/Log.class.php new file mode 100644 index 0000000..bf85d60 --- /dev/null +++ b/ThinkPHP/Lib/Core/Log.class.php @@ -0,0 +1,115 @@ + +// +---------------------------------------------------------------------- + +/** + * 日志处理类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Log { + + // 日志级别 从上到下,由低到高 + const EMERG = 'EMERG'; // 严重错误: 导致系统崩溃无法使用 + const ALERT = 'ALERT'; // 警戒性错误: 必须被立即修改的错误 + const CRIT = 'CRIT'; // 临界值错误: 超过临界值的错误,例如一天24小时,而输入的是25小时这样 + const ERR = 'ERR'; // 一般错误: 一般性错误 + const WARN = 'WARN'; // 警告性错误: 需要发出警告的错误 + const NOTICE = 'NOTIC'; // 通知: 程序可以运行但是还不够完美的错误 + const INFO = 'INFO'; // 信息: 程序输出信息 + const DEBUG = 'DEBUG'; // 调试: 调试信息 + const SQL = 'SQL'; // SQL:SQL语句 注意只在调试模式开启时有效 + + // 日志记录方式 + const SYSTEM = 0; + const MAIL = 1; + const FILE = 3; + const SAPI = 4; + + // 日志信息 + static $log = array(); + + // 日期格式 + static $format = '[ c ]'; + + /** + * 记录日志 并且会过滤未经设置的级别 + * @static + * @access public + * @param string $message 日志信息 + * @param string $level 日志级别 + * @param boolean $record 是否强制记录 + * @return void + */ + static function record($message,$level=self::ERR,$record=false) { + if($record || false !== strpos(C('LOG_LEVEL'),$level)) { + self::$log[] = "{$level}: {$message}\r\n"; + } + } + + /** + * 日志保存 + * @static + * @access public + * @param integer $type 日志记录方式 + * @param string $destination 写入目标 + * @param string $extra 额外参数 + * @return void + */ + static function save($type='',$destination='',$extra='') { + if(empty(self::$log)) return ; + $type = $type?$type:C('LOG_TYPE'); + if(self::FILE == $type) { // 文件方式记录日志信息 + if(empty($destination)) + $destination = C('LOG_PATH').date('y_m_d').'.log'; + //检测日志文件大小,超过配置大小则备份日志文件重新生成 + if(is_file($destination) && floor(C('LOG_FILE_SIZE')) <= filesize($destination) ) + rename($destination,dirname($destination).'/'.time().'-'.basename($destination)); + }else{ + $destination = $destination?$destination:C('LOG_DEST'); + $extra = $extra?$extra:C('LOG_EXTRA'); + } + $now = date(self::$format); + error_log($now.' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n".implode('',self::$log)."\r\n", $type,$destination ,$extra); + // 保存后清空日志缓存 + self::$log = array(); + //clearstatcache(); + } + + /** + * 日志直接写入 + * @static + * @access public + * @param string $message 日志信息 + * @param string $level 日志级别 + * @param integer $type 日志记录方式 + * @param string $destination 写入目标 + * @param string $extra 额外参数 + * @return void + */ + static function write($message,$level=self::ERR,$type='',$destination='',$extra='') { + $now = date(self::$format); + $type = $type?$type:C('LOG_TYPE'); + if(self::FILE == $type) { // 文件方式记录日志 + if(empty($destination)) + $destination = C('LOG_PATH').date('y_m_d').'.log'; + //检测日志文件大小,超过配置大小则备份日志文件重新生成 + if(is_file($destination) && floor(C('LOG_FILE_SIZE')) <= filesize($destination) ) + rename($destination,dirname($destination).'/'.time().'-'.basename($destination)); + }else{ + $destination = $destination?$destination:C('LOG_DEST'); + $extra = $extra?$extra:C('LOG_EXTRA'); + } + error_log("{$now} {$level}: {$message}\r\n", $type,$destination,$extra ); + //clearstatcache(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Model.class.php b/ThinkPHP/Lib/Core/Model.class.php new file mode 100644 index 0000000..fc91708 --- /dev/null +++ b/ThinkPHP/Lib/Core/Model.class.php @@ -0,0 +1,1553 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP Model模型类 + * 实现了ORM和ActiveRecords模式 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Model { + // 操作状态 + const MODEL_INSERT = 1; // 插入模型数据 + const MODEL_UPDATE = 2; // 更新模型数据 + const MODEL_BOTH = 3; // 包含上面两种方式 + const MUST_VALIDATE = 1;// 必须验证 + const EXISTS_VALIDATE = 0;// 表单存在字段则验证 + const VALUE_VALIDATE = 2;// 表单值不为空则验证 + // 当前使用的扩展模型 + private $_extModel = null; + // 当前数据库操作对象 + protected $db = null; + // 主键名称 + protected $pk = 'id'; + // 数据表前缀 + protected $tablePrefix = ''; + // 模型名称 + protected $name = ''; + // 数据库名称 + protected $dbName = ''; + //数据库配置 + protected $connection = ''; + // 数据表名(不包含表前缀) + protected $tableName = ''; + // 实际数据表名(包含表前缀) + protected $trueTableName = ''; + // 最近错误信息 + protected $error = ''; + // 字段信息 + protected $fields = array(); + // 数据信息 + protected $data = array(); + // 查询表达式参数 + protected $options = array(); + protected $_validate = array(); // 自动验证定义 + protected $_auto = array(); // 自动完成定义 + protected $_map = array(); // 字段映射定义 + protected $_scope = array(); // 命名范围定义 + // 是否自动检测数据表字段信息 + protected $autoCheckFields = true; + // 是否批处理验证 + protected $patchValidate = false; + // 链操作方法列表 + protected $methods = array('table','order','alias','having','group','lock','distinct','auto','filter','validate','result','bind','token'); + + /** + * 架构函数 + * 取得DB类的实例对象 字段检查 + * @access public + * @param string $name 模型名称 + * @param string $tablePrefix 表前缀 + * @param mixed $connection 数据库连接信息 + */ + public function __construct($name='',$tablePrefix='',$connection='') { + // 模型初始化 + $this->_initialize(); + // 获取模型名称 + if(!empty($name)) { + if(strpos($name,'.')) { // 支持 数据库名.模型名的 定义 + list($this->dbName,$this->name) = explode('.',$name); + }else{ + $this->name = $name; + } + }elseif(empty($this->name)){ + $this->name = $this->getModelName(); + } + // 设置表前缀 + if(is_null($tablePrefix)) {// 前缀为Null表示没有前缀 + $this->tablePrefix = ''; + }elseif('' != $tablePrefix) { + $this->tablePrefix = $tablePrefix; + }else{ + $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX'); + } + + // 数据库初始化操作 + // 获取数据库操作对象 + // 当前模型有独立的数据库连接信息 + $this->db(0,empty($this->connection)?$connection:$this->connection); + } + + /** + * 自动检测数据表信息 + * @access protected + * @return void + */ + protected function _checkTableInfo() { + // 如果不是Model类 自动记录数据表信息 + // 只在第一次执行记录 + if(empty($this->fields)) { + // 如果数据表字段没有定义则自动获取 + if(C('DB_FIELDS_CACHE')) { + $db = $this->dbName?$this->dbName:C('DB_NAME'); + $fields = F('_fields/'.strtolower($db.'.'.$this->name)); + if($fields) { + $version = C('DB_FIELD_VERSION'); + if(empty($version) || $fields['_version']== $version) { + $this->fields = $fields; + return ; + } + } + } + // 每次都会读取数据表信息 + $this->flush(); + } + } + + /** + * 获取字段信息并缓存 + * @access public + * @return void + */ + public function flush() { + // 缓存不存在则查询数据表信息 + $this->db->setModel($this->name); + $fields = $this->db->getFields($this->getTableName()); + if(!$fields) { // 无法获取字段信息 + return false; + } + $this->fields = array_keys($fields); + $this->fields['_autoinc'] = false; + foreach ($fields as $key=>$val){ + // 记录字段类型 + $type[$key] = $val['type']; + if($val['primary']) { + $this->fields['_pk'] = $key; + if($val['autoinc']) $this->fields['_autoinc'] = true; + } + } + // 记录字段类型信息 + $this->fields['_type'] = $type; + if(C('DB_FIELD_VERSION')) $this->fields['_version'] = C('DB_FIELD_VERSION'); + + // 2008-3-7 增加缓存开关控制 + if(C('DB_FIELDS_CACHE')){ + // 永久缓存数据表信息 + $db = $this->dbName?$this->dbName:C('DB_NAME'); + F('_fields/'.strtolower($db.'.'.$this->name),$this->fields); + } + } + + /** + * 动态切换扩展模型 + * @access public + * @param string $type 模型类型名称 + * @param mixed $vars 要传入扩展模型的属性变量 + * @return Model + */ + public function switchModel($type,$vars=array()) { + $class = ucwords(strtolower($type)).'Model'; + if(!class_exists($class)) + throw_exception($class.L('_MODEL_NOT_EXIST_')); + // 实例化扩展模型 + $this->_extModel = new $class($this->name); + if(!empty($vars)) { + // 传入当前模型的属性到扩展模型 + foreach ($vars as $var) + $this->_extModel->setProperty($var,$this->$var); + } + return $this->_extModel; + } + + /** + * 设置数据对象的值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return void + */ + public function __set($name,$value) { + // 设置数据对象属性 + $this->data[$name] = $value; + } + + /** + * 获取数据对象的值 + * @access public + * @param string $name 名称 + * @return mixed + */ + public function __get($name) { + return isset($this->data[$name])?$this->data[$name]:null; + } + + /** + * 检测数据对象的值 + * @access public + * @param string $name 名称 + * @return boolean + */ + public function __isset($name) { + return isset($this->data[$name]); + } + + /** + * 销毁数据对象的值 + * @access public + * @param string $name 名称 + * @return void + */ + public function __unset($name) { + unset($this->data[$name]); + } + + /** + * 利用__call方法实现一些特殊的Model方法 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(in_array(strtolower($method),$this->methods,true)) { + // 连贯操作的实现 + $this->options[strtolower($method)] = $args[0]; + return $this; + }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){ + // 统计查询的实现 + $field = isset($args[0])?$args[0]:'*'; + return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method); + }elseif(strtolower(substr($method,0,5))=='getby') { + // 根据某个字段获取记录 + $field = parse_name(substr($method,5)); + $where[$field] = $args[0]; + return $this->where($where)->find(); + }elseif(strtolower(substr($method,0,10))=='getfieldby') { + // 根据某个字段获取记录的某个值 + $name = parse_name(substr($method,10)); + $where[$name] =$args[0]; + return $this->where($where)->getField($args[1]); + }elseif(isset($this->_scope[$method])){// 命名范围的单独调用支持 + return $this->scope($method,$args[0]); + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } + // 回调方法 初始化模型 + protected function _initialize() {} + + /** + * 对保存到数据库的数据进行处理 + * @access protected + * @param mixed $data 要操作的数据 + * @return boolean + */ + protected function _facade($data) { + // 检查非数据字段 + if(!empty($this->fields)) { + foreach ($data as $key=>$val){ + if(!in_array($key,$this->fields,true)){ + unset($data[$key]); + }elseif(is_scalar($val)) { + // 字段类型检查 + $this->_parseType($data,$key); + } + } + } + // 安全过滤 + if(!empty($this->options['filter'])) { + $data = array_map($this->options['filter'],$data); + unset($this->options['filter']); + } + $this->_before_write($data); + return $data; + } + + // 写入数据前的回调方法 包括新增和更新 + protected function _before_write(&$data) {} + + /** + * 新增数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @param boolean $replace 是否replace + * @return mixed + */ + public function add($data='',$options=array(),$replace=false) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + // 重置数据 + $this->data = array(); + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 分析表达式 + $options = $this->_parseOptions($options); + // 数据处理 + $data = $this->_facade($data); + if(false === $this->_before_insert($data,$options)) { + return false; + } + // 写入数据到数据库 + $result = $this->db->insert($data,$options,$replace); + if(false !== $result ) { + $insertId = $this->getLastInsID(); + if($insertId) { + // 自增主键返回插入ID + $data[$this->getPk()] = $insertId; + $this->_after_insert($data,$options); + return $insertId; + } + $this->_after_insert($data,$options); + } + return $result; + } + // 插入数据前的回调方法 + protected function _before_insert(&$data,$options) {} + // 插入成功后的回调方法 + protected function _after_insert($data,$options) {} + + public function addAll($dataList,$options=array(),$replace=false){ + if(empty($dataList)) { + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + // 分析表达式 + $options = $this->_parseOptions($options); + // 数据处理 + foreach ($dataList as $key=>$data){ + $dataList[$key] = $this->_facade($data); + } + // 写入数据到数据库 + $result = $this->db->insertAll($dataList,$options,$replace); + if(false !== $result ) { + $insertId = $this->getLastInsID(); + if($insertId) { + return $insertId; + } + } + return $result; + } + + /** + * 通过Select方式添加记录 + * @access public + * @param string $fields 要插入的数据表字段名 + * @param string $table 要插入的数据表名 + * @param array $options 表达式 + * @return boolean + */ + public function selectAdd($fields='',$table='',$options=array()) { + // 分析表达式 + $options = $this->_parseOptions($options); + // 写入数据到数据库 + if(false === $result = $this->db->selectInsert($fields?$fields:$options['field'],$table?$table:$this->getTableName(),$options)){ + // 数据库插入操作失败 + $this->error = L('_OPERATION_WRONG_'); + return false; + }else { + // 插入成功 + return $result; + } + } + + /** + * 保存数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return boolean + */ + public function save($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + // 重置数据 + $this->data = array(); + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 数据处理 + $data = $this->_facade($data); + // 分析表达式 + $options = $this->_parseOptions($options); + $pk = $this->getPk(); + if(!isset($options['where']) ) { + // 如果存在主键数据 则自动作为更新条件 + if(isset($data[$pk])) { + $where[$pk] = $data[$pk]; + $options['where'] = $where; + unset($data[$pk]); + }else{ + // 如果没有任何更新条件则不执行 + $this->error = L('_OPERATION_WRONG_'); + return false; + } + } + if(is_array($options['where']) && isset($options['where'][$pk])){ + $pkValue = $options['where'][$pk]; + } + if(false === $this->_before_update($data,$options)) { + return false; + } + $result = $this->db->update($data,$options); + if(false !== $result) { + if(isset($pkValue)) $data[$pk] = $pkValue; + $this->_after_update($data,$options); + } + return $result; + } + // 更新数据前的回调方法 + protected function _before_update(&$data,$options) {} + // 更新成功后的回调方法 + protected function _after_update($data,$options) {} + + /** + * 删除数据 + * @access public + * @param mixed $options 表达式 + * @return mixed + */ + public function delete($options=array()) { + if(empty($options) && empty($this->options['where'])) { + // 如果删除条件为空 则删除当前数据对象所对应的记录 + if(!empty($this->data) && isset($this->data[$this->getPk()])) + return $this->delete($this->data[$this->getPk()]); + else + return false; + } + $pk = $this->getPk(); + if(is_numeric($options) || is_string($options)) { + // 根据主键删除记录 + if(strpos($options,',')) { + $where[$pk] = array('IN', $options); + }else{ + $where[$pk] = $options; + } + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + if(is_array($options['where']) && isset($options['where'][$pk])){ + $pkValue = $options['where'][$pk]; + } + $result = $this->db->delete($options); + if(false !== $result) { + $data = array(); + if(isset($pkValue)) $data[$pk] = $pkValue; + $this->_after_delete($data,$options); + } + // 返回删除记录个数 + return $result; + } + // 删除成功后的回调方法 + protected function _after_delete($data,$options) {} + + /** + * 查询数据集 + * @access public + * @param array $options 表达式参数 + * @return mixed + */ + public function select($options=array()) { + if(is_string($options) || is_numeric($options)) { + // 根据主键查询 + $pk = $this->getPk(); + if(strpos($options,',')) { + $where[$pk] = array('IN',$options); + }else{ + $where[$pk] = $options; + } + $options = array(); + $options['where'] = $where; + }elseif(false === $options){ // 用于子查询 不查询只返回SQL + $options = array(); + // 分析表达式 + $options = $this->_parseOptions($options); + return '( '.$this->db->buildSelectSql($options).' )'; + } + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(false === $resultSet) { + return false; + } + if(empty($resultSet)) { // 查询结果为空 + return null; + } + $this->_after_select($resultSet,$options); + return $resultSet; + } + // 查询成功后的回调方法 + protected function _after_select(&$resultSet,$options) {} + + /** + * 生成查询SQL 可用于子查询 + * @access public + * @param array $options 表达式参数 + * @return string + */ + public function buildSql($options=array()) { + // 分析表达式 + $options = $this->_parseOptions($options); + return '( '.$this->db->buildSelectSql($options).' )'; + } + + /** + * 分析表达式 + * @access protected + * @param array $options 表达式参数 + * @return array + */ + protected function _parseOptions($options=array()) { + if(is_array($options)) + $options = array_merge($this->options,$options); + // 查询过后清空sql表达式组装 避免影响下次查询 + $this->options = array(); + if(!isset($options['table'])){ + // 自动获取表名 + $options['table'] = $this->getTableName(); + $fields = $this->fields; + }else{ + // 指定数据表 则重新获取字段列表 但不支持类型检测 + $fields = $this->getDbFields(); + } + + if(!empty($options['alias'])) { + $options['table'] .= ' '.$options['alias']; + } + // 记录操作的模型名称 + $options['model'] = $this->name; + + // 字段类型验证 + if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) { + // 对数组查询条件进行字段类型检查 + foreach ($options['where'] as $key=>$val){ + $key = trim($key); + if(in_array($key,$fields,true)){ + if(is_scalar($val)) { + $this->_parseType($options['where'],$key); + } + }elseif(!is_numeric($key) && '_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'(') && false === strpos($key,'|') && false === strpos($key,'&')){ + unset($options['where'][$key]); + } + } + } + + // 表达式过滤 + $this->_options_filter($options); + return $options; + } + // 表达式过滤回调方法 + protected function _options_filter(&$options) {} + + /** + * 数据类型检测 + * @access protected + * @param mixed $data 数据 + * @param string $key 字段名 + * @return void + */ + protected function _parseType(&$data,$key) { + if(empty($this->options['bind'][':'.$key])){ + $fieldType = strtolower($this->fields['_type'][$key]); + if(false !== strpos($fieldType,'enum')){ + // 支持ENUM类型优先检测 + }elseif(false === strpos($fieldType,'bigint') && false !== strpos($fieldType,'int')) { + $data[$key] = intval($data[$key]); + }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){ + $data[$key] = floatval($data[$key]); + }elseif(false !== strpos($fieldType,'bool')){ + $data[$key] = (bool)$data[$key]; + } + } + } + + /** + * 查询数据 + * @access public + * @param mixed $options 表达式参数 + * @return mixed + */ + public function find($options=array()) { + if(is_numeric($options) || is_string($options)) { + $where[$this->getPk()] = $options; + $options = array(); + $options['where'] = $where; + } + // 总是查找一条记录 + $options['limit'] = 1; + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(false === $resultSet) { + return false; + } + if(empty($resultSet)) {// 查询结果为空 + return null; + } + $this->data = $resultSet[0]; + $this->_after_find($this->data,$options); + if(!empty($this->options['result'])) { + return $this->returnResult($this->data,$this->options['result']); + } + return $this->data; + } + // 查询成功的回调方法 + protected function _after_find(&$result,$options) {} + + protected function returnResult($data,$type=''){ + if ($type){ + if(is_callable($type)){ + return call_user_func($type,$data); + } + switch (strtolower($type)){ + case 'json': + return json_encode($data); + case 'xml': + return xml_encode($data); + } + } + return $data; + } + + /** + * 处理字段映射 + * @access public + * @param array $data 当前数据 + * @param integer $type 类型 0 写入 1 读取 + * @return array + */ + public function parseFieldsMap($data,$type=1) { + // 检查字段映射 + if(!empty($this->_map)) { + foreach ($this->_map as $key=>$val){ + if($type==1) { // 读取 + if(isset($data[$val])) { + $data[$key] = $data[$val]; + unset($data[$val]); + } + }else{ + if(isset($data[$key])) { + $data[$val] = $data[$key]; + unset($data[$key]); + } + } + } + } + return $data; + } + + /** + * 设置记录的某个字段值 + * 支持使用数据库字段和方法 + * @access public + * @param string|array $field 字段名 + * @param string $value 字段值 + * @return boolean + */ + public function setField($field,$value='') { + if(is_array($field)) { + $data = $field; + }else{ + $data[$field] = $value; + } + return $this->save($data); + } + + /** + * 字段值增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @return boolean + */ + public function setInc($field,$step=1) { + return $this->setField($field,array('exp',$field.'+'.$step)); + } + + /** + * 字段值减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @return boolean + */ + public function setDec($field,$step=1) { + return $this->setField($field,array('exp',$field.'-'.$step)); + } + + /** + * 获取一条记录的某个字段值 + * @access public + * @param string $field 字段名 + * @param string $spea 字段数据间隔符号 NULL返回数组 + * @return mixed + */ + public function getField($field,$sepa=null) { + $options['field'] = $field; + $options = $this->_parseOptions($options); + $field = trim($field); + if(strpos($field,',')) { // 多字段 + if(!isset($options['limit'])){ + $options['limit'] = is_numeric($sepa)?$sepa:''; + } + $resultSet = $this->db->select($options); + if(!empty($resultSet)) { + $_field = explode(',', $field); + $field = array_keys($resultSet[0]); + $key = array_shift($field); + $key2 = array_shift($field); + $cols = array(); + $count = count($_field); + foreach ($resultSet as $result){ + $name = $result[$key]; + if(2==$count) { + $cols[$name] = $result[$key2]; + }else{ + $cols[$name] = is_string($sepa)?implode($sepa,$result):$result; + } + } + return $cols; + } + }else{ // 查找一条记录 + // 返回数据个数 + if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据 + $options['limit'] = is_numeric($sepa)?$sepa:1; + } + $result = $this->db->select($options); + if(!empty($result)) { + if(true !== $sepa && 1==$options['limit']) return reset($result[0]); + foreach ($result as $val){ + $array[] = $val[$field]; + } + return $array; + } + } + return null; + } + + /** + * 创建数据对象 但不保存到数据库 + * @access public + * @param mixed $data 创建数据 + * @param string $type 状态 + * @return mixed + */ + public function create($data='',$type='') { + // 如果没有传值默认取POST数据 + if(empty($data)) { + $data = $_POST; + }elseif(is_object($data)){ + $data = get_object_vars($data); + } + // 验证数据 + if(empty($data) || !is_array($data)) { + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + + // 检查字段映射 + $data = $this->parseFieldsMap($data,0); + + // 状态 + $type = $type?$type:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT); + + // 检测提交字段的合法性 + if(isset($this->options['field'])) { // $this->field('field1,field2...')->create() + $fields = $this->options['field']; + unset($this->options['field']); + }elseif($type == self::MODEL_INSERT && isset($this->insertFields)) { + $fields = $this->insertFields; + }elseif($type == self::MODEL_UPDATE && isset($this->updateFields)) { + $fields = $this->updateFields; + } + if(isset($fields)) { + if(is_string($fields)) { + $fields = explode(',',$fields); + } + // 判断令牌验证字段 + if(C('TOKEN_ON')) $fields[] = C('TOKEN_NAME'); + foreach ($data as $key=>$val){ + if(!in_array($key,$fields)) { + unset($data[$key]); + } + } + } + + // 数据自动验证 + if(!$this->autoValidation($data,$type)) return false; + + // 表单令牌验证 + if(!$this->autoCheckToken($data)) { + $this->error = L('_TOKEN_ERROR_'); + return false; + } + + // 验证完成生成数据对象 + if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据 + $fields = $this->getDbFields(); + foreach ($data as $key=>$val){ + if(!in_array($key,$fields)) { + unset($data[$key]); + }elseif(MAGIC_QUOTES_GPC && is_string($val)){ + $data[$key] = stripslashes($val); + } + } + } + + // 创建完成对数据进行自动处理 + $this->autoOperation($data,$type); + // 赋值当前数据对象 + $this->data = $data; + // 返回创建的数据以供其他调用 + return $data; + } + + // 自动表单令牌验证 + // TODO ajax无刷新多次提交暂不能满足 + public function autoCheckToken($data) { + // 支持使用token(false) 关闭令牌验证 + if(isset($this->options['token']) && !$this->options['token']) return true; + if(C('TOKEN_ON')){ + $name = C('TOKEN_NAME'); + if(!isset($data[$name]) || !isset($_SESSION[$name])) { // 令牌数据无效 + return false; + } + + // 令牌验证 + list($key,$value) = explode('_',$data[$name]); + if($value && $_SESSION[$name][$key] === $value) { // 防止重复提交 + unset($_SESSION[$name][$key]); // 验证完成销毁session + return true; + } + // 开启TOKEN重置 + if(C('TOKEN_RESET')) unset($_SESSION[$name][$key]); + return false; + } + return true; + } + + /** + * 使用正则验证数据 + * @access public + * @param string $value 要验证的数据 + * @param string $rule 验证规则 + * @return boolean + */ + public function regex($value,$rule) { + $validate = array( + 'require' => '/.+/', + 'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/', + 'url' => '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/', + 'currency' => '/^\d+(\.\d+)?$/', + 'number' => '/^\d+$/', + 'zip' => '/^\d{6}$/', + 'integer' => '/^[-\+]?\d+$/', + 'double' => '/^[-\+]?\d+(\.\d+)?$/', + 'english' => '/^[A-Za-z]+$/', + ); + // 检查是否有内置的正则表达式 + if(isset($validate[strtolower($rule)])) + $rule = $validate[strtolower($rule)]; + return preg_match($rule,$value)===1; + } + + /** + * 自动表单处理 + * @access public + * @param array $data 创建数据 + * @param string $type 创建类型 + * @return mixed + */ + private function autoOperation(&$data,$type) { + if(!empty($this->options['auto'])) { + $_auto = $this->options['auto']; + unset($this->options['auto']); + }elseif(!empty($this->_auto)){ + $_auto = $this->_auto; + } + // 自动填充 + if(isset($_auto)) { + foreach ($_auto as $auto){ + // 填充因子定义格式 + // array('field','填充内容','填充条件','附加规则',[额外参数]) + if(empty($auto[2])) $auto[2] = self::MODEL_INSERT; // 默认为新增的时候自动填充 + if( $type == $auto[2] || $auto[2] == self::MODEL_BOTH) { + switch(trim($auto[3])) { + case 'function': // 使用函数进行填充 字段的值作为参数 + case 'callback': // 使用回调方法 + $args = isset($auto[4])?(array)$auto[4]:array(); + if(isset($data[$auto[0]])) { + array_unshift($args,$data[$auto[0]]); + } + if('function'==$auto[3]) { + $data[$auto[0]] = call_user_func_array($auto[1], $args); + }else{ + $data[$auto[0]] = call_user_func_array(array(&$this,$auto[1]), $args); + } + break; + case 'field': // 用其它字段的值进行填充 + $data[$auto[0]] = $data[$auto[1]]; + break; + case 'ignore': // 为空忽略 + if(''===$data[$auto[0]]) + unset($data[$auto[0]]); + break; + case 'string': + default: // 默认作为字符串填充 + $data[$auto[0]] = $auto[1]; + } + if(false === $data[$auto[0]] ) unset($data[$auto[0]]); + } + } + } + return $data; + } + + /** + * 自动表单验证 + * @access protected + * @param array $data 创建数据 + * @param string $type 创建类型 + * @return boolean + */ + protected function autoValidation($data,$type) { + if(!empty($this->options['validate'])) { + $_validate = $this->options['validate']; + unset($this->options['validate']); + }elseif(!empty($this->_validate)){ + $_validate = $this->_validate; + } + // 属性验证 + if(isset($_validate)) { // 如果设置了数据自动验证则进行数据验证 + if($this->patchValidate) { // 重置验证错误信息 + $this->error = array(); + } + foreach($_validate as $key=>$val) { + // 验证因子定义格式 + // array(field,rule,message,condition,type,when,params) + // 判断是否需要执行验证 + if(empty($val[5]) || $val[5]== self::MODEL_BOTH || $val[5]== $type ) { + if(0==strpos($val[2],'{%') && strpos($val[2],'}')) + // 支持提示信息的多语言 使用 {%语言定义} 方式 + $val[2] = L(substr($val[2],2,-1)); + $val[3] = isset($val[3])?$val[3]:self::EXISTS_VALIDATE; + $val[4] = isset($val[4])?$val[4]:'regex'; + // 判断验证条件 + switch($val[3]) { + case self::MUST_VALIDATE: // 必须验证 不管表单是否有设置该字段 + if(false === $this->_validationField($data,$val)) + return false; + break; + case self::VALUE_VALIDATE: // 值不为空的时候才验证 + if('' != trim($data[$val[0]])) + if(false === $this->_validationField($data,$val)) + return false; + break; + default: // 默认表单存在该字段就验证 + if(isset($data[$val[0]])) + if(false === $this->_validationField($data,$val)) + return false; + } + } + } + // 批量验证的时候最后返回错误 + if(!empty($this->error)) return false; + } + return true; + } + + /** + * 验证表单字段 支持批量验证 + * 如果批量验证返回错误的数组信息 + * @access protected + * @param array $data 创建数据 + * @param array $val 验证因子 + * @return boolean + */ + protected function _validationField($data,$val) { + if(false === $this->_validationFieldItem($data,$val)){ + if($this->patchValidate) { + $this->error[$val[0]] = $val[2]; + }else{ + $this->error = $val[2]; + return false; + } + } + return ; + } + + /** + * 根据验证因子验证字段 + * @access protected + * @param array $data 创建数据 + * @param array $val 验证因子 + * @return boolean + */ + protected function _validationFieldItem($data,$val) { + switch(strtolower(trim($val[4]))) { + case 'function':// 使用函数进行验证 + case 'callback':// 调用方法进行验证 + $args = isset($val[6])?(array)$val[6]:array(); + if(is_string($val[0]) && strpos($val[0], ',')) + $val[0] = explode(',', $val[0]); + if(is_array($val[0])){ + // 支持多个字段验证 + foreach($val[0] as $field) + $_data[$field] = $data[$field]; + array_unshift($args, $_data); + }else{ + array_unshift($args, $data[$val[0]]); + } + if('function'==$val[4]) { + return call_user_func_array($val[1], $args); + }else{ + return call_user_func_array(array(&$this, $val[1]), $args); + } + case 'confirm': // 验证两个字段是否相同 + return $data[$val[0]] == $data[$val[1]]; + case 'unique': // 验证某个值是否唯一 + if(is_string($val[0]) && strpos($val[0],',')) + $val[0] = explode(',',$val[0]); + $map = array(); + if(is_array($val[0])) { + // 支持多个字段验证 + foreach ($val[0] as $field) + $map[$field] = $data[$field]; + }else{ + $map[$val[0]] = $data[$val[0]]; + } + if(!empty($data[$this->getPk()])) { // 完善编辑的时候验证唯一 + $map[$this->getPk()] = array('neq',$data[$this->getPk()]); + } + if($this->where($map)->find()) return false; + return true; + default: // 检查附加规则 + return $this->check($data[$val[0]],$val[1],$val[4]); + } + } + + /** + * 验证数据 支持 in between equal length regex expire ip_allow ip_deny + * @access public + * @param string $value 验证数据 + * @param mixed $rule 验证表达式 + * @param string $type 验证方式 默认为正则验证 + * @return boolean + */ + public function check($value,$rule,$type='regex'){ + $type = strtolower(trim($type)); + switch($type) { + case 'in': // 验证是否在某个指定范围之内 逗号分隔字符串或者数组 + case 'notin': + $range = is_array($rule)? $rule : explode(',',$rule); + return $type == 'in' ? in_array($value ,$range) : !in_array($value ,$range); + case 'between': // 验证是否在某个范围 + case 'notbetween': // 验证是否不在某个范围 + if (is_array($rule)){ + $min = $rule[0]; + $max = $rule[1]; + }else{ + list($min,$max) = explode(',',$rule); + } + return $type == 'between' ? $value>=$min && $value<=$max : $value<$min || $value>$max; + case 'equal': // 验证是否等于某个值 + case 'notequal': // 验证是否等于某个值 + return $type == 'equal' ? $value == $rule : $value != $rule; + case 'length': // 验证长度 + $length = mb_strlen($value,'utf-8'); // 当前数据长度 + if(strpos($rule,',')) { // 长度区间 + list($min,$max) = explode(',',$rule); + return $length >= $min && $length <= $max; + }else{// 指定长度 + return $length == $rule; + } + case 'expire': + list($start,$end) = explode(',',$rule); + if(!is_numeric($start)) $start = strtotime($start); + if(!is_numeric($end)) $end = strtotime($end); + return NOW_TIME >= $start && NOW_TIME <= $end; + case 'ip_allow': // IP 操作许可验证 + return in_array(get_client_ip(),explode(',',$rule)); + case 'ip_deny': // IP 操作禁止验证 + return !in_array(get_client_ip(),explode(',',$rule)); + case 'regex': + default: // 默认使用正则验证 可以使用验证类中定义的验证名称 + // 检查附加规则 + return $this->regex($value,$rule); + } + } + + /** + * SQL查询 + * @access public + * @param string $sql SQL指令 + * @param mixed $parse 是否需要解析SQL + * @return mixed + */ + public function query($sql,$parse=false) { + if(!is_bool($parse) && !is_array($parse)) { + $parse = func_get_args(); + array_shift($parse); + } + $sql = $this->parseSql($sql,$parse); + return $this->db->query($sql); + } + + /** + * 执行SQL语句 + * @access public + * @param string $sql SQL指令 + * @param mixed $parse 是否需要解析SQL + * @return false | integer + */ + public function execute($sql,$parse=false) { + if(!is_bool($parse) && !is_array($parse)) { + $parse = func_get_args(); + array_shift($parse); + } + $sql = $this->parseSql($sql,$parse); + return $this->db->execute($sql); + } + + /** + * 解析SQL语句 + * @access public + * @param string $sql SQL指令 + * @param boolean $parse 是否需要解析SQL + * @return string + */ + protected function parseSql($sql,$parse) { + // 分析表达式 + if(true === $parse) { + $options = $this->_parseOptions(); + $sql = $this->db->parseSql($sql,$options); + }elseif(is_array($parse)){ // SQL预处理 + $parse = array_map(array($this->db,'escapeString'),$parse); + $sql = vsprintf($sql,$parse); + }else{ + $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX'))); + } + $this->db->setModel($this->name); + return $sql; + } + + /** + * 切换当前的数据库连接 + * @access public + * @param integer $linkNum 连接序号 + * @param mixed $config 数据库连接信息 + * @param array $params 模型参数 + * @return Model + */ + public function db($linkNum='',$config='',$params=array()){ + if(''===$linkNum && $this->db) { + return $this->db; + } + static $_linkNum = array(); + static $_db = array(); + if(!isset($_db[$linkNum]) || (isset($_db[$linkNum]) && $config && $_linkNum[$linkNum]!=$config) ) { + // 创建一个新的实例 + if(!empty($config) && is_string($config) && false === strpos($config,'/')) { // 支持读取配置参数 + $config = C($config); + } + $_db[$linkNum] = Db::getInstance($config); + }elseif(NULL === $config){ + $_db[$linkNum]->close(); // 关闭数据库连接 + unset($_db[$linkNum]); + return ; + } + if(!empty($params)) { + if(is_string($params)) parse_str($params,$params); + foreach ($params as $name=>$value){ + $this->setProperty($name,$value); + } + } + // 记录连接信息 + $_linkNum[$linkNum] = $config; + // 切换数据库连接 + $this->db = $_db[$linkNum]; + $this->_after_db(); + // 字段检测 + if(!empty($this->name) && $this->autoCheckFields) $this->_checkTableInfo(); + return $this; + } + // 数据库切换后回调方法 + protected function _after_db() {} + + /** + * 得到当前的数据对象名称 + * @access public + * @return string + */ + public function getModelName() { + if(empty($this->name)) + $this->name = substr(get_class($this),0,-5); + return $this->name; + } + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + $this->trueTableName = strtolower($tableName); + } + return (!empty($this->dbName)?$this->dbName.'.':'').$this->trueTableName; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->commit(); + $this->db->startTrans(); + return ; + } + + /** + * 提交事务 + * @access public + * @return boolean + */ + public function commit() { + return $this->db->commit(); + } + + /** + * 事务回滚 + * @access public + * @return boolean + */ + public function rollback() { + return $this->db->rollback(); + } + + /** + * 返回模型的错误信息 + * @access public + * @return string + */ + public function getError(){ + return $this->error; + } + + /** + * 返回数据库的错误信息 + * @access public + * @return string + */ + public function getDbError() { + return $this->db->getError(); + } + + /** + * 返回最后插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->db->getLastInsID(); + } + + /** + * 返回最后执行的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->db->getLastSql($this->name); + } + // 鉴于getLastSql比较常用 增加_sql 别名 + public function _sql(){ + return $this->getLastSql(); + } + + /** + * 获取主键名称 + * @access public + * @return string + */ + public function getPk() { + return isset($this->fields['_pk'])?$this->fields['_pk']:$this->pk; + } + + /** + * 获取数据表字段信息 + * @access public + * @return array + */ + public function getDbFields(){ + if(isset($this->options['table'])) {// 动态指定表名 + $fields = $this->db->getFields($this->options['table']); + return $fields?array_keys($fields):false; + } + if($this->fields) { + $fields = $this->fields; + unset($fields['_autoinc'],$fields['_pk'],$fields['_type'],$fields['_version']); + return $fields; + } + return false; + } + + /** + * 设置数据对象值 + * @access public + * @param mixed $data 数据 + * @return Model + */ + public function data($data=''){ + if('' === $data && !empty($this->data)) { + return $this->data; + } + if(is_object($data)){ + $data = get_object_vars($data); + }elseif(is_string($data)){ + parse_str($data,$data); + }elseif(!is_array($data)){ + throw_exception(L('_DATA_TYPE_INVALID_')); + } + $this->data = $data; + return $this; + } + + /** + * 查询SQL组装 join + * @access public + * @param mixed $join + * @return Model + */ + public function join($join) { + if(is_array($join)) { + $this->options['join'] = $join; + }elseif(!empty($join)) { + $this->options['join'][] = $join; + } + return $this; + } + + /** + * 查询SQL组装 union + * @access public + * @param mixed $union + * @param boolean $all + * @return Model + */ + public function union($union,$all=false) { + if(empty($union)) return $this; + if($all) { + $this->options['union']['_all'] = true; + } + if(is_object($union)) { + $union = get_object_vars($union); + } + // 转换union表达式 + if(is_string($union) ) { + $options = $union; + }elseif(is_array($union)){ + if(isset($union[0])) { + $this->options['union'] = array_merge($this->options['union'],$union); + return $this; + }else{ + $options = $union; + } + }else{ + throw_exception(L('_DATA_TYPE_INVALID_')); + } + $this->options['union'][] = $options; + return $this; + } + + /** + * 查询缓存 + * @access public + * @param mixed $key + * @param integer $expire + * @param string $type + * @return Model + */ + public function cache($key=true,$expire=null,$type=''){ + if(false !== $key) + $this->options['cache'] = array('key'=>$key,'expire'=>$expire,'type'=>$type); + return $this; + } + + /** + * 指定查询字段 支持字段排除 + * @access public + * @param mixed $field + * @param boolean $except 是否排除 + * @return Model + */ + public function field($field,$except=false){ + if(true === $field) {// 获取全部字段 + $fields = $this->getDbFields(); + $field = $fields?$fields:'*'; + }elseif($except) {// 字段排除 + if(is_string($field)) { + $field = explode(',',$field); + } + $fields = $this->getDbFields(); + $field = $fields?array_diff($fields,$field):$field; + } + $this->options['field'] = $field; + return $this; + } + + /** + * 调用命名范围 + * @access public + * @param mixed $scope 命名范围名称 支持多个 和直接定义 + * @param array $args 参数 + * @return Model + */ + public function scope($scope='',$args=NULL){ + if('' === $scope) { + if(isset($this->_scope['default'])) { + // 默认的命名范围 + $options = $this->_scope['default']; + }else{ + return $this; + } + }elseif(is_string($scope)){ // 支持多个命名范围调用 用逗号分割 + $scopes = explode(',',$scope); + $options = array(); + foreach ($scopes as $name){ + if(!isset($this->_scope[$name])) continue; + $options = array_merge($options,$this->_scope[$name]); + } + if(!empty($args) && is_array($args)) { + $options = array_merge($options,$args); + } + }elseif(is_array($scope)){ // 直接传入命名范围定义 + $options = $scope; + } + + if(is_array($options) && !empty($options)){ + $this->options = array_merge($this->options,array_change_key_case($options)); + } + return $this; + } + + /** + * 指定查询条件 支持安全过滤 + * @access public + * @param mixed $where 条件表达式 + * @param mixed $parse 预处理参数 + * @return Model + */ + public function where($where,$parse=null){ + if(!is_null($parse) && is_string($where)) { + if(!is_array($parse)) { + $parse = func_get_args(); + array_shift($parse); + } + $parse = array_map(array($this->db,'escapeString'),$parse); + $where = vsprintf($where,$parse); + }elseif(is_object($where)){ + $where = get_object_vars($where); + } + if(is_string($where) && '' != $where){ + $map = array(); + $map['_string'] = $where; + $where = $map; + } + if(isset($this->options['where'])){ + $this->options['where'] = array_merge($this->options['where'],$where); + }else{ + $this->options['where'] = $where; + } + + return $this; + } + + /** + * 指定查询数量 + * @access public + * @param mixed $offset 起始位置 + * @param mixed $length 查询数量 + * @return Model + */ + public function limit($offset,$length=null){ + $this->options['limit'] = is_null($length)?$offset:$offset.','.$length; + return $this; + } + + /** + * 指定分页 + * @access public + * @param mixed $page 页数 + * @param mixed $listRows 每页数量 + * @return Model + */ + public function page($page,$listRows=null){ + $this->options['page'] = is_null($listRows)?$page:$page.','.$listRows; + return $this; + } + + /** + * 查询注释 + * @access public + * @param string $comment 注释 + * @return Model + */ + public function comment($comment){ + $this->options['comment'] = $comment; + return $this; + } + + /** + * 设置模型的属性值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return Model + */ + public function setProperty($name,$value) { + if(property_exists($this,$name)) + $this->$name = $value; + return $this; + } + +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Think.class.php b/ThinkPHP/Lib/Core/Think.class.php new file mode 100644 index 0000000..201461e --- /dev/null +++ b/ThinkPHP/Lib/Core/Think.class.php @@ -0,0 +1,316 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP Portal类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Think { + + private static $_instance = array(); + + /** + * 应用程序初始化 + * @access public + * @return void + */ + static public function start() { + // 设定错误和异常处理 + register_shutdown_function(array('Think','fatalError')); + set_error_handler(array('Think','appError')); + set_exception_handler(array('Think','appException')); + // 注册AUTOLOAD方法 + spl_autoload_register(array('Think', 'autoload')); + //[RUNTIME] + Think::buildApp(); // 预编译项目 + //[/RUNTIME] + // 运行应用 + App::run(); + return ; + } + + //[RUNTIME] + /** + * 读取配置信息 编译项目 + * @access private + * @return string + */ + static private function buildApp() { + + // 读取运行模式 + if(defined('MODE_NAME')) { // 读取模式的设置 + $mode = include MODE_PATH.strtolower(MODE_NAME).'.php'; + }else{ + $mode = array(); + } + // 加载核心惯例配置文件 + C(include THINK_PATH.'Conf/convention.php'); + if(isset($mode['config'])) {// 加载模式配置文件 + C( is_array($mode['config'])?$mode['config']:include $mode['config'] ); + } + + // 加载项目配置文件 + if(is_file(CONF_PATH.'config.php')) + C(include CONF_PATH.'config.php'); + + // 加载框架底层语言包 + L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php'); + + // 加载模式系统行为定义 + if(C('APP_TAGS_ON')) { + if(isset($mode['extends'])) { + C('extends',is_array($mode['extends'])?$mode['extends']:include $mode['extends']); + }else{ // 默认加载系统行为扩展定义 + C('extends', include THINK_PATH.'Conf/tags.php'); + } + } + + // 加载应用行为定义 + if(isset($mode['tags'])) { + C('tags', is_array($mode['tags'])?$mode['tags']:include $mode['tags']); + }elseif(is_file(CONF_PATH.'tags.php')){ + // 默认加载项目配置目录的tags文件定义 + C('tags', include CONF_PATH.'tags.php'); + } + + $compile = ''; + // 读取核心编译文件列表 + if(isset($mode['core'])) { + $list = $mode['core']; + }else{ + $list = array( + THINK_PATH.'Common/functions.php', // 标准模式函数库 + CORE_PATH.'Core/Log.class.php', // 日志处理类 + CORE_PATH.'Core/Dispatcher.class.php', // URL调度类 + CORE_PATH.'Core/App.class.php', // 应用程序类 + CORE_PATH.'Core/Action.class.php', // 控制器类 + CORE_PATH.'Core/View.class.php', // 视图类 + ); + } + // 项目追加核心编译列表文件 + if(is_file(CONF_PATH.'core.php')) { + $list = array_merge($list,include CONF_PATH.'core.php'); + } + foreach ($list as $file){ + if(is_file($file)) { + require_cache($file); + if(!APP_DEBUG) $compile .= compile($file); + } + } + + // 加载项目公共文件 + if(is_file(COMMON_PATH.'common.php')) { + include COMMON_PATH.'common.php'; + // 编译文件 + if(!APP_DEBUG) $compile .= compile(COMMON_PATH.'common.php'); + } + + // 加载模式别名定义 + if(isset($mode['alias'])) { + $alias = is_array($mode['alias'])?$mode['alias']:include $mode['alias']; + alias_import($alias); + if(!APP_DEBUG) $compile .= 'alias_import('.var_export($alias,true).');'; + } + + // 加载项目别名定义 + if(is_file(CONF_PATH.'alias.php')){ + $alias = include CONF_PATH.'alias.php'; + alias_import($alias); + if(!APP_DEBUG) $compile .= 'alias_import('.var_export($alias,true).');'; + } + + if(APP_DEBUG) { + // 调试模式加载系统默认的配置文件 + C(include THINK_PATH.'Conf/debug.php'); + // 读取调试模式的应用状态 + $status = C('APP_STATUS'); + // 加载对应的项目配置文件 + if(is_file(CONF_PATH.$status.'.php')) + // 允许项目增加开发模式配置定义 + C(include CONF_PATH.$status.'.php'); + }else{ + // 部署模式下面生成编译文件 + build_runtime_cache($compile); + } + return ; + } + //[/RUNTIME] + + /** + * 系统自动加载ThinkPHP类库 + * 并且支持配置自动加载路径 + * @param string $class 对象类名 + * @return void + */ + public static function autoload($class) { + // 检查是否存在别名定义 + if(alias_import($class)) return ; + $libPath = defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH; + $group = defined('GROUP_NAME') && C('APP_GROUP_MODE')==0 ?GROUP_NAME.'/':''; + $file = $class.'.class.php'; + if(substr($class,-8)=='Behavior') { // 加载行为 + if(require_array(array( + CORE_PATH.'Behavior/'.$file, + EXTEND_PATH.'Behavior/'.$file, + LIB_PATH.'Behavior/'.$file, + $libPath.'Behavior/'.$file),true) + || (defined('MODE_NAME') && require_cache(MODE_PATH.ucwords(MODE_NAME).'/Behavior/'.$file))) { + return ; + } + }elseif(substr($class,-5)=='Model'){ // 加载模型 + if(require_array(array( + LIB_PATH.'Model/'.$group.$file, + $libPath.'Model/'.$file, + EXTEND_PATH.'Model/'.$file),true)) { + return ; + } + }elseif(substr($class,-6)=='Action'){ // 加载控制器 + if(require_array(array( + LIB_PATH.'Action/'.$group.$file, + $libPath.'Action/'.$file, + EXTEND_PATH.'Action/'.$file),true)) { + return ; + } + }elseif(substr($class,0,5)=='Cache'){ // 加载缓存驱动 + if(require_array(array( + EXTEND_PATH.'Driver/Cache/'.$file, + CORE_PATH.'Driver/Cache/'.$file),true)){ + return ; + } + }elseif(substr($class,0,2)=='Db'){ // 加载数据库驱动 + if(require_array(array( + EXTEND_PATH.'Driver/Db/'.$file, + CORE_PATH.'Driver/Db/'.$file),true)){ + return ; + } + }elseif(substr($class,0,8)=='Template'){ // 加载模板引擎驱动 + if(require_array(array( + EXTEND_PATH.'Driver/Template/'.$file, + CORE_PATH.'Driver/Template/'.$file),true)){ + return ; + } + }elseif(substr($class,0,6)=='TagLib'){ // 加载标签库驱动 + if(require_array(array( + EXTEND_PATH.'Driver/TagLib/'.$file, + CORE_PATH.'Driver/TagLib/'.$file),true)) { + return ; + } + } + + // 根据自动加载路径设置进行尝试搜索 + $paths = explode(',',C('APP_AUTOLOAD_PATH')); + foreach ($paths as $path){ + if(import($path.'.'.$class)) + // 如果加载类成功则返回 + return ; + } + } + + /** + * 取得对象实例 支持调用类的静态方法 + * @param string $class 对象类名 + * @param string $method 类的静态方法名 + * @return object + */ + static public function instance($class,$method='') { + $identify = $class.$method; + if(!isset(self::$_instance[$identify])) { + if(class_exists($class)){ + $o = new $class(); + if(!empty($method) && method_exists($o,$method)) + self::$_instance[$identify] = call_user_func_array(array(&$o, $method)); + else + self::$_instance[$identify] = $o; + } + else + halt(L('_CLASS_NOT_EXIST_').':'.$class); + } + return self::$_instance[$identify]; + } + + /** + * 自定义异常处理 + * @access public + * @param mixed $e 异常对象 + */ + static public function appException($e) { + $error = array(); + $error['message'] = $e->getMessage(); + $trace = $e->getTrace(); + if('throw_exception'==$trace[0]['function']) { + $error['file'] = $trace[0]['file']; + $error['line'] = $trace[0]['line']; + }else{ + $error['file'] = $e->getFile(); + $error['line'] = $e->getLine(); + } + Log::record($error['message'],Log::ERR); + halt($error); + } + + /** + * 自定义错误处理 + * @access public + * @param int $errno 错误类型 + * @param string $errstr 错误信息 + * @param string $errfile 错误文件 + * @param int $errline 错误行数 + * @return void + */ + static public function appError($errno, $errstr, $errfile, $errline) { + switch ($errno) { + case E_ERROR: + case E_PARSE: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + ob_end_clean(); + // 页面压缩输出支持 + if(C('OUTPUT_ENCODE')){ + $zlib = ini_get('zlib.output_compression'); + if(empty($zlib)) ob_start('ob_gzhandler'); + } + $errorStr = "$errstr ".$errfile." 第 $errline 行."; + if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR); + function_exists('halt')?halt($errorStr):exit('ERROR:'.$errorStr); + break; + case E_STRICT: + case E_USER_WARNING: + case E_USER_NOTICE: + default: + $errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行."; + trace($errorStr,'','NOTIC'); + break; + } + } + + // 致命错误捕获 + static public function fatalError() { + // 保存日志记录 + if(C('LOG_RECORD')) Log::save(); + if ($e = error_get_last()) { + switch($e['type']){ + case E_ERROR: + case E_PARSE: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + ob_end_clean(); + function_exists('halt')?halt($e):exit('ERROR:'.$e['message']. ' in '.$e['file'].' on line '.$e['line'].''); + break; + } + } + } + +} diff --git a/ThinkPHP/Lib/Core/ThinkException.class.php b/ThinkPHP/Lib/Core/ThinkException.class.php new file mode 100644 index 0000000..64dd380 --- /dev/null +++ b/ThinkPHP/Lib/Core/ThinkException.class.php @@ -0,0 +1,20 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP系统异常基类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class ThinkException extends Exception { +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/View.class.php b/ThinkPHP/Lib/Core/View.class.php new file mode 100644 index 0000000..8ec3acd --- /dev/null +++ b/ThinkPHP/Lib/Core/View.class.php @@ -0,0 +1,227 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 视图类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class View { + /** + * 模板输出变量 + * @var tVar + * @access protected + */ + protected $tVar = array(); + + /** + * 模板主题 + * @var theme + * @access protected + */ + protected $theme = ''; + + /** + * 模板变量赋值 + * @access public + * @param mixed $name + * @param mixed $value + */ + public function assign($name,$value=''){ + if(is_array($name)) { + $this->tVar = array_merge($this->tVar,$name); + }else { + $this->tVar[$name] = $value; + } + } + + /** + * 取得模板变量的值 + * @access public + * @param string $name + * @return mixed + */ + public function get($name=''){ + if('' === $name) { + return $this->tVar; + } + return isset($this->tVar[$name])?$this->tVar[$name]:false; + } + + /** + * 加载模板和页面输出 可以返回输出内容 + * @access public + * @param string $templateFile 模板文件名 + * @param string $charset 模板输出字符集 + * @param string $contentType 输出类型 + * @param string $content 模板输出内容 + * @param string $prefix 模板缓存前缀 + * @return mixed + */ + public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') { + G('viewStartTime'); + // 视图开始标签 + tag('view_begin',$templateFile); + // 解析并获取模板内容 + $content = $this->fetch($templateFile,$content,$prefix); + // 输出模板内容 + $this->render($content,$charset,$contentType); + // 视图结束标签 + tag('view_end'); + } + + /** + * 输出内容文本可以包括Html + * @access private + * @param string $content 输出内容 + * @param string $charset 模板输出字符集 + * @param string $contentType 输出类型 + * @return mixed + */ + private function render($content,$charset='',$contentType=''){ + if(empty($charset)) $charset = C('DEFAULT_CHARSET'); + if(empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE'); + // 网页字符编码 + header('Content-Type:'.$contentType.'; charset='.$charset); + header('Cache-control: '.C('HTTP_CACHE_CONTROL')); // 页面缓存控制 + header('X-Powered-By:ThinkPHP'); + // 输出模板文件 + echo $content; + } + + /** + * 解析和获取模板内容 用于输出 + * @access public + * @param string $templateFile 模板文件名 + * @param string $content 模板输出内容 + * @param string $prefix 模板缓存前缀 + * @return string + */ + public function fetch($templateFile='',$content='',$prefix='') { + if(empty($content)) { + $templateFile = $this->parseTemplate($templateFile); + // 模板文件不存在直接返回 + if(!is_file($templateFile)) + throw_exception(L('_TEMPLATE_NOT_EXIST_').'['.$templateFile.']'); + } + // 页面缓存 + ob_start(); + ob_implicit_flush(0); + if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板 + // 模板阵列变量分解成为独立变量 + extract($this->tVar, EXTR_OVERWRITE); + // 直接载入PHP模板 + empty($content)?include $templateFile:eval('?>'.$content); + }else{ + // 视图解析标签 + $params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix); + tag('view_parse',$params); + } + // 获取并清空缓存 + $content = ob_get_clean(); + // 内容过滤标签 + tag('view_filter',$content); + // 输出模板文件 + return $content; + } + + /** + * 自动定位模板文件 + * @access protected + * @param string $template 模板文件规则 + * @return string + */ + public function parseTemplate($template='') { + $app_name=APP_NAME==basename(dirname($_SERVER['SCRIPT_FILENAME'])) && ''==__APP__?'':APP_NAME.'/'; + if(is_file($template)) { + $group = defined('GROUP_NAME')?GROUP_NAME.'/':''; + $theme = C('DEFAULT_THEME'); + // 获取当前主题的模版路径 + if(1==C('APP_GROUP_MODE')){ // 独立分组模式 + define('THEME_PATH', dirname(BASE_LIB_PATH).'/'.$group.basename(TMPL_PATH).'/'.$theme); + define('APP_TMPL_PATH',__ROOT__.'/'.$app_name.C('APP_GROUP_PATH').'/'.$group.basename(TMPL_PATH).'/'.$theme); + }else{ + define('THEME_PATH', TMPL_PATH.$group.$theme); + define('APP_TMPL_PATH',__ROOT__.'/'.$app_name.basename(TMPL_PATH).'/'.$group.$theme); + } + return $template; + } + $depr = C('TMPL_FILE_DEPR'); + $template = str_replace(':', $depr, $template); + // 获取当前主题名称 + $theme = $this->getTemplateTheme(); + // 获取当前模版分组 + $group = defined('GROUP_NAME')?GROUP_NAME.'/':''; + if(defined('GROUP_NAME') && strpos($template,'@')){ // 跨分组调用模版文件 + list($group,$template) = explode('@',$template); + $group .= '/'; + } + // 获取当前主题的模版路径 + if(1==C('APP_GROUP_MODE')){ // 独立分组模式 + define('THEME_PATH', dirname(BASE_LIB_PATH).'/'.$group.basename(TMPL_PATH).'/'.$theme); + define('APP_TMPL_PATH',__ROOT__.'/'.$app_name.C('APP_GROUP_PATH').'/'.$group.basename(TMPL_PATH).'/'.$theme); + }else{ + define('THEME_PATH', TMPL_PATH.$group.$theme); + define('APP_TMPL_PATH',__ROOT__.'/'.$app_name.basename(TMPL_PATH).'/'.$group.$theme); + } + + // 分析模板文件规则 + if('' == $template) { + // 如果模板文件名为空 按照默认规则定位 + $template = MODULE_NAME . $depr . ACTION_NAME; + }elseif(false === strpos($template, '/')){ + $template = MODULE_NAME . $depr . $template; + } + return THEME_PATH.$template.C('TMPL_TEMPLATE_SUFFIX'); + } + + /** + * 设置当前输出的模板主题 + * @access public + * @param mixed $theme 主题名称 + * @return View + */ + public function theme($theme){ + $this->theme = $theme; + return $this; + } + + /** + * 获取当前的模板主题 + * @access private + * @return string + */ + private function getTemplateTheme() { + if($this->theme) { // 指定模板主题 + $theme = $this->theme; + }else{ + /* 获取模板主题名称 */ + $theme = C('DEFAULT_THEME'); + if(C('TMPL_DETECT_THEME')) {// 自动侦测模板主题 + $t = C('VAR_TEMPLATE'); + if (isset($_GET[$t])){ + $theme = $_GET[$t]; + }elseif(cookie('think_template')){ + $theme = cookie('think_template'); + } + if(!in_array($theme,explode(',',C('THEME_LIST')))){ + $theme = C('DEFAULT_THEME'); + } + cookie('think_template',$theme,864000); + } + } + define('THEME_NAME', $theme); // 当前模板主题名称 + return $theme?$theme . '/':''; + } + +} diff --git a/ThinkPHP/Lib/Core/Widget.class.php b/ThinkPHP/Lib/Core/Widget.class.php new file mode 100644 index 0000000..38cd7c0 --- /dev/null +++ b/ThinkPHP/Lib/Core/Widget.class.php @@ -0,0 +1,107 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP Widget类 抽象类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +abstract class Widget { + + // 使用的模板引擎 每个Widget可以单独配置不受系统影响 + protected $template = ''; + + /** + * 渲染输出 render方法是Widget唯一的接口 + * 使用字符串返回 不能有任何输出 + * @access public + * @param mixed $data 要渲染的数据 + * @return string + */ + abstract public function render($data); + + /** + * 渲染模板输出 供render方法内部调用 + * @access public + * @param string $templateFile 模板文件 + * @param mixed $var 模板变量 + * @return string + */ + protected function renderFile($templateFile='',$var='') { + ob_start(); + ob_implicit_flush(0); + if(!file_exists_case($templateFile)){ + // 自动定位模板文件 + $name = substr(get_class($this),0,-6); + $filename = empty($templateFile)?$name:$templateFile; + $templateFile = BASE_LIB_PATH.'Widget/'.$name.'/'.$filename.C('TMPL_TEMPLATE_SUFFIX'); + if(!file_exists_case($templateFile)) + throw_exception(L('_TEMPLATE_NOT_EXIST_').'['.$templateFile.']'); + } + $template = strtolower($this->template?$this->template:(C('TMPL_ENGINE_TYPE')?C('TMPL_ENGINE_TYPE'):'php')); + if('php' == $template) { + // 使用PHP模板 + if(!empty($var)) extract($var, EXTR_OVERWRITE); + // 直接载入PHP模板 + include $templateFile; + }elseif('think'==$template){ // 采用Think模板引擎 + if($this->checkCache($templateFile)) { // 缓存有效 + // 分解变量并载入模板缓存 + extract($var, EXTR_OVERWRITE); + //载入模版缓存文件 + include C('CACHE_PATH').md5($templateFile).C('TMPL_CACHFILE_SUFFIX'); + }else{ + $tpl = Think::instance('ThinkTemplate'); + // 编译并加载模板文件 + $tpl->fetch($templateFile,$var); + } + }else{ + $class = 'Template'.ucwords($template); + if(is_file(CORE_PATH.'Driver/Template/'.$class.'.class.php')) { + // 内置驱动 + $path = CORE_PATH; + }else{ // 扩展驱动 + $path = EXTEND_PATH; + } + require_cache($path.'Driver/Template/'.$class.'.class.php'); + $tpl = new $class; + $tpl->fetch($templateFile,$var); + } + $content = ob_get_clean(); + return $content; + } + + /** + * 检查缓存文件是否有效 + * 如果无效则需要重新编译 + * @access public + * @param string $tmplTemplateFile 模板文件名 + * @return boolen + */ + protected function checkCache($tmplTemplateFile) { + if (!C('TMPL_CACHE_ON')) // 优先对配置设定检测 + return false; + $tmplCacheFile = C('CACHE_PATH').md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX'); + if(!is_file($tmplCacheFile)){ + return false; + }elseif (filemtime($tmplTemplateFile) > filemtime($tmplCacheFile)) { + // 模板文件如果有更新则缓存需要更新 + return false; + }elseif (C('TMPL_CACHE_TIME') != 0 && time() > filemtime($tmplCacheFile)+C('TMPL_CACHE_TIME')) { + // 缓存是否在有效期 + return false; + } + // 缓存有效 + return true; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php b/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php new file mode 100644 index 0000000..8f5c301 --- /dev/null +++ b/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php @@ -0,0 +1,184 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * 文件类型缓存类 + * @category Think + * @package Think + * @subpackage Driver.Cache + * @author liu21st + */ +class CacheFile extends Cache { + + /** + * 架构函数 + * @access public + */ + public function __construct($options=array()) { + if(!empty($options)) { + $this->options = $options; + } + $this->options['temp'] = !empty($options['temp'])? $options['temp'] : C('DATA_CACHE_PATH'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/'; + $this->init(); + } + + /** + * 初始化检查 + * @access private + * @return boolen + */ + private function init() { + // 创建项目缓存目录 + if (!is_dir($this->options['temp'])) { + mkdir($this->options['temp']); + } + } + + /** + * 取得变量的存储文件名 + * @access private + * @param string $name 缓存变量名 + * @return string + */ + private function filename($name) { + $name = md5($name); + if(C('DATA_CACHE_SUBDIR')) { + // 使用子目录 + $dir =''; + for($i=0;$ioptions['temp'].$dir)) { + mkdir($this->options['temp'].$dir,0755,true); + } + $filename = $dir.$this->options['prefix'].$name.'.php'; + }else{ + $filename = $this->options['prefix'].$name.'.php'; + } + return $this->options['temp'].$filename; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + $filename = $this->filename($name); + if (!is_file($filename)) { + return false; + } + N('cache_read',1); + $content = file_get_contents($filename); + if( false !== $content) { + $expire = (int)substr($content,8, 12); + if($expire != 0 && time() > filemtime($filename) + $expire) { + //缓存过期删除缓存文件 + unlink($filename); + return false; + } + if(C('DATA_CACHE_CHECK')) {//开启数据校验 + $check = substr($content,20, 32); + $content = substr($content,52, -3); + if($check != md5($content)) {//校验错误 + return false; + } + }else { + $content = substr($content,20, -3); + } + if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //启用数据压缩 + $content = gzuncompress($content); + } + $content = unserialize($content); + return $content; + } + else { + return false; + } + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param int $expire 有效时间 0为永久 + * @return boolen + */ + public function set($name,$value,$expire=null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $filename = $this->filename($name); + $data = serialize($value); + if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //数据压缩 + $data = gzcompress($data,3); + } + if(C('DATA_CACHE_CHECK')) {//开启数据校验 + $check = md5($data); + }else { + $check = ''; + } + $data = ""; + $result = file_put_contents($filename,$data); + if($result) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + clearstatcache(); + return true; + }else { + return false; + } + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return unlink($this->filename($name)); + } + + /** + * 清除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function clear() { + $path = $this->options['temp']; + $files = scandir($path); + if($files){ + foreach($files as $file){ + if ($file != '.' && $file != '..' && is_dir($path.$file) ){ + array_map( 'unlink', glob( $path.$file.'/*.*' ) ); + }elseif(is_file($path.$file)){ + unlink( $path . $file ); + } + } + return true; + } + return false; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Driver/Db/DbMysql.class.php b/ThinkPHP/Lib/Driver/Db/DbMysql.class.php new file mode 100644 index 0000000..4d3a783 --- /dev/null +++ b/ThinkPHP/Lib/Driver/Db/DbMysql.class.php @@ -0,0 +1,350 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); + +/** + * Mysql数据库驱动类 + * @category Think + * @package Think + * @subpackage Driver.Db + * @author liu21st + */ +class DbMysql extends Db{ + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysql') ) { + throw_exception(L('_NOT_SUPPERT_').':mysql'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = ''; + } + } + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect($config='',$linkNum=0,$force=false) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); + // 是否长连接 + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + if($pconnect) { + $this->linkID[$linkNum] = mysql_pconnect( $host, $config['username'], $config['password'],131072); + }else{ + $this->linkID[$linkNum] = mysql_connect( $host, $config['username'], $config['password'],true,131072); + } + if ( !$this->linkID[$linkNum] || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID[$linkNum])) ) { + throw_exception(mysql_error()); + } + $dbVersion = mysql_get_server_info($this->linkID[$linkNum]); + //使用UTF8存取数据库 + mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID[$linkNum]); + //设置 sql_model + if($dbVersion >'5.0.1'){ + mysql_query("SET sql_mode=''",$this->linkID[$linkNum]); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mysql_free_result($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + if(0===stripos($str, 'call')){ // 存储过程查询支持 + $this->close(); + $this->connected = false; + } + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mysql_query($str, $this->_linkID); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = mysql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer|false + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = mysql_query($str, $this->_linkID) ; + $this->debug(); + if ( false === $result) { + $this->error(); + return false; + } else { + $this->numRows = mysql_affected_rows($this->_linkID); + $this->lastInsID = mysql_insert_id($this->_linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mysql_query('START TRANSACTION', $this->_linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = mysql_query('COMMIT', $this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = mysql_query('ROLLBACK', $this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mysql_fetch_assoc($this->queryID)){ + $result[] = $row; + } + mysql_data_seek($this->queryID,0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName)); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) (strtoupper($val['Null']) === 'NO'), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + if(!empty($dbName)) { + $sql = 'SHOW TABLES FROM '.$dbName; + }else{ + $sql = 'SHOW TABLES '; + } + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 替换记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @return false | integer + */ + public function replace($data,$options=array()) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + return $this->execute($sql); + } + + /** + * 插入记录 + * @access public + * @param mixed $datas 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insertAll($datas,$options=array(),$replace=false) { + if(!is_array($datas[0])) return false; + $fields = array_keys($datas[0]); + array_walk($fields, array($this, 'parseKey')); + $values = array(); + foreach ($datas as $data){ + $value = array(); + foreach ($data as $key=>$val){ + $val = $this->parseValue($val); + if(is_scalar($val)) { // 过滤非标量数据 + $value[] = $val; + } + } + $values[] = '('.implode(',', $value).')'; + } + $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values); + return $this->execute($sql); + } + + /** + * 关闭数据库 + * @access public + * @return void + */ + public function close() { + if ($this->_linkID){ + mysql_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mysql_errno().':'.mysql_error($this->_linkID); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escapeString($str) { + if($this->_linkID) { + return mysql_real_escape_string($str,$this->_linkID); + }else{ + return mysql_escape_string($str); + } + } + + /** + * 字段和表名处理添加` + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + $key = trim($key); + if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { + $key = '`'.$key.'`'; + } + return $key; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php b/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php new file mode 100644 index 0000000..a796063 --- /dev/null +++ b/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php @@ -0,0 +1,345 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * Mysqli数据库驱动类 + * @category Think + * @package Think + * @subpackage Driver.Db + * @author liu21st + */ +class DbMysqli extends Db{ + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysqli') ) { + throw_exception(L('_NOT_SUPPERT_').':mysqli'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = ''; + } + } + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $this->linkID[$linkNum] = new mysqli($config['hostname'],$config['username'],$config['password'],$config['database'],$config['hostport']?intval($config['hostport']):3306); + if (mysqli_connect_errno()) throw_exception(mysqli_connect_error()); + $dbVersion = $this->linkID[$linkNum]->server_version; + + // 设置数据库编码 + $this->linkID[$linkNum]->query("SET NAMES '".C('DB_CHARSET')."'"); + //设置 sql_model + if($dbVersion >'5.0.1'){ + $this->linkID[$linkNum]->query("SET sql_mode=''"); + } + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->queryID->free_result(); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = $this->_linkID->query($str); + // 对存储过程改进 + if( $this->_linkID->more_results() ){ + while (($res = $this->_linkID->next_result()) != NULL) { + $res->free_result(); + } + } + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = $this->queryID->num_rows; + $this->numCols = $this->queryID->field_count; + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_linkID->query($str); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + $this->numRows = $this->_linkID->affected_rows; + $this->lastInsID = $this->_linkID->insert_id; + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + //数据rollback 支持 + if ($this->transTimes == 0) { + $this->_linkID->autocommit(false); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = $this->_linkID->commit(); + $this->_linkID->autocommit( true); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = $this->_linkID->rollback(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @param string $sql sql语句 + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows>0) { + //返回数据集 + for($i=0;$i<$this->numRows ;$i++ ){ + $result[$i] = $this->queryID->fetch_assoc(); + } + $this->queryID->data_seek(0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName)); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + } + return $info; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + $sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES '; + $result = $this->query($sql); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + } + return $info; + } + + /** + * 替换记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @return false | integer + */ + public function replace($data,$options=array()) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + return $this->execute($sql); + } + + /** + * 插入记录 + * @access public + * @param mixed $datas 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insertAll($datas,$options=array(),$replace=false) { + if(!is_array($datas[0])) return false; + $fields = array_keys($datas[0]); + array_walk($fields, array($this, 'parseKey')); + $values = array(); + foreach ($datas as $data){ + $value = array(); + foreach ($data as $key=>$val){ + $val = $this->parseValue($val); + if(is_scalar($val)) { // 过滤非标量数据 + $value[] = $val; + } + } + $values[] = '('.implode(',', $value).')'; + } + $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values); + return $this->execute($sql); + } + + /** + * 关闭数据库 + * @access public + * @return volid + */ + public function close() { + if ($this->_linkID){ + $this->_linkID->close(); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @static + * @access public + * @return string + */ + public function error() { + $this->error = $this->_linkID->errno.':'.$this->_linkID->error; + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @static + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + if($this->_linkID) { + return $this->_linkID->real_escape_string($str); + }else{ + return addslashes($str); + } + } + + /** + * 字段和表名处理添加` + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + $key = trim($key); + if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { + $key = '`'.$key.'`'; + } + return $key; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php b/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php new file mode 100644 index 0000000..7f8c2a0 --- /dev/null +++ b/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php @@ -0,0 +1,642 @@ + +// +---------------------------------------------------------------------- + +defined('THINK_PATH') or exit(); +/** + * CX标签库解析类 + * @category Think + * @package Think + * @subpackage Driver.Taglib + * @author liu21st + */ +class TagLibCx extends TagLib { + + // 标签定义 + protected $tags = array( + // 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次 + 'php' => array(), + 'volist' => array('attr'=>'name,id,offset,length,key,mod','level'=>3,'alias'=>'iterate'), + 'foreach' => array('attr'=>'name,item,key','level'=>3), + 'if' => array('attr'=>'condition','level'=>2), + 'elseif' => array('attr'=>'condition','close'=>0), + 'else' => array('attr'=>'','close'=>0), + 'switch' => array('attr'=>'name','level'=>2), + 'case' => array('attr'=>'value,break'), + 'default' => array('attr'=>'','close'=>0), + 'compare' => array('attr'=>'name,value,type','level'=>3,'alias'=>'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'), + 'range' => array('attr'=>'name,value,type','level'=>3,'alias'=>'in,notin,between,notbetween'), + 'empty' => array('attr'=>'name','level'=>3), + 'notempty' => array('attr'=>'name','level'=>3), + 'present' => array('attr'=>'name','level'=>3), + 'notpresent'=> array('attr'=>'name','level'=>3), + 'defined' => array('attr'=>'name','level'=>3), + 'notdefined'=> array('attr'=>'name','level'=>3), + 'import' => array('attr'=>'file,href,type,value,basepath','close'=>0,'alias'=>'load,css,js'), + 'assign' => array('attr'=>'name,value','close'=>0), + 'define' => array('attr'=>'name,value','close'=>0), + 'for' => array('attr'=>'start,end,name,comparison,step', 'level'=>3), + ); + + /** + * php标签解析 + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _php($attr,$content) { + $parseStr = ''; + return $parseStr; + } + + /** + * volist标签解析 循环输出数据集 + * 格式: + * + * {user.username} + * {user.email} + * + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string|void + */ + public function _volist($attr,$content) { + static $_iterateParseCache = array(); + //如果已经解析过,则直接返回变量值 + $cacheIterateId = md5($attr.$content); + if(isset($_iterateParseCache[$cacheIterateId])) + return $_iterateParseCache[$cacheIterateId]; + $tag = $this->parseXmlAttr($attr,'volist'); + $name = $tag['name']; + $id = $tag['id']; + $empty = isset($tag['empty'])?$tag['empty']:''; + $key = !empty($tag['key'])?$tag['key']:'i'; + $mod = isset($tag['mod'])?$tag['mod']:'2'; + // 允许使用函数设定数据集 {$vo.name} + $parseStr = 'autoBuildVar($name); + } + $parseStr .= 'if(is_array('.$name.')): $'.$key.' = 0;'; + if(isset($tag['length']) && '' !=$tag['length'] ) { + $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].','.$tag['length'].',true);'; + }elseif(isset($tag['offset']) && '' !=$tag['offset']){ + $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].',null,true);'; + }else{ + $parseStr .= ' $__LIST__ = '.$name.';'; + } + $parseStr .= 'if( count($__LIST__)==0 ) : echo "'.$empty.'" ;'; + $parseStr .= 'else: '; + $parseStr .= 'foreach($__LIST__ as $key=>$'.$id.'): '; + $parseStr .= '$mod = ($'.$key.' % '.$mod.' );'; + $parseStr .= '++$'.$key.';?>'; + $parseStr .= $this->tpl->parse($content); + $parseStr .= ''; + $_iterateParseCache[$cacheIterateId] = $parseStr; + + if(!empty($parseStr)) { + return $parseStr; + } + return ; + } + + /** + * foreach标签解析 循环输出数据集 + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string|void + */ + public function _foreach($attr,$content) { + static $_iterateParseCache = array(); + //如果已经解析过,则直接返回变量值 + $cacheIterateId = md5($attr.$content); + if(isset($_iterateParseCache[$cacheIterateId])) + return $_iterateParseCache[$cacheIterateId]; + $tag = $this->parseXmlAttr($attr,'foreach'); + $name = $tag['name']; + $item = $tag['item']; + $key = !empty($tag['key'])?$tag['key']:'key'; + $name = $this->autoBuildVar($name); + $parseStr = '$'.$item.'): ?>'; + $parseStr .= $this->tpl->parse($content); + $parseStr .= ''; + $_iterateParseCache[$cacheIterateId] = $parseStr; + if(!empty($parseStr)) { + return $parseStr; + } + return ; + } + + /** + * if标签解析 + * 格式: + * + * + * + * + * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || && + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _if($attr,$content) { + $tag = $this->parseXmlAttr($attr,'if'); + $condition = $this->parseCondition($tag['condition']); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * else标签解析 + * 格式:见if标签 + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _elseif($attr,$content) { + $tag = $this->parseXmlAttr($attr,'elseif'); + $condition = $this->parseCondition($tag['condition']); + $parseStr = ''; + return $parseStr; + } + + /** + * else标签解析 + * @access public + * @param string $attr 标签属性 + * @return string + */ + public function _else($attr) { + $parseStr = ''; + return $parseStr; + } + + /** + * switch标签解析 + * 格式: + * + * 1 + * 2 + * other + * + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _switch($attr,$content) { + $tag = $this->parseXmlAttr($attr,'switch'); + $name = $tag['name']; + $varArray = explode('|',$name); + $name = array_shift($varArray); + $name = $this->autoBuildVar($name); + if(count($varArray)>0) + $name = $this->tpl->parseVarFunction($name,$varArray); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * case标签解析 需要配合switch才有效 + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _case($attr,$content) { + $tag = $this->parseXmlAttr($attr,'case'); + $value = $tag['value']; + if('$' == substr($value,0,1)) { + $varArray = explode('|',$value); + $value = array_shift($varArray); + $value = $this->autoBuildVar(substr($value,1)); + if(count($varArray)>0) + $value = $this->tpl->parseVarFunction($value,$varArray); + $value = 'case '.$value.': '; + }elseif(strpos($value,'|')){ + $values = explode('|',$value); + $value = ''; + foreach ($values as $val){ + $value .= 'case "'.addslashes($val).'": '; + } + }else{ + $value = 'case "'.$value.'": '; + } + $parseStr = ''.$content; + $isBreak = isset($tag['break']) ? $tag['break'] : ''; + if('' ==$isBreak || $isBreak) { + $parseStr .= ''; + } + return $parseStr; + } + + /** + * default标签解析 需要配合switch才有效 + * 使用: ddfdf + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _default($attr) { + $parseStr = ''; + return $parseStr; + } + + /** + * compare标签解析 + * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq + * 格式: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _compare($attr,$content,$type='eq') { + $tag = $this->parseXmlAttr($attr,'compare'); + $name = $tag['name']; + $value = $tag['value']; + $type = isset($tag['type'])?$tag['type']:$type; + $type = $this->parseCondition(' '.$type.' '); + $varArray = explode('|',$name); + $name = array_shift($varArray); + $name = $this->autoBuildVar($name); + if(count($varArray)>0) + $name = $this->tpl->parseVarFunction($name,$varArray); + if('$' == substr($value,0,1)) { + $value = $this->autoBuildVar(substr($value,1)); + }else { + $value = '"'.$value.'"'; + } + $parseStr = ''.$content.''; + return $parseStr; + } + + public function _eq($attr,$content) { + return $this->_compare($attr,$content,'eq'); + } + + public function _equal($attr,$content) { + return $this->_compare($attr,$content,'eq'); + } + + public function _neq($attr,$content) { + return $this->_compare($attr,$content,'neq'); + } + + public function _notequal($attr,$content) { + return $this->_compare($attr,$content,'neq'); + } + + public function _gt($attr,$content) { + return $this->_compare($attr,$content,'gt'); + } + + public function _lt($attr,$content) { + return $this->_compare($attr,$content,'lt'); + } + + public function _egt($attr,$content) { + return $this->_compare($attr,$content,'egt'); + } + + public function _elt($attr,$content) { + return $this->_compare($attr,$content,'elt'); + } + + public function _heq($attr,$content) { + return $this->_compare($attr,$content,'heq'); + } + + public function _nheq($attr,$content) { + return $this->_compare($attr,$content,'nheq'); + } + + /** + * range标签解析 + * 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外 + * 格式: content + * example: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @param string $type 比较类型 + * @return string + */ + public function _range($attr,$content,$type='in') { + $tag = $this->parseXmlAttr($attr,'range'); + $name = $tag['name']; + $value = $tag['value']; + $varArray = explode('|',$name); + $name = array_shift($varArray); + $name = $this->autoBuildVar($name); + if(count($varArray)>0) + $name = $this->tpl->parseVarFunction($name,$varArray); + + $type = isset($tag['type'])?$tag['type']:$type; + + if('$' == substr($value,0,1)) { + $value = $this->autoBuildVar(substr($value,1)); + $str = 'is_array('.$value.')?'.$value.':explode(\',\','.$value.')'; + }else{ + $value = '"'.$value.'"'; + $str = 'explode(\',\','.$value.')'; + } + if($type=='between') { + $parseStr = '= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.''; + }elseif($type=='notbetween'){ + $parseStr = '$_RANGE_VAR_[1]):?>'.$content.''; + }else{ + $fun = ($type == 'in')? 'in_array' : '!in_array'; + $parseStr = ''.$content.''; + } + return $parseStr; + } + + // range标签的别名 用于in判断 + public function _in($attr,$content) { + return $this->_range($attr,$content,'in'); + } + + // range标签的别名 用于notin判断 + public function _notin($attr,$content) { + return $this->_range($attr,$content,'notin'); + } + + public function _between($attr,$content){ + return $this->_range($attr,$content,'between'); + } + + public function _notbetween($attr,$content){ + return $this->_range($attr,$content,'notbetween'); + } + + /** + * present标签解析 + * 如果某个变量已经设置 则输出内容 + * 格式: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _present($attr,$content) { + $tag = $this->parseXmlAttr($attr,'present'); + $name = $tag['name']; + $name = $this->autoBuildVar($name); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * notpresent标签解析 + * 如果某个变量没有设置,则输出内容 + * 格式: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _notpresent($attr,$content) { + $tag = $this->parseXmlAttr($attr,'notpresent'); + $name = $tag['name']; + $name = $this->autoBuildVar($name); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * empty标签解析 + * 如果某个变量为empty 则输出内容 + * 格式: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _empty($attr,$content) { + $tag = $this->parseXmlAttr($attr,'empty'); + $name = $tag['name']; + $name = $this->autoBuildVar($name); + $parseStr = ''.$content.''; + return $parseStr; + } + + public function _notempty($attr,$content) { + $tag = $this->parseXmlAttr($attr,'notempty'); + $name = $tag['name']; + $name = $this->autoBuildVar($name); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * 判断是否已经定义了该常量 + * 已定义 + * @param $attr + * @param $content + * @return string + */ + public function _defined($attr,$content) { + $tag = $this->parseXmlAttr($attr,'defined'); + $name = $tag['name']; + $parseStr = ''.$content.''; + return $parseStr; + } + + public function _notdefined($attr,$content) { + $tag = $this->parseXmlAttr($attr,'_notdefined'); + $name = $tag['name']; + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * import 标签解析 + * + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @param boolean $isFile 是否文件方式 + * @param string $type 类型 + * @return string + */ + public function _import($attr,$content,$isFile=false,$type='') { + $tag = $this->parseXmlAttr($attr,'import'); + $file = isset($tag['file'])?$tag['file']:$tag['href']; + $parseStr = ''; + $endStr = ''; + // 判断是否存在加载条件 允许使用函数判断(默认为isset) + if (isset($tag['value'])) { + $varArray = explode('|',$tag['value']); + $name = array_shift($varArray); + $name = $this->autoBuildVar($name); + if (!empty($varArray)) + $name = $this->tpl->parseVarFunction($name,$varArray); + else + $name = 'isset('.$name.')'; + $parseStr .= ''; + $endStr = ''; + } + if($isFile) { + // 根据文件名后缀自动识别 + $type = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):null); + // 文件方式导入 + $array = explode(',',$file); + foreach ($array as $val){ + if (!$type || isset($reset)) { + $type = $reset = strtolower(substr(strrchr($val, '.'),1)); + } + switch($type) { + case 'js': + $parseStr .= ''; + break; + case 'css': + $parseStr .= ''; + break; + case 'php': + $parseStr .= ''; + break; + } + } + }else{ + // 命名空间导入模式 默认是js + $type = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):'js'); + $basepath = !empty($tag['basepath'])?$tag['basepath']:__ROOT__.'/Public'; + // 命名空间方式导入外部文件 + $array = explode(',',$file); + foreach ($array as $val){ + list($val,$version) = explode('?',$val); + switch($type) { + case 'js': + $parseStr .= ''; + break; + case 'css': + $parseStr .= ''; + break; + case 'php': + $parseStr .= ''; + break; + } + } + } + return $parseStr.$endStr; + } + + // import别名 采用文件方式加载(要使用命名空间必须用import) 例如 + public function _load($attr,$content) { + return $this->_import($attr,$content,true); + } + + // import别名使用 导入css文件 + public function _css($attr,$content) { + return $this->_import($attr,$content,true,'css'); + } + + // import别名使用 导入js文件 + public function _js($attr,$content) { + return $this->_import($attr,$content,true,'js'); + } + + /** + * assign标签解析 + * 在模板中给某个变量赋值 支持变量赋值 + * 格式: + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _assign($attr,$content) { + $tag = $this->parseXmlAttr($attr,'assign'); + $name = $this->autoBuildVar($tag['name']); + if('$'==substr($tag['value'],0,1)) { + $value = $this->autoBuildVar(substr($tag['value'],1)); + }else{ + $value = '\''.$tag['value']. '\''; + } + $parseStr = ''; + return $parseStr; + } + + /** + * define标签解析 + * 在模板中定义常量 支持变量赋值 + * 格式: + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _define($attr,$content) { + $tag = $this->parseXmlAttr($attr,'define'); + $name = '\''.$tag['name']. '\''; + if('$'==substr($tag['value'],0,1)) { + $value = $this->autoBuildVar(substr($tag['value'],1)); + }else{ + $value = '\''.$tag['value']. '\''; + } + $parseStr = ''; + return $parseStr; + } + + /** + * for标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _for($attr, $content){ + //设置默认值 + $start = 0; + $end = 0; + $step = 1; + $comparison = 'lt'; + $name = 'i'; + $rand = rand(); //添加随机数,防止嵌套变量冲突 + //获取属性 + foreach ($this->parseXmlAttr($attr, 'for') as $key => $value){ + $value = trim($value); + if(':'==substr($value,0,1)) + $value = substr($value,1); + elseif('$'==substr($value,0,1)) + $value = $this->autoBuildVar(substr($value,1)); + switch ($key){ + case 'start': + $start = $value; break; + case 'end' : + $end = $value; break; + case 'step': + $step = $value; break; + case 'comparison': + $comparison = $value; break; + case 'name': + $name = $value; break; + } + } + + $parseStr = 'parseCondition('$'.$name.' '.$comparison.' $__FOR_END_'.$rand.'__').';$'.$name.'+='.$step.'){ ?>'; + $parseStr .= $content; + $parseStr .= ''; + return $parseStr; + } + + } diff --git a/ThinkPHP/Lib/Template/TagLib.class.php b/ThinkPHP/Lib/Template/TagLib.class.php new file mode 100644 index 0000000..ea3993c --- /dev/null +++ b/ThinkPHP/Lib/Template/TagLib.class.php @@ -0,0 +1,231 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP标签库TagLib解析基类 + * @category Think + * @package Think + * @subpackage Template + * @author liu21st + */ +class TagLib { + + /** + * 标签库定义XML文件 + * @var string + * @access protected + */ + protected $xml = ''; + protected $tags = array();// 标签定义 + /** + * 标签库名称 + * @var string + * @access protected + */ + protected $tagLib =''; + + /** + * 标签库标签列表 + * @var string + * @access protected + */ + protected $tagList = array(); + + /** + * 标签库分析数组 + * @var string + * @access protected + */ + protected $parse = array(); + + /** + * 标签库是否有效 + * @var string + * @access protected + */ + protected $valid = false; + + /** + * 当前模板对象 + * @var object + * @access protected + */ + protected $tpl; + + protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < '); + + /** + * 架构函数 + * @access public + */ + public function __construct() { + $this->tagLib = strtolower(substr(get_class($this),6)); + $this->tpl = Think::instance('ThinkTemplate'); + } + + /** + * TagLib标签属性分析 返回标签属性数组 + * @access public + * @param string $tagStr 标签内容 + * @return array + */ + public function parseXmlAttr($attr,$tag) { + //XML解析安全过滤 + $attr = str_replace('&','___', $attr); + $xml = ''; + $xml = simplexml_load_string($xml); + if(!$xml) { + throw_exception(L('_XML_TAG_ERROR_').' : '.$attr); + } + $xml = (array)($xml->tag->attributes()); + $array = array_change_key_case($xml['@attributes']); + if($array) { + $attrs = explode(',',$this->tags[strtolower($tag)]['attr']); + if(isset($this->tags[strtolower($tag)]['must'])){ + $must = explode(',',$this->tags[strtolower($tag)]['must']); + }else{ + $must = array(); + } + foreach($attrs as $name) { + if( isset($array[$name])) { + $array[$name] = str_replace('___','&',$array[$name]); + }elseif(false !== array_search($name,$must)){ + throw_exception(L('_PARAM_ERROR_').':'.$name); + } + } + return $array; + } + } + + /** + * 解析条件表达式 + * @access public + * @param string $condition 表达式标签内容 + * @return array + */ + public function parseCondition($condition) { + $condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition); + $condition = preg_replace('/\$(\w+):(\w+)\s/is','$\\1->\\2 ',$condition); + switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { + case 'array': // 识别为数组 + $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition); + break; + case 'obj': // 识别为对象 + $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1->\\2 ',$condition); + break; + default: // 自动判断数组或对象 只支持二维 + $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition); + } + if(false !== strpos($condition, '$Think')) + $condition = preg_replace('/(\$Think.*?)\s/ies',"\$this->parseThinkVar('\\1');" , $condition); + return $condition; + } + + /** + * 自动识别构建变量 + * @access public + * @param string $name 变量描述 + * @return string + */ + public function autoBuildVar($name) { + if('Think.' == substr($name,0,6)){ + // 特殊变量 + return $this->parseThinkVar($name); + }elseif(strpos($name,'.')) { + $vars = explode('.',$name); + $var = array_shift($vars); + switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { + case 'array': // 识别为数组 + $name = '$'.$var; + foreach ($vars as $key=>$val){ + if(0===strpos($val,'$')) { + $name .= '["{'.$val.'}"]'; + }else{ + $name .= '["'.$val.'"]'; + } + } + break; + case 'obj': // 识别为对象 + $name = '$'.$var; + foreach ($vars as $key=>$val) + $name .= '->'.$val; + break; + default: // 自动判断数组或对象 只支持二维 + $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0]; + } + }elseif(strpos($name,':')){ + // 额外的对象方式支持 + $name = '$'.str_replace(':','->',$name); + }elseif(!defined($name)) { + $name = '$'.$name; + } + return $name; + } + + /** + * 用于标签属性里面的特殊模板变量解析 + * 格式 以 Think. 打头的变量属于特殊模板变量 + * @access public + * @param string $varStr 变量字符串 + * @return string + */ + public function parseThinkVar($varStr){ + $vars = explode('.',$varStr); + $vars[1] = strtoupper(trim($vars[1])); + $parseStr = ''; + if(count($vars)>=3){ + $vars[2] = trim($vars[2]); + switch($vars[1]){ + case 'SERVER': $parseStr = '$_SERVER[\''.$vars[2].'\']';break; + case 'GET': $parseStr = '$_GET[\''.$vars[2].'\']';break; + case 'POST': $parseStr = '$_POST[\''.$vars[2].'\']';break; + case 'COOKIE': + if(isset($vars[3])) { + $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']'; + }elseif(C('COOKIE_PREFIX')){ + $parseStr = '$_COOKIE[\''.C('COOKIE_PREFIX').$vars[2].'\']'; + }else{ + $parseStr = '$_COOKIE[\''.$vars[2].'\']'; + } + break; + case 'SESSION': + if(isset($vars[3])) { + $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']'; + }elseif(C('SESSION_PREFIX')){ + $parseStr = '$_SESSION[\''.C('SESSION_PREFIX').'\'][\''.$vars[2].'\']'; + }else{ + $parseStr = '$_SESSION[\''.$vars[2].'\']'; + } + break; + case 'ENV': $parseStr = '$_ENV[\''.$vars[2].'\']';break; + case 'REQUEST': $parseStr = '$_REQUEST[\''.$vars[2].'\']';break; + case 'CONST': $parseStr = strtoupper($vars[2]);break; + case 'LANG': $parseStr = 'L("'.$vars[2].'")';break; + case 'CONFIG': $parseStr = 'C("'.$vars[2].'")';break; + } + }else if(count($vars)==2){ + switch($vars[1]){ + case 'NOW': $parseStr = "date('Y-m-d g:i a',time())";break; + case 'VERSION': $parseStr = 'THINK_VERSION';break; + case 'TEMPLATE':$parseStr = 'C("TEMPLATE_NAME")';break; + case 'LDELIM': $parseStr = 'C("TMPL_L_DELIM")';break; + case 'RDELIM': $parseStr = 'C("TMPL_R_DELIM")';break; + default: if(defined($vars[1])) $parseStr = $vars[1]; + } + } + return $parseStr; + } + + // 获取标签定义 + public function getTags(){ + return $this->tags; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Template/ThinkTemplate.class.php b/ThinkPHP/Lib/Template/ThinkTemplate.class.php new file mode 100644 index 0000000..c976852 --- /dev/null +++ b/ThinkPHP/Lib/Template/ThinkTemplate.class.php @@ -0,0 +1,699 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP内置模板引擎类 + * 支持XML标签和普通标签的模板解析 + * 编译型模板引擎 支持动态缓存 + * @category Think + * @package Think + * @subpackage Template + * @author liu21st + */ +class ThinkTemplate { + + // 模板页面中引入的标签库列表 + protected $tagLib = array(); + // 当前模板文件 + protected $templateFile = ''; + // 模板变量 + public $tVar = array(); + public $config = array(); + private $literal = array(); + private $block = array(); + + /** + * 架构函数 + * @access public + */ + public function __construct(){ + $this->config['cache_path'] = C('CACHE_PATH'); + $this->config['template_suffix'] = C('TMPL_TEMPLATE_SUFFIX'); + $this->config['cache_suffix'] = C('TMPL_CACHFILE_SUFFIX'); + $this->config['tmpl_cache'] = C('TMPL_CACHE_ON'); + $this->config['cache_time'] = C('TMPL_CACHE_TIME'); + $this->config['taglib_begin'] = $this->stripPreg(C('TAGLIB_BEGIN')); + $this->config['taglib_end'] = $this->stripPreg(C('TAGLIB_END')); + $this->config['tmpl_begin'] = $this->stripPreg(C('TMPL_L_DELIM')); + $this->config['tmpl_end'] = $this->stripPreg(C('TMPL_R_DELIM')); + $this->config['default_tmpl'] = C('TEMPLATE_NAME'); + $this->config['layout_item'] = C('TMPL_LAYOUT_ITEM'); + } + + private function stripPreg($str) { + return str_replace( + array('{','}','(',')','|','[',']','-','+','*','.','^','?'), + array('\{','\}','\(','\)','\|','\[','\]','\-','\+','\*','\.','\^','\?'), + $str); + } + + // 模板变量获取和设置 + public function get($name) { + if(isset($this->tVar[$name])) + return $this->tVar[$name]; + else + return false; + } + + public function set($name,$value) { + $this->tVar[$name]= $value; + } + + /** + * 加载模板 + * @access public + * @param string $tmplTemplateFile 模板文件 + * @param array $templateVar 模板变量 + * @param string $prefix 模板标识前缀 + * @return void + */ + public function fetch($templateFile,$templateVar,$prefix='') { + $this->tVar = $templateVar; + $templateCacheFile = $this->loadTemplate($templateFile,$prefix); + // 模板阵列变量分解成为独立变量 + extract($templateVar, EXTR_OVERWRITE); + //载入模版缓存文件 + include $templateCacheFile; + } + + /** + * 加载主模板并缓存 + * @access public + * @param string $tmplTemplateFile 模板文件 + * @param string $prefix 模板标识前缀 + * @return string + * @throws ThinkExecption + */ + public function loadTemplate ($tmplTemplateFile,$prefix='') { + if(is_file($tmplTemplateFile)) { + $this->templateFile = $tmplTemplateFile; + // 读取模板文件内容 + $tmplContent = file_get_contents($tmplTemplateFile); + }else{ + $tmplContent = $tmplTemplateFile; + } + // 根据模版文件名定位缓存文件 + $tmplCacheFile = $this->config['cache_path'].$prefix.md5($tmplTemplateFile).$this->config['cache_suffix']; + + // 判断是否启用布局 + if(C('LAYOUT_ON')) { + if(false !== strpos($tmplContent,'{__NOLAYOUT__}')) { // 可以单独定义不使用布局 + $tmplContent = str_replace('{__NOLAYOUT__}','',$tmplContent); + }else{ // 替换布局的主体内容 + $layoutFile = THEME_PATH.C('LAYOUT_NAME').$this->config['template_suffix']; + $tmplContent = str_replace($this->config['layout_item'],$tmplContent,file_get_contents($layoutFile)); + } + } + // 编译模板内容 + $tmplContent = $this->compiler($tmplContent); + // 检测模板目录 + $dir = dirname($tmplCacheFile); + if(!is_dir($dir)) + mkdir($dir,0755,true); + //重写Cache文件 + if( false === file_put_contents($tmplCacheFile,trim($tmplContent))) + throw_exception(L('_CACHE_WRITE_ERROR_').':'.$tmplCacheFile); + return $tmplCacheFile; + } + + /** + * 编译模板文件内容 + * @access protected + * @param mixed $tmplContent 模板内容 + * @return string + */ + protected function compiler($tmplContent) { + //模板解析 + $tmplContent = $this->parse($tmplContent); + // 还原被替换的Literal标签 + $tmplContent = preg_replace('//eis',"\$this->restoreLiteral('\\1')",$tmplContent); + // 添加安全代码 + $tmplContent = ''.$tmplContent; + if(C('TMPL_STRIP_SPACE')) { + /* 去除html空格与换行 */ + $find = array('~>\s+<~','~>(\s+\n|\r)~'); + $replace = array('><','>'); + $tmplContent = preg_replace($find, $replace, $tmplContent); + } + // 优化生成的php代码 + $tmplContent = str_replace('?>config['taglib_begin']; + $end = $this->config['taglib_end']; + // 检查include语法 + $content = $this->parseInclude($content); + // 检查PHP语法 + $content = $this->parsePhp($content); + // 首先替换literal标签内容 + $content = preg_replace('/'.$begin.'literal'.$end.'(.*?)'.$begin.'\/literal'.$end.'/eis',"\$this->parseLiteral('\\1')",$content); + + // 获取需要引入的标签库列表 + // 标签库只需要定义一次,允许引入多个一次 + // 一般放在文件的最前面 + // 格式: + // 当TAGLIB_LOAD配置为true时才会进行检测 + if(C('TAGLIB_LOAD')) { + $this->getIncludeTagLib($content); + if(!empty($this->tagLib)) { + // 对导入的TagLib进行解析 + foreach($this->tagLib as $tagLibName) { + $this->parseTagLib($tagLibName,$content); + } + } + } + // 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀 + if(C('TAGLIB_PRE_LOAD')) { + $tagLibs = explode(',',C('TAGLIB_PRE_LOAD')); + foreach ($tagLibs as $tag){ + $this->parseTagLib($tag,$content); + } + } + // 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀 + $tagLibs = explode(',',C('TAGLIB_BUILD_IN')); + foreach ($tagLibs as $tag){ + $this->parseTagLib($tag,$content,true); + } + //解析普通模板标签 {tagName} + $content = preg_replace('/('.$this->config['tmpl_begin'].')([^\d\s'.$this->config['tmpl_begin'].$this->config['tmpl_end'].'].+?)('.$this->config['tmpl_end'].')/eis',"\$this->parseTag('\\2')",$content); + return $content; + } + + // 检查PHP语法 + protected function parsePhp($content) { + if(ini_get('short_open_tag')){ + // 开启短标签的情况要将'."\n", $content ); + } + // PHP语法检查 + if(C('TMPL_DENY_PHP') && false !== strpos($content,'config['taglib_begin'].'layout\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches); + if($find) { + //替换Layout标签 + $content = str_replace($matches[0],'',$content); + //解析Layout标签 + $array = $this->parseXmlAttrs($matches[1]); + if(!C('LAYOUT_ON') || C('LAYOUT_NAME') !=$array['name'] ) { + // 读取布局模板 + $layoutFile = THEME_PATH.$array['name'].$this->config['template_suffix']; + $replace = isset($array['replace'])?$array['replace']:$this->config['layout_item']; + // 替换布局的主体内容 + $content = str_replace($replace,$content,file_get_contents($layoutFile)); + } + }else{ + $content = str_replace('{__NOLAYOUT__}','',$content); + } + return $content; + } + + // 解析模板中的include标签 + protected function parseInclude($content) { + // 解析继承 + $content = $this->parseExtend($content); + // 解析布局 + $content = $this->parseLayout($content); + // 读取模板中的include标签 + $find = preg_match_all('/'.$this->config['taglib_begin'].'include\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches); + if($find) { + for($i=0;$i<$find;$i++) { + $include = $matches[1][$i]; + $array = $this->parseXmlAttrs($include); + $file = $array['file']; + unset($array['file']); + $content = str_replace($matches[0][$i],$this->parseIncludeItem($file,$array),$content); + } + } + return $content; + } + + // 解析模板中的extend标签 + protected function parseExtend($content) { + $begin = $this->config['taglib_begin']; + $end = $this->config['taglib_end']; + // 读取模板中的继承标签 + $find = preg_match('/'.$begin.'extend\s(.+?)\s*?\/'.$end.'/is',$content,$matches); + if($find) { + //替换extend标签 + $content = str_replace($matches[0],'',$content); + // 记录页面中的block标签 + preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"\$this->parseBlock('\\1','\\2')",$content); + // 读取继承模板 + $array = $this->parseXmlAttrs($matches[1]); + $content = $this->parseTemplateName($array['name']); + // 替换block标签 + $content = preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"\$this->replaceBlock('\\1','\\2')",$content); + }else{ + $content = preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"stripslashes('\\2')",$content); + } + return $content; + } + + /** + * 分析XML属性 + * @access private + * @param string $attrs XML属性字符串 + * @return array + */ + private function parseXmlAttrs($attrs) { + $xml = ''; + $xml = simplexml_load_string($xml); + if(!$xml) + throw_exception(L('_XML_TAG_ERROR_')); + $xml = (array)($xml->tag->attributes()); + $array = array_change_key_case($xml['@attributes']); + return $array; + } + + /** + * 替换页面中的literal标签 + * @access private + * @param string $content 模板内容 + * @return string|false + */ + private function parseLiteral($content) { + if(trim($content)=='') return ''; + $content = stripslashes($content); + $i = count($this->literal); + $parseStr = ""; + $this->literal[$i] = $content; + return $parseStr; + } + + /** + * 还原被替换的literal标签 + * @access private + * @param string $tag literal标签序号 + * @return string|false + */ + private function restoreLiteral($tag) { + // 还原literal标签 + $parseStr = $this->literal[$tag]; + // 销毁literal记录 + unset($this->literal[$tag]); + return $parseStr; + } + + /** + * 记录当前页面中的block标签 + * @access private + * @param string $name block名称 + * @param string $content 模板内容 + * @return string + */ + private function parseBlock($name,$content) { + $this->block[$name] = $content; + return ''; + } + + /** + * 替换继承模板中的block标签 + * @access private + * @param string $name block名称 + * @param string $content 模板内容 + * @return string + */ + private function replaceBlock($name,$content) { + // 替换block标签 没有重新定义则使用原来的 + $replace = isset($this->block[$name])? $this->block[$name] : $content; + return stripslashes($replace); + } + + /** + * 搜索模板页面中包含的TagLib库 + * 并返回列表 + * @access public + * @param string $content 模板内容 + * @return string|false + */ + public function getIncludeTagLib(& $content) { + //搜索是否有TagLib标签 + $find = preg_match('/'.$this->config['taglib_begin'].'taglib\s(.+?)(\s*?)\/'.$this->config['taglib_end'].'\W/is',$content,$matches); + if($find) { + //替换TagLib标签 + $content = str_replace($matches[0],'',$content); + //解析TagLib标签 + $array = $this->parseXmlAttrs($matches[1]); + $this->tagLib = explode(',',$array['name']); + } + return; + } + + /** + * TagLib库解析 + * @access public + * @param string $tagLib 要解析的标签库 + * @param string $content 要解析的模板内容 + * @param boolen $hide 是否隐藏标签库前缀 + * @return string + */ + public function parseTagLib($tagLib,&$content,$hide=false) { + $begin = $this->config['taglib_begin']; + $end = $this->config['taglib_end']; + $className = 'TagLib'.ucwords($tagLib); + $tLib = Think::instance($className); + foreach ($tLib->getTags() as $name=>$val){ + $tags = array($name); + if(isset($val['alias'])) {// 别名设置 + $tags = explode(',',$val['alias']); + $tags[] = $name; + } + $level = isset($val['level'])?$val['level']:1; + $closeTag = isset($val['close'])?$val['close']:true; + foreach ($tags as $tag){ + $parseTag = !$hide? $tagLib.':'.$tag: $tag;// 实际要解析的标签名称 + if(!method_exists($tLib,'_'.$tag)) { + // 别名可以无需定义解析方法 + $tag = $name; + } + $n1 = empty($val['attr'])?'(\s*?)':'\s([^'.$end.']*)'; + if (!$closeTag){ + $patterns = '/'.$begin.$parseTag.$n1.'\/(\s*?)'.$end.'/eis'; + $replacement = "\$this->parseXmlTag('$tagLib','$tag','$1','')"; + $content = preg_replace($patterns, $replacement,$content); + }else{ + $patterns = '/'.$begin.$parseTag.$n1.$end.'(.*?)'.$begin.'\/'.$parseTag.'(\s*?)'.$end.'/eis'; + $replacement = "\$this->parseXmlTag('$tagLib','$tag','$1','$2')"; + for($i=0;$i<$level;$i++) + $content=preg_replace($patterns,$replacement,$content); + } + } + } + } + + /** + * 解析标签库的标签 + * 需要调用对应的标签库文件解析类 + * @access public + * @param string $tagLib 标签库名称 + * @param string $tag 标签名 + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string|false + */ + public function parseXmlTag($tagLib,$tag,$attr,$content) { + //if (MAGIC_QUOTES_GPC) { + $attr = stripslashes($attr); + $content= stripslashes($content); + //} + if(ini_get('magic_quotes_sybase')) + $attr = str_replace('\"','\'',$attr); + $tLib = Think::instance('TagLib'.ucwords(strtolower($tagLib))); + $parse = '_'.$tag; + $content = trim($content); + return $tLib->$parse($attr,$content); + } + + /** + * 模板标签解析 + * 格式: {TagName:args [|content] } + * @access public + * @param string $tagStr 标签内容 + * @return string + */ + public function parseTag($tagStr){ + //if (MAGIC_QUOTES_GPC) { + $tagStr = stripslashes($tagStr); + //} + //还原非模板标签 + if(preg_match('/^[\s|\d]/is',$tagStr)) + //过滤空格和数字打头的标签 + return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM'); + $flag = substr($tagStr,0,1); + $flag2 = substr($tagStr,1,1); + $name = substr($tagStr,1); + if('$' == $flag && '.' != $flag2 && '(' != $flag2){ //解析模板变量 格式 {$varName} + return $this->parseVar($name); + }elseif('-' == $flag || '+'== $flag){ // 输出计算 + return ''; + }elseif(':' == $flag){ // 输出某个函数的结果 + return ''; + }elseif('~' == $flag){ // 执行某个函数 + return ''; + }elseif(substr($tagStr,0,2)=='//' || (substr($tagStr,0,2)=='/*' && substr($tagStr,-2)=='*/')){ + //注释标签 + return ''; + } + // 未识别的标签直接返回 + return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM'); + } + + /** + * 模板变量解析,支持使用函数 + * 格式: {$varname|function1|function2=arg1,arg2} + * @access public + * @param string $varStr 变量数据 + * @return string + */ + public function parseVar($varStr){ + $varStr = trim($varStr); + static $_varParseList = array(); + //如果已经解析过该变量字串,则直接返回变量值 + if(isset($_varParseList[$varStr])) return $_varParseList[$varStr]; + $parseStr = ''; + $varExists = true; + if(!empty($varStr)){ + $varArray = explode('|',$varStr); + //取得变量名称 + $var = array_shift($varArray); + if('Think.' == substr($var,0,6)){ + // 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出 + $name = $this->parseThinkVar($var); + }elseif( false !== strpos($var,'.')) { + //支持 {$var.property} + $vars = explode('.',$var); + $var = array_shift($vars); + switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { + case 'array': // 识别为数组 + $name = '$'.$var; + foreach ($vars as $key=>$val) + $name .= '["'.$val.'"]'; + break; + case 'obj': // 识别为对象 + $name = '$'.$var; + foreach ($vars as $key=>$val) + $name .= '->'.$val; + break; + default: // 自动判断数组或对象 只支持二维 + $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0]; + } + }elseif(false !== strpos($var,'[')) { + //支持 {$var['key']} 方式输出数组 + $name = "$".$var; + preg_match('/(.+?)\[(.+?)\]/is',$var,$match); + $var = $match[1]; + }elseif(false !==strpos($var,':') && false ===strpos($var,'(') && false ===strpos($var,'::') && false ===strpos($var,'?')){ + //支持 {$var:property} 方式输出对象的属性 + $vars = explode(':',$var); + $var = str_replace(':','->',$var); + $name = "$".$var; + $var = $vars[0]; + }else { + $name = "$$var"; + } + //对变量使用函数 + if(count($varArray)>0) + $name = $this->parseVarFunction($name,$varArray); + $parseStr = ''; + } + $_varParseList[$varStr] = $parseStr; + return $parseStr; + } + + /** + * 对模板变量使用函数 + * 格式 {$varname|function1|function2=arg1,arg2} + * @access public + * @param string $name 变量名 + * @param array $varArray 函数列表 + * @return string + */ + public function parseVarFunction($name,$varArray){ + //对变量使用函数 + $length = count($varArray); + //取得模板禁止使用函数列表 + $template_deny_funs = explode(',',C('TMPL_DENY_FUNC_LIST')); + for($i=0;$i<$length ;$i++ ){ + $args = explode('=',$varArray[$i],2); + //模板函数过滤 + $fun = strtolower(trim($args[0])); + switch($fun) { + case 'default': // 特殊模板函数 + $name = '('.$name.')?('.$name.'):'.$args[1]; + break; + default: // 通用模板函数 + if(!in_array($fun,$template_deny_funs)){ + if(isset($args[1])){ + if(strstr($args[1],'###')){ + $args[1] = str_replace('###',$name,$args[1]); + $name = "$fun($args[1])"; + }else{ + $name = "$fun($name,$args[1])"; + } + }else if(!empty($args[0])){ + $name = "$fun($name)"; + } + } + } + } + return $name; + } + + /** + * 特殊模板变量解析 + * 格式 以 $Think. 打头的变量属于特殊模板变量 + * @access public + * @param string $varStr 变量字符串 + * @return string + */ + public function parseThinkVar($varStr){ + $vars = explode('.',$varStr); + $vars[1] = strtoupper(trim($vars[1])); + $parseStr = ''; + if(count($vars)>=3){ + $vars[2] = trim($vars[2]); + switch($vars[1]){ + case 'SERVER': + $parseStr = '$_SERVER[\''.strtoupper($vars[2]).'\']';break; + case 'GET': + $parseStr = '$_GET[\''.$vars[2].'\']';break; + case 'POST': + $parseStr = '$_POST[\''.$vars[2].'\']';break; + case 'COOKIE': + if(isset($vars[3])) { + $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']'; + }else{ + $parseStr = 'cookie(\''.$vars[2].'\')'; + } + break; + case 'SESSION': + if(isset($vars[3])) { + $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']'; + }else{ + $parseStr = 'session(\''.$vars[2].'\')'; + } + break; + case 'ENV': + $parseStr = '$_ENV[\''.strtoupper($vars[2]).'\']';break; + case 'REQUEST': + $parseStr = '$_REQUEST[\''.$vars[2].'\']';break; + case 'CONST': + $parseStr = strtoupper($vars[2]);break; + case 'LANG': + $parseStr = 'L("'.$vars[2].'")';break; + case 'CONFIG': + if(isset($vars[3])) { + $vars[2] .= '.'.$vars[3]; + } + $parseStr = 'C("'.$vars[2].'")';break; + default:break; + } + }else if(count($vars)==2){ + switch($vars[1]){ + case 'NOW': + $parseStr = "date('Y-m-d g:i a',time())"; + break; + case 'VERSION': + $parseStr = 'THINK_VERSION'; + break; + case 'TEMPLATE': + $parseStr = "'".$this->templateFile."'";//'C("TEMPLATE_NAME")'; + break; + case 'LDELIM': + $parseStr = 'C("TMPL_L_DELIM")'; + break; + case 'RDELIM': + $parseStr = 'C("TMPL_R_DELIM")'; + break; + default: + if(defined($vars[1])) + $parseStr = $vars[1]; + } + } + return $parseStr; + } + + /** + * 加载公共模板并缓存 和当前模板在同一路径,否则使用相对路径 + * @access private + * @param string $tmplPublicName 公共模板文件名 + * @param array $vars 要传递的变量列表 + * @return string + */ + private function parseIncludeItem($tmplPublicName,$vars=array()){ + // 分析模板文件名并读取内容 + $parseStr = $this->parseTemplateName($tmplPublicName); + // 替换变量 + foreach ($vars as $key=>$val) { + $parseStr = str_replace('['.$key.']',$val,$parseStr); + } + // 再次对包含文件进行模板分析 + return $this->parseInclude($parseStr); + } + + /** + * 分析加载的模板文件并读取内容 支持多个模板文件读取 + * @access private + * @param string $tmplPublicName 模板文件名 + * @return string + */ + private function parseTemplateName($templateName){ + if(substr($templateName,0,1)=='$') + //支持加载变量文件名 + $templateName = $this->get(substr($templateName,1)); + $array = explode(',',$templateName); + $parseStr = ''; + foreach ($array as $templateName){ + if(false === strpos($templateName,$this->config['template_suffix'])) { + // 解析规则为 分组@模板主题:模块:操作 + if(strpos($templateName,'@')){ + list($group,$templateName) = explode('@',$templateName); + if(1==C('APP_GROUP_MODE')){ + $basePath = dirname(BASE_LIB_PATH).'/'.$group.'/'.basename(TMPL_PATH).'/'.(THEME_NAME?THEME_NAME.'/':''); + }else{ + $basePath = TMPL_PATH.'/'.$group.'/'.(THEME_NAME?THEME_NAME.'/':''); + } + }else{ + $basePath = THEME_PATH; + } + $templateName = str_replace(':', '/', $templateName); + $path = explode('/',$templateName); + $action = array_pop($path); + $module = !empty($path)?array_pop($path):MODULE_NAME; + if(!empty($path)) {// 设置模板主题 + $basePath = dirname($basePath).'/'.array_pop($path).'/'; + } + $templateName = $basePath.$module.C('TMPL_FILE_DEPR').$action.$this->config['template_suffix']; + } + // 获取模板文件内容 + $parseStr .= file_get_contents($templateName); + } + return $parseStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/README.txt b/ThinkPHP/README.txt new file mode 100644 index 0000000..0b5eed3 --- /dev/null +++ b/ThinkPHP/README.txt @@ -0,0 +1,127 @@ ++------------------------------------------------------------------- +| 感谢您使用ThinkPHP开发框架 ^_^ ++------------------------------------------------------------------- +| 大道至简 开发由我 WE CAN DO IT,JUST THINK ++------------------------------------------------------------------- +| 版本信息:ThinkPHP 3.1.3 Release 2013/5/16 ++------------------------------------------------------------------- +| Copyright(c) 2006-2013 http://thinkphp.cn All rights reserved. ++------------------------------------------------------------------- + +[ 简介 ] +ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架, +遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而 +诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性 +能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在 +社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,众多 +的典型案例确保可以稳定用于商业以及门户级的开发。 + +经过6年的不断积累和重构,3.*版本在框架底层的定制和扩展方面趋于完善, +使得应用的开发范围和需求适应度更加扩大,能够满足不同程度的开发人员的 +需求。而且引入了全新的CBD(核心+行为+驱动)架构模式,旨在打造DIY框架 +和AOP编程体验,让ThinkPHP能够在不同方面都能快速满足项目和应用的需求, +并且正式引入SAE、REST和Mongo支持。 + +使用ThinkPHP,你可以更方便和快捷的开发和部署应用。当然不仅仅是企业级 +应用,任何PHP应用开发都可以从ThinkPHP的简单和快速的特性中受益。 +ThinkPHP本身具有很多的原创特性,并且倡导大道至简,开发由我的开发理念, +用最少的代码完成更多的功能,宗旨就是让WEB应用开发更简单、更快速。 +为此ThinkPHP会不断吸收和融入更好的技术以保证其新鲜和活力,提供WEB应 +用开发的最佳实践!经过6年来的不断重构和改进,ThinkPHP达到了一个新的 +阶段,能够满足企业开发中复杂的项目需求,足以达到企业级和门户级的开 +发标准。 + +[ 协议 ] +ThinkPHP遵循Apache2开源许可协议发布,意味着你可以免费使用ThinkPHP, +甚至允许把你的ThinkPHP应用采用商业闭源发布。 +具体参考LICENSE.txt内容 + +[ 特性 ] +CBD架构:ThinkPHP3.0版本引入了全新的CBD(核心+行为+驱动)架构模式, +打造框架底层DIY定制和类AOP编程体验。利用这一新的特性,开发人员可以 +方便地通过模式扩展为自己量身定制一套属于自己或者企业的开发框架。 +编译机制:独创的项目编译机制,有效减少OOP开发中文件加载的性能开销。 +改进后的项目编译机制,可以支持编译文件直接作为入口载入,并且支持常量 +外部载入,利于产品发布。 + +类库导入:采用基于类库包和命名空间的方式导入类库,让类库导入看起来更 +加简单清晰,而且还支持自动加载和别名导入。为了方便项目的跨平台移植, +系统还可以严格检查加载文件的大小写。 + +URL和路由:系统支持普通模式、PATHINFO模式、REWRITE模式和兼容模式的 +URL方式,支持不同的服务器和运行模式的部署,配合URL路由功能,让你随心 +所欲的构建需要的URL地址和进行SEO优化工作。支持灵活的规则路由和正则路 +由,以及路由重定向支持,带给开发人员更方便灵活的URL优化体验。 +调试模式:框架提供的调试模式可以方便用于开发过程的不同阶段,包括开发、 +测试和演示等任何需要的情况,不同的应用模式可以配置独立的项目配置文件。 +只是小小的性能牺牲就能满足调试开发过程中的日志和分析需要,并确保将来的 +部署顺利,一旦切换到部署模式则可以迅速提升性能。 + +ORM :简洁轻巧的ORM实现,配合简单的CURD以及AR模式,让开发效率无处不在。 + +数据库:支持包括Mysql、Sqlite、Pgsql、Oracle、SqlServer、Mongo等数据库, +并且内置分布式数据库和读写分离功能支持。系统支持多数据库连接和动态切换 +机制,犹如企业开发的一把利刃,跨数据库应用和分布式支持从此无忧。 + +查询语言:内建丰富的查询机制,包括组合查询、快捷查询、复合查询、区间 +查询、统计查询、定位查询、多表查询、子查询、动态查询和原生查询,让你的 +数据查询简洁高效。 + +动态模型:无需创建任何对应的模型类,轻松完成CURD操作,支持多种模型之间 +的动态切换,让你领略数据操作的无比畅快和最佳体验。 + +扩展模型:提供了丰富的扩展模型,包括:支持序列化字段、文本字段、只读字 +段、延迟写入、乐观锁、数据分表等高级特性的高级模型;可以轻松动态地创建 +数据库视图的视图模型;支持关联操作的关联模型;支持Mongo数据库的Mongo模 +型等等,都可以方便的使用。 + +模块分组:不用担心大项目的分工协调和部署问题,分组帮你解决跨项目的难题, +还可以支持对分组的二级域名部署支持。 + +模板引擎:系统内建了一款卓越的基于XML的编译型模板引擎,支持两种类型的 +模板标签,融合了Smarty和JSP标签库的思想,并内置布局模板功能和标签库扩展 +支持。通过驱动还可以支持Smarty、EaseTemplate、TemplateLite、Smart等其他第 +三方模板引擎。 + +AJAX支持:内置和客户端无关的AJAX数据返回方法,支持JSON、XML和EVAL类型 +返回客户端,而且可以扩展返回数据格式,系统不绑定任何AJAX类库,可随意使 +用自己熟悉的AJAX类库进行操作。 + +云引擎支持:提供了新浪SAE平台和百度BAE平台的强力支持,具备“横跨性”和“平滑性”,支持本地化 +开发和调试以及部署切换,让你轻松过渡,打造全新的开发体验。 + +RESTFul支持:REST模式提供了RESTFul支持,为你打造全新的URL设计和访问体验, +同时为接口应用提供了支持。 + +多语言支持:系统支持语言包功能,项目和分组都可以有单独的语言包,并且可以 +自动检测浏览器语言自动载入对应的语言包。 + +模式扩展:除了标准模式外,还提供了AMF、PHPRpc、Lite、Thin和Cli模式扩展支 +持,针对不同级别的应用开发提供最佳核心框架,还可以自定义模式扩展。 + +自动验证和完成:自动完成表单数据的验证和过滤,新版新增了IP验证和有效期验 +证等更多的验证方式,配合自动完成可以生成安全的数据对象。 + +字段类型检测:系统会自动缓存字段信息和字段类型,支持非法字段过滤和字段类 +型强制转换,确保数据写入和查询更安全。 + +缓存机制:系统支持包括文件方式、APC、Db、Memcache、Shmop、Sqlite、Redis、 +Eaccelerator和Xcache在内的动态数据缓存类型,以及可定制的静态缓存规则,并 +提供了快捷方法进行存取操作。 + +扩展机制:系统支持包括模式扩展、行为扩展、类库扩展、驱动扩展、模型扩展、 +控制器扩展、Widget扩展在内的强大灵活的扩展机制,让你不再受限于核心的不足 +和无所适从,随心DIY自己的框架和扩展应用,满足企业开发中更加复杂的项目需求。 + +[ 要求 ] +ThinkPHP3.1需要PHP5.2.0以上版本支持,可以运行在任何系统环境下面。 + +[ 安装 ] +ThinkPHP无需安装,下载ThinkPHP核心包或者完整版之后,把解压后的目录拷贝到 +你的WEB服务器或者WEB目录即可。 + +[ 鸣谢 ] +特别要鸣谢ThinkPHP团队和所有关注和支持ThinkPHP的用户。 + +[ 支持 ] +更多内容和支持请访问ThinkPHP官方网站http://thinkphp.cn/。 \ No newline at end of file diff --git a/ThinkPHP/ThinkPHP.php b/ThinkPHP/ThinkPHP.php new file mode 100644 index 0000000..5f49f9c --- /dev/null +++ b/ThinkPHP/ThinkPHP.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + +// ThinkPHP 入口文件 +// 记录开始运行时间 +$GLOBALS['_beginTime'] = microtime(TRUE); +// 记录内存初始使用 +define('MEMORY_LIMIT_ON',function_exists('memory_get_usage')); +if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage(); +// 系统目录定义 +defined('THINK_PATH') or define('THINK_PATH', dirname(__FILE__).'/'); +defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); +defined('APP_DEBUG') or define('APP_DEBUG',false); // 是否调试模式 +if(defined('ENGINE_NAME')) { + defined('ENGINE_PATH') or define('ENGINE_PATH',THINK_PATH.'Extend/Engine/'); + require ENGINE_PATH.strtolower(ENGINE_NAME).'.php'; +}else{ + defined('RUNTIME_PATH') or define('RUNTIME_PATH',APP_PATH.'Runtime/'); + $runtime = defined('MODE_NAME')?'~'.strtolower(MODE_NAME).'_runtime.php':'~runtime.php'; + defined('RUNTIME_FILE') or define('RUNTIME_FILE',RUNTIME_PATH.$runtime); + if(!APP_DEBUG && is_file(RUNTIME_FILE)) { + // 部署模式直接载入运行缓存 + require RUNTIME_FILE; + }else{ + // 加载运行时文件 + require THINK_PATH.'Common/runtime.php'; + } +} diff --git a/ThinkPHP/Tpl/default_index.tpl b/ThinkPHP/Tpl/default_index.tpl new file mode 100644 index 0000000..bc5bd37 --- /dev/null +++ b/ThinkPHP/Tpl/default_index.tpl @@ -0,0 +1,7 @@ +show('

    :)

    欢迎使用 ThinkPHP

    ','utf-8'); + } +} \ No newline at end of file diff --git a/ThinkPHP/Tpl/dispatch_jump.tpl b/ThinkPHP/Tpl/dispatch_jump.tpl new file mode 100644 index 0000000..585efa5 --- /dev/null +++ b/ThinkPHP/Tpl/dispatch_jump.tpl @@ -0,0 +1,44 @@ + + + + +跳转提示 + + + +
    + +

    :)

    +

    + +

    :(

    +

    +
    +

    +

    +页面自动 跳转 等待时间: +

    +
    + + + \ No newline at end of file diff --git a/ThinkPHP/Tpl/page_trace.tpl b/ThinkPHP/Tpl/page_trace.tpl new file mode 100644 index 0000000..cb7b97e --- /dev/null +++ b/ThinkPHP/Tpl/page_trace.tpl @@ -0,0 +1,67 @@ +
    + + +
    +
    + \ No newline at end of file diff --git a/ThinkPHP/Tpl/think_exception.tpl b/ThinkPHP/Tpl/think_exception.tpl new file mode 100644 index 0000000..84b27e9 --- /dev/null +++ b/ThinkPHP/Tpl/think_exception.tpl @@ -0,0 +1,53 @@ + + + +系统发生错误 + + + +
    +

    :(

    +

    +
    + +
    +
    +

    错误位置

    +
    +
    +

    FILE:  LINE:

    +
    +
    + + +
    +
    +

    TRACE

    +
    +
    +

    +
    +
    + +
    +
    + + + \ No newline at end of file diff --git a/ThinkPHP/logo.png b/ThinkPHP/logo.png new file mode 100644 index 0000000..e0b195d Binary files /dev/null and b/ThinkPHP/logo.png differ diff --git a/Todo/Conf/config.php b/Todo/Conf/config.php new file mode 100644 index 0000000..c5818e5 --- /dev/null +++ b/Todo/Conf/config.php @@ -0,0 +1,12 @@ + 'mysql', // 数据库类型 + 'DB_HOST' => 'localhost', // 服务器地址 + 'DB_NAME' => 'Todos', // 数据库名 + 'DB_USER' => 'root', // 用户名 + 'DB_PWD' => 'root', // 密码 + 'DB_PORT' => 3306, // 端口 + 'DB_PREFIX' => '', // 数据库表前缀 +); +?> \ No newline at end of file diff --git a/Todo/Lib/Action/IndexAction.class.php b/Todo/Lib/Action/IndexAction.class.php new file mode 100644 index 0000000..a8906ac --- /dev/null +++ b/Todo/Lib/Action/IndexAction.class.php @@ -0,0 +1,26 @@ +display(); + } + public function save(){ + $man = json_decode(file_get_contents("php://input"),true); + var_dump($man); + $Todos = D('Todos'); + $Todos->add($man); + } + public function fetch(){ + $all_todos = M("Todos"); + $list = $all_todos -> select(); + // var_dump($list); + foreach($list as $k=>$v){ + if($list[$k]['done'] == '0'){ + $list[$k]['done'] = false; + } + } + $this->ajaxReturn($list,'JSON'); + //die(json_encode($list)); + } +} \ No newline at end of file diff --git a/Todo/Runtime/Cache/7754dd7d835f559fb8aec999e401860a.php b/Todo/Runtime/Cache/7754dd7d835f559fb8aec999e401860a.php new file mode 100644 index 0000000..a42b275 --- /dev/null +++ b/Todo/Runtime/Cache/7754dd7d835f559fb8aec999e401860a.php @@ -0,0 +1,69 @@ + + + + + the5fire-Backbone.js-todos + + + + + + + + + + + + +
    +
    +

    Todos

    +
    +
    +
    + + +
    +
    + + +
      +
      +
      +
      +
      + + + + + + + + + \ No newline at end of file diff --git a/Todo/Runtime/Cache/9885ecc411f90bec36756701bd64bb4a.php b/Todo/Runtime/Cache/9885ecc411f90bec36756701bd64bb4a.php new file mode 100644 index 0000000..c728c1c --- /dev/null +++ b/Todo/Runtime/Cache/9885ecc411f90bec36756701bd64bb4a.php @@ -0,0 +1 @@ +

      :)

      欢迎使用 ThinkPHP

      \ No newline at end of file diff --git a/Todo/Runtime/Logs/13_10_07.log b/Todo/Runtime/Logs/13_10_07.log new file mode 100644 index 0000000..ea9afa4 --- /dev/null +++ b/Todo/Runtime/Logs/13_10_07.log @@ -0,0 +1,1901 @@ +[ 2013-10-07T17:39:18+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002333s ] +INFO: [ app_begin ] --END-- [ RunTime:0.034079s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.063129s ] +INFO: [ view_parse ] --END-- [ RunTime:0.063316s ] +INFO: [ view_filter ] --START-- +NOTIC: [8] Use of undefined constant APP_TMPL_PATH - assumed 'APP_TMPL_PATH' F:\WWW\backbone\wxyoo1-todos\ThinkPHP\Lib\Behavior\ContentReplaceBehavior.class.php 第 40 行. +NOTIC: [8] Use of undefined constant APP_TMPL_PATH - assumed 'APP_TMPL_PATH' F:\WWW\backbone\wxyoo1-todos\ThinkPHP\Lib\Behavior\ContentReplaceBehavior.class.php 第 47 行. +INFO: ContentReplace Behavior ::run [ RunTime:0.002212s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002124s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001786s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002112s ] +INFO: [ view_filter ] --END-- [ RunTime:0.008645s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.008489s ] +INFO: [ view_end ] --END-- [ RunTime:0.008617s ] + +[ 2013-10-07T17:40:17+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001560s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001692s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.048572s ] +INFO: [ view_parse ] --END-- [ RunTime:0.048744s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001711s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001645s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001170s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001473s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006301s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001874s ] +INFO: [ view_end ] --END-- [ RunTime:0.001971s ] + +[ 2013-10-07T17:40:17+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/css/todos.css +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002519s ] +INFO: [ route_check ] --END-- [ RunTime:0.002689s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001135s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001252s ] +ERR: 无法加载模块:css + +[ 2013-10-07T17:40:17+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002330s ] +INFO: [ route_check ] --END-- [ RunTime:0.002507s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002029s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002205s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:40:17+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002422s ] +INFO: [ route_check ] --END-- [ RunTime:0.002608s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002108s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002276s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:40:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000738s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000847s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.023798s ] +INFO: [ view_parse ] --END-- [ RunTime:0.023987s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001070s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001026s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000899s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001125s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004323s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001338s ] +INFO: [ view_end ] --END-- [ RunTime:0.001427s ] + +[ 2013-10-07T17:40:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002154s ] +INFO: [ route_check ] --END-- [ RunTime:0.002273s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000678s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000756s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:40:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003365s ] +INFO: [ route_check ] --END-- [ RunTime:0.003488s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000702s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000781s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:40:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/css/todos.css +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001547s ] +INFO: [ route_check ] --END-- [ RunTime:0.001722s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001103s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001237s ] +ERR: 无法加载模块:css + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000644s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000739s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.009313s ] +INFO: [ view_parse ] --END-- [ RunTime:0.009454s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000655s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000570s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000343s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000580s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002350s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.000697s ] +INFO: [ view_end ] --END-- [ RunTime:0.000756s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/css/todos.css +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000909s ] +INFO: [ route_check ] --END-- [ RunTime:0.001003s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001212s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001318s ] +ERR: 无法加载模块:css + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002966s ] +INFO: [ route_check ] --END-- [ RunTime:0.003117s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000883s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000980s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002273s ] +INFO: [ route_check ] --END-- [ RunTime:0.002692s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001808s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001927s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000674s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000772s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012109s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012227s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001006s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001277s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000879s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001418s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004752s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001206s ] +INFO: [ view_end ] --END-- [ RunTime:0.001265s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000709s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000809s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012525s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012679s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000527s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000442s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000413s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000726s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002305s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.000941s ] +INFO: [ view_end ] --END-- [ RunTime:0.001034s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000622s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000713s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.020952s ] +INFO: [ view_parse ] --END-- [ RunTime:0.021150s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001256s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001486s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001199s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001287s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005532s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001343s ] +INFO: [ view_end ] --END-- [ RunTime:0.001417s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001662s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001805s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.027303s ] +INFO: [ view_parse ] --END-- [ RunTime:0.027476s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001711s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001848s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001424s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001891s ] +INFO: [ view_filter ] --END-- [ RunTime:0.007279s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002813s ] +INFO: [ view_end ] --END-- [ RunTime:0.002931s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000993s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001139s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014472s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014652s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000616s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000621s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000484s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000731s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002770s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001011s ] +INFO: [ view_end ] --END-- [ RunTime:0.001128s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001225s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001379s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014210s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014395s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000755s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000719s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000565s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000884s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003260s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001225s ] +INFO: [ view_end ] --END-- [ RunTime:0.001359s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000948s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001093s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014605s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014780s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000664s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000671s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001067s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001101s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003888s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001021s ] +INFO: [ view_end ] --END-- [ RunTime:0.001117s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000952s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001108s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.015571s ] +INFO: [ view_parse ] --END-- [ RunTime:0.015850s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001075s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000818s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000843s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.011910s ] +INFO: [ view_filter ] --END-- [ RunTime:0.015057s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001854s ] +INFO: [ view_end ] --END-- [ RunTime:0.001986s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001112s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001274s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014643s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014829s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000714s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000733s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000481s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000785s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003040s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.000981s ] +INFO: [ view_end ] --END-- [ RunTime:0.001076s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001556s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001772s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.023331s ] +INFO: [ view_parse ] --END-- [ RunTime:0.023489s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000753s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000653s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000536s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000791s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003043s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.000901s ] +INFO: [ view_end ] --END-- [ RunTime:0.001006s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001011s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001157s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014278s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014574s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000722s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000703s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000536s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000801s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003189s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001067s ] +INFO: [ view_end ] --END-- [ RunTime:0.001235s ] + +[ 2013-10-07T17:40:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001085s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001245s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.015220s ] +INFO: [ view_parse ] --END-- [ RunTime:0.015435s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000821s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000656s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000508s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000786s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003090s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001119s ] +INFO: [ view_end ] --END-- [ RunTime:0.001239s ] + +[ 2013-10-07T17:40:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000942s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001100s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012570s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012754s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000663s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000679s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000500s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000871s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003032s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001107s ] +INFO: [ view_end ] --END-- [ RunTime:0.001231s ] + +[ 2013-10-07T17:40:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000896s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001027s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013327s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013516s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000715s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000732s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000548s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000833s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003148s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001238s ] +INFO: [ view_end ] --END-- [ RunTime:0.001358s ] + +[ 2013-10-07T17:40:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001092s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001265s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014153s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014319s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000712s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000658s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000500s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001990s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004202s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001206s ] +INFO: [ view_end ] --END-- [ RunTime:0.001326s ] + +[ 2013-10-07T17:40:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001087s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001212s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013753s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013931s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000794s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000736s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000558s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000848s ] +INFO: [ view_filter ] --END-- [ RunTime:0.003272s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001428s ] +INFO: [ view_end ] --END-- [ RunTime:0.001557s ] + +[ 2013-10-07T17:40:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000807s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000918s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.008954s ] +INFO: [ view_parse ] --END-- [ RunTime:0.009122s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000657s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000626s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000456s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000750s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002747s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.000953s ] +INFO: [ view_end ] --END-- [ RunTime:0.001044s ] + +[ 2013-10-07T17:40:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/css/todos.css +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001461s ] +INFO: [ route_check ] --END-- [ RunTime:0.001631s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001069s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001208s ] +ERR: 无法加载模块:css + +[ 2013-10-07T17:40:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002523s ] +INFO: [ route_check ] --END-- [ RunTime:0.002714s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002612s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002778s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:40:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001501s ] +INFO: [ route_check ] --END-- [ RunTime:0.001675s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001056s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001195s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:40:58+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/css/todos.css +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001261s ] +INFO: [ route_check ] --END-- [ RunTime:0.001377s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000786s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000861s ] +ERR: 无法加载模块:css + +[ 2013-10-07T17:42:33+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001235s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001362s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011765s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011890s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001516s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001498s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001285s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001916s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006530s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001805s ] +INFO: [ view_end ] --END-- [ RunTime:0.001885s ] + +[ 2013-10-07T17:43:00+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001773s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001920s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014554s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014692s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001124s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001697s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001034s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001362s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005477s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001926s ] +INFO: [ view_end ] --END-- [ RunTime:0.002039s ] + +[ 2013-10-07T17:43:45+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001559s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001693s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013660s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013801s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001170s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001124s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001581s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002133s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006351s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001481s ] +INFO: [ view_end ] --END-- [ RunTime:0.001562s ] + +[ 2013-10-07T17:47:04+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001227s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001327s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013626s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013742s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001032s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001202s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000985s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001134s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004555s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001367s ] +INFO: [ view_end ] --END-- [ RunTime:0.001450s ] + +[ 2013-10-07T17:47:04+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002290s ] +INFO: [ route_check ] --END-- [ RunTime:0.002470s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001886s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002056s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:47:04+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002374s ] +INFO: [ route_check ] --END-- [ RunTime:0.002543s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002111s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002286s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:49:02+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000669s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000763s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.017804s ] +INFO: [ view_parse ] --END-- [ RunTime:0.017936s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001148s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001254s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001957s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001260s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005878s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001888s ] +INFO: [ view_end ] --END-- [ RunTime:0.002024s ] + +[ 2013-10-07T17:49:02+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001519s ] +INFO: [ route_check ] --END-- [ RunTime:0.001623s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001279s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001371s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:49:02+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001879s ] +INFO: [ route_check ] --END-- [ RunTime:0.002047s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000716s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000791s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:50:17+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001338s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001457s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012354s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012490s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001127s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001162s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001340s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001615s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005548s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001883s ] +INFO: [ view_end ] --END-- [ RunTime:0.001974s ] + +[ 2013-10-07T17:50:19+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000715s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000812s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.009426s ] +INFO: [ view_parse ] --END-- [ RunTime:0.009539s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000668s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000631s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000713s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000634s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002892s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001605s ] +INFO: [ view_end ] --END-- [ RunTime:0.001710s ] + +[ 2013-10-07T17:50:20+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001469s ] +INFO: [ route_check ] --END-- [ RunTime:0.001648s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001435s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001571s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:50:20+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002941s ] +INFO: [ route_check ] --END-- [ RunTime:0.003202s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002112s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002298s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:51:42+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000704s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000882s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013823s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013970s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001126s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001481s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000987s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001201s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005021s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001790s ] +INFO: [ view_end ] --END-- [ RunTime:0.001886s ] + +[ 2013-10-07T17:51:42+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002163s ] +INFO: [ route_check ] --END-- [ RunTime:0.002323s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001866s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002027s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:51:42+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002543s ] +INFO: [ route_check ] --END-- [ RunTime:0.002724s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002274s ] +INFO: [ app_begin ] --END-- [ RunTime:0.003157s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:52:38+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001484s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001621s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012209s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012361s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001555s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001608s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001495s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002088s ] +INFO: [ view_filter ] --END-- [ RunTime:0.007147s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001528s ] +INFO: [ view_end ] --END-- [ RunTime:0.001746s ] + +[ 2013-10-07T17:52:38+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/json2.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001377s ] +INFO: [ route_check ] --END-- [ RunTime:0.001541s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000949s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001089s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:52:38+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php/js/jquery-1.6.4.min.js +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002450s ] +INFO: [ route_check ] --END-- [ RunTime:0.002615s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002132s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002309s ] +ERR: 无法加载模块:js + +[ 2013-10-07T17:53:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000709s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000816s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014011s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014144s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001221s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001142s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000956s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001239s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004855s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002366s ] +INFO: [ view_end ] --END-- [ RunTime:0.002515s ] + +[ 2013-10-07T17:57:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001899s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002041s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013671s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013843s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001801s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002730s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002468s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002162s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009601s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002474s ] +INFO: [ view_end ] --END-- [ RunTime:0.002614s ] + +[ 2013-10-07T17:59:22+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.003644s ] +INFO: [ app_begin ] --END-- [ RunTime:0.003795s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.016842s ] +INFO: [ view_parse ] --END-- [ RunTime:0.017112s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001514s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001496s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001109s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.003581s ] +INFO: [ view_filter ] --END-- [ RunTime:0.008007s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001720s ] +INFO: [ view_end ] --END-- [ RunTime:0.001815s ] + +[ 2013-10-07T17:59:36+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001833s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001993s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012549s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012662s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001075s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001041s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001024s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001186s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004556s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001673s ] +INFO: [ view_end ] --END-- [ RunTime:0.001765s ] + +[ 2013-10-07T18:05:33+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001186s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001286s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012073s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012200s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001590s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002138s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001372s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001439s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006910s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001829s ] +INFO: [ view_end ] --END-- [ RunTime:0.001914s ] + +[ 2013-10-07T18:05:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Todo/Index +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003084s ] +INFO: [ route_check ] --END-- [ RunTime:0.003256s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002250s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002455s ] +ERR: 无法加载模块:Todo + +[ 2013-10-07T18:05:36+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Todo/Index +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.004549s ] +INFO: [ route_check ] --END-- [ RunTime:0.004754s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000682s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000737s ] +ERR: 无法加载模块:Todo + +[ 2013-10-07T18:05:45+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Todo/Index +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001633s ] +INFO: [ route_check ] --END-- [ RunTime:0.001768s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001327s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001433s ] +ERR: 无法加载模块:Todo + +[ 2013-10-07T22:31:19+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.091816s ] +INFO: [ app_begin ] --END-- [ RunTime:0.130176s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 7 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.738316s ] +INFO: [ view_parse ] --END-- [ RunTime:0.738461s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.052026s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.070788s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.044729s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.042246s ] +INFO: [ view_filter ] --END-- [ RunTime:0.210295s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.055379s ] +INFO: [ view_end ] --END-- [ RunTime:0.055502s ] + +[ 2013-10-07T22:31:20+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Todo/Index +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.110426s ] +INFO: [ route_check ] --END-- [ RunTime:0.110633s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000833s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000920s ] +ERR: 无法加载模块:Todo + +[ 2013-10-07T22:31:33+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Todo/Index +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000980s ] +INFO: [ route_check ] --END-- [ RunTime:0.001071s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000726s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000820s ] +ERR: 无法加载模块:Todo + +[ 2013-10-07T22:31:55+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Todo/Index +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000934s ] +INFO: [ route_check ] --END-- [ RunTime:0.001023s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000644s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000696s ] +ERR: 无法加载模块:Todo + +[ 2013-10-07T22:34:27+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001221s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001314s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012229s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012363s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001356s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001071s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000962s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001454s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005113s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001917s ] +INFO: [ view_end ] --END-- [ RunTime:0.002013s ] + +[ 2013-10-07T22:34:27+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Todo/Index/vote +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001592s ] +INFO: [ route_check ] --END-- [ RunTime:0.001706s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000694s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000769s ] +ERR: 无法加载模块:Todo + +[ 2013-10-07T22:34:31+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Todo/Index/vote +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.011025s ] +INFO: [ route_check ] --END-- [ RunTime:0.011198s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001650s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001784s ] +ERR: 无法加载模块:Todo + +[ 2013-10-07T22:35:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001267s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001375s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012825s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013005s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001359s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001520s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001611s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002066s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006941s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002214s ] +INFO: [ view_end ] --END-- [ RunTime:0.002346s ] + +[ 2013-10-07T22:35:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/vote +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002315s ] +INFO: [ route_check ] --END-- [ RunTime:0.002491s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002172s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002327s ] +NOTIC: [8] Trying to get property of non-object F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 11 行. + +[ 2013-10-07T22:35:37+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/vote +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000968s ] +INFO: [ route_check ] --END-- [ RunTime:0.001060s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000625s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000677s ] + +[ 2013-10-07T22:52:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001759s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001923s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.015296s ] +INFO: [ view_parse ] --END-- [ RunTime:0.015445s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001578s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001065s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001092s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001438s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005498s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002773s ] +INFO: [ view_end ] --END-- [ RunTime:0.002893s ] + +[ 2013-10-07T22:52:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002900s ] +INFO: [ route_check ] --END-- [ RunTime:0.003101s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002162s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002347s ] + +[ 2013-10-07T22:52:09+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001148s ] +INFO: [ route_check ] --END-- [ RunTime:0.001316s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000748s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000840s ] + +[ 2013-10-07T22:53:30+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000959s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001103s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.016208s ] +INFO: [ view_parse ] --END-- [ RunTime:0.016369s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001130s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001009s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000915s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001348s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004666s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002620s ] +INFO: [ view_end ] --END-- [ RunTime:0.002708s ] + +[ 2013-10-07T22:53:30+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002186s ] +INFO: [ route_check ] --END-- [ RunTime:0.002343s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000999s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001109s ] + +[ 2013-10-07T22:53:42+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000910s ] +INFO: [ route_check ] --END-- [ RunTime:0.000999s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000621s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000673s ] + +[ 2013-10-07T22:54:20+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001366s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001678s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.018166s ] +INFO: [ view_parse ] --END-- [ RunTime:0.018344s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001730s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001598s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001005s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001237s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005864s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002436s ] +INFO: [ view_end ] --END-- [ RunTime:0.002556s ] + +[ 2013-10-07T22:54:21+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002659s ] +INFO: [ route_check ] --END-- [ RunTime:0.002871s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002660s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002828s ] + +[ 2013-10-07T22:54:25+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002016s ] +INFO: [ route_check ] --END-- [ RunTime:0.002177s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000745s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000897s ] + +[ 2013-10-07T22:54:39+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001275s ] +INFO: [ route_check ] --END-- [ RunTime:0.001390s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000845s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000917s ] + +[ 2013-10-07T22:54:44+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001256s ] +INFO: [ route_check ] --END-- [ RunTime:0.001369s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000842s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000910s ] + +[ 2013-10-07T22:55:43+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000824s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000933s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011782s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011926s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001359s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001041s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000936s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001278s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004873s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002203s ] +INFO: [ view_end ] --END-- [ RunTime:0.002307s ] + +[ 2013-10-07T22:55:43+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001929s ] +INFO: [ route_check ] --END-- [ RunTime:0.002042s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000926s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001020s ] + +[ 2013-10-07T22:55:47+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000921s ] +INFO: [ route_check ] --END-- [ RunTime:0.001016s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000604s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000657s ] + +[ 2013-10-07T22:56:24+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001290s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001391s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011290s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011422s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001055s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001073s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001389s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001370s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005190s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002249s ] +INFO: [ view_end ] --END-- [ RunTime:0.002353s ] + +[ 2013-10-07T22:56:24+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002673s ] +INFO: [ route_check ] --END-- [ RunTime:0.002845s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002057s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002215s ] + +[ 2013-10-07T22:56:27+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000908s ] +INFO: [ route_check ] --END-- [ RunTime:0.001074s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000598s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000652s ] + +[ 2013-10-07T22:56:48+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000746s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000848s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011349s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011491s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000518s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000484s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000350s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000528s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002054s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001529s ] +INFO: [ view_end ] --END-- [ RunTime:0.001598s ] + +[ 2013-10-07T22:56:48+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001619s ] +INFO: [ route_check ] --END-- [ RunTime:0.001794s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000971s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001094s ] + +[ 2013-10-07T22:56:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000946s ] +INFO: [ route_check ] --END-- [ RunTime:0.001045s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000603s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000656s ] + +[ 2013-10-07T22:57:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000685s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000781s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.010401s ] +INFO: [ view_parse ] --END-- [ RunTime:0.010571s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002536s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000840s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000666s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000746s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005120s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001731s ] +INFO: [ view_end ] --END-- [ RunTime:0.001830s ] + +[ 2013-10-07T22:57:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002531s ] +INFO: [ route_check ] --END-- [ RunTime:0.002710s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001919s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002078s ] + +[ 2013-10-07T22:57:36+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001423s ] +INFO: [ route_check ] --END-- [ RunTime:0.001575s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000898s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000983s ] + +[ 2013-10-07T22:59:19+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000627s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000721s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011911s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012048s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001088s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001475s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000988s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001207s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005023s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002307s ] +INFO: [ view_end ] --END-- [ RunTime:0.002403s ] + +[ 2013-10-07T22:59:19+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002403s ] +INFO: [ route_check ] --END-- [ RunTime:0.002577s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001979s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002137s ] + +[ 2013-10-07T22:59:21+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001078s ] +INFO: [ route_check ] --END-- [ RunTime:0.001183s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000767s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000829s ] + +[ 2013-10-07T22:59:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000648s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000752s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011440s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011561s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001063s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001333s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001339s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001434s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005469s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002879s ] +INFO: [ view_end ] --END-- [ RunTime:0.002997s ] + +[ 2013-10-07T22:59:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001352s ] +INFO: [ route_check ] --END-- [ RunTime:0.001496s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001173s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001295s ] + +[ 2013-10-07T22:59:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001729s ] +INFO: [ route_check ] --END-- [ RunTime:0.001886s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001250s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001372s ] + +[ 2013-10-07T23:00:01+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001665s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001798s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.009823s ] +INFO: [ view_parse ] --END-- [ RunTime:0.009989s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000629s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000457s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000394s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000686s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002373s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.000850s ] +INFO: [ view_end ] --END-- [ RunTime:0.000929s ] + +[ 2013-10-07T23:00:01+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003463s ] +INFO: [ route_check ] --END-- [ RunTime:0.003653s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.003261s ] +INFO: [ app_begin ] --END-- [ RunTime:0.003416s ] + +[ 2013-10-07T23:00:03+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000924s ] +INFO: [ route_check ] --END-- [ RunTime:0.001016s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000599s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000651s ] + +[ 2013-10-07T23:01:08+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001292s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001399s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012687s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012821s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001193s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001652s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000984s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001327s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005516s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002987s ] +INFO: [ view_end ] --END-- [ RunTime:0.003104s ] + +[ 2013-10-07T23:01:08+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002910s ] +INFO: [ route_check ] --END-- [ RunTime:0.003080s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002096s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002273s ] + +[ 2013-10-07T23:01:10+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001027s ] +INFO: [ route_check ] --END-- [ RunTime:0.001126s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000691s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000747s ] + +[ 2013-10-07T23:10:33+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001349s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001464s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.022357s ] +INFO: [ view_parse ] --END-- [ RunTime:0.022555s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002318s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001896s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001703s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001867s ] +INFO: [ view_filter ] --END-- [ RunTime:0.008205s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002618s ] +INFO: [ view_end ] --END-- [ RunTime:0.002738s ] + +[ 2013-10-07T23:10:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002078s ] +INFO: [ route_check ] --END-- [ RunTime:0.002255s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001464s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001578s ] + +[ 2013-10-07T23:10:36+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001058s ] +INFO: [ route_check ] --END-- [ RunTime:0.001163s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000665s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000760s ] + +[ 2013-10-07T23:21:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001290s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001395s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.024124s ] +INFO: [ view_parse ] --END-- [ RunTime:0.024384s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002024s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002197s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002527s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001472s ] +INFO: [ view_filter ] --END-- [ RunTime:0.008555s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002261s ] +INFO: [ view_end ] --END-- [ RunTime:0.002343s ] + +[ 2013-10-07T23:21:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003051s ] +INFO: [ route_check ] --END-- [ RunTime:0.003220s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002009s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002156s ] + +[ 2013-10-07T23:21:54+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001089s ] +INFO: [ route_check ] --END-- [ RunTime:0.001191s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000677s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000735s ] + +[ 2013-10-07T23:22:22+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001393s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001512s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012087s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012224s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001139s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001053s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001192s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002285s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006080s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002057s ] +INFO: [ view_end ] --END-- [ RunTime:0.002199s ] + +[ 2013-10-07T23:22:22+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001705s ] +INFO: [ route_check ] --END-- [ RunTime:0.001840s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000783s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000874s ] + +[ 2013-10-07T23:22:24+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000973s ] +INFO: [ route_check ] --END-- [ RunTime:0.001069s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000646s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000699s ] +NOTIC: [2] json_decode() expects parameter 1 to be string, object given F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 9 行. + +[ 2013-10-07T23:22:33+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000876s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000979s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.009898s ] +INFO: [ view_parse ] --END-- [ RunTime:0.010030s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000550s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000506s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000390s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002774s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004449s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002354s ] +INFO: [ view_end ] --END-- [ RunTime:0.002456s ] + +[ 2013-10-07T23:22:33+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003107s ] +INFO: [ route_check ] --END-- [ RunTime:0.003369s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001632s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001766s ] + +[ 2013-10-07T23:22:35+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001234s ] +INFO: [ route_check ] --END-- [ RunTime:0.001337s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000733s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000794s ] + +[ 2013-10-07T23:24:33+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001765s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001918s ] + +[ 2013-10-07T23:24:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000645s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000742s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011279s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011413s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001614s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001433s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001273s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001815s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006476s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001987s ] +INFO: [ view_end ] --END-- [ RunTime:0.002100s ] + +[ 2013-10-07T23:24:51+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001727s ] +INFO: [ route_check ] --END-- [ RunTime:0.001887s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001660s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001786s ] + +[ 2013-10-07T23:24:54+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000964s ] +INFO: [ route_check ] --END-- [ RunTime:0.001062s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000631s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000691s ] + +[ 2013-10-07T23:26:13+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000627s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000720s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014590s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014783s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001532s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001046s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000938s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001208s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005036s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.003186s ] +INFO: [ view_end ] --END-- [ RunTime:0.003305s ] + +[ 2013-10-07T23:26:13+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003189s ] +INFO: [ route_check ] --END-- [ RunTime:0.003392s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002034s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002171s ] + +[ 2013-10-07T23:26:16+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000954s ] +INFO: [ route_check ] --END-- [ RunTime:0.001051s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000599s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000655s ] + +[ 2013-10-07T23:34:25+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001197s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001293s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011953s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012075s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001289s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001111s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000941s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001324s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004938s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002045s ] +INFO: [ view_end ] --END-- [ RunTime:0.002130s ] + +[ 2013-10-07T23:34:25+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001991s ] +INFO: [ route_check ] --END-- [ RunTime:0.002156s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001642s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001814s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.028719s ] + +[ 2013-10-07T23:34:28+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001694s ] +INFO: [ route_check ] --END-- [ RunTime:0.001799s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000728s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000787s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004370s ] + +[ 2013-10-07T23:36:01+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001035s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001189s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.010979s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011108s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000675s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000512s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000374s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000560s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002334s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002234s ] +INFO: [ view_end ] --END-- [ RunTime:0.002354s ] + +[ 2013-10-07T23:36:02+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002252s ] +INFO: [ route_check ] --END-- [ RunTime:0.002442s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001893s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002034s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004789s ] + +[ 2013-10-07T23:36:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001085s ] +INFO: [ route_check ] --END-- [ RunTime:0.001243s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000722s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000779s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003997s ] + +[ 2013-10-07T23:37:39+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001169s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001264s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.016802s ] +INFO: [ view_parse ] --END-- [ RunTime:0.016947s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001319s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001150s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001284s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001710s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005764s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.004151s ] +INFO: [ view_end ] --END-- [ RunTime:0.004280s ] + +[ 2013-10-07T23:37:39+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002470s ] +INFO: [ route_check ] --END-- [ RunTime:0.002674s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001693s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001864s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.005571s ] +SQL: INSERT INTO `todos` (`content`) VALUES ('aaa') [ RunTime:0.092046s ] + +[ 2013-10-07T23:37:42+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001978s ] +INFO: [ route_check ] --END-- [ RunTime:0.002134s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001339s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001445s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004567s ] +SQL: INSERT INTO `todos` (`content`) VALUES ('aaa') [ RunTime:0.061740s ] + +[ 2013-10-07T23:38:26+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001472s ] +INFO: [ route_check ] --END-- [ RunTime:0.001578s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001161s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001219s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.006986s ] +SQL: INSERT INTO `todos` (`content`) VALUES ('aaa') [ RunTime:0.043637s ] + +[ 2013-10-07T23:38:31+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001030s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001161s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011181s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011289s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002141s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001539s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001329s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001420s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006730s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001502s ] +INFO: [ view_end ] --END-- [ RunTime:0.001573s ] + +[ 2013-10-07T23:38:31+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002147s ] +INFO: [ route_check ] --END-- [ RunTime:0.002288s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001294s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001369s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.005938s ] +SQL: INSERT INTO `todos` (`content`) VALUES ('aaa') [ RunTime:0.145242s ] + +[ 2013-10-07T23:38:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001154s ] +INFO: [ route_check ] --END-- [ RunTime:0.001254s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000674s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000730s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003717s ] +SQL: INSERT INTO `todos` (`content`) VALUES ('aaa') [ RunTime:0.049602s ] + +[ 2013-10-07T23:39:10+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000946s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001079s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.080259s ] +INFO: [ view_parse ] --END-- [ RunTime:0.080420s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001770s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001484s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001448s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002168s ] +INFO: [ view_filter ] --END-- [ RunTime:0.007202s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.003098s ] +INFO: [ view_end ] --END-- [ RunTime:0.003200s ] + +[ 2013-10-07T23:39:10+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002342s ] +INFO: [ route_check ] --END-- [ RunTime:0.004878s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001111s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001244s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.007144s ] + +[ 2013-10-07T23:39:14+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000991s ] +INFO: [ route_check ] --END-- [ RunTime:0.001106s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000622s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000676s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004548s ] + +[ 2013-10-07T23:39:30+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000942s ] +INFO: [ route_check ] --END-- [ RunTime:0.001040s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000661s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000725s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003591s ] + +[ 2013-10-07T23:40:26+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000736s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000831s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012744s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012859s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001078s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001979s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001280s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001399s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006020s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002043s ] +INFO: [ view_end ] --END-- [ RunTime:0.002118s ] + +[ 2013-10-07T23:40:26+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001921s ] +INFO: [ route_check ] --END-- [ RunTime:0.002040s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001303s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001410s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004992s ] +NOTIC: [8] Undefined variable: man F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 23 行. + +[ 2013-10-07T23:40:36+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001166s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001257s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011612s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011742s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001550s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001060s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000978s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001436s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005294s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001459s ] +INFO: [ view_end ] --END-- [ RunTime:0.001525s ] + +[ 2013-10-07T23:40:36+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001607s ] +INFO: [ route_check ] --END-- [ RunTime:0.001715s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001738s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001848s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004166s ] + +[ 2013-10-07T23:40:39+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001242s ] +INFO: [ route_check ] --END-- [ RunTime:0.001347s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000847s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000914s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004515s ] + +[ 2013-10-07T23:42:58+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001248s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001351s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011460s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011596s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001466s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001459s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001299s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002232s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006769s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002151s ] +INFO: [ view_end ] --END-- [ RunTime:0.002228s ] + +[ 2013-10-07T23:42:58+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002099s ] +INFO: [ route_check ] --END-- [ RunTime:0.002299s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000767s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000841s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004583s ] +SQL: INSERT INTO `todos` (`content`) VALUES ('aaa') [ RunTime:0.073344s ] + +[ 2013-10-07T23:43:01+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001129s ] +INFO: [ route_check ] --END-- [ RunTime:0.001279s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000761s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000820s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003757s ] + +[ 2013-10-07T23:45:11+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001191s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001289s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013389s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013541s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001581s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001932s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001279s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001726s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006877s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001791s ] +INFO: [ view_end ] --END-- [ RunTime:0.001868s ] + +[ 2013-10-07T23:45:11+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001605s ] +INFO: [ route_check ] --END-- [ RunTime:0.001719s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001504s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001594s ] + +[ 2013-10-07T23:45:14+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001223s ] +INFO: [ route_check ] --END-- [ RunTime:0.001342s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000750s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000843s ] + +[ 2013-10-07T23:45:39+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001152s ] +INFO: [ route_check ] --END-- [ RunTime:0.001262s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000755s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001224s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004780s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('12334',0,1) [ RunTime:0.040077s ] + diff --git a/Todo/Runtime/Logs/13_10_08.log b/Todo/Runtime/Logs/13_10_08.log new file mode 100644 index 0000000..305a459 --- /dev/null +++ b/Todo/Runtime/Logs/13_10_08.log @@ -0,0 +1,1552 @@ +[ 2013-10-08T00:49:41+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.413948s ] +INFO: [ app_begin ] --END-- [ RunTime:0.414090s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.261365s ] +INFO: [ view_parse ] --END-- [ RunTime:0.261533s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.017612s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.094142s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.067000s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.053344s ] +INFO: [ view_filter ] --END-- [ RunTime:0.232461s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.055543s ] +INFO: [ view_end ] --END-- [ RunTime:0.055637s ] + +[ 2013-10-08T00:49:42+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.108861s ] +INFO: [ route_check ] --END-- [ RunTime:0.109040s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000922s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001009s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.078394s ] + +[ 2013-10-08T00:51:43+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001505s ] +INFO: [ route_check ] --END-- [ RunTime:0.001599s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001426s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001525s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003111s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('23456563',0,1) [ RunTime:0.085387s ] + +[ 2013-10-08T00:51:48+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000909s ] +INFO: [ route_check ] --END-- [ RunTime:0.000992s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000599s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000652s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.002987s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('233232',0,1) [ RunTime:0.067350s ] + +[ 2013-10-08T00:54:45+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001798s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001948s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.016821s ] +INFO: [ view_parse ] --END-- [ RunTime:0.016974s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002300s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002247s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002517s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002701s ] +INFO: [ view_filter ] --END-- [ RunTime:0.010118s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001963s ] +INFO: [ view_end ] --END-- [ RunTime:0.002084s ] + +[ 2013-10-08T00:54:45+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002456s ] +INFO: [ route_check ] --END-- [ RunTime:0.002639s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001024s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001137s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.005269s ] + +[ 2013-10-08T00:54:49+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000901s ] +INFO: [ route_check ] --END-- [ RunTime:0.000987s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000711s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000784s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003943s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('123',0,1) [ RunTime:0.048118s ] + +[ 2013-10-08T00:57:30+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002050s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002203s ] +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012754s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012886s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001346s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001126s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001076s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001264s ] +INFO: [ view_filter ] --END-- [ RunTime:0.005044s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001376s ] +INFO: [ view_end ] --END-- [ RunTime:0.001437s ] + +[ 2013-10-08T00:57:31+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.004322s ] +INFO: [ route_check ] --END-- [ RunTime:0.004516s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000992s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001092s ] +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004924s ] + +[ 2013-10-08T01:04:10+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002431s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002570s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.016729s ] +INFO: [ view_parse ] --END-- [ RunTime:0.016872s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002418s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002258s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.004050s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002541s ] +INFO: [ view_filter ] --END-- [ RunTime:0.011648s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001327s ] +INFO: [ view_end ] --END-- [ RunTime:0.001405s ] + +[ 2013-10-08T01:04:11+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002454s ] +INFO: [ route_check ] --END-- [ RunTime:0.002636s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002033s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002194s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004915s ] +SQL: SELECT * FROM `todos` ORDER BY order desc LIMIT 10 [ RunTime:0.000855s ] +ERR: 1064:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order desc LIMIT 10' at line 1 + [ SQL语句 ] : SELECT * FROM `todos` ORDER BY order desc LIMIT 10 + +[ 2013-10-08T01:04:19+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000899s ] +INFO: [ route_check ] --END-- [ RunTime:0.000984s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000628s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000680s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003089s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('123',0,1) [ RunTime:0.066414s ] + +[ 2013-10-08T01:04:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000622s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000705s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014886s ] +INFO: [ view_parse ] --END-- [ RunTime:0.015038s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001329s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001007s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000906s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001128s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004574s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001826s ] +INFO: [ view_end ] --END-- [ RunTime:0.001897s ] + +[ 2013-10-08T01:04:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002262s ] +INFO: [ route_check ] --END-- [ RunTime:0.002409s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001828s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001942s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004380s ] +SQL: SELECT * FROM `todos` ORDER BY order desc LIMIT 10 [ RunTime:0.000851s ] +ERR: 1064:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order desc LIMIT 10' at line 1 + [ SQL语句 ] : SELECT * FROM `todos` ORDER BY order desc LIMIT 10 + +[ 2013-10-08T01:04:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001088s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001252s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.029924s ] +INFO: [ view_parse ] --END-- [ RunTime:0.030096s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001634s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001553s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.007338s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002047s ] +INFO: [ view_filter ] --END-- [ RunTime:0.012954s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002052s ] +INFO: [ view_end ] --END-- [ RunTime:0.002166s ] + +[ 2013-10-08T01:04:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001836s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001990s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.016890s ] +INFO: [ view_parse ] --END-- [ RunTime:0.017038s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001779s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001863s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001414s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001773s ] +INFO: [ view_filter ] --END-- [ RunTime:0.007179s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002320s ] +INFO: [ view_end ] --END-- [ RunTime:0.002464s ] + +[ 2013-10-08T01:04:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001581s ] +INFO: [ route_check ] --END-- [ RunTime:0.001683s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001505s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001593s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004139s ] +SQL: SELECT * FROM `todos` ORDER BY order desc LIMIT 10 [ RunTime:0.001160s ] +ERR: 1064:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order desc LIMIT 10' at line 1 + [ SQL语句 ] : SELECT * FROM `todos` ORDER BY order desc LIMIT 10 + +[ 2013-10-08T01:05:10+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000984s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001126s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 21 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.020932s ] +INFO: [ view_parse ] --END-- [ RunTime:0.021102s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002326s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002368s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002100s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002416s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009491s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001893s ] +INFO: [ view_end ] --END-- [ RunTime:0.001989s ] + +[ 2013-10-08T01:05:11+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002505s ] +INFO: [ route_check ] --END-- [ RunTime:0.002663s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000993s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001097s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 21 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004261s ] +SQL: SELECT * FROM `todos` ORDER BY order desc LIMIT 10 [ RunTime:0.001379s ] +ERR: 1064:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order desc LIMIT 10' at line 1 + [ SQL语句 ] : SELECT * FROM `todos` ORDER BY order desc LIMIT 10 + +[ 2013-10-08T01:06:04+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001429s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001523s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 21 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.008932s ] +INFO: [ view_parse ] --END-- [ RunTime:0.009058s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000674s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000667s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000466s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000746s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002815s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.000945s ] +INFO: [ view_end ] --END-- [ RunTime:0.001035s ] + +[ 2013-10-08T01:06:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000996s ] +INFO: [ route_check ] --END-- [ RunTime:0.001094s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000647s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000704s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 21 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004255s ] +SQL: SELECT * FROM `todos` LIMIT 10 [ RunTime:0.001231s ] + +[ 2013-10-08T01:06:25+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000617s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000699s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 21 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.015591s ] +INFO: [ view_parse ] --END-- [ RunTime:0.015694s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001664s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001742s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001490s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001945s ] +INFO: [ view_filter ] --END-- [ RunTime:0.007093s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001130s ] +INFO: [ view_end ] --END-- [ RunTime:0.001198s ] + +[ 2013-10-08T01:06:25+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002212s ] +INFO: [ route_check ] --END-- [ RunTime:0.002359s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001276s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001354s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 21 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004597s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001295s ] + +[ 2013-10-08T01:08:10+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001434s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001556s ] + +[ 2013-10-08T01:08:45+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000629s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000719s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 22 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011900s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012058s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001497s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001444s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001324s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001927s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006593s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001941s ] +INFO: [ view_end ] --END-- [ RunTime:0.002064s ] + +[ 2013-10-08T01:08:45+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002283s ] +INFO: [ route_check ] --END-- [ RunTime:0.002441s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002054s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002166s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 22 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.005293s ] +SQL: SELECT * FROM `todos` [ RunTime:0.000921s ] + +[ 2013-10-08T01:09:08+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000951s ] +INFO: [ route_check ] --END-- [ RunTime:0.001048s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000664s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000737s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 22 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004177s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('123',0,11) [ RunTime:0.058515s ] + +[ 2013-10-08T01:10:26+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001575s ] +INFO: [ route_check ] --END-- [ RunTime:0.001675s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001141s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001194s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003315s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('123',0,1) [ RunTime:0.068049s ] + +[ 2013-10-08T01:10:38+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000637s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000729s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014820s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014980s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001473s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001466s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001378s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001586s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006185s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001852s ] +INFO: [ view_end ] --END-- [ RunTime:0.001960s ] + +[ 2013-10-08T01:10:39+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001006s ] +INFO: [ route_check ] --END-- [ RunTime:0.001111s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000830s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000911s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004470s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001094s ] + +[ 2013-10-08T01:11:40+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001434s ] +INFO: [ route_check ] --END-- [ RunTime:0.001523s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001984s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002125s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003124s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('aaa',0,111) [ RunTime:0.060971s ] + +[ 2013-10-08T01:19:55+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001438s ] +INFO: [ route_check ] --END-- [ RunTime:0.001527s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001129s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001183s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003266s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('123',0,111) [ RunTime:0.063477s ] + +[ 2013-10-08T01:21:24+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000626s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000713s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012502s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012611s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001327s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001714s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001289s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001615s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006232s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002698s ] +INFO: [ view_end ] --END-- [ RunTime:0.002798s ] + +[ 2013-10-08T01:21:25+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002836s ] +INFO: [ route_check ] --END-- [ RunTime:0.003059s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002239s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002420s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004750s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001334s ] + +[ 2013-10-08T01:21:38+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000906s ] +INFO: [ route_check ] --END-- [ RunTime:0.000998s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000601s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000653s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004033s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('111',0,1) [ RunTime:0.071959s ] + +[ 2013-10-08T01:22:03+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001544s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001637s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012315s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012411s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000966s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000984s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000857s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001039s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004008s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001201s ] +INFO: [ view_end ] --END-- [ RunTime:0.001258s ] + +[ 2013-10-08T01:22:03+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003328s ] +INFO: [ route_check ] --END-- [ RunTime:0.003515s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001852s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001951s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 19 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004645s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001766s ] + +[ 2013-10-08T01:27:00+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001882s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002029s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.019722s ] +INFO: [ view_parse ] --END-- [ RunTime:0.019875s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002413s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002504s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002132s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002413s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009800s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002793s ] +INFO: [ view_end ] --END-- [ RunTime:0.002902s ] + +[ 2013-10-08T01:27:00+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002338s ] +INFO: [ route_check ] --END-- [ RunTime:0.002518s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002009s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002153s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.005483s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001572s ] + +[ 2013-10-08T01:27:04+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001333s ] +INFO: [ route_check ] --END-- [ RunTime:0.001472s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000841s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000920s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003066s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('ASDF ',0,11) [ RunTime:0.059438s ] + +[ 2013-10-08T01:27:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000896s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001027s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.010967s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011075s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001081s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000994s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000871s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001153s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004284s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001902s ] +INFO: [ view_end ] --END-- [ RunTime:0.001990s ] + +[ 2013-10-08T01:27:06+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002274s ] +INFO: [ route_check ] --END-- [ RunTime:0.002387s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000646s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000706s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.018660s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001612s ] + +[ 2013-10-08T01:30:21+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001135s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001229s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012714s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012842s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002349s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002301s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002144s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002762s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009912s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002934s ] +INFO: [ view_end ] --END-- [ RunTime:0.003068s ] + +[ 2013-10-08T01:30:22+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001843s ] +INFO: [ route_check ] --END-- [ RunTime:0.001974s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001887s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002007s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 20 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.005053s ] +SQL: SELECT * FROM `todos` [ RunTime:0.000782s ] + +[ 2013-10-08T01:31:27+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001900s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002074s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 25 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013614s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013906s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001623s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001582s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001686s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001948s ] +INFO: [ view_filter ] --END-- [ RunTime:0.007246s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001977s ] +INFO: [ view_end ] --END-- [ RunTime:0.002042s ] + +[ 2013-10-08T01:31:27+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003537s ] +INFO: [ route_check ] --END-- [ RunTime:0.003739s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001646s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001788s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 25 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004343s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001255s ] +NOTIC: [8] Undefined index: done F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 17 行. +NOTIC: [2] Invalid argument supplied for foreach() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 17 行. + +[ 2013-10-08T01:31:59+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000918s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001056s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.015748s ] +INFO: [ view_parse ] --END-- [ RunTime:0.015895s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002340s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002369s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002523s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002238s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009795s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002416s ] +INFO: [ view_end ] --END-- [ RunTime:0.002555s ] + +[ 2013-10-08T01:31:59+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001540s ] +INFO: [ route_check ] --END-- [ RunTime:0.001776s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000969s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001067s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004144s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001275s ] +NOTIC: [8] Undefined index: done F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 18 行. +NOTIC: [2] Invalid argument supplied for foreach() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 18 行. + +[ 2013-10-08T01:32:58+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000960s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001102s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013219s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013366s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000682s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000449s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000333s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000545s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002201s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001590s ] +INFO: [ view_end ] --END-- [ RunTime:0.001653s ] + +[ 2013-10-08T01:32:58+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003359s ] +INFO: [ route_check ] --END-- [ RunTime:0.003508s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001744s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001840s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004254s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001929s ] + +[ 2013-10-08T01:33:41+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000686s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000779s ] + +[ 2013-10-08T01:34:35+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000644s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000736s ] + +[ 2013-10-08T01:35:02+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001159s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001250s ] + +[ 2013-10-08T01:35:25+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000993s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001140s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 25 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.020867s ] +INFO: [ view_parse ] --END-- [ RunTime:0.021032s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002413s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002350s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002156s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002611s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009801s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.003039s ] +INFO: [ view_end ] --END-- [ RunTime:0.003158s ] + +[ 2013-10-08T01:35:25+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002443s ] +INFO: [ route_check ] --END-- [ RunTime:0.002628s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001928s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002053s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 25 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003716s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001514s ] + +[ 2013-10-08T01:35:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000614s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000701s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 25 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011959s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012089s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001041s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001012s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000867s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001147s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004282s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002251s ] +INFO: [ view_end ] --END-- [ RunTime:0.002368s ] + +[ 2013-10-08T01:35:52+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002342s ] +INFO: [ route_check ] --END-- [ RunTime:0.002501s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001923s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002046s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 25 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004571s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001124s ] + +[ 2013-10-08T01:36:33+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000654s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000740s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 24 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011965s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012094s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002464s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002312s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002719s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002597s ] +INFO: [ view_filter ] --END-- [ RunTime:0.010462s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001784s ] +INFO: [ view_end ] --END-- [ RunTime:0.001853s ] + +[ 2013-10-08T01:36:34+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002782s ] +INFO: [ route_check ] --END-- [ RunTime:0.003021s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001997s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002151s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 24 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004402s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001370s ] + +[ 2013-10-08T01:36:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000624s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000709s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 24 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012214s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012315s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000996s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000982s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000895s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001311s ] +INFO: [ view_filter ] --END-- [ RunTime:0.004346s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001735s ] +INFO: [ view_end ] --END-- [ RunTime:0.001817s ] + +[ 2013-10-08T01:36:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003302s ] +INFO: [ route_check ] --END-- [ RunTime:0.003488s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000763s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000857s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 24 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004570s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001306s ] + +[ 2013-10-08T01:37:29+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001619s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001728s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.015282s ] +INFO: [ view_parse ] --END-- [ RunTime:0.015466s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001691s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001666s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001699s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001955s ] +INFO: [ view_filter ] --END-- [ RunTime:0.007350s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001817s ] +INFO: [ view_end ] --END-- [ RunTime:0.001886s ] + +[ 2013-10-08T01:37:29+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001047s ] +INFO: [ route_check ] --END-- [ RunTime:0.001154s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000938s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001025s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.039464s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001199s ] + +[ 2013-10-08T01:37:53+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001629s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001754s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.008299s ] +INFO: [ view_parse ] --END-- [ RunTime:0.008414s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000451s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000429s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000322s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000513s ] +INFO: [ view_filter ] --END-- [ RunTime:0.001874s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.000656s ] +INFO: [ view_end ] --END-- [ RunTime:0.000711s ] + +[ 2013-10-08T01:37:53+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002191s ] +INFO: [ route_check ] --END-- [ RunTime:0.002330s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002173s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002317s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004377s ] +SQL: SELECT * FROM `todos` [ RunTime:0.000797s ] + +[ 2013-10-08T01:38:03+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002097s ] +INFO: [ route_check ] --END-- [ RunTime:0.002189s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000653s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000717s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.063612s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('ASDF ',1,11) [ RunTime:0.072970s ] + +[ 2013-10-08T01:38:04+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001909s ] +INFO: [ route_check ] --END-- [ RunTime:0.001993s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000672s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000725s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003637s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('ASDF ',0,11) [ RunTime:0.068831s ] + +[ 2013-10-08T01:38:04+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002013s ] +INFO: [ route_check ] --END-- [ RunTime:0.002108s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000703s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000771s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003621s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('ASDF ',1,11) [ RunTime:0.061138s ] + +[ 2013-10-08T01:38:07+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002321s ] +INFO: [ route_check ] --END-- [ RunTime:0.002447s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000604s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000659s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003336s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('111',1,1) [ RunTime:0.060365s ] + +[ 2013-10-08T01:38:08+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001941s ] +INFO: [ route_check ] --END-- [ RunTime:0.002033s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000597s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000649s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003268s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('111',0,1) [ RunTime:0.051395s ] + +[ 2013-10-08T01:40:16+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003226s ] +INFO: [ route_check ] --END-- [ RunTime:0.003389s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001895s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002019s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003650s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('ryg',0,111) [ RunTime:0.073061s ] + +[ 2013-10-08T01:40:18+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000619s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000703s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014892s ] +INFO: [ view_parse ] --END-- [ RunTime:0.015009s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001611s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001538s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001520s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001657s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006560s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001739s ] +INFO: [ view_end ] --END-- [ RunTime:0.001802s ] + +[ 2013-10-08T01:40:18+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002488s ] +INFO: [ route_check ] --END-- [ RunTime:0.002666s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.002019s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002182s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004201s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001421s ] + +[ 2013-10-08T01:40:31+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000688s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000791s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014528s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014678s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002480s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002440s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001718s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002441s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009419s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001844s ] +INFO: [ view_end ] --END-- [ RunTime:0.001937s ] + +[ 2013-10-08T01:40:31+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.003581s ] +INFO: [ route_check ] --END-- [ RunTime:0.003763s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001624s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001783s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004616s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001076s ] + +[ 2013-10-08T01:40:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001170s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001262s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013111s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013212s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001583s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001460s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001346s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001597s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006149s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001178s ] +INFO: [ view_end ] --END-- [ RunTime:0.001233s ] + +[ 2013-10-08T01:40:32+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001548s ] +INFO: [ route_check ] --END-- [ RunTime:0.001652s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001381s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001459s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004200s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001458s ] + +[ 2013-10-08T01:41:01+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001298s ] +INFO: [ route_check ] --END-- [ RunTime:0.001442s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001113s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001204s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003535s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('111',1,1) [ RunTime:0.059280s ] + +[ 2013-10-08T01:41:57+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000657s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000746s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013254s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013377s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001466s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001503s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001394s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001575s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006245s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002759s ] +INFO: [ view_end ] --END-- [ RunTime:0.002871s ] + +[ 2013-10-08T01:41:57+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002343s ] +INFO: [ route_check ] --END-- [ RunTime:0.002506s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001786s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001885s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.048898s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001887s ] +NOTIC: [2] Invalid argument supplied for foreach() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 18 行. + +[ 2013-10-08T01:42:03+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001440s ] +INFO: [ route_check ] --END-- [ RunTime:0.001524s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000589s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000640s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004374s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('111111',0,1) [ RunTime:0.090325s ] + +[ 2013-10-08T01:42:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000693s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000784s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013333s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013453s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002304s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002680s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002670s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002375s ] +INFO: [ view_filter ] --END-- [ RunTime:0.010380s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001008s ] +INFO: [ view_end ] --END-- [ RunTime:0.001067s ] + +[ 2013-10-08T01:42:05+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001719s ] +INFO: [ route_check ] --END-- [ RunTime:0.001920s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001133s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001276s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004224s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001597s ] + +[ 2013-10-08T01:42:09+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000950s ] +INFO: [ route_check ] --END-- [ RunTime:0.001044s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000614s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000667s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003464s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('2222222',0,11) [ RunTime:0.110455s ] + +[ 2013-10-08T01:42:10+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000607s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000687s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.010902s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011032s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.000678s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.000631s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.000451s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.000737s ] +INFO: [ view_filter ] --END-- [ RunTime:0.002749s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002263s ] +INFO: [ view_end ] --END-- [ RunTime:0.002380s ] + +[ 2013-10-08T01:42:10+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002044s ] +INFO: [ route_check ] --END-- [ RunTime:0.002149s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000634s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000697s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004509s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001370s ] + +[ 2013-10-08T01:42:13+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002654s ] +INFO: [ route_check ] --END-- [ RunTime:0.002782s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000606s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000659s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003056s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('3333',0,111) [ RunTime:0.028242s ] + +[ 2013-10-08T01:42:15+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000708s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000793s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.011328s ] +INFO: [ view_parse ] --END-- [ RunTime:0.011428s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001550s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001678s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001458s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001866s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006794s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002105s ] +INFO: [ view_end ] --END-- [ RunTime:0.002196s ] + +[ 2013-10-08T01:42:15+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001526s ] +INFO: [ route_check ] --END-- [ RunTime:0.001690s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001001s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001110s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.005328s ] +SQL: SELECT * FROM `todos` [ RunTime:0.000845s ] + +[ 2013-10-08T01:44:00+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001786s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001928s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012554s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012673s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001681s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001576s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001389s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002000s ] +INFO: [ view_filter ] --END-- [ RunTime:0.007004s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001841s ] +INFO: [ view_end ] --END-- [ RunTime:0.001943s ] + +[ 2013-10-08T01:44:00+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001184s ] +INFO: [ route_check ] --END-- [ RunTime:0.001323s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001321s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001414s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004521s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001448s ] + +[ 2013-10-08T01:44:06+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002373s ] +INFO: [ route_check ] --END-- [ RunTime:0.002524s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000941s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001031s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003434s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('AsDF',0,1111) [ RunTime:0.079251s ] + +[ 2013-10-08T01:44:36+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000940s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001083s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.014596s ] +INFO: [ view_parse ] --END-- [ RunTime:0.014752s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.002316s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002268s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002563s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002039s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009508s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001208s ] +INFO: [ view_end ] --END-- [ RunTime:0.001266s ] + +[ 2013-10-08T01:44:36+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002409s ] +INFO: [ route_check ] --END-- [ RunTime:0.002563s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001308s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001391s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004158s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001801s ] + +[ 2013-10-08T01:44:39+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000969s ] +INFO: [ route_check ] --END-- [ RunTime:0.001065s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000637s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000693s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004010s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('SDFASFSDFA',0,11111) [ RunTime:0.123704s ] + +[ 2013-10-08T01:54:21+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.080706s ] +INFO: [ app_begin ] --END-- [ RunTime:0.080894s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.553297s ] +INFO: [ view_parse ] --END-- [ RunTime:0.553493s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.026159s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.048704s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.044640s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.043187s ] +INFO: [ view_filter ] --END-- [ RunTime:0.163121s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.043597s ] +INFO: [ view_end ] --END-- [ RunTime:0.043730s ] + +[ 2013-10-08T01:54:23+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.147255s ] +INFO: [ route_check ] --END-- [ RunTime:0.147407s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001382s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001500s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.078633s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001141s ] + +[ 2013-10-08T01:54:37+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001480s ] +INFO: [ route_check ] --END-- [ RunTime:0.001577s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001136s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001198s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.002929s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('2222222',1,11) [ RunTime:0.199702s ] + +[ 2013-10-08T01:54:48+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000968s ] +INFO: [ route_check ] --END-- [ RunTime:0.001054s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000665s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000716s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.002988s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('123111',0,111111) [ RunTime:0.059449s ] + +[ 2013-10-08T01:54:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000622s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000713s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.019449s ] +INFO: [ view_parse ] --END-- [ RunTime:0.019554s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001514s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001490s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001378s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001569s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006113s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001760s ] +INFO: [ view_end ] --END-- [ RunTime:0.001818s ] + +[ 2013-10-08T01:54:50+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000948s ] +INFO: [ route_check ] --END-- [ RunTime:0.001046s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000621s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000675s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.002931s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001183s ] + +[ 2013-10-08T01:59:21+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001209s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001304s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012296s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012405s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001589s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001566s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001662s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001882s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006967s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.001776s ] +INFO: [ view_end ] --END-- [ RunTime:0.001841s ] + +[ 2013-10-08T01:59:21+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001716s ] +INFO: [ route_check ] --END-- [ RunTime:0.001829s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001948s ] +INFO: [ app_begin ] --END-- [ RunTime:0.002058s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003469s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001409s ] + +[ 2013-10-08T01:59:31+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.000902s ] +INFO: [ route_check ] --END-- [ RunTime:0.000990s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000616s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000669s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003426s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('aaaaaaaaaaaaaaa',0,1111111) [ RunTime:0.073146s ] + +[ 2013-10-08T01:59:31+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001464s ] +INFO: [ route_check ] --END-- [ RunTime:0.001575s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001230s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001296s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003211s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001075s ] + +[ 2013-10-08T01:59:57+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000812s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000920s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.013723s ] +INFO: [ view_parse ] --END-- [ RunTime:0.013863s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001626s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.001462s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.001276s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.001565s ] +INFO: [ view_filter ] --END-- [ RunTime:0.006222s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002875s ] +INFO: [ view_end ] --END-- [ RunTime:0.003003s ] + +[ 2013-10-08T01:59:57+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001406s ] +INFO: [ route_check ] --END-- [ RunTime:0.001554s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000905s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000985s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003649s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001665s ] +NOTIC: [2] Invalid argument supplied for foreach() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 18 行. + +[ 2013-10-08T02:00:00+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001508s ] +INFO: [ route_check ] --END-- [ RunTime:0.001617s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000804s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000874s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003082s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('aaaaaaa',0,1) [ RunTime:0.062586s ] + +[ 2013-10-08T02:00:00+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001917s ] +INFO: [ route_check ] --END-- [ RunTime:0.002013s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000817s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000889s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.006074s ] +SQL: SELECT * FROM `todos` [ RunTime:0.002170s ] + +[ 2013-10-08T02:00:03+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001202s ] +INFO: [ route_check ] --END-- [ RunTime:0.001322s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000701s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000763s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003216s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('bbbbbbbbb',0,11) [ RunTime:0.064462s ] + +[ 2013-10-08T02:00:03+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001032s ] +INFO: [ route_check ] --END-- [ RunTime:0.001123s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000691s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000754s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003764s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001319s ] + +[ 2013-10-08T02:00:06+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/save +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001849s ] +INFO: [ route_check ] --END-- [ RunTime:0.002003s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001402s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001510s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.003053s ] +SQL: INSERT INTO `todos` (`content`,`done`,`order`) VALUES ('cccc',0,111) [ RunTime:0.080219s ] + +[ 2013-10-08T02:00:06+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.002260s ] +INFO: [ route_check ] --END-- [ RunTime:0.002409s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001476s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001575s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.006129s ] +SQL: SELECT * FROM `todos` [ RunTime:0.001930s ] + +[ 2013-10-08T02:00:19+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000636s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000726s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.012550s ] +INFO: [ view_parse ] --END-- [ RunTime:0.012656s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.001854s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.002268s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.002158s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.002657s ] +INFO: [ view_filter ] --END-- [ RunTime:0.009278s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.002178s ] +INFO: [ view_end ] --END-- [ RunTime:0.002271s ] + +[ 2013-10-08T02:00:19+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.001401s ] +INFO: [ route_check ] --END-- [ RunTime:0.001556s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.000763s ] +INFO: [ app_begin ] --END-- [ RunTime:0.000882s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.004806s ] +SQL: SELECT * FROM `todos` [ RunTime:0.002096s ] + +[ 2013-10-08T20:09:56+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/ +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.046720s ] +INFO: [ app_begin ] --END-- [ RunTime:0.046936s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +INFO: [ view_parse ] --START-- +INFO: ParseTemplate Behavior ::run [ RunTime:0.325154s ] +INFO: [ view_parse ] --END-- [ RunTime:0.325462s ] +INFO: [ view_filter ] --START-- +INFO: ContentReplace Behavior ::run [ RunTime:0.042486s ] +INFO: TokenBuild Behavior ::run [ RunTime:0.102169s ] +INFO: WriteHtmlCache Behavior ::run [ RunTime:0.044666s ] +INFO: ShowRuntime Behavior ::run [ RunTime:0.042974s ] +INFO: [ view_filter ] --END-- [ RunTime:0.232641s ] +INFO: [ view_end ] --START-- +INFO: ShowPageTrace Behavior ::run [ RunTime:0.043715s ] +INFO: [ view_end ] --END-- [ RunTime:0.043809s ] + +[ 2013-10-08T20:09:57+08:00 ] 127.0.0.1 /backbone/wxyoo1-todos/index.php?s=Index/fetch +INFO: [ route_check ] --START-- +INFO: CheckRoute Behavior ::run [ RunTime:0.030189s ] +INFO: [ route_check ] --END-- [ RunTime:0.030318s ] +INFO: [ app_begin ] --START-- +INFO: ReadHtmlCache Behavior ::run [ RunTime:0.001201s ] +INFO: [ app_begin ] --END-- [ RunTime:0.001258s ] +NOTIC: [2048] Declaration of IndexAction::fetch() should be compatible with that of Action::fetch() F:\WWW\backbone\wxyoo1-todos\Todo\Lib\Action\IndexAction.class.php 第 26 行. +SQL: SHOW COLUMNS FROM `todos` [ RunTime:0.171758s ] +SQL: SELECT * FROM `todos` [ RunTime:0.033577s ] + diff --git a/Todo/Tpl/Index/css/destroy.png b/Todo/Tpl/Index/css/destroy.png new file mode 100644 index 0000000..56d7637 Binary files /dev/null and b/Todo/Tpl/Index/css/destroy.png differ diff --git a/Todo/Tpl/Index/css/style.css b/Todo/Tpl/Index/css/style.css new file mode 100644 index 0000000..cd1a009 --- /dev/null +++ b/Todo/Tpl/Index/css/style.css @@ -0,0 +1,165 @@ +html, body { + margin: 0; + padding: 0; +} +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +cite, +code, +del, +dfn, +em, +img, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +dd, +dl, +dt, +li, +ol, +ul, +fieldset, +form, +label, +legend, +button, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td { + margin: 0; + padding: 0; + border: 0; + font-weight: normal; + font-style: normal; + font-size: 100%; + line-height: 1; + font-family: inherit; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +ol, ul { + list-style: none; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +html { + overflow-y: scroll; + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted; +} +a:hover, a:active { + outline: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + font-size: 100%; + margin: 0; + vertical-align: baseline; + *vertical-align: middle; +} +button, input { + line-height: normal; + *overflow: visible; +} +button::-moz-focus-inner, input::-moz-focus-inner { + border: 0; + padding: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} + + +/* Yahei */ +body { + font-family: "Helvetica Neue", "Luxi Sans", "DejaVu Sans", Tahoma, "Hiragino Sans GB", STHeiti, "Microsoft YaHei", Arial, sans-serif; +} \ No newline at end of file diff --git a/Todo/Tpl/Index/css/todos.css b/Todo/Tpl/Index/css/todos.css new file mode 100644 index 0000000..28e586f --- /dev/null +++ b/Todo/Tpl/Index/css/todos.css @@ -0,0 +1,531 @@ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-weight: inherit; + font-style: inherit; + font-size: 100%; + font-family: inherit; + vertical-align: baseline; +} +body { + line-height: 1; + color: black; + background: white; +} +ol, ul { + list-style: none; +} +a img { + border: none; +} + +html { + background: #eeeeee; +} +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.4em; + background: #eeeeee; + color: #333333; +} + +#todoapp { + width: 480px; + margin: 0 auto 40px; + background: white; + padding: 20px; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0; + -o-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0; + box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0; +} +#todoapp h1 { + font-size: 36px; + font-weight: bold; + text-align: center; + padding: 20px 0 30px 0; + line-height: 1; +} + +#create-todo { + position: relative; +} +#create-todo input { + width: 466px; + font-size: 24px; + font-family: inherit; + line-height: 1.4em; + border: 0; + outline: none; + padding: 6px; + border: 1px solid #999999; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; +} + +#create-todo span { + position: absolute; + z-index: 999; + width: 170px; + left: 50%; + margin-left: -85px; +} + +#todo-list { + margin-top: 10px; +} +#todo-list li { + padding: 12px 20px 11px 0; + position: relative; + font-size: 24px; + line-height: 1.1em; + border-bottom: 1px solid #cccccc; +} +#todo-list li:after { + content: "\0020"; + display: block; + height: 0; + clear: both; + overflow: hidden; + visibility: hidden; +} +#todo-list li.editing { + padding: 0; + border-bottom: 0; +} +#todo-list .editing .display, +#todo-list .edit { + display: none; +} +#todo-list .editing .edit { + display: block; +} +#todo-list .editing input { + width: 444px; + font-size: 24px; + font-family: inherit; + margin: 0; + line-height: 1.6em; + border: 0; + outline: none; + padding: 10px 7px 0px 27px; + border: 1px solid #999999; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; +} +#todo-list .check { + position: relative; + top: 9px; + margin: 0 10px 0 7px; + float: left; +} +#todo-list .done .todo-content { + text-decoration: line-through; + color: #777777; +} +#todo-list .todo-destroy { + position: absolute; + right: 5px; + top: 14px; + display: none; + cursor: pointer; + width: 20px; + height: 20px; + background: url(destroy.png) no-repeat 0 0; +} +#todo-list li:hover .todo-destroy { + display: block; +} +#todo-list .todo-destroy:hover { + background-position: 0 -20px; +} + +#todo-stats { + *zoom: 1; + margin-top: 10px; + color: #777777; +} +#todo-stats:after { + content: "\0020"; + display: block; + height: 0; + clear: both; + overflow: hidden; + visibility: hidden; +} +#todo-stats .todo-count { + float: left; +} +#todo-stats .todo-count .number { + font-weight: bold; + color: #333333; +} +#todo-stats .todo-clear { + float: right; +} +#todo-stats .todo-clear a { + color: #777777; + font-size: 12px; +} +#todo-stats .todo-clear a:visited { + color: #777777; +} +#todo-stats .todo-clear a:hover { + color: #336699; +} + +#instructions { + width: 520px; + margin: 10px auto; + color: #777777; + text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0; + text-align: center; +} +#instructions a { + color: #336699; +} + +#credits { + width: 520px; + margin: 30px auto; + color: #999; + text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0; + text-align: center; +} +#credits a { + color: #888; +} + + +/* +* François 'cahnory' Germain +*/ +.ui-tooltip, .ui-tooltip-top, .ui-tooltip-right, .ui-tooltip-bottom, .ui-tooltip-left { + color:#ffffff; + cursor:normal; + display:-moz-inline-stack; + display:inline-block; + font-size:12px; + font-family:arial; + padding:.5em 1em; + position:relative; + text-align:center; + text-shadow:0 -1px 1px #111111; + -webkit-border-top-left-radius:4px ; + -webkit-border-top-right-radius:4px ; + -webkit-border-bottom-right-radius:4px ; + -webkit-border-bottom-left-radius:4px ; + -khtml-border-top-left-radius:4px ; + -khtml-border-top-right-radius:4px ; + -khtml-border-bottom-right-radius:4px ; + -khtml-border-bottom-left-radius:4px ; + -moz-border-radius-topleft:4px ; + -moz-border-radius-topright:4px ; + -moz-border-radius-bottomright:4px ; + -moz-border-radius-bottomleft:4px ; + border-top-left-radius:4px ; + border-top-right-radius:4px ; + border-bottom-right-radius:4px ; + border-bottom-left-radius:4px ; + -o-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; + -moz-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; + -khtml-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; + -webkit-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; + box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444; + background-color:#3b3b3b; + background-image:-moz-linear-gradient(top,#555555,#222222); + background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#555555),color-stop(1,#222222)); + filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222); + -ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222); +} +.ui-tooltip:after, .ui-tooltip-top:after, .ui-tooltip-right:after, .ui-tooltip-bottom:after, .ui-tooltip-left:after { + content:"\25B8"; + display:block; + font-size:2em; + height:0; + line-height:0; + position:absolute; +} +.ui-tooltip:after, .ui-tooltip-bottom:after { + color:#2a2a2a; + bottom:0; + left:1px; + text-align:center; + text-shadow:1px 0 2px #000000; + -o-transform:rotate(90deg); + -moz-transform:rotate(90deg); + -khtml-transform:rotate(90deg); + -webkit-transform:rotate(90deg); + width:100%; +} +.ui-tooltip-top:after { + bottom:auto; + color:#4f4f4f; + left:-2px; + top:0; + text-align:center; + text-shadow:none; + -o-transform:rotate(-90deg); + -moz-transform:rotate(-90deg); + -khtml-transform:rotate(-90deg); + -webkit-transform:rotate(-90deg); + width:100%; +} +.ui-tooltip-right:after { + color:#222222; + right:-0.375em; + top:50%; + margin-top:-.05em; + text-shadow:0 1px 2px #000000; + -o-transform:rotate(0); + -moz-transform:rotate(0); + -khtml-transform:rotate(0); + -webkit-transform:rotate(0); +} +.ui-tooltip-left:after { + color:#222222; + left:-0.375em; + top:50%; + margin-top:.1em; + text-shadow:0 -1px 2px #000000; + -o-transform:rotate(180deg); + -moz-transform:rotate(180deg); + -khtml-transform:rotate(180deg); + -webkit-transform:rotate(180deg); +} + + + +/*the following changes require some cleanup and integration with the above.**/ + +/* line 9 */ + + +/* line 17 */ +#todoapp { + background: white; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0; + -o-box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0; + box-shadow: rgba(0, 0, 0, 0.2) 0 2px 6px 0; + -moz-border-radius-bottomleft: 5px; + -webkit-border-bottom-left-radius: 5px; + -o-border-bottom-left-radius: 5px; + -ms-border-bottom-left-radius: 5px; + -khtml-border-bottom-left-radius: 5px; + border-bottom-left-radius: 5px; + -moz-border-radius-bottomright: 5px; + -webkit-border-bottom-right-radius: 5px; + -o-border-bottom-right-radius: 5px; + -ms-border-bottom-right-radius: 5px; + -khtml-border-bottom-right-radius: 5px; + border-bottom-right-radius: 5px; +} +/* line 24 */ + + +/* line 32 */ +#todoapp .content #create-todo { + position: relative; +} +/* line 34 */ +#todoapp .content #create-todo input { + font-size: 24px; + font-family: inherit; + line-height: 1.4em; + border: 0; + outline: none; + padding: 6px; + border: 1px solid #999999; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; +} + +/* line 47 */ +#todoapp .content #create-todo span { + position: absolute; + z-index: 999; + width: 170px; + left: 50%; + margin-left: -85px; +} +/* line 55 */ +#todoapp .content ul#todo-list { + margin-top: 10px; +} +/* line 57 */ +#todoapp .content ul#todo-list li { + padding: 15px 20px 15px 0; + position: relative; + font-size: 24px; + border-bottom: 1px solid #cccccc; + *zoom: 1; + cursor: move; +} +/* line 22, /opt/ree/lib/ruby/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/utilities/general/_clearfix.scss */ +#todoapp .content ul#todo-list li:after { + content: "\0020"; + display: block; + height: 0; + clear: both; + overflow: hidden; + visibility: hidden; +} +/* line 64 */ +#todoapp .content ul#todo-list li.editing { + padding: 0; + border-bottom: 0; +} +/* line 67 */ +#todoapp .content ul#todo-list li.editing .todo-input { + display: block; + width: 466px; + font-size: 24px; + font-family: inherit; + line-height: 1.4em; + border: 0; + outline: none; + padding: 6px; + border: 1px solid #999999; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + -o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; + box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset; +} +/* line 79 */ +#todoapp .content ul#todo-list li.editing .todo-content { + display: none; +} +/* line 81 */ +#todoapp .content ul#todo-list li.editing .todo-check { + display: none; +} +/* line 83 */ +#todoapp .content ul#todo-list li.editing .todo-destroy { + display: none !important; +} +/* line 85 */ +#todoapp .content ul#todo-list li .todo-input { + display: none; +} +/* line 87 */ +#todoapp .content ul#todo-list li .todo-check { + position: relative; + top: 6px; + margin: 0 10px 0 7px; + float: left; +} +/* line 93 */ +#todoapp .content ul#todo-list li.done .todo-content { + text-decoration: line-through; + color: #777777; +} +/* line 96 */ +#todoapp .content ul#todo-list li .todo-destroy { + position: absolute; + right: 0px; + top: 16px; + display: none; + cursor: pointer; + width: 20px; + height: 20px; +} +/* line 106 */ +#todoapp .content ul#todo-list li:hover .todo-destroy { + display: block; +} +/* line 109 */ +#todoapp #todo-stats { + *zoom: 1; + margin-top: 10px; + color: #555555; + -moz-border-radius-bottomleft: 5px; + -webkit-border-bottom-left-radius: 5px; + -o-border-bottom-left-radius: 5px; + -ms-border-bottom-left-radius: 5px; + -khtml-border-bottom-left-radius: 5px; + border-bottom-left-radius: 5px; + -moz-border-radius-bottomright: 5px; + -webkit-border-bottom-right-radius: 5px; + -o-border-bottom-right-radius: 5px; + -ms-border-bottom-right-radius: 5px; + -khtml-border-bottom-right-radius: 5px; + border-bottom-right-radius: 5px; + background: #f4fce8; + border-top: 1px solid #ededed; + padding: 0 20px; + line-height: 36px; +} +/* line 22, /opt/ree/lib/ruby/gems/1.8/gems/compass-0.10.5/frameworks/compass/stylesheets/compass/utilities/general/_clearfix.scss */ +#todoapp #todo-stats:after { + content: "\0020"; + display: block; + height: 0; + clear: both; + overflow: hidden; + visibility: hidden; +} +/* line 118 */ +#todoapp #todo-stats .todo-count { + float: left; +} +/* line 120 */ +#todoapp #todo-stats .todo-count .number { + font-weight: bold; + color: #555555; +} +/* line 123 */ +#todoapp #todo-stats .todo-clear { + float: right; +} +/* line 125 */ +#todoapp #todo-stats .todo-clear a { + display: block; + line-height: 20px; + text-decoration: none; + -moz-border-radius: 12px; + -webkit-border-radius: 12px; + -o-border-radius: 12px; + -ms-border-radius: 12px; + -khtml-border-radius: 12px; + border-radius: 12px; + background: rgba(0, 0, 0, 0.1); + color: #555555; + font-size: 11px; + margin-top: 8px; + padding: 0 10px 1px; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0; + -o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0; + box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0; +} +/* line 136 */ +#todoapp #todo-stats .todo-clear a:hover, #todoapp #todo-stats .todo-clear a:focus { + background: rgba(0, 0, 0, 0.15); + -moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0; + -webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0; + -o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0; + box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0; +} +/* line 139 */ +#todoapp #todo-stats .todo-clear a:active { + position: relative; + top: 1px; +} + diff --git a/Todo/Tpl/Index/index.html b/Todo/Tpl/Index/index.html new file mode 100644 index 0000000..7056082 --- /dev/null +++ b/Todo/Tpl/Index/index.html @@ -0,0 +1,69 @@ + + + + + the5fire-Backbone.js-todos + + + + + + + + + + + + +
      +
      +

      Todos

      +
      +
      +
      + + +
      +
      + + +
        +
        +
        +
        +
        + + + + + + + + + diff --git a/Todo/Tpl/Index/js/backbone-localstorage.js b/Todo/Tpl/Index/js/backbone-localstorage.js new file mode 100644 index 0000000..091d7f3 --- /dev/null +++ b/Todo/Tpl/Index/js/backbone-localstorage.js @@ -0,0 +1,84 @@ +// A simple module to replace `Backbone.sync` with *localStorage*-based +// persistence. Models are given GUIDS, and saved into a JSON object. Simple +// as that. + +// Generate four random hex digits. +function S4() { + return (((1+Math.random())*0x10000)|0).toString(16).substring(1); +}; + +// Generate a pseudo-GUID by concatenating random hexadecimal. +function guid() { + return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); +}; + +// Our Store is represented by a single JS object in *localStorage*. Create it +// with a meaningful name, like the name you'd give a table. +var Store = function(name) { + this.name = name; + var store = localStorage.getItem(this.name); + this.data = (store && JSON.parse(store)) || {}; +}; + +_.extend(Store.prototype, { + + // Save the current state of the **Store** to *localStorage*. + save: function() { + localStorage.setItem(this.name, JSON.stringify(this.data)); + }, + + // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already + // have an id of it's own. + create: function(model) { + if (!model.id) model.id = model.attributes.id = guid(); + this.data[model.id] = model; + this.save(); + return model; + }, + + // Update a model by replacing its copy in `this.data`. + update: function(model) { + this.data[model.id] = model; + this.save(); + return model; + }, + + // Retrieve a model from `this.data` by id. + find: function(model) { + return this.data[model.id]; + }, + + // Return the array of all models currently in storage. + findAll: function() { + return _.values(this.data); + }, + + // Delete a model from `this.data`, returning it. + destroy: function(model) { + delete this.data[model.id]; + this.save(); + return model; + } + +}); + +// Override `Backbone.sync` to use delegate to the model or collection's +// *localStorage* property, which should be an instance of `Store`. +Backbone.sync = function(method, model, options) { + + var resp; + var store = model.localStorage || model.collection.localStorage; + + switch (method) { + case "read": resp = model.id ? store.find(model) : store.findAll(); break; + case "create": resp = store.create(model); break; + case "update": resp = store.update(model); break; + case "delete": resp = store.destroy(model); break; + } + + if (resp) { + options.success(resp); + } else { + options.error("Record not found"); + } +}; \ No newline at end of file diff --git a/Todo/Tpl/Index/js/backbone-min.js b/Todo/Tpl/Index/js/backbone-min.js new file mode 100644 index 0000000..3541019 --- /dev/null +++ b/Todo/Tpl/Index/js/backbone-min.js @@ -0,0 +1,4 @@ +(function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.0.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this}a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=k[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON});var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&window.ActiveXObject&&!(window.external&&window.external.msActiveXFilteringEnabled)){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(h.extend(s,i));e.trigger("request",e,o,i);return o};var k={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var S=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var $=/\((.*?)\)/g;var T=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(S.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.apply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace($,"(?:$1)?").replace(T,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var P=/^\/+|\/+$/g;var O=/msie [\w.]+/;var C=/\/$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.substr(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({},{root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=O.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(P,"/");if(r&&this._wantsHashChange){this.iframe=a.$(' \ + \ + Powered by JSLitmus \ + '; + + /** + * The public API for creating and running tests + */ + window.JSLitmus = { + /** The list of all tests that have been registered with JSLitmus.test */ + _tests: [], + /** The queue of tests that need to be run */ + _queue: [], + + /** + * The parsed query parameters the current page URL. This is provided as a + * convenience for test functions - it's not used by JSLitmus proper + */ + params: {}, + + /** + * Initialize + */ + _init: function() { + // Parse query params into JSLitmus.params[] hash + var match = (location + '').match(/([^?#]*)(#.*)?$/); + if (match) { + var pairs = match[1].split('&'); + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i].split('='); + if (pair.length > 1) { + var key = pair.shift(); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + this.params[key] = value; + } + } + } + + // Write out the stylesheet. We have to do this here because IE + // doesn't honor sheets written after the document has loaded. + document.write(STYLESHEET); + + // Setup the rest of the UI once the document is loaded + if (window.addEventListener) { + window.addEventListener('load', this._setup, false); + } else if (document.addEventListener) { + document.addEventListener('load', this._setup, false); + } else if (window.attachEvent) { + window.attachEvent('onload', this._setup); + } + + return this; + }, + + /** + * Set up the UI + */ + _setup: function() { + var el = jsl.$('jslitmus_container'); + if (!el) document.body.appendChild(el = document.createElement('div')); + + el.innerHTML = MARKUP; + + // Render the UI for all our tests + for (var i=0; i < JSLitmus._tests.length; i++) + JSLitmus.renderTest(JSLitmus._tests[i]); + }, + + /** + * (Re)render all the test results + */ + renderAll: function() { + for (var i = 0; i < JSLitmus._tests.length; i++) + JSLitmus.renderTest(JSLitmus._tests[i]); + JSLitmus.renderChart(); + }, + + /** + * (Re)render the chart graphics + */ + renderChart: function() { + var url = JSLitmus.chartUrl(); + jsl.$('chart_link').href = url; + jsl.$('chart_image').src = url; + jsl.$('chart').style.display = ''; + + // Update the tiny URL + jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url); + }, + + /** + * (Re)render the results for a specific test + */ + renderTest: function(test) { + // Make a new row if needed + if (!test._row) { + var trow = jsl.$('test_row_template'); + if (!trow) return; + + test._row = trow.cloneNode(true); + test._row.style.display = ''; + test._row.id = ''; + test._row.onclick = function() {JSLitmus._queueTest(test);}; + test._row.title = 'Run ' + test.name + ' test'; + trow.parentNode.appendChild(test._row); + test._row.cells[0].innerHTML = test.name; + } + + var cell = test._row.cells[1]; + var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping']; + + if (test.error) { + cns.push('test_error'); + cell.innerHTML = + '
        ' + test.error + '
        ' + + '
        • ' + + jsl.join(test.error, ': ', '
        • ') + + '
        '; + } else { + if (test.running) { + cns.push('test_running'); + cell.innerHTML = 'running'; + } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) { + cns.push('test_pending'); + cell.innerHTML = 'pending'; + } else if (test.count) { + cns.push('test_done'); + var hz = test.getHz(jsl.$('test_normalize').checked); + cell.innerHTML = hz != Infinity ? hz : '∞'; + cell.title = 'Looped ' + test.count + ' times in ' + test.time + ' seconds'; + } else { + cell.innerHTML = 'ready'; + } + } + cell.className = cns.join(' '); + }, + + /** + * Create a new test + */ + test: function(name, f) { + // Create the Test object + var test = new Test(name, f); + JSLitmus._tests.push(test); + + // Re-render if the test state changes + test.onChange = JSLitmus.renderTest; + + // Run the next test if this one finished + test.onStop = function(test) { + if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test); + JSLitmus.currentTest = null; + JSLitmus._nextTest(); + }; + + // Render the new test + this.renderTest(test); + }, + + /** + * Add all tests to the run queue + */ + runAll: function(e) { + e = e || window.event; + var reverse = e && e.shiftKey, len = JSLitmus._tests.length; + for (var i = 0; i < len; i++) { + JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]); + } + }, + + /** + * Remove all tests from the run queue. The current test has to finish on + * it's own though + */ + stop: function() { + while (JSLitmus._queue.length) { + var test = JSLitmus._queue.shift(); + JSLitmus.renderTest(test); + } + }, + + /** + * Run the next test in the run queue + */ + _nextTest: function() { + if (!JSLitmus.currentTest) { + var test = JSLitmus._queue.shift(); + if (test) { + jsl.$('stop_button').disabled = false; + JSLitmus.currentTest = test; + test.run(); + JSLitmus.renderTest(test); + if (JSLitmus.onTestStart) JSLitmus.onTestStart(test); + } else { + jsl.$('stop_button').disabled = true; + JSLitmus.renderChart(); + } + } + }, + + /** + * Add a test to the run queue + */ + _queueTest: function(test) { + if (jsl.indexOf(JSLitmus._queue, test) >= 0) return; + JSLitmus._queue.push(test); + JSLitmus.renderTest(test); + JSLitmus._nextTest(); + }, + + /** + * Generate a Google Chart URL that shows the data for all tests + */ + chartUrl: function() { + var n = JSLitmus._tests.length, markers = [], data = []; + var d, min = 0, max = -1e10; + var normalize = jsl.$('test_normalize').checked; + + // Gather test data + for (var i=0; i < JSLitmus._tests.length; i++) { + var test = JSLitmus._tests[i]; + if (test.count) { + var hz = test.getHz(normalize); + var v = hz != Infinity ? hz : 0; + data.push(v); + markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' + + markers.length + ',10'); + max = Math.max(v, max); + } + } + if (markers.length <= 0) return null; + + // Build chart title + var title = document.getElementsByTagName('title'); + title = (title && title.length) ? title[0].innerHTML : null; + var chart_title = []; + if (title) chart_title.push(title); + chart_title.push('Ops/sec (' + platform + ')'); + + // Build labels + var labels = [jsl.toLabel(min), jsl.toLabel(max)]; + + var w = 250, bw = 15; + var bs = 5; + var h = markers.length*(bw + bs) + 30 + chart_title.length*20; + + var params = { + chtt: escape(chart_title.join('|')), + chts: '000000,10', + cht: 'bhg', // chart type + chd: 't:' + data.join(','), // data set + chds: min + ',' + max, // max/min of data + chxt: 'x', // label axes + chxl: '0:|' + labels.join('|'), // labels + chsp: '0,1', + chm: markers.join('|'), // test names + chbh: [bw, 0, bs].join(','), // bar widths + // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient + chs: w + 'x' + h + }; + return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&'); + } + }; + + JSLitmus._init(); +})(); \ No newline at end of file diff --git a/Todo/Tpl/Index/js/json2.js b/Todo/Tpl/Index/js/json2.js new file mode 100644 index 0000000..2360259 --- /dev/null +++ b/Todo/Tpl/Index/js/json2.js @@ -0,0 +1,481 @@ +/* + http://www.JSON.org/json2.js + 2009-09-29 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +/*jslint evil: true, strict: false */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +if (!this.JSON) { + this.JSON = {}; +} + +(function () { + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/. +test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). +replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). +replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); \ No newline at end of file diff --git a/Todo/Tpl/Index/js/todos.js b/Todo/Tpl/Index/js/todos.js new file mode 100644 index 0000000..c6e0fa8 --- /dev/null +++ b/Todo/Tpl/Index/js/todos.js @@ -0,0 +1,152 @@ +$(function(){ + var Todo = Backbone.Model.extend({ + defaults:{ + content:"empty todo...", + done:false + }, + initialize: function(){ + if(!this.get("content")){ + this.set({"content":this.defaults.content}); + } + }, + toggle:function(){ + this.save({done: !this.get("done")}); + }, + clear: function(){ + this.destroy(); + } + }); + var TodoList = Backbone.Collection.extend({ + model: Todo, + url:'index.php?s=Index/save', + done: function(){ + return this.filter(function(todo){return todo.get('done');}); + }, + remaining: function(){ + return this.without.apply(this,this.done()); + }, + nextOrder: function(){ + if(!this.length) return 1; + console.log(this.last().get('order')+1); + return this.last().get('order') +1; + }, + comparator: function(todo){ + return todo.get('order'); + } + }); + var Todos = new TodoList; + var TodoView = Backbone.View.extend({ + tagName: "li", + template:_.template($('#item-template').html()), + events:{ + "click .check" :"toggleDone", + "dblclick label.todo-content" :"edit", + "click span.todo-destroy" :"clear", + "keypress .todo-input" :"updateOnEnter", + "blur .todo-input" :"close" + }, + initialize: function() { + _.bindAll(this, 'render', 'close', 'remove'); + this.model.bind('change', this.render); + this.model.bind('destroy', this.remove); //这个remove是view的中的方法,用来清除页面中的dom + }, + render: function(){ + $(this.el).html(this.template(this.model.toJSON())); + this.input = this.$('.todo-input'); + return this; + }, + toggleDone: function(){ + this.model.toggle(); + }, + edit: function(){ + $(this.el).addClass("editing"); + this.input.focus(); + }, + close:function(){ + this.model.save({content:this.input.val()}); + $(this.el).removeClass("editing"); + }, + updateOnEnter:function(e){ + if(e.keyCode == 13) this.close(); + }, + clear: function(){ + this.model.clear(); + } + }); + var AppView = Backbone.View.extend({ + el:$("#todoapp"), + statsTemplate:_.template($('#stats-template').html()), + events:{ + "keypress #new-todo":"createOnEnter", + "keyup #new-todo" :"showTooltip", + "click .todo-clear a":"clearCompleted", + "click .mark-all-done":"toggleAllComplete" + }, + initialize: function() { + //下面这个是underscore库中的方法,用来绑定方法到目前的这个对象中,是为了在以后运行环境中调用当前对象的时候能够找到对象中的这些方法。 + _.bindAll(this, 'addOne', 'addAll', 'render', 'toggleAllComplete'); + + this.input = this.$("#new-todo"); + this.allCheckbox = this.$(".mark-all-done")[0]; + + Todos.bind('add', this.addOne); + Todos.bind('reset', this.addAll); + Todos.bind('all', this.render); + + Todos.fetch({ + url:"index.php?s=Index/fetch" + }); + }, + + render:function(){ + var done = Todos.done().length; + var remaining = Todos.remaining().length; + this.$('#todo-stats').html(this.statsTemplate({ + total: Todos.length, + done:done, + remaining:remaining + })); + this.allCheckbox.checked = !remaining; + }, + addOne: function(todo){ + var view = new TodoView({model:todo}); + this.$("#todo-list").append(view.render().el); + }, + addAll: function(){ + Todos.each(this.addOne); + }, + newAttributes: function(){ + return { + content: this.input.val(), + order :Todos.nextOrder(), + done :false + }; + }, + createOnEnter: function(e){ + if(e.keyCode != 13) return; + Todos.create(this.newAttributes()); + this.input.val(''); + Todos.fetch({ + url:"index.php?s=Index/fetch" + }); + }, + clearCompleted: function(){ + _.each(Todos.done(),function(todo){todo.clear();}); + return false; + }, + showTooltip:function(e){ + var tooltip = this.$(".ui-tooltip-top"); + var val = this.input.val(); + tooltip.fadeOut(); + if(this.tooltipTimeout) clearTimeout(this.tooltipTimeout); + if(val == '' ||val== this.input.attr('placeholder')) return ; + var show = function(){tooltip.show().fadeIn();}; + this.tooltipTimeout = _.delay(show,1000); + }, + toggleAllComplete: function(){ + var done = this.allCheckbox.checked; + Todos.each(function(todo){todo.save({'done':done});}); + } + }); + var App = new AppView; +}); \ No newline at end of file diff --git a/Todo/Tpl/Index/js/underscore-1.1.6.js b/Todo/Tpl/Index/js/underscore-1.1.6.js new file mode 100644 index 0000000..eaba008 --- /dev/null +++ b/Todo/Tpl/Index/js/underscore-1.1.6.js @@ -0,0 +1,807 @@ +// Underscore.js 1.1.6 +// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var slice = ArrayProto.slice, + unshift = ArrayProto.unshift, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { return new wrapper(obj); }; + + // Export the Underscore object for **CommonJS**, with backwards-compatibility + // for the old `require()` API. If we're not in CommonJS, add `_` to the + // global object. + if (typeof module !== 'undefined' && module.exports) { + module.exports = _; + _._ = _; + } else { + root._ = _; + } + + // Current version. + _.VERSION = '1.1.6'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects implementing `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (_.isNumber(obj.length)) { + for (var i = 0, l = obj.length; i < l; i++) { + if (iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (hasOwnProperty.call(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + return results; + }; + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = memo !== void 0; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial && index === 0) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError("Reduce of empty array with no initial value"); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse(); + return _.reduce(reversed, iterator, memo, context); + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + each(obj, function(value, index, list) { + if (!iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Determine whether all of the elements match a truth test. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result = iterator.call(context, value, index, list)) return breaker; + }); + return result; + }; + + // Determine if a given value is included in the array or object using `===`. + // Aliased as `contains`. + _.include = _.contains = function(obj, target) { + var found = false; + if (obj == null) return found; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + any(obj, function(value) { + if (found = value === target) return true; + }); + return found; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + return _.map(obj, function(value) { + return (method.call ? method || value : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + // Return the maximum element or (element-based computation). + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); + var result = {computed : -Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); + var result = {computed : Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }; + + // Use a comparator function to figure out at what index an object should + // be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator) { + iterator || (iterator = _.identity); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely convert anything iterable into a real, live array. + _.toArray = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + if (_.isArray(iterable)) return iterable; + if (_.isArguments(iterable)) return slice.call(iterable); + return _.values(iterable); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + return _.toArray(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head`. The **guard** check allows it to work + // with `_.map`. + _.first = _.head = function(array, n, guard) { + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + + // Returns everything but the first entry of the array. Aliased as `tail`. + // Especially useful on the arguments object. Passing an **index** will return + // the rest of the values in the array from that index onward. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = function(array, index, guard) { + return slice.call(array, (index == null) || guard ? 1 : index); + }; + + // Get the last element of an array. + _.last = function(array) { + return array[array.length - 1]; + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, function(value){ return !!value; }); + }; + + // Return a completely flattened version of an array. + _.flatten = function(array) { + return _.reduce(array, function(memo, value) { + if (_.isArray(value)) return memo.concat(_.flatten(value)); + memo[memo.length] = value; + return memo; + }, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + var values = slice.call(arguments, 1); + return _.filter(array, function(value){ return !_.include(values, value); }); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted) { + return _.reduce(array, function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el; + return memo; + }, []); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersect = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); + return results; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i, l; + if (isSorted) { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); + for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; + return -1; + }; + + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item) { + if (array == null) return -1; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); + var i = array.length; + while (i--) if (array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. + // Delegates to **ECMAScript 5**'s native `Function.bind` if available. + // We check for `func.bind` first, to fail fast when `func` is undefined. + _.bind = function(func, obj) { + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + var args = slice.call(arguments, 2); + return function() { + return func.apply(obj, args.concat(slice.call(arguments))); + }; + }; + + // Bind all of an object's methods to that object. Useful for ensuring that + // all callbacks defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length == 0) funcs = _.functions(obj); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(func, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Internal function used to implement `_.throttle` and `_.debounce`. + var limit = function(func, wait, debounce) { + var timeout; + return function() { + var context = this, args = arguments; + var throttler = function() { + timeout = null; + func.apply(context, args); + }; + if (debounce) clearTimeout(timeout); + if (debounce || !timeout) timeout = setTimeout(throttler, wait); + }; + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. + _.throttle = function(func, wait) { + return limit(func, wait, false); + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. + _.debounce = function(func, wait) { + return limit(func, wait, true); + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + return memo = func.apply(this, arguments); + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func].concat(slice.call(arguments)); + return wrapper.apply(this, args); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = slice.call(arguments); + return function() { + var args = slice.call(arguments); + for (var i=funcs.length-1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + return function() { + if (--times < 1) { return func.apply(this, arguments); } + }; + }; + + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key; + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + return _.map(obj, _.identity); + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (source[prop] !== void 0) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + // Check object identity. + if (a === b) return true; + // Different types? + var atype = typeof(a), btype = typeof(b); + if (atype != btype) return false; + // Basic equality test (watch out for coercions). + if (a == b) return true; + // One is falsy and the other truthy. + if ((!a && b) || (a && !b)) return false; + // Unwrap any wrapped objects. + if (a._chain) a = a._wrapped; + if (b._chain) b = b._wrapped; + // One of them implements an isEqual()? + if (a.isEqual) return a.isEqual(b); + // Check dates' integer values. + if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime(); + // Both are NaN? + if (_.isNaN(a) && _.isNaN(b)) return false; + // Compare regular expressions. + if (_.isRegExp(a) && _.isRegExp(b)) + return a.source === b.source && + a.global === b.global && + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline; + // If a is not an object by this point, we can't handle it. + if (atype !== 'object') return false; + // Check for different array lengths before comparing contents. + if (a.length && (a.length !== b.length)) return false; + // Nothing else worked, deep compare the contents. + var aKeys = _.keys(a), bKeys = _.keys(b); + // Different object sizes? + if (aKeys.length != bKeys.length) return false; + // Recursive comparison of contents. + for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false; + return true; + }; + + // Is a given array or object empty? + _.isEmpty = function(obj) { + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (hasOwnProperty.call(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType == 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }; + + // Is a given variable an arguments object? + _.isArguments = function(obj) { + return !!(obj && hasOwnProperty.call(obj, 'callee')); + }; + + // Is a given value a function? + _.isFunction = function(obj) { + return !!(obj && obj.constructor && obj.call && obj.apply); + }; + + // Is a given value a string? + _.isString = function(obj) { + return !!(obj === '' || (obj && obj.charCodeAt && obj.substr)); + }; + + // Is a given value a number? + _.isNumber = function(obj) { + return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed)); + }; + + // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript + // that does not equal itself. + _.isNaN = function(obj) { + return obj !== obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false; + }; + + // Is a given value a date? + _.isDate = function(obj) { + return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear); + }; + + // Is the given value a regular expression? + _.isRegExp = function(obj) { + return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false)); + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + // Run a function **n** times. + _.times = function (n, iterator, context) { + for (var i = 0; i < n; i++) iterator.call(context, i); + }; + + // Add your own custom functions to the Underscore object, ensuring that + // they're correctly added to the OOP wrapper as well. + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + addToWrapper(name, _[name] = obj[name]); + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(str, data) { + var c = _.templateSettings; + var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + 'with(obj||{}){__p.push(\'' + + str.replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(c.interpolate, function(match, code) { + return "'," + code.replace(/\\'/g, "'") + ",'"; + }) + .replace(c.evaluate || null, function(match, code) { + return "');" + code.replace(/\\'/g, "'") + .replace(/[\r\n\t]/g, ' ') + "__p.push('"; + }) + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + "');}return __p.join('');"; + var func = new Function('obj', tmpl); + return data ? func(data) : func; + }; + + // The OOP Wrapper + // --------------- + + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + var wrapper = function(obj) { this._wrapped = obj; }; + + // Expose `wrapper.prototype` as `_.prototype` + _.prototype = wrapper.prototype; + + // Helper function to continue chaining intermediate results. + var result = function(obj, chain) { + return chain ? _(obj).chain() : obj; + }; + + // A method to easily add functions to the OOP wrapper. + var addToWrapper = function(name, func) { + wrapper.prototype[name] = function() { + var args = slice.call(arguments); + unshift.call(args, this._wrapped); + return result(func.apply(_, args), this._chain); + }; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + method.apply(this._wrapped, arguments); + return result(this._wrapped, this._chain); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + return result(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + // Start chaining a wrapped Underscore object. + wrapper.prototype.chain = function() { + this._chain = true; + return this; + }; + + // Extracts the result from a wrapped and chained object. + wrapper.prototype.value = function() { + return this._wrapped; + }; + +})(); diff --git a/Todo/Tpl/Index/js/underscore-min.js b/Todo/Tpl/Index/js/underscore-min.js new file mode 100644 index 0000000..d22f881 --- /dev/null +++ b/Todo/Tpl/Index/js/underscore-min.js @@ -0,0 +1,6 @@ +// Underscore.js 1.5.2 +// http://underscorejs.org +// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. +(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,g=e.filter,d=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,w=Object.keys,_=i.bind,j=function(n){return n instanceof j?n:this instanceof j?(this._wrapped=n,void 0):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exports._=j):n._=j,j.VERSION="1.5.2";var A=j.each=j.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a=j.keys(n),u=0,i=a.length;i>u;u++)if(t.call(e,n[a[u]],a[u],n)===r)return};j.map=j.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var E="Reduce of empty array with no initial value";j.reduce=j.foldl=j.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=j.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(E);return r},j.reduceRight=j.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=j.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=j.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(E);return r},j.find=j.detect=function(n,t,r){var e;return O(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},j.filter=j.select=function(n,t,r){var e=[];return null==n?e:g&&n.filter===g?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},j.reject=function(n,t,r){return j.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},j.every=j.all=function(n,t,e){t||(t=j.identity);var u=!0;return null==n?u:d&&n.every===d?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var O=j.some=j.any=function(n,t,e){t||(t=j.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};j.contains=j.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:O(n,function(n){return n===t})},j.invoke=function(n,t){var r=o.call(arguments,2),e=j.isFunction(t);return j.map(n,function(n){return(e?t:n[t]).apply(n,r)})},j.pluck=function(n,t){return j.map(n,function(n){return n[t]})},j.where=function(n,t,r){return j.isEmpty(t)?r?void 0:[]:j[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},j.findWhere=function(n,t){return j.where(n,t,!0)},j.max=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.max.apply(Math,n);if(!t&&j.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>e.computed&&(e={value:n,computed:a})}),e.value},j.min=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.min.apply(Math,n);if(!t&&j.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;ae||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={},i=null==r?j.identity:k(r);return A(t,function(r,a){var o=i.call(e,r,a,t);n(u,o,r)}),u}};j.groupBy=F(function(n,t,r){(j.has(n,t)?n[t]:n[t]=[]).push(r)}),j.indexBy=F(function(n,t,r){n[t]=r}),j.countBy=F(function(n,t){j.has(n,t)?n[t]++:n[t]=1}),j.sortedIndex=function(n,t,r,e){r=null==r?j.identity:k(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;r.call(e,n[o])=0})})},j.difference=function(n){var t=c.apply(e,o.call(arguments,1));return j.filter(n,function(n){return!j.contains(t,n)})},j.zip=function(){for(var n=j.max(j.pluck(arguments,"length").concat(0)),t=new Array(n),r=0;n>r;r++)t[r]=j.pluck(arguments,""+r);return t},j.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},j.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=j.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},j.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},j.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=new Array(e);e>u;)i[u++]=n,n+=r;return i};var R=function(){};j.bind=function(n,t){var r,e;if(_&&n.bind===_)return _.apply(n,o.call(arguments,1));if(!j.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));R.prototype=n.prototype;var u=new R;R.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},j.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},j.bindAll=function(n){var t=o.call(arguments,1);if(0===t.length)throw new Error("bindAll must be passed function names");return A(t,function(t){n[t]=j.bind(n[t],n)}),n},j.memoize=function(n,t){var r={};return t||(t=j.identity),function(){var e=t.apply(this,arguments);return j.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},j.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},j.defer=function(n){return j.delay.apply(j,[n,1].concat(o.call(arguments,1)))},j.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var c=function(){o=r.leading===!1?0:new Date,a=null,i=n.apply(e,u)};return function(){var l=new Date;o||r.leading!==!1||(o=l);var f=t-(l-o);return e=this,u=arguments,0>=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u)):a||r.trailing===!1||(a=setTimeout(c,f)),i}},j.debounce=function(n,t,r){var e,u,i,a,o;return function(){i=this,u=arguments,a=new Date;var c=function(){var l=new Date-a;t>l?e=setTimeout(c,t-l):(e=null,r||(o=n.apply(i,u)))},l=r&&!e;return e||(e=setTimeout(c,t)),l&&(o=n.apply(i,u)),o}},j.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},j.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},j.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},j.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},j.keys=w||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)j.has(n,r)&&t.push(r);return t},j.values=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},j.pairs=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},j.invert=function(n){for(var t={},r=j.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},j.functions=j.methods=function(n){var t=[];for(var r in n)j.isFunction(n[r])&&t.push(r);return t.sort()},j.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},j.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},j.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)j.contains(r,u)||(t[u]=n[u]);return t},j.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},j.clone=function(n){return j.isObject(n)?j.isArray(n)?n.slice():j.extend({},n):n},j.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof j&&(n=n._wrapped),t instanceof j&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==String(t);case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;var a=n.constructor,o=t.constructor;if(a!==o&&!(j.isFunction(a)&&a instanceof a&&j.isFunction(o)&&o instanceof o))return!1;r.push(n),e.push(t);var c=0,f=!0;if("[object Array]"==u){if(c=n.length,f=c==t.length)for(;c--&&(f=S(n[c],t[c],r,e)););}else{for(var s in n)if(j.has(n,s)&&(c++,!(f=j.has(t,s)&&S(n[s],t[s],r,e))))break;if(f){for(s in t)if(j.has(t,s)&&!c--)break;f=!c}}return r.pop(),e.pop(),f};j.isEqual=function(n,t){return S(n,t,[],[])},j.isEmpty=function(n){if(null==n)return!0;if(j.isArray(n)||j.isString(n))return 0===n.length;for(var t in n)if(j.has(n,t))return!1;return!0},j.isElement=function(n){return!(!n||1!==n.nodeType)},j.isArray=x||function(n){return"[object Array]"==l.call(n)},j.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){j["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),j.isArguments(arguments)||(j.isArguments=function(n){return!(!n||!j.has(n,"callee"))}),"function"!=typeof/./&&(j.isFunction=function(n){return"function"==typeof n}),j.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},j.isNaN=function(n){return j.isNumber(n)&&n!=+n},j.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},j.isNull=function(n){return null===n},j.isUndefined=function(n){return n===void 0},j.has=function(n,t){return f.call(n,t)},j.noConflict=function(){return n._=t,this},j.identity=function(n){return n},j.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},j.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var I={escape:{"&":"&","<":"<",">":">",'"':""","'":"'"}};I.unescape=j.invert(I.escape);var T={escape:new RegExp("["+j.keys(I.escape).join("")+"]","g"),unescape:new RegExp("("+j.keys(I.unescape).join("|")+")","g")};j.each(["escape","unescape"],function(n){j[n]=function(t){return null==t?"":(""+t).replace(T[n],function(t){return I[n][t]})}}),j.result=function(n,t){if(null==n)return void 0;var r=n[t];return j.isFunction(r)?r.call(n):r},j.mixin=function(n){A(j.functions(n),function(t){var r=j[t]=n[t];j.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(j,n))}})};var N=0;j.uniqueId=function(n){var t=++N+"";return n?n+t:t},j.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;j.template=function(n,t,r){var e;r=j.defaults({},r,j.templateSettings);var u=new RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(D,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=new Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,j);var c=function(n){return e.call(this,n,j)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},j.chain=function(n){return j(n).chain()};var z=function(n){return this._chain?j(n).chain():n};j.mixin(j),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];j.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];j.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),j.extend(j.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); +//# sourceMappingURL=underscore-min.map \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..dffb526 --- /dev/null +++ b/index.php @@ -0,0 +1,8 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/backbone-min.js b/test/backbone-min.js new file mode 100644 index 0000000..3541019 --- /dev/null +++ b/test/backbone-min.js @@ -0,0 +1,4 @@ +(function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.0.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this}a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=k[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON});var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&window.ActiveXObject&&!(window.external&&window.external.msActiveXFilteringEnabled)){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(h.extend(s,i));e.trigger("request",e,o,i);return o};var k={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var S=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var $=/\((.*?)\)/g;var T=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(S.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.apply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace($,"(?:$1)?").replace(T,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var P=/^\/+|\/+$/g;var O=/msie [\w.]+/;var C=/\/$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.substr(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({},{root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=O.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(P,"/");if(r&&this._wantsHashChange){this.iframe=a.$('