GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( ac9ac4...942aba )
by Joram van den
04:18
created

Blocker::isRefererOnBlocklist()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 1 Features 0
Metric Value
c 6
b 1
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 6
nc 2
nop 0
1
<?php
2
namespace Nabble\SemaltBlocker;
3
4
/**
5
 * The most important class for this package. Basic usage:
6
 * ```
7
 * Blocker::protect();
8
 * ```
9
 *
10
 * @package Nabble\SemaltBlocker
11
 */
12
class Blocker
13
{
14
    const SEPERATOR = ':';
15
16
    public static $explanation = "Access to this website has been blocked because your referral is set to %s. <a href='%s'>Read why</a>";
17
18
    private static $blocklist = './../../domains/blocked';
19
    private static $reason    = 'Not blocking, no reason given';
20
21
    //////////////////////////////////////////
22
    // PUBLIC API                           //
23
    //////////////////////////////////////////
24
25
    /**
26
     * Block a page if referer is found on list of blocked domains
27
     *
28
     * @param string $action If empty, send 403 response; if URL, redirect here; if non-empty string, print message
29
     */
30
    public static function protect($action = '')
31
    {
32
        // Try to update the list
33
        if (!defined('SEMALT_UNIT_TESTING')) Updater::update();
34
35
        // Simply stop here if referer is not on the list
36
        if (!self::isRefererOnBlocklist()) return;
37
38
        self::doBlock($action);
39
40
        // Stop execution altogether, bye bye bots
41
        if (!defined('SEMALT_UNIT_TESTING')) exit;
42
    }
43
44
    /**
45
     * @param bool $verbose Deprecated. Please use the explain() method instead.
46
     * @return bool|string
47
     */
48
    public static function blocked($verbose = false)
49
    {
50
        $blocked = self::isRefererOnBlocklist();
51
        if ($verbose === true) {
52
            return self::$reason;
53
        }
54
        return $blocked;
55
    }
56
57
    /**
58
     * @return string
59
     */
60
    public static function explain()
61
    {
62
        return self::$reason;
63
    }
64
65
    /**
66
     * Send a 403 Forbidden header
67
     */
68
    public static function forbidden()
69
    {
70
        $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
71
        header($protocol . ' 403 Forbidden');
72
    }
73
74
    /**
75
     * @return array
76
     */
77
    public static function getBlocklist()
78
    {
79
        return self::parseBlocklist(self::getBlocklistContents());
80
    }
81
82
    /**
83
     * @return string
84
     */
85
    public static function getBlocklistFilename()
86
    {
87
        return __DIR__ . DIRECTORY_SEPARATOR . static::$blocklist;
0 ignored issues
show
Bug introduced by
Since $blocklist is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $blocklist to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
88
    }
89
90
    //////////////////////////////////////////
91
    // PRIVATE FUNCTIONS                    //
92
    //////////////////////////////////////////
93
94
    /**
95
     * Responsible for sending action output
96
     *
97
     * @param string $action
98
     */
99
    private static function doBlock($action = '')
100
    {
101
        // Clear buffered output
102
        if (!defined('SEMALT_UNIT_TESTING')) self::cls();
103
104
        // Take user defined action
105
        self::blockAction($action);
106
107
        // If a human comes by, don't just serve a blank page
108
        echo sprintf(self::$explanation, self::getHttpReferer(), "https://www.google.com/#q=" . urlencode(preg_replace('/https?:\/\//', '', self::getHttpReferer()) . " referral spam"));
109
    }
110
111
    /**
112
     * Execute desired action
113
     *
114
     * @param string $action
115
     */
116
    private static function blockAction($action = '')
117
    {
118
        // Redirect or 403
119
        if (filter_var($action, FILTER_VALIDATE_URL)) {
120
            self::redirect($action);
121
        } else {
122
            self::forbidden();
123
            if (!empty($action)) echo $action . '<br/>'; // tell them something nice
124
        }
125
    }
126
127
128
    /**
129
     * Clear output buffer
130
     */
131
    private static function cls()
132
    {
133
        while (ob_get_level()) ob_end_clean();
134
    }
135
136
    /**
137
     * Redirect to a url by sending the appropriate header.
138
     * @param string $url
139
     */
140
    private static function redirect($url)
141
    {
142
        header("Location: " . $url);
143
    }
144
145
146
    /**
147
     * The public use of this function is undocumented.
148
     *
149
     * @return bool
150
     */
151
    public static function isRefererOnBlocklist()
152
    {
153
        $referer = self::getHttpReferer();
154
        if ($referer === null) {
155
            self::$reason = "Not blocking because referer header is not set or empty";
156
157
            return false;
158
        }
159
160
        return self::isUrlOnBlocklist($referer, "referer");
161
    }
162
163
164
    /**
165
     * The public use of this function is undocumented.
166
     *
167
     * @param string $url
168
     * @param string $entity
169
     * @return bool
170
     */
171
    public static function isUrlOnBlocklist($url, $entity = 'url')
172
    {
173
        $rootDomain = Domainparser::getRootDomain($url);
174
        if ($rootDomain === false) {
175
            self::$reason = "Not blocking because we couldn't parse root domain";
176
177
            return false;
178
        }
179
180
        $blocklist = self::getConcatenateBlocklist();
181 View Code Duplication
        if (substr_count($blocklist, self::SEPERATOR . $rootDomain . self::SEPERATOR)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
182
            self::$reason = "Blocking because " . $entity . " root domain (" . $rootDomain . ") is found on blocklist";
183
184
            return true;
185
        }
186
187
        $hostname = Domainparser::getHostname($url);
188 View Code Duplication
        if (substr_count($blocklist, self::SEPERATOR . $hostname . self::SEPERATOR)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
189
            self::$reason = "Blocking because " . $entity . " hostname (" . $hostname . ") is found on blocklist";
190
191
            return true;
192
        }
193
194
        $path = Domainparser::getPath($url);
195
        if (trim($path, '/')) {
196 View Code Duplication
            if (substr_count($blocklist, self::SEPERATOR . $rootDomain . $path . self::SEPERATOR)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
197
                self::$reason = "Blocking because " . $entity . " root domain/path (" . $rootDomain . $path . ") is found on blocklist";
198
199
                return true;
200
            }
201 View Code Duplication
            if (substr_count($blocklist, self::SEPERATOR . $hostname . $path . self::SEPERATOR)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
202
                self::$reason = "Blocking because " . $entity . " hostname/path (" . $hostname . $path . ") is found on blocklist";
203
204
                return true;
205
            }
206
        }
207
208
        self::$reason = "Not blocking because " . $entity . " (" . $url . ") is not matched against blocklist";
209
        return false;
210
    }
211
212
    /**
213
     * Returns HTTP Referer if it is available and not empty, null otherwise
214
     *
215
     * @return string|null
216
     */
217
    private static function getHttpReferer()
218
    {
219
        if (isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER'])) {
220
            return $_SERVER['HTTP_REFERER'];
221
        }
222
        return null;
223
    }
224
225
    /**
226
     * @return string
227
     */
228
    private static function getBlocklistContents()
229
    {
230
        $blocklistContent = file_get_contents(self::getBlocklistFilename());
231
        return $blocklistContent;
232
    }
233
234
    /**
235
     * @return string
236
     */
237
    private static function getConcatenateBlocklist()
238
    {
239
        return self::concatenateBlocklist(self::getBlocklistContents());
240
    }
241
242
    /**
243
     * @param string $blocklistContent
244
     * @return array
245
     */
246
    private static function parseBlocklist($blocklistContent)
247
    {
248
        return array_map('trim', array_filter(explode(PHP_EOL, strtolower($blocklistContent))));
249
    }
250
251
    /**
252
     * @param string $blocklistContent
253
     * @return string
254
     */
255
    private static function concatenateBlocklist($blocklistContent)
256
    {
257
        return self::SEPERATOR . str_replace(PHP_EOL, self::SEPERATOR, strtolower($blocklistContent)) . self::SEPERATOR;
258
    }
259
}