@@ -341,23 +341,31 @@ static xmlNodePtr dom_xml_fragment_parsing_algorithm(dom_object *obj, const xmlN
341341 return NULL ;
342342}
343343
344- /* https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin
345- * and https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm */
346- zend_result dom_element_inner_html_write (dom_object * obj , zval * newval )
344+ /* https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm */
345+ static xmlNodePtr dom_parse_fragment (dom_object * obj , xmlNodePtr context_node , const zend_string * input )
347346{
348- DOM_PROP_NODE (xmlNodePtr , context_node , obj );
349-
350- xmlNodePtr fragment ;
351347 if (context_node -> doc -> type == XML_DOCUMENT_NODE ) {
352- fragment = dom_xml_fragment_parsing_algorithm (obj , context_node , Z_STR_P ( newval ) );
348+ return dom_xml_fragment_parsing_algorithm (obj , context_node , input );
353349 } else {
354- fragment = dom_html_fragment_parsing_algorithm (obj , context_node , Z_STR_P ( newval ) , obj -> document -> quirks_mode );
350+ return dom_html_fragment_parsing_algorithm (obj , context_node , input , obj -> document -> quirks_mode );
355351 }
352+ }
353+
354+ /* https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin */
355+ zend_result dom_element_inner_html_write (dom_object * obj , zval * newval )
356+ {
357+ /* 1. We don't do injection sinks, skip. */
358+
359+ /* 2. Let context be this. */
360+ DOM_PROP_NODE (xmlNodePtr , context_node , obj );
356361
362+ /* 3. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString. */
363+ xmlNodePtr fragment = dom_parse_fragment (obj , context_node , Z_STR_P (newval ));
357364 if (fragment == NULL ) {
358365 return FAILURE ;
359366 }
360367
368+ /* 4. If context is a template element, then set context to the template element's template contents (a DocumentFragment). */
361369 if (php_dom_ns_is_fast (context_node , php_dom_ns_is_html_magic_token ) && xmlStrEqual (context_node -> name , BAD_CAST "template" )) {
362370 context_node = php_dom_ensure_templated_content (php_dom_get_private_data (obj ), context_node );
363371 if (context_node == NULL ) {
@@ -366,6 +374,7 @@ zend_result dom_element_inner_html_write(dom_object *obj, zval *newval)
366374 }
367375 }
368376
377+ /* 5. Replace all with fragment within context. */
369378 dom_remove_all_children (context_node );
370379 return php_dom_pre_insert (obj -> document , fragment , context_node , NULL ) ? SUCCESS : FAILURE ;
371380}
@@ -397,4 +406,62 @@ zend_result dom_element_outer_html_read(dom_object *obj, zval *retval)
397406 return SUCCESS ;
398407}
399408
409+ /* https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#the-outerhtml-property */
410+ zend_result dom_element_outer_html_write (dom_object * obj , zval * newval )
411+ {
412+ /* 1. We don't do injection sinks, skip. */
413+
414+ /* 2. Let parent be this's parent. */
415+ DOM_PROP_NODE (xmlNodePtr , this , obj );
416+ xmlNodePtr parent = this -> parent ;
417+ bool created_parent = false;
418+
419+ /* 3. If parent is null, return. */
420+ if (parent == NULL ) {
421+ return SUCCESS ;
422+ }
423+
424+ /* 4. If parent is a Document, throw. */
425+ if (parent -> type == XML_DOCUMENT_NODE || parent -> type == XML_HTML_DOCUMENT_NODE ) {
426+ php_dom_throw_error (INVALID_MODIFICATION_ERR , true);
427+ return FAILURE ;
428+ }
429+
430+ /* 5. If parent is a DocumentFragment, set parent to the result of creating an element given this's node document, body, and the HTML namespace. */
431+ if (parent -> type == XML_DOCUMENT_FRAG_NODE ) {
432+ xmlNsPtr html_ns = php_dom_libxml_ns_mapper_ensure_html_ns (php_dom_get_ns_mapper (obj ));
433+
434+ parent = xmlNewDocNode (parent -> doc , html_ns , BAD_CAST "body" , NULL );
435+ created_parent = true;
436+ if (UNEXPECTED (parent == NULL )) {
437+ php_dom_throw_error (INVALID_STATE_ERR , true);
438+ return FAILURE ;
439+ }
440+ }
441+
442+ /* 6. Let fragment be the result of invoking the fragment parsing algorithm steps given parent and compliantString. */
443+ xmlNodePtr fragment = dom_parse_fragment (obj , parent , Z_STR_P (newval ));
444+ if (fragment == NULL ) {
445+ if (created_parent ) {
446+ xmlFreeNode (parent );
447+ }
448+ return FAILURE ;
449+ }
450+
451+ /* 7. Replace this with fragment within this's parent. */
452+ if (!php_dom_pre_insert (obj -> document , fragment , this -> parent , this )) {
453+ xmlFreeNode (fragment );
454+ if (created_parent ) {
455+ xmlFreeNode (parent );
456+ }
457+ return FAILURE ;
458+ }
459+ xmlUnlinkNode (this );
460+ if (created_parent ) {
461+ ZEND_ASSERT (parent -> children == NULL );
462+ xmlFreeNode (parent );
463+ }
464+ return SUCCESS ;
465+ }
466+
400467#endif
0 commit comments