PHPCMS乱解读之 pc标签的实现

标 题: PHPCMS乱解读之 pc标签的实现
作 者: web开发网[http://www.zeroplace.cn]
时 间: 2013/07/31 12:15:00
链 接: http://www.zeroplace.cn/article.asp?id=855
说 明: 转载请保留本段文字 

最近电脑硬件出了点问题,现正在修理中呀,敢问各位有没有会修主板那种电路的...

 前面在写 PHPCMSV9 乱解读 之 PHPCMS V9的MVC 的时候有写到phpcms模板解析引擎的部分,但只是解释了一下模板是怎么编译的,没有具体讲其中的每个标签的实现细节。实际上多数的标签都很常规,并没有什么好说的。这里我来写写PC这个标签的实现方法。

 首先还是看到libs/classes/template_cache.class.php这个文件中template_parse这个方法,发现里面有一句代码是用来编译pc这个标签的

$str = preg_replace("/\{pc:(\w+)\s+([^}]+)\}/ie", "self::pc_tag("$1','$2', '$0')", $str);

这句代码的作用就是对类似于

{pc:content  action="position" posid="2" order="listorder DESC" num="4"}

的代码做一个划分,$1就是content, $2就是action="position" posid="2" order="listorder DESC" num="4",$0就是这整句话。然后分别将他们传入了self::pc_tag中

现在看到template_cache::pc_tag这个函数

	/**
	 * 解析PC标签
	 * @param string $op 操作方式
	 * @param string $data 参数
	 * @param string $html 匹配到的所有的HTML代码
	 */
	public static function pc_tag($op, $data, $html) {
		preg_match_all("/([a-z]+)\=[\"]?([^\"]+)[\"]?/i", stripslashes($data), $matches, PREG_SET_ORDER);
		$arr = array("action','num','cache','page', 'pagesize', 'urlrule', 'return', 'start');
		$tools = array('json', 'xml', 'block', 'get');
		$datas = array();
		$tag_id = md5(stripslashes($html));
		//可视化条件
		$str_datas = 'op='.$op.'&tag_md5='.$tag_id;
		foreach ($matches as $v) {
			$str_datas .= $str_datas ? "&$v[1]=".($op == 'block' && strpos($v[2], '$') === 0 ? $v[2] : urlencode($v[2])) : "$v[1]=".(strpos($v[2], '$') === 0 ? $v[2] : urlencode($v[2]));
			// arr数组中的参数直接添加到变量表中
			if(in_array($v[1], $arr)) {
				$$v[1] = $v[2];
				continue;
			}
			
			// 不是arr数组中的参数添加到data数组中
			$datas[$v[1]] = $v[2];
		}
		$str = '';
		$num = isset($num) && intval($num) ? intval($num) : 20;
		$cache = isset($cache) && intval($cache) ? intval($cache) : 0;
		$return = isset($return) && trim($return) ? trim($return) : 'data';
		if (!isset($urlrule)) $urlrule = '';
		
		// 设置了cache且没有设置page
		if (!empty($cache) && !isset($page)) {
			$str .= '$tag_cache_name = md5(implode(\'&\','.self::arr_to_html($datas).').\''.$tag_id.'\');if(!$'.$return.' = tpl_cache($tag_cache_name,'.$cache.')){';
		}
		if (in_array($op,$tools)) {
			switch ($op) {
				case 'json':
						if (isset($datas['url']) && !empty($datas['url'])) {
							$str .= '$json = @file_get_contents(\''.$datas['url'].'\');';
							$str .= '$'.$return.' = json_decode($json, true);';
						}
					break;
					
				case 'xml':
						$str .= '$xml = pc_base::load_sys_class(\'xml\');';
						$str .= '$xml_data = @file_get_contents(\''.$datas['url'].'\');';
						$str .= '$'.$return.' = $xml->xml_unserialize($xml_data);';
					break;
					
				case 'get':
						$str .= 'pc_base::load_sys_class("get_model", "model", 0);';
						if ($datas['dbsource']) {
							$dbsource = getcache('dbsource', 'commons');
							if (isset($dbsource[$datas['dbsource']])) {
								$str .= '$get_db = new get_model('.var_export($dbsource,true).', \''.$datas['dbsource'].'\');';
							} else {
								return false;
							}
						} else {
							$str .= '$get_db = new get_model();';
						}
						$num = isset($num) && intval($num) > 0 ? intval($num) : 20;
						if (isset($start) && intval($start)) {
							$limit = intval($start).','.$num;
						} else {
							$limit = $num;
						}
						if (isset($page)) {
							$str .= '$pagesize = '.$num.';';
							$str .= '$page = intval('.$page.') ? intval('.$page.') : 1;if($page<=0){$page=1;}';
							$str .= '$offset = ($page - 1) * $pagesize;';
							$limit = '$offset,$pagesize';
							if ($sql = preg_replace('/select([^from].*)from/i', "Select COUNT(*) as count FROM ", $datas['sql'])) {
								$str .= '$r = $get_db->sql_query("'.$sql.'");$s = $get_db->fetch_next();$pages=pages($s[\'count\'], $page, $pagesize, $urlrule);';
							}
						}
						
						
						$str .= '$r = $get_db->sql_query("'.$datas['sql'].' LIMIT '.$limit.'");while(($s = $get_db->fetch_next()) != false) {$a[] = $s;}$'.$return.' = $a;unset($a);';
					break;
					
				case 'block':
					$str .= '$block_tag = pc_base::load_app_class(\'block_tag\', \'block\');';
					$str .= 'echo $block_tag->pc_tag('.self::arr_to_html($datas).');';
					break;
			}
		} else {
			if (!isset($action) || empty($action)) return false;
			if (module_exists($op) && file_exists(PC_PATH.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.$op.DIRECTORY_SEPARATOR.'classes'.DIRECTORY_SEPARATOR.$op.'_tag.class.php')) {
				$str .= '$'.$op.'_tag = pc_base::load_app_class("'.$op.'_tag", "'.$op.'");if (method_exists($'.$op.'_tag, \''.$action.'\')) {';	
				if (isset($start) && intval($start)) {
					$datas['limit'] = intval($start).','.$num;
				} else {
					$datas['limit'] = $num;
				}
				if (isset($page)) {
					$str .= '$pagesize = '.$num.';';
					$str .= '$page = intval('.$page.') ? intval('.$page.') : 1;if($page<=0){$page=1;}';
					$str .= '$offset = ($page - 1) * $pagesize;';
					$datas['limit'] = '$offset.",".$pagesize';
					$datas['action'] = $action;
					$str .= '$'.$op.'_total = $'.$op.'_tag->count('.self::arr_to_html($datas).');';
					$str .= '$pages = pages($'.$op.'_total, $page, $pagesize, $urlrule);';
				}
				$str .= '$'.$return.' = $'.$op.'_tag->'.$action.'('.self::arr_to_html($datas).');';
				$str .= '}';
			} 
		}
		if (!empty($cache) && !isset($page)) {
			$str .= 'if(!empty($'.$return.')){setcache($tag_cache_name, $'.$return.', \'tpl_data\');}';
			$str .= '}';
		}
		return "<"."?php if(defined('IN_ADMIN')  && !defined('HTML')) {echo \"

这个函数通过in_array($op,$tools)将所有的pc标签分为两类,就是phpcms官方称的功能模块和工具箱

工具箱

工具箱里面的xml和json是比较简单的,只是调用了一下file_get_contents来取得指定url的内容再做decode而已。

get实际上就是一个执行sql语句的方法,可以配置调取外部数据库的数据。

block就是一个数据块,在程序上只是调用数据库取出内容而已。

功能模块

在功能模块的分枝pc_base::load_app_class加载了/module/$op/classes/$op_tag.class.php了然后调用这个 类的$action方法。所有写在pc标签中间的属性将会传递给$action方法。

如果要对模块进行二次开发,直接修改这个文件即可。

 



文章来自: 本站原创
Tags:
评论: 0 | 查看次数: 10560