xsltprocessor.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  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. | https://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. | Authors: Christian Stocker <chregu@php.net> |
  14. | Rob Richards <rrichards@php.net> |
  15. +----------------------------------------------------------------------+
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. #include "config.h"
  19. #endif
  20. #include "php.h"
  21. #include "php_xsl.h"
  22. #include "ext/libxml/php_libxml.h"
  23. /* {{{ php_xsl_xslt_string_to_xpathexpr()
  24. Translates a string to a XPath Expression */
  25. static char *php_xsl_xslt_string_to_xpathexpr(const char *str)
  26. {
  27. const xmlChar *string = (const xmlChar *)str;
  28. xmlChar *value;
  29. int str_len;
  30. str_len = xmlStrlen(string) + 3;
  31. if (xmlStrchr(string, '"')) {
  32. if (xmlStrchr(string, '\'')) {
  33. php_error_docref(NULL, E_WARNING, "Cannot create XPath expression (string contains both quote and double-quotes)");
  34. return NULL;
  35. }
  36. value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
  37. snprintf((char*)value, str_len, "'%s'", string);
  38. } else {
  39. value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
  40. snprintf((char *)value, str_len, "\"%s\"", string);
  41. }
  42. return (char *) value;
  43. }
  44. /* }}} */
  45. /* {{{ php_xsl_xslt_make_params()
  46. Translates a PHP array to a libxslt parameters array */
  47. static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params)
  48. {
  49. int parsize;
  50. zval *value;
  51. char *xpath_expr;
  52. zend_string *string_key;
  53. char **params = NULL;
  54. int i = 0;
  55. parsize = (2 * zend_hash_num_elements(parht) + 1) * sizeof(char *);
  56. params = (char **)safe_emalloc((2 * zend_hash_num_elements(parht) + 1), sizeof(char *), 0);
  57. memset((char *)params, 0, parsize);
  58. ZEND_HASH_FOREACH_STR_KEY_VAL(parht, string_key, value) {
  59. ZEND_ASSERT(string_key != NULL);
  60. if (Z_TYPE_P(value) != IS_STRING) {
  61. if (!try_convert_to_string(value)) {
  62. efree(params);
  63. return NULL;
  64. }
  65. }
  66. if (!xpath_params) {
  67. xpath_expr = php_xsl_xslt_string_to_xpathexpr(Z_STRVAL_P(value));
  68. } else {
  69. xpath_expr = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
  70. }
  71. if (xpath_expr) {
  72. params[i++] = estrndup(ZSTR_VAL(string_key), ZSTR_LEN(string_key));
  73. params[i++] = xpath_expr;
  74. }
  75. } ZEND_HASH_FOREACH_END();
  76. params[i++] = NULL;
  77. return params;
  78. }
  79. /* }}} */
  80. static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
  81. {
  82. xsltTransformContextPtr tctxt;
  83. zval *args = NULL;
  84. zval retval;
  85. int result, i;
  86. int error = 0;
  87. zend_fcall_info fci;
  88. zval handler;
  89. xmlXPathObjectPtr obj;
  90. char *str;
  91. xsl_object *intern;
  92. zend_string *callable = NULL;
  93. if (! zend_is_executing()) {
  94. xsltGenericError(xsltGenericErrorContext,
  95. "xsltExtFunctionTest: Function called from outside of PHP\n");
  96. error = 1;
  97. } else {
  98. tctxt = xsltXPathGetTransformContext(ctxt);
  99. if (tctxt == NULL) {
  100. xsltGenericError(xsltGenericErrorContext,
  101. "xsltExtFunctionTest: failed to get the transformation context\n");
  102. error = 1;
  103. } else {
  104. intern = (xsl_object*)tctxt->_private;
  105. if (intern == NULL) {
  106. xsltGenericError(xsltGenericErrorContext,
  107. "xsltExtFunctionTest: failed to get the internal object\n");
  108. error = 1;
  109. }
  110. else if (intern->registerPhpFunctions == 0) {
  111. xsltGenericError(xsltGenericErrorContext,
  112. "xsltExtFunctionTest: PHP Object did not register PHP functions\n");
  113. error = 1;
  114. }
  115. }
  116. }
  117. if (error == 1) {
  118. for (i = nargs - 1; i >= 0; i--) {
  119. obj = valuePop(ctxt);
  120. if (obj) {
  121. xmlXPathFreeObject(obj);
  122. }
  123. }
  124. return;
  125. }
  126. fci.param_count = nargs - 1;
  127. if (fci.param_count > 0) {
  128. args = safe_emalloc(fci.param_count, sizeof(zval), 0);
  129. }
  130. /* Reverse order to pop values off ctxt stack */
  131. for (i = nargs - 2; i >= 0; i--) {
  132. obj = valuePop(ctxt);
  133. if (obj == NULL) {
  134. ZVAL_NULL(&args[i]);
  135. continue;
  136. }
  137. switch (obj->type) {
  138. case XPATH_STRING:
  139. ZVAL_STRING(&args[i], (char *)obj->stringval);
  140. break;
  141. case XPATH_BOOLEAN:
  142. ZVAL_BOOL(&args[i], obj->boolval);
  143. break;
  144. case XPATH_NUMBER:
  145. ZVAL_DOUBLE(&args[i], obj->floatval);
  146. break;
  147. case XPATH_NODESET:
  148. if (type == 1) {
  149. str = (char*)xmlXPathCastToString(obj);
  150. ZVAL_STRING(&args[i], str);
  151. xmlFree(str);
  152. } else if (type == 2) {
  153. int j;
  154. dom_object *domintern = (dom_object *)intern->doc;
  155. if (obj->nodesetval && obj->nodesetval->nodeNr > 0) {
  156. array_init(&args[i]);
  157. for (j = 0; j < obj->nodesetval->nodeNr; j++) {
  158. xmlNodePtr node = obj->nodesetval->nodeTab[j];
  159. zval child;
  160. /* not sure, if we need this... it's copied from xpath.c */
  161. if (node->type == XML_NAMESPACE_DECL) {
  162. xmlNsPtr curns;
  163. xmlNodePtr nsparent;
  164. nsparent = node->_private;
  165. curns = xmlNewNs(NULL, node->name, NULL);
  166. if (node->children) {
  167. curns->prefix = xmlStrdup((xmlChar *)node->children);
  168. }
  169. if (node->children) {
  170. node = xmlNewDocNode(node->doc, NULL, (xmlChar *) node->children, node->name);
  171. } else {
  172. node = xmlNewDocNode(node->doc, NULL, (const xmlChar *) "xmlns", node->name);
  173. }
  174. node->type = XML_NAMESPACE_DECL;
  175. node->parent = nsparent;
  176. node->ns = curns;
  177. } else {
  178. node = xmlDocCopyNode(node, domintern->document->ptr, 1);
  179. }
  180. php_dom_create_object(node, &child, domintern);
  181. add_next_index_zval(&args[i], &child);
  182. }
  183. } else {
  184. ZVAL_EMPTY_ARRAY(&args[i]);
  185. }
  186. }
  187. break;
  188. default:
  189. str = (char *) xmlXPathCastToString(obj);
  190. ZVAL_STRING(&args[i], str);
  191. xmlFree(str);
  192. }
  193. xmlXPathFreeObject(obj);
  194. }
  195. fci.size = sizeof(fci);
  196. fci.named_params = NULL;
  197. if (fci.param_count > 0) {
  198. fci.params = args;
  199. } else {
  200. fci.params = NULL;
  201. }
  202. obj = valuePop(ctxt);
  203. if (obj == NULL || obj->stringval == NULL) {
  204. php_error_docref(NULL, E_WARNING, "Handler name must be a string");
  205. xmlXPathFreeObject(obj);
  206. valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
  207. if (fci.param_count > 0) {
  208. for (i = 0; i < nargs - 1; i++) {
  209. zval_ptr_dtor(&args[i]);
  210. }
  211. efree(args);
  212. }
  213. return;
  214. }
  215. ZVAL_STRING(&handler, (char *) obj->stringval);
  216. xmlXPathFreeObject(obj);
  217. ZVAL_COPY_VALUE(&fci.function_name, &handler);
  218. fci.object = NULL;
  219. fci.retval = &retval;
  220. if (!zend_make_callable(&handler, &callable)) {
  221. if (!EG(exception)) {
  222. php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", ZSTR_VAL(callable));
  223. }
  224. valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
  225. } else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) {
  226. php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'", ZSTR_VAL(callable));
  227. /* Push an empty string, so that we at least have an xslt result... */
  228. valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
  229. } else {
  230. result = zend_call_function(&fci, NULL);
  231. if (result == FAILURE) {
  232. if (Z_TYPE(handler) == IS_STRING) {
  233. php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", Z_STRVAL(handler));
  234. valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
  235. }
  236. /* retval is == NULL, when an exception occurred, don't report anything, because PHP itself will handle that */
  237. } else if (Z_ISUNDEF(retval)) {
  238. } else {
  239. if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) {
  240. xmlNode *nodep;
  241. dom_object *obj;
  242. if (intern->node_list == NULL) {
  243. intern->node_list = zend_new_array(0);
  244. }
  245. Z_ADDREF(retval);
  246. zend_hash_next_index_insert(intern->node_list, &retval);
  247. obj = Z_DOMOBJ_P(&retval);
  248. nodep = dom_object_get_node(obj);
  249. valuePush(ctxt, xmlXPathNewNodeSet(nodep));
  250. } else if (Z_TYPE(retval) == IS_TRUE || Z_TYPE(retval) == IS_FALSE) {
  251. valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(retval) == IS_TRUE));
  252. } else if (Z_TYPE(retval) == IS_OBJECT) {
  253. php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string");
  254. valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
  255. } else {
  256. convert_to_string(&retval);
  257. valuePush(ctxt, xmlXPathNewString((xmlChar *) Z_STRVAL(retval)));
  258. }
  259. zval_ptr_dtor(&retval);
  260. }
  261. }
  262. zend_string_release_ex(callable, 0);
  263. zval_ptr_dtor(&handler);
  264. if (fci.param_count > 0) {
  265. for (i = 0; i < nargs - 1; i++) {
  266. zval_ptr_dtor(&args[i]);
  267. }
  268. efree(args);
  269. }
  270. }
  271. /* }}} */
  272. void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
  273. {
  274. xsl_ext_function_php(ctxt, nargs, 1);
  275. }
  276. /* }}} */
  277. void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
  278. {
  279. xsl_ext_function_php(ctxt, nargs, 2);
  280. }
  281. /* }}} */
  282. /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
  283. Since:
  284. */
  285. PHP_METHOD(XSLTProcessor, importStylesheet)
  286. {
  287. zval *id, *docp = NULL;
  288. xmlDoc *doc = NULL, *newdoc = NULL;
  289. xsltStylesheetPtr sheetp, oldsheetp;
  290. xsl_object *intern;
  291. int prevSubstValue, prevExtDtdValue, clone_docu = 0;
  292. xmlNode *nodep = NULL;
  293. zval *cloneDocu, rv;
  294. zend_string *member;
  295. id = ZEND_THIS;
  296. if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
  297. RETURN_THROWS();
  298. }
  299. nodep = php_libxml_import_node(docp);
  300. if (nodep) {
  301. doc = nodep->doc;
  302. }
  303. if (doc == NULL) {
  304. zend_argument_value_error(1, "must be a valid XML node");
  305. RETURN_THROWS();
  306. }
  307. /* libxslt uses _private, so we must copy the imported
  308. stylesheet document otherwise the node proxies will be a mess */
  309. newdoc = xmlCopyDoc(doc, 1);
  310. xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
  311. prevSubstValue = xmlSubstituteEntitiesDefault(1);
  312. prevExtDtdValue = xmlLoadExtDtdDefaultValue;
  313. xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
  314. sheetp = xsltParseStylesheetDoc(newdoc);
  315. xmlSubstituteEntitiesDefault(prevSubstValue);
  316. xmlLoadExtDtdDefaultValue = prevExtDtdValue;
  317. if (!sheetp) {
  318. xmlFreeDoc(newdoc);
  319. RETURN_FALSE;
  320. }
  321. intern = Z_XSL_P(id);
  322. member = zend_string_init("cloneDocument", sizeof("cloneDocument")-1, 0);
  323. cloneDocu = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_IS, NULL, &rv);
  324. if (Z_TYPE_P(cloneDocu) != IS_NULL) {
  325. convert_to_long(cloneDocu);
  326. clone_docu = Z_LVAL_P(cloneDocu);
  327. }
  328. zend_string_release_ex(member, 0);
  329. if (clone_docu == 0) {
  330. /* check if the stylesheet is using xsl:key, if yes, we have to clone the document _always_ before a transformation */
  331. nodep = xmlDocGetRootElement(sheetp->doc);
  332. if (nodep && (nodep = nodep->children)) {
  333. while (nodep) {
  334. if (nodep->type == XML_ELEMENT_NODE && xmlStrEqual(nodep->name, (const xmlChar *) "key") && xmlStrEqual(nodep->ns->href, XSLT_NAMESPACE)) {
  335. intern->hasKeys = 1;
  336. break;
  337. }
  338. nodep = nodep->next;
  339. }
  340. }
  341. } else {
  342. intern->hasKeys = clone_docu;
  343. }
  344. if ((oldsheetp = (xsltStylesheetPtr)intern->ptr)) {
  345. /* free wrapper */
  346. if (((xsltStylesheetPtr) intern->ptr)->_private != NULL) {
  347. ((xsltStylesheetPtr) intern->ptr)->_private = NULL;
  348. }
  349. xsltFreeStylesheet((xsltStylesheetPtr) intern->ptr);
  350. intern->ptr = NULL;
  351. }
  352. php_xsl_set_object(id, sheetp);
  353. RETVAL_TRUE;
  354. }
  355. /* }}} end XSLTProcessor::importStylesheet */
  356. static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStylesheetPtr style, zval *docp) /* {{{ */
  357. {
  358. xmlDocPtr newdocp = NULL;
  359. xmlDocPtr doc = NULL;
  360. xmlNodePtr node = NULL;
  361. xsltTransformContextPtr ctxt;
  362. php_libxml_node_object *object;
  363. char **params = NULL;
  364. int clone;
  365. zval *doXInclude, rv;
  366. zend_string *member;
  367. FILE *f;
  368. int secPrefsError = 0;
  369. int secPrefsValue;
  370. xsltSecurityPrefsPtr secPrefs = NULL;
  371. node = php_libxml_import_node(docp);
  372. if (node) {
  373. doc = node->doc;
  374. }
  375. if (doc == NULL) {
  376. zend_argument_value_error(1, "must be a valid XML node");
  377. return NULL;
  378. }
  379. if (style == NULL) {
  380. zend_string *name = get_active_function_or_method_name();
  381. zend_throw_error(NULL, "%s() can only be called after a stylesheet has been imported",
  382. ZSTR_VAL(name));
  383. zend_string_release(name);
  384. return NULL;
  385. }
  386. if (intern->profiling) {
  387. if (php_check_open_basedir(intern->profiling)) {
  388. f = NULL;
  389. } else {
  390. f = VCWD_FOPEN(intern->profiling, "w");
  391. }
  392. } else {
  393. f = NULL;
  394. }
  395. if (intern->parameter) {
  396. params = php_xsl_xslt_make_params(intern->parameter, 0);
  397. }
  398. intern->doc = emalloc(sizeof(php_libxml_node_object));
  399. memset(intern->doc, 0, sizeof(php_libxml_node_object));
  400. if (intern->hasKeys == 1) {
  401. doc = xmlCopyDoc(doc, 1);
  402. } else {
  403. object = Z_LIBXML_NODE_P(docp);
  404. intern->doc->document = object->document;
  405. }
  406. php_libxml_increment_doc_ref(intern->doc, doc);
  407. ctxt = xsltNewTransformContext(style, doc);
  408. ctxt->_private = (void *) intern;
  409. member = zend_string_init("doXInclude", sizeof("doXInclude")-1, 0);
  410. doXInclude = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_IS, NULL, &rv);
  411. if (Z_TYPE_P(doXInclude) != IS_NULL) {
  412. convert_to_long(doXInclude);
  413. ctxt->xinclude = Z_LVAL_P(doXInclude);
  414. }
  415. zend_string_release_ex(member, 0);
  416. secPrefsValue = intern->securityPrefs;
  417. /* if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... */
  418. if (secPrefsValue != XSL_SECPREF_NONE) {
  419. secPrefs = xsltNewSecurityPrefs();
  420. if (secPrefsValue & XSL_SECPREF_READ_FILE ) {
  421. if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) {
  422. secPrefsError = 1;
  423. }
  424. }
  425. if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) {
  426. if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) {
  427. secPrefsError = 1;
  428. }
  429. }
  430. if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) {
  431. if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) {
  432. secPrefsError = 1;
  433. }
  434. }
  435. if (secPrefsValue & XSL_SECPREF_READ_NETWORK) {
  436. if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) {
  437. secPrefsError = 1;
  438. }
  439. }
  440. if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) {
  441. if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) {
  442. secPrefsError = 1;
  443. }
  444. }
  445. if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) {
  446. secPrefsError = 1;
  447. }
  448. }
  449. if (secPrefsError == 1) {
  450. php_error_docref(NULL, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons");
  451. } else {
  452. newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params, NULL, f, ctxt);
  453. }
  454. if (f) {
  455. fclose(f);
  456. }
  457. xsltFreeTransformContext(ctxt);
  458. if (secPrefs) {
  459. xsltFreeSecurityPrefs(secPrefs);
  460. }
  461. if (intern->node_list != NULL) {
  462. zend_hash_destroy(intern->node_list);
  463. FREE_HASHTABLE(intern->node_list);
  464. intern->node_list = NULL;
  465. }
  466. php_libxml_decrement_doc_ref(intern->doc);
  467. efree(intern->doc);
  468. intern->doc = NULL;
  469. if (params) {
  470. clone = 0;
  471. while(params[clone]) {
  472. efree(params[clone++]);
  473. }
  474. efree(params);
  475. }
  476. return newdocp;
  477. }
  478. /* }}} */
  479. /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
  480. Since:
  481. */
  482. PHP_METHOD(XSLTProcessor, transformToDoc)
  483. {
  484. zval *id, *docp = NULL;
  485. xmlDoc *newdocp;
  486. xsltStylesheetPtr sheetp;
  487. zend_string *ret_class = NULL;
  488. xsl_object *intern;
  489. id = ZEND_THIS;
  490. intern = Z_XSL_P(id);
  491. sheetp = (xsltStylesheetPtr) intern->ptr;
  492. if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|S!", &docp, &ret_class) == FAILURE) {
  493. RETURN_THROWS();
  494. }
  495. newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
  496. if (newdocp) {
  497. if (ret_class) {
  498. zend_string *curclass_name;
  499. zend_class_entry *curce, *ce;
  500. php_libxml_node_object *interndoc;
  501. curce = Z_OBJCE_P(docp);
  502. curclass_name = curce->name;
  503. while (curce->parent != NULL) {
  504. curce = curce->parent;
  505. }
  506. ce = zend_lookup_class(ret_class);
  507. if (ce == NULL || !instanceof_function(ce, curce)) {
  508. xmlFreeDoc(newdocp);
  509. zend_argument_type_error(2, "must be a class name compatible with %s, \"%s\" given",
  510. ZSTR_VAL(curclass_name), ZSTR_VAL(ret_class)
  511. );
  512. RETURN_THROWS();
  513. }
  514. object_init_ex(return_value, ce);
  515. interndoc = Z_LIBXML_NODE_P(return_value);
  516. php_libxml_increment_doc_ref(interndoc, newdocp);
  517. php_libxml_increment_node_ptr(interndoc, (xmlNodePtr)newdocp, (void *)interndoc);
  518. } else {
  519. php_dom_create_object((xmlNodePtr) newdocp, return_value, NULL);
  520. }
  521. } else {
  522. RETURN_FALSE;
  523. }
  524. }
  525. /* }}} end XSLTProcessor::transformToDoc */
  526. /* {{{ */
  527. PHP_METHOD(XSLTProcessor, transformToUri)
  528. {
  529. zval *id, *docp = NULL;
  530. xmlDoc *newdocp;
  531. xsltStylesheetPtr sheetp;
  532. int ret;
  533. size_t uri_len;
  534. char *uri;
  535. xsl_object *intern;
  536. id = ZEND_THIS;
  537. intern = Z_XSL_P(id);
  538. sheetp = (xsltStylesheetPtr) intern->ptr;
  539. if (zend_parse_parameters(ZEND_NUM_ARGS(), "op", &docp, &uri, &uri_len) == FAILURE) {
  540. RETURN_THROWS();
  541. }
  542. newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
  543. ret = -1;
  544. if (newdocp) {
  545. ret = xsltSaveResultToFilename(uri, newdocp, sheetp, 0);
  546. xmlFreeDoc(newdocp);
  547. }
  548. RETVAL_LONG(ret);
  549. }
  550. /* }}} end XSLTProcessor::transformToUri */
  551. /* {{{ */
  552. PHP_METHOD(XSLTProcessor, transformToXml)
  553. {
  554. zval *id, *docp = NULL;
  555. xmlDoc *newdocp;
  556. xsltStylesheetPtr sheetp;
  557. int ret;
  558. xmlChar *doc_txt_ptr;
  559. int doc_txt_len;
  560. xsl_object *intern;
  561. id = ZEND_THIS;
  562. intern = Z_XSL_P(id);
  563. sheetp = (xsltStylesheetPtr) intern->ptr;
  564. if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
  565. RETURN_THROWS();
  566. }
  567. newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
  568. ret = -1;
  569. if (newdocp) {
  570. ret = xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, newdocp, sheetp);
  571. if (doc_txt_ptr && doc_txt_len) {
  572. RETVAL_STRINGL((char *) doc_txt_ptr, doc_txt_len);
  573. xmlFree(doc_txt_ptr);
  574. }
  575. xmlFreeDoc(newdocp);
  576. }
  577. if (ret < 0) {
  578. RETURN_FALSE;
  579. }
  580. }
  581. /* }}} end XSLTProcessor::transformToXml */
  582. /* {{{ */
  583. PHP_METHOD(XSLTProcessor, setParameter)
  584. {
  585. zval *id = ZEND_THIS;
  586. zval *entry, new_string;
  587. HashTable *array_value;
  588. xsl_object *intern;
  589. char *namespace;
  590. size_t namespace_len;
  591. zend_string *string_key, *name, *value = NULL;
  592. ZEND_PARSE_PARAMETERS_START(2, 3)
  593. Z_PARAM_STRING(namespace, namespace_len)
  594. Z_PARAM_ARRAY_HT_OR_STR(array_value, name)
  595. Z_PARAM_OPTIONAL
  596. Z_PARAM_STR_OR_NULL(value)
  597. ZEND_PARSE_PARAMETERS_END();
  598. intern = Z_XSL_P(id);
  599. if (array_value) {
  600. if (value) {
  601. zend_argument_value_error(3, "must be null when argument #2 ($name) is an array");
  602. RETURN_THROWS();
  603. }
  604. ZEND_HASH_FOREACH_STR_KEY_VAL(array_value, string_key, entry) {
  605. zval tmp;
  606. zend_string *str;
  607. if (string_key == NULL) {
  608. zend_argument_type_error(2, "must contain only string keys");
  609. RETURN_THROWS();
  610. }
  611. str = zval_try_get_string(entry);
  612. if (UNEXPECTED(!str)) {
  613. RETURN_THROWS();
  614. }
  615. ZVAL_STR(&tmp, str);
  616. zend_hash_update(intern->parameter, string_key, &tmp);
  617. } ZEND_HASH_FOREACH_END();
  618. RETURN_TRUE;
  619. } else {
  620. if (!value) {
  621. zend_argument_value_error(3, "cannot be null when argument #2 ($name) is a string");
  622. RETURN_THROWS();
  623. }
  624. ZVAL_STR_COPY(&new_string, value);
  625. zend_hash_update(intern->parameter, name, &new_string);
  626. RETURN_TRUE;
  627. }
  628. }
  629. /* }}} end XSLTProcessor::setParameter */
  630. /* {{{ */
  631. PHP_METHOD(XSLTProcessor, getParameter)
  632. {
  633. zval *id = ZEND_THIS;
  634. char *namespace;
  635. size_t namespace_len = 0;
  636. zval *value;
  637. zend_string *name;
  638. xsl_object *intern;
  639. if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
  640. RETURN_THROWS();
  641. }
  642. intern = Z_XSL_P(id);
  643. if ((value = zend_hash_find(intern->parameter, name)) != NULL) {
  644. RETURN_STR(zval_get_string(value));
  645. } else {
  646. RETURN_FALSE;
  647. }
  648. }
  649. /* }}} end XSLTProcessor::getParameter */
  650. /* {{{ */
  651. PHP_METHOD(XSLTProcessor, removeParameter)
  652. {
  653. zval *id = ZEND_THIS;
  654. size_t namespace_len = 0;
  655. char *namespace;
  656. zend_string *name;
  657. xsl_object *intern;
  658. if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
  659. RETURN_THROWS();
  660. }
  661. intern = Z_XSL_P(id);
  662. if (zend_hash_del(intern->parameter, name) == SUCCESS) {
  663. RETURN_TRUE;
  664. } else {
  665. RETURN_FALSE;
  666. }
  667. }
  668. /* }}} end XSLTProcessor::removeParameter */
  669. /* {{{ */
  670. PHP_METHOD(XSLTProcessor, registerPHPFunctions)
  671. {
  672. zval *id = ZEND_THIS;
  673. xsl_object *intern;
  674. zval *entry, new_string;
  675. zend_string *restrict_str = NULL;
  676. HashTable *restrict_ht = NULL;
  677. ZEND_PARSE_PARAMETERS_START(0, 1)
  678. Z_PARAM_OPTIONAL
  679. Z_PARAM_ARRAY_HT_OR_STR_OR_NULL(restrict_ht, restrict_str)
  680. ZEND_PARSE_PARAMETERS_END();
  681. intern = Z_XSL_P(id);
  682. if (restrict_ht) {
  683. ZEND_HASH_FOREACH_VAL(restrict_ht, entry) {
  684. zend_string *str = zval_try_get_string(entry);
  685. if (UNEXPECTED(!str)) {
  686. return;
  687. }
  688. ZVAL_LONG(&new_string, 1);
  689. zend_hash_update(intern->registered_phpfunctions, str, &new_string);
  690. zend_string_release(str);
  691. } ZEND_HASH_FOREACH_END();
  692. intern->registerPhpFunctions = 2;
  693. } else if (restrict_str) {
  694. ZVAL_LONG(&new_string, 1);
  695. zend_hash_update(intern->registered_phpfunctions, restrict_str, &new_string);
  696. intern->registerPhpFunctions = 2;
  697. } else {
  698. intern->registerPhpFunctions = 1;
  699. }
  700. }
  701. /* }}} end XSLTProcessor::registerPHPFunctions(); */
  702. /* {{{ */
  703. PHP_METHOD(XSLTProcessor, setProfiling)
  704. {
  705. zval *id = ZEND_THIS;
  706. xsl_object *intern;
  707. char *filename = NULL;
  708. size_t filename_len;
  709. if (zend_parse_parameters(ZEND_NUM_ARGS(), "p!", &filename, &filename_len) == FAILURE) {
  710. RETURN_THROWS();
  711. }
  712. intern = Z_XSL_P(id);
  713. if (intern->profiling) {
  714. efree(intern->profiling);
  715. }
  716. if (filename != NULL) {
  717. intern->profiling = estrndup(filename, filename_len);
  718. } else {
  719. intern->profiling = NULL;
  720. }
  721. RETURN_TRUE;
  722. }
  723. /* }}} end XSLTProcessor::setProfiling */
  724. /* {{{ */
  725. PHP_METHOD(XSLTProcessor, setSecurityPrefs)
  726. {
  727. zval *id = ZEND_THIS;
  728. xsl_object *intern;
  729. zend_long securityPrefs, oldSecurityPrefs;
  730. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &securityPrefs) == FAILURE) {
  731. RETURN_THROWS();
  732. }
  733. intern = Z_XSL_P(id);
  734. oldSecurityPrefs = intern->securityPrefs;
  735. intern->securityPrefs = securityPrefs;
  736. /* set this to 1 so that we know, it was set through this method. Can be removed, when we remove the ini setting */
  737. intern->securityPrefsSet = 1;
  738. RETURN_LONG(oldSecurityPrefs);
  739. }
  740. /* }}} end XSLTProcessor::setSecurityPrefs */
  741. /* {{{ */
  742. PHP_METHOD(XSLTProcessor, getSecurityPrefs)
  743. {
  744. zval *id = ZEND_THIS;
  745. xsl_object *intern;
  746. if (zend_parse_parameters_none() == FAILURE) {
  747. RETURN_THROWS();
  748. }
  749. intern = Z_XSL_P(id);
  750. RETURN_LONG(intern->securityPrefs);
  751. }
  752. /* }}} end XSLTProcessor::getSecurityPrefs */
  753. /* {{{ */
  754. PHP_METHOD(XSLTProcessor, hasExsltSupport)
  755. {
  756. if (zend_parse_parameters_none() == FAILURE) {
  757. RETURN_THROWS();
  758. }
  759. #ifdef HAVE_XSL_EXSLT
  760. RETURN_TRUE;
  761. #else
  762. RETURN_FALSE;
  763. #endif
  764. }
  765. /* }}} end XSLTProcessor::hasExsltSupport(); */