_is_pc = $name == 'pc'; // 标记为pc端模板 $this->_is_mobile = $name == 'mobile'; // 标记为移动端模板 // 模板缓存目录 $this->_cache = WRITEPATH.'template/'; $this->_tname = $this->_is_mobile ? MOBILE_TPL_DIR : ($name ? $name : 'pc'); $this->_aroot = $this->_froot = COREPATH.'View/'; $this->_mroot = $this->get_client_member_path($this->_tname); // 当前项目模板目录 if (IS_ADMIN) { // 后台 $this->admin(); } elseif (IS_MEMBER) { // 会员 //$this->_is_mobile && !is_dir(TPLPATH.'mobile/'.SITE_TEMPLATE.'/member/') && $this->_tname = 'pc'; $this->_root = $this->get_client_home_path($this->_tname); $this->_dir = $this->_mroot; // 当用户中心没有这个模板目录时我们就调用default的用户中心模板 !is_dir($this->_mroot) && $this->_mroot = str_replace('/'.SITE_TEMPLATE.'/', '/default/', $this->_mroot); // 项目的会员中心 APP_DIR != 'member' && $this->_dir = $this->get_client_member_path($this->_tname, APP_DIR); } elseif (IS_API || (APP_DIR && dr_is_app_dir(APP_DIR))) { // 插件模块或者api $dir = IS_API ? 'api' : APP_DIR; //$this->_is_mobile && !is_dir(TPLPATH.'mobile/'.SITE_TEMPLATE.'/home/') && $this->_tname = 'pc'; $this->_root = $this->get_client_home_path($this->_tname); $this->_dir = $this->get_client_home_path($this->_tname, $dir); } else { // 首页前端页面 //$this->_is_mobile && !is_dir(TPLPATH.'mobile/'.SITE_TEMPLATE.'/home/') && $this->_tname = 'pc'; $this->_dir = $this->_root = $this->get_client_home_path($this->_tname); } // 系统action $this->action = [ 'category', 'module', 'content', 'related', 'share', 'table', 'form', 'mform', 'member', 'page', 'tag', 'hits', 'search', 'category_search_field', 'linkage', 'sql', 'function', 'comment', 'cache', 'navigator' ,'modules' ]; } // 判断是pc端模板 public function is_pc() { return $this->_is_pc; } // 判断是移动端模板 public function is_mobile() { return $this->_is_mobile; } // 终端路径 private function get_client_home_path($name, $mid = '') { if ($name == 'NULL') { return TPLPATH.($mid ? $mid.'/' : ''); } return dr_get_app_tpl($mid).$name.'/'.SITE_TEMPLATE.'/home/'.($mid ? $mid.'/' : ''); } // 终端路径 private function get_client_member_path($name, $mid = '') { return dr_get_app_tpl($mid).$name.'/'.SITE_TEMPLATE.'/member/'.($mid ? $mid.'/' : ''); } /** * 强制设置模块模板目录 * * @param string $dir 模板名称 * @param string $isweb 强制前台 */ public function module($module, $isweb = 0) { if ($isweb == 0 && (IS_ADMIN || IS_MEMBER)) { return; } // 默认模板目录 $this->_is_admin = 0; $this->_root = $this->get_client_home_path($this->_tname); $this->_dir = $this->get_client_home_path($this->_tname, $module); } // 外部获取当前应用的模板路径 public function get_dir() { return $this->_dir; } /** * 强制设置为当前默认的模板目录(一般用于api外部接入) */ public function dir($dir) { $this->_dir = $this->_mdir = TPLPATH.$dir; } /** * 强制设置为当前默认的模板目录 */ public function set_dir($path) { $this->_dir = $this->_mdir = $path; } /** * 设置是否返回模板名称不显示 */ public function set_return($is) { $this->_is_return = $is; } /** * 强制设置为后台模板目录 */ public function admin($path = '', $fix_path = '') { $this->_aroot = COREPATH.'View/'; $this->_dir = $path ? $path : (APP_DIR ? APPPATH.'Views/' : $this->_aroot); $this->_froot = $fix_path ? $fix_path : (APP_DIR ? APPPATH.'Views/' : $this->_aroot); $this->_is_admin = 1; } /** * 当前模板对应的URL地址 */ public function now_php_url() { if (isset($this->_options['my_php_url']) && $this->_options['my_php_url']) { return $this->_options['my_php_url']; } elseif (isset($this->_options['my_web_url']) && $this->_options['my_web_url']) { return $this->_options['my_web_url']; } return FC_NOW_URL; } /** * 输出模板 * * @param string $_name 模板文件名称(含扩展名) * @param string $_dir 模块名称 * @param boll $is_destruction 是否销毁变量 * @return void */ public function display($phpcmf_name, $phpcmf_dir = '', $is_destruction = true) { if ($this->_is_return) { return $phpcmf_name; } $phpcmf_start = microtime(true); // 定义当前模板的url地址 if (!isset($this->_options['my_web_url']) or !$this->_options['my_web_url']) { $this->_options['my_web_url'] = isset($this->_options['fix_html_now_url']) && $this->_options['fix_html_now_url'] ? $this->_options['fix_html_now_url'] : dr_now_url(); } // 定义当前url参数值 if (!isset($this->_options['get'])) { $this->_options['get'] = \Phpcmf\Service::L('input')->xss_clean($_GET); } // 如果是来自api就不解析模板,直接输出变量 if (IS_API_HTTP) { \Phpcmf\Service::C()->_json(1, '当前是get请求方式,返回当前模板可用的变量', $this->_options); } // 生成静态时退出账号记录 if (defined('SC_HTML_FILE')) { $this->_options['member'] = []; } // 挂钩点 模板加载之前 \Phpcmf\Hooks::trigger('cms_view_display', $this->_options, $phpcmf_name, $phpcmf_dir); extract($this->_options, EXTR_SKIP); $ci = \Phpcmf\Service::C(); // 控制器对象简写 $phpcmf_name && $this->_filename = str_replace('..', '[removed]', $phpcmf_name); // 加载编译后的缓存文件 $this->_disp_dir = $phpcmf_dir; $this->_view_file = $_view_file = $this->get_file_name($this->_filename, $phpcmf_dir); $is_dev = 0; if ((IS_DEV || (IS_ADMIN && SYS_DEBUG)) && !isset($_GET['callback']) && !isset($_GET['is_ajax']) && !IS_API_HTTP && !IS_AJAX) { $is_dev = 1; echo "".PHP_EOL; } // 兼容php8 !defined('IS_SHARE') && define('IS_SHARE', 1); !defined('IS_OEM_CMS') && define('IS_OEM_CMS', 0); !defined('MOD_DIR') && define('MOD_DIR', ''); !defined('MODULE_NAME') && define('MODULE_NAME', ''); !defined('MODULE_URL') && define('MODULE_URL', ''); !defined('SITE_TITLE') && define('SITE_TITLE', SITE_NAME); !defined('IS_PC') && define('IS_PC', \Phpcmf\Service::IS_PC_USER()); !defined('IS_MOBILE') && define('IS_MOBILE', \Phpcmf\Service::IS_MOBILE_USER()); !defined('IS_MOBILE_USER') && define('IS_MOBILE_USER', \Phpcmf\Service::IS_MOBILE_USER()); !defined('IS_COMMENT') && define('IS_COMMENT', dr_is_app('comment')); !defined('IS_CLIENT') && define('IS_CLIENT', ''); $LANG_PATH = LANG_PATH; $THEME_PATH = THEME_PATH; $_temp_file = $this->load_view_file($_view_file); // 挂钩点 模板加载之后 \Phpcmf\Hooks::trigger('cms_view', $this->_options, $_temp_file); include $_temp_file; // 挂钩点 模板结束之后 \Phpcmf\Hooks::trigger('cms_view_end'); $this->_view_time = round(microtime(true) - $phpcmf_start, 2); // 消毁变量 if ($is_destruction) { unset($this->loadjs); unset($this->_include_file); if (!$is_dev) { unset($this->_options); } if (!defined('IS_INSTALL') && (CI_DEBUG || !defined('SC_HTML_FILE'))) { \Phpcmf\Service::M()->close(); } } } // 动态加载js public function load_js($js) { if (isset($this->loadjs[$js])) { return ''; } else { $this->loadjs[$js] = 1; return ''; } } /** * 设置模块/应用的模板目录 * * @param string $file 文件名 * @param string $dir 模块/应用名称 * @param string $include 是否使用的是include标签 */ public function get_file_name($file, $dir = null, $include = FALSE) { if (!$file) { $this->show_error('模板文件没有设置'); } $dir = $dir ? $dir : $this->_disp_dir; $file = str_replace('..', '', (string)$file); // 安全规范化模板名称引入 if ($dir == 'admin' || $this->_is_admin) { // 后台操作时,不需要加载风格目录,如果文件不存在可以尝试调用主项目模板 if (APP_DIR && is_file(MYPATH.'View/'.APP_DIR.'/'.$file)) { return MYPATH . 'View/' . APP_DIR . '/' . $file; } elseif (is_file(MYPATH.'View/'.$file) && is_file(COREPATH.'View/'.$file)) { if (APP_DIR && is_file($this->_dir.$file)) { // 防止app目录加载主目录的模板 return $this->_dir.$file; } return MYPATH.'View/'.$file; } elseif ((!APP_DIR or $dir == 'admin') && is_file(MYPATH.'View/'.$file)) { // 强制定位admin目录时验证my目录文件 return MYPATH.'View/'.$file; } elseif (is_file($this->_dir.$file)) { return $this->_dir.$file; // 调用当前后台的模板 } elseif (is_file($this->_froot.$file)) { $this->_load_file_tips[$file] = '由于模板文件['.$this->_dir.$file.']不存在,因此本页面引用主目录的模板['.$this->_froot.$file.']!'; return $this->_froot.$file; // 当前项目目录模板不存在时调用主项目的 } elseif (is_file($this->_aroot.$file)) { $this->_load_file_tips[$file] = '由于模板文件['.$this->_dir.$file.']不存在,因此本页面引用主目录的模板['.$this->_aroot.$file.']'; return $this->_aroot.$file; // 当前项目目录模板不存在时调用主项目的 } elseif (APP_DIR && is_file(MYPATH.'View/'.$file)) { return MYPATH.'View/'.$file; // 当前项目目录模板不存在时调用主项目的My目录 } elseif ($dir != 'admin' && is_file(APPSPATH.ucfirst($dir).'/Views/'.$file)) { return APPSPATH.ucfirst($dir).'/Views/'.$file; // 指定模块时调用模块下的文件 } $error = $this->_dir.$file; } elseif (IS_MEMBER || $dir == 'member') { // 会员操作时,需要加载风格目录,如果文件不存在可以尝试调用主项目模板 if ($dir === '/' && is_file($this->_root.$file)) { return $this->_root.$file; } if (IS_XRDEV) { $this->_dir = dr_get_app_tpl($dir ? $dir : 'member').$this->_tname.'/'.SITE_TEMPLATE.'/member/'.($dir ? $mid.'/' : ''); } if (is_file($this->_dir.$file)) { // 调用当前的会员模块目录 return $this->_dir.$file; } elseif (is_file($this->_mroot.$file)) { // 调用默认的会员模块目录 $this->_load_file_tips[$file] = '由于模板文件['.$this->_dir.$file.']不存在,因此本页面引用会员模块目录的模板['.$this->_mroot.$file.']'; return $this->_mroot.$file; } elseif (is_file($this->_root.$file)) { // 调用网站主站模块目录 $this->_load_file_tips[$file] = '由于模板文件['.$this->_dir.$file.']不存在,因此本页面引用主目录的模板['.$this->_root.$file.']'; return $this->_root.$file; } else { // 仍然没有找到文件 if (IS_XRDEV && APP_DIR) { $this->_dir = dr_get_app_tpl(APP_DIR).$this->_tname.'/default/member/'.APP_DIR.'/'; if (is_file($this->_dir.$file)) { // 调用当前的会员模块目录 return $this->_dir.$file; } $this->_dir = dr_get_app_tpl(APP_DIR).$this->_tname.'/default/member/'; if (is_file($this->_dir.$file)) { // 调用当前的会员模块目录 return $this->_dir.$file; } } } $error = $dir === '/' ? $this->_root.$file : $this->_dir.$file; } elseif ($file == 'goto_url') { // 转向字段模板 return COREPATH.'View/go.html'; } elseif (CLIENT_NAME == '') { if (is_file($this->_dir.$file)) { return $this->_dir.$file; } return $this->_root.$file; } else { if (IS_XRDEV) { if (\Phpcmf\Service::C()->module) { $this->_dir = dr_get_app_tpl(APP_DIR).$this->_tname.'/'.SITE_TEMPLATE.'/home/'.APP_DIR.'/'; if (is_file($this->_dir.$file)) { return $this->_dir.$file; } $this->_dir = dr_get_app_tpl('module').$this->_tname.'/'.SITE_TEMPLATE.'/home/'.($dir ? $mid.'/' : ''); } } if ($dir === '/' && is_file($this->_root.$file)) { // 强制主目录 return $this->_root.$file; } elseif (is_file($this->_dir.$file)) { // 调用本目录 return $this->_dir.$file; } elseif (is_file($this->_root.$file)) { // 再次调用主程序下的文件 $this->_load_file_tips[$file] = '由于模板文件['.$this->_dir.$file.']不存在,因此本页面引用主目录的模板['.$this->_root.$file.']'; return $this->_root.$file; } // 尝试判断主defualt目录 $default_file = TPLPATH.$this->_tname.'/default/home/'.(APP_DIR ? APP_DIR.'/' : '').$file; if (is_file($default_file)) { $this->_load_file_tips[$file] = '由于模板文件['.$this->_dir.$file.']不存在,因此本页面引用default目录的模板['.$default_file.']'; return $default_file; } $error = $dir === '/' ? $this->_root.$file : $this->_dir.$file; $default_file = str_replace($this->_root, TPLPATH.$this->_tname.'/default/home/', $error); if (is_file($default_file)) { $this->_load_file_tips[$file] = '由于模板文件['.$this->_dir.$file.']不存在,因此本页面引用default目录的模板['.$default_file.']'; return $default_file; } } /* // 如果移动端模板不存在就调用主网站风格 if ($this->_is_mobile && is_file(str_replace('/mobile/', '/pc/', $error))) { return str_replace('/mobile/', '/pc/', $error); } elseif ($this->_is_mobile && is_file(str_replace('/mobile/', '/pc/', $this->_root.$file))) { return str_replace('/mobile/', '/pc/', $this->_root.$file); }*/ if (in_array($file, ['msg.html', '404.html'])) { if (IS_USE_MODULE && is_file(TPLPATH.'pc/default/home/'.$file)) { return TPLPATH.'pc/default/home/'.$file; } elseif (is_file(TPLPATH.$file)) { return TPLPATH.$file; } } if (CI_DEBUG) { log_message('error', '模板文件['.$error.']不存在'); if ($file == 'msg.html' || $file == '404.html') { return COREPATH.'View/api_msg.html'; } if ($this->_is_mobile && $default_file) { $pc = str_replace('/mobile/', '/pc/', (string)$default_file); if (is_file($pc)) { $this->show_error('移动端模板文件不存在', $error, $pc);exit; } } } $this->show_error('模板文件不存在', $error); } /** * 设置模板变量 */ public function assign($key, $value = '') { if (!$key) { return FALSE; } if (is_array($key)) { foreach ($key as $k => $v) { $this->_options[$k] = $v; } } else { $this->_options[$key] = $value; } } /** * 获取模板变量 */ public function get_value($key) { if (!$key) { return ''; } return $this->_options[$key]; } /** * 重新赋值模板变量 */ public function set_value($key, $value = '', $replace = '') { if (!$key) { return ''; } $this->_options[$key] = $replace ? str_replace($replace, $value, $this->_options[$key]) : $value; } /** * 模板标签include/template * * @param string $name 模板文件 * @param string $dir 应用、模块目录 * @return bool */ public function _include($name, $dir = '') { $dir = $dir == 'MOD_DIR' ? MOD_DIR : $dir; $file = $this->get_file_name($name, $dir, TRUE); $fname = md5($file); isset($this->_include_file[$fname]) ? $this->_include_file[$fname] ++ : $this->_include_file[$fname] = 0; if ($this->_include_file[$fname] > 500) { $this->show_error('模板文件标签template引用文件目录结构错误', $file); } return $this->load_view_file($file); } /** * 模板标签load * * @param string $file 模板文件 * @return bool */ public function _load($file) { $file = (string)$file; if ($file === '' || strpos($file, '://') !== false) { $this->show_error('模板文件路径非法', $file); } if (!in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), ['html', 'htm'])) { $this->show_error('模板文件只能是html、htm格式', $file); } $fname = md5($file); isset($this->_include_file[$fname]) ? $this->_include_file[$fname] ++ : $this->_include_file[$fname] = 0; if ($this->_include_file[$fname] > 500) { $this->show_error('模板文件标签load引用文件目录结构错误', $file); } $safe_name = $this->_safe_template_path($file); if ($safe_name && is_file($safe_name)) { // 安全目录 } else { $file = $this->get_file_name($file); } return $this->load_view_file($file); } /** * 允许的模板根目录(FCPATH / TPLPATH / WRITEPATH) */ private function _template_roots() { static $roots = null; if ($roots !== null) { return $roots; } $path = [FCPATH, TPLPATH, WRITEPATH]; if (defined('XRDEV_PATH')) { $path[] = XRDEV_PATH; } $roots = []; foreach ($path as $dir) { $r = realpath($dir); $r && $roots[] = $r; } return $roots; } /** * 校验模板源文件:仅允许 html/htm,且位于允许的模板根目录下 * 失败时写入 $_safe_template_error,开发者模式下由调用方展示 * * @param string $path 模板绝对/相对路径 * @return string|false 合法绝对路径,失败返回 false */ public function _safe_template_path($path) { $this->_safe_template_error = ''; if (!$path || strpos($path, "\0") !== false) { $this->_safe_template_error = '路径为空或包含非法空字符'; return false; } $real = realpath($path); if (!$real) { $this->_safe_template_error = 'realpath失败,文件不存在或路径不可解析:'.$path; return false; } if (!is_file($real)) { $this->_safe_template_error = '路径不是普通文件:'.$real; return false; } $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); if (!in_array($ext, ['html', 'htm'])) { $this->_safe_template_error = '扩展名必须是 html/htm,当前为:'.($ext !== '' ? $ext : '(无)'); return false; } $roots = $this->_template_roots(); if (!$roots) { $this->_safe_template_error = '未配置可用模板根目录(FCPATH/TPLPATH/WRITEPATH 等 realpath 均为空)'; return false; } foreach ($roots as $root) { if (strncmp($real, $root, strlen($root)) === 0) { return $real; } } $this->_safe_template_error = '文件不在允许的模板根目录内。文件:'.$real.';允许目录:'.implode('、', $roots); return false; } /** * 加载缓存文件 * * @param string * @return string */ public function load_view_file($name) { $safe_name = $this->_safe_template_path($name); if (!$safe_name) { $msg = '模板文件不存在或路径非法'; if ((defined('IS_DEV') && IS_DEV) || CI_DEBUG) { $msg = $this->_safe_template_error ? ':'.$this->_safe_template_error : ''; } $this->show_error($msg, $name); } $name = $safe_name; $cache_file = $this->_cache.str_replace([ WEBPATH, '/', '\\', DIRECTORY_SEPARATOR, ':', '?', '*', '|', '<', '>' ], [ '', '_DS_', '_DS_', '_DS_', '', '', '', '', '', '' ], $name).'.cache.php'; $this->_view_files[$name] = [ 'name' => pathinfo($name, PATHINFO_BASENAME), 'path' => $name, ]; // 当缓存文件不存在时或者缓存文件创建时间少于了模板文件时,再重新生成缓存文件 // 开发者模式下关闭缓存 if (IS_DEV || !is_file($cache_file) || (is_file($cache_file) && is_file($name) && filemtime($cache_file) < filemtime($name))) { // 防止目录未创建的情况 $path = dirname($cache_file); if (!is_dir($path)) { dr_mkdirs($path); } // 写入新文件 $content = $this->handle_view_file(file_get_contents($name)); if (file_put_contents($cache_file, $content, LOCK_EX) === FALSE) { if (IS_DEV) { $this->show_error('模板缓存文件 ('.$cache_file.') 创建失败,请将cache目录权限设为777'); } else { $this->show_error('请将模板缓存目录 ('.$path.') 权限设为777'); } } } return $cache_file; } // 将模板代码转化为php public function code2php($code, $time = 0, $include = 1) { $file = md5($code).$time.'.code.php'; if (!$include) { $code = preg_replace([ '#{template.*}#Uis', '#{load.*}#Uis' ], [ '--', '--', ], $code); } if (!is_file($this->_cache.$file)) { file_put_contents($this->_cache.$file, str_replace('$this->', '\Phpcmf\Service::V()->', $this->handle_view_file($code))); } return $this->_cache.$file; } /** * 解析模板文件 * * @param string * @param string * @return string */ public function handle_view_file($view_content) { if (!$view_content) { return ''; } if (function_exists('my_parser_view_rule')) { $view_content = my_parser_view_rule($view_content); } // 正则表达式匹配的模板标签 $regex_array = [ // 3维数组变量 '#{\$(\w+?)\.(\w+?)\.(\w+?)\.(\w+?)}#i', // 2维数组变量 '#{\$(\w+?)\.(\w+?)\.(\w+?)}#i', // 1维数组变量 '#{\$(\w+?)\.(\w+?)}#i', // 3维数组变量 '#\$(\w+?)\.(\w+?)\.(\w+?)\.(\w+?)#Ui', // 2维数组变量 '#\$(\w+?)\.(\w+?)\.(\w+?)#Ui', // 1维数组变量 '#\$(\w+?)\.(\w+?)#Ui', // PHP函数 '#{([a-z_0-9]+)\((.*)\)}#Ui', // PHP常量 '#{([A-Z_0-9]+)}#', // PHP变量 '#{\$(.+?)}#i', // 类库函数 '#{([A-Za-z_]+)::(.+)\((.*)\)}#Ui', // 引入模板 '#{\s*template\s+"([\$\-_\/\w\.]+)",\s*"(.+)"\s*}#Uis', '#{\s*template\s+"([\$\-_\/\w\.]+)",\s*MOD_DIR\s*}#Uis', '#{\s*template\s+"([\$\-_\/\w\.]+)"\s*}#Uis', '#{\s*template\s+([\$\-_\/\w\.]+)\s*}#Uis', // 加载指定文件到模板 '#{\s*load\s+"([\$\-_\/\w\.]+)"\s*}#Uis', '#{\s*load\s+([\$\-_\/\w\.]+)\s*}#Uis', // php标签 '#{php\s+(.+?)}#is', // list标签 '#{list\s+(.+?)return=([\w]+)}#i', //(.+?)\s? '#{list\s+(.+?)\s?}#i', '#{\s?\/list\s?}#i', // if判断语句 '#{\s?if\s+(.+?)\s?}#i', '#{\s?else\sif\s+(.+?)\s?}#i', '#{\s?elseif\s+(.+?)\s?}#i', '#{\s?else\s?}#i', '#{\s?\/if\s?}#i', // 循环语句 '#{\s?loop\s+\$(.+?)\s+\$(\w+?)\s?\$(\w+?)\s?}#i', '#{\s?loop\s+\$(.+?)\s+\$(\w+?)\s?}#i', '#{\s?loop\s+\$(.+?)\s+\$(\w+?)\s?=>\s?\$(\w+?)\s?}#i', '#{\s?\/loop\s?}#i', // for '#{for\s+(.+?)\s+(.+?)\s+(.+?)\s?}#i', '#{\s?\/for\s?}#i', // 结束标记 '#{\s?php\s?}#i', '#{\s?\/php\s?}#i', '#\?\>\s*\<\?php\s#s', // 结果为空时 '#{\s?empty\s?}#i', '#{\s?\/empty\s?}#i', ]; // 替换直接变量输出 $replace_array = [ "", "", "", "\$\\1['\\2']['\\3']['\\4']", "\$\\1['\\2']['\\3']", "\$\\1['\\2']", "", "", "", "\\2(\\3); ?>", //"library_method(\"\\1\",\"\\2\", \$this->_get_method(\\3));, "_include(\"\\1\", \"\\2\")) { include(\$fn_include); } ?>", "_include(\"\\1\", \"MOD_DIR\")) { include(\$fn_include); } ?>", "_include(\"\\1\")) { include(\$fn_include); } ?>", "_include(\"\\1\")) { include(\$fn_include); } ?>", "_load(\"\\1\")) { include(\$fn_include); } ?>", "_load(\"\\1\")) { include(\$fn_include); } ?>", "", "list_tag(\"\\1 return=\\2\"); if (\$list_return_\\2) { extract(\$list_return_\\2, EXTR_OVERWRITE); \$count_\\2=dr_count(\$return_\\2);} if (is_array(\$return_\\2) && \$return_\\2) { \$key_\\2=-1;foreach (\$return_\\2 as \$\\2) { \$key_\\2++; \$is_first=\$key_\\2==0 ? 1 : 0;\$is_last=\$count_\\2==\$key_\\2+1 ? 1 : 0; ?>", "list_tag(\"\\1\"); if (\$list_return) { extract(\$list_return, EXTR_OVERWRITE); \$count=dr_count(\$return);} if (is_array(\$return) && \$return) { \$key=-1; foreach (\$return as \$t) { \$key++; \$is_first=\$key==0 ? 1 : 0;\$is_last=\$count==\$key+1 ? 1 : 0; ?>", "", "", "", "", "", "", "\$\\3) { \$key_\\3++; \$is_first=\$key_\\3==0 ? 1 : 0;\$is_last=\$count_\\3==\$key_\\3+1 ? 1 : 0; ?>", "", "\$\\3) { \$key_\\3++; \$is_first=\$key_\\3==0 ? 1 : 0;\$is_last=\$count_\\3==\$key_\\3+1 ? 1 : 0; ?>", "", "", "", "", " ", "", "", ]; // 统计和求和 foreach (['sum', 'count'] as $name) { // 正则表达式匹配的模板标签 $regex_array[] = '#{'.$name.'\s+(.+?)return=([\w]+)}#i';// 去掉\s,win平台 $regex_array[] = '#{'.$name.'\s+(.+?)\s?}#i'; // 替换直接变量输出 $replace_array[] = "list_tag(\"".$name." \\1 return=\\2\"); if (\$list_return_".$name."_\\2 && is_array(\$list_return_".$name."_\\2)) { extract(\$list_return_".$name."_\\2, EXTR_OVERWRITE); \$\\2_".$name."=(\$return_".$name." ? \$return_".$name."[0]['ct'] : 0); } else { \$\\2_".$name."= 0; } ?>"; $replace_array[] = "list_tag(\"".$name." \\1\"); if (\$list_return_".$name." && is_array(\$list_return_".$name.")) { extract(\$list_return_".$name.", EXTR_OVERWRITE); echo (\$return_".$name." ? \$return_".$name."[0]['ct'] : 0); } else { echo 0; } ?>"; } // list标签别名 foreach ($this->action as $name) { // 正则表达式匹配的模板标签 $regex_array[] = '#{'.$name.'\s+(.+?)return=([\w]+)}#i';// 去掉\s,win平台 $regex_array[] = '#{'.$name.'\s+(.+?)\s?}#i'; $regex_array[] = '#{\s?\/'.$name.'\s?}#i'; // 替换直接变量输出 $replace_array[] = "list_tag(\"action=".$name." \\1 return=\\2\"); if (\$list_return_\\2 && is_array(\$list_return_\\2)) { extract(\$list_return_\\2, EXTR_OVERWRITE); } \$count_\\2=dr_count(\$return_\\2); if (is_array(\$return_\\2) && \$return_\\2) { \$key_\\2=-1; foreach (\$return_\\2 as \$\\2) { \$key_\\2++; \$is_first=\$key_\\2==0 ? 1 : 0;\$is_last=\$count_\\2==\$key_\\2+1 ? 1 : 0; ?>"; $replace_array[] = "list_tag(\"action=".$name." \\1\"); if (\$list_return && is_array(\$list_return)) { extract(\$list_return, EXTR_OVERWRITE); } \$count=dr_count(\$return); if (is_array(\$return) && \$return) { \$key=-1; foreach (\$return as \$t) { \$key++; \$is_first=\$key==0 ? 1 : 0;\$is_last=\$count==\$key+1 ? 1 : 0; ?>"; $replace_array[] = ""; } // 注释内容 $view_content = preg_replace('#{note}(.+){/note}#Us', '', $view_content); // 保护代码 $this->_code = []; $view_content = preg_replace_callback('#{code}(.+){/code}#Us', function ($match) { $key = count($this->_code); $this->_code[$key] = $match[1]; return ''; }, $view_content); $view_content = preg_replace($regex_array, $replace_array, $view_content); $view_content = preg_replace_callback("/_get_var\('(.*)'\)/Ui", function ($match) { return "_get_var('".preg_replace('#\[\'(\w+)\'\]#Ui', '.\\1', $match[1])."')"; }, $view_content); $view_content = preg_replace_callback("/list_tag\(\"(.*)\"\)/Ui", function ($match) { return "list_tag(\"".preg_replace('#\[\'(\w+)\'\]#Ui', '[\\1]', $match[1])."\")"; }, $view_content); // 恢复代码:仅转义 PHP 标签边界,HTML/JS 原样输出,PHP 源码在浏览器可见且不执行 if ($this->_code) { foreach ($this->_code as $key => $code) { $code = preg_replace_callback('#<\?(?:php|=)?|\?>#i', function ($m) { return htmlspecialchars($m[0], ENT_QUOTES, 'UTF-8'); }, $code); $view_content = str_replace( '', $code, $view_content ); } } return $view_content; } // 方法类解析 public function library_method($class, $method, $param) { return call_user_func_array( [\Phpcmf\Service::L($class), $method], $param ); } // 替换方法变量 public function _get_method(...$params) { if (!$params) { return []; } $value = []; foreach ($params as $var) { if ($var && strpos($var, '$') === 0) { $value[] = preg_replace('/\[(.+)\]/U', '[\'\\1\']', $var); } else { $value[] = $var; } } return $value; } // 存储缓存 private function _save_cache_data($cache_name, $data, $time) { \Phpcmf\Service::L('cache')->set_data($cache_name, $data, $time); } // 解析参数变量和值 private function _get_params_var_val($t) { if (!$t) { return ['', '']; } $arr = ['!=' => 'NOT_', '>=' => 'EGT_', '<=' => 'ELT_', '==' => '', '=' => '', '>' => 'GT_', '<' => 'LT_']; foreach ($arr as $a => $v) { if (strpos($t, $a) !== FALSE) { $var = substr($t, 0, strpos($t, $a)); $val = substr($t, strpos($t, $a) + strlen($a)); return [$v.$var, $val]; } } return ['', '']; } // list 标签解析 public function list_tag($_params) { $param = $where = []; $system = [ 'db' => '', // 数据源 'app' => '', // 指定插件时 'num' => '', // 显示数量 'limit' => '', // 显示数量 'maxlimit' => '', // 显示数量 'sum' => '', // 求和字段 'form' => '', // 表单 'page' => '', // 是否分页 'site' => '', // 站点id 'flag' => '', // 推荐位id 'not_flag' => '', // 排除推荐位id 'show_flag' => '', // 显示推荐位名称 'more' => '', // 是否显示栏目模型表 'catid' => '', // 栏目id,支持多id 'field' => '', // 显示字段 'order' => '', // 排序 'space' => '', // 空间uid 'table' => '', // 表名变量 'table_site' => '', // 当前站点表名变量 'total' => '', // 分页总数据 'join' => '', // 关联表名 'on' => '', // 关联表条件 'cache' => SYS_CACHE ? SYS_CACHE_LIST * 3600 : 0, // 默认缓存时间 'action' => '', // 动作标识 'return' => '', // 返回变量 'sbpage' => '', // 不按默认分页 'module' => '', // 模块名称 'urlrule' => '', // 自定义分页规则 'firsturl' => '', // 分页是第一页的固定地址 'pagesize' => '', // 自定义分页数量 'pagefile' => '', // 自定义分页配置文件 ]; if (!$system['pagefile'] && $this->_is_admin) { $system['pagefile'] = 'admin'; } $_params = trim($_params); $this->_list_tag = '{list '.$_params.'}'; $this->_list_param = []; // 过滤掉自定义where语句 if (preg_match('/where=\'(.+)\'/sU', $_params, $match)) { $param['where'] = $match[1]; $_params = str_replace($match[0], '', $_params); } // 判断是否是统计 if (stripos($_params, 'count') === 0) { $_params = trim(substr($_params, 5)); $this->_return_sql = 'count'; } elseif (stripos($_params, 'sum') === 0) { $_params = trim(substr($_params, 3)); $this->_return_sql = 'sum'; } else { $this->_return_sql = ''; } $params = explode(' ', $_params); if (in_array($params[0], $this->action)) { $params[0] = 'action='.$params[0]; } $sysadj = [ 'IN', 'BEWTEEN', 'BETWEEN', 'LIKE', 'NOT', 'BW', 'NOTLIKE', 'NOTJSON', 'NOTFIND', 'NOTIN', 'NOTNULL', 'NULL', 'GT', 'EGT', 'LT', 'ELT', 'DAY', 'MONTH', 'MAP', 'YEAR', 'SEASON', 'WEEK', 'JSON', 'FIND' ]; foreach ($params as $t) { list($var, $val) = $this->_get_params_var_val($t); if (!$var) { continue; } $val = defined($val) ? constant($val) : dr_rp_view($val, true); if ($var == 'fid' && !$val) { continue; } if (isset($system[$var])) { // 系统参数,只能出现一次,不能添加修饰符 if ($var != 'cache' && $system[$var]) { continue; // 防止重复记录 } $system[$var] = in_array($var, ['urlrule']) ? $val : dr_safe_replace($val); } else { if (preg_match('/^([A-Z_]+)(.+)/', $var, $match)) { // 筛选修饰符参数 $_adj = ''; $_pre = explode('_', $match[1]); foreach ($_pre as $p) { if (in_array($p, $sysadj)) { $_adj = $p; } } $where[$var] = [ 'adj' => $_adj, 'name' => $match[2], 'value' => $val ]; } else { $where[$var] = [ 'adj' => '', 'name' => $var, 'value' => $val ]; } $param[$var] = $val; // 用于特殊action } $this->_list_param[$var] = $val; } // return位置判断 if ($system['return'] && strpos(end($params), 'return=') === false) { return $this->_return($system['return'], $this->_return_sql.'标签中的return参数只能放在标签的尾部'); } // 替换order中的非法字符 isset($system['order']) && $system['order'] && $system['order'] = str_ireplace( ['"', "'", ';', 'select', 'insert'], //, '`', ')', '(' '', $system['order'] ); // limit别名映射num if (isset($system['limit']) && !isset($system['num'])) { $system['num'] = $system['limit']; } // 开发模式下显示求和字段 if (CI_DEBUG) { $this->_sum_field = $system['sum']; } $action = $system['action']; // 当hits动作时,定位到moule动作 $system['action'] == 'hits' && $system['action'] = 'module'; // 默认站点参数 $system['site'] = !$system['site'] ? SITE_ID : $system['site']; // 默认模块参数 $system['module'] = $dirname = strtolower($system['module'] ? (string)$system['module'] : (string)\Phpcmf\Service::C()->module['dirname']); // 格式化field $system['field'] && $system['field'] = urldecode($system['field']); // 分页页码变量 $this->_page_value = $system['page']; if (in_array(strtoupper($system['order']), ['RAND()', 'RAND'])) { $cache_name = 'view-'.IS_CLIENT.'-'.$this->_return_sql.md5($_params.dr_now_url().$this->_get_page_id($system['page']).$this->_is_mobile); } else { $cache_name = 'view-'.IS_CLIENT.'-'.$this->_return_sql.($system['page'] ? $this->_get_page_id($system['page']) : 'one').md5($_params.$this->_is_mobile); } if (!CI_DEBUG && SYS_CACHE && $system['cache']) { $cache_data = \Phpcmf\Service::L('cache')->get_data($cache_name); if ($cache_data) { $this->_page_used = $cache_data['page_used']; $this->_page_urlrule = $cache_data['page_urlrule']; return $this->_return($system['return'], $cache_data['data'], $cache_data['sql'], $cache_data['total'], $cache_data['pages'], $cache_data['pagesize'], $system['cache']); } } // 运算排除 if ($this->_return_sql && !in_array($action, ['sql', 'module', 'member', 'form', 'mform', 'comment', 'table', 'tag', 'related'])) { return $this->_return($system['return'], $this->_return_sql.'标签不支持[acntion='.$action.']的运算'); } // 判断标签是否是搜索标签 $this->_is_list_search = 0; // action switch ($system['action']) { case 'function': //执行函数 if (!isset($param['name'])) { return $this->_return($system['return'], 'name参数不存在'); } elseif (strpos($param['name'], 'my_') !== 0) { return $this->_return($system['return'], '自定义函数['.$param['name'].']必须以my_开头'); } elseif (!function_exists($param['name'])) { return $this->_return($system['return'], '自定义函数['.$param['name'].']未定义'); } $name = 'function-'.md5(dr_array2string($param)); $cache = \Phpcmf\Service::L('cache')->get_data($name); if (!$cache) { $p = []; foreach ($param as $var => $t) { if (strpos($var, 'param') === 0) { $n = intval(substr($var, 5)); $p[$n] = $t; } } if ($p) { $rt = call_user_func_array($param['name'], $p); } else { $rt = call_user_func($param['name']); } $cache = [ $rt ]; $system['cache'] && \Phpcmf\Service::L('cache')->set_data($name, $cache, $system['cache']); } return $this->_return($system['return'], $cache, ''); break; case 'cache': // 系统缓存数据 if (!isset($param['name'])) { return $this->_return($system['return'], 'name参数不存在'); } $pos = strpos($param['name'], '.'); if ($pos !== FALSE) { $_name = substr($param['name'], 0, $pos); $_param = substr($param['name'], $pos + 1); } else { $_name = $param['name']; $_param = NULL; } $cache = $this->_cache_var($_name, $system['site']); if (!$cache) { return $this->_return($system['return'], "缓存({$_name})不存在,请在后台更新缓存"); } elseif ($_name == 'module-content') { // 指定模块 if ($system['module'] && $system['module'] != 'all') { $mid = explode(',', $system['module']); foreach ($cache as $i => $t) { if (!in_array($t['dirname'], $mid)) { unset($cache[$i]); } } if (!$cache) { return $this->_return($system['return'], '指定的模块('.$system['module'].')都不存在'); } } // 读取内容模块更多信息 if ($system['more']) { foreach ($cache as $i => $t) { $cache[$i] = \Phpcmf\Service::L('cache')->get('module-'.$system['site'].'-'.$t['dirname']); } } } if ($_param) { $data = dr_get_param_var($cache, $_param); //eval('$data=$cache'.$this->_get_var($_param).';'); if (!$data) { return $this->_return($system['return'], "缓存({$_name})参数不存在!!"); } } else { $data = $cache; } return $this->_return($system['return'], $data, ''); break; case 'linkage': // 联动菜单 if (isset($param['pid']) && $param['pid']) { $link = dr_linkage($param['code'], $param['pid']); if (!$link) { return $this->_return($system['return'], "联动菜单{$param['code']}不存在,请在后台一键生成数据"); } if (!$link['child']) { // 表示本身就是子菜单,我们需要调用父级作为同级显示 $param['pid'] = $link['pid']; } } $linkage = dr_linkage_list($param['code'], isset($param['pid']) && $param['pid'] ? $param['pid'] : 0); if (!$linkage) { return $this->_return($system['return'], "联动菜单{$param['code']}不存在,请在后台一键生成数据"); } $i = 0; $return = []; foreach ($linkage as $t) { if ($system['num'] && $i >= $system['num']) { break; } elseif (isset($param['id']) && !dr_in_array($t['id'], explode(',', $param['id']))) { continue; } elseif (isset($param['ii']) && !dr_in_array($t['ii'], explode(',', $param['ii']))) { continue; } $return[] = $t; $i ++; } $data = isset($param['call']) && $param['call'] ? array_reverse($return) : $return; // 存储缓存 $system['cache'] && $data && $this->_save_cache_data($cache_name, [ 'data' => $data, 'sql' => '', 'total' => '', 'pages' => '', 'pagesize' => '', 'page_used' => $this->_page_used, 'page_urlrule' => $this->_page_urlrule, ], $system['cache']); return $this->_return($system['return'], $data, ''); break; case 'sql': // 直接sql查询 if (preg_match('/sql=\'(.+)\'/sU', $_params, $sql)) { // 替换前缀 $sql = str_replace( ['@#S', 'S@#', '@#'], [\Phpcmf\Service::M()->dbprefix($system['site']), \Phpcmf\Service::M()->dbprefix($system['site']), \Phpcmf\Service::M()->dbprefix()], trim(urldecode($sql[1])) ); if (stripos($sql, 'SELECT') !== 0) { return $this->_return($system['return'], 'SQL语句只能是SELECT查询语句'); } elseif (preg_match('/select(.*)into outfile(.*)/i', $sql)) { return $this->_return($system['return'], 'SQL语句只能是SELECT查询语句'); } elseif (preg_match('/select(.*)into dumpfile(.*)/i', $sql)) { return $this->_return($system['return'], 'SQL语句只能是SELECT查询语句'); } $total = 0; $pages = ''; // 统计标签 if ($this->_return_sql) { $sql = preg_replace('/select .* from /iUs', 'SELECT '.$this->_select_rt_name.' FROM ', $sql, 1); } else { // 如存在分页条件才进行分页查询 if ($system['page']) { $page = $this->_get_page_id($system['page']); $row = $this->_query(preg_replace('/select .* from /iUs', 'SELECT count(*) as c FROM ', $sql, 1), $system, FALSE); $total = (int)$row['c']; $pagesize = $system['pagesize'] ? $system['pagesize'] : 10; // 没有数据时返回空 if (!$total) { return $this->_return($system['return'], '没有查询到内容', $sql, 0); } $sql.= ' LIMIT '.intval($pagesize * ($page - 1)).','.$pagesize; $pages = $this->_new_pagination($system, $pagesize, $total); } } $data = $this->_query($sql, $system); // 存储缓存 $system['cache'] && $data && $this->_save_cache_data($cache_name, [ 'data' => $data, 'sql' => $sql, 'total' => $total, 'pages' => $pages, 'pagesize' => $pagesize, 'page_used' => $this->_page_used, 'page_urlrule' => $this->_page_urlrule, ], $system['cache']); return $this->_return($system['return'], $data, $sql, $total, $pages, $pagesize); } else { return $this->_return($system['return'], '参数不正确,SQL语句必须用单引号包起来'); // 没有查询到内容 } break; case 'table': // 表名查询 if (!$system['table'] && !$system['table_site']) { return $this->_return($system['return'], 'table参数不存在'); } // 填充当前站点id的写法 if ($system['table_site']) { $system['table'] = dr_site_table_prefix($system['table_site'], SITE_ID); } $tableinfo = \Phpcmf\Service::L('cache')->get_data('table-'.$system['table']); if (!$tableinfo) { $tableinfo = \Phpcmf\Service::M('Table')->get_field($system['table']); \Phpcmf\Service::L('cache')->set_data('table-'.$system['table'], $tableinfo, 36000); } if (!$tableinfo) { return $this->_return($system['return'], '表('.$system['table'].')结构不存在'); } // 是否操作自定义where if ($param['where']) { $where[] = [ 'adj' => 'SQL', 'value' => urldecode($param['where']) ]; unset($param['where']); } $table = \Phpcmf\Service::M()->dbprefix($system['table']); $where = $this->_set_where_field_prefix($where, $tableinfo, $table); // 给条件字段加上表前缀 $system['field'] = $this->_set_select_field_prefix($system['field'], $tableinfo, $table); // 给显示字段加上表前缀 $_order = []; $_order[$table] = $tableinfo; $total = 0; $sql_from = \Phpcmf\Service::M()->quote_table($table); // sql的from子句 // 关联表 if ($system['join'] && $system['on']) { $rt = $this->_join_table($table, $system, $where, $_order, $sql_from); if (!$rt['code']) { return $this->_return($system['return'], $rt['msg']); } list($system, $where, $_order, $sql_from) = $rt['data']; } // catid 参数 if ($system['catid']) { $where[] = [ 'adj' => 'SQL', 'value' => urldecode(\Phpcmf\Service::M()->quote_field($table, 'catid').' IN ('.$system['catid'].')') ]; } $sql_limit = $pages = ''; $sql_where = $this->_get_where($where); // sql的where子句 // 统计标签 if ($this->_return_sql) { $sql = "SELECT ".$this->_select_rt_name." FROM $sql_from ".($sql_where ? "WHERE $sql_where" : "")." ORDER BY NULL"; } else { if ($system['page']) { $page = $this->_get_page_id($system['page']); $pagesize = (int) $system['pagesize']; $pagesize = $pagesize ? $pagesize : 10; $sql = "SELECT count(*) as c FROM $sql_from ".($sql_where ? "WHERE $sql_where" : "")." ORDER BY NULL"; $row = $this->_query($sql, $system, FALSE); $total = (int)$row['c']; if ($system['maxlimit'] && $total > $system['maxlimit']) { $total = $system['maxlimit']; // 最大限制 if ($page * $pagesize > $total) { $return_data = $this->_return($system['return'], 'maxlimit设置最大显示'.$system['maxlimit'].'条,当前('.$total.')已超出', $sql, 0); return; } } // 没有数据时返回空 if (!$total) { return $this->_return($system['return'], '没有查询到内容', $sql, 0); } $sql_limit = 'LIMIT '.intval($pagesize * ($page - 1)).','.$pagesize; $pages = $this->_new_pagination($system, $pagesize, $total); } elseif ($system['num']) { $sql_limit = "LIMIT {$system['num']}"; } $system['order'] = $this->_set_orders_field_prefix($system['order'], $_order); // 给排序字段加上表前缀 $sql = "SELECT ".$this->_get_select_field($system['field'] ? $system['field'] : "*")." FROM $sql_from ".($sql_where ? "WHERE $sql_where" : "")." ".($system['order'] ? "ORDER BY {$system['order']}" : "")." $sql_limit"; } $data = $this->_query($sql, $system); if (is_array($data) && $data) { // 表的系统字段 $myfield = \Phpcmf\Service::M('field')->get_mytable_field($system['table'], 0); if (!$myfield) { $myfield = \Phpcmf\Service::M('field')->get_mytable_field($system['table'], SITE_ID); } if ($myfield) { $dfield = \Phpcmf\Service::L('Field')->app(); foreach ($data as $i => $t) { $data[$i] = $dfield->format_value($myfield, $t, 1); } } // 存储缓存 $system['cache'] && $data && $this->_save_cache_data($cache_name, [ 'data' => $data, 'sql' => $sql, 'total' => $total, 'pages' => $pages, 'pagesize' => $pagesize, 'page_used' => $this->_page_used, 'page_urlrule' => $this->_page_urlrule, ], $system['cache']); } return $this->_return($system['return'], $data, $sql, $total, $pages, $pagesize); break; default : // 插件自定义标签 if (!$system['app']) { if (in_array($system['action'], [ 'member', 'page', 'navigator', 'tag', 'comment', 'form', 'mform' ])) { $system['app'] = $system['action']; } elseif (in_array($system['action'], [ 'category_search_field', 'content', 'category', 'related', 'search', 'modules', 'module' ])) { $system['app'] = 'module'; } } $return_data = []; // 当来自插件目录 if ($system['app']) { if (!dr_is_app($system['app'])) { return $this->_return($system['return'], '本插件('.$system['app'].')没有安装'); } $myfile = dr_get_app_dir($system['app']).'Action/'.dr_safe_filename(ucfirst($system['action'])).'.php'; if (is_file($myfile)) { $rs = require $myfile; if (!$return_data && is_array($rs)) { return $rs; } return $return_data; } else { return $this->_return($system['return'], '本插件('.$system['app'].')没有('.$system['action'].')标签'); } } else { // 识别自定义标签 $myfile = MYPATH.'Action/'.dr_safe_filename(ucfirst($system['action'])).'.php'; if (is_file($myfile)) { $rs = require $myfile; if (!$return_data && is_array($rs)) { return $rs; } return $return_data; } else { return $this->_return($system['return'], '无此标签('.$system['action'].')'); } } break; } } /** * 查询缓存 */ public function _query($sql, $system, $all = TRUE) { $mysql = \Phpcmf\Service::M()->db; if (isset($system['db']) && $system['db']) { list($mysql) = \Frame\Model::_load_db_source($system['db']); } // 运算替换 if ($this->_return_sql && strpos($sql, $this->_select_rt_name) !== false) { switch ($this->_return_sql) { case 'count': $sql = str_replace($this->_select_rt_name, 'count(*) as ct', $sql); break; case 'sum': if (!$system['sum']) { return '缺少参数sum,指定求和的字段名称'; } $sql = str_replace($this->_select_rt_name, 'sum('.$system['sum'].') as ct', $sql); break; } } // 执行SQL $t = microtime(TRUE); $query = $mysql->query($sql); $time = microtime(TRUE) - $t; // 记录慢日志 if ($time > 1 && is_file(WRITEPATH.'database/sql.lock')) { $file = WRITEPATH.'database/Sql/sql.txt'; $path = dirname($file); if (!is_dir($path)) { dr_mkdirs($path); } $size = filesize($file); $json = json_encode([SYS_TIME, $sql, $time, $this->_view_file, $this->_list_tag, SITE_URL.SELF.'?'.http_build_query($_GET)]); if ($size > 1024*1024*2) { copy($file, $path.SYS_TIME.'.txt'); file_put_contents($file, $json.PHP_EOL, LOCK_EX); } else { file_put_contents($file, $json.PHP_EOL, FILE_APPEND | LOCK_EX); } } $this->_sql = $sql; $this->_sql_time = $time; // 挂钩点 模板中的sql语句 \Phpcmf\Hooks::trigger('cms_view_sql', $sql, $time, $this->_view_file, $this->_list_tag); if (!$query) { return 'SQL查询解析不正确:'.$sql; } // 查询结果 $data = $all ? $query->getResultArray() : $query->getRowArray(); return $data; } // 获取当前执行后的sql语句 public function get_sql_query() { return $this->_sql; } // 设置分页参数 public function set_page_config($config) { $this->_page_config = $config; } /** * 新分页 */ public function _new_pagination($system, $pagesize, $total) { return $this->_get_pagination($system['urlrule'], $pagesize, $total, $system['pagefile'], $system['firsturl']); } /** * 分页 */ public function _get_pagination($url, $pagesize, $total, $name = 'page', $first_url = '') { $this->_page_used = 1; $this->_page_config_file = ''; if ($name == 'admin') { // 使用后台分页规则 $this->_page_config_file = CMSPATH.'Config/Apage.php'; } else { // 这里要支持移动端分页条件 !$name && $name = 'page'; $file = 'page/'.($this->_is_mobile ? 'mobile' : 'pc').'/'.(dr_safe_filename($name)).'.php'; if (is_file(WEBPATH.'config/'.$file)) { $this->_page_config_file = WEBPATH.'config/'.$file; } elseif (is_file(CONFIGPATH.$file)) { $this->_page_config_file = CONFIGPATH.$file; } else { exit('无法找到分页配置文件【'.$file.'】'); } } $config = require $this->_page_config_file; if ($this->_page_config) { $config = dr_array22array($config, $this->_page_config); } !$url && $url = '此标签没有设置urlrule参数'; $this->_page_urlrule = str_replace(['[page]', '%7Bpage%7D', '%5Bpage%5D', '%7bpage%7d', '%5bpage%5d'], '{page}', $url); $config['base_url'] = $this->_page_urlrule; $config['first_url'] = $first_url ? $first_url : ''; $config['per_page'] = $pagesize; $config['page_name'] = $this->_page_value; $config['total_rows'] = $total; $config['use_page_numbers'] = TRUE; $config['query_string_segment'] = 'page'; return \Phpcmf\Service::L('Page')->initialize($config)->create_links(); } private function _get_where_in($str) { if (!$str) { return 0; } $arr = explode(',', $str); foreach ($arr as $i => $t) { $arr[$i] = intval($t); } return implode(',', $arr); } // 条件子句格式化 public function _get_where($where) { if (!$where) { return ''; } $m = \Phpcmf\Service::M(); $string = ''; foreach ($where as $i => $t) { // 过滤字段 if (isset($t['use']) && $t['use'] == 0 || !strlen($t['value'])) { continue; } $join = $string ? ' AND' : ''; // 条件组装 switch ($t['adj']) { case 'MAP': // 地图 if ($t['value'] == '') { $string .= $join." ".$t['name']." = ''"; } else { list($a, $km) = explode('|', $t['value']); list($lng, $lat) = explode(',', $a); if ($lat && $lng) { $this->pos_map = [ 'lng' => $lng, 'lat' => $lat, 'km' => $km, ]; $squares = dr_square_point($lng, $lat, $km); $table = !empty($t['table']) ? $t['table'] : ''; if ($table !== '') { $lat_col = $m->quote_field($table, $t['name'].'_lat'); $lng_col = $m->quote_field($table, $t['name'].'_lng'); } else { // 兼容旧 prefix(已加引的 `table`.) $lat_col = $m->quote_column(($t['prefix'] ?? '').$t['name'].'_lat'); $lng_col = $m->quote_column(($t['prefix'] ?? '').$t['name'].'_lng'); } $string .= $join.' ('.$m->where_between($lat_col, $squares['right-bottom']['lat'], $squares['left-top']['lat']) .' AND '.$m->where_between($lng_col, $squares['left-top']['lng'], $squares['right-bottom']['lng']).')'; } else { $string .= $join." ".$t['name']." = '没有定位到您的坐标'"; } } break; case 'JSON': case 'NOTJSON': if ($t['value'] == '') { $string .= $join." ".$t['name']." = ''"; } else { $or_and = strpos($t['value'], ','); if ($or_and) { $arr = explode(',', $t['value']); } elseif (strpos($t['value'], '|')) { $arr = explode('|', $t['value']); } else { $arr = [$t['value']]; } $vals = []; foreach ($arr as $value) { if ($value) { $vals[] = $m->where_json('', $t['name'], $m->db->escapeString(dr_safe_replace($value), true)); } } if ($t['adj'] == 'NOTJSON') { $join .= ' NOT'; } $string .= $vals ? $join.'('.$m->where_ne($t['name'], '').' AND ('.implode($or_and ? ' AND ' : ' OR ', $vals).'))' : ''; } break; case 'FIND': case 'NOTFIND': $vals = []; if (dr_safe_replace($t['value'])) { foreach (explode('|', $t['value']) as $v) { if ($v !== '' && $v !== null) { $vals[] = $m->where_find_in_set($t['name'], $v); } } } if ($t['adj'] == 'NOTFIND') { $join .= ' NOT'; } $string .= $vals ? $join.' ('.implode(' OR ', $vals).')' : ''; break; case 'LIKE': case 'NOTLIKE': $vals = []; if (dr_safe_replace($t['value'])) { foreach (explode('|', $t['value']) as $value) { if ($value) { $ns = strpos($value, '%'); // % 不在开头 → 尾部模糊;否则首尾模糊 $side = ($ns !== false && $ns !== 0) ? 'right' : 'both'; $vals[] = $m->where_like($t['name'], trim($value, '%'), $side); } } } if ($t['adj'] == 'NOTLIKE') { $join .= ' NOT'; } $string .= $vals ? $join.' ('.implode(' OR ', $vals).')' : ''; break; case 'IN': $sql = $m->where_in_expr($t['name'], explode(',', dr_safe_replace($t['value']))); $string .= $sql ? $join.' '.$sql : ''; break; case 'NOTIN': $sql = $m->where_in_expr($t['name'], explode(',', dr_safe_replace($t['value'])), true); $string .= $sql ? $join.' '.$sql : ''; break; case 'NOT': $string .= $join.' '.$m->where_ne( $t['name'], dr_is_numeric($t['value']) ? $t['value'] : ($t['value'] == "''" ? '' : dr_safe_replace($t['value'])) ); break; case 'BEWTEEN': case 'BW': case 'BETWEEN': list($s, $e) = explode(',', $t['value']); $string .= $join.' '.$m->where_between($t['name'], (int) $s, (int) $e); break; case 'GT': $string .= $join.' '.$m->where_cmp($t['name'], '>', intval($t['value'])); break; case 'EGT': $string .= $join.' '.$m->where_cmp($t['name'], '>=', intval($t['value'])); break; case 'LT': $string .= $join.' '.$m->where_cmp($t['name'], '<', intval($t['value'])); break; case 'ELT': $string .= $join.' '.$m->where_cmp($t['name'], '<=', intval($t['value'])); break; case 'SQL': $string .= $join.' '.str_replace('@#', $m->dbprefix(), $t['value']); break; case 'DAY': if (substr($t['value'], 0, 1) == 'E') { $stime = strtotime('-'.intval(substr($t['value'], 1)).' day'); $stime = strtotime(date('Y-m-d', $stime).' 00:00:00'); $etime = strtotime(date('Y-m-d 23:59:59', $stime)); } elseif (strpos($t['value'], ',')) { list($s, $e) = explode(',', $t['value']); $stime = strtotime($s.' 00:00:00'); $etime = strtotime(($e ? $e : date('Y-m-d')).' 23:59:59'); } else { $time = strtotime('-'.intval($t['value']).' day'); $stime = strtotime(date('Y-m-d', $time).' 00:00:00'); $etime = SYS_TIME; } if ($stime > $etime) { $tp = $stime; $stime = $etime; $etime = $tp; } $string .= $join.' ('.$m->where_between($t['name'], $stime, $etime).')'; break; case 'WEEK': if (substr($t['value'], 0, 1) == 'E') { $num = intval(substr($t['value'], 1)); if ($num) { $stime = strtotime(date('Y-m-d', strtotime('-'.($num + 1).' monday')).' 00:00:00'); $etime = strtotime(date('Y-m-d 23:59:59', ($stime + (8 - (date('w') == 0 ? 8 : date('w'))) * 24 * 3600))); } else { $stime = strtotime(date('Y-m-d 00:00:00', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 24 * 3600))); $etime = strtotime(date('Y-m-d 23:59:59', ($stime + (8 - (date('w') == 0 ? 8 : date('w'))) * 24 * 3600))); } } else { $num = intval($t['value']); if ($num) { $stime = strtotime(date('Y-m-d', strtotime('-'.($num + 1).' monday')).' 00:00:00'); } else { $stime = strtotime(date('Y-m-d 00:00:00', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 24 * 3600))); } $etime = SYS_TIME; } if ($stime > $etime) { $tp = $stime; $stime = $etime; $etime = $tp; } $string .= $join.' ('.$m->where_between($t['name'], $stime, $etime).')'; break; case 'SEASON': list($s, $y) = explode('-', $t['value']); if (!$y) { $y = date('Y'); } if (!$s || !in_array($s, [1, 2, 3, 4])) { $s = ceil(date('n') / 3); } $season = [ 1 => ['-01-01 00:00:00', '-03-31 23:59:59'], 2 => ['-04-01 00:00:00', '-06-30 23:59:59'], 3 => ['-07-01 00:00:00', '-09-30 23:59:59'], 4 => ['-10-01 00:00:00', '-12-31 23:59:59'], ]; $stime = strtotime($y.$season[$s][0]); $etime = strtotime($y.$season[$s][1]); if ($stime > $etime) { $tp = $stime; $stime = $etime; $etime = $tp; } $string .= $join.' ('.$m->where_between($t['name'], $stime, $etime).')'; break; case 'MONTH': if (substr($t['value'], 0, 1) == 'E') { $stime = strtotime(date('Y-m-01 00:00:00').' - '.intval(substr($t['value'], 1)).' month'); $etime = strtotime(date('Y-m', $stime).'-1 +1 month -1 day 23:59:59'); } elseif (strpos($t['value'], ',')) { list($s, $e) = explode(',', $t['value']); if (!$e) { $e = $s; } $stime = strtotime($s.'-01 00:00:00'); $etime = strtotime($e.' +1 month -1 day 23:59:59'); } else { $time = strtotime('-'.intval($t['value']).' month'); $stime = strtotime(date('Y-m', $time).'-01 00:00:00'); $etime = SYS_TIME; } if ($stime > $etime) { $tp = $stime; $stime = $etime; $etime = $tp; } $string .= $join.' ('.$m->where_between($t['name'], $stime, $etime).')'; break; case 'YEAR': if (strlen($t['value']) == 4) { $stime = strtotime($t['value'].'-01-01 00:00:00'); $etime = strtotime($t['value'].'-12-31 23:59:59'); } elseif (substr($t['value'], 0, 1) == 'E') { $stime = strtotime(date('Y', strtotime('-'.intval(substr($t['value'], 1)).' year')).'-01-01 00:00:00'); $etime = strtotime(date('Y', $stime).'-12-31 23:59:59'); } elseif (strpos($t['value'], ',')) { list($s, $e) = explode(',', $t['value']); $stime = strtotime(intval($s).'-01-01 00:00:00'); $etime = strtotime(intval($e ? $e : date('Y')).'-12-31 23:59:59'); } else { $stime = strtotime(date('Y', strtotime('-'.intval($t['value']).' year')).'-01-01 00:00:00'); $etime = SYS_TIME; } if ($stime > $etime) { $tp = $stime; $stime = $etime; $etime = $tp; } $string .= $join.' ('.$m->where_between($t['name'], $stime, $etime).')'; break; case 'NOTNULL': $string .= $join.' '.$m->where_ne($t['name'], ''); break; case 'NULL': $string .= $join." ({$t['name']}='' or {$t['name']} IS NULL)"; break; default: if ($t['name'] && ( (!empty($t['field']) && $t['field'] === 'thumb') || $m->bare_field($t['name']) === 'thumb' )) { $sql = $m->where_field_thumb('', $t['name'], $t['value']); $string .= $sql ? $join.' '.$sql : ''; } elseif (!$t['name'] && $t['value']) { $string .= $join.' '.$t['value']; } else { $string .= $join.(dr_is_numeric($t['value']) ? " {$t['name']} = ".intval($t['value']) : " {$t['name']} = '".($t['value'] == "''" ? '' : dr_safe_replace($t['value']))."'"); } break; } } return trim($string); } // 给条件字段加上表前缀 public function _set_where_field_prefix($where, $field, $prefix, $myfield = []) { if (!$where) { return []; } $m = \Phpcmf\Service::M(); $this->_list_where = $where; foreach ($where as $i => $t) { if (dr_in_array($t['name'], $field)) { $fname = $t['name']; $where[$i]['use'] = 1; $where[$i]['field'] = $fname; $where[$i]['table'] = $prefix; $where[$i]['name'] = $m->quote_field($prefix, $fname); if ($myfield && $t['value']) { if ($myfield[$fname]['fieldtype'] == 'Linkages') { // 联动多选 $arr = explode('|', $t['value']); $link_where = []; foreach ($arr as $value) { $data = dr_linkage($myfield[$fname]['setting']['option']['linkage'], $value); if ($data) { if ($data['child']) { $link_where = dr_array2array($link_where, explode(',', $data['childids'])); } else { $link_where[] = intval($data['ii']); } } } $where[$i]['adj'] = 'JSON'; if ($link_where) { $where[$i]['value'] = implode('|', array_unique($link_where)); } else { // 没有找到就当做普通数据库查询 $where[$i]['value'] = $t['value']; } } elseif (isset($myfield[$fname]['fieldtype']) && in_array($myfield[$fname]['fieldtype'], ['Members', 'Related'])) { // 关联字段 if (!$where[$i]['adj']) { $where[$i]['adj'] = 'FIND'; $where[$i]['value'] = intval($t['value']); } } elseif ($myfield[$fname]['fieldtype'] == 'Linkage') { // 联动菜单 $arr = explode('|', $t['value']); $link_where = []; $col = $where[$i]['name']; foreach ($arr as $value) { $data = dr_linkage($myfield[$fname]['setting']['option']['linkage'], $value); if ($data) { if ($data['child']) { $link_where[] = $col.' IN ('.$data['childids'].')'; } else { $link_where[] = $col.' = '.intval($data['ii']); } } } if ($link_where) { $where[$i]['adj'] = 'SQL'; $where[$i]['value'] = '('.implode(' OR ', array_unique($link_where)).')'; } else { // 没有找到就当做普通数据库查询 $where[$i]['value'] = $t['value']; } } } } elseif (!$t['name'] && $t['value']) { // 标示只有where的条件查询 $where[$i]['use'] = 1; } elseif ($t['adj'] == 'MAP' && dr_in_array($t['name'].'_lat', $field) && dr_in_array($t['name'].'_lng', $field)) { $where[$i]['use'] = 1; $where[$i]['table'] = $prefix; $where[$i]['prefix'] = $m->quote_table($prefix).'.'; } else { if (!$t['use'] && !in_array($t['name'], ['where'])) { $this->_list_error[] = '在['.$prefix.']表中字段['.$t['name'].']不存在(可用字段:'.implode('、', $field).')'; } $where[$i]['use'] = $t['use'] ? 1 : 0; } } return $where; } // 给显示字段加上表前缀 public function _set_select_field_prefix($select, $field, $prefix) { if ($select) { $m = \Phpcmf\Service::M(); $array = explode(',', $select); foreach ($array as $i => $t) { $field_prefix = ''; if (strpos($t, 'DISTINCT_') === 0) { $t = str_replace('DISTINCT_', '', $t); $field_prefix = 'DISTINCT '; } if (dr_in_array($t, $field)) { $array[$i] = $field_prefix.$m->quote_field($prefix, $t); } elseif (strpos($t, '.') !== false && !$m->has_id_quotes($t)) { list($a, $b) = explode('.', $t); if (($prefix == $a || substr($prefix, strlen($m->dbprefix())) == $a)) { if (strpos($b, ':') !== false) { // 存在别名 list($b, $cname) = explode(':', $b); if (dr_in_array($b, $field)) { $array[$i] = $field_prefix.$m->quote_field($prefix, $b).' as '.$m->quote_id($cname); } } else { if (dr_in_array($b, $field)) { $array[$i] = $field_prefix.$m->quote_field($prefix, $b); } } } } } return implode(',', $array); } return $select; } // 获取分页页数 private function _get_page_id($page) { if (dr_is_numeric($page)) { return max(1, (int)$_GET['page']); } else { return max(1, isset($_GET[$page]) ? (int)$_GET[$page] : 0); } } // 格式化查询参数 private function _get_select_field($field) { if ($field != '*') { $my = []; $array = explode(',', $field); foreach ($array as $t) { // 已加表前缀/引号的字段才保留 if (\Phpcmf\Service::M()->is_column_expr($t)) { $my[] = $t; continue; } } if (!$my) { $field = '*'; } else { $field = implode(',', $my); } } // 定位范围搜索 if ($this->pos_order) { if ($this->pos_map && $this->pos_map['lat'] && $this->pos_map['lng']) { if (version_compare(\Phpcmf\Service::M()->db->getVersion(), '5.7.0') < 0) { $field .= ',ROUND(6378.138*2*ASIN(SQRT(POW(SIN((' . $this->pos_map['lat'] . '*PI()/180-' . $this->pos_order . '_lat*PI()/180)/2),2)+COS(' . $this->pos_map['lat'] . '*PI()/180)*COS(' . $this->pos_order . '_lat*PI()/180)*POW(SIN((' . $this->pos_map['lng'] . '*PI()/180-' . $this->pos_order . '_lng*PI()/180)/2),2)))*1000) AS ' . $this->pos_order . '_map'; } else { $field.= ',ST_Distance_Sphere(POINT('.$this->pos_order.'_lng, '.$this->pos_order.'_lat), POINT('.$this->pos_map['lng'].', '.$this->pos_map['lat'].')) AS '.$this->pos_order.'_map'; } } else { $field.= '没有定位到您的坐标'; } } return $field; } // join 联合查询表 public function _join_table($main, $system, $where, $_order, $sql_from) { $table = \Phpcmf\Service::M()->dbprefix($system['join']); // 关联表 $tableinfo = \Phpcmf\Service::L('cache')->get_data('table-join-'.$system['join']); if (!$tableinfo) { $tableinfo = \Phpcmf\Service::M('Table')->get_field($system['join']); if (!$tableinfo) { return dr_return_data(0, '关联数据表('.$system['join'].')结构不存在'); } \Phpcmf\Service::L('cache')->set_data('table-join-'.$system['join'], $tableinfo, 36000); } list($a, $b) = explode(',', $system['on']); $b = $b ? $b : $a; $where = $this->_set_where_field_prefix($where, $tableinfo, $table); // 给条件字段加上表前缀 $system['field'] = $this->_set_select_field_prefix($system['field'], $tableinfo, $table); // 给显示字段加上表前缀 $_order[$table] = $tableinfo; $sql_from.= ' LEFT JOIN '.\Phpcmf\Service::M()->quote_table($table) .' ON '.\Phpcmf\Service::M()->quote_field($main, $a) .'='.\Phpcmf\Service::M()->quote_field($table, $b); return dr_return_data(1, 'ok', [$system, $where, $_order, $sql_from]); } // 给排序字段加上多表前缀 public function _set_orders_field_prefix($order, $fields) { if (!$order) { return NULL; } elseif (strtoupper($order) == 'FIXNULL') { // NULL排序 return 'NULL'; } elseif (in_array(strtoupper($order), ['RAND()', 'RAND'])) { // 随机排序 return 'RAND()'; } $order = urldecode($order); if (\Phpcmf\Service::M()->has_id_quotes($order)) { return $order; } // 字段排序 $m = \Phpcmf\Service::M(); $my = []; $array = explode(',', $order); foreach ($array as $i => $t) { $a = explode('_', $t); $b = end($a); if (in_array(strtolower($b), ['desc', 'asc', 'instr', 'field'])) { $a = str_replace('_'.$b, '', $t); } else { $a = $t; $b = ''; } $b = strtoupper($b); foreach ($fields as $prefix => $field) { if (is_array($field)) { if (dr_in_array($a, $field)) { $col = $m->quote_field($prefix, $a); if ($b == 'INSTR') { if (isset($this->_list_where['IN_' . $a]) && $this->_list_where['IN_' . $a]) { $my[$i] = 'instr("'.$this->_list_where['IN_' . $a]['value'].'",'.$col.')'; } else { $this->_list_error[] = '无法找到字段' . $a . '的IN通配符参数,order参数将会无效'; } } elseif ($b == 'FIELD') { if (isset($this->_list_where['IN_'.$a]) && $this->_list_where['IN_'.$a]) { $my[$i] = 'FIELD('.$col.', '.$this->_list_where['IN_'.$a]['value'].')'; } else { $this->_list_error[] = '无法找到字段'.$a.'的IN通配符参数,order参数将会无效'; } } else { $my[$i] = $col.' '.($b ? $b : 'DESC'); } } elseif (dr_in_array($a.'_lat', $field) && dr_in_array($a.'_lng', $field)) { if ($this->pos_map) { $my[$i] = $m->quote_id($a.'_map').' ASC'; $this->pos_order = $a; } else { $this->_list_error[] = '没有定位到您的坐标,order参数将会无效'; } } } } } if ($my) { return implode(',', $my); } return NULL; } // 给排序字段加上表前缀 public function _set_order_field_prefix($order, $field, $prefix) { return $this->_set_orders_field_prefix($order, [$prefix => $field]); } // list 返回 public function _return($return, $data = [], $sql = '', $total = 0, $pages = '', $pagesize = 0, $is_cache = 0) { $this->pos_map = $this->pos_order = null; $total = isset($total) && $total ? $total : dr_count($data); $page = $this->_get_page_id($this->_page_value); $nums = $pagesize ? ceil($total/$pagesize) : 0; if (CI_DEBUG) { // 显示debug数据 $debug = '
';
if ($this->_list_tag) {
$debug.= '标签解析:'.str_replace('{list action=', '{', $this->_list_tag).'
';
}
if ($this->_list_error) {
$debug.= '错误提示:'.implode('、', $this->_list_error).'
';
}
if (strpos($this->_list_tag, 'return=') !== false) {
$arr = explode('return=', $this->_list_tag);
if (strpos($arr[1], ' ') !== false) {
$debug.= '错误提示:return参数必须放在最后,且后面不能带有空格符号
';
}
}
if ($this->_is_list_search) {
if (!$this->_options['is_search_page']) {
$debug.= '使用范围:search标签只能用于搜索页面,当前页面不是搜索页面,可能会无效
';
}
$debug.= '搜索解析:'.$this->_options['search_sql'].'
';
} elseif ($this->_options['is_search_page'] && (strpos($this->_list_tag, 'page=1') || $this->_page_used)) {
$debug.= '标签提醒:当前页面是搜索页面,只有search标签才适用于搜索页面,可能会引起本标签分页无效
';
}
if ($sql) {
// 运算替换
if ($this->_return_sql && strpos($sql, $this->_select_rt_name) !== false) {
switch ($this->_return_sql) {
case 'count':
$sql = str_replace($this->_select_rt_name, 'count(*) as ct', $sql);
break;
case 'sum':
$sql = str_replace($this->_select_rt_name, 'sum('.$this->_sum_field.') as ct', $sql);
break;
}
}
$debug.= '查询解析: '.$sql.'
';
$debug.= '查询耗时: '.$this->_sql_time.'s
';
}
$debug.= '当前路由:'.\Phpcmf\Service::L('router')->uri().'
';
CMSURI && $debug.= '当前地址:'.CMSURI.'
';
$debug.= '动态地址:'.SELF.'?'.http_build_query($_GET).'
';
if ($data && !is_array($data)) {
$debug.= ''.$data.'
';
$data = [];
}
$debug.= '变量前缀:'.($return ? $return : 't').'
';
} else {
$debug = 'debug诊断信息需要在index.php文件中开启开发者模式才能查看';
}
// 开始返回
if ($this->_return_sql) {
if (CI_DEBUG) {
$debug .= '运算数量:' . ($data[0]['ct']) . '
';
$debug .= '运算变量:' . ($return ? '{$' . $return . '_' . $this->_return_sql . '} 不输出,需要手动调用变量' : '自动输出') . '
';
$debug .= '';
}
return [
'debug_'.$this->_return_sql => $debug,
'return_'.$this->_return_sql => $data,
];
} else {
if ($data) {
$rt2 = \Phpcmf\Hooks::trigger_callback('view_return', $data, $this->_list_tag, $this->_list_param);
if ($rt2 && isset($rt2['code']) && $rt2['code']) {
$data = $rt2['data'];
}
}
if (CI_DEBUG) {
$debug.= '总记录数:'.$total.'
'; if ($this->_page_used) { $debug.= '分页功能:已开启
'; $debug.= '当前页码:'.$page.'
'; $debug.= '总页数量:'.$nums. ($nums == 1 ? '(数据量未达到分页数据,因此只有一页)' : '').'
'; $debug.= '每页数量:'.$pagesize.'
'; $debug.= '分页地址:'.$this->_page_urlrule.'
'; $debug.= '分页配置:'.$this->page_config_file.'
'; } else { $debug.= '分页功能:未开启
'; } isset($data[0]) && is_array($data[0]) && $debug.= '可用字段:'.implode('、', array_keys($data[0])).'
'; $debug.= ''; } // 返回数据格式 if ($return) { return [ 'nums_'.$return => $nums, 'page_'.$return => $page, 'pages_'.$return => $pages, 'debug_'.$return => $debug, 'total_'.$return => $total, 'return_'.$return => $data, 'pagerule_'.$return => $this->_page_urlrule, 'pagesize_'.$return => $pagesize, ]; } else { return [ 'nums' => $nums, 'debug' => $debug, 'page' => $page, 'total' => $total, 'pages' => $pages, 'return' => $data, 'pagerule' => $this->_page_urlrule, 'pagesize' => $pagesize, ]; } } } // 替换变量 public function _get_var($param) { $array = explode('.', $param); if (!$array) { return ''; } $string = ''; foreach ($array as $var) { $var = dr_safe_replace($var); $string.= '['; if (strpos($var, '$') === 0) { $string.= preg_replace('/\[(.+)\]/U', '[\'\\1\']', $var); } elseif (preg_match('/[A-Z_]+/', $var)) { $string.= ''.$var.''; } else { $string.= '\''.$var.'\''; } $string.= ']'; } return $string; } // 公共变量参数 public function _cache_var($name, $siteid = 0) { $data = null; $name = strtolower($name); switch ($name) { case 'member': $data = \Phpcmf\Service::C()->member_cache; break; case 'member_group': $data = \Phpcmf\Service::C()->member_cache['group']; break; case 'site_info': $data = \Phpcmf\Service::C()->site_info; break; case 'urlrule': $data = \Phpcmf\Service::L('cache')->get('urlrule'); break; case 'module-content': $data = \Phpcmf\Service::L('cache')->get('module-'.$siteid.'-content'); break; case 'category': $data = \Phpcmf\Service::L('cache')->get('module-'.$siteid.'-'.MOD_DIR, 'category'); break; case 'page': $data = \Phpcmf\Service::L('cache')->get('page-'.$siteid, 'data'); break; default: if ($siteid) { $data = \Phpcmf\Service::L('cache')->get($name.'-'.$siteid); } else { $data = \Phpcmf\Service::L('cache')->get($name); } break; } return $data; } // 模板中的全部变量 public function get_data() { return $this->_options; } // 模板中的全部变量 public function getData() { return []; } // 模板中的文件数 public function get_view_files() { return $this->_view_files; } // 模板中的文件引用提示 public function add_load_tips($name, $msg) { if ($name) { $this->_load_file_tips[$name] = $msg; } else { $this->_load_file_tips[] = $msg; } } // 模板中的文件引用提示 public function get_load_tips() { if (!$this->_load_file_tips) { return [ [ 'name' => $this->_filename, 'tips' => '' ] ]; } $rt = []; foreach ($this->_load_file_tips as $i => $t) { $rt[] = [ 'name' => $i, 'tips' => $t, ]; } return $rt; } // 模板中的运行时间 public function get_view_time() { return $this->_view_time; } /** * 主要用于调试工具栏 * * @return array */ public function getPerformanceData(): array { return $this->performanceData; } /** * 记录模板的性能数据 * * @param float $start * @param float $end * @param string $view */ protected function logPerformance(float $start, float $end, string $view) { if (!CI_DEBUG) return; $this->performanceData[] = [ 'start' => $start, 'end' => $end, 'view' => $view ]; } // 错误提示 public function show_error($msg, $file = '', $fixfile = '') { if (CI_DEBUG || defined('SC_HTML_FILE')) { // 开发者模式下,静态生成模式下,显示详细错误 if ($file) { $msg.= '('.$file.')'; if ($fixfile) { $msg.= '