ProShell v2.0
Dashboard
Server Info
Server: 158.106.128.192
PHP: 8.2.33
home
planet5
public_html
bansibaba.com
wp-includes
2026-09-17 21:05:42
Editing: class-amp-iframe-sanitizer.php
Cancel
Save Changes
<?php /** * Class AMP_Iframe_Sanitizer * * @package AMP */ use AmpProject\AmpWP\ValidationExemption; use AmpProject\DevMode; use AmpProject\Html\Attribute; use AmpProject\Layout; /** * Class AMP_Iframe_Sanitizer * * Converts <iframe> tags to <amp-iframe> * * @internal */ class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer { use AMP_Noscript_Fallback; /** * Default values for sandboxing IFrame. * * | Sandbox Token | Included | Rationale * |-------------------------------------------|----------|---------- * | `allow-downloads` | Yes | Useful for downloading documents, etc. * | `allow-downloads-without-user-activation` | No | Experimental per MDN. Bad UX. * | `allow-forms` | Yes | For embeds like polls. * | `allow-modals` | Yes | For apps to show `confirm()`, etc. * | `allow-orientation-lock` | Yes | Since we `allowfullscreen`, useful for games, etc. * | `allow-pointer-lock` | Yes | Useful for games. * | `allow-popups` | Yes | To open YouTube video in new window, for example. * | `allow-popups-to-escape-sandbox` | Yes | Useful for ads. * | `allow-presentation` | Yes | To cast YouTube videos, for example. * | `allow-same-origin` | Yes | Removed if iframe is same origin. * | `allow-scripts` | Yes | An iframe's primary use case is custom JS. * | `allow-storage-access-by-user-activation` | No | Experimental per MDN. * | `allow-top-navigation` | No | Poor user experience. * | `allow-top-navigation-by-user-activation` | Yes | Key for clicking `target=_top` links in iframes. * * @since 0.2 * @since 2.0.5 Updated to include majority of other sandbox values which are included by default if sandbox is not provided. * @link https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-iframe-sandbox * * @const string */ const SANDBOX_DEFAULTS = 'allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation'; /** * Tag. * * @since 0.2 * * @var string HTML <iframe> tag to identify and replace with AMP version. */ public static $tag = 'iframe'; /** * Default args. * * @var array { * Default args. * * @type bool $add_placeholder Whether to add a placeholder element. * @type bool $add_noscript_fallback Whether to add a noscript fallback. * @type string $current_origin The current origin serving the page. Normally this will be the $_SERVER[HTTP_HOST]. * @type string $alias_origin An alternative origin which can be supplied which is used when encountering same-origin iframes. * @type bool $native_iframe_used Whether an HTML5 iframe element should be used instead of amp-iframe. * } */ protected $DEFAULT_ARGS = [ 'add_placeholder' => false, 'add_noscript_fallback' => true, 'current_origin' => null, 'alias_origin' => null, 'native_iframe_used' => false, ]; /** * Get mapping of HTML selectors to the AMP component selectors which they may be converted into. * * @return array Mapping. */ public function get_selector_conversion_mapping() { if ( $this->args['native_iframe_used'] ) { return []; } return [ 'iframe' => [ 'amp-iframe', ], ]; } /** * Sanitize the <iframe> elements from the HTML contained in this instance's Dom\Document. * * @since 0.2 */ public function sanitize() { $nodes = $this->dom->getElementsByTagName( self::$tag ); $num_nodes = $nodes->length; if ( 0 === $num_nodes ) { return; } if ( $this->args['add_noscript_fallback'] ) { $this->initialize_noscript_allowed_attributes( self::$tag ); } // Ensure origins are normalized. $this->args['current_origin'] = $this->get_origin_from_url( $this->args['current_origin'] ); if ( ! empty( $this->args['alias_origin'] ) ) { $this->args['alias_origin'] = $this->get_origin_from_url( $this->args['alias_origin'] ); } for ( $i = $num_nodes - 1; $i >= 0; $i-- ) { /** * Iframe element. * * @var DOMElement $node */ $node = $nodes->item( $i ); // Skip element if already inside of an AMP element as a noscript fallback, or if it has a dev mode exemption. if ( $this->is_inside_amp_noscript( $node ) || DevMode::hasExemptionForNode( $node ) ) { continue; } // If using native <iframe> instead of converting to <amp-iframe>, just mark the element as being unvalidated. if ( $this->args['native_iframe_used'] ) { ValidationExemption::mark_node_as_px_verified( $node ); continue; } $normalized_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node ); $normalized_attributes = $this->set_layout( $normalized_attributes ); $normalized_attributes = $this->normalize_attributes( $normalized_attributes ); /** * If the src doesn't exist, remove the node. Either it never * existed or was invalidated while filtering attributes above. * * @todo: add an arg to allow for a fallback element in this instance (note that filter cannot be used inside a sanitizer). * @see: https://github.com/ampproject/amphtml/issues/2261 */ if ( empty( $normalized_attributes['src'] ) ) { $this->remove_invalid_child( $node, [ 'code' => AMP_Tag_And_Attribute_Sanitizer::ATTR_REQUIRED_BUT_MISSING, 'attributes' => [ 'src' ], 'spec_name' => 'amp-iframe', ] ); continue; } $this->did_convert_elements = true; if ( empty( $normalized_attributes[ Attribute::LAYOUT ] ) && ! empty( $normalized_attributes[ Attribute::HEIGHT ] ) && ! empty( $normalized_attributes[ Attribute::WIDTH ] ) ) { // Set layout to responsive if the iframe is aligned to full width. $figure_node = null; if ( $node->parentNode instanceof DOMElement && 'figure' === $node->parentNode->tagName ) { $figure_node = $node->parentNode; } if ( $node->parentNode->parentNode instanceof DOMElement && 'figure' === $node->parentNode->parentNode->tagName ) { $figure_node = $node->parentNode->parentNode; } if ( ! empty( $this->args['align_wide_support'] ) && $figure_node && preg_match( '/(^|\s)(alignwide|alignfull)(\s|$)/', $figure_node->getAttribute( Attribute::CLASS_ ) ) ) { $normalized_attributes[ Attribute::LAYOUT ] = Layout::RESPONSIVE; } else { $normalized_attributes[ Attribute::LAYOUT ] = Layout::INTRINSIC; } $this->add_or_append_attribute( $normalized_attributes, 'class', 'amp-wp-enforced-sizes' ); } // Remove the ID from the original node so that PHP DOM doesn't fail to set it on the replacement element. $node->removeAttribute( Attribute::ID ); $new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-iframe', $normalized_attributes ); // Find existing placeholder/overflow. $placeholder_node = null; $overflow_node = null; foreach ( iterator_to_array( $node->childNodes ) as $child ) { if ( ! ( $child instanceof DOMElement ) ) { continue; } if ( $child->hasAttribute( 'placeholder' ) ) { $placeholder_node = $node->removeChild( $child ); } elseif ( $child->hasAttribute( 'overflow' ) ) { $overflow_node = $node->removeChild( $child ); } } // Add placeholder. if ( $placeholder_node || true === $this->args['add_placeholder'] ) { if ( ! $placeholder_node ) { $placeholder_node = $this->build_placeholder(); // @todo Can a better placeholder default be devised? } $new_node->appendChild( $placeholder_node ); } // Add overflow. if ( $new_node->hasAttribute( 'resizable' ) && ! $overflow_node ) { $overflow_node = $this->dom->createElement( 'button' ); $overflow_node->setAttribute( 'overflow', '' ); if ( $node->hasAttribute( 'data-amp-overflow-text' ) ) { $overflow_text = $node->getAttribute( 'data-amp-overflow-text' ); } else { $overflow_text = __( 'Show all', 'amp' ); } $overflow_node->appendChild( $this->dom->createTextNode( $overflow_text ) ); } if ( $overflow_node ) { $new_node->appendChild( $overflow_node ); } $node->parentNode->replaceChild( $new_node, $node ); if ( $this->args['add_noscript_fallback'] ) { $node->setAttribute( 'src', $normalized_attributes['src'] ); // AMP is stricter than HTML5 for this attribute, so make sure we use a normalized value. if ( $node->hasAttribute( 'frameborder' ) ) { $node->setAttribute( 'frameborder', $normalized_attributes['frameborder'] ); } // Preserve original node in noscript for no-JS environments. $this->append_old_node_noscript( $new_node, $node, $this->dom ); } } } /** * Normalize HTML attributes for <amp-iframe> elements. * * @param string[] $attributes { * Attributes. * * @type string $src IFrame URL - Empty if HTTPS required per $this->args['require_https_src'] * @type int $width <iframe> width attribute - Set to numeric value if px or % * @type int $height <iframe> height attribute - Set to numeric value if px or % * @type string $sandbox <iframe> `sandbox` attribute - Pass along if found; default to value of self::SANDBOX_DEFAULTS * @type string $class <iframe> `class` attribute - Pass along if found * @type string $sizes <iframe> `sizes` attribute - Pass along if found * @type string $id <iframe> `id` attribute - Pass along if found * @type int $frameborder <iframe> `frameborder` attribute - Filter to '0' or '1'; default to '0' * @type bool $allowfullscreen <iframe> `allowfullscreen` attribute - Convert 'false' to empty string '' * @type bool $allowtransparency <iframe> `allowtransparency` attribute - Convert 'false' to empty string '' * @type string $type <iframe> `type` attribute - Pass along if value is not `text/html` * } * @return array Returns HTML attributes; normalizes src, dimensions, frameborder, sandbox, allowtransparency and allowfullscreen */ private function normalize_attributes( $attributes ) { $out = []; $remove_allow_same_origin = false; foreach ( $attributes as $name => $value ) { switch ( $name ) { case 'src': // Make the URL absolute since relative URLs are not allowed in amp-iframe. if ( '/' === substr( $value, 0, 1 ) && '/' !== substr( $value, 1, 1 ) ) { $value = untrailingslashit( $this->args['current_origin'] ) . $value; } $value = $this->maybe_enforce_https_src( $value, true ); // Handle case where iframe source origin is the same as the host page's origin. if ( $this->get_origin_from_url( $value ) === $this->args['current_origin'] ) { if ( ! empty( $this->args['alias_origin'] ) ) { $value = preg_replace( '#^\w+://[^/]+#', $this->args['alias_origin'], $value ); } else { $remove_allow_same_origin = true; } } $out[ $name ] = $value; break; case 'width': case 'height': $out[ $name ] = $this->sanitize_dimension( $value, $name ); break; case 'frameborder': $out[ $name ] = $this->sanitize_boolean_digit( $value ); break; case 'allowfullscreen': case 'allowtransparency': if ( 'false' !== strtolower( $value ) ) { $out[ $name ] = ''; } break; case 'mozallowfullscreen': case 'webkitallowfullscreen': // Omit these since amp-iframe will add them if needed if the `allowfullscreen` attribute is present. break; case 'loading': /* * The `amp-iframe` component already does lazy-loading by default; trigger a validation error only * if the value is not `lazy`. */ if ( 'lazy' !== strtolower( $value ) ) { $out[ $name ] = $value; } break; case 'security': /* * Omit the `security` attribute as it now been superseded by the `sandbox` attribute. It is * (apparently) only supported by IE <https://stackoverflow.com/a/20071528>. */ break; case 'marginwidth': case 'marginheight': // These attributes have been obsolete since HTML5. If they have the value `0` they can be omitted. if ( '0' !== $value ) { $out[ $name ] = $value; } break; case 'data-amp-resizable': $out['resizable'] = ''; break; case 'data-amp-overflow-text': // No need to copy. break; case 'type': /* * Omit the `type` attribute if its value is `text/html`. Popular embed providers such as Amazon * Kindle use this non-standard attribute, which is apparently a vestige from usage on <object>. */ if ( 'text/html' !== strtolower( $value ) ) { $out[ $name ] = $value; } break; default: $out[ $name ] = $value; break; } } if ( ! isset( $out['sandbox'] ) ) { $out['sandbox'] = self::SANDBOX_DEFAULTS; } // Remove allow-same-origin from sandbox if required. if ( $remove_allow_same_origin ) { $out['sandbox'] = trim( preg_replace( '/(^|\s)allow-same-origin(\s|$)/', ' ', $out['sandbox'] ) ); } return $out; } /** * Obtain the origin part of a given URL (scheme, host, port). * * @param string $url URL. * @return string|null Origin URL or null if parse failed. */ private function get_origin_from_url( $url ) { $parsed_url = wp_parse_url( $url ); if ( ! isset( $parsed_url['host'] ) ) { return null; } if ( ! isset( $parsed_url['scheme'] ) ) { $parsed_url['scheme'] = wp_parse_url( $this->args['current_origin'], PHP_URL_SCHEME ); } $origin = $parsed_url['scheme'] . '://'; $origin .= $parsed_url['host']; if ( isset( $parsed_url['port'] ) ) { $origin .= ':' . $parsed_url['port']; } return $origin; } /** * Builds a DOMElement to use as a placeholder for an <iframe>. * * Important: The element returned must not be block-level (e.g. div) as the PHP DOM parser * will move it out from inside any containing paragraph. So this is why a span is used. * * @since 0.2 * * @return DOMElement|false */ private function build_placeholder() { return AMP_DOM_Utils::create_node( $this->dom, 'span', [ 'placeholder' => '', 'class' => 'amp-wp-iframe-placeholder', ] ); } /** * Sanitizes a boolean character (or string) into a '0' or '1' character. * * @param mixed $value A boolean character to sanitize. If a string containing more than a single * character is provided, only the first character is taken into account. * * @return string Returns either '0' or '1'. */ private function sanitize_boolean_digit( $value ) { // Default to false if the value was forgotten. if ( empty( $value ) ) { return '0'; } // Default to false if the value has an unexpected type. if ( ! is_string( $value ) && ! is_numeric( $value ) ) { return '0'; } // See: https://github.com/ampproject/amp-wp/issues/2335#issuecomment-493209861. switch ( substr( (string) $value, 0, 1 ) ) { case '1': case 'y': case 'Y': return '1'; } return '0'; } }
Upload Files
Cancel
Upload
Create New
Cancel
Create
Change Permissions
Cancel
Save
Change Date
Cancel
Save
Rename Item
Cancel
Save
Confirm Delete
Are you sure you want to delete the selected items?
Cancel
Delete