public function filter(string $string): string
    {
        $result = '';

        $string = $this->filterEntities($string);
        $string = $this->filterMetaTags($string);

        // Current/last tag name
        $tagName = null;
        // Current/last attribute name
        $attrName = null;
        // Current context
        $context = self::CTX_TAG_CONTENT;
        // Expected context
        $expecting = null;

        // By default tag content treated as text.
        $ignoreTagContent = false;
        // By default attribute values NOT treated as text.
        $ignoreAttrValue = true;

        $length = mb_strlen($string);
        for ($i = 0; $i < $length; $i++) {
            $char = mb_substr($string, $i, 1);
            switch (true) {
                case '<' === $char:
                    $context = self::CTX_TAG_NAME;
                    $tagName = null;
                    $char = ' ';
                    break;

                case '>' === $char:
                    if ($this->isIgnoredTag($tagName)) {
                        $ignoreTagContent = true;
                    } elseif ('/' === $tagName[0]) {
                        $ignoreTagContent = false; // Restore to default state.
                    }
                    $context = self::CTX_TAG_CONTENT;
                    $expecting = null;
                    $char = ' ';
                    break;

                case ' ' === $char:
                case "\n" === $char:
                case "\t" === $char:
                    switch ($context) {
                        case self::CTX_TAG_NAME:
                            $context = self::CTX_TAG_ATTRS;
                            break;

                        case self::CTX_ATTR_NAME:
                            $context = self::CTX_TAG_ATTRS;
                            break;
                    }
                    break;

                case '=' === $char
                    && (self::CTX_ATTR_NAME === $context || self::CTX_TAG_ATTRS === $context):
                    $expecting = self::CTX_ATTR_VALUE;
                    $char = ' ';
                    break;

                case '"' === $char:
                case "'" === $char:
                    switch (true) {
                        case self::CTX_ATTR_VALUE === $expecting:
                            $context = self::CTX_ATTR_VALUE;
                            $ignoreAttrValue
                                = !in_array(strtolower($attrName), self::$textAttrs, true);
                            $expecting = null;
                            $char = ' ';
                            break;

                        case self::CTX_ATTR_VALUE === $context:
                            $context = self::CTX_TAG_ATTRS;
                            $char = ' ';
                            break;
                    }
                    break;

                default:
                    switch ($context) {
                        case self::CTX_TAG_NAME:
                            $tagName .= $char;
                            $char = ' ';
                            break;

                        /** @noinspection PhpMissingBreakStatementInspection */
                        case self::CTX_TAG_ATTRS:
                            $context = self::CTX_ATTR_NAME;
                            $attrName = null;
                        // no break needed
                        case self::CTX_ATTR_NAME:
                            $attrName .= $char;
                            $char = ' ';
                            break;

                        case self::CTX_ATTR_VALUE:
                            if ($ignoreAttrValue) {
                                $char = ' ';
                            }
                            break;

                        case self::CTX_TAG_CONTENT:
                            if ($ignoreTagContent) {
                                $char = ' ';
                            }
                            break;
                    }
            }
            $result .= $char;
        }

        return $result;
    }
public function filter(string $string): string
    {
        $result = '';

        $string = $this->filterEntities($string);
        $string = $this->filterMetaTags($string);

        // Current/last tag name
        $tagName = null;
        // Current/last attribute name
        $attrName = null;
        // Current context
        $context = self::CTX_TAG_CONTENT;
        // Expected context
        $expecting = null;

        // By default tag content treated as text.
        $ignoreTagContent = false;
        // By default attribute values NOT treated as text.
        $ignoreAttrValue = true;

        $length = mb_strlen($string);
        for ($i = 0; $i < $length; $i++) {
            $char = mb_substr($string, $i, 1);
            switch (true) {
                case '<' === $char:
                    $context = self::CTX_TAG_NAME;
                    $tagName = null;
                    $char = ' ';
                    break;

                case '>' === $char:
                    if ($this->isIgnoredTag($tagName)) {
                        $ignoreTagContent = true;
                    } elseif ('/' === $tagName[0]) {
                        $ignoreTagContent = false; // Restore to default state.
                    }
                    $context = self::CTX_TAG_CONTENT;
                    $expecting = null;
                    $char = ' ';
                    break;

                case ' ' === $char:
                case "\n" === $char:
                case "\t" === $char:
                    switch ($context) {
                        case self::CTX_TAG_NAME:
                            $context = self::CTX_TAG_ATTRS;
                            break;

                        case self::CTX_ATTR_NAME:
                            $context = self::CTX_TAG_ATTRS;
                            break;
                    }
                    break;

                case '=' === $char
                    && (self::CTX_ATTR_NAME === $context || self::CTX_TAG_ATTRS === $context):
                    $expecting = self::CTX_ATTR_VALUE;
                    $char = ' ';
                    break;

                case '"' === $char:
                case "'" === $char:
                    switch (true) {
                        case self::CTX_ATTR_VALUE === $expecting:
                            $context = self::CTX_ATTR_VALUE;
                            $ignoreAttrValue
                                = !in_array(strtolower($attrName), self::$textAttrs, true);
                            $expecting = null;
                            $char = ' ';
                            break;

                        case self::CTX_ATTR_VALUE === $context:
                            $context = self::CTX_TAG_ATTRS;
                            $char = ' ';
                            break;
                    }
                    break;

                default:
                    switch ($context) {
                        case self::CTX_TAG_NAME:
                            $tagName .= $char;
                            $char = ' ';
                            break;

                        /** @noinspection PhpMissingBreakStatementInspection */
                        case self::CTX_TAG_ATTRS:
                            $context = self::CTX_ATTR_NAME;
                            $attrName = null;
                        // no break needed
                        case self::CTX_ATTR_NAME:
                            $attrName .= $char;
                            $char = ' ';
                            break;

                        case self::CTX_ATTR_VALUE:
                            if ($ignoreAttrValue) {
                                $char = ' ';
                            }
                            break;

                        case self::CTX_TAG_CONTENT:
                            if ($ignoreTagContent) {
                                $char = ' ';
                            }
                            break;
                    }
            }
            $result .= $char;
        }

        return $result;
    }
public function filter ( string $ string ) : string { $ result = '' ; $ string = $ this -> filterEntities ( $ string ) ; $ string = $ this -> filterMetaTags ( $ string ) ; // Current/last tag name $ tagName = null ; // Current/last attribute name $ attrName = null ; // Current context $ context = self :: CTX_TAG_CONTENT ; // Expected context $ expecting = null ; // By default tag content treated as text. $ ignoreTagContent = false ; // By default attribute values NOT treated as text. $ ignoreAttrValue = true ; $ length = mb_strlen ( $ string ) ; for ( $ i = 0 ; $ i < $ length ; $ i ++ ) { $ char = mb_substr ( $ string , $ i , 1 ) ; switch ( true ) { case '<' === $ char : $ context = self :: CTX_TAG_NAME ; $ tagName = null ; $ char = ' ' ; break ; case '>' === $ char : if ( $ this -> isIgnoredTag ( $ tagName ) ) { $ ignoreTagContent = true ; } elseif ( '/' === $ tagName [ 0 ] ) { $ ignoreTagContent = false ; // Restore to default state. } $ context = self :: CTX_TAG_CONTENT ; $ expecting = null ; $ char = ' ' ; break ; case ' ' === $ char : case "\n" === $ char : case "\t" === $ char : switch ( $ context ) { case self :: CTX_TAG_NAME : $ context = self :: CTX_TAG_ATTRS ; break ; case self :: CTX_ATTR_NAME : $ context = self :: CTX_TAG_ATTRS ; break ; } break ; case '=' === $ char && ( self :: CTX_ATTR_NAME === $ context || self :: CTX_TAG_ATTRS === $ context ) : $ expecting = self :: CTX_ATTR_VALUE ; $ char = ' ' ; break ; case '"' === $ char : case "'" === $ char : switch ( true ) { case self :: CTX_ATTR_VALUE === $ expecting : $ context = self :: CTX_ATTR_VALUE ; $ ignoreAttrValue = ! in_array ( strtolower ( $ attrName ) , self :: $ textAttrs , true ) ; $ expecting = null ; $ char = ' ' ; break ; case self :: CTX_ATTR_VALUE === $ context : $ context = self :: CTX_TAG_ATTRS ; $ char = ' ' ; break ; } break ; default : switch ( $ context ) { case self :: CTX_TAG_NAME : $ tagName .= $ char ; $ char = ' ' ; break ; /** @noinspection PhpMissingBreakStatementInspection */ case self :: CTX_TAG_ATTRS : $ context = self :: CTX_ATTR_NAME ; $ attrName = null ; // no break needed case self :: CTX_ATTR_NAME : $ attrName .= $ char ; $ char = ' ' ; break ; case self :: CTX_ATTR_VALUE : if ( $ ignoreAttrValue ) { $ char = ' ' ; } break ; case self :: CTX_TAG_CONTENT : if ( $ ignoreTagContent ) { $ char = ' ' ; } break ; } } $ result .= $ char ; } return $ result ; }
Filter string.

@param string $string String to be filtered.

@return string Filtered string.

@since 1.3
Filter string .