PageRenderTime 26ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/routes/yaf_route_regex.c

https://gitlab.com/oytunistrator/yaf
C | 411 lines | 286 code | 72 blank | 53 comment | 109 complexity | 8f0dee2daf8681e1f29487139693016b MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Yet Another Framework |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Xinchen Hui <laruence@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include "ext/pcre/php_pcre.h"
  21. #include "php_yaf.h"
  22. #include "yaf_namespace.h"
  23. #include "yaf_exception.h"
  24. #include "yaf_request.h"
  25. #include "yaf_router.h"
  26. #include "routes/yaf_route_interface.h"
  27. #include "routes/yaf_route_regex.h"
  28. #include "ext/standard/php_string.h"
  29. #include "ext/standard/php_smart_str.h" /* for smart_str */
  30. zend_class_entry *yaf_route_regex_ce;
  31. /** {{{ ARG_INFO
  32. */
  33. ZEND_BEGIN_ARG_INFO_EX(yaf_route_regex_construct_arginfo, 0, 0, 2)
  34. ZEND_ARG_INFO(0, match)
  35. ZEND_ARG_ARRAY_INFO(0, route, 0)
  36. ZEND_ARG_ARRAY_INFO(0, map, 1)
  37. ZEND_ARG_ARRAY_INFO(0, verify, 1)
  38. ZEND_ARG_INFO(0, reverse)
  39. ZEND_END_ARG_INFO()
  40. /* }}} */
  41. /** {{{ yaf_route_t * yaf_route_regex_instance(yaf_route_t *this_ptr, zval *route, zval *def, zval *map, zval *verify, zval reverse TSRMLS_DC)
  42. */
  43. yaf_route_t * yaf_route_regex_instance(yaf_route_t *this_ptr, zval *route, zval *def, zval *map, zval *verify, zval *reverse TSRMLS_DC) {
  44. yaf_route_t *instance;
  45. if (this_ptr) {
  46. instance = this_ptr;
  47. } else {
  48. MAKE_STD_ZVAL(instance);
  49. object_init_ex(instance, yaf_route_regex_ce);
  50. }
  51. zend_update_property(yaf_route_regex_ce, instance, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_MATCH), route TSRMLS_CC);
  52. zend_update_property(yaf_route_regex_ce, instance, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_ROUTE), def TSRMLS_CC);
  53. if (map) {
  54. zend_update_property(yaf_route_regex_ce, instance, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_MAP), map TSRMLS_CC);
  55. }
  56. if (!verify) {
  57. zend_update_property_null(yaf_route_regex_ce, instance, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_VERIFY) TSRMLS_CC);
  58. } else {
  59. zend_update_property(yaf_route_regex_ce, instance, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_VERIFY), verify TSRMLS_CC);
  60. }
  61. if (!reverse || IS_STRING != Z_TYPE_P(reverse)) {
  62. zend_update_property_null(yaf_route_regex_ce, instance, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_REVERSE) TSRMLS_CC);
  63. } else {
  64. zend_update_property(yaf_route_regex_ce, instance, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_REVERSE), reverse TSRMLS_CC);
  65. }
  66. return instance;
  67. }
  68. /* }}} */
  69. /** {{{ static zval * yaf_route_regex_match(yaf_route_t *router, char *uri, int len TSRMLS_DC)
  70. */
  71. static zval * yaf_route_regex_match(yaf_route_t *route, char *uri, int len TSRMLS_DC) {
  72. zval *match;
  73. pcre_cache_entry *pce_regexp;
  74. if (!len) {
  75. return NULL;
  76. }
  77. match = zend_read_property(yaf_route_regex_ce, route, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_MATCH), 1 TSRMLS_CC);
  78. if ((pce_regexp = pcre_get_compiled_regex_cache(Z_STRVAL_P(match), Z_STRLEN_P(match) TSRMLS_CC)) == NULL) {
  79. return NULL;
  80. } else {
  81. zval matches, *subparts, *map;
  82. MAKE_STD_ZVAL(subparts);
  83. ZVAL_NULL(subparts);
  84. map = zend_read_property(yaf_route_regex_ce, route, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_MAP), 1 TSRMLS_CC);
  85. if (IS_ARRAY != Z_TYPE_P(map)) {
  86. map = NULL;
  87. }
  88. php_pcre_match_impl(pce_regexp, uri, len, &matches, subparts /* subpats */,
  89. 0/* global */, 0/* ZEND_NUM_ARGS() >= 4 */, 0/*flags PREG_OFFSET_CAPTURE*/, 0/* start_offset */ TSRMLS_CC);
  90. if (!zend_hash_num_elements(Z_ARRVAL_P(subparts))) {
  91. zval_ptr_dtor(&subparts);
  92. return NULL;
  93. } else {
  94. zval *ret, **name, **ppzval;
  95. char *key = NULL;
  96. uint len = 0;
  97. ulong idx = 0;
  98. HashTable *ht;
  99. MAKE_STD_ZVAL(ret);
  100. array_init(ret);
  101. ht = Z_ARRVAL_P(subparts);
  102. for(zend_hash_internal_pointer_reset(ht);
  103. zend_hash_has_more_elements(ht) == SUCCESS;
  104. zend_hash_move_forward(ht)) {
  105. if (zend_hash_get_current_data(ht, (void**)&ppzval) == FAILURE) {
  106. continue;
  107. }
  108. if (zend_hash_get_current_key_ex(ht, &key, &len, &idx, 0, NULL) == HASH_KEY_IS_LONG) {
  109. if (map && zend_hash_index_find(Z_ARRVAL_P(map), idx, (void **)&name) == SUCCESS && Z_TYPE_PP(name) == IS_STRING) {
  110. Z_ADDREF_P(*ppzval);
  111. zend_hash_update(Z_ARRVAL_P(ret), Z_STRVAL_PP(name), Z_STRLEN_PP(name) + 1, (void **)ppzval, sizeof(zval *), NULL);
  112. }
  113. } else {
  114. Z_ADDREF_P(*ppzval);
  115. zend_hash_update(Z_ARRVAL_P(ret), key, len, (void **)ppzval, sizeof(zval *), NULL);
  116. }
  117. }
  118. zval_ptr_dtor(&subparts);
  119. return ret;
  120. }
  121. }
  122. return NULL;
  123. }
  124. /* }}} */
  125. /** {{{ zval * yaf_route_regex_assemble(yaf_route_t *this_ptr, zval *info, zval *query TSRMLS_DC)
  126. */
  127. zval * yaf_route_regex_assemble(yaf_route_t *this_ptr, zval *info, zval *query TSRMLS_DC) {
  128. zval *reverse, *uri;
  129. zval **tmp;
  130. char *tstr, *inter;
  131. int tlen;
  132. smart_str squery = {0};
  133. reverse = zend_read_property(yaf_route_regex_ce, this_ptr, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_REVERSE), 0 TSRMLS_CC);
  134. if (Z_TYPE_P(reverse) != IS_STRING) {
  135. yaf_trigger_error(YAF_ERR_TYPE_ERROR TSRMLS_CC, "%s", "Reverse property is not a valid string");
  136. return NULL;
  137. }
  138. MAKE_STD_ZVAL(uri);
  139. tstr = estrndup(Z_STRVAL_P(reverse), Z_STRLEN_P(reverse));
  140. tlen = Z_STRLEN_P(reverse);
  141. if (zend_hash_find(Z_ARRVAL_P(info), ZEND_STRS(YAF_ROUTE_ASSEMBLE_MOUDLE_FORMAT), (void **)&tmp) == SUCCESS) {
  142. inter = php_str_to_str(tstr, tlen, ZEND_STRL(YAF_ROUTE_ASSEMBLE_MOUDLE_FORMAT), Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &tlen);
  143. efree(tstr);
  144. tstr = inter;
  145. }
  146. if (zend_hash_find(Z_ARRVAL_P(info), ZEND_STRS(YAF_ROUTE_ASSEMBLE_CONTROLLER_FORMAT), (void **)&tmp) == SUCCESS) {
  147. inter = php_str_to_str(tstr, tlen, ZEND_STRL(YAF_ROUTE_ASSEMBLE_CONTROLLER_FORMAT), Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &tlen);
  148. efree(tstr);
  149. tstr = inter;
  150. }
  151. if (zend_hash_find(Z_ARRVAL_P(info), ZEND_STRS(YAF_ROUTE_ASSEMBLE_ACTION_FORMAT), (void **)&tmp) == SUCCESS) {
  152. inter = php_str_to_str(tstr, tlen, ZEND_STRL(YAF_ROUTE_ASSEMBLE_ACTION_FORMAT), Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &tlen);
  153. efree(tstr);
  154. tstr = inter;
  155. }
  156. if (query && IS_ARRAY == Z_TYPE_P(query)) {
  157. uint key_len;
  158. char *key;
  159. ulong key_idx;
  160. HashTable *ht = Z_ARRVAL_P(query);
  161. smart_str_appendc(&squery, '?');
  162. for (zend_hash_internal_pointer_reset(ht);
  163. zend_hash_get_current_data(ht, (void **)&tmp) == SUCCESS;
  164. zend_hash_move_forward(ht)) {
  165. if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(ht, &key, &key_len, &key_idx, 0, NULL)) {
  166. if (IS_STRING == Z_TYPE_PP(tmp)) {
  167. smart_str_appendl(&squery, key, key_len - 1);
  168. smart_str_appendc(&squery, '=');
  169. smart_str_appendl(&squery, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
  170. smart_str_appendc(&squery, '&');
  171. }
  172. }
  173. }
  174. }
  175. if (squery.len) {
  176. squery.len--; /* get rid of the tail & */
  177. smart_str_0(&squery);
  178. tstr = erealloc(tstr, tlen + squery.len + 1);
  179. memcpy(tstr + tlen, squery.c, squery.len);
  180. tlen += squery.len;
  181. tstr[tlen] = '\0';
  182. }
  183. ZVAL_STRINGL(uri, tstr, tlen, 0);
  184. smart_str_free(&squery);
  185. return uri;
  186. }
  187. /** }}} */
  188. /** {{{ int yaf_route_regex_route(yaf_route_t *router, yaf_request_t *request TSRMLS_DC)
  189. */
  190. int yaf_route_regex_route(yaf_route_t *router, yaf_request_t *request TSRMLS_DC) {
  191. char *request_uri;
  192. zval *args, *base_uri, *zuri;
  193. zuri = zend_read_property(yaf_request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_URI), 1 TSRMLS_CC);
  194. base_uri = zend_read_property(yaf_request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_BASE), 1 TSRMLS_CC);
  195. if (base_uri && IS_STRING == Z_TYPE_P(base_uri)
  196. && !strncasecmp(Z_STRVAL_P(zuri), Z_STRVAL_P(base_uri), Z_STRLEN_P(base_uri))) {
  197. request_uri = estrdup(Z_STRVAL_P(zuri) + Z_STRLEN_P(base_uri));
  198. } else {
  199. request_uri = estrdup(Z_STRVAL_P(zuri));
  200. }
  201. if (!(args = yaf_route_regex_match(router, request_uri, strlen(request_uri) TSRMLS_CC))) {
  202. efree(request_uri);
  203. return 0;
  204. } else {
  205. zval **module, **controller, **action, *routes;
  206. routes = zend_read_property(yaf_route_regex_ce, router, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_ROUTE), 1 TSRMLS_CC);
  207. if (zend_hash_find(Z_ARRVAL_P(routes), ZEND_STRS("module"), (void **)&module) == SUCCESS && IS_STRING == Z_TYPE_PP(module)) {
  208. if (Z_STRVAL_PP(module)[0] != ':') {
  209. zend_update_property(yaf_request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_MODULE), *module TSRMLS_CC);
  210. } else {
  211. zval **m;
  212. if (zend_hash_find(Z_ARRVAL_P(args), Z_STRVAL_PP(module) + 1, Z_STRLEN_PP(module), (void **)&m) == SUCCESS && IS_STRING == Z_TYPE_PP(m)) {
  213. zend_update_property(yaf_request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_MODULE), *m TSRMLS_CC);
  214. }
  215. }
  216. }
  217. if (zend_hash_find(Z_ARRVAL_P(routes), ZEND_STRS("controller"), (void **)&controller) == SUCCESS && IS_STRING == Z_TYPE_PP(controller)) {
  218. if (Z_STRVAL_PP(controller)[0] != ':') {
  219. zend_update_property(yaf_request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_CONTROLLER), *controller TSRMLS_CC);
  220. } else {
  221. zval **c;
  222. if (zend_hash_find(Z_ARRVAL_P(args), Z_STRVAL_PP(controller) + 1, Z_STRLEN_PP(controller), (void **)&c) == SUCCESS && IS_STRING == Z_TYPE_PP(c)) {
  223. zend_update_property(yaf_request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_CONTROLLER), *c TSRMLS_CC);
  224. }
  225. }
  226. }
  227. if (zend_hash_find(Z_ARRVAL_P(routes), ZEND_STRS("action"), (void **)&action) == SUCCESS && IS_STRING == Z_TYPE_PP(action)) {
  228. if (Z_STRVAL_PP(action)[0] != ':') {
  229. zend_update_property(yaf_request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_ACTION), *action TSRMLS_CC);
  230. } else {
  231. zval **a;
  232. if (zend_hash_find(Z_ARRVAL_P(args), Z_STRVAL_PP(action) + 1, Z_STRLEN_PP(action), (void **)&a) == SUCCESS && IS_STRING == Z_TYPE_PP(a)) {
  233. zend_update_property(yaf_request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_ACTION), *a TSRMLS_CC);
  234. }
  235. }
  236. }
  237. (void)yaf_request_set_params_multi(request, args TSRMLS_CC);
  238. zval_ptr_dtor(&args);
  239. efree(request_uri);
  240. }
  241. return 1;
  242. }
  243. /* }}} */
  244. /** {{{ proto public Yaf_Route_Regex::route(string $uri)
  245. */
  246. PHP_METHOD(yaf_route_regex, route) {
  247. yaf_route_t *route;
  248. yaf_request_t *request;
  249. route = getThis();
  250. RETVAL_FALSE;
  251. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, yaf_request_ce) == FAILURE) {
  252. return;
  253. }
  254. if (!request || IS_OBJECT != Z_TYPE_P(request)
  255. || !instanceof_function(Z_OBJCE_P(request), yaf_request_ce TSRMLS_CC)) {
  256. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expects a %s instance", yaf_request_ce->name);
  257. RETURN_FALSE;
  258. }
  259. RETURN_BOOL(yaf_route_regex_route(route, request TSRMLS_CC));
  260. }
  261. /** }}} */
  262. /** {{{ proto public Yaf_Route_Regex::__construct(string $match, array $route, array $map = NULL, array $verify = NULL, string reverse = NULL)
  263. */
  264. PHP_METHOD(yaf_route_regex, __construct) {
  265. zval *match, *route, *map = NULL, *verify = NULL, *reverse = NULL;
  266. yaf_route_t *self = getThis();
  267. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|aaz", &match, &route, &map, &verify, &reverse) == FAILURE) {
  268. YAF_UNINITIALIZED_OBJECT(getThis());
  269. return;
  270. }
  271. if (IS_STRING != Z_TYPE_P(match) || !Z_STRLEN_P(match)) {
  272. YAF_UNINITIALIZED_OBJECT(getThis());
  273. yaf_trigger_error(YAF_ERR_TYPE_ERROR TSRMLS_CC, "Expects a valid string as the first parameter", yaf_route_regex_ce->name);
  274. RETURN_FALSE;
  275. }
  276. if (verify && IS_ARRAY != Z_TYPE_P(verify)) {
  277. YAF_UNINITIALIZED_OBJECT(getThis());
  278. yaf_trigger_error(YAF_ERR_TYPE_ERROR TSRMLS_CC, "Expects an array as third parameter", yaf_route_regex_ce->name);
  279. RETURN_FALSE;
  280. }
  281. if (reverse && IS_STRING != Z_TYPE_P(reverse)) {
  282. YAF_UNINITIALIZED_OBJECT(getThis());
  283. yaf_trigger_error(YAF_ERR_TYPE_ERROR TSRMLS_CC, "Expects a valid string reverse as fourth parameter");
  284. RETURN_FALSE;
  285. }
  286. (void)yaf_route_regex_instance(self, match, route, map, verify, reverse TSRMLS_CC);
  287. if (self) {
  288. RETURN_ZVAL(self, 1, 0);
  289. }
  290. RETURN_FALSE;
  291. }
  292. /** }}} */
  293. /** {{{ proto public Yaf_Route_regex::assemble(array $info[, array $query = NULL])
  294. */
  295. PHP_METHOD(yaf_route_regex, assemble) {
  296. zval *info, *query = NULL, *return_uri = NULL;
  297. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|a", &info, &query) == FAILURE) {
  298. return;
  299. } else {
  300. if ((return_uri = yaf_route_regex_assemble(getThis(), info, query TSRMLS_CC))) {
  301. RETURN_ZVAL(return_uri, 0, 1);
  302. }
  303. }
  304. RETURN_FALSE;
  305. }
  306. /* }}} */
  307. /** {{{ yaf_route_regex_methods
  308. */
  309. zend_function_entry yaf_route_regex_methods[] = {
  310. PHP_ME(yaf_route_regex, __construct, yaf_route_regex_construct_arginfo, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
  311. PHP_ME(yaf_route_regex, route, yaf_route_route_arginfo, ZEND_ACC_PUBLIC)
  312. PHP_ME(yaf_route_regex, assemble, yaf_route_assemble_arginfo, ZEND_ACC_PUBLIC)
  313. {NULL, NULL, NULL}
  314. };
  315. /* }}} */
  316. /** {{{ YAF_STARTUP_FUNCTION
  317. */
  318. YAF_STARTUP_FUNCTION(route_regex) {
  319. zend_class_entry ce;
  320. YAF_INIT_CLASS_ENTRY(ce, "Yaf_Route_Regex", "Yaf\\Route\\Regex", yaf_route_regex_methods);
  321. yaf_route_regex_ce = zend_register_internal_class_ex(&ce, yaf_route_ce, NULL TSRMLS_CC);
  322. zend_class_implements(yaf_route_regex_ce TSRMLS_CC, 1, yaf_route_ce);
  323. yaf_route_regex_ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
  324. zend_declare_property_null(yaf_route_regex_ce, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_MATCH), ZEND_ACC_PROTECTED TSRMLS_CC);
  325. zend_declare_property_null(yaf_route_regex_ce, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_ROUTE), ZEND_ACC_PROTECTED TSRMLS_CC);
  326. zend_declare_property_null(yaf_route_regex_ce, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_MAP), ZEND_ACC_PROTECTED TSRMLS_CC);
  327. zend_declare_property_null(yaf_route_regex_ce, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_VERIFY), ZEND_ACC_PROTECTED TSRMLS_CC);
  328. zend_declare_property_null(yaf_route_regex_ce, ZEND_STRL(YAF_ROUTE_PROPETY_NAME_REVERSE), ZEND_ACC_PROTECTED TSRMLS_CC);
  329. return SUCCESS;
  330. }
  331. /* }}} */
  332. /*
  333. * Local variables:
  334. * tab-width: 4
  335. * c-basic-offset: 4
  336. * End:
  337. * vim600: noet sw=4 ts=4 fdm=marker
  338. * vim<600: noet sw=4 ts=4
  339. */