Вход Регистрация
Файл: outs/jevix/jevix.class.php
Строк: 487
<?php

class Jevix
{
    const 
PRINTABLE 0x1;
    const 
ALPHA 0x2;
    const 
LAT 0x4;
    const 
RUS 0x8;
    const 
NUMERIC 0x10;
    const 
SPACE 0x20;
    const 
NAME 0x40;
    const 
URL 0x100;
    const 
NOPRINT 0x200;
    const 
PUNCTUATUON 0x400;
    const 
HTML_QUOTE 0x2000;
    const 
TAG_QUOTE 0x4000;
    const 
QUOTE_CLOSE 0x8000;
    const 
NL 0x10000;
    const 
QUOTE_OPEN 0;
    const 
STATE_TEXT 0;
    const 
STATE_TAG_PARAMS 1;
    const 
STATE_TAG_PARAM_VALUE 2;
    const 
STATE_INSIDE_TAG 3;
    const 
STATE_INSIDE_NOTEXT_TAG 4;
    const 
STATE_INSIDE_PREFORMATTED_TAG 5;

    public 
$blackListMode false;
    public 
$commonTagParamRules = array();
    public 
$tagsRules = array();
    public 
$entities1 = array();
    public 
$entities2 = array();
    public 
$dash " — ";
    public 
$apostrof "’";
    public 
$dotes "…";
    public 
$nl "rn";
    public 
$mediaSrcValidate false;
    public 
$mediaValidSrc = array();
    public 
$forceShortTags = array('br''img''input''hr''link');
    protected 
$text;
    protected 
$textBuf;
    protected 
$textLen 0;
    protected 
$curPos;
    protected 
$curCh;
    protected 
$curChOrd;
    protected 
$curChClass;
    protected 
$curParentTag;
    protected 
$states;
    protected 
$quotesOpened 0;
    protected 
$brAdded 0;
    protected 
$state;
    protected 
$tagsStack;
    protected 
$openedTag;
    protected 
$isXHTMLMode false;
    protected 
$noTypoMode true;
    public 
$isAutoLinkMode false;
    public 
$outBuffer '';
    public 
$errors;

    const 
TR_TAG_LIST 1;
    const 
TR_PARAM_ALLOWED 2;
    const 
TR_PARAM_REQUIRED 3;
    const 
TR_TAG_SHORT 4;
    const 
TR_TAG_CUT 5;
    const 
TR_TAG_CHILD 6;
    const 
TR_TAG_CONTAINER 7;
    const 
TR_TAG_CHILD_TAGS 8;
    const 
TR_TAG_PARENT 9;
    const 
TR_TAG_PREFORMATTED 10;
    const 
TR_PARAM_AUTO_ADD 11;
    const 
TR_TAG_NO_TYPOGRAPHY 12;
    const 
TR_TAG_IS_EMPTY 13;
    const 
TR_TAG_NO_AUTO_BR 14;

    protected 
$chClasses = array(=> 512=> 512=> 512=> 512=> 512=> 512=> 512=> 512=> 512=> 3210 => 6604811 => 51212 => 51213 => 6604814 => 51215 => 51216 => 51217 => 51218 => 51219 => 51220 => 51221 => 51222 => 51223 => 51224 => 51225 => 51226 => 51227 => 51228 => 51229 => 51230 => 51231 => 51232 => 3297 => 7198 => 7199 => 71100 => 71101 => 71102 => 71103 => 71104 => 71105 => 71106 => 71107 => 71108 => 71109 => 71110 => 71111 => 71112 => 71113 => 71114 => 71115 => 71116 => 71117 => 71118 => 71119 => 71120 => 71121 => 71122 => 7165 => 7166 => 7167 => 7168 => 7169 => 7170 => 7171 => 7172 => 7173 => 7174 => 7175 => 7176 => 7177 => 7178 => 7179 => 7180 => 7181 => 7182 => 7183 => 7184 => 7185 => 7186 => 7187 => 7188 => 7189 => 7190 => 711072 => 111073 => 111074 => 111075 => 111076 => 111077 => 111078 => 111079 => 111080 => 111081 => 111082 => 111083 => 111084 => 111085 => 111086 => 111087 => 111088 => 111089 => 111090 => 111091 => 111092 => 111093 => 111094 => 111095 => 111096 => 111097 => 111098 => 111099 => 111100 => 111101 => 111102 => 111103 => 111040 => 111041 => 111042 => 111043 => 111044 => 111045 => 111046 => 111047 => 111048 => 111049 => 111050 => 111051 => 111052 => 111053 => 111054 => 111055 => 111056 => 111057 => 111058 => 111059 => 111060 => 111061 => 111062 => 111063 => 111064 => 111065 => 111066 => 111067 => 111068 => 111069 => 111070 => 111071 => 1148 => 33749 => 33750 => 33751 => 33752 => 33753 => 33754 => 33755 => 33756 => 33757 => 33734 => 5734539 => 1638546 => 128144 => 102533 => 102563 => 128158 => 102559 => 12811105 => 111025 => 1147 => 25738 => 25737 => 25745 => 25795 => 25761 => 25743 => 25735 => 257124 => 257,);

    protected function &
strToArray$str )
    {
        
$chars null;
        
preg_match_all('/./su'$str$chars);
        return 
$chars[0];
    }

    function 
parse$text )
    {
        
$this->curPos = -1;
        
$this->curCh null;
        
$this->curChOrd 0;
        
$this->state self::STATE_TEXT;
        
$this->states = array();
        
$this->quotesOpened 0;
        
$this->noTypoMode false;
        
$this->text $text;
        
$this->textBuf $this->strToArray($this->text);
        
$this->textLen count($this->textBuf);
        
$this->getCh();
        
$content '';
        
$this->outBuffer '';
        
$this->brAdded 0;
        
$this->tagsStack = array();
        
$this->openedTag null;
        
$this->errors = array();

        
$this->skipSpaces();

        
$this->anyThing($content);

        if ( 
mb_strstr($content'<!--') && (mb_substr_count($content'<!--') > mb_substr_count($content'-->')) )
        {
            
$content .= '-->';
        }

        return 
$content;
    }

    protected function 
getCh()
    {
        return 
$this->goToPosition($this->curPos 1);
    }

    protected function 
goToPosition$position )
    {
        
$this->curPos $position;
        if ( 
$this->curPos $this->textLen )
        {
            
$this->curCh $this->textBuf[$this->curPos];
            
$this->curChOrd uniord($this->curCh);
            
$this->curChClass $this->getCharClass($this->curChOrd);
        }
        else
        {
            
$this->curCh null;
            
$this->curChOrd 0;
            
$this->curChClass 0;
        }
        return 
$this->curCh;
    }

    protected function 
saveState()
    {
        
$state = array(
            
'pos' => $this->curPos,
            
'ch' => $this->curCh,
            
'ord' => $this->curChOrd,
            
'class' => $this->curChClass,
        );

        
$this->states[] = $state;
        return 
count($this->states) - 1;
    }

    protected function 
restoreState$index null )
    {
        if ( !
count($this->states) )
        {
            throw new 
Exception('The end of stack');
        }

        if ( 
$index == null )
        {
            
$state array_pop($this->states);
        }
        else
        {
            if ( !isset(
$this->states[$index]) )
            {
                throw new 
Exception('Invalid stack index');
            }
            
$state $this->states[$index];
            
$this->states array_slice($this->states0$index);
        }

        
$this->curPos $state['pos'];
        
$this->curCh $state['ch'];
        
$this->curChOrd $state['ord'];
        
$this->curChClass $state['class'];
    }

    protected function 
matchCh$ch$skipSpaces false )
    {
        if ( 
$this->curCh == $ch )
        {
            
$this->getCh();
            if ( 
$skipSpaces )
            {
                
$this->skipSpaces();
            }
            return 
true;
        }

        return 
false;
    }

    protected function 
matchChClass$chClass$skipSpaces false )
    {
        if ( (
$this->curChClass $chClass) == $chClass )
        {
            
$ch $this->curCh;
            
$this->getCh();
            if ( 
$skipSpaces )
            {
                
$this->skipSpaces();
            }
            return 
$ch;
        }

        return 
false;
    }

    protected function 
matchStr$str$skipSpaces false )
    {
        
$this->saveState();
        
$len mb_strlen($str'UTF-8');
        
$test '';
        while ( 
$len-- && $this->curChClass )
        {
            
$test.=$this->curCh;
            
$this->getCh();
        }

        if ( 
$test == $str )
        {
            if ( 
$skipSpaces )
            {
                
$this->skipSpaces();
            }
            return 
true;
        }
        else
        {
            
$this->restoreState();
            return 
false;
        }
    }

    protected function 
skipUntilCh$ch )
    {
        
$chPos mb_strpos($this->text$ch$this->curPos'UTF-8');
        if ( 
$chPos )
        {
            return 
$this->goToPosition($chPos);
        }
        else
        {
            return 
false;
        }
    }

    protected function 
skipUntilStr$str )
    {
        
$str $this->strToArray($str);
        
$firstCh $str[0];
        
$len count($str);
        while ( 
$this->curChClass )
        {
            if ( 
$this->curCh == $firstCh )
            {
                
$this->saveState();
                
$this->getCh();
                
$strOK true;
                for ( 
$i 1$i $len$i++ )
                {
                    if ( !
$this->curChClass )
                    {
                        return 
false;
                    }

                    if ( 
$this->curCh != $str[$i] )
                    {
                        
$strOK false;
                        break;
                    }

                    
$this->getCh();
                }

                if ( !
$strOK )
                {
                    
$this->restoreState();
                }
                else
                {
                    return 
true;
                }
            }

            
$this->getCh();
        }
        return 
false;
    }

    protected function 
getCharClass$ord )
    {
        return isset(
$this->chClasses[$ord]) ? $this->chClasses[$ord] : self::PRINTABLE;
    }

    protected function 
skipSpaces( &$count )
    {
        while ( 
$this->curChClass == self::SPACE )
        {
            
$this->getCh();
            
$count++;
        }
        return 
$count 0;
    }

    protected function 
name( &$name ''$minus false )
    {
        
$this->skipNL();

        if ( (
$this->curChClass self::LAT) == self::LAT )
        {
            
$name.=$this->curCh;
            
$this->getCh();
        }
        else
        {
            return 
false;
        }

        while ( ((
$this->curChClass self::NAME) == self::NAME || ($minus && !in_array($this->curCh, array(' ''=''>')) ) ) )
        {
            
$name.=$this->curCh;
            
$this->getCh();
        }

        
$this->skipSpaces();
        return 
true;
    }

    protected function 
tag( &$tag, &$params, &$content, &$short )
    {
        
$this->saveState();
        
$params = array();
        
$tag '';
        
$closeTag '';
        
$params = array();
        
$short false;

        if ( !
$this->tagOpen($tag$params$short) )
        {
            return 
false;
        }

        if ( 
$short )
        {
            return 
true;
        }

        
$oldState $this->state;
        
$oldNoTypoMode $this->noTypoMode;

        if ( !empty(
$this->tagsRules[$tag][self::TR_TAG_PREFORMATTED]) )
        {
            
$this->state self::STATE_INSIDE_PREFORMATTED_TAG;
        }
        elseif ( !empty(
$this->tagsRules[$tag][self::TR_TAG_CONTAINER]) )
        {
            
$this->state self::STATE_INSIDE_NOTEXT_TAG;
        }
        elseif ( !empty(
$this->tagsRules[$tag][self::TR_TAG_NO_TYPOGRAPHY]) )
        {
            
$this->noTypoMode true;
            
$this->state self::STATE_INSIDE_TAG;
        }
        else
        {
            
$this->state self::STATE_INSIDE_TAG;
        }

        
array_push($this->tagsStack$tag);
        
$this->openedTag $tag;
        
$content '';
        if ( 
$this->state == self::STATE_INSIDE_PREFORMATTED_TAG )
        {
            
$this->preformatted($content$tag);
        }
        else
        {
            
$this->anyThing($content$tag);
        }

        
array_pop($this->tagsStack);
        
$this->openedTag = !empty($this->tagsStack) ? array_pop($this->tagsStack) : null;

        
$isTagClose $this->tagClose($closeTag);
        if ( 
$isTagClose && ($tag != $closeTag) )
        {
            
$this->error("Invalid tag close $closeTag. > expected $tag");
        }

        
$this->state $oldState;
        
$this->noTypoMode $oldNoTypoMode;

        return 
true;
    }

    protected function 
preformatted( &$content ''$insideTag null )
    {
        while ( 
$this->curChClass )
        {
            if ( 
$this->curCh == '<' )
            {
                
$tag '';
                
$this->saveState();

                
$isClosedTag $this->tagClose($tag);

                if ( 
$isClosedTag )
                {
                    
$this->restoreState();
                }

                if ( 
$isClosedTag && $tag == $insideTag )
                {
                    return;
                }
            }
            
$content.= isset($this->entities2[$this->curCh]) ? $this->entities2[$this->curCh] : $this->curCh;
            
$this->getCh();
        }
    }

    protected function 
tagOpen( &$name, &$params, &$short false )
    {
        
$restore $this->saveState();

        if ( !
$this->matchCh('<') )
        {
            return 
false;
        }
        
$this->skipSpaces();
        if ( !
$this->name($name) )
        {
            
$this->restoreState();
            return 
false;
        }
        
$name mb_strtolower($name'UTF-8');

        if ( 
$this->curCh != '>' && $this->curCh != '/' )
        {
            
$this->tagParams($params);
        }

        
$short = ( /* $this->curCh == '/' && */ in_array($name$this->forceShortTags) && !empty($this->tagsRules[$name][self::TR_TAG_SHORT]) );

        
$slash $this->matchCh('/');

        if ( !
$short && $slash && empty($this->tagsRules[$name][self::TR_TAG_SHORT]) )
        {
            
$this->restoreState();
            return 
false;
        }

        if ( 
$slash )
        {
            
$short true;
        }

        
$this->skipSpaces();

        if ( !
$this->matchCh('>') )
        {
            
$this->restoreState($restore);
            return 
false;
        }

        
$this->skipSpaces();
        return 
true;
    }

    protected function 
tagParams( &$params = array() )
    {
        
$name null;
        
$value null;
        while ( 
$this->tagParam($name$value) )
        {
            
$params[$name] = $value;
            
$name '';
            
$value '';
        }
        return 
count($params) > 0;
    }

    protected function 
tagParam( &$name, &$value )
    {
        
$this->saveState();
        if ( !
$this->name($nametrue) )
        {
            return 
false;
        }

        if ( !
$this->matchCh('='true) )
        {
            if ( (
$this->curCh == '>' || ($this->curChClass self::LAT) == self::LAT ) )
            {
                
$value $name;
                return 
true;
            }
            else
            {
                
$this->restoreState();
                return 
false;
            }
        }

        
$quote $this->matchChClass(self::TAG_QUOTEtrue);

        if ( !
$this->tagParamValue($value$quote) )
        {
            
$this->restoreState();
            return 
false;
        }

        if ( 
$quote && !$this->matchCh($quotetrue) )
        {
            
$this->restoreState();
            return 
false;
        }

        
$this->skipSpaces();
        return 
true;
    }

    protected function 
tagParamValue( &$value$quote )
    {
        if ( 
$quote !== false )
        {
            
$escape false;
            while ( 
$this->curChClass && ($this->curCh != $quote || $escape) )
            {
                
$escape false;

                
$value.=isset($this->entities1[$this->curCh]) ? $this->entities1[$this->curCh] : $this->curCh;

                if ( 
$this->curCh == '\' )
                {
                    $escape = true;
                }
                $this->getCh();
            }
        }
        else
        {
            while ( $this->curChClass && !($this->curChClass & self::SPACE) && $this->curCh != '
>' )
            {
                $value.=isset($this->entities1[$this->curCh]) ? $this->entities1[$this->curCh] : $this->curCh;
                $this->getCh();
            }
        }

        return true;
    }

    protected function tagClose( &$name )
    {
        $this->saveState();
        if ( !$this->matchCh('
<') )
        {
            return false;
        }
        $this->skipSpaces();
        if ( !$this->matchCh('
/') )
        {
            $this->restoreState();
            return false;
        }
        $this->skipSpaces();
        if ( !$this->name($name) )
        {
            $this->restoreState();
            return false;
        }
        $name = mb_strtolower($name, '
UTF-8');
        $this->skipSpaces();
        if ( !$this->matchCh('
>') )
        {
            $this->restoreState();
            return false;
        }
        return true;
    }

    protected function makeTag( $tag, $params, $content, $short, $parentTag = null )
    {
        $this->curParentTag = $parentTag;

        $tag = mb_strtolower($tag, '
UTF-8');

        $tagRules = isset($this->tagsRules[$tag]) ? $this->tagsRules[$tag] : null;

        $parentTagIsContainer = $parentTag && isset($this->tagsRules[$parentTag][self::TR_TAG_CONTAINER]);

        if ( ( $this->blackListMode && !empty($tagRules[self::TR_TAG_LIST]) ) || (!$this->blackListMode && empty($tagRules[self::TR_TAG_LIST]) ) )
        {
            return !empty($this->tagsRules[$tag][self::TR_TAG_CUT]) ? '' : $content;
        }

        if ( (!$this->blackListMode && !$tagRules ) || (!$this->blackListMode && empty($tagRules[self::TR_TAG_LIST])) || ( $this->blackListMode && !empty($tagRules[self::TR_TAG_LIST]) ) )
        {
            return $parentTagIsContainer ? '' : $content;
        }

// hardcoded black list
        if ( in_array($tag, array('
meta', 'title', 'html', 'body', 'head')) )
        {
            return '';
        }
// params processing
        $resParams = array();

        foreach ( $params as $param => $value )
        {
            $param = mb_strtolower($param, '
UTF-8');
            $value = trim($value);

// custom iframe processing
            if ( $this->mediaSrcValidate && in_array($tag, array('
iframe', 'object', 'embed', 'param')) && in_array($param, array('src')) )
            {
                $val = $value;

                if ( mb_substr($val, 0, 2) == '
//' )
                
{
                    
$val 'http:' $val;
                }

                
$urlArr parse_url($val);

                
$parts explode('.'$urlArr['host']);

                if ( 
count($parts) < )
                {
                    return 
'';
                }

                
$d1 array_pop($parts);
                
$d2 array_pop($parts);

                
$host $d2 '.' $d1;

                if ( !
in_array($host$this->mediaValidSrc) && !in_array($urlArr['host'], $this->mediaValidSrc) )
                {
                    return 
'';
                }
            }

// if value is empty ignore param
//            if ( empty($value) )
//            {
//                continue;
//            }

            
if ( $this->blackListMode )
            {
                if ( 
in_array('*'$this->commonTagParamRules) || !empty($tagRules[self::TR_PARAM_ALLOWED]['*']) || isset($tagRules[self::TR_PARAM_ALLOWED][$param]) || in_array($param$this->commonTagParamRules) )
                {
                    continue;
                }
            }
            else
            {
                if ( !
in_array('*'$this->commonTagParamRules) && empty($tagRules[self::TR_PARAM_ALLOWED]['*']) && !isset($tagRules[self::TR_PARAM_ALLOWED][$param]) && !in_array($param$this->commonTagParamRules) )
                {
                    continue;
                }
            }

            
$resParams[$param] = $value;
        }

        
$text '<' $tag;

        foreach ( 
$resParams as $param => $value )
        {
            
$text.=' ' $param '="' $value '"';
        }

        
$text.= $short ' />' '>';

        if ( isset(
$tagRules[self::TR_TAG_CONTAINER]) )
        {
            
$text .= "rn";
        }
        if ( !
$short )
        {
            
$text.= $content '</' $tag '>';
        }
        if ( 
$parentTagIsContainer )
        {
            
$text .= "rn";
        }
        if ( 
$tag == 'br' )
        {
            
$text.="rn";
        }

        return 
$text;
    }

    protected function 
comment()
    {
        return 
false;
        if ( !
$this->matchStr('<!--') )
        {
            return 
false;
        }
        return 
$this->skipUntilStr('-->');
    }

    protected function 
anyThing( &$content ''$parentTag null )
    {
        
$this->skipNL();

        while ( 
$this->curChClass )
        {
            
$tag '';
            
$params null;
            
$text null;
            
$shortTag false;
            
$name null;

            if ( 
$this->state == self::STATE_INSIDE_NOTEXT_TAG && $this->curCh != '<' )
            {
                
$this->skipUntilCh('<');
            }

            if ( 
$this->curCh == '<' && $this->tag($tag$params$text$shortTag) )
            {
                
$tagText $this->makeTag($tag$params$text$shortTag$parentTag);

                
$content.=$tagText;

                if ( 
$tag == 'br' )
                {
                    
$this->skipNL();
                }
                elseif ( empty(
$tagText) )
                {
                    
$this->skipSpaces();
                }
            }
            elseif ( 
$this->curCh == '<' && $this->comment() )
            {
                continue;
            }
            elseif ( 
$this->curCh == '<' )
            {
                
$this->saveState();
                if ( 
$this->tagClose($name) )
                {
                    if ( 
$this->state == self::STATE_INSIDE_TAG || $this->state == self::STATE_INSIDE_NOTEXT_TAG )
                    {
                        
$this->restoreState();
                        return 
false;
                    }
                    else
                    {
                        
$this->error('Unexpectedly closed tag `>` ' $name);
                    }
                }
                else
                {
                    if ( 
$this->state != self::STATE_INSIDE_NOTEXT_TAG )
                    {
                        
$content.= '<'//$this->entities2['<'];
                    
}
                    
$this->getCh();
                }
            }
            elseif ( 
$this->text($text) )
            {
                
$content.=$text;
            }
        }

//        $content = str_replace(array('<!--', '-->'), array('##lc##', '##lc##'), $content);
//        $content = str_replace(array('<', '>'), array('&lt;', '&gt;'), $content);
//        $content = str_replace(array('##lc##', '##lc##'), array('<!--', '-->'), $content);

        
return true;
    }

    protected function 
skipNL( &$count )
    {
        if ( !(
$this->curChClass self::NL) )
        {
            return 
false;
        }

        
$count++;
        
$firstNL $this->curCh;
        
$nl $this->getCh();

        while ( 
$this->curChClass self::NL )
        {

            if ( 
$nl == $firstNL )
            {
                
$count++;
            }
            
$nl $this->getCh();

            
$this->skipSpaces();
        }
        return 
true;
    }

    protected function 
text( &$text )
    {
        
$text '';
        
$dash '';
        
$newLine true;
        
$newWord true;
        
$url null;
        
$href null;

        while ( (
$this->curCh != '<') && $this->curChClass )
        {
            
$brCount 0;
            
$spCount 0;
            
$quote null;
            
$closed false;
            
$punctuation null;
            
$entity null;

            
$this->skipSpaces($spCount);

            if ( 
$spCount )
            {
                
$text.=' ';
                
$newWord true;
            }
            elseif ( 
$this->skipNL($brCount) )
            {
                if ( 
$this->curParentTag && isset($this->tagsRules[$this->curParentTag]) && isset($this->tagsRules[$this->curParentTag][self::TR_TAG_NO_AUTO_BR]) && (is_null($this->openedTag) or isset($this->tagsRules[$this->openedTag][self::TR_TAG_NO_AUTO_BR]))
                )
                {
                    
                }
                else
                {
                    
$text.= str_repeat("rn"$brCount);
                }

                
$newLine true;
                
$newWord true;
            }
            elseif ( 
$this->isAutoLinkMode && ($this->curChClass self::LAT) && $this->openedTag != 'a' && $this->url($url$href) )
            {
                
$linkLabel $url;

                if ( 
strlen($linkLabel) > 60 )
                {
                    
$arr parse_url($linkLabel);

                    
$domain = (!empty($arr['scheme']) ? $arr['scheme'] . '://' '' ) . (!empty($arr['host']) ? $arr['host'] : '' ) . (!empty($arr['port']) ? ':' $arr['port'] : '' ) . '/';
                    
$qs = (!empty($arr['path']) ? $arr['path'] : '' ) . (!empty($arr['query']) ? '?' $arr['query'] : '' );

                    if ( 
strlen($qs) > 23 )
                    {
                        
$qs '...' substr($qs, -20);
                    }

                    
$linkLabel $domain $qs;
                }


                
$text.= $this->makeTag('a', array('href' => $href'class' => 'peep_autolink''target' => '_blank''rel' => 'nofollow'), $linkLabelfalse);
                
$newWord true;
            }
            elseif ( 
$this->curChClass self::PRINTABLE )
            {
                
$text.=isset($this->entities2[$this->curCh]) ? $this->entities2[$this->curCh] : $this->curCh;
                
$this->getCh();
                
$newWord false;
                
$newLine false;
            }
            else
            {
                
$this->getCh();
            }
        }

        
$this->skipSpaces();
        return 
$text != '';
    }

    
// fake function to optimize url function
    
private function simpleMatchString$string )
    {
        
$count mb_strlen($string);
        for ( 
$i 0$i $count$i++ )
        {
            if ( !isset(
$this->textBuf[$this->curPos $i]) || $this->textBuf[$this->curPos $i] !== mb_substr($string$i1) )
            {
                return 
false;
            }
        }
        return 
true;
    }

    protected function 
url( &$url, &$href )
    {
        
$hrefPrefix null;

        if ( !empty(
$this->curPos) && $this->getCharClass(uniord($this->textBuf[$this->curPos 1])) === self::PRINTABLE )
        {
            return 
false;
        }

        if ( 
$this->curCh === 'h' )
        {
            if ( 
$this->simpleMatchString('http://') )
            {
                
$hrefPrefix 'http://';
                
$this->goToPosition($this->curPos 7);
            }
            else if ( 
$this->simpleMatchString('https://') )
            {
                
$hrefPrefix 'https://';
                
$this->goToPosition($this->curPos 8);
            }
        }
        else if ( 
$this->curCh === 'w' )
        {
            if ( 
$this->simpleMatchString('www.') )
            {
                
$hrefPrefix 'http://www.';
                
$urlPrefix 'www.';
                
$this->goToPosition($this->curPos 4);
            }
        }

        if ( 
$hrefPrefix === null )
        {
            return 
false;
        }

        
$this->saveState();
        
$url '';
        
$urlChMask self::URL self::ALPHA;
        
$urlPunctValidChars = array(":"",""!""'""~""."";");
        
        while ( 
$this->curChClass $urlChMask || in_array($this->curCh$urlPunctValidChars) )
        {            
            
$url.= $this->curCh;
            
$this->getCh();
        }
        
        
$chCount 0;        
        
        for( 
$i = (mb_strlen($url) - 1); $i >= 0$i-- )
        {
            if( 
in_array(mb_substr($url$i1), $urlPunctValidChars) )
            {
                
$chCount++;
            }
            else
            {
                break;
            }
        }
        
        if( 
$chCount )
        {
            
$url mb_substr($url0mb_strlen($url) - $chCount);
            
$this->goToPosition($this->curPos-$chCount);
        }       
        
        if( 
mb_strlen($url) == )
        {
            return 
false;
        }
        
        if ( !
mb_strlen($url) )
        {
            
$this->restoreState();
            return 
false;
        }

        
$href $hrefPrefix $url;
        
$url = !empty($urlPrefix) ? $urlPrefix $url $href;
        return 
true;
    }

    protected function 
error$message )
    {
        
$str '';
        
$strEnd min($this->curPos 8$this->textLen);
        for ( 
$i $this->curPos$i $strEnd$i++ )
        {
            
$str.=$this->textBuf[$i];
        }

        
$this->errors[] = array(
            
'message' => $message,
            
'pos' => $this->curPos,
            
'ch' => $this->curCh,
            
'line' => 0,
            
'str' => $str,
        );
    }
}

function 
uniord$c )
{
    
$h ord($c{0});
    if ( 
$h <= 0x7F )
    {
        return 
$h;
    }
    else if ( 
$h 0xC2 )
    {
        return 
false;
    }
    else if ( 
$h <= 0xDF )
    {
        return (
$h 0x1F) << | (ord($c{1}) & 0x3F);
    }
    else if ( 
$h <= 0xEF )
    {
        return (
$h 0x0F) << 12 | (ord($c{1}) & 0x3F) << | (ord($c{2}) & 0x3F);
    }
    else if ( 
$h <= 0xF4 )
    {
        return (
$h 0x0F) << 18 | (ord($c{1}) & 0x3F) << 12 | (ord($c{2}) & 0x3F) << | (ord($c{3}) & 0x3F);
    }
    else
    {
        return 
false;
    }
}
Онлайн: 2
Реклама