Passed
Push — master ( 357b9b...ef7620 )
by Limon
02:56
created

AdblockRule::isException()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
namespace Limonte;
3
4
class AdblockRule
5
{
6
    private $rule;
7
8
    private $regex;
9
10
    private $isComment = false;
11
12
    private $isHtml = false;
13
14
    private $isException = false;
15
16
    public function __construct($rule)
17
    {
18
        $this->rule = $rule;
19
20
        if ($this->startsWith($this->rule, '@@')) {
21
            $this->isException = true;
22
            $this->rule = mb_substr($this->rule, 2);
23
        }
24
25
        // comment
26
        if ($this->startsWith($rule, '!') || $this->startsWith($rule, '[Adblock')) {
27
            $this->isComment = true;
28
29
        // HTML rule
30
        } elseif ($this->contains($rule, '##') || $this->contains($rule, '#@#')) {
31
            $this->isHtml = true;
32
33
        // URI rule
34
        } else {
35
            $this->makeRegex();
36
        }
37
    }
38
39
    /**
40
     * @param  string  $url
41
     *
42
     * @return  boolean
43
     */
44
    public function matchUrl($url)
45
    {
46
        return (boolean)preg_match(
47
            '/' . $this->getRegex() . '/',
48
            $url
49
        );
50
    }
51
52
    /**
53
     * @return  string
54
     */
55
    public function getRegex()
56
    {
57
        return $this->regex;
58
    }
59
60
    /**
61
     * @return  boolean
62
     */
63
    public function isComment()
64
    {
65
        return $this->isComment;
66
    }
67
68
    /**
69
     * @return  boolean
70
     */
71
    public function isHtml()
72
    {
73
        return $this->isHtml;
74
    }
75
76
    /**
77
     * @return  boolean
78
     */
79
    public function isException()
80
    {
81
        return $this->isException;
82
    }
83
84
    private function makeRegex()
85
    {
86
        if (empty($this->rule)) {
87
            throw new InvalidRuleException("Empty rule");
88
        }
89
90
        $regex = $this->rule;
91
92
        // Check if the rule isn't already regexp
93
        if ($this->startsWith($regex, '/') && $this->endsWith($regex, '/')) {
94
            $this->regex = mb_substr($this->rule, 1, mb_strlen($this->rule) - 2);
95
96
            if (empty($this->regex)) {
97
                throw new InvalidRuleException("Empty rule");
98
            }
99
100
            return;
101
        }
102
103
        // escape special regex characters
104
        $regex = preg_replace("/([\\\.\$\+\?\{\}\(\)\[\]\/])/", "\\\\$1", $this->rule);
105
106
        // Separator character ^ matches anything but a letter, a digit, or
107
        // one of the following: _ - . %. The end of the address is also
108
        // accepted as separator.
109
        $regex = str_replace("^", "([^\w\d_\-.%]|$)", $regex);
110
111
        // * symbol
112
        $regex = str_replace("*", ".*", $regex);
113
114
        // | in the end means the end of the address
115
        if ($this->endsWith($regex, '|')) {
116
            $regex = mb_substr($regex, 0, mb_strlen($regex) - 1) . '$';
117
        }
118
119
        // || in the beginning means beginning of the domain name
120
        if ($this->startsWith($regex, '||')) {
121
            if (mb_strlen($regex) > 2) {
122
                // http://tools.ietf.org/html/rfc3986#appendix-B
123
                $regex = "^([^:\/?#]+:)?(\/\/([^\/?#]*\.)?)?" . mb_substr($regex, 2);
124
            }
125
        // | in the beginning means start of the address
126
        } elseif ($this->startsWith($regex, '|')) {
127
            $regex = '^' . mb_substr($regex, 1);
128
        }
129
130
        // other | symbols should be escaped
131
        $regex = preg_replace("/\|(?![\$])/", "\|$1", $regex);
132
133
        $this->regex = $regex;
134
    }
135
136
    private function startsWith($haystack, $needle)
137
    {
138
        $length = mb_strlen($needle);
139
        return (mb_substr($haystack, 0, $length) === $needle);
140
    }
141
142
    private function endsWith($haystack, $needle)
143
    {
144
        $length = mb_strlen($needle);
145
        if ($length == 0) {
146
            return true;
147
        }
148
149
        return (mb_substr($haystack, -$length) === $needle);
150
    }
151
152
    private function contains($haystack, $needle)
153
    {
154
        return strpos($haystack, $needle) !== false;
155
    }
156
}
157