PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/simplate.cpp

https://github.com/yunoka/simplate
C++ | 2330 lines | 1710 code | 215 blank | 405 comment | 336 complexity | e64a10aa48784859a9f0bfcfa983347e MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 4/5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) Kazuhiro IIzuka All rights reserved. |
  6. +----------------------------------------------------------------------+
  7. | This source file is the BSD License, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://static.aimy.jp/license.txt |
  11. +----------------------------------------------------------------------+
  12. | Author: Kazuhiro IIzuka |
  13. +----------------------------------------------------------------------+
  14. */
  15. /* $Id$ */
  16. /**
  17. * @file simplate.cpp
  18. * @brief Simplate class implementation
  19. * @author Kazuhiro IIzuka
  20. * @author Shimizu
  21. * @version $Id$
  22. * Copyright (C) Kazuhiro IIzuka
  23. */
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #ifdef PHP_WIN32
  28. #include "config.w32.h"
  29. #endif // PHP_WIN32
  30. // C++ header...
  31. #include <iostream>
  32. #include <ctime>
  33. #include <string>
  34. #include <vector>
  35. #include <set>
  36. using std::cout;
  37. using std::cerr;
  38. using std::endl;
  39. using std::string;
  40. using std::vector;
  41. using std::set;
  42. extern "C" {
  43. #include "php.h"
  44. #include "php_ini.h"
  45. #include "ext/standard/info.h"
  46. #include "ext/standard/php_var.h" // var_dump
  47. #ifdef PHP_WIN32
  48. #include "win32/flock.h"
  49. #else
  50. #include "ext/standard/flock_compat.h"
  51. #endif // PHP_WIN32
  52. }
  53. #include "php_simplate.h"
  54. //Debug
  55. #ifdef SIMPLATE_DEBUG
  56. FILE *fp;
  57. char msg[1024];
  58. #ifdef PHP_WIN32
  59. #define DEBUG_PRINTF(format, ...) \
  60. sprintf(msg, format, __VA_ARGS__); \
  61. fp = fopen("debug.log", "a"); \
  62. if (NULL != fp) fprintf(fp, "%s(%d): %s\n", __FUNCTION__, __LINE__, msg); \
  63. fclose(fp);
  64. #else
  65. #define DEBUG_PRINTF(format, ...) \
  66. sprintf(msg, format, __VA_ARGS__); \
  67. fp = fopen("debug.log", "a"); \
  68. if (NULL != fp) fprintf(fp, "%s(%d): %s\n", __func__, __LINE__, msg); \
  69. fclose(fp);
  70. #endif // PHP_WIN32
  71. #else
  72. #define DEBUG_PRINTF(format, ...)
  73. #endif // SIMPLATE_DEBUG
  74. //#define PHP5.3 or more
  75. #ifndef Z_REFCOUNT_P
  76. #define Z_REFCOUNT_PP(ppz) ((*(ppz))->refcount)
  77. #define Z_SET_REFCOUNT_PP(ppz, rc) ((*(ppz))->refcount = rc)
  78. #define Z_ADDREF_PP(ppz) (++(*(ppz))->refcount)
  79. #define Z_DELREF_PP(ppz) (--(*(ppz))->refcount)
  80. #define Z_ISREF_PP(ppz) ((*(ppz))->is_ref)
  81. #define Z_SET_ISREF_PP(ppz) ((*(ppz))->is_ref = 1)
  82. #define Z_UNSET_ISREF_PP(ppz) ((*(ppz))->is_ref = 0)
  83. #define Z_SET_ISREF_TO_PP(ppz, isref) ((*(ppz))->is_ref = isref)
  84. #define Z_REFCOUNT_P(pz) ((pz)->refcount)
  85. #define Z_SET_REFCOUNT_P(z, rc) ((pz)->refcount = rc)
  86. #define Z_ADDREF_P(pz) (++(pz)->refcount)
  87. #define Z_DELREF_P(pz) (--(pz)->refcount)
  88. #define Z_ISREF_P(pz) ((pz)->is_ref)
  89. #define Z_SET_ISREF_P(pz) ((pz)->is_ref = 1)
  90. #define Z_UNSET_ISREF_P(pz) ((pz)->is_ref = 0)
  91. #define Z_SET_ISREF_TO_P(z, isref) ((pz)->is_ref = isref)
  92. #define Z_REFCOUNT(z) ((z).refcount)
  93. #define Z_SET_REFCOUNT(z, rc) ((z).refcount = rc)
  94. #define Z_ADDREF(z) (++(z).refcount)
  95. #define Z_DELREF(z) (--(z).refcount)
  96. #define Z_ISREF(z) ((z).is_ref)
  97. #define Z_SET_ISREF(z) ((z).is_ref = 1)
  98. #define Z_UNSET_ISREF(z) ((z).is_ref = 0)
  99. #define Z_SET_ISREF_TO(z, isref) ((z).is_ref = isref)
  100. #endif
  101. //#define USE_ZEND_EXECUTE
  102. #define SET_ZVAL_STRING(z, s) \
  103. INIT_PZVAL(&z); \
  104. Z_STRVAL(z) = estrndup(s, strlen(s)); \
  105. Z_STRLEN(z) = strlen(s); \
  106. Z_TYPE(z) = IS_STRING;
  107. /* If you declare any globals in php_simplate.h uncomment this: */
  108. ZEND_DECLARE_MODULE_GLOBALS(simplate)
  109. /* True global resources - no need for thread safety here */
  110. static int le_simplate;
  111. // default parameters
  112. #define DEFAULT_TEMPLATE_DIR "template"
  113. #define DEFAULT_COMPILE_DIR "template_c"
  114. #define DEFAULT_CACHE_DIR "cache"
  115. #define DEFAULT_LEFT_DELIMITER "<{"
  116. #define DEFAULT_RIGHT_DELIMITER "}>"
  117. #define DEFAULT_COMPILE_CHECK true
  118. #define DEFAULT_FORCE_COMPILE false
  119. #define DEFAULT_LAZY_CHECK false
  120. #define DEFAULT_CACHE_LIFETIME 3600
  121. #define DEFAULT_CACHING 0 // 0: no caching
  122. // 1: use class cache_lifetime value
  123. // 2: use cache_lifetime in cache file
  124. // fetch mode
  125. #define SIMPLATE_FETCH 0
  126. #define SIMPLATE_DISPLAY 1
  127. // parameter names
  128. #define TEMPLATE_DIR "template_dir"
  129. #define COMPILE_DIR "compile_dir"
  130. #define CACHE_DIR "cache_dir"
  131. #define LEFT_DELIMITER "left_delimiter"
  132. #define RIGHT_DELIMITER "right_delimiter"
  133. #define COMPILE_CHECK "compile_check"
  134. #define FORCE_COMPILE "force_compile"
  135. #define LAZY_CHECK "lazy_check"
  136. #define VERSION "0.4.2.y_1"
  137. #define CACHE_LIFETIME "cache_lifetime"
  138. #define CACHING "caching"
  139. // class entry pointer
  140. static zend_class_entry *simplate_entry_ptr;
  141. static zend_function_entry php_simplate_functions[] = {
  142. #ifdef ZEND_ENGINE_2
  143. ZEND_ME(simplate, __construct, NULL, ZEND_ACC_PUBLIC)
  144. ZEND_ME(simplate, assign, NULL, ZEND_ACC_PUBLIC)
  145. ZEND_ME(simplate, fetch, NULL, ZEND_ACC_PUBLIC)
  146. ZEND_ME(simplate, display, NULL, ZEND_ACC_PUBLIC)
  147. ZEND_ME(simplate, clear_cache, NULL, ZEND_ACC_PUBLIC)
  148. ZEND_ME(simplate, register_prefilter, NULL, ZEND_ACC_PUBLIC)
  149. ZEND_ME(simplate, register_postfilter, NULL, ZEND_ACC_PUBLIC)
  150. #else
  151. PHP_FALIAS(simplate, simplate_init, NULL)
  152. PHP_FALIAS(assign, simplate_assign, NULL)
  153. PHP_FALIAS(fetch, simplate_fetch, NULL)
  154. PHP_FALIAS(display, simplate_display, NULL)
  155. PHP_FALIAS(clear_cache, simplate_clear_cache, NULL)
  156. PHP_FALIAS(register_prefilter, simplate_register_prefilter, NULL)
  157. PHP_FALIAS(register_postfilter, simplate_register_postfilter, NULL)
  158. #endif // ZEND_ENGINE_2
  159. {NULL, NULL, NULL}
  160. };
  161. /* {{{ simplate_functions[]
  162. *
  163. * Every user visible function must have an entry in simplate_functions[].
  164. */
  165. function_entry simplate_functions[] = {
  166. {NULL, NULL, NULL} /* Must be the last line in simplate_functions[] */
  167. };
  168. /* }}} */
  169. /* {{{ simplate_module_entry
  170. */
  171. zend_module_entry simplate_module_entry = {
  172. #if ZEND_MODULE_API_NO >= 20010901
  173. STANDARD_MODULE_HEADER,
  174. #endif
  175. "simplate",
  176. simplate_functions,
  177. PHP_MINIT(simplate),
  178. PHP_MSHUTDOWN(simplate),
  179. PHP_RINIT(simplate), /* Replace with NULL if there's nothing to do at request start */
  180. PHP_RSHUTDOWN(simplate), /* Replace with NULL if there's nothing to do at request end */
  181. PHP_MINFO(simplate),
  182. #if ZEND_MODULE_API_NO >= 20010901
  183. VERSION,
  184. #endif
  185. STANDARD_MODULE_PROPERTIES
  186. };
  187. /* }}} */
  188. #ifdef COMPILE_DL_SIMPLATE
  189. BEGIN_EXTERN_C()
  190. ZEND_GET_MODULE(simplate)
  191. END_EXTERN_C()
  192. #endif
  193. /* {{{ PHP_INI
  194. */
  195. /* Remove comments and fill if you need to have entries in php.ini
  196. PHP_INI_BEGIN()
  197. STD_PHP_INI_ENTRY("simplate.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_simplate_globals, simplate_globals)
  198. STD_PHP_INI_ENTRY("simplate.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_simplate_globals, simplate_globals)
  199. PHP_INI_END()
  200. */
  201. /* }}} */
  202. /* {{{ php_simplate_init_globals
  203. */
  204. /* Uncomment this function if you have INI entries */
  205. static void php_simplate_init_globals(
  206. zend_simplate_globals *simplate_globals TSRMLS_DC
  207. )
  208. {
  209. simplate_globals->global_string;
  210. }
  211. /* }}} */
  212. #if 0
  213. // create custom objects
  214. typedef struct{
  215. string fetch_buffer;
  216. zend_object zo;
  217. }simplate_object;
  218. static void simplate_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
  219. {
  220. zend_objects_destroy_object(object, handle TSRMLS_CC);
  221. }
  222. static void simplate_objects_clone(void *object, void **object_clone TSRMLS_DC)
  223. {
  224. simplate_object *intern = (simplate_object*)object;
  225. simplate_object **intern_clone = (simplate_object**)object_clone;
  226. *intern_clone = emalloc(sizeof(simplate_object));
  227. (*intern_object)->zo.ce = intern->zo.ce;
  228. (*intern_object)->zo.in_get = 0;
  229. (*intern_object)->zo.in_set = 0;
  230. ALLOC_HASHTABLE((*intern_clone)->zo.properties);
  231. (*intern_clone)->fetch_buffer=
  232. }
  233. #endif // 0
  234. /* {{{ Returns full path of the specified filename.
  235. *
  236. * ex)
  237. * filename = "foo.tpl"
  238. * => template_dir + DEFAULT_SLASH + "foo.tpl"
  239. * filename = "$variable"
  240. * => template_dir + DEFAULT_SLASH + $variable
  241. * filename = "$variable.tpl"
  242. * => template_dir + DEFAULT_SLASH + $variable ".tpl"
  243. * filename = "/path/to/foo.tpl"
  244. * => "/path/to/foo.tpl"
  245. *
  246. * @param zval *obj instance of this class
  247. * @param string template_dir template directory
  248. * @param string filename filename
  249. *
  250. * @return string full path of the specified filename
  251. */
  252. static string get_include_filename(
  253. zval *obj,
  254. string template_dir,
  255. string filename TSRMLS_DC
  256. )
  257. {
  258. string included_filename; // return value
  259. // search "$" (use variable or don't use variable)
  260. size_t pos = filename.find("$");
  261. if (pos != string::npos) {
  262. // use variable
  263. string include_variable = "";
  264. // From "$" to "." or "/" string is cut out.
  265. // $variable => $variable
  266. // $variable.tpl => $variable
  267. include_variable = filename.substr(pos);
  268. size_t dot_pos = include_variable.find(".");
  269. size_t dot_pos2 = include_variable.find("/");
  270. if (dot_pos > dot_pos2 || (dot_pos == string::npos && dot_pos2 != string::npos )){
  271. dot_pos = dot_pos2;
  272. }
  273. if (dot_pos != string::npos) {
  274. include_variable = include_variable.substr(0, dot_pos);
  275. }
  276. DEBUG_PRINTF("[B2]include_variable = (%s)", const_cast<char*>(include_variable.c_str()));
  277. // delete "$"
  278. // $variable => variable
  279. include_variable.erase(0, 1);
  280. #ifdef ZEND_ENGINE_2
  281. zval *_tpl_vars = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>("_tpl_vars"), strlen("_tpl_vars"), 1 TSRMLS_CC);
  282. #else
  283. zval *_tpl_vars;
  284. if (zend_hash_find(Z_OBJPROP_P(obj), const_cast<char*>("_tpl_vars"), sizeof("_tpl_vars"), (void**)&_tpl_vars) != SUCCESS) {
  285. zend_error(E_ERROR, "_tpl_vars not found from zend_hash.");
  286. }
  287. #endif // ZEND_ENGINE_2
  288. zval **zinclude_file;
  289. string new_filename;
  290. if (zend_hash_find(Z_ARRVAL_P(_tpl_vars), const_cast<char*>(include_variable.c_str()), include_variable.length() + 1, (void**)&zinclude_file) == SUCCESS
  291. && Z_TYPE_PP(zinclude_file) == IS_STRING
  292. ) {
  293. DEBUG_PRINTF("(%s) -> (%s)", const_cast<char*>(include_variable.c_str()), Z_STRVAL_PP(zinclude_file));
  294. new_filename = filename.replace(filename.find("$"), include_variable.length() + 1, Z_STRVAL_PP(zinclude_file));
  295. } else {
  296. zend_error(E_ERROR, "include file variable = ($%s) is not assigned.", include_variable.c_str());
  297. }
  298. if (new_filename[0] == DEFAULT_SLASH) {
  299. // use variable
  300. // $variable = "/path/to/file.tpl"
  301. included_filename = new_filename;
  302. } else {
  303. included_filename = template_dir + DEFAULT_SLASH + new_filename;
  304. }
  305. } else if (filename[0] == DEFAULT_SLASH) {
  306. // don't use variable
  307. // <{include file="/path/to/file.tpl"}>
  308. included_filename = filename;
  309. } else {
  310. // don't use variable
  311. // <{include file="file.tpl"}>
  312. included_filename = template_dir + DEFAULT_SLASH + filename;
  313. }
  314. return included_filename;
  315. }
  316. /* }}} */
  317. /* {{{ Read contents from the specified filename, and replaces xml start-end tags.
  318. *
  319. * <?xml
  320. * => <?php echo'<?xml'; ?>
  321. * ?>
  322. * => <?php echo'?>'; ?>
  323. *
  324. * @param const char *filename filename
  325. *
  326. * @return string contents
  327. */
  328. static string _readfile(
  329. const char *filename TSRMLS_DC
  330. )
  331. {
  332. string line;
  333. // check open_basedir restriction in php.ini
  334. if (php_check_open_basedir(filename TSRMLS_CC)) {
  335. return "";
  336. }
  337. #ifdef PHP_WIN32
  338. php_stream *strm;
  339. char *buffer = NULL;
  340. size_t buffer_length = 0;
  341. strm = php_stream_open_wrapper(const_cast<char*>(filename), "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
  342. if (!strm) {
  343. zend_error(E_ERROR, "Cannot read such file or directory:%s", const_cast<char*>(filename));
  344. return "";
  345. }
  346. buffer_length = php_stream_copy_to_mem(strm, &buffer, PHP_STREAM_COPY_ALL, 0);
  347. php_stream_close(strm);
  348. if (buffer_length < 0) {
  349. zend_error(E_ERROR, "Cannot read such file or directory:%s", const_cast<char*>(filename));
  350. efree(buffer);
  351. return "";
  352. }
  353. line = buffer;
  354. efree(buffer);
  355. #else // PHP_WIN32
  356. FILE *fp;
  357. char buf[8192];
  358. fp = VCWD_FOPEN(filename, "rb");
  359. if (fp == NULL) {
  360. zend_error(E_ERROR, "Cannot read such file or directory:%s", const_cast<char*>(filename));
  361. return "";
  362. }
  363. while (fgets(buf, sizeof(buf), fp) != 0) {
  364. line += buf;
  365. }
  366. fclose(fp);
  367. #endif // PHP_WIN32
  368. // replace xml tag
  369. // <?xml => <?php echo'<?xml'; ?>
  370. // ?> => <?php echo'?>'; ?>
  371. const char *xml_tag = "<?xml";
  372. size_t pos = 0;
  373. string new_tag;
  374. while ((pos = line.find(xml_tag, pos)) != string::npos) {
  375. new_tag = "<?php echo \'";
  376. new_tag += xml_tag;
  377. new_tag += "\'; ?>";
  378. line.replace(pos, strlen(xml_tag), new_tag);
  379. pos += new_tag.length();
  380. new_tag = "<?php echo \'?>\'; ?>";
  381. pos = line.find("?>", pos);
  382. line.replace(pos, 2, new_tag);
  383. pos += new_tag.length();
  384. }
  385. return line;
  386. }
  387. /* }}} */
  388. /* {{{ Trims the specified string.
  389. *
  390. * @param const char *s string
  391. *
  392. * @return string trim string
  393. */
  394. static string trim(
  395. const char *s
  396. )
  397. {
  398. string new_str(s);
  399. // trim from left-side
  400. while (new_str[0] == ' ') {
  401. new_str.erase(0, 1);
  402. }
  403. // trim from right-side
  404. while (new_str[new_str.length() - 1] == ' ') {
  405. new_str.erase(new_str.length() - 1, 1);
  406. }
  407. return new_str;
  408. }
  409. /* }}} */
  410. /* {{{ Splits the specified string with the separator. The results is stored in the specified vector.
  411. *
  412. * @param const char *s string
  413. * @param vector<string> &e vector
  414. * @param char separator separator (= ".")
  415. *
  416. * @return void
  417. */
  418. static void split_element(
  419. const char *s,
  420. vector<string> &e,
  421. char separator = '.'
  422. )
  423. {
  424. string str(s);
  425. size_t spos = 0, epos = 0;
  426. e.push_back(str.substr(spos, str.find(separator, spos)));
  427. while ((epos = str.find(separator, epos)) != string::npos) {
  428. e.push_back(str.substr(epos + 1, str.find(separator, epos + 1) - epos - 1));
  429. epos++;
  430. }
  431. }
  432. /* }}} */
  433. /* {{{ Looks for [a-z0-9_] consecutive string from i position of the specified variable. The result is stored in the specified new_variable.
  434. *
  435. * @param const char *variable
  436. * @param int i
  437. * @param string &new_variable
  438. *
  439. * @return int length of [a-z0-9_] consecutive string
  440. */
  441. static int get_identifier(
  442. const char *variable,
  443. int i,
  444. string &new_variable
  445. )
  446. {
  447. int j = 0;
  448. while (isalnum(variable[i]) || variable[i] == '_') {
  449. new_variable += variable[i];
  450. i++;
  451. j++;
  452. }
  453. return j;
  454. }
  455. /* }}} */
  456. /* {{{ Parses the specified variable.
  457. *
  458. * array pattern
  459. * $hoge[i] => _tpl_vars['hoge'][$i]
  460. * $hoge[i].foo.bar => _tpl_vars['hoge'][$i]['foo']['bar']
  461. * $hoge[i].huga[j].foo => _tpl_vars['hoge'][$i]['huga'][$j]['foo']
  462. * $hoge[i]->huga[j]->foo => _tpl_vars['hoge'][$i]->huga[$j]->foo
  463. *
  464. * section pattern
  465. * $simplate.section.i.index => $i
  466. * $simplate.section.ary.count => count($this->_tpl_vars['ary'])
  467. * $simplate.section.i.first => $this->_section['i']['first']
  468. * $simplate.section.i.last => $this->_section['i']['last']
  469. *
  470. * arrow pattern
  471. * $ary10.foo->bar => $this->_tpl_vars['ary10']['foo']->bar
  472. * $foo->bar => $this->_tpl_vars['foo']->bar
  473. *
  474. * normal pattern
  475. * $key => $this->_tpl_vars['key']
  476. *
  477. * @param const char *variable variable string
  478. *
  479. * @return string parsed variable string
  480. */
  481. static string parse_variable(
  482. const char *variable
  483. )
  484. {
  485. string new_variable = "";
  486. DEBUG_PRINTF("variable = (%s)", variable);
  487. if (variable[0] != '$' || strncmp(variable, "$this", 5) == 0) {
  488. new_variable = variable;
  489. DEBUG_PRINTF("new_variable = (%s)", const_cast<char*>(new_variable.c_str()));
  490. return new_variable;
  491. }
  492. if (strstr(variable, "[")) {
  493. DEBUG_PRINTF("%s", "array pattern");
  494. // $hoge[i] => _tpl_vars['hoge'][$i]
  495. // $hoge[i].foo.bar => _tpl_vars['hoge'][$i]['foo']['bar']
  496. // $hoge[i].huga[j].foo => _tpl_vars['hoge'][$i]['huga'][$j]['foo']
  497. // $hoge[i]->huga[j]->foo => _tpl_vars['hoge'][$i]->huga[$j]->foo
  498. int i = 0;
  499. while (variable[i]) {
  500. if (variable[i] == '$') {
  501. new_variable += "$this->_tpl_vars['";
  502. i++;
  503. i += get_identifier(variable, i, new_variable);
  504. new_variable += "']";
  505. } else if (variable[i] == '.') {
  506. new_variable += "['";
  507. i++;
  508. i += get_identifier(variable, i, new_variable);
  509. new_variable += "']";
  510. } else if (variable[i] == '[') {
  511. new_variable += "[$";
  512. i++;
  513. i += get_identifier(variable, i, new_variable);
  514. new_variable += "]";
  515. i++;
  516. } else if (i > 0 && variable[i] == '>' && variable[i - 1] == '-') {
  517. new_variable += "->";
  518. i++;
  519. i += get_identifier(variable, i, new_variable);
  520. } else {
  521. i++;
  522. }
  523. }
  524. } else if (strstr(variable, ".")) {
  525. DEBUG_PRINTF("%s", "section pattern");
  526. vector<string> elements;
  527. split_element(variable + 1, elements);
  528. #ifdef SIMPLATE_DEBUG
  529. for (vector<string>::iterator i = elements.begin(); i != elements.end(); ++i) {
  530. DEBUG_PRINTF("vector(i) = (%s)", const_cast<char*>((*i).c_str()));
  531. }
  532. #endif // SIMPLATE_DEBUG
  533. // $simplate.section.i.index => $i
  534. // $simplate.section.ary.count => count($this->_tpl_vars['ary'])
  535. // $simplate.section.i.first => $this->_section['i']['first']
  536. // $simplate.section.i.last => $this->_section['i']['last']
  537. // $ary10.foo->bar => $this->_tpl_vars["ary10"]["foo"]->bar
  538. if (elements.size() == 4 && elements[1] == "section" && elements[3] == "index") {
  539. new_variable += "$";
  540. new_variable += elements[2];
  541. } else if (elements.size() == 4 && elements[1] == "section" && elements[3] == "count") {
  542. new_variable += "count($this->_tpl_vars['";
  543. new_variable += elements[2];
  544. new_variable += "'])";
  545. } else if (elements.size() == 4 && elements[1] == "section" && (elements[3] == "first"|| elements[3] == "last")) {
  546. new_variable += "$this->_section['";
  547. new_variable += elements[2];
  548. new_variable += "']['";
  549. new_variable += elements[3];
  550. new_variable += "']";
  551. } else {
  552. new_variable += "$this->_tpl_vars";
  553. for (vector<string>::iterator i = elements.begin(); i != elements.end(); ++i) {
  554. new_variable += "['";
  555. size_t pos = 0;
  556. if ((pos = (*i).find("->")) != string::npos) {
  557. new_variable += (*i).substr(0, pos);
  558. new_variable += "']";
  559. new_variable += (*i).substr(pos);
  560. } else {
  561. new_variable += *i;
  562. new_variable += "']";
  563. }
  564. }
  565. }
  566. } else if (strstr(variable, "->")) {
  567. DEBUG_PRINTF("%s", "arrow pattern");
  568. // $foo->bar => $this->_tpl_vars['foo']->bar
  569. string temp = variable;
  570. new_variable += "$this->_tpl_vars['";
  571. new_variable += temp.substr(1, temp.find("->") - 1);
  572. new_variable += "']";
  573. new_variable += temp.substr(temp.find("->"));
  574. } else {
  575. DEBUG_PRINTF("%s", "normal pattern");
  576. // $key => $this->_tpl_vars['key']
  577. new_variable += "$this->_tpl_vars['";
  578. new_variable += (variable + 1);
  579. new_variable += "']";
  580. }
  581. DEBUG_PRINTF("new_variable = (%s)", const_cast<char*>(new_variable.c_str()));
  582. return new_variable;
  583. }
  584. /* }}} */
  585. /* {{{ Returns the value of the simplate tag's attribute to which specified key is coinciding
  586. *
  587. * @param const char *s simplate tag
  588. * @param const char *key attribute name
  589. *
  590. * @return string the value of simplate tag's attribute
  591. */
  592. static string get_element(
  593. const char *s,
  594. const char *key
  595. )
  596. {
  597. int i;
  598. string value = "";
  599. string key_name;
  600. DEBUG_PRINTF("s = (%s), key = (%s)", s, key);
  601. while ((s = strstr(s, key)) != NULL) {
  602. i = 0;
  603. key_name = "";
  604. while (isalnum(*(s + i))) {
  605. key_name += *(s + i);
  606. i++;
  607. }
  608. if (strcmp(key_name.c_str(), key) == 0) {
  609. while (*(s + i) != '=') {
  610. i++;
  611. }
  612. i++;
  613. while (*(s + i) == '\'' || *(s + i) == '"' || *(s + i) == ' ') {
  614. i++;
  615. }
  616. while (*(s + i) != '\'' && *(s + i) != '"' && *(s + i) != ' ' && *(s + i)) {
  617. value += *(s + i);
  618. i++;
  619. }
  620. break;
  621. }
  622. s++;
  623. }
  624. DEBUG_PRINTF("value = (%s)", const_cast<char*>(value.c_str()));
  625. return value;
  626. }
  627. /* }}} */
  628. /* {{{ Returns true if the specified file has compiled.
  629. *
  630. * @param zval *obj instance of this
  631. * @param const char *template_dir template directory
  632. * @param const char *compile_dir compile direcotry
  633. * @param const char *filename target file
  634. * @param const char *left_delimiter left-delimiter
  635. * @param const char *right_delimiter right-delimiter
  636. *
  637. * @return boolean returns true if the specified file has compiled
  638. */
  639. static inline bool _is_compiled(
  640. zval *obj,
  641. const char *template_dir,
  642. const char *compile_dir,
  643. const char *filename,
  644. const char *left_delimiter,
  645. const char *right_delimiter TSRMLS_DC
  646. )
  647. {
  648. string error;
  649. unsigned char compile_check = DEFAULT_COMPILE_CHECK;
  650. unsigned char force_compile = 0;
  651. unsigned char lazy_check = 0;
  652. #ifdef ZEND_ENGINE_2
  653. zval *temp_zval;
  654. // Reads property COMPILE_CHECK
  655. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(COMPILE_CHECK), strlen(COMPILE_CHECK), 1 TSRMLS_CC);
  656. if (Z_TYPE_P(temp_zval) == IS_BOOL) {
  657. compile_check = Z_BVAL_P(temp_zval);
  658. }
  659. // Reads property FORCE_COMPILE
  660. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(FORCE_COMPILE), strlen(FORCE_COMPILE), 1 TSRMLS_CC);
  661. if (Z_TYPE_P(temp_zval) == IS_BOOL) {
  662. force_compile = Z_BVAL_P(temp_zval);
  663. }
  664. // Reads property LAZY_CHECK
  665. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(LAZY_CHECK), strlen(LAZY_CHECK), 1 TSRMLS_CC);
  666. if (Z_TYPE_P(temp_zval) == IS_BOOL) {
  667. lazy_check = Z_BVAL_P(temp_zval);
  668. }
  669. #else
  670. zval **temp;
  671. // Reads property COMPILE_CHECK
  672. if (zend_hash_find(Z_OBJPROP_P(obj), const_cast<char*>(COMPILE_CHECK), sizeof(COMPILE_CHECK), (void**)&temp) == SUCCESS) {
  673. if (Z_TYPE_PP(temp) == IS_BOOL) {
  674. compile_check = Z_BVAL_PP(temp);
  675. }
  676. }
  677. // Reads property FORCE_COMPILE
  678. if (zend_hash_find(Z_OBJPROP_P(obj), const_cast<char*>(FORCE_COMPILE), sizeof(FORCE_COMPILE), (void**)&temp) == SUCCESS) {
  679. if (Z_TYPE_PP(temp) == IS_BOOL) {
  680. force_compile = Z_BVAL_PP(temp);
  681. }
  682. }
  683. // Reads property LAZY_CHECK
  684. if (zend_hash_find(Z_OBJPROP_P(obj), const_cast<char*>(LAZY_CHECK), sizeof(LAZY_CHECK), (void**)&temp) == SUCCESS) {
  685. if (Z_TYPE_PP(temp) == IS_BOOL) {
  686. lazy_check = Z_BVAL_PP(temp);
  687. }
  688. }
  689. #endif // ZEND_ENGINE_2
  690. DEBUG_PRINTF("compile_check = (%d)", compile_check);
  691. DEBUG_PRINTF("force_compile = (%d)", force_compile);
  692. DEBUG_PRINTF("lazy_check = (%d)", lazy_check);
  693. // Returns false if force_compile is true.
  694. if (force_compile) {
  695. return false;
  696. }
  697. // Has the compiled file already exists?
  698. struct stat cs;
  699. string full_compile_filename(compile_dir);
  700. full_compile_filename += DEFAULT_SLASH;
  701. full_compile_filename += filename;
  702. if (VCWD_STAT(full_compile_filename.c_str(), &cs) == -1) {
  703. // the compiled file doesn't exists.
  704. return false;
  705. }
  706. // Returns true if compile_check is false.
  707. if (!compile_check) {
  708. return true;
  709. }
  710. // compare the file and compiled file.
  711. struct stat ts;
  712. string full_template_filename(template_dir);
  713. full_template_filename += DEFAULT_SLASH;
  714. full_template_filename += filename;
  715. if (VCWD_STAT(full_template_filename.c_str(), &ts) == -1) {
  716. zend_error(E_ERROR, "cannot stat:%s", full_template_filename.c_str());
  717. return false;
  718. }
  719. DEBUG_PRINTF("template_filename = (%s)", full_template_filename.c_str());
  720. DEBUG_PRINTF("compiled_filename = (%s)", full_compile_filename.c_str());
  721. DEBUG_PRINTF("cs.st_mtime = (%ld), ts.st_mtime = (%ld)", cs.st_mtime, ts.st_mtime);
  722. // Returns false if template file is newer than compiled file.
  723. if (cs.st_mtime < ts.st_mtime) {
  724. return false;
  725. } else {
  726. // Not checks the included file if lazy check is true.
  727. if (!lazy_check) {
  728. size_t pos = 0;
  729. size_t tag_start_pos, tag_end_pos;
  730. size_t element_start_pos, element_end_pos;
  731. string item;
  732. string file_content = _readfile(full_template_filename.c_str() TSRMLS_CC);
  733. // Reads include tags.
  734. while ((pos = file_content.find(left_delimiter, pos)) != string::npos) {
  735. tag_start_pos = pos;
  736. element_start_pos = tag_start_pos + strlen(left_delimiter);
  737. element_end_pos = file_content.find(right_delimiter, tag_start_pos);
  738. if (element_end_pos == string::npos) {
  739. zend_error(E_ERROR, "No closed delimiter:`%s' in %s", right_delimiter, full_template_filename.c_str());
  740. return false;
  741. }
  742. tag_end_pos = element_end_pos + strlen(right_delimiter);
  743. // Reads between left_delimiter and right_delimiter.
  744. item.assign(file_content, element_start_pos, element_end_pos - element_start_pos);
  745. item = trim(item.c_str());
  746. // Finds include tag.
  747. if (item.substr(0, 7) == "include") {
  748. DEBUG_PRINTF("item = (%s)", item.c_str());
  749. string filename = get_element(item.c_str(), "file");
  750. string included_filename = get_include_filename(obj, template_dir, filename TSRMLS_CC);
  751. // Check included template file timestamp
  752. struct stat is;
  753. if (VCWD_STAT(included_filename.c_str(), &is) == -1) {
  754. zend_error(E_ERROR, "cannot stat:%s", included_filename.c_str());
  755. return false;
  756. }
  757. DEBUG_PRINTF("included_filename = (%s)", included_filename.c_str());
  758. DEBUG_PRINTF("cs.st_mtime = (%ld), is.st_mtime = (%ld)", cs.st_mtime, is.st_mtime);
  759. // Returns false if included file is newer than compiled file.
  760. if (cs.st_mtime < is.st_mtime) {
  761. return false;
  762. }
  763. // Reads included file.
  764. string new_condition = _readfile(included_filename.c_str() TSRMLS_CC);
  765. // Needs this check ?
  766. if (new_condition.find(filename) != string::npos) {
  767. zend_error(E_ERROR, "Found recursive include:%s", filename.c_str());
  768. return "";
  769. }
  770. file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, new_condition);
  771. continue;
  772. }
  773. pos++;
  774. }
  775. } // lazy check
  776. }
  777. return true;
  778. }
  779. /* }}} */
  780. /* {{{ Parses and compiles the specified temaplte file.
  781. *
  782. * @param INTERNAL_FUNCTION_PARAMETERS see zend.h
  783. * @param char **fullfile_name returns full path of template file
  784. * @param int mode SIMPLATE_FETCH or SIMPLATE_DISPLAY
  785. * @param char **cache_content returns results (use fetch mode)
  786. *
  787. * @return void
  788. */
  789. void read_parse_template(
  790. INTERNAL_FUNCTION_PARAMETERS,
  791. char **fullfile_name,
  792. int mode,
  793. char **cache_content = NULL
  794. )
  795. {
  796. zval *obj;
  797. char *resource_name = NULL;
  798. int resource_name_len = 0;
  799. string template_dir;
  800. char *compile_dir = NULL;
  801. char *left_delimiter = NULL;
  802. char *right_delimiter = NULL;
  803. long caching = 0;
  804. long cache_lifetime = 0;
  805. size_t i = 0;
  806. string error;
  807. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &resource_name, &resource_name_len) == FAILURE) {
  808. return;
  809. }
  810. DEBUG_PRINTF("resource_name = (%s)", resource_name);
  811. obj = getThis();
  812. #ifdef ZEND_ENGINE_2
  813. zval *temp_zval;
  814. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(TEMPLATE_DIR), strlen(TEMPLATE_DIR), 1 TSRMLS_CC);
  815. if (Z_TYPE_P(temp_zval) == IS_STRING) {
  816. template_dir = Z_STRVAL_P(temp_zval);
  817. }
  818. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(COMPILE_DIR), strlen(COMPILE_DIR), 1 TSRMLS_CC);
  819. if (Z_TYPE_P(temp_zval) == IS_STRING) {
  820. compile_dir = Z_STRVAL_P(temp_zval);
  821. }
  822. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(LEFT_DELIMITER), strlen(LEFT_DELIMITER), 1 TSRMLS_CC);
  823. if (Z_TYPE_P(temp_zval) == IS_STRING) {
  824. left_delimiter = Z_STRVAL_P(temp_zval);
  825. }
  826. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(RIGHT_DELIMITER), strlen(RIGHT_DELIMITER), 1 TSRMLS_CC);
  827. if (Z_TYPE_P(temp_zval) == IS_STRING) {
  828. right_delimiter = Z_STRVAL_P(temp_zval);
  829. }
  830. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(CACHING), strlen(CACHING), 1 TSRMLS_CC);
  831. if (Z_TYPE_P(temp_zval) == IS_LONG) {
  832. caching = Z_LVAL_P(temp_zval);
  833. }
  834. temp_zval = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(CACHE_LIFETIME), strlen(CACHE_LIFETIME), 1 TSRMLS_CC);
  835. if (Z_TYPE_P(temp_zval) == IS_LONG) {
  836. cache_lifetime = Z_LVAL_P(temp_zval);
  837. }
  838. #else
  839. zval **temp_zval;
  840. // Logic to implement var_dump($this) for PHP4
  841. // $this = &$smarty;
  842. // zend_hash_update(&EG(symbol_table), "this", strlen("this") + 1, &obj, sizeof(zval*), NULL);
  843. if (zend_hash_find(Z_OBJPROP_P(obj), TEMPLATE_DIR, sizeof(TEMPLATE_DIR), (void**)&temp_zval) == SUCCESS) {
  844. if ((*temp_zval)->type == IS_STRING) {
  845. template_dir = Z_STRVAL_PP(temp_zval);
  846. }
  847. }
  848. if (zend_hash_find(Z_OBJPROP_P(obj), COMPILE_DIR, sizeof(COMPILE_DIR), (void**)&temp_zval) == SUCCESS) {
  849. if ((*temp_zval)->type == IS_STRING) {
  850. compile_dir = Z_STRVAL_PP(temp_zval);
  851. }
  852. }
  853. if (zend_hash_find(Z_OBJPROP_P(obj), LEFT_DELIMITER, sizeof(LEFT_DELIMITER), (void**)&temp_zval) == SUCCESS) {
  854. if ((*temp_zval)->type == IS_STRING) {
  855. left_delimiter = Z_STRVAL_PP(temp_zval);
  856. }
  857. }
  858. if (zend_hash_find(Z_OBJPROP_P(obj), RIGHT_DELIMITER, sizeof(RIGHT_DELIMITER), (void**)&temp_zval) == SUCCESS) {
  859. if ((*temp_zval)->type == IS_STRING) {
  860. right_delimiter = Z_STRVAL_PP(temp_zval);
  861. }
  862. }
  863. if (zend_hash_find(Z_OBJPROP_P(obj), CACHING, sizeof(CACHING), (void**)&temp_zval) == SUCCESS) {
  864. if ((*temp_zval)->type == IS_LONG) {
  865. caching = Z_LVAL_PP(temp_zval);
  866. }
  867. }
  868. if (zend_hash_find(Z_OBJPROP_P(obj), CACHE_LIFETIME, sizeof(CACHE_LIFETIME), (void**)&temp_zval) == SUCCESS) {
  869. if ((*temp_zval)->type == IS_LONG) {
  870. cache_lifetime = Z_LVAL_PP(temp_zval);
  871. }
  872. }
  873. #endif // ZEND_ENGINE_2
  874. DEBUG_PRINTF("template_dir = (%s)", template_dir.c_str());
  875. DEBUG_PRINTF("compile_dir = (%s)", compile_dir);
  876. DEBUG_PRINTF("left_delimiter = (%s)", left_delimiter);
  877. DEBUG_PRINTF("right_delimiter = (%s)", right_delimiter);
  878. DEBUG_PRINTF("caching = (%ld)", caching);
  879. DEBUG_PRINTF("cache_lifetime = (%ld)", cache_lifetime);
  880. if (template_dir[template_dir.length() - 1] == DEFAULT_SLASH) {
  881. template_dir.erase(template_dir.length() - 1, 1);
  882. }
  883. string full_template_filename(template_dir);
  884. full_template_filename += DEFAULT_SLASH;
  885. full_template_filename += resource_name;
  886. DEBUG_PRINTF("full_template_filename = (%s)", full_template_filename.c_str());
  887. string full_compile_filename(compile_dir);
  888. if (full_compile_filename[full_compile_filename.length() - 1] != DEFAULT_SLASH) {
  889. full_compile_filename += DEFAULT_SLASH;
  890. }
  891. full_compile_filename += resource_name;
  892. DEBUG_PRINTF("full_compile_filename = (%s)", full_compile_filename.c_str());
  893. if (caching) {
  894. struct stat cache_stat;
  895. char *cache_dir;
  896. unsigned char compile_check;
  897. unsigned char force_compile;
  898. #ifdef ZEND_ENGINE_2
  899. cache_dir = Z_STRVAL_P(zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(CACHE_DIR), strlen(CACHE_DIR), 1 TSRMLS_CC));
  900. compile_check = Z_BVAL_P(zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(COMPILE_CHECK), strlen(COMPILE_CHECK), 1 TSRMLS_CC));
  901. force_compile = Z_BVAL_P(zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(FORCE_COMPILE), strlen(FORCE_COMPILE), 1 TSRMLS_CC));
  902. #else
  903. #endif // ZEND_ENGINE_2
  904. if (cache_dir[strlen(cache_dir) - 1] == DEFAULT_SLASH) {
  905. cache_dir[strlen(cache_dir) - 1] = '\0';
  906. }
  907. // cache directory exists?
  908. if (VCWD_STAT(cache_dir, &cache_stat) != -1) {
  909. if (!S_ISDIR(cache_stat.st_mode)) {
  910. zend_error(E_ERROR, "does not exist cache directory: %s", cache_dir);
  911. return;
  912. }
  913. }
  914. string full_cache_filename(cache_dir);
  915. full_cache_filename += DEFAULT_SLASH;
  916. full_cache_filename += resource_name;
  917. DEBUG_PRINTF("full_cache_filename = (%s)", full_cache_filename.c_str());
  918. // there are no cache file.
  919. if (VCWD_STAT(full_cache_filename.c_str(), &cache_stat) == -1 || force_compile) {
  920. create_cache:
  921. if (VCWD_STAT(full_compile_filename.c_str(), &cache_stat) == -1) {
  922. goto compile;
  923. }
  924. zend_file_handle file_handle;
  925. zend_op_array *op_array;
  926. file_handle.filename = const_cast<char*>(full_compile_filename.c_str());
  927. file_handle.free_filename = 0;
  928. file_handle.type = ZEND_HANDLE_FILENAME;
  929. file_handle.opened_path = NULL;
  930. op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);
  931. if (!op_array) {
  932. zend_error(E_ERROR, "Error parsing script:%s", full_compile_filename.c_str());
  933. return;
  934. }
  935. zend_destroy_file_handle(&file_handle TSRMLS_CC);
  936. SIMPLATE_G(global_string.str(std::string())); // let global_string empty.
  937. int (*old_output_func)(const char*, unsigned int TSRMLS_DC);
  938. old_output_func = OG(php_body_write);
  939. OG(php_body_write) = php_my_output_func;
  940. zend_execute(op_array TSRMLS_CC);
  941. OG(php_body_write) = old_output_func;
  942. #ifdef ZEND_ENGINE_2
  943. destroy_op_array(op_array TSRMLS_CC);
  944. #else
  945. destroy_op_array(op_array);
  946. #endif // ZEND_ENGINE_2
  947. efree(op_array);
  948. DEBUG_PRINTF("SIMPLATE_G(global_string) = (%ld)", SIMPLATE_G(global_string).str().length());
  949. if (mode == SIMPLATE_FETCH) {
  950. *cache_content = estrndup(SIMPLATE_G(global_string).str().c_str(), SIMPLATE_G(global_string).str().length());
  951. } else {
  952. if (SIMPLATE_G(global_string).str().length() > 0) {
  953. zend_printf("%s", SIMPLATE_G(global_string).str().c_str());
  954. }
  955. }
  956. #ifdef PHP_WIN32
  957. php_stream *strm = php_stream_open_wrapper(const_cast<char*>(full_cache_filename.c_str()), "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
  958. if (strm) {
  959. if (php_stream_supports_lock(strm)) {
  960. php_stream_lock(strm, LOCK_EX);
  961. }
  962. if (SIMPLATE_G(global_string).str().length() > 0) {
  963. php_stream_write_string(strm, const_cast<char*>(SIMPLATE_G(global_string).str().c_str()));
  964. }
  965. if (php_stream_supports_lock(strm)) {
  966. php_stream_lock(strm, LOCK_UN);
  967. }
  968. php_stream_close(strm);
  969. }
  970. #else
  971. FILE *fp = VCWD_FOPEN(full_cache_filename.c_str(), "wb");
  972. if (fp == NULL) {
  973. // fail to create cache
  974. zend_error(E_ERROR, "fail to create cache:%s", full_cache_filename.c_str());
  975. return;
  976. }
  977. if (fwrite(SIMPLATE_G(global_string).str().c_str(), 1, SIMPLATE_G(global_string).str().length(), fp) != SIMPLATE_G(global_string).str().length()) {
  978. // fail to write cache
  979. zend_error(E_ERROR, "fail to write cache:%s", full_cache_filename.c_str());
  980. // Notice: don't retun, yet.
  981. }
  982. fclose(fp);
  983. #endif // PHP_WIN32
  984. } else {
  985. DEBUG_PRINTF("%s", "cache file exists.");
  986. if (compile_check) {
  987. DEBUG_PRINTF("%s", "check cache file is compiled.");
  988. // check cache filestamp
  989. time_t now;
  990. time(&now);
  991. if (now - cache_stat.st_mtime > cache_lifetime) {
  992. DEBUG_PRINTF("%s", "cache file is not compiled.");
  993. goto create_cache;
  994. }
  995. }
  996. string file_contents = _readfile(full_cache_filename.c_str() TSRMLS_CC);
  997. if (mode == SIMPLATE_FETCH) {
  998. *cache_content = estrndup(file_contents.c_str(), file_contents.length());
  999. } else {
  1000. zend_printf("%s", file_contents.c_str());
  1001. }
  1002. }
  1003. DEBUG_PRINTF("%s", "end function");
  1004. return;
  1005. }
  1006. // the directory for compiled templates exists?
  1007. struct stat compile_dir_stat;
  1008. if (VCWD_STAT(compile_dir, &compile_dir_stat) != -1) {
  1009. if (!S_ISDIR(compile_dir_stat.st_mode)) {
  1010. zend_error(E_ERROR, "%s is not directory", compile_dir);
  1011. return;
  1012. }
  1013. } else {
  1014. // mkdir recursively
  1015. php_stream_context *context = NULL;
  1016. if (!php_stream_mkdir(compile_dir, 0777, (PHP_STREAM_MKDIR_RECURSIVE | REPORT_ERRORS), context)) {
  1017. zend_error(E_ERROR, "fail to mkdir (%s)", compile_dir);
  1018. return;
  1019. }
  1020. }
  1021. // already compiled
  1022. if (_is_compiled(obj, template_dir.c_str(), compile_dir, resource_name, left_delimiter, right_delimiter TSRMLS_CC)) {
  1023. } else {
  1024. compile:
  1025. // compile now
  1026. string compiled_file_content = _readfile(full_template_filename.c_str() TSRMLS_CC);
  1027. // prefilter
  1028. zval *plugins = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>("_plugins"), strlen("_plugins"), 1 TSRMLS_CC);
  1029. if (plugins && Z_TYPE_P(plugins) == IS_ARRAY) {
  1030. zval **prefilter;
  1031. if (zend_hash_find(Z_ARRVAL_P(plugins), "prefilter", sizeof("prefilter"), (void**)&prefilter) == SUCCESS
  1032. && Z_TYPE_PP(prefilter) == IS_ARRAY
  1033. ) {
  1034. zval **elem;
  1035. zend_hash_internal_pointer_reset(Z_ARRVAL_PP(prefilter));
  1036. while (zend_hash_get_current_data(Z_ARRVAL_PP(prefilter), (void**)&elem) == SUCCESS) {
  1037. DEBUG_PRINTF("prefilter function = (%s)", Z_STRVAL_PP(elem));
  1038. zval prefilter_function, prefilter_ret;
  1039. zval zcontent;
  1040. zval *prefilter_argv[1];
  1041. prefilter_argv[0] = &zcontent;
  1042. SET_ZVAL_STRING(zcontent, compiled_file_content.c_str());
  1043. INIT_ZVAL(prefilter_function);
  1044. ZVAL_STRING(&prefilter_function, Z_STRVAL_PP(elem), 1);
  1045. if (call_user_function(EG(function_table), NULL, &prefilter_function, &prefilter_ret, 1, prefilter_argv TSRMLS_CC) == FAILURE) {
  1046. zval_dtor(&zcontent);
  1047. zend_error(E_ERROR, "fail to %s", Z_STRVAL_PP(elem));
  1048. return;
  1049. }
  1050. zval_dtor(&prefilter_function);
  1051. zval_dtor(&zcontent);
  1052. compiled_file_content = Z_STRVAL(prefilter_ret);
  1053. DEBUG_PRINTF("compiled_file_content = (%s)", compiled_file_content.c_str());
  1054. zval_dtor(&prefilter_ret);
  1055. zend_hash_move_forward(Z_ARRVAL_PP(prefilter));
  1056. }
  1057. }
  1058. }
  1059. size_t pos = 0;
  1060. size_t tag_start_pos, tag_end_pos;
  1061. size_t element_start_pos, element_end_pos;
  1062. string item;
  1063. char end_comment_tag[12];
  1064. string new_condition;
  1065. sprintf(end_comment_tag, "*%s", right_delimiter);
  1066. while ((pos = compiled_file_content.find(left_delimiter, pos)) != string::npos) {
  1067. // <{$hoge}>
  1068. // ^ :tag_start_pos
  1069. // ^ :element_start_pos
  1070. // ^ :element_end_pos
  1071. // ^:tag_end_pos
  1072. // ^---^ :item
  1073. tag_start_pos = pos;
  1074. element_start_pos = tag_start_pos + strlen(left_delimiter);
  1075. element_end_pos = compiled_file_content.find(right_delimiter, tag_start_pos);
  1076. if (element_end_pos == string::npos) {
  1077. zend_error(E_ERROR, "No closed delimiter:`%s' in %s", right_delimiter, full_template_filename.c_str());
  1078. return;
  1079. }
  1080. tag_end_pos = element_end_pos + strlen(right_delimiter);
  1081. item.assign(compiled_file_content, element_start_pos, element_end_pos - element_start_pos);
  1082. item = trim(item.c_str());
  1083. string variable;
  1084. string new_variable;
  1085. DEBUG_PRINTF("item = (%s)", item.c_str());
  1086. if (item[0] == '$') {
  1087. DEBUG_PRINTF("variable item = (%s)", item.c_str());
  1088. cond_var:
  1089. new_condition = "<?php echo ";
  1090. i = 0;
  1091. while (element_start_pos + i < element_end_pos) {
  1092. if (compiled_file_content[element_start_pos + i] == '+'
  1093. || (compiled_file_content[element_start_pos + i] == '-'
  1094. && compiled_file_content.at(element_start_pos + i + 1) != '>')
  1095. || compiled_file_content[element_start_pos + i] == '*'
  1096. || compiled_file_content[element_start_pos + i] == '/'
  1097. || compiled_file_content[element_start_pos + i] == '%'
  1098. || compiled_file_content[element_start_pos + i] == '('
  1099. || compiled_file_content[element_start_pos + i] == ')'
  1100. || compiled_file_content[element_start_pos + i] == ','
  1101. || compiled_file_content[element_start_pos + i] == '\''
  1102. || compiled_file_content[element_start_pos + i] == '"'
  1103. || compiled_file_content[element_start_pos + i] == '?'
  1104. || compiled_file_content[element_start_pos + i] == ':'
  1105. || compiled_file_content[element_start_pos + i] == ';'
  1106. || compiled_file_content[element_start_pos + i] == ','
  1107. || compiled_file_content[element_start_pos + i] == ' '
  1108. ) {
  1109. if (variable != "$") {
  1110. new_variable = parse_variable(variable.c_str());
  1111. DEBUG_PRINTF("(%s) = (%s)", variable.c_str(), new_variable.c_str());
  1112. } else {
  1113. new_variable = variable;
  1114. }
  1115. new_condition += new_variable;
  1116. new_condition += compiled_file_content[element_start_pos + i];
  1117. variable = "";
  1118. } else {
  1119. variable += compiled_file_content[element_start_pos + i];
  1120. DEBUG_PRINTF("variable = (%s)", variable.c_str());
  1121. }
  1122. i++;
  1123. }
  1124. new_variable = parse_variable(variable.c_str());
  1125. DEBUG_PRINTF("(%s) = (%s)", variable.c_str(), new_variable.c_str());
  1126. new_condition += new_variable;
  1127. new_condition += "; ?>";
  1128. DEBUG_PRINTF("new_condition = (%s)", new_condition.c_str());
  1129. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, new_condition);
  1130. pos += new_condition.length() - 1; // 20060527
  1131. } else if (item[0] == '*') { // Comment
  1132. if (item[item.length() - 1] != '*') { // support multi-line comment
  1133. tag_end_pos = compiled_file_content.find(end_comment_tag, tag_end_pos) + strlen(end_comment_tag);
  1134. }
  1135. DEBUG_PRINTF("COMMENT = (%s)", compiled_file_content.substr(tag_start_pos, tag_end_pos - tag_start_pos).c_str());
  1136. compiled_file_content.erase(tag_start_pos, tag_end_pos - tag_start_pos);
  1137. pos = tag_start_pos - 1;
  1138. } else {
  1139. DEBUG_PRINTF("CONDITION = (%s)", item.c_str());
  1140. string command_tag;
  1141. string condition;
  1142. if (item.find(" ") != string::npos) {
  1143. command_tag = item.substr(0, item.find(" "));
  1144. condition = item.substr(item.find(" ") + 1);
  1145. } else {
  1146. command_tag = item;
  1147. }
  1148. DEBUG_PRINTF("COMMAND = (%s)", command_tag.c_str());
  1149. DEBUG_PRINTF("CONDITION = (%s)", condition.c_str());
  1150. if (command_tag == "if") {
  1151. new_condition = "<?php if (";
  1152. cond_if:
  1153. i = 0;
  1154. while (i < condition.length()) {
  1155. if (condition[i] == '+'
  1156. || (condition[i] == '-' && condition.at(i + 1) != '>')
  1157. || condition[i] == '*'
  1158. || condition[i] == '/'
  1159. || condition[i] == '%'
  1160. || condition[i] == '<'
  1161. || (condition[i] == '>' && condition.at(i - 1) != '-')
  1162. || condition[i] == '='
  1163. || condition[i] == '!'
  1164. || condition[i] == '|'
  1165. || condition[i] == '&'
  1166. || condition[i] == '('
  1167. || condition[i] == ')'
  1168. || condition[i] == ','
  1169. || condition[i] == ' '
  1170. ) {
  1171. new_variable = parse_variable(variable.c_str());
  1172. DEBUG_PRINTF("(%s) = (%s)", variable.c_str(), new_variable.c_str());
  1173. new_condition += new_variable;
  1174. new_condition += condition[i];
  1175. variable = "";
  1176. } else {
  1177. variable += condition[i];
  1178. }
  1179. i++;
  1180. }
  1181. new_variable = parse_variable(variable.c_str());
  1182. new_condition += new_variable;
  1183. new_condition += ") { ?>";
  1184. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, new_condition);
  1185. pos += new_condition.length() - 1; // 20060527
  1186. } else if (command_tag == "/if") {
  1187. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, "<?php } ?>");
  1188. pos += strlen("<?php } ?>") - 1; // 20060527
  1189. } else if (command_tag == "else") {
  1190. if (item.find("else if") != string::npos) {
  1191. new_condition = "<?php } else if (";
  1192. condition = item.substr(item.find("else if") + strlen("else if"));
  1193. condition = trim(condition.c_str());
  1194. goto cond_if;
  1195. }
  1196. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, "<?php } else { ?>");
  1197. pos += strlen("<?php } else { ?>") - 1; // 20060527
  1198. } else if (command_tag == "elseif") {
  1199. new_condition = "<?php } else if (";
  1200. goto cond_if;
  1201. } else if (command_tag == "section") {
  1202. string section_name = get_element(item.c_str(), "name");
  1203. string section_loop = get_element(item.c_str(), "loop");
  1204. string section_start = get_element(item.c_str(), "start");
  1205. string section_step = get_element(item.c_str(), "step");
  1206. string new_section_loop2 = "";
  1207. condition = section_loop;
  1208. i = 0;
  1209. while (i < condition.length()) {
  1210. if (condition[i] == '+'
  1211. || condition[i] == '-'
  1212. || condition[i] == '*'
  1213. || condition[i] == '/'
  1214. || condition[i] == '%'
  1215. || condition[i] == '<'
  1216. || condition[i] == '>'
  1217. || condition[i] == '='
  1218. || condition[i] == '!'
  1219. || condition[i] == '|'
  1220. || condition[i] == '&'
  1221. || condition[i] == '('
  1222. || condition[i] == ')'
  1223. ) {
  1224. new_variable = parse_variable(variable.c_str());
  1225. new_section_loop2 += new_variable;
  1226. new_section_loop2 += condition[i];
  1227. DEBUG_PRINTF("variable = (%s), new_section_loop2 = (%s)", variable.c_str(), new_section_loop2.c_str());
  1228. variable = "";
  1229. } else {
  1230. if (condition[i] != ' ') {
  1231. variable += condition[i];
  1232. }
  1233. DEBUG_PRINTF("variable = (%s)", variable.c_str());
  1234. }
  1235. i++;
  1236. }
  1237. new_section_loop2 += parse_variable(variable.c_str());
  1238. DEBUG_PRINTF("new_section_loop2 = (%s)", new_section_loop2.c_str());
  1239. // "<?php $this->_section['%s']['total'] = count(%s);\n"
  1240. new_condition = "<?php ";
  1241. new_condition += "$this->_section['";
  1242. new_condition += section_name;
  1243. new_condition += "']['total'] = ";
  1244. new_condition += "count(";
  1245. new_condition += new_section_loop2;
  1246. new_condition += ");\n";
  1247. // "for ($%s = 0, $this->_section['%s']['iteration'] = 1; $%s<$this->_section['%s']['total']; $%s++, $this->_section['%s']['iteration']++) {\n"
  1248. new_condition += "for ($";
  1249. new_condition += section_name;
  1250. new_condition += " = ";
  1251. if (section_start.length() > 0) {
  1252. new_condition += section_start;
  1253. } else {
  1254. new_condition += "0";
  1255. }
  1256. new_condition += ", $this->_section['";
  1257. new_condition += section_name;
  1258. new_condition += "']['iteration'] = 1; $";
  1259. new_condition += section_name;
  1260. new_condition += " < $this->_section['";
  1261. new_condition += section_name;
  1262. new_condition += "']['total']; $";
  1263. new_condition += section_name;
  1264. if (section_step.length() > 0) {
  1265. new_condition += " += ";
  1266. new_condition += section_step;
  1267. } else {
  1268. new_condition += "++";
  1269. }
  1270. new_condition += ", $this->_section['";
  1271. new_condition += section_name;
  1272. new_condition += "']['iteration']++";
  1273. new_condition += ") {\n";
  1274. // "$this->_section['%s']['first'] = ($% == 0);\n"
  1275. new_condition += "$this->_section['";
  1276. new_condition += section_name;
  1277. new_condition += "']['first'] = ($";
  1278. new_condition += section_name;
  1279. new_condition += " == ";
  1280. if (section_start.length() > 0) {
  1281. new_condition += section_start;
  1282. } else {
  1283. new_condition += "0";
  1284. }
  1285. new_condition += ");\n";
  1286. // "$this->_section['%s']['last'] == ($this->_section['%s']['iteration'] == $this->_section['%s']['total']);\n"
  1287. new_condition += "$this->_section['";
  1288. new_condition += section_name;
  1289. new_condition += "']['last'] = ($this->_section['";
  1290. new_condition += section_name;
  1291. new_condition += "']['iteration']";
  1292. new_condition += " == $this->_section['";
  1293. new_condition += section_name;
  1294. new_condition += "']['total']);\n";
  1295. new_condition += "?>";
  1296. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, new_condition);
  1297. pos += new_condition.length() - 1; // 20060527
  1298. } else if (command_tag == "/section") {
  1299. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, "<?php } ?>");
  1300. pos += strlen("<?php } ?>") - 1; // 20060527
  1301. } else if (command_tag == "foreach") {
  1302. string foreach_key = get_element(item.c_str(), "key");
  1303. string foreach_item = get_element(item.c_str(), "item");
  1304. string foreach_from = get_element(item.c_str(), "from");
  1305. string new_foreach_from2 = "";
  1306. condition = foreach_from;
  1307. i = 0;
  1308. while (i < condition.length()) {
  1309. if (condition[i] == '+'
  1310. || condition[i] == '-'
  1311. || condition[i] == '*'
  1312. || condition[i] == '/'
  1313. || condition[i] == '%'
  1314. || condition[i] == '<'
  1315. || condition[i] == '>'
  1316. || condition[i] == '='
  1317. || condition[i] == '!'
  1318. || condition[i] == '|'
  1319. || condition[i] == '&'
  1320. || condition[i] == '('
  1321. || condition[i] == ')'
  1322. ) {
  1323. new_variable = parse_variable(variable.c_str());
  1324. new_foreach_from2 += new_variable;
  1325. new_foreach_from2 += condition[i];
  1326. variable = "";
  1327. } else {
  1328. if (condition[i] != ' ') {
  1329. variable += condition[i];
  1330. }
  1331. }
  1332. i++;
  1333. }
  1334. new_foreach_from2 += parse_variable(variable.c_str());
  1335. // "<?php if (!is_array(%s) && !is_object(%s)) { settype("%s", 'array') };\n"
  1336. new_condition = "<?php ";
  1337. new_condition += "if (!is_array(";
  1338. new_condition += new_foreach_from2;
  1339. new_condition += ") && !is_object(";
  1340. new_condition += new_foreach_from2;
  1341. new_condition += ")) { settype(";
  1342. new_condition += new_foreach_from2;
  1343. new_condition += ", 'array'); }\n";
  1344. // "if (count(%s)) {\n"
  1345. new_condition += "if (count(";
  1346. new_condition += new_foreach_from2;
  1347. new_condition += ")) {\n";
  1348. // "foreach (%s as %s) { ?>"
  1349. new_condition += "foreach (";
  1350. new_condition += new_foreach_from2;
  1351. new_condition += " as ";
  1352. if (foreach_key.length() > 0) {
  1353. new_condition += "$this->_tpl_vars[\"";
  1354. new_condition += foreach_key;
  1355. new_condition += "\"] => ";
  1356. }
  1357. new_condition += "$this->_tpl_vars[\"";
  1358. new_condition += foreach_item;
  1359. new_condition += "\"]) { ?>";
  1360. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, new_condition);
  1361. pos += new_condition.length() - 1; // 20060527
  1362. } else if (command_tag == "/foreach") {
  1363. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, "<?php }} ?>");
  1364. pos += strlen("<?php }} ?>") - 1; // 20060527
  1365. } else if (command_tag == "include") {
  1366. string filename = get_element(item.c_str(), "file");
  1367. string included_filename = get_include_filename(obj, template_dir, filename TSRMLS_CC);
  1368. new_condition = _readfile(included_filename.c_str() TSRMLS_CC);
  1369. zval *plugins = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>("_plugins"), strlen("_plugins"), 1 TSRMLS_CC);
  1370. if (plugins && Z_TYPE_P(plugins) == IS_ARRAY) {
  1371. zval **prefilter;
  1372. if (zend_hash_find(Z_ARRVAL_P(plugins), "prefilter", sizeof("prefilter"), (void**)&prefilter) == SUCCESS
  1373. && Z_TYPE_PP(prefilter) == IS_ARRAY
  1374. ) {
  1375. zval **elem;
  1376. zend_hash_internal_pointer_reset(Z_ARRVAL_PP(prefilter));
  1377. while (zend_hash_get_current_data(Z_ARRVAL_PP(prefilter), (void**)&elem) == SUCCESS) {
  1378. zval prefilter_function, prefilter_ret;
  1379. zval zcontent;
  1380. zval *prefilter_argv[1];
  1381. prefilter_argv[0] = &zcontent;
  1382. SET_ZVAL_STRING(zcontent, new_condition.c_str());
  1383. INIT_ZVAL(prefilter_function);
  1384. ZVAL_STRING(&prefilter_function, Z_STRVAL_PP(elem), 1);
  1385. if (call_user_function(EG(function_table), NULL, &prefilter_function, &prefilter_ret, 1, prefilter_argv TSRMLS_CC) == FAILURE) {
  1386. zval_dtor(&zcontent);
  1387. zend_error(E_ERROR, "fail to %s", Z_STRVAL_PP(elem));
  1388. return;
  1389. }
  1390. zval_dtor(&prefilter_function);
  1391. zval_dtor(&zcontent);
  1392. new_condition = Z_STRVAL(prefilter_ret);
  1393. zval_dtor(&prefilter_ret);
  1394. zend_hash_move_forward(Z_ARRVAL_PP(prefilter));
  1395. }
  1396. }
  1397. }
  1398. if (new_condition.find(filename) != string::npos) {
  1399. zend_error(E_ERROR, "Found recursive include:%s", filename.c_str());
  1400. return;
  1401. }
  1402. compiled_file_content.replace(tag_start_pos, tag_end_pos - tag_start_pos, new_condition);
  1403. continue; // don't skip with pos
  1404. } else if (command_tag == "php") {
  1405. string end_php_tag;
  1406. size_t php_tag_end_pos;
  1407. end_php_tag = left_delimiter;
  1408. end_php_tag += "/php";
  1409. end_php_tag += right_delimiter;
  1410. php_tag_end_pos = compiled_file_content.find(end_php_tag, tag_end_pos);
  1411. new_condition = "<?php ";
  1412. new_condition += compiled_file_content.substr(tag_end_pos, php_tag_end_pos - tag_end_pos);
  1413. new_condition += " ?>";
  1414. compiled_file_content.replace(tag_start_pos, php_tag_end_pos+end_php_tag.length() - tag_start_pos, new_condition);
  1415. pos += new_condition.length() - 1;
  1416. } else if (command_tag == "literal") {
  1417. string end_literal = left_delimiter;
  1418. end_literal += "/literal";
  1419. end_literal += right_delimiter;
  1420. new_condition = compiled_file_content.substr(tag_end_pos, compiled_file_content.find(end_literal, element_end_pos) - tag_end_pos);
  1421. compiled_file_content.replace(tag_start_pos, compiled_file_content.find(end_literal, element_end_pos) + end_literal.length() - tag_start_pos, new_condition);
  1422. pos += new_condition.length() - 1;
  1423. } else {
  1424. goto cond_var;
  1425. }
  1426. }
  1427. pos++;
  1428. }
  1429. // postfilter
  1430. if (plugins && Z_TYPE_P(plugins) == IS_ARRAY) {
  1431. zval **postfilter;
  1432. if (zend_hash_find(Z_ARRVAL_P(plugins), "postfilter", sizeof("postfilter"), (void**)&postfilter) == SUCCESS && Z_TYPE_PP(postfilter) == IS_ARRAY) {
  1433. zval **elem;
  1434. zend_hash_internal_pointer_reset(Z_ARRVAL_PP(postfilter));
  1435. while (zend_hash_get_current_data(Z_ARRVAL_PP(postfilter), (void**)&elem) == SUCCESS) {
  1436. zval postfilter_function, postfilter_ret;
  1437. zval zcontent;
  1438. zval *postfilter_argv[1];
  1439. postfilter_argv[0] = &zcontent;
  1440. SET_ZVAL_STRING(zcontent, compiled_file_content.c_str());
  1441. INIT_ZVAL(postfilter_function);
  1442. ZVAL_STRING(&postfilter_function, Z_STRVAL_PP(elem), 1);
  1443. if (call_user_function(EG(function_table), NULL, &postfilter_function, &postfilter_ret, 1, postfilter_argv TSRMLS_CC) == FAILURE) {
  1444. zval_dtor(&zcontent);
  1445. zend_error(E_ERROR, "fail to %s", Z_STRVAL_PP(elem));
  1446. return;
  1447. }
  1448. zval_dtor(&postfilter_function);
  1449. zval_dtor(&zcontent);
  1450. compiled_file_content = Z_STRVAL(postfilter_ret);
  1451. zval_dtor(&postfilter_ret);
  1452. zend_hash_move_forward(Z_ARRVAL_PP(postfilter));
  1453. }
  1454. }
  1455. }
  1456. DEBUG_PRINTF("write compiled file path = (%s)", const_cast<char*>(full_compile_filename.c_str()));
  1457. #ifdef PHP_WIN32
  1458. php_stream *strm = php_stream_open_wrapper(const_cast<char*>(full_compile_filename.c_str()), "wb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
  1459. if (!strm) {
  1460. // create sub directory path
  1461. if (full_compile_filename.find(DEFAULT_SLASH) != string::npos) {
  1462. size_t slash_rpos = full_compile_filename.rfind("/");
  1463. size_t default_slash_rpos = full_compile_filename.rfind(DEFAULT_SLASH);
  1464. DEBUG_PRINTF("slash_rpos=(%d), default_slash_rpos=(%d)", slash_rpos, default_slash_rpos);
  1465. if (slash_rpos == string::npos || slash_rpos < default_slash_rpos) {
  1466. slash_rpos = default_slash_rpos;
  1467. }
  1468. string directory_path = full_compile_filename.substr(0, slash_rpos);
  1469. DEBUG_PRINTF("slash_rpos=(%d)", slash_rpos);
  1470. DEBUG_PRINTF("directory_path=(%s)", const_cast<char*>(directory_path.c_str()));
  1471. // mkdir recursively
  1472. php_stream_context *context = NULL;
  1473. if (!php_stream_mkdir(const_cast<char*>(directory_path.c_str()), 0755, (PHP_STREAM_MKDIR_RECURSIVE | REPORT_ERRORS), context)) {
  1474. zend_error(E_ERROR, "fail to php_stream_mkdir(win32) (%s)", const_cast<char*>(directory_path.c_str()));
  1475. return;
  1476. }
  1477. strm = php_stream_open_wrapper(const_cast<char*>(full_compile_filename.c_str()), "wb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
  1478. }
  1479. }
  1480. if (strm) {
  1481. if (php_stream_supports_lock(strm)) {
  1482. php_stream_lock(strm, LOCK_EX);
  1483. }
  1484. if (compiled_file_content.length() > 0) {
  1485. php_stream_write_string(strm, const_cast<char*>(compiled_file_content.c_str()));
  1486. }
  1487. if (php_stream_supports_lock(strm)) {
  1488. php_stream_lock(strm, LOCK_UN);
  1489. }
  1490. php_stream_close(strm);
  1491. }
  1492. #else
  1493. // write compiled file
  1494. FILE *fp = VCWD_FOPEN(full_compile_filename.c_str(), "wb");
  1495. if (fp == NULL) {
  1496. // create sub directory path
  1497. if (full_compile_filename.find(DEFAULT_SLASH) != string::npos) {
  1498. size_t slash_rpos = full_compile_filename.rfind("\\");
  1499. size_t default_slash_rpos = full_compile_filename.rfind(DEFAULT_SLASH);
  1500. DEBUG_PRINTF("slash_rpos=(%d), default_slash_rpos=(%d)", slash_rpos, default_slash_rpos);
  1501. if (slash_rpos == string::npos || slash_rpos < default_slash_rpos) {
  1502. slash_rpos = default_slash_rpos;
  1503. }
  1504. string directory_path = full_compile_filename.substr(0, slash_rpos);
  1505. DEBUG_PRINTF("slash_rpos=(%d)", slash_rpos);
  1506. DEBUG_PRINTF("directory_path=(%s)", const_cast<char*>(directory_path.c_str()));
  1507. // mkdir recursively
  1508. php_stream_context *context = NULL;
  1509. if (!php_stream_mkdir(const_cast<char*>(directory_path.c_str()), 0755, (PHP_STREAM_MKDIR_RECURSIVE | REPORT_ERRORS), context)) {
  1510. zend_error(E_ERROR, "fail to php_stream_mkdir (%s)", const_cast<char*>(directory_path.c_str()));
  1511. return;
  1512. }
  1513. }
  1514. fp = VCWD_FOPEN(full_compile_filename.c_str(), "wb");
  1515. if (fp == NULL) {
  1516. // error handling
  1517. zend_error(E_ERROR, "fail to write : %s", full_compile_filename.c_str());
  1518. return;
  1519. }
  1520. }
  1521. if (fwrite(compiled_file_content.c_str(), 1, compiled_file_content.length(), fp) != compiled_file_content.length()) {
  1522. zend_error(E_WARNING, "fail to write:%s", full_compile_filename.c_str());
  1523. return;
  1524. }
  1525. fclose(fp);
  1526. #endif // PHP_WIN32
  1527. }
  1528. *fullfile_name = estrndup(full_compile_filename.c_str(), full_compile_filename.length());
  1529. DEBUG_PRINTF("%s", "end function");
  1530. return;
  1531. }
  1532. /* {{{ Registers simplate properties.
  1533. *
  1534. * @return void
  1535. */
  1536. static void register_simplate_properties(TSRMLS_D)
  1537. {
  1538. zend_class_entry simplate_ce;
  1539. // register class entry
  1540. INIT_CLASS_ENTRY(simplate_ce, "Simplate", php_simplate_functions);
  1541. simplate_entry_ptr = zend_register_internal_class(&simplate_ce TSRMLS_CC);
  1542. #ifdef ZEND_ENGINE_2
  1543. /**
  1544. * Class property
  1545. */
  1546. // directory parameter seting
  1547. zend_declare_property_string(simplate_entry_ptr, const_cast<char*>(TEMPLATE_DIR), strlen(TEMPLATE_DIR), const_cast<char*>(DEFAULT_TEMPLATE_DIR), ZEND_ACC_PUBLIC TSRMLS_CC);
  1548. zend_declare_property_string(simplate_entry_ptr, const_cast<char*>(COMPILE_DIR), strlen(COMPILE_DIR), const_cast<char*>(DEFAULT_COMPILE_DIR), ZEND_ACC_PUBLIC TSRMLS_CC);
  1549. zend_declare_property_string(simplate_entry_ptr, const_cast<char*>(CACHE_DIR), strlen(CACHE_DIR), const_cast<char*>(DEFAULT_CACHE_DIR), ZEND_ACC_PUBLIC TSRMLS_CC);
  1550. zend_declare_property_long(simplate_entry_ptr, const_cast<char*>(CACHING), strlen(CACHING), DEFAULT_CACHING, ZEND_ACC_PUBLIC TSRMLS_CC);
  1551. zend_declare_property_long(simplate_entry_ptr, const_cast<char*>(CACHE_LIFETIME), strlen(CACHE_LIFETIME), DEFAULT_CACHE_LIFETIME, ZEND_ACC_PUBLIC TSRMLS_CC);
  1552. // delimitter
  1553. zend_declare_property_string(simplate_entry_ptr, const_cast<char*>(LEFT_DELIMITER), strlen(LEFT_DELIMITER), const_cast<char*>(DEFAULT_LEFT_DELIMITER), ZEND_ACC_PUBLIC TSRMLS_CC);
  1554. zend_declare_property_string(simplate_entry_ptr, const_cast<char*>(RIGHT_DELIMITER), strlen(RIGHT_DELIMITER), const_cast<char*>(DEFAULT_RIGHT_DELIMITER), ZEND_ACC_PUBLIC TSRMLS_CC);
  1555. zend_declare_property_bool(simplate_entry_ptr, const_cast<char*>(COMPILE_CHECK), strlen(COMPILE_CHECK), DEFAULT_COMPILE_CHECK, ZEND_ACC_PUBLIC TSRMLS_CC);
  1556. // force_compile, lazy_check
  1557. zend_declare_property_bool(simplate_entry_ptr, const_cast<char*>(FORCE_COMPILE), strlen(FORCE_COMPILE), DEFAULT_FORCE_COMPILE, ZEND_ACC_PUBLIC TSRMLS_CC);
  1558. zend_declare_property_bool(simplate_entry_ptr, const_cast<char*>(LAZY_CHECK), strlen(LAZY_CHECK), DEFAULT_LAZY_CHECK, ZEND_ACC_PUBLIC TSRMLS_CC);
  1559. // version
  1560. zend_declare_property_string(simplate_entry_ptr, const_cast<char*>("version"), strlen("version"), const_cast<char*>(VERSION), ZEND_ACC_PUBLIC TSRMLS_CC);
  1561. // temporary
  1562. zend_declare_property_null(simplate_entry_ptr, const_cast<char*>("_tpl_vars"), strlen("_tpl_vars"), ZEND_ACC_PUBLIC TSRMLS_CC);
  1563. // plugins
  1564. zend_declare_property_null(simplate_entry_ptr, const_cast<char*>("_plugins"), strlen("_plugins"), ZEND_ACC_PUBLIC TSRMLS_CC);
  1565. #endif // ZEND_ENGINE_2
  1566. }
  1567. /* }}} */
  1568. /* {{{ PHP_MINIT_FUNCTION
  1569. *
  1570. * @return int returns SUCCESS if function succeeded
  1571. */
  1572. PHP_MINIT_FUNCTION(simplate)
  1573. {
  1574. /* If you have INI entries, uncomment these lines
  1575. ZEND_INIT_MODULE_GLOBALS(simplate, php_simplate_init_globals, NULL);
  1576. REGISTER_INI_ENTRIES();
  1577. */
  1578. ZEND_INIT_MODULE_GLOBALS(simplate, php_simplate_init_globals, NULL);
  1579. register_simplate_properties(TSRMLS_C);
  1580. return SUCCESS;
  1581. }
  1582. /* }}} */
  1583. /* {{{ PHP_MSHUTDOWN_FUNCTION
  1584. *
  1585. * @return int returns SUCCESS if function succeeded
  1586. */
  1587. PHP_MSHUTDOWN_FUNCTION(simplate)
  1588. {
  1589. /* uncomment this line if you have INI entries
  1590. UNREGISTER_INI_ENTRIES();
  1591. */
  1592. return SUCCESS;
  1593. }
  1594. /* }}} */
  1595. /* Remove if there's nothing to do at request start */
  1596. /* {{{ PHP_RINIT_FUNCTION
  1597. *
  1598. * @return int returns SUCCESS if function succeeded
  1599. */
  1600. PHP_RINIT_FUNCTION(simplate)
  1601. {
  1602. return SUCCESS;
  1603. }
  1604. /* }}} */
  1605. /* Remove if there's nothing to do at request end */
  1606. /* {{{ PHP_RSHUTDOWN_FUNCTION
  1607. *
  1608. * @return int returns SUCCESS if function succeeded
  1609. */
  1610. PHP_RSHUTDOWN_FUNCTION(simplate)
  1611. {
  1612. return SUCCESS;
  1613. }
  1614. /* }}} */
  1615. /* {{{ PHP_MINFO_FUNCTION
  1616. *
  1617. * @return void
  1618. */
  1619. PHP_MINFO_FUNCTION(simplate)
  1620. {
  1621. php_info_print_table_start();
  1622. php_info_print_table_header(2, "simplate support", "enabled");
  1623. php_info_print_table_row(2, "Version", VERSION);
  1624. php_info_print_table_end();
  1625. /* Remove comments if you have entries in php.ini
  1626. DISPLAY_INI_ENTRIES();
  1627. */
  1628. }
  1629. /* }}} */
  1630. #ifdef ZEND_ENGINE_2
  1631. /* {{{ ZEND_METHOD __construct
  1632. *
  1633. * @return void
  1634. */
  1635. ZEND_METHOD(simplate, __construct)
  1636. #else
  1637. /* {{{ PHP_FUNCTION simplate_init
  1638. *
  1639. * @return void
  1640. */
  1641. PHP_FUNCTION(simplate_init)
  1642. #endif // ZEND_ENGINE_2
  1643. {
  1644. #ifdef ZEND_ENGINE_2
  1645. #else
  1646. zval *obj = getThis();
  1647. object_init_ex(obj, simplate_entry_ptr);
  1648. add_property_string(obj, TEMPLATE_DIR, DEFAULT_TEMPLATE_DIR, 1);
  1649. add_property_string(obj, COMPILE_DIR, DEFAULT_COMPILE_DIR, 1);
  1650. add_property_string(obj, CACHE_DIR, DEFAULT_CACHE_DIR, 1);
  1651. add_property_long(obj, CACHING, DEFAULT_CACHING);
  1652. add_property_long(obj, CACHE_LIFETIME, DEFAULT_CACHE_LIFETIME);
  1653. add_property_string(obj, LEFT_DELIMITER, DEFAULT_LEFT_DELIMITER, 1);
  1654. add_property_string(obj, RIGHT_DELIMITER, DEFAULT_RIGHT_DELIMITER, 1);
  1655. add_property_bool(obj, COMPILE_CHECK, DEFAULT_COMPILE_CHECK);
  1656. add_property_bool(obj, FORCE_COMPILE, DEFAULT_FORCE_COMPILE);
  1657. add_property_bool(obj, LAZY_CHECK, DEFAULT_LAZY_CHECK);
  1658. add_property_string(obj, "version", VERSION, 1);
  1659. #endif // ZEND_ENGINE_2
  1660. }
  1661. /* }}} */
  1662. #ifdef ZEND_ENGINE_2
  1663. #else
  1664. /* {{{ Set already exist array on new array recursively(PHP4).
  1665. *
  1666. * @param zval **struc old array
  1667. * @param zval **new_array new array to be set
  1668. *
  1669. * @return void
  1670. */
  1671. static void php_set_r(
  1672. zval **struc,
  1673. zval **new_array
  1674. )
  1675. {
  1676. zval **elem;
  1677. char *k = 0;
  1678. ulong i = 0;
  1679. char buf[128];
  1680. zend_hash_internal_pointer_reset(Z_ARRVAL_PP(struc));
  1681. while (zend_hash_get_current_data(Z_ARRVAL_PP(struc), (void **)&elem) == SUCCESS) {
  1682. zend_hash_get_current_key(Z_ARRVAL_PP(struc), &k, &i, 0);
  1683. sprintf(buf, "%d", i);
  1684. switch (Z_TYPE_PP(elem)) {
  1685. case IS_NULL:
  1686. add_assoc_unset(*new_array, k);
  1687. break;
  1688. case IS_BOOL:
  1689. add_assoc_bool(*new_array, k, Z_BVAL_PP(elem));
  1690. break;
  1691. case IS_LONG:
  1692. add_assoc_long(*new_array, k, Z_LVAL_PP(elem));
  1693. break;
  1694. case IS_DOUBLE:
  1695. add_assoc_double(*new_array, k, Z_DVAL_PP(elem));
  1696. break;
  1697. case IS_STRING:
  1698. add_assoc_stringl(*new_array, k, Z_STRVAL_PP(elem), Z_STRLEN_P(elem)/* (*elem)->value.str.val */, 1);
  1699. break;
  1700. case IS_ARRAY:
  1701. zval_add_ref(elem);
  1702. add_assoc_zval(*new_array, k, *elem);
  1703. }
  1704. zend_hash_move_forward(Z_ARRVAL_PP(struc));
  1705. }
  1706. }
  1707. #endif // ZEND_ENGINE_2
  1708. /* }}} */
  1709. #ifdef ZEND_ENGINE_2
  1710. /* {{{ ZEND_METHOD assign
  1711. *
  1712. * @return void
  1713. */
  1714. ZEND_METHOD(simplate, assign)
  1715. #else
  1716. /* {{{ PHP_FUNCTION simplate_assign
  1717. *
  1718. * @return void
  1719. */
  1720. PHP_FUNCTION(simplate_assign)
  1721. #endif // ZEND_ENGINE_2
  1722. {
  1723. char *key = NULL;
  1724. zval *zvalue;
  1725. int key_len;
  1726. DEBUG_PRINTF("%s", "start function");
  1727. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("sz"), &key, &key_len, &zvalue) == FAILURE) {
  1728. return;
  1729. }
  1730. zval *obj = getThis();
  1731. zval *new_array;
  1732. #ifdef ZEND_ENGINE_2
  1733. new_array = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>("_tpl_vars"), strlen("_tpl_vars"), 1 TSRMLS_CC);
  1734. // initialize.use new_array on the first time.
  1735. if (new_array == EG(uninitialized_zval_ptr) || Z_TYPE_P(new_array) == IS_NULL) {
  1736. MAKE_STD_ZVAL(new_array);
  1737. array_init(new_array);
  1738. Z_DELREF_P(new_array);
  1739. }
  1740. #else
  1741. zval **tmp;
  1742. MAKE_STD_ZVAL(new_array);
  1743. array_init(new_array);
  1744. // the ``_tpl_vars'' exists already.
  1745. if (zend_hash_find(Z_OBJPROP_P(obj), "_tpl_vars", sizeof("_tpl_vars"), (void**)&tmp) == SUCCESS) {
  1746. // set old array to new array recursively.
  1747. php_set_r(tmp, &new_array);
  1748. }
  1749. #endif // ZEND_ENGINE_2
  1750. switch (Z_TYPE_P(zvalue)) {
  1751. case IS_NULL:
  1752. add_assoc_unset(new_array, key);
  1753. break;
  1754. case IS_BOOL:
  1755. add_assoc_bool(new_array, key, Z_BVAL_P(zvalue));
  1756. break;
  1757. case IS_DOUBLE:
  1758. add_assoc_double(new_array, key, Z_DVAL_P(zvalue));
  1759. break;
  1760. case IS_STRING:
  1761. add_assoc_stringl(new_array, key, Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue), 1);
  1762. break;
  1763. case IS_LONG:
  1764. add_assoc_long(new_array, key, Z_LVAL_P(zvalue));
  1765. break;
  1766. case IS_ARRAY:
  1767. zval_add_ref(&zvalue); // don't forget this!
  1768. add_assoc_zval(new_array, key, zvalue);
  1769. break;
  1770. case IS_OBJECT:
  1771. zval_add_ref(&zvalue);
  1772. add_assoc_zval(new_array, key, zvalue);
  1773. }
  1774. #ifdef ZEND_ENGINE_2
  1775. zend_update_property(Z_OBJCE_P(obj), obj, const_cast<char*>("_tpl_vars"), strlen("_tpl_vars"), new_array TSRMLS_CC);
  1776. #else
  1777. zend_hash_update(Z_OBJPROP_P(obj), "_tpl_vars", strlen("_tpl_vars") + 1, &new_array, sizeof(zval*), NULL);
  1778. #endif // ZEND_ENGINE_2
  1779. DEBUG_PRINTF("%s", "end function");
  1780. return;
  1781. }
  1782. /* }}} */
  1783. /* {{{ Outputs to global_string.
  1784. *
  1785. * @param const char *str
  1786. * @param uint strlen
  1787. *
  1788. * @return int returns strlen
  1789. */
  1790. static int php_my_output_func(
  1791. const char *str,
  1792. uint str_len TSRMLS_DC
  1793. )
  1794. {
  1795. SIMPLATE_G(global_string) << str;
  1796. return str_len;
  1797. }
  1798. /* }}} */
  1799. #ifdef ZEND_ENGINE_2
  1800. /* {{{ ZEND_METHOD fetch
  1801. *
  1802. * @return void
  1803. */
  1804. ZEND_METHOD(simplate, fetch)
  1805. #else
  1806. /* {{{ PHP_FUNCTION simplate_fetch
  1807. *
  1808. * @return void
  1809. */
  1810. PHP_FUNCTION(simplate_fetch)
  1811. #endif // ZEND_ENGINE_2
  1812. {
  1813. string error;
  1814. char *fullfile_name = NULL;
  1815. char *fetch_content = NULL;
  1816. DEBUG_PRINTF("%s", "start function");
  1817. read_parse_template(INTERNAL_FUNCTION_PARAM_PASSTHRU, &fullfile_name, SIMPLATE_FETCH, &fetch_content);
  1818. if (fetch_content) {
  1819. RETURN_STRING(fetch_content, 1);
  1820. }
  1821. if (!fullfile_name || strlen(fullfile_name) <= 0) {
  1822. return;
  1823. }
  1824. //
  1825. // Execute compiled file
  1826. //
  1827. zend_file_handle file_handle;
  1828. zend_op_array *op_array;
  1829. file_handle.filename = fullfile_name;
  1830. file_handle.free_filename = 0;
  1831. file_handle.type = ZEND_HANDLE_FILENAME;
  1832. file_handle.opened_path = NULL;
  1833. op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);
  1834. if (!op_array) {
  1835. zend_error(E_ERROR, "Error parsing script:%s", fullfile_name);
  1836. return;
  1837. }
  1838. zend_destroy_file_handle(&file_handle TSRMLS_CC);
  1839. #ifdef USE_ZEND_EXECUTE
  1840. SIMPLATE_G(global_string.str(std::string()));
  1841. int (*old_output_func)(const char*, unsigned int TSRMLS_DC);
  1842. old_output_func = OG(php_body_write);
  1843. OG(php_body_write) = php_my_output_func;
  1844. zend_execute(op_array TSRMLS_CC);
  1845. OG(php_body_write) = old_output_func;
  1846. RETURN_STRING(const_cast<char*>(SIMPLATE_G(global_string).str().c_str()), 1);
  1847. #else
  1848. // ob_start();
  1849. zval *output_handler = NULL;
  1850. zend_bool erase = 1;
  1851. long chunk_size = 0;
  1852. if (php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC) == FAILURE) {
  1853. zend_error(E_ERROR, "Error: fail to ob_start");
  1854. RETURN_FALSE;
  1855. }
  1856. // include
  1857. string include_execute = "include '";
  1858. include_execute += fullfile_name;
  1859. include_execute += "';";
  1860. zend_eval_string(const_cast<char*>(include_execute.c_str()), NULL, const_cast<char*>("simplate") TSRMLS_CC);
  1861. #ifdef ZEND_ENGINE_2
  1862. destroy_op_array(op_array TSRMLS_CC);
  1863. #else
  1864. destroy_op_array(op_array);
  1865. #endif // ZEND_ENGINE_2
  1866. efree(op_array);
  1867. efree(fullfile_name);
  1868. if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
  1869. RETURN_FALSE;
  1870. }
  1871. php_end_ob_buffer(0, 0 TSRMLS_CC);
  1872. #endif // USE_ZEND_EXECUTE
  1873. DEBUG_PRINTF("%s", "end function");
  1874. }
  1875. /* }}} */
  1876. #ifdef ZEND_ENGINE_2
  1877. /* {{{ ZEND_METHOD display
  1878. *
  1879. * @return void
  1880. */
  1881. ZEND_METHOD(simplate, display)
  1882. #else
  1883. /* {{{ PHP_FUNCTION simplate_display
  1884. *
  1885. * @return void
  1886. */
  1887. PHP_FUNCTION(simplate_display)
  1888. #endif // ZEND_ENGINE_2
  1889. {
  1890. DEBUG_PRINTF("%s", "start function");
  1891. char *fullfile_name = NULL;
  1892. read_parse_template(INTERNAL_FUNCTION_PARAM_PASSTHRU, &fullfile_name, SIMPLATE_DISPLAY);
  1893. if (!fullfile_name || strlen(fullfile_name) <= 0) {
  1894. DEBUG_PRINTF("%s", "end function");
  1895. return;
  1896. }
  1897. DEBUG_PRINTF("full file name = (%s)", fullfile_name);
  1898. //
  1899. // Execute compiled file
  1900. //
  1901. #ifdef USE_ZEND_EXECUTE
  1902. zend_file_handle file_handle;
  1903. zend_op_array *op_array;
  1904. file_handle.filename = full_compile_filename;
  1905. file_handle.free_filename = 0;
  1906. file_handle.type = ZEND_HANDLE_FILENAME;
  1907. file_handle.opened_path = NULL;
  1908. op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);
  1909. if (!op_array) {
  1910. zend_error(E_ERROR, "Error parsing script:%s", full_compile_filename.c_str());
  1911. efree(fullfile_name);
  1912. return;
  1913. }
  1914. zend_destroy_file_handle(&file_handle TSRMLS_CC);
  1915. zend_execute(op_array TSRMLS_CC);
  1916. #else
  1917. // This way is safer
  1918. string include_execute = "include '";
  1919. include_execute += fullfile_name;
  1920. include_execute += "';";
  1921. DEBUG_PRINTF("include_execute = (%s)", include_execute.c_str());
  1922. zend_eval_string(const_cast<char*>(include_execute.c_str()), NULL, const_cast<char*>("simplate") TSRMLS_CC);
  1923. #endif // USE_ZEND_EXECUTE
  1924. efree(fullfile_name);
  1925. DEBUG_PRINTF("%s", "end function");
  1926. return;
  1927. }
  1928. /* }}} */
  1929. #ifdef ZEND_ENGINE_2
  1930. /* {{{ ZEND_METHOD clear_cache
  1931. *
  1932. * @return void
  1933. */
  1934. ZEND_METHOD(simplate, clear_cache)
  1935. #else
  1936. /* {{{ PHP_FUNCTION simplate_clear_cache
  1937. *
  1938. * @return void
  1939. */
  1940. PHP_FUNCTION(simplate_clear_cache)
  1941. #endif // ZEND_ENGINE_2
  1942. {
  1943. zval *obj;
  1944. char *resource_name = NULL;
  1945. int resource_name_len = 0;
  1946. long caching = 0;
  1947. char *cache_dir;
  1948. string error;
  1949. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &resource_name, &resource_name_len) == FAILURE) {
  1950. RETURN_FALSE;
  1951. }
  1952. obj = getThis();
  1953. #ifdef ZEND_ENGINE_2
  1954. caching = Z_LVAL_P(zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(CACHING), strlen(CACHING), 1 TSRMLS_CC));
  1955. #else
  1956. #endif // ZEND_ENGINE_2
  1957. if (caching) {
  1958. #ifdef ZEND_ENGINE_2
  1959. cache_dir = Z_STRVAL_P(zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>(CACHE_DIR), strlen(CACHE_DIR), 1 TSRMLS_CC));
  1960. #else
  1961. #endif // ZEND_ENGINE_2
  1962. if (cache_dir[strlen(cache_dir) - 1] == DEFAULT_SLASH) {
  1963. cache_dir[strlen(cache_dir) - 1] = '\0';
  1964. }
  1965. struct stat cache_stat;
  1966. // cache directory exists?
  1967. if (VCWD_STAT(cache_dir, &cache_stat) != -1) {
  1968. if (!S_ISDIR(cache_stat.st_mode)) {
  1969. zend_error(E_ERROR, "does not exist cache directory:%s", cache_dir);
  1970. }
  1971. }
  1972. string full_cache_filename(cache_dir);
  1973. full_cache_filename += DEFAULT_SLASH;
  1974. full_cache_filename += resource_name;
  1975. if (VCWD_STAT(full_cache_filename.c_str(), &cache_stat) != -1) {
  1976. unlink(full_cache_filename.c_str());
  1977. }
  1978. }
  1979. }
  1980. /* }}} */
  1981. /* {{{ Registers filter into plugins.
  1982. *
  1983. * @param INTERNAL_FUNCTION_PARAMETERS see zend.h
  1984. * @param char *filter_name filter's name
  1985. *
  1986. * @return void
  1987. */
  1988. void register_plugins(INTERNAL_FUNCTION_PARAMETERS, char *filter_name)
  1989. {
  1990. char *function_name = NULL;
  1991. int function_name_len = 0;
  1992. DEBUG_PRINTF("%s", "start function");
  1993. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &function_name, &function_name_len) == FAILURE) {
  1994. return;
  1995. }
  1996. DEBUG_PRINTF("filter_name = (%s)", filter_name);
  1997. DEBUG_PRINTF("function_name = (%s)", function_name);
  1998. zval *obj = getThis();
  1999. zval *_plugins;
  2000. #ifdef ZEND_ENGINE_2
  2001. _plugins = zend_read_property(Z_OBJCE_P(obj), obj, const_cast<char*>("_plugins"), strlen("_plugins"), 1 TSRMLS_CC);
  2002. // initialize.use _plugins on the first time.
  2003. if (_plugins == EG(uninitialized_zval_ptr) || Z_TYPE_P(_plugins) == IS_NULL) {
  2004. MAKE_STD_ZVAL(_plugins);
  2005. array_init(_plugins);
  2006. Z_DELREF_P(_plugins);
  2007. }
  2008. #else
  2009. #endif // ZEND_ENGINE_2
  2010. //php_var_dump(&_plugins, 1 TSRMLS_CC);
  2011. zval **zfilter;
  2012. // filter
  2013. if (zend_hash_find(Z_ARRVAL_P(_plugins), filter_name, strlen(filter_name) + 1, (void**)&zfilter) == SUCCESS) {
  2014. //php_var_dump(zfilter, 1 TSRMLS_CC);
  2015. add_assoc_string(*zfilter, function_name, function_name, 1);
  2016. } else {
  2017. zval *data;
  2018. MAKE_STD_ZVAL(data);
  2019. array_init(data);
  2020. add_assoc_string(data, function_name, function_name, 1);
  2021. add_assoc_zval(_plugins, filter_name, data);
  2022. }
  2023. #ifdef ZEND_ENGINE_2
  2024. zend_update_property(Z_OBJCE_P(obj), obj, const_cast<char*>("_plugins"), strlen("_plugins"), _plugins TSRMLS_CC);
  2025. #else
  2026. #endif // ZEND_ENGINE_2
  2027. DEBUG_PRINTF("%s", "end function");
  2028. }
  2029. /* }}} */
  2030. #ifdef ZEND_ENGINE_2
  2031. /* {{{ ZEND_METHOD register_prefilter
  2032. *
  2033. * @return void
  2034. */
  2035. ZEND_METHOD(simplate, register_prefilter)
  2036. #else
  2037. /* {{{ PHP_FUNCTION simplate_register_prefilter
  2038. *
  2039. * @return void
  2040. */
  2041. PHP_FUNCTION(simplate_register_prefilter)
  2042. #endif // ZEND_ENGINE_2
  2043. {
  2044. register_plugins(INTERNAL_FUNCTION_PARAM_PASSTHRU, const_cast<char*>("prefilter"));
  2045. }
  2046. /* }}} */
  2047. #ifdef ZEND_ENGINE_2
  2048. /* {{{ ZEND_METHOD register_postfilter
  2049. *
  2050. * @return void
  2051. */
  2052. ZEND_METHOD(simplate, register_postfilter)
  2053. #else
  2054. /* {{{ PHP_FUNCTION simplate_register_postfilter
  2055. *
  2056. * @return void
  2057. */
  2058. PHP_FUNCTION(simplate_register_postfilter)
  2059. #endif // ZEND_ENGINE_2
  2060. {
  2061. register_plugins(INTERNAL_FUNCTION_PARAM_PASSTHRU, const_cast<char*>("postfilter"));
  2062. }
  2063. /* }}} */
  2064. /*
  2065. * Local variables:
  2066. * tab-width: 4
  2067. * c-basic-offset: 4
  2068. * indent-tabs-mode: nil
  2069. * End:
  2070. * vim600: noet sw=4 ts=4 sts=4 fdm=marker
  2071. * vim<600: noet sw=4 ts=4 sts=4
  2072. */