jon-b
5/26/2016 - 5:45 AM

PHP script to sanitize HTML using wp_kses_post() except allow <script src="http://youtube.com/..." type="..."> tags.

PHP script to sanitize HTML using wp_kses_post() except allow

<?php 

$html = "...";
echo Allow_Youtube_Scripts::sanitize_html( $html );

class Allow_Youtube_Scripts {

    static $allowed_protocols;

    static function sanitize_html( $html ) {

        if ( ! isset( self::$allowed_protocols ) ) {
            self::$allowed_protocols = wp_allowed_protocols();
        }

        add_filter( 'wp_kses_allowed_html', $filter = array( __CLASS__, '_wp_kses_allowed_html' ), 10, 2 );

        $html = wp_kses_post( $html );

        $html = preg_replace_callback('#<script(.+?)>#', array( __CLASS__, '_strip_non_youtube_scripts' ), $html );

        $html = preg_replace_callback('#<script.+?</script>?#ims', array( __CLASS__, '_strip_multiline_scripts' ), $html );

        $html = str_replace( '<~script', '<script', $html );

        remove_filter( 'wp_kses_allowed_html', $filter );

        return $html;
    }

    static function _wp_kses_allowed_html($tags, $context) {

        if ('post' === $context) {
            $tags['script'] = array_fill_keys(array('src', 'type'), true);
        }
        return $tags;

    }

    static function _strip_multiline_scripts( $script ) {
        return '';
    }

    static function _strip_non_youtube_scripts( $script ) {

        $attributes = wp_kses_hair( $script[1], self::$allowed_protocols );

        if ( empty( $attributes['src'] ) || ! preg_match( '#^https?://youtube.com/#', $attributes['src']['value'] ) ) {
            $script = $script[0];
        } else {
            $script = '<~script';
            foreach( array( 'src','type') as $attribute ) {
                if ( ! empty( $attributes[ $attribute ] ) ) {
                    $script .= " {$attributes['src']['whole']}";
                }
            }
            $script .= '>';
            if ( empty( $script[2] ) ) {
                $script .= '</script>';    
            } 

        }

        return $script;
    }
    
}