├── README.rst └── ext └── twig ├── config.m4 ├── .gitignore ├── LICENSE ├── php_twig.h └── twig.c /README.rst: -------------------------------------------------------------------------------- 1 | This repository is outdated and no longer maintained. 2 | 3 | The extension is now part of the normal Twig repository at 4 | https://github.com/twigphp/Twig 5 | -------------------------------------------------------------------------------- /ext/twig/config.m4: -------------------------------------------------------------------------------- 1 | dnl config.m4 for extension twig 2 | 3 | PHP_ARG_ENABLE(twig, whether to enable twig support, 4 | [ --enable-twig Enable twig support]) 5 | 6 | if test "$PHP_TWIG" != "no"; then 7 | PHP_NEW_EXTENSION(twig, twig.c, $ext_shared) 8 | fi 9 | -------------------------------------------------------------------------------- /ext/twig/.gitignore: -------------------------------------------------------------------------------- 1 | *.sw* 2 | .deps 3 | Makefile 4 | Makefile.fragments 5 | Makefile.global 6 | Makefile.objects 7 | acinclude.m4 8 | aclocal.m4 9 | build/ 10 | config.cache 11 | config.guess 12 | config.h 13 | config.h.in 14 | config.log 15 | config.nice 16 | config.status 17 | config.sub 18 | configure 19 | configure.in 20 | install-sh 21 | libtool 22 | ltmain.sh 23 | missing 24 | mkinstalldirs 25 | run-tests.php 26 | twig.loT 27 | .libs/ 28 | modules/ 29 | twig.la 30 | twig.lo 31 | -------------------------------------------------------------------------------- /ext/twig/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Derick Rethans 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /ext/twig/php_twig.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Twig Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2011 Derick Rethans | 6 | +----------------------------------------------------------------------+ 7 | | Redistribution and use in source and binary forms, with or without | 8 | | modification, are permitted provided that the conditions mentioned | 9 | | in the accompanying LICENSE file are met (BSD, revised). | 10 | +----------------------------------------------------------------------+ 11 | | Author: Derick Rethans | 12 | +----------------------------------------------------------------------+ 13 | */ 14 | 15 | #ifndef PHP_TWIG_H 16 | #define PHP_TWIG_H 17 | 18 | #include "php.h" 19 | 20 | extern zend_module_entry twig_module_entry; 21 | #define phpext_twig_ptr &twig_module_entry 22 | 23 | #ifdef PHP_WIN32 24 | #define PHP_TWIG_API __declspec(dllexport) 25 | #else 26 | #define PHP_TWIG_API 27 | #endif 28 | 29 | #ifdef ZTS 30 | #include "TSRM.h" 31 | #endif 32 | 33 | PHP_FUNCTION(twig_template_get_attributes); 34 | 35 | PHP_MINIT_FUNCTION(twig); 36 | PHP_MSHUTDOWN_FUNCTION(twig); 37 | PHP_RINIT_FUNCTION(twig); 38 | PHP_RSHUTDOWN_FUNCTION(twig); 39 | PHP_MINFO_FUNCTION(twig); 40 | 41 | ZEND_BEGIN_MODULE_GLOBALS(twig) 42 | ZEND_END_MODULE_GLOBALS(twig) 43 | 44 | #ifdef ZTS 45 | #define TWIG_G(v) TSRMG(twig_globals_id, zend_twig_globals *, v) 46 | #else 47 | #define TWIG_G(v) (twig_globals.v) 48 | #endif 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /ext/twig/twig.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Twig Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2011 Derick Rethans | 6 | +----------------------------------------------------------------------+ 7 | | Redistribution and use in source and binary forms, with or without | 8 | | modification, are permitted provided that the conditions mentioned | 9 | | in the accompanying LICENSE file are met (BSD, revised). | 10 | +----------------------------------------------------------------------+ 11 | | Author: Derick Rethans | 12 | +----------------------------------------------------------------------+ 13 | */ 14 | 15 | #ifdef HAVE_CONFIG_H 16 | #include "config.h" 17 | #endif 18 | 19 | #include "php.h" 20 | #include "php_ini.h" 21 | #include "ext/standard/info.h" 22 | #include "php_twig.h" 23 | #include "ext/standard/php_string.h" 24 | #include "ext/standard/php_smart_str.h" 25 | 26 | #include "Zend/zend_object_handlers.h" 27 | #include "Zend/zend_interfaces.h" 28 | #include "Zend/zend_exceptions.h" 29 | 30 | ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 6) 31 | ZEND_ARG_INFO(0, template) 32 | ZEND_ARG_INFO(0, object) 33 | ZEND_ARG_INFO(0, item) 34 | ZEND_ARG_INFO(0, arguments) 35 | ZEND_ARG_INFO(0, type) 36 | ZEND_ARG_INFO(0, isDefinedTest) 37 | ZEND_END_ARG_INFO() 38 | 39 | zend_function_entry twig_functions[] = { 40 | PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args) 41 | {NULL, NULL, NULL} 42 | }; 43 | 44 | 45 | zend_module_entry twig_module_entry = { 46 | #if ZEND_MODULE_API_NO >= 20010901 47 | STANDARD_MODULE_HEADER, 48 | #endif 49 | "twig", 50 | twig_functions, 51 | PHP_MINIT(twig), 52 | PHP_MSHUTDOWN(twig), 53 | PHP_RINIT(twig), 54 | PHP_RSHUTDOWN(twig), 55 | PHP_MINFO(twig), 56 | #if ZEND_MODULE_API_NO >= 20010901 57 | "0.0.1", 58 | #endif 59 | STANDARD_MODULE_PROPERTIES 60 | }; 61 | 62 | 63 | #ifdef COMPILE_DL_TWIG 64 | ZEND_GET_MODULE(twig) 65 | #endif 66 | 67 | ZEND_DECLARE_MODULE_GLOBALS(twig) 68 | 69 | PHP_INI_BEGIN() 70 | PHP_INI_END() 71 | 72 | static void twig_init_globals(zend_twig_globals *twig_globals) 73 | { 74 | } 75 | 76 | 77 | PHP_MINIT_FUNCTION(twig) 78 | { 79 | ZEND_INIT_MODULE_GLOBALS(twig, twig_init_globals, NULL); 80 | REGISTER_INI_ENTRIES(); 81 | 82 | return SUCCESS; 83 | } 84 | 85 | 86 | PHP_MSHUTDOWN_FUNCTION(twig) 87 | { 88 | UNREGISTER_INI_ENTRIES(); 89 | 90 | return SUCCESS; 91 | } 92 | 93 | 94 | 95 | PHP_RINIT_FUNCTION(twig) 96 | { 97 | return SUCCESS; 98 | } 99 | 100 | 101 | 102 | PHP_RSHUTDOWN_FUNCTION(twig) 103 | { 104 | return SUCCESS; 105 | } 106 | 107 | 108 | PHP_MINFO_FUNCTION(twig) 109 | { 110 | php_info_print_table_start(); 111 | php_info_print_table_header(2, "twig support", "enabled"); 112 | php_info_print_table_end(); 113 | 114 | DISPLAY_INI_ENTRIES(); 115 | 116 | } 117 | 118 | int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key) 119 | { 120 | if (Z_TYPE_P(array) != IS_ARRAY) { 121 | return 0; 122 | } 123 | convert_to_string(key); 124 | return zend_symtable_exists(Z_ARRVAL_P(array), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1); 125 | } 126 | 127 | int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC) 128 | { 129 | if (Z_TYPE_P(object) != IS_OBJECT) { 130 | return 0; 131 | } 132 | return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC); 133 | } 134 | 135 | int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC) 136 | { 137 | zend_class_entry **pce; 138 | if (Z_TYPE_P(object) != IS_OBJECT) { 139 | return 0; 140 | } 141 | if (zend_lookup_class(interface, strlen(interface), &pce TSRMLS_CC) == FAILURE) { 142 | return 0; 143 | } 144 | return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC); 145 | } 146 | 147 | zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC) 148 | { 149 | zend_class_entry *ce = Z_OBJCE_P(object); 150 | zval *retval; 151 | 152 | if (Z_TYPE_P(object) == IS_OBJECT) { 153 | SEPARATE_ARG_IF_REF(offset); 154 | zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset); 155 | 156 | zval_ptr_dtor(&offset); 157 | 158 | if (!retval) { 159 | if (!EG(exception)) { 160 | zend_error_noreturn(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); 161 | } 162 | return NULL; 163 | } 164 | 165 | return retval; 166 | } 167 | return NULL; 168 | } 169 | 170 | int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC) 171 | { 172 | zend_class_entry *ce = Z_OBJCE_P(object); 173 | zval *retval; 174 | 175 | if (Z_TYPE_P(object) == IS_OBJECT) { 176 | SEPARATE_ARG_IF_REF(offset); 177 | zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset); 178 | 179 | zval_ptr_dtor(&offset); 180 | 181 | if (!retval) { 182 | if (!EG(exception)) { 183 | zend_error_noreturn(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); 184 | } 185 | return 0; 186 | } 187 | 188 | return (retval && Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval)); 189 | } 190 | return 0; 191 | } 192 | 193 | char *TWIG_STRTOLOWER_ZVAL(zval *item) 194 | { 195 | char *item_dup; 196 | 197 | if (Z_TYPE_P(item) != IS_STRING) { 198 | return NULL; 199 | } 200 | item_dup = estrndup(Z_STRVAL_P(item), Z_STRLEN_P(item)); 201 | php_strtolower(item_dup, Z_STRLEN_P(item)); 202 | return item_dup; 203 | } 204 | 205 | zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC) 206 | { 207 | zend_fcall_info fci; 208 | zval ***args = NULL; 209 | int arg_count = 0; 210 | HashTable *table; 211 | HashPosition pos; 212 | int i = 0; 213 | zval *retval_ptr; 214 | zval *zfunction; 215 | 216 | if (arguments) { 217 | table = HASH_OF(arguments); 218 | args = safe_emalloc(sizeof(zval **), table->nNumOfElements, 0); 219 | 220 | zend_hash_internal_pointer_reset_ex(table, &pos); 221 | 222 | while (zend_hash_get_current_data_ex(table, (void **)&args[i], &pos) == SUCCESS) { 223 | i++; 224 | zend_hash_move_forward_ex(table, &pos); 225 | } 226 | arg_count = table->nNumOfElements; 227 | } 228 | 229 | MAKE_STD_ZVAL(zfunction); 230 | ZVAL_STRING(zfunction, function, 1); 231 | fci.size = sizeof(fci); 232 | fci.function_table = EG(function_table); 233 | fci.function_name = zfunction; 234 | fci.symbol_table = NULL; 235 | #if PHP_VERSION_ID >= 50300 236 | fci.object_ptr = object; 237 | #else 238 | fci.object_pp = &object; 239 | #endif 240 | fci.retval_ptr_ptr = &retval_ptr; 241 | fci.param_count = arg_count; 242 | fci.params = args; 243 | fci.no_separation = 0; 244 | 245 | if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { 246 | zval_dtor(zfunction); 247 | efree(zfunction); 248 | zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", zend_get_class_entry(object TSRMLS_CC)->name, function TSRMLS_CC); 249 | } 250 | 251 | if (args) { 252 | efree(fci.params); 253 | } 254 | zval_dtor(zfunction); 255 | efree(zfunction); 256 | return retval_ptr; 257 | } 258 | 259 | int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC) 260 | { 261 | zval *ret; 262 | int res; 263 | 264 | ret = TWIG_CALL_USER_FUNC_ARRAY(object, functionName, NULL TSRMLS_CC); 265 | res = Z_LVAL_P(ret); 266 | zval_ptr_dtor(&ret); 267 | return res; 268 | } 269 | 270 | zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC) 271 | { 272 | zval **tmp_zval; 273 | zend_class_entry *ce; 274 | 275 | if (class == NULL || Z_TYPE_P(class) != IS_OBJECT) { 276 | return NULL; 277 | } 278 | 279 | ce = zend_get_class_entry(class TSRMLS_CC); 280 | #if PHP_VERSION_ID >= 50400 281 | tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0, NULL TSRMLS_CC); 282 | #else 283 | tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0 TSRMLS_CC); 284 | #endif 285 | return *tmp_zval; 286 | } 287 | 288 | zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC) 289 | { 290 | zval **tmp_zval; 291 | char *tmp_name; 292 | 293 | if (class == NULL || Z_TYPE_P(class) != IS_ARRAY || Z_TYPE_P(prop_name) != IS_STRING) { 294 | if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) { 295 | // array access object 296 | return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC); 297 | } 298 | return NULL; 299 | } 300 | 301 | convert_to_string(prop_name); 302 | tmp_name = Z_STRVAL_P(prop_name); 303 | if (zend_symtable_find(HASH_OF(class), tmp_name, strlen(tmp_name)+1, (void**) &tmp_zval) == SUCCESS) { 304 | return *tmp_zval; 305 | } 306 | return NULL; 307 | } 308 | 309 | zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC) 310 | { 311 | zval **tmp_zval; 312 | 313 | if (class == NULL/* || Z_TYPE_P(class) != IS_ARRAY*/) { 314 | return NULL; 315 | } 316 | 317 | if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) { 318 | // array access object 319 | zval *tmp_name_zval; 320 | zval *tmp_ret_zval; 321 | 322 | ALLOC_INIT_ZVAL(tmp_name_zval); 323 | ZVAL_STRING(tmp_name_zval, prop_name, 1); 324 | tmp_ret_zval = TWIG_GET_ARRAYOBJECT_ELEMENT(class, tmp_name_zval TSRMLS_CC); 325 | zval_dtor(tmp_name_zval); 326 | efree(tmp_name_zval); 327 | return tmp_ret_zval; 328 | } 329 | 330 | if (zend_symtable_find(HASH_OF(class), prop_name, prop_name_length+1, (void**)&tmp_zval) == SUCCESS) { 331 | return *tmp_zval; 332 | } 333 | return NULL; 334 | } 335 | 336 | zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC) 337 | { 338 | char *prot_name; 339 | int prot_name_length; 340 | zval *tmp = NULL; 341 | 342 | tmp = TWIG_GET_ARRAY_ELEMENT(object, Z_STRVAL_P(propname), Z_STRLEN_P(propname) TSRMLS_CC); 343 | if (tmp) { 344 | return tmp; 345 | } 346 | 347 | zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, Z_STRVAL_P(propname), Z_STRLEN_P(propname), 0); 348 | tmp = TWIG_GET_ARRAY_ELEMENT(object, prot_name, prot_name_length TSRMLS_CC); 349 | efree(prot_name); 350 | if (tmp) { 351 | return tmp; 352 | } 353 | 354 | if (Z_OBJ_HT_P(object)->read_property) { 355 | #if PHP_VERSION_ID >= 50400 356 | tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS, NULL TSRMLS_CC); 357 | #else 358 | tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS TSRMLS_CC); 359 | #endif 360 | if (tmp != EG(uninitialized_zval_ptr)) { 361 | return tmp; 362 | } else { 363 | return NULL; 364 | } 365 | } 366 | return tmp; 367 | } 368 | 369 | int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC) 370 | { 371 | if (Z_OBJ_HT_P(object)->has_property) { 372 | #if PHP_VERSION_ID >= 50400 373 | return Z_OBJ_HT_P(object)->has_property(object, propname, 0, NULL TSRMLS_CC); 374 | #else 375 | return Z_OBJ_HT_P(object)->has_property(object, propname, 0 TSRMLS_CC); 376 | #endif 377 | } 378 | return 0; 379 | } 380 | 381 | zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC) 382 | { 383 | zval *tmp_name_zval, *tmp; 384 | 385 | ALLOC_INIT_ZVAL(tmp_name_zval); 386 | ZVAL_STRING(tmp_name_zval, propname, 1); 387 | tmp = TWIG_PROPERTY(object, tmp_name_zval TSRMLS_CC); 388 | zval_dtor(tmp_name_zval); 389 | efree(tmp_name_zval); 390 | return tmp; 391 | } 392 | 393 | int TWIG_CALL_B_0(zval *object, char *method) 394 | { 395 | return 0; 396 | } 397 | 398 | zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC) 399 | { 400 | zend_fcall_info fci; 401 | zval **args[1]; 402 | zval *argument; 403 | zval *zfunction; 404 | zval *retval_ptr; 405 | 406 | MAKE_STD_ZVAL(argument); 407 | ZVAL_STRING(argument, arg0, 1); 408 | args[0] = &argument; 409 | 410 | MAKE_STD_ZVAL(zfunction); 411 | ZVAL_STRING(zfunction, method, 1); 412 | fci.size = sizeof(fci); 413 | fci.function_table = EG(function_table); 414 | fci.function_name = zfunction; 415 | fci.symbol_table = NULL; 416 | #if PHP_VERSION_ID >= 50300 417 | fci.object_ptr = object; 418 | #else 419 | fci.object_pp = &object; 420 | #endif 421 | fci.retval_ptr_ptr = &retval_ptr; 422 | fci.param_count = 1; 423 | fci.params = args; 424 | fci.no_separation = 0; 425 | 426 | if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { 427 | zval_dtor(argument); 428 | return 0; 429 | } 430 | zval_dtor(zfunction); 431 | efree(zfunction); 432 | zval_dtor(argument); 433 | efree(argument); 434 | return retval_ptr; 435 | } 436 | 437 | int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC) 438 | { 439 | zval *retval_ptr; 440 | int success; 441 | 442 | retval_ptr = TWIG_CALL_S(object, method, arg0 TSRMLS_CC); 443 | success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr)); 444 | 445 | if (retval_ptr) { 446 | zval_ptr_dtor(&retval_ptr); 447 | } 448 | 449 | return success; 450 | } 451 | 452 | int TWIG_CALL_Z(zval *object, char *method, zval *arg1 TSRMLS_DC) 453 | { 454 | zend_fcall_info fci; 455 | zval **args[1]; 456 | zval *zfunction; 457 | zval *retval_ptr; 458 | int success; 459 | 460 | args[0] = &arg1; 461 | 462 | MAKE_STD_ZVAL(zfunction); 463 | ZVAL_STRING(zfunction, method, 1); 464 | fci.size = sizeof(fci); 465 | fci.function_table = EG(function_table); 466 | fci.function_name = zfunction; 467 | fci.symbol_table = NULL; 468 | #if PHP_VERSION_ID >= 50300 469 | fci.object_ptr = object; 470 | #else 471 | fci.object_pp = &object; 472 | #endif 473 | fci.retval_ptr_ptr = &retval_ptr; 474 | fci.param_count = 1; 475 | fci.params = args; 476 | fci.no_separation = 0; 477 | 478 | if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { 479 | zval_dtor(zfunction); 480 | efree(zfunction); 481 | if (retval_ptr) { 482 | zval_ptr_dtor(&retval_ptr); 483 | } 484 | return 0; 485 | } 486 | 487 | zval_dtor(zfunction); 488 | efree(zfunction); 489 | 490 | success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr)); 491 | if (retval_ptr) { 492 | zval_ptr_dtor(&retval_ptr); 493 | } 494 | 495 | return success; 496 | } 497 | 498 | int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC) 499 | { 500 | zend_fcall_info fci; 501 | zval **args[2]; 502 | zval *zfunction; 503 | zval *retval_ptr; 504 | int success; 505 | 506 | args[0] = &arg1; 507 | args[1] = &arg2; 508 | 509 | MAKE_STD_ZVAL(zfunction); 510 | ZVAL_STRING(zfunction, method, 1); 511 | fci.size = sizeof(fci); 512 | fci.function_table = EG(function_table); 513 | fci.function_name = zfunction; 514 | fci.symbol_table = NULL; 515 | #if PHP_VERSION_ID >= 50300 516 | fci.object_ptr = object; 517 | #else 518 | fci.object_pp = &object; 519 | #endif 520 | fci.retval_ptr_ptr = &retval_ptr; 521 | fci.param_count = 2; 522 | fci.params = args; 523 | fci.no_separation = 0; 524 | 525 | if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { 526 | zval_dtor(zfunction); 527 | return 0; 528 | } 529 | 530 | zval_dtor(zfunction); 531 | 532 | success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr)); 533 | if (retval_ptr) { 534 | zval_ptr_dtor(&retval_ptr); 535 | } 536 | 537 | return success; 538 | } 539 | 540 | #ifndef Z_SET_REFCOUNT_P 541 | # define Z_SET_REFCOUNT_P(pz, rc) pz->refcount = rc 542 | # define Z_UNSET_ISREF_P(pz) pz->is_ref = 0 543 | #endif 544 | 545 | void TWIG_NEW(zval *object, char *class, zval *value TSRMLS_DC) 546 | { 547 | zend_class_entry **pce; 548 | 549 | if (zend_lookup_class(class, strlen(class), &pce TSRMLS_CC) == FAILURE) { 550 | return; 551 | } 552 | 553 | Z_TYPE_P(object) = IS_OBJECT; 554 | object_init_ex(object, *pce); 555 | Z_SET_REFCOUNT_P(object, 1); 556 | Z_UNSET_ISREF_P(object); 557 | 558 | TWIG_CALL_Z(object, "__construct", value TSRMLS_CC); 559 | } 560 | 561 | static void twig_add_array_key_to_string(zval **zv TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) 562 | { 563 | smart_str *buf; 564 | char *joiner; 565 | 566 | buf = va_arg(args, smart_str*); 567 | joiner = va_arg(args, char*); 568 | 569 | if (buf->len != 0) { 570 | smart_str_appends(buf, joiner); 571 | } 572 | 573 | if (hash_key->nKeyLength == 0) { 574 | smart_str_append_long(buf, (long) hash_key->h); 575 | } else { 576 | char *key, *tmp_str; 577 | int key_len, tmp_len; 578 | key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC); 579 | tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL); 580 | 581 | smart_str_appendl(buf, tmp_str, tmp_len); 582 | efree(key); 583 | efree(tmp_str); 584 | } 585 | } 586 | 587 | char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC) 588 | { 589 | smart_str collector = { 0, 0, 0 }; 590 | 591 | smart_str_appendl(&collector, "", 0); 592 | zend_hash_apply_with_arguments(HASH_OF(array) TSRMLS_CC, (apply_func_args_t) twig_add_array_key_to_string, 2, &collector, joiner); 593 | smart_str_0(&collector); 594 | 595 | return collector.c; 596 | } 597 | 598 | static void TWIG_THROW_EXCEPTION(char *exception_name, char *message, ...) 599 | { 600 | char *buffer; 601 | va_list args; 602 | zend_class_entry **pce; 603 | 604 | TSRMLS_FETCH(); 605 | 606 | if (zend_lookup_class(exception_name, strlen(exception_name), &pce TSRMLS_CC) == FAILURE) 607 | { 608 | return; 609 | } 610 | 611 | va_start(args, message); 612 | vspprintf(&buffer, 0, message, args); 613 | va_end(args); 614 | 615 | zend_throw_exception_ex(*pce, 0 TSRMLS_CC, buffer); 616 | } 617 | 618 | char *TWIG_GET_CLASS_NAME(zval *object TSRMLS_DC) 619 | { 620 | char *class_name; 621 | zend_uint class_name_len; 622 | 623 | if (Z_TYPE_P(object) != IS_OBJECT) { 624 | return ""; 625 | } 626 | zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC); 627 | return class_name; 628 | } 629 | 630 | static void twig_add_method_to_class(zend_function *mptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) 631 | { 632 | zval *retval = va_arg(args, zval*); 633 | char *item = php_strtolower(mptr->common.function_name, strlen(mptr->common.function_name)); 634 | 635 | add_assoc_string(retval, item, item, 1); 636 | } 637 | 638 | static int twig_add_property_to_class(zend_property_info *pptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) 639 | { 640 | zend_class_entry *ce = *va_arg(args, zend_class_entry**); 641 | zval *retval = va_arg(args, zval*); 642 | char *class_name, *prop_name; 643 | 644 | if (pptr->flags & ZEND_ACC_SHADOW) { 645 | return 0; 646 | } 647 | 648 | zend_unmangle_property_name(pptr->name, pptr->name_length, &class_name, &prop_name); 649 | 650 | add_assoc_string(retval, prop_name, prop_name, 1); 651 | 652 | return 0; 653 | } 654 | 655 | /* {{{ _adddynproperty */ 656 | static int twig_add_dyn_property_to_class(zval **pptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) 657 | { 658 | zend_class_entry *ce = *va_arg(args, zend_class_entry**); 659 | zval *retval = va_arg(args, zval*), member; 660 | char *class_name, *prop_name; 661 | 662 | if (hash_key->arKey[0] == '\0') { 663 | return 0; /* non public cannot be dynamic */ 664 | } 665 | 666 | ZVAL_STRINGL(&member, hash_key->arKey, hash_key->nKeyLength-1, 0); 667 | if (zend_get_property_info(ce, &member, 1 TSRMLS_CC) == &EG(std_property_info)) { 668 | zend_unmangle_property_name((&EG(std_property_info))->name, (&EG(std_property_info))->name_length, &class_name, &prop_name); 669 | add_assoc_string(retval, prop_name, prop_name, 1); 670 | } 671 | return 0; 672 | } 673 | 674 | static void twig_add_class_to_cache(zval *cache, zval *object, char *class_name TSRMLS_DC) 675 | { 676 | zval *class_info, *class_methods, *class_properties; 677 | zend_class_entry *class_ce; 678 | 679 | class_ce = zend_get_class_entry(object TSRMLS_CC); 680 | 681 | ALLOC_INIT_ZVAL(class_info); 682 | ALLOC_INIT_ZVAL(class_methods); 683 | ALLOC_INIT_ZVAL(class_properties); 684 | array_init(class_info); 685 | array_init(class_methods); 686 | array_init(class_properties); 687 | // add all methods to self::cache[$class]['methods'] 688 | zend_hash_apply_with_arguments(&class_ce->function_table TSRMLS_CC, (apply_func_args_t) twig_add_method_to_class, 1, class_methods); 689 | zend_hash_apply_with_arguments(&class_ce->properties_info TSRMLS_CC, (apply_func_args_t) twig_add_property_to_class, 2, &class_ce, class_properties); 690 | 691 | if (object && Z_OBJ_HT_P(object)->get_properties) { 692 | HashTable *properties = Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC); 693 | zend_hash_apply_with_arguments(properties TSRMLS_CC, (apply_func_args_t) twig_add_dyn_property_to_class, 2, &class_ce, class_properties); 694 | } 695 | add_assoc_zval(class_info, "methods", class_methods); 696 | add_assoc_zval(class_info, "properties", class_properties); 697 | add_assoc_zval(cache, class_name, class_info); 698 | } 699 | 700 | /* {{{ proto mixed twig_template_get_attributes(TwigTemplate template, mixed object, mixed item, array arguments, string type, boolean isDefinedTest, boolean ignoreStrictCheck) 701 | A C implementation of TwigTemplate::getAttribute() */ 702 | PHP_FUNCTION(twig_template_get_attributes) 703 | { 704 | zval *template; 705 | zval *object; 706 | zval *item; 707 | zval *arguments = NULL; 708 | zval *ret = NULL; 709 | char *type = NULL; 710 | int type_len = 0; 711 | zend_bool isDefinedTest = 0; 712 | zend_bool ignoreStrictCheck = 0; 713 | int free_ret = 0; 714 | 715 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozz|asbb", &template, &object, &item, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) { 716 | return; 717 | } 718 | 719 | if (!type) { 720 | type = "any"; 721 | } 722 | 723 | /* 724 | // array 725 | if (Twig_TemplateInterface::METHOD_CALL !== $type) { 726 | if ((is_array($object) && array_key_exists($item, $object)) 727 | || ($object instanceof ArrayAccess && isset($object[$item])) 728 | ) { 729 | if ($isDefinedTest) { 730 | return true; 731 | } 732 | 733 | return $object[$item]; 734 | } 735 | */ 736 | if (strcmp("method", type) != 0) { 737 | // printf("XXXmethod: %s\n", type); 738 | if ((TWIG_ARRAY_KEY_EXISTS(object, item)) 739 | || (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, item TSRMLS_CC)) 740 | ) { 741 | zval *ret; 742 | 743 | if (isDefinedTest) { 744 | RETURN_TRUE; 745 | } 746 | 747 | ret = TWIG_GET_ARRAY_ELEMENT(object, Z_STRVAL_P(item), Z_STRLEN_P(item) TSRMLS_CC); 748 | RETVAL_ZVAL(ret, 1, 0); 749 | if (free_ret) { 750 | zval_ptr_dtor(&ret); 751 | } 752 | return; 753 | } 754 | /* 755 | if (Twig_TemplateInterface::ARRAY_CALL === $type) { 756 | if ($isDefinedTest) { 757 | return false; 758 | } 759 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { 760 | return null; 761 | } 762 | */ 763 | if (strcmp("array", type) == 0) { 764 | if (isDefinedTest) { 765 | RETURN_FALSE; 766 | } 767 | if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC) TSRMLS_CC) { 768 | return; 769 | } 770 | /* 771 | if (is_object($object)) { 772 | throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $item, get_class($object))); 773 | // array 774 | } else { 775 | throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $item, implode(', ', array_keys($object)))); 776 | } 777 | } 778 | } 779 | */ 780 | if (Z_TYPE_P(object) == IS_OBJECT) { 781 | TWIG_THROW_EXCEPTION("Twig_Error_Runtime", "Key \"%s\" in object (with ArrayAccess) of type \"%s\" does not exist", Z_STRVAL_P(item), TWIG_GET_CLASS_NAME(object TSRMLS_CC)); 782 | } else { 783 | TWIG_THROW_EXCEPTION("Twig_Error_Runtime", "Key \"%s\" for array with keys \"%s\" does not exist", Z_STRVAL_P(item), TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC)); 784 | } 785 | return; 786 | } 787 | } 788 | 789 | /* 790 | if (!is_object($object)) { 791 | if ($isDefinedTest) { 792 | return false; 793 | } 794 | */ 795 | 796 | if (Z_TYPE_P(object) != IS_OBJECT) { 797 | if (isDefinedTest) { 798 | RETURN_FALSE; 799 | } 800 | /* 801 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { 802 | return null; 803 | } 804 | throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, implode(', ', array_keys($object)))); 805 | } 806 | */ 807 | if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC) TSRMLS_CC) { 808 | RETURN_FALSE; 809 | } 810 | TWIG_THROW_EXCEPTION("Twig_Error_Runtime", "Item \"%s\" for \"%s\" does not exist", Z_STRVAL_P(item), TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC)); 811 | return; 812 | } 813 | /* 814 | // get some information about the object 815 | $class = get_class($object); 816 | if (!isset(self::$cache[$class])) { 817 | $r = new ReflectionClass($class); 818 | self::$cache[$class] = array('methods' => array(), 'properties' => array()); 819 | foreach ($r->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { 820 | self::$cache[$class]['methods'][strtolower($method->getName())] = true; 821 | } 822 | 823 | foreach ($r->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { 824 | self::$cache[$class]['properties'][$property->getName()] = true; 825 | } 826 | } 827 | */ 828 | zval *tmp_self_cache; 829 | 830 | if (Z_TYPE_P(object) == IS_OBJECT) { 831 | char *class_name = NULL; 832 | 833 | class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC); 834 | tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC); 835 | 836 | if (!TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC)) { 837 | twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC); 838 | } 839 | efree(class_name); 840 | } 841 | 842 | /* 843 | // object property 844 | if (Twig_TemplateInterface::METHOD_CALL !== $type) { 845 | if (isset(self::$cache[$class]['properties'][$item]) 846 | || isset($object->$item) || array_key_exists($item, $object) 847 | ) { 848 | if ($isDefinedTest) { 849 | return true; 850 | } 851 | if ($this->env->hasExtension('sandbox')) { 852 | $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item); 853 | } 854 | 855 | return $object->$item; 856 | } 857 | } 858 | */ 859 | if (strcmp("method", type) != 0) { 860 | zval *tmp_class, *tmp_properties, *tmp_item; 861 | char *class_name = NULL; 862 | 863 | class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC); 864 | tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC); 865 | tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC); 866 | tmp_item = TWIG_GET_ARRAY_ELEMENT_ZVAL(tmp_properties, item TSRMLS_CC); 867 | 868 | efree(class_name); 869 | 870 | if (tmp_item || TWIG_HAS_PROPERTY(object, item TSRMLS_CC) || TWIG_ARRAY_KEY_EXISTS(object, item) // FIXME: Array key? is that array access here? 871 | ) { 872 | if (isDefinedTest) { 873 | RETURN_TRUE; 874 | } 875 | if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) { 876 | TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, item TSRMLS_CC); 877 | } 878 | if (EG(exception)) { 879 | return; 880 | } 881 | 882 | convert_to_string(item); 883 | ret = TWIG_PROPERTY(object, item TSRMLS_CC); 884 | RETURN_ZVAL(ret, 1, 0); 885 | } 886 | } 887 | /* 888 | // object method 889 | $lcItem = strtolower($item); 890 | if (isset(self::$cache[$class]['methods'][$lcItem])) { 891 | $method = $item; 892 | } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) { 893 | $method = 'get'.$item; 894 | } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) { 895 | $method = 'is'.$item; 896 | } elseif (isset(self::$cache[$class]['methods']['__call'])) { 897 | $method = $item; 898 | */ 899 | { 900 | char *lcItem = TWIG_STRTOLOWER_ZVAL(item); 901 | int lcItem_length; 902 | char *method = NULL; 903 | char *tmp_method_name_get; 904 | char *tmp_method_name_is; 905 | zval *tmp_class, *tmp_methods; 906 | char *class_name = NULL; 907 | 908 | class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC); 909 | lcItem_length = strlen(lcItem); 910 | tmp_method_name_get = emalloc(4 + lcItem_length); 911 | tmp_method_name_is = emalloc(3 + lcItem_length); 912 | 913 | sprintf(tmp_method_name_get, "get%s", lcItem); 914 | sprintf(tmp_method_name_is, "is%s", lcItem); 915 | 916 | tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC); 917 | tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC); 918 | efree(class_name); 919 | 920 | if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) { 921 | method = Z_STRVAL_P(item); 922 | } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_get, lcItem_length + 3 TSRMLS_CC)) { 923 | method = tmp_method_name_get; 924 | } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_is, lcItem_length + 2 TSRMLS_CC)) { 925 | method = tmp_method_name_is; 926 | } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, "__call", 6 TSRMLS_CC)) { 927 | method = Z_STRVAL_P(item); 928 | /* 929 | } else { 930 | if ($isDefinedTest) { 931 | return false; 932 | } 933 | if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { 934 | return null; 935 | } 936 | throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object))); 937 | } 938 | if ($isDefinedTest) { 939 | return true; 940 | } 941 | */ 942 | } else { 943 | if (isDefinedTest) { 944 | RETURN_FALSE; 945 | } 946 | if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC) TSRMLS_CC) { 947 | return; 948 | } 949 | TWIG_THROW_EXCEPTION("Twig_Error_Runtime", "Method \"%s\" for object \"%s\" does not exist", Z_STRVAL_P(item), TWIG_GET_CLASS_NAME(object TSRMLS_CC)); 950 | return; 951 | } 952 | if (isDefinedTest) { 953 | efree(tmp_method_name_get); 954 | efree(tmp_method_name_is); 955 | efree(lcItem); 956 | RETURN_TRUE; 957 | } 958 | /* 959 | if ($this->env->hasExtension('sandbox')) { 960 | $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); 961 | } 962 | */ 963 | if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) { 964 | TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, item TSRMLS_CC); 965 | } 966 | if (EG(exception)) { 967 | return; 968 | } 969 | /* 970 | $ret = call_user_func_array(array($object, $method), $arguments); 971 | */ 972 | if (Z_TYPE_P(object) == IS_OBJECT) { 973 | ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC); 974 | free_ret = 1; 975 | } 976 | efree(tmp_method_name_get); 977 | efree(tmp_method_name_is); 978 | efree(lcItem); 979 | } 980 | /* 981 | if ($object instanceof Twig_TemplateInterface) { 982 | return new Twig_Markup($ret); 983 | } 984 | */ 985 | if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) { 986 | TWIG_NEW(return_value, "Twig_Markup", ret TSRMLS_CC); 987 | if (ret) { 988 | zval_ptr_dtor(&ret); 989 | } 990 | return; 991 | } 992 | /* 993 | return $ret; 994 | */ 995 | if (ret) { 996 | RETVAL_ZVAL(ret, 1, 0); 997 | if (free_ret) { 998 | zval_ptr_dtor(&ret); 999 | } 1000 | } 1001 | } 1002 | --------------------------------------------------------------------------------