This commit is contained in:
Gitea
2022-01-24 10:43:35 +08:00
commit 15dfc6576b
786 changed files with 219240 additions and 0 deletions

396
core/view/Paging.php Normal file
View File

@@ -0,0 +1,396 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2016年11月6日
* 分页控制类
*/
namespace core\view;
use core\basic\Config;
class Paging
{
// 每页数量
public $pageSize;
// 当前页码
public $page;
// 数字条数量
public $num = 5;
// 调整数量
public $start = 1;
// 总记录
private $rowTotal = 0;
// 页面数量
private $pageCount;
// 存储前置URL
private $preUrl;
// 分页实例
private static $paging;
private function __construct()
{
// 禁用类new实例化
}
// 获取单一实例
public static function getInstance()
{
if (! self::$paging) {
self::$paging = new self();
}
return self::$paging;
}
// 限制语句
public function limit($total = null, $morePageStr = false)
{
// 起始数据调整
if (! is_numeric($this->start) || $this->start < 1) {
$this->start = 1;
}
if ($this->start > $total) {
$this->start = $total + 1;
}
// 设置总数
if ($total) {
$this->rowTotal = $total - ($this->start - 1);
}
// 设置分页大小
if (! isset($this->pageSize)) {
$this->pageSize = get('pagesize') ?: Config::get('pagesize') ?: 15;
}
// 分页数字条数量
$this->num = Config::get('pagenum') ?: 5;
// 计算页数
$this->pageCount = @ceil($this->rowTotal / $this->pageSize);
// 获取当前页面
$this->page = $this->page();
// 定义相关常量,用于方便模板引擎解析序号等计算和调用
define('ROWTOTAL', $this->rowTotal);
define('PAGECOUNT', $this->pageCount);
define('PAGE', $this->page);
define('PAGESIZE', $this->pageSize);
// 注入分页模板变量
$this->assign($morePageStr);
// 返回限制语句
return ($this->page - 1) * $this->pageSize + ($this->start - 1) . ",$this->pageSize";
}
// 快速分页字符代码
public function quikLimit()
{
$page = get('page', 'int') ?: 1;
if ($page < 1) {
$page = 0;
}
$pagesize = config::get('pagesize') ?: 15;
return ($page - 1) * $pagesize . ",$pagesize";
}
// 注入页面相关信息,用于模板调用,如:{$pagebar}调用分页条
private function assign($morePageStr = false)
{
assign('pagebar', $this->pageBar());
if ($morePageStr) {
assign('pagecurrent', $this->page()); // 注入当前页
assign('pagecount', $this->pageCount); // 注入总页数
assign('pagerows', $this->rowTotal); // 注入总数据
assign('pageindex', $this->pageIndex()); // 注入首页链接
assign('pagepre', $this->pagePre()); // 注入前一页链接
assign('pagenext', $this->pageNext()); // 注入后一页链接
assign('pagelast', $this->pageLast()); // 注入最后一页链接
assign('pagestatus', $this->pageStatus()); // 注入分页状态
assign('pagenumbar', $this->pageNumBar()); // 注入数字
assign('pageselectbar', $this->pageSelectBar()); // 注入选择栏
}
}
// 当前页码容错处理
private function page()
{
$page = get('page', 'int') ?: $this->page;
if (is_numeric($page) && $page > 1) {
if ($page > $this->pageCount && $this->pageCount) {
return $this->pageCount;
} else {
return $page;
}
} else {
return 1;
}
}
// 过滤pathinfo中分页参数
private function getPreUrl()
{
if (! isset($this->preUrl) && URL) {
$url = parse_url(URL);
$path = preg_replace('/\/page\/[0-9]+/i', '', $url['path']);
if (defined('CMS_PAGE') && CMS_PAGE == true) { // 使用CMS分页时去除扩展
$url_rule_suffix = Config::get('url_rule_suffix');
if (! ! $pos = strripos($path, $url_rule_suffix)) {
$path = substr($path, 0, $pos);
}
}
$this->preUrl = $path;
}
return $this->preUrl;
}
// 构建链接地址
private function buildPath($page)
{
if ($page) {
if (defined('CMS_PAGE') && CMS_PAGE == true) {
$url_rule_type = Config::get('url_rule_type') ?: 3;
$url_rule_suffix = Config::get('url_rule_suffix') ?: '.html';
$url_break_char = Config::get('url_break_char') ?: '_';
$url_rule_sort_suffix = '/';
if ($url_rule_type == 1 || $url_rule_type == 2) {
if (defined('CMS_PAGE_CUSTOM')) { // 去分页参数
$prepath = preg_replace('/(.*)' . $url_break_char . '[0-9]+$/', '$1', rtrim($this->getPreUrl(), '/'));
} else {
$prepath = preg_replace('/(.*)(' . $url_break_char . '[0-9]+)' . $url_break_char . '[0-9]+$/', '$1$2', rtrim($this->getPreUrl(), '/'));
}
if ($prepath) { // 非首页分页
if ($page == 1) { // 第一页处理
$path = $prepath . $url_rule_sort_suffix . query_string('p,s');
} else {
$path = $prepath . $url_break_char . $page . $url_rule_sort_suffix . query_string('p,s');
}
} else { // 首页分页
$path = ($page == 1) ? SITE_INDEX_DIR . '/' : '?page=' . $page;
}
} else {
if ($url_rule_type == 3 && isset($_SERVER["QUERY_STRING"]) && $qs = $_SERVER["QUERY_STRING"]) {
parse_str($qs, $output);
unset($output['page']);
if ($output && ! current($output)) {
$path_qs = key($output); // 第一个参数为路径信息注意PHP数组会自动将点转换下划线
unset($output[$path_qs]); // 去除路径参数
// 去后缀扩展
$temp_suffix = substr($url_rule_suffix, 1);
if (! ! $pos = strripos($path_qs, '_' . $temp_suffix)) {
$path = substr($path_qs, 0, $pos); // 去扩展
} else {
$path = $path_qs;
}
// 去除原分页参数
if (defined('CMS_PAGE_CUSTOM')) {
$path = preg_replace('/(.*)' . $url_break_char . '[0-9]+$/', "$1", rtrim($path, '/'));
} else {
$path = preg_replace('/(.*)(' . $url_break_char . '[0-9]+)' . $url_break_char . '[0-9]+$/', "$1$2", rtrim($path, '/'));
}
// 第一页链接处理
if ($page == 1) {
$path = SITE_INDEX_DIR . '/?' . $path . $url_rule_sort_suffix;
} else {
$path = SITE_INDEX_DIR . '/?' . $path . $url_break_char . $page . $url_rule_sort_suffix;
}
// 附加参数
if (! ! $qs = http_build_query($output)) {
$path = rtrim($path, '/') . '&' . $qs;
}
}
}
if (! $path) { // 转基本分页模式
return $this->buildBasicPage($page);
}
}
return $path;
} else {
return $this->buildBasicPage($page);
}
} else {
return 'javascript:;';
}
}
// 构建基本分页
private function buildBasicPage($page)
{
// 对于路径保留变量给予去除
$qs = $_SERVER["QUERY_STRING"];
if ((M == 'home' && Config::get('url_rule_type') == 2) || (M != 'home' && Config::get('app_url_type') == 2)) {
$qs = preg_replace('/[&\?]?p=([\w\/\.]+)?/i', '', $qs);
$qs = preg_replace('/[&\?]?s=([\w\/\.]+)?/i', '', $qs);
}
$qs = preg_replace('/[&\?]?page=([0-9]+)?/i', '', $qs);
if ($page == 1) {
if ($qs) {
return $this->getPreUrl() . '?' . $qs;
} else {
return $this->getPreUrl();
}
} else {
if ($qs) {
return $this->getPreUrl() . '?' . $qs . '&page=' . $page;
} else {
return $this->getPreUrl() . '?page=' . $page;
}
}
}
// 分页条
private function pageBar()
{
if (! $this->pageCount)
return "<span class='page-none' style='color:#999'>未查询到任何数据!</span>";
$string = "<span class='page-status'>{$this->pageStatus()}</span>";
$string .= "<span class='page-index'><a href='" . $this->pageIndex() . "'>首页</a></span>";
$string .= "<span class='page-pre'><a href='" . $this->pagePre() . "'>前一页</a></span>";
$string .= "<span class='page-numbar'>{$this->pageNumBar()}</span>";
$string .= "<span class='page-next'><a href='" . $this->pageNext() . "'>后一页</a></span>";
$string .= "<span class='page-last'><a href='" . $this->pageLast() . "'>尾页</a></span>";
// $string .= "<span class='page-select'>{$this->pageSelectBar()}</span>";
return $string;
}
// 当前页面情况
private function pageStatus()
{
if (! $this->pageCount)
return;
return "" . $this->rowTotal . "条 当前" . $this->page . "/" . $this->pageCount . "";
}
// 首页链接
private function pageIndex()
{
if (! $this->pageCount)
return $this->buildPath('');
return $this->buildPath(1);
}
// 上一页链接
private function pagePre()
{
if (! $this->pageCount)
return $this->buildPath('');
if ($this->page > 1) {
$pre_page = $this->buildPath($this->page - 1);
} else {
$pre_page = $this->buildPath('');
}
return $pre_page;
}
// 下一页链接
private function pageNext()
{
if (! $this->pageCount)
return $this->buildPath('');
if ($this->page < $this->pageCount) {
$next_page = $this->buildPath($this->page + 1);
} else {
$next_page = $this->buildPath('');
}
return $next_page;
}
// 尾页
private function pageLast()
{
if (! $this->pageCount)
return $this->buildPath('');
return $this->buildPath($this->pageCount);
}
// 数字分页,要修改数字显示的条数请修改类头部num属性值
private function pageNumBar()
{
if (! $this->pageCount)
return;
if (M == 'admin') {
$total = 5;
} else {
$total = $this->num;
}
$halfl = intval($total / 2);
$halfu = ceil($total / 2);
$num_html = '';
if ($this->page > $halfu) {
$num_html .= '<span class="page-num">···</span>';
}
if ($this->page <= $halfl || $this->pageCount < $total) { // 当前页小于一半或页数小于总数
for ($i = 1; $i <= $total; $i ++) {
if ($i > $this->pageCount)
break;
if ($this->page == $i) {
$num_html .= '<a href="' . $this->buildPath($i) . '" class="page-num page-num-current">' . $i . '</a>';
} else {
$num_html .= '<a href="' . $this->buildPath($i) . '" class="page-num">' . $i . '</a>';
}
}
} elseif ($this->page + $halfl >= $this->pageCount) { // 当前页为倒数页以内
for ($i = $this->pageCount - $total + 1; $i <= $this->pageCount; $i ++) {
if ($this->page == $i) {
$num_html .= '<a href="' . $this->buildPath($i) . '" class="page-num page-num-current">' . $i . '</a>';
} else {
$num_html .= '<a href="' . $this->buildPath($i) . '" class="page-num">' . $i . '</a>';
}
}
} else { // 正常的前后各5页
for ($i = $this->page - $halfl; $i <= $this->page + $halfl; $i ++) {
if ($this->page == $i) {
$num_html .= '<a href="' . $this->buildPath($i) . '" class="page-num page-num-current">' . $i . '</a>';
} else {
$num_html .= '<a href="' . $this->buildPath($i) . '" class="page-num">' . $i . '</a>';
}
}
}
if ($this->pageCount > $total && $this->page < $this->pageCount - $halfl) {
$num_html .= '<span class="page-num">···</span>';
}
return $num_html;
}
// 跳转分页
private function pageSelectBar()
{
if (! $this->pageCount)
return;
$select_html = '<select onchange="changepage(this)" lay-ignore>';
for ($i = 1; $i <= $this->pageCount; $i ++) {
if ($i == $this->page) {
$select_html .= '<option value="' . $i . '" selected="selected">跳到' . $i . '页</option>';
} else {
$select_html .= '<option value="' . $i . '">跳到' . $i . '页</option>';
}
}
$select_html .= '</select><script>function changepage(tag){window.location.href="' . $this->buildPath('"+tag.value+"') . '";}</script>';
return $select_html;
}
}

521
core/view/Parser.php Normal file
View File

@@ -0,0 +1,521 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2016年11月6日
* 模板解析引擎
*/
namespace core\view;
use core\basic\Config;
class Parser
{
// 模板内容
private static $content;
// 模板路径在嵌套时必须
private static $tplPath;
// 包含文件
private static $tplInc = array();
/**
* 编译公共方法
*
* @param string $tplPath
* 模板主题目录,需要是物理路径
* @param string $tplFile
* 需要解析的模板文件,需要是物理路径
* @return string|mixed
*/
public static function compile($tplPath, $tplFile)
{
// 接收模板目录参数
self::$tplPath = $tplPath;
// 读取模板内容
$content = file_get_contents($tplFile) ?: error('模板文件读取错误!' . $tplFile);
// 去除内容Bom信息;
self::$content = ltrim($content, "\xEF\xBB\xBF");
// 解析文件包含,需要优先解析
self::parInclude();
// 添加包含文件记录
self::$content .= "<?php return " . var_export(array_unique(self::$tplInc), 1) . "; ?>";
// =====以下为直接输出方法=========
self::parOutputUrl(); // 输出地址
self::parOutputHomeUrl(); // 输出前端地址
self::parOutputDefine(); // 输出常量
self::parOutputVar(); // 输出变量
self::parOutputObjVal(); // 输出对象
self::parOutputConfig(); // 输出配置参数
self::parOutputSession(); // 输出会话Session
self::parOutputCookie(); // 输出会话Cookie
self::parOutputServer(); // 输出环境变量
self::parOutputPost(); // 输出POST请求值
self::parOutputGet(); // 输出GET请求值
self::parOutputArrVal(); // 输出数组
self::parOutputFun(); // 使用函数
// =========以下为逻辑控制方法==========
self::parIf(); // IF语句
self::parForeachVar(); // Foreach语句
self::parForeachValue(); // Foreach语句嵌套
self::parForeachObj(); // Foreach对象属性
self::parNote(); // 备注
self::parPhp(); // PHP语句
// ============以下为变量解析方法==========
self::parVar(); // 解析变量
self::parObjVar(); // 解析对象
self::parConfigVar(); // 解析配置
self::parSession(); // 解析Session
self::parCookie(); // 解析Cookie
self::parServer(); // 解析环境变量
self::parPost(); // 解析POST请求值
self::parGet(); // 解析GET请求值
self::parArrVar(); // 解析数组
self::parFun(); // 解析函数
// 返回解释的内容
return self::$content;
}
// 解析包含文件,支持多层嵌套
private static function parInclude()
{
$pattern = '/\{include\s+file\s?=\s?([\"\']?)([\w\.\-\/@]+)([\"\']?)\s*\}/';
if (preg_match_all($pattern, self::$content, $matches)) {
$arr = $matches[0]; // 匹配到的所有“包含字符串”:{include file='head.html'}
$brr = $matches[2]; // 包含的文件名head.html
$count = count($arr);
for ($i = 0; $i < $count; $i ++) {
// 然包含文件支持绝对路径,以/开头
if (strpos($brr[$i], '/') === 0) {
$inc_file = ROOT_PATH . $brr[$i];
} elseif (! ! $pos = strpos($brr[$i], '@')) {
$inc_file = APP_PATH . '/' . substr($brr[$i], 0, $pos) . '/view/' . basename(self::$tplPath) . '/' . substr($brr[$i], $pos + 1);
} else {
if (M == 'home') { // 前台适应模板子目录
$htmldir = Config::get('tpl_html_dir') ? Config::get('tpl_html_dir') . '/' : '';
$inc_file = self::$tplPath . '/' . $htmldir . $brr[$i];
} else {
$inc_file = self::$tplPath . '/' . $brr[$i];
}
}
file_exists($inc_file) ?: error('包含文件不存在!' . $inc_file);
if (! $inc_content = file_get_contents($inc_file)) {
error('包含的模板文件' . $brr[$i] . '读取错误!');
} else {
self::$content = str_replace($arr[$i], $inc_content, self::$content); // 包含内容
self::$tplInc[] = $inc_file;
}
}
// 最大数量不超过50防止互相包含导致无限循环
if (count(self::$tplInc) < 50) {
self::parInclude();
} else {
error('检测到您模板中包含文件超过50个请检查是否存在互相包含导致无限循环的情况');
}
} else {
return false;
}
}
// 解析地址输出 {url./admin/index/index}
private static function parOutputUrl()
{
$pattern = '/\{url\.([^\}]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo \\core\\basic\\Url::get('$1');?>", self::$content);
}
}
// 解析地址输出 {homeurl./home/index/index}
private static function parOutputHomeUrl()
{
$pattern = '/\{homeurl\.([^\}]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo \\core\\basic\\Url::home('$1');?>", self::$content);
}
}
// 解析输出常量 如:{DB_HOST}
private static function parOutputDefine()
{
$pattern = '/\{([A-Z_]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo $1;?>", self::$content);
}
}
// 解析输出普通变量 如:{$name}
private static function parOutputVar()
{
$pattern = '/\{\$([\w]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo \$this->getVar('$1');?>", self::$content);
}
}
// 解析输出对象变量 如:{$user->name}
private static function parOutputObjVal()
{
$pattern = '/\{\$([\w]+)(\->)(\{?)([^}]+)(\}?)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo @\$this->getVar('$1')$2$3$4$5;?>", self::$content);
}
}
// 解析输出配置 如:{$config.public_app},支持多级
private static function parOutputConfig()
{
$pattern = '/\{\$config\.([\w\.]+)\}/';
if (preg_match_all($pattern, self::$content, $matchs)) {
foreach ($matchs[0] as $key => $value) {
if (strpos($matchs[1][$key], 'database') === false) {
self::$content = str_replace($matchs[0][$key], "<?php print_r(\\core\\basic\\Config::get('" . $matchs[1][$key] . "'));?>", self::$content);
}
}
}
}
// 解析输出Session变量 如:{$session.username},支持多级
private static function parOutputSession()
{
$pattern = '/\{\$session\.([\w\.]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo session('$1');?>", self::$content);
}
}
// 解析输出Cookie变量 如:{$cookie.username}
private static function parOutputCookie()
{
$pattern = '/\{\$cookie\.([\w]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo cookie('$1');?>", self::$content);
}
}
// 解析输出Server变量 如:{$server.PATH_INFO}
private static function parOutputServer()
{
$pattern = '/\{\$server\.([\w\-]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo escape_string(\$_SERVER['$1']);?>", self::$content);
}
}
// 解析输出POST变量 如:{$post.username}
private static function parOutputPost()
{
$pattern = '/\{\$post\.([\w\-]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo post('$1');?>", self::$content);
}
}
// 解析输出GET变量 如:{$get.username}
private static function parOutputGet()
{
$pattern = '/\{\$get\.([\w\-]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo get('$1');?>", self::$content);
}
}
// 解析输出数组变量 如:{$user['name']} 2.0修改为:{$user.name},支持二维数组{$user.name.sex}
private static function parOutputArrVal()
{
$pattern = '/\{\$([\w]+)\.([\w\-]+)(\.([\w\-]+))?\}/';
if (preg_match_all($pattern, self::$content, $matches)) {
foreach ($matches[0] as $key => $value) {
if ($matches[3][$key]) {
self::$content = preg_replace($pattern, "<?php echo @\$this->vars['$1']['$2']['$4'];?>", self::$content);
} else {
self::$content = preg_replace($pattern, "<?php echo @\$this->vars['$1']['$2'];?>", self::$content);
}
}
}
}
// 应用函数 如:{fun=md5('aaa')}
private static function parOutputFun()
{
$pattern = '/\{fun\s?=\s?([^\}]+)\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php echo $1;?>", self::$content);
}
}
// 解析if语句 例:{if(a==b)}aaaa{else}bbbb{/if}
private static function parIf()
{
$pattern = '/\{if\(([^}]+)\)\s*\}([\s\S]*)\{\/if\}/';
$pattern_if = '/\{if\(([^}]+)\)\s*\}/';
$pattern_end_if = '/\{\/if\}/';
$pattern_else = '/\{else\}/';
// 未配对的if不进行解析
if (preg_match_all($pattern, self::$content, $matches)) {
$count = count($matches[0]);
for ($i = 0; $i < $count; $i ++) {
$content = preg_replace($pattern_if, "<?php if ($1) {?>", $matches[0][$i]);
$content = preg_replace($pattern_end_if, "<?php } ?>", $content);
$content = preg_replace($pattern_else, "<?php } else { ?>", $content);
self::$content = str_replace($matches[0][$i], $content, self::$content);
}
}
}
// 解析循环语句 {foreach $var(key,value,num)}...[num][value->name]或[value]...{/foreach}
private static function parForeachVar()
{
$pattern_foreach = '/\{foreach\s+\$([\w]+)\(([\w]+),([\w]+)(,([\w]+))?\)\}/';
$pattern_end_foreach = '/\{\/foreach\}/';
if (preg_match_all($pattern_foreach, self::$content, $matches)) {
$count = count($matches[0]);
for ($i = 0; $i < $count; $i ++) {
if (! $matches[5][$i]) {
$matches[5][$i] = 'num';
}
// 解析首标签
self::$content = str_replace($matches[0][$i], "<?php \$" . $matches[5][$i] . " = 0;foreach (\$this->getVar('" . $matches[1][$i] . "') as \$" . $matches[2][$i] . " => \$" . $matches[3][$i] . ") { \$" . $matches[5][$i] . "++;?>", self::$content);
// 解析序号
$pattern_num = '/\[(' . $matches[5][$i] . ')\]/';
if (preg_match($pattern_num, self::$content)) {
if (defined('PAGE')) {
self::$content = preg_replace($pattern_num, "<?php echo @(PAGE-1)*PAGESIZE+\$$1; ?>", self::$content);
} else {
self::$content = preg_replace($pattern_num, "<?php echo \$$1; ?>", self::$content);
}
}
// 解析key
$pattern_key = '/\[(' . $matches[2][$i] . ')\]/';
if (preg_match($pattern_key, self::$content)) {
self::$content = preg_replace($pattern_key, "<?php echo \$$1; ?>", self::$content);
}
// 解析内部变量
$pattern_var = '/\[(' . $matches[3][$i] . ')(\[[\'\"][\w]+[\'\"]\])?(\-\>[\w$]+)?\]/';
self::$content = preg_replace($pattern_var, "<?php echo \$$1$2$3; ?>", self::$content);
}
// 解析闭合标签
self::$content = str_replace('{/foreach}', "<?php } ?>", self::$content);
}
}
// 解析循环语句嵌套 {foreach $value->name(key,value,num)}...[num][value->name]或[value]...{/foreach}
private static function parForeachValue()
{
$pattern_foreach = '/\{foreach\s+\$([\w][\w\->]+)\(([\w]+),([\w]+)(,([\w]+))?\)\}/';
$pattern_end_foreach = '/\{\/foreach\}/';
if (preg_match_all($pattern_foreach, self::$content, $matches)) {
$count = count($matches[0]);
for ($i = 0; $i < $count; $i ++) {
if (! $matches[5][$i]) {
$matches[5][$i] = 'num';
}
// 解析首标签
self::$content = str_replace($matches[0][$i], "<?php \$" . $matches[5][$i] . " = 0;foreach (\$" . $matches[1][$i] . " as \$" . $matches[2][$i] . " => \$" . $matches[3][$i] . ") { \$" . $matches[5][$i] . "++;?>", self::$content);
// 解析序号
$pattern_num = '/\[(' . $matches[5][$i] . ')\]/';
if (preg_match($pattern_num, self::$content)) {
if (defined('PAGE')) {
self::$content = preg_replace($pattern_num, "<?php echo (PAGE-1)*PAGESIZE+\$$1; ?>", self::$content);
} else {
self::$content = preg_replace($pattern_num, "<?php echo \$$1; ?>", self::$content);
}
}
// 解析key
$pattern_key = '/\[(' . $matches[2][$i] . ')\]/';
if (preg_match($pattern_key, self::$content)) {
self::$content = preg_replace($pattern_key, "<?php echo \$$1; ?>", self::$content);
}
// 解析内部变量
$pattern_var = '/\[(' . $matches[3][$i] . ')(\[[\'\"][\w]+[\'\"]\])?(\-\>[\w$]+)?\]/';
self::$content = preg_replace($pattern_var, "<?php echo \$$1$2$3; ?>", self::$content);
}
// 解析闭合标签
self::$content = str_replace('{/foreach}', "<?php }?>", self::$content);
}
}
// 解析循环语句 {foreach [$var->name](key,value,num)}...{/foreach}
private static function parForeachObj()
{
$pattern_foreach = '/\{foreach\s+\[\$([\w]+)\-\>([\w]+)\]\(([\w]+),([\w]+)(,([\w]+))?\)\}/';
$pattern_end_foreach = '/\{\/foreach\}/';
if (preg_match_all($pattern_foreach, self::$content, $matches)) {
$count = count($matches[0]);
for ($i = 0; $i < $count; $i ++) {
if (! $matches[6][$i]) {
$matches[6][$i] = 'num';
}
// 解析首标签
self::$content = str_replace($matches[0][$i], "<?php \$" . $matches[6][$i] . " = 0;foreach (\$this->getVar('" . $matches[1][$i] . "')->" . $matches[2][$i] . " as \$" . $matches[3][$i] . " => \$" . $matches[4][$i] . ") { \$" . $matches[6][$i] . "++;?>", self::$content);
// 解析序号
$pattern_num = '/\[(' . $matches[6][$i] . ')\]/';
if (preg_match($pattern_num, self::$content)) {
if (defined('PAGE')) {
self::$content = preg_replace($pattern_num, "<?php echo @(PAGE-1)*PAGESIZE+\$$1; ?>", self::$content);
} else {
self::$content = preg_replace($pattern_num, "<?php echo \$$1; ?>", self::$content);
}
}
// 解析key
$pattern_key = '/\[(' . $matches[3][$i] . ')\]/';
if (preg_match($pattern_key, self::$content)) {
self::$content = preg_replace($pattern_key, "<?php echo \$$1; ?>", self::$content);
}
// 解析内部变量
$pattern_var = '/\[(' . $matches[4][$i] . ')(\[[\'\"][\w]+[\'\"]\])?(\-\>[\w$]+)?\]/';
self::$content = preg_replace($pattern_var, "<?php echo \$$1$2$3; ?>", self::$content);
}
// 解析闭合标签
self::$content = str_replace('{/foreach}', "<?php } ?>", self::$content);
}
}
// PHP代码注释{#}...{#}
private static function parNote()
{
$pattern = '/\{#\}(\s\S]*?)\{#\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php
/* $1 */
?>", self::$content);
}
}
// 原生PHP代码{php}...{/php}
private static function parPhp()
{
$pattern = '/\{php\}([\s\S]*?)\{\/php\}/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "<?php $1?>", self::$content);
}
}
// 解析变量[$varname]
private static function parVar()
{
$pattern = '/\[\$([\w]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "\$this->getVar('$1')", self::$content);
}
}
// 解析对象变量 [$user->name]
private static function parObjVar()
{
$pattern = '/\[\$([\w]+)\-\>([\w\$]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "\$this->getVar('$1')->$2", self::$content);
}
}
// 解析配置变量[$config.name],支持多级
private static function parConfigVar()
{
$pattern = '/\[\$config\.([\w\.]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "\\core\\basic\\Config::get('$1')", self::$content);
}
if (preg_match_all($pattern, self::$content, $matchs)) {
foreach ($matchs[0] as $key => $value) {
if (strpos($matchs[1][$key], 'database') === false) {
self::$content = str_replace($matchs[0][$key], "\\core\\basic\\Config::get('" . $matchs[1][$key] . "')", self::$content);
}
}
}
}
// 解析Session [$session.name],支持多级
private static function parSession()
{
$pattern = '/\[\$session\.([\w\.]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "session('$1')", self::$content);
}
}
// 解析Cookie [$cookie.name]
private static function parCookie()
{
$pattern = '/\[\$cookie\.([\w]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "cookie('$1')", self::$content);
}
}
// 解析Server [$server.name]
private static function parServer()
{
$pattern = '/\[\$server\.([\w]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "escape_string(\$_SERVER['$1'])", self::$content);
}
}
// 解析POST [$post.id]
private static function parPost()
{
$pattern = '/\[\$post\.([\w]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "post('$1')", self::$content);
}
}
// 解析GET[$get.id]
private static function parGet()
{
$pattern = '/\[\$get\.([\w]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "get('$1')", self::$content);
}
}
// 解析数组变量 [$user['name']] 2.0修改为[$user.name],支持二维数组[$user.name.sex]
private static function parArrVar()
{
$pattern = '/\[\$([\w]+)\.([\w\-]+)(\.([\w\-]+))?\]/';
if (preg_match_all($pattern, self::$content, $matches)) {
foreach ($matches[0] as $key => $value) {
if ($matches[3][$key]) {
self::$content = preg_replace($pattern, "\$this->vars['$1']['$2']['$4']", self::$content);
} else {
self::$content = preg_replace($pattern, "\$this->vars['$1']['$2']", self::$content);
}
}
}
}
// 内部应用函数 如:[fun=md5('aaa')]
private static function parFun()
{
$pattern = '/\[fun=([^\]]+)\]/';
if (preg_match($pattern, self::$content)) {
self::$content = preg_replace($pattern, "$1", self::$content);
}
}
}

159
core/view/View.php Normal file
View File

@@ -0,0 +1,159 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2016年11月6日
* 模板显示类
*/
namespace core\view;
use core\basic\Config;
class View
{
// 模板路径
protected $tplPath;
// 编译路径
protected $tplcPath;
// 缓存路径
protected $cachePath;
// 存储注入变量
protected $vars = array();
// 存储包含文件
protected $incFile = array();
// 实例
protected static $view;
// 获取单一实例
public static function getInstance()
{
if (! self::$view) {
self::$view = new self();
}
return self::$view;
}
// 禁止通过new实例化类
private function __construct()
{
$this->tplPath = APP_VIEW_PATH;
$this->tplcPath = RUN_PATH . '/complile';
$this->cachePath = RUN_PATH . '/cache';
check_dir($this->tplcPath, true);
check_dir($this->cachePath, true);
}
private function __clone()
{
die('不允许克隆对象请使用getInstance获取实例');
}
// 变量注入
public function assign($var, $value)
{
if (! empty($var)) {
if (isset($this->vars[$var])) {
error('模板变量$' . $var . '出现重复注入!');
}
$this->vars[$var] = $value;
return true;
} else {
error('传递的设置模板变量有误');
}
}
// 变量获取
public function getVar($var)
{
if (! empty($var)) {
if (isset($this->vars[$var])) {
return $this->vars[$var];
} else {
return null;
}
} else {
error('传递的获取模板变量有误');
}
}
// 解析模板文件
public function parser($file)
{
// 设置主题
$theme = isset($this->vars['theme']) ? $this->vars['theme'] : 'default';
$theme = preg_replace_r('{\.\.(\/|\\\\)}', '', $theme); // 过滤掉相对路径
$file = preg_replace_r('{\.\.(\/|\\\\)}', '', $file); // 过滤掉相对路径
if (strpos($file, '/') === 0) { // 绝对路径模板
$tpl_file = ROOT_PATH . $file;
} elseif (! ! $pos = strpos($file, '@')) { // 跨模块调用
$path = APP_PATH . '/' . substr($file, 0, $pos) . '/view/' . $theme;
define('APP_THEME_DIR', str_replace(DOC_PATH, '', $path));
if (! is_dir($path)) { // 检查主题是否存在
error('模板主题目录不存在!主题路径:' . $path);
} else {
$this->tplPath = $path;
}
$tpl_file = $path . '/' . substr($file, $pos + 1);
} else {
// 定义当前应用主题目录
define('APP_THEME_DIR', str_replace(DOC_PATH, '', APP_VIEW_PATH) . '/' . $theme);
if (! is_dir($this->tplPath .= '/' . $theme)) { // 检查主题是否存在
error('模板主题目录不存在!主题路径:' . APP_THEME_DIR);
}
$tpl_file = $this->tplPath . '/' . $file; // 模板文件
}
$note = Config::get('tpl_html_dir') ? '<br>同时检测到您后台配置中配置了模板子目录,请核对是否是此原因导致!' : '';
file_exists($tpl_file) ?: error('模板文件' . basename($file) . '不存在!' . $note);
$tpl_c_file = $this->tplcPath . '/' . md5($tpl_file) . '.php'; // 编译文件
// 当编译文件不存在,或者模板文件修改过,则重新生成编译文件
if (! file_exists($tpl_c_file) || filemtime($tpl_c_file) < filemtime($tpl_file) || ! Config::get('tpl_parser_cache')) {
$content = Parser::compile($this->tplPath, $tpl_file); // 解析模板
file_put_contents($tpl_c_file, $content) ?: error('编译文件' . $tpl_c_file . '生成出错!请检查目录是否有可写权限!'); // 写入编译文件
$compile = true;
}
ob_start(); // 开启缓冲区,引入编译文件
$rs = include $tpl_c_file;
if (! isset($compile)) {
foreach ($rs as $value) { // 检查包含文件是否更新,其中一个包含文件不存在或修改则重新解析模板
if (! file_exists($value) || filemtime($tpl_c_file) < filemtime($value) || ! Config::get('tpl_parser_cache')) {
$content = Parser::compile($this->tplPath, $tpl_file); // 解析模板
file_put_contents($tpl_c_file, $content) ?: error('编译文件' . $tpl_c_file . '生成出错!请检查目录是否有可写权限!'); // 写入编译文件
ob_clean();
include $tpl_c_file;
break;
}
}
}
$content = ob_get_contents();
ob_end_clean();
return $content;
}
// 缓存页面, 开启缓存开关时有效
public function cache($content)
{
if (Config::get('tpl_html_cache') && ! query_string('p,s')) {
$lg = cookie('lg');
if (Config::get('open_wap') && (is_mobile() || Config::get('wap_domain') == get_http_host())) {
$wap = 'wap';
} else {
$wap = '';
}
$cacheFile = $this->cachePath . '/' . md5(get_http_url() . $_SERVER["REQUEST_URI"] . $lg . $wap) . '.html'; // 缓存文件
file_put_contents($cacheFile, $content) ?: error('缓存文件' . $cacheFile . '生成出错!请检查目录是否有可写权限!'); // 写入缓存文件
return true;
}
return false;
}
}