Maison > développement back-end > tutoriel php > Analyse PHP et traitement des chaînes des fichiers modèles

Analyse PHP et traitement des chaînes des fichiers modèles

墨辰丷
Libérer: 2023-03-30 22:40:01
original
2705 Les gens l'ont consulté

本篇文章主要介绍php针对模板文件的解析与字符串处理,感兴趣的朋友参考下,希望对大家有所帮助。

本文实例讲述了PHP模板解析类,具体如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

<?php

class template {

 private $vars = array();

 private $conf = &#39;&#39;;

 private $tpl_name = &#39;index&#39;;

 //如果模板不存在 会查找当前 controller默认index模板

 private $tpl_suffix = &#39;.html&#39;;//如果CONFIG没配置默认后缀 则显示

 private $tpl_compile_suffix= &#39;.tpl.php&#39;;//编译模板路径

 private $template_tag_left = &#39;<{&#39;;//模板左标签

 private $template_tag_right = &#39;}>&#39;;//模板右标签

 private $template_c = &#39;&#39;;//编译目录

 private $template_path = &#39;&#39;;//模板完整路径

 private $template_name = &#39;&#39;;//模板名称 index.html

 //定义每个模板的标签的元素

 private $tag_foreach = array(&#39;from&#39;, &#39;item&#39;, &#39;key&#39;);

 private $tag_include = array(&#39;file&#39;);//目前只支持读取模板默认路径

 public function __construct($conf) {

  $this->conf = &$conf;

  $this->template_c = $this->conf[&#39;template_config&#39;][&#39;template_c&#39;];//编译目录

  $this->_tpl_suffix = $this->tpl_suffix();

 }

 private function str_replace($search, $replace, $content) {

  if(empty($search) || empty($replace) || empty($content)) return false;

  return str_replace($search, $replace, $content);

 }

 /**

  * preg_match_all

  * @param $pattern 正则

  * @param $content 内容

  * @return array

  */

 private function preg_match_all($pattern, $content) {

  if(empty($pattern) || empty($content)) core::show_error(&#39;查找模板标签失败!&#39;);

  preg_match_all("/".$this->template_tag_left.$pattern.$this->template_tag_right."/is", $content, $match);

  return $match;

 }

 /**

  * 模板文件后缀

  */

 public function tpl_suffix() {

  $tpl_suffix = empty($this->conf[&#39;template_config&#39;][&#39;template_suffix&#39;]) ?

       $this->tpl_suffix :

       $this->conf[&#39;template_config&#39;][&#39;template_suffix&#39;] ;

  return $tpl_suffix;

 }

 /**

  * 此处不解释了

  * @return

  */

 public function assign($key, $value) {

  $this->vars[$key] = $value;

 }

 /**

  * 渲染页面

  * @param

  * 使用方法 1

  * $this->view->display(&#39;error&#39;, &#39;comm/&#39;);

  * 默认是指向TPL模版的跟目录,所以comm/就是 tpl/comm/error.html

  * 使用方法 2

  * $this->view->display(&#39;errorfile&#39;);

  * 默认指向控制器固定的文件夹

  * 例如你的域名是 http://heartphp/admin/index, 那么正确路径就是tpl/admin/index/errorfile.html

  * @return

  */

 public function display($filename = &#39;&#39;, $view_path = &#39;&#39;) {

  $tpl_path_arr = $this->get_tpl($filename, $view_path);//获取TPL完整路径 并且向指针传送路径以及名称

  if(!$tpl_path_arr) core::show_error($filename.$this->_tpl_suffix.&#39;模板不存在&#39;);

  //编译开始

  $this->view_path_param = $view_path;//用户传递过来的模版跟目录

  $this->compile();

 }

 /**

  * 编译控制器

  * @param

  * @return

  */

 private function compile() {

  $filepath = $this->template_path.$this->template_name;

  $compile_dirpath = $this->check_temp_compile();

  $vars_template_c_name = str_replace($this->_tpl_suffix, &#39;&#39;, $this->template_name);

  $include_file = $this->template_replace($this->read_file($filepath), $compile_dirpath, $vars_template_c_name);//解析

  if($include_file) {

   $this->read_config() && $config = $this->read_config();

   extract($this->vars, EXTR_SKIP);

   [url=home.php?mod=space&uid=48608]@include[/url] $include_file;

  }

 }

 /**

  * 读取当前项目配置文件

  */

 protected function read_config() {

  if(file_exists(SYSTEM_PATH.&#39;conf/config.php&#39;)) {

   @include SYSTEM_PATH.&#39;conf/config.php&#39;;

   return $config;

  }

  return false;

 }

 /**

  * 解析模板语法

  * @param $str 内容

  * @param $compile_dirpath 模版编译目录

  * @param $vars_template_c_name 模版编译文件名

  * @return 编译过的PHP模板文件名

  */

 private function template_replace($str, $compile_dirpath, $vars_template_c_name) {

  if(empty($str)) core::show_error(&#39;模板内容为空!&#39;);

  //处理编译头部

  $compile_path = $compile_dirpath.$vars_template_c_name.$this->tpl_compile_suffix;//编译文件

  if(is_file($compile_path)) {

   //$header_content = $this->get_compile_header($compile_path);

   //$compile_date = $this->get_compile_header_comment($header_content);

   $tpl_filemtime = filemtime($this->template_path.$this->template_name);

   $compile_filemtime = filemtime($compile_path);

   //echo $tpl_filemtime.&#39;==&#39;.date(&#39;Y-m-d H:i:s&#39;, $tpl_filemtime).&#39;<br/>&#39;;

   //echo $compile_filemtime.&#39;==&#39;.date(&#39;Y-m-d H:i:s&#39;, $compile_filemtime);

   //如果文件过期编译 当模板标签有include并且有修改时 也重新编译

   //<{include file="public/left.html"}> 当修改include里的文件,非DEBUG模式时 如果不更改主文件 目前是不重新编译include里的文件,我在考虑是否也要更改,没想好,暂时这样,所以在开发阶段一定要开启DEBUG=1模式 要不然修改include文件无效 。 有点罗嗦,不知道表述清楚没

   if($tpl_filemtime > $compile_filemtime || DEBUG) {

    $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath);

   } else {

    $ret_file = $compile_path;

   }

  } else {//编译文件不存在 创建他

   $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath);

  }

  return $ret_file;

 }

 /**

  * 模板文件主体

  * @param string $str 内容

  * @return html

  */

 private function body_content($str) {

  //解析

  $str = $this->parse($str);

  $header_comment = "Create On##".time()."|Compiled from##".$this->template_path.$this->template_name;

  $content = "<? if(!defined(&#39;IS_HEARTPHP&#39;)) exit(&#39;Access Denied&#39;);/*{$header_comment}*/?>\r\n$str";

  return $content;

 }

 /**

  * 开始解析相关模板标签

  * @param $content 模板内容

  */

 private function parse($content) {

  //foreach

  $content = $this->parse_foreach($content);

  //include

  $content = $this->parse_include($content);

  //if

  $content = $this->parse_if($content);

  //elseif

  $content = $this->parse_elseif($content);

  //模板标签公用部分

  $content = $this->parse_comm($content);

  //转为PHP代码

  $content = $this->parse_php($content);

  return $content;

 }

 /**

  * echo 如果默认直接<{$config[&#39;domain&#39;]}> 转成 <?php echo $config[&#39;domain&#39;]?>

  */

 private function parse_echo($content) {

 }

 /**

  * 转换为PHP

  * @param $content html 模板内容

  * @return html 替换好的HTML

  */

 private function parse_php($content){

  if(empty($content)) return false;

  $content = preg_replace("/".$this->template_tag_left."(.+?)".$this->template_tag_right."/is", "<?php $1 ?>", $content);

  return $content;

 }

 /**

  * if判断语句

  * <{if empty($zhang)}>

  * zhang

  * <{elseif empty($liang)}>

  * liang

  * <{else}>

  * zhangliang

  * <{/if}>

  */

 private function parse_if($content) {

  if(empty($content)) return false;

  //preg_match_all("/".$this->template_tag_left."if\s+(.*?)".$this->template_tag_right."/is", $content, $match);

  $match = $this->preg_match_all("if\s+(.*?)", $content);

  if(!isset($match[1]) || !is_array($match[1])) return $content;

  foreach($match[1] as $k => $v) {

   //$s = preg_split("/\s+/is", $v);

   //$s = array_filter($s);

   $content = str_replace($match[0][$k], "<?php if({$v}) { ?>", $content);

  }

  return $content;

 }

 private function parse_elseif($content) {

  if(empty($content)) return false;

  //preg_match_all("/".$this->template_tag_left."elseif\s+(.*?)".$this->template_tag_right."/is", $content, $match);

  $match = $this->preg_match_all("elseif\s+(.*?)", $content);

  if(!isset($match[1]) || !is_array($match[1])) return $content;

  foreach($match[1] as $k => $v) {

   //$s = preg_split("/\s+/is", $v);

   //$s = array_filter($s);

   $content = str_replace($match[0][$k], "<?php } elseif ({$v}) { ?>", $content);

  }

  return $content;

 }

 /**

  * 解析 include include标签不是实时更新的 当主体文件更新的时候 才更新标签内容,所以想include生效 请修改一下主体文件

  * 记录一下 有时间开发一个当DEBUG模式的时候 每次执行删除模版编译文件

  * 使用方法 <{include file="www.phpddt.com"}>

  * @param $content 模板内容

  * @return html

  */

 private function parse_include($content) {

  if(empty($content)) return false;

  //preg_match_all("/".$this->template_tag_left."include\s+(.*?)".$this->template_tag_right."/is", $content, $match);

  $match = $this->preg_match_all("include\s+(.*?)", $content);

  if(!isset($match[1]) || !is_array($match[1])) return $content;

  foreach($match[1] as $match_key => $match_value) {

   $a = preg_split("/\s+/is", $match_value);

   $new_tag = array();

   //分析元素

   foreach($a as $t) {

    $b = explode(&#39;=&#39;, $t);

    if(in_array($b[0], $this->tag_include)) {

     if(!empty($b[1])) {

      $new_tag[$b[0]] = str_replace("\"", "", $b[1]);

     } else {

      core::show_error(&#39;模板路径不存在!&#39;);

     }

    }

   }

   extract($new_tag);

   //查询模板文件

   foreach($this->conf[&#39;view_path&#39;] as $v){

    $conf_view_tpl = $v.$file;//include 模板文件

    if(is_file($conf_view_tpl)) {

     $c = $this->read_file($conf_view_tpl);

     $inc_file = str_replace($this->_tpl_suffix, &#39;&#39;, basename($file));

     $this->view_path_param = dirname($file).&#39;/&#39;;

     $compile_dirpath = $this->check_temp_compile();

     $include_file = $this->template_replace($c, $compile_dirpath, $inc_file);//解析

     break;

    } else {

     core::show_error(&#39;模板文件不存在,请仔细检查 文件:&#39;. $conf_view_tpl);

    }

   }

   $content = str_replace($match[0][$match_key], &#39;<?php include("&#39;.$include_file.&#39;")?>&#39;, $content);

  }

  return $content;

 }

 /**

  * 解析 foreach

  * 使用方法 <{foreach from=$lists item=value key=kk}>

  * @param $content 模板内容

  * @return html 解析后的内容

  */

 private function parse_foreach($content) {

  if(empty($content)) return false;

  //preg_match_all("/".$this->template_tag_left."foreach\s+(.*?)".$this->template_tag_right."/is", $content, $match);

  $match = $this->preg_match_all("foreach\s+(.*?)", $content);

  if(!isset($match[1]) || !is_array($match[1])) return $content;

  foreach($match[1] as $match_key => $value) {

   $split = preg_split("/\s+/is", $value);

   $split = array_filter($split);

   $new_tag = array();

   foreach($split as $v) {

    $a = explode("=", $v);

    if(in_array($a[0], $this->tag_foreach)) {//此处过滤标签 不存在过滤

     $new_tag[$a[0]] = $a[1];

    }

   }

   $key = &#39;&#39;;

   extract($new_tag);

   $key = ($key) ? &#39;$&#39;.$key.&#39; =>&#39; : &#39;&#39; ;

   $s = &#39;<?php foreach(&#39;.$from.&#39; as &#39;.$key.&#39; $&#39;.$item.&#39;) { ?>&#39;;

   $content = $this->str_replace($match[0][$match_key], $s, $content);

  }

  return $content;

 }

 /**

  * 匹配结束 字符串

  */

 private function parse_comm($content) {

  $search = array(

   "/".$this->template_tag_left."\/foreach".$this->template_tag_right."/is",

   "/".$this->template_tag_left."\/if".$this->template_tag_right."/is",

   "/".$this->template_tag_left."else".$this->template_tag_right."/is",

  );

  $replace = array(

   "<?php } ?>",

   "<?php } ?>",

   "<?php } else { ?>"

  );

  $content = preg_replace($search, $replace, $content);

  return $content;

 }

 /**

  * 检查编译目录 如果没有创建 则递归创建目录

  * @param string $path 文件完整路径

  * @return 模板内容

  */

 private function check_temp_compile() {

  //$paht = $this->template_c.

  $tpl_path = ($this->view_path_param) ? $this->view_path_param : $this->get_tpl_path() ;

  $all_tpl_apth = $this->template_c.$tpl_path;

  if(!is_dir($all_tpl_apth)) {

   $this->create_dir($tpl_path);

  }

  return $all_tpl_apth;

 }

 /**

  * 读文件

  * @param string $path 文件完整路径

  * @return 模板内容

  */

 private function read_file($path) {

  //$this->check_file_limits($path, &#39;r&#39;);

  if(($r = @fopen($path, &#39;r&#39;)) === false) {

   core::show_error(&#39;模版文件没有读取或执行权限,请检查!&#39;);

  }

  $content = fread($r, filesize($path));

  fclose($r);

  return $content;

 }

 /**

  * 写文件

  * @param string $filename 文件名

  * @param string $content 模板内容

  * @return 文件名

  */

 private function compile_file($filename, $content, $dir) {

  if(empty($filename)) core::show_error("{$filename} Creation failed");

  $content = $this->body_content($content);//对文件内容操作

  //echo &#39;开始编译了=====&#39;;

  $f = $dir.$filename.$this->tpl_compile_suffix;

  //$this->check_file_limits($f, &#39;w&#39;);

  if(($fp = @fopen($f, &#39;wb&#39;)) === false) {

   core::show_error($f.&#39;<br/>编译文件失败,请检查文件权限.&#39;);

  }

  //开启flock

  flock($fp, LOCK_EX + LOCK_NB);

  fwrite($fp, $content, strlen($content));

  flock($fp, LOCK_UN + LOCK_NB);

  fclose($fp);

  return $f;

 }

 /**

  * 这个检查文件权限函数 暂时废弃了

  * @param [$path] [路径]

  * @param [status] [w=write, r=read]

  */

 public function check_file_limits($path , $status = &#39;rw&#39;) {

  clearstatcache();

  if(!is_writable($path) && $status == &#39;w&#39;) {

   core::show_error("{$path}<br/>没有写入权限,请检查.");

  } elseif(!is_readable($path) && $status == &#39;r&#39;) {

   core::show_error("{$path}<br/>没有读取权限,请检查.");

  } elseif($status == &#39;rw&#39;) {//check wirte and read

   if(!is_writable($path) || !is_readable($path)) {

    core::show_error("{$path}<br/>没有写入或读取权限,请检查");

   }

  }

 }

 /**

  * 读取编译后模板的第一行 并分析成数组

  * @param string $filepath 文件路径

  * @param number $line  行数

  * @return 返回指定行数的字符串

  */

 /*

 private function get_compile_header($filepath, $line = 0) {

  if(($file_arr = @file($filepath)) === false) {

   core::show_error($filepath.&#39;<br/>读取文件失败,请检查文件权限!&#39;);

  }

  return $file_arr[0];

 }

 */

 /**

  * 分析头部注释的日期

  * @param string $cotnent 编译文件头部第一行

  * @return 返回上一次日期

  */

 /*

 private function get_compile_header_comment($content) {

  preg_match("/\/\*(.*?)\*\//", $content, $match);

  if(!isset($match[1]) || empty($match[1])) core::show_error(&#39;编译错误!&#39;);

  $arr = explode(&#39;|&#39;, $match[1]);

  $arr_date = explode(&#39;##&#39;, $arr[0]);

  return $arr_date[1];

 }

 */

 /**

  * 获取模板完整路径 并返回已存在文件

  * @param string $filename 文件名

  * @param string $view_path 模板路径

  * @return

  */

 private function get_tpl($filename, $view_path) {

  empty($filename) && $filename = $this->tpl_name;

  //遍历模板路径

  foreach($this->conf[&#39;view_path&#39;] as $path) {

   if($view_path) {//直接从tpl跟目录找文件

    $tpl_path = $path.$view_path;

    $view_file_path = $tpl_path.$filename.$this->_tpl_suffix;

   } else {//根据目录,控制器,方法开始找文件

    $view_file_path = ($tpl_path = $this->get_tpl_path($path)) ? $tpl_path.$filename.$this->_tpl_suffix : exit(0);

   }

   if(is_file($view_file_path)) {

    //向指针传送模板路径和模板名称

    $this->template_path = $tpl_path;//

    $this->template_name = $filename.$this->_tpl_suffix;

    return true;

   } else {

    core::show_error($filename.$this->_tpl_suffix.&#39;模板不存在&#39;);

   }

  }

 }

 /**

  * 获取模板路径

  * @param string $path 主目录

  * @return URL D和M的拼接路径

  */

 private function get_tpl_path($path = &#39;&#39;) {

  core::get_directory_name() && $path_arr[0] = core::get_directory_name();

  core::get_controller_name() && $path_arr[1] = core::get_controller_name();

  (is_array($path_arr)) ? $newpath = implode(&#39;/&#39;, $path_arr) : core::show_error(&#39;获取模板路径失败!&#39;) ;

  return $path.$newpath.&#39;/&#39;;

 }

 /**

  * 创建目录

  * @param string $path 目录

  * @return

  */

 private function create_dir($path, $mode = 0777){

  if(is_dir($path)) return false;

  $dir_arr = explode(&#39;/&#39;, $path);

  $dir_arr = array_filter($dir_arr);

  $allpath = &#39;&#39;;

  $newdir = $this->template_c;

  foreach($dir_arr as $dir) {

   $allpath = $newdir.&#39;/&#39;.$dir;

   if(!is_dir($allpath)) {

    $newdir = $allpath;

    if(!@mkdir($allpath, $mode)) {

     core::show_error( $allpath.&#39;<br/>创建目录失败,请检查是否有可都写权限!&#39;);

    }

    chmod($allpath, $mode);

   } else {

    $newdir = $allpath;

   }

  }

  return true;

 }

 public function __destruct(){

  $this->vars = null;

  $this->view_path_param = null;

 }

}

Copier après la connexion

总结:以上就是本篇文的全部内容,希望能对大家的学习有所帮助。

相关推荐:

PHP+Mysql+jQuery实现的查询和列表框选择

PHP通过禁止IP频繁访问防止网站被防攻击

php实现数字格式化,数字每三位加逗号的功能函数

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers numéros
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal