Completed
Push — master ( 952982...6e36ff )
by Stevie-Ray
07:42
created

src/Generator.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace StevieRay;
3
4
use Mso\IdnaConvert\IdnaConvert;
5
6
class Generator
7
{
8
    private $projectUrl = "https://github.com/Stevie-Ray/referrer-spam-blocker";
9
10
    /** @var string string */
11
    private $outputDir;
12
13
    /**
14
     * @param string $outputDir
15
     */
16
    public function __construct($outputDir)
17
    {
18
        $this->outputDir = $outputDir;
19
    }
20
21
    public function generateFiles()
22
    {
23
        $date = date('Y-m-d H:i:s');
24
        $lines = $this->domainWorker();
25
        $this->createApache($date, $lines);
26
        $this->createNginx($date, $lines);
27
        $this->createVarnish($date, $lines);
28
        $this->createIIS($date, $lines);
29
        $this->createuWSGI($date, $lines);
30
        $this->createGoogleExclude($lines);
31
    }
32
33
    /**
34
     * @return array
35
     */
36
    public function domainWorker()
37
    {
38
        $domainsFile = __DIR__ . "/domains.txt";
39
40
        $handle = fopen($domainsFile, "r");
41
        if (! $handle) {
42
            throw new \RuntimeException('Error opening file ' . $domainsFile);
43
        }
44
        $lines = array();
45
        while (($line = fgets($handle)) !== false) {
46
            $line = trim(preg_replace('/\s\s+/', ' ', $line));
47
48
            // convert internationalized domain names
49
            if (preg_match('/[А-Яа-яЁёɢ]/u', $line)) {
50
51
                $IDN = new IdnaConvert();
52
53
                $line = $IDN->encode($line);
54
55
            }
56
57
            if (empty($line)) {
58
                continue;
59
            }
60
            $lines[] = $line;
61
        }
62
        fclose($handle);
63
        $uniqueLines = array_unique($lines, SORT_STRING);
64
        sort($uniqueLines, SORT_STRING);
65
        if (is_writable($domainsFile)) {
66
            file_put_contents($domainsFile, implode("\n", $uniqueLines));
67
        } else {
68
            trigger_error("Permission denied");
69
        }
70
71
        return $lines;
72
    }
73
74
    /**
75
     * @param string $filename
76
     * @param string $data
77
     */
78
    protected function writeToFile($filename, $data)
79
    {
80
        $file = $this->outputDir . '/' . $filename;
81
        if (is_writable($file)) {
82
            file_put_contents($file, $data);
83
            if (! chmod($file, 0644)) {
84
                trigger_error("Couldn't not set " . $filename . " permissions to 644");
85
            }
86
        } else {
87
            trigger_error("Permission denied");
88
        }
89
    }
90
91
    /**
92
     * @param string $date
93
     * @param array  $lines
94
     */
95
    public function createApache($date, array $lines)
96
    {
97
        $data = "# " . $this->projectUrl . "\n# Updated " . $date . "\n\n" .
98
            "<IfModule mod_rewrite.c>\n\nRewriteEngine On\n\n";
99 View Code Duplication
        foreach ($lines as $line) {
1 ignored issue
show
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...
100
            if ($line === end($lines)) {
101
                $data .= "RewriteCond %{HTTP_REFERER} ^http(s)?://(www.)?.*" . preg_quote($line) . ".*$ [NC]\n";
102
                break;
103
            }
104
105
            $data .= "RewriteCond %{HTTP_REFERER} ^http(s)?://(www.)?.*" . preg_quote($line) . ".*$ [NC,OR]\n";
106
        }
107
108
        $data .= "RewriteRule ^(.*)$ – [F,L]\n\n</IfModule>\n\n<IfModule mod_setenvif.c>\n\n";
109
        foreach ($lines as $line) {
110
            $data .= "SetEnvIfNoCase Referer " . preg_quote($line) . " spambot=yes\n";
111
        }
112
        $data .= "\n</IfModule>\n\n# Apache 2.2\n<IfModule !mod_authz_core.c>\n\t<IfModule mod_authz_host.c>\n\t\t" .
113
            "Order allow,deny\n\t\tAllow from all\n\t\tDeny from env=spambot\n\t</IfModule>\n</IfModule>\n# " .
114
            "Apache 2.4\n<IfModule mod_authz_core.c>\n\t<RequireAll>" .
115
            "\n\t\tRequire all granted\n\t\tRequire not env spambot\n\t</RequireAll>\n</IfModule>";
116
117
        $this->writeToFile('.htaccess', $data);
118
    }
119
120
    /**
121
     * @param string $date
122
     * @param array  $lines
123
     */
124 View Code Duplication
    public function createNginx($date, array $lines)
1 ignored issue
show
This method seems to be duplicated in 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...
125
    {
126
        $data = "# " . $this->projectUrl . "\n# Updated " . $date . "\n#\n# /etc/nginx/referral-spam.conf\n#\n" .
127
            "# With referral-spam.conf in /etc/nginx, include it globally from within /etc/nginx/nginx.conf:\n#\n" .
128
            "#     include referral-spam.conf;\n#\n" .
129
            "# Add the following to each /etc/nginx/site-available/your-site.conf that needs protection:\n#\n" .
130
            "#      server {\n#        if (\$bad_referer) {\n#          return 444;\n#        }\n#      }\n" .
131
            "#\nmap \$http_referer \$bad_referer {\n\tdefault 0;\n\n";
132
        foreach ($lines as $line) {
133
            $data .= "\t\"~*" . preg_quote($line) . "\" 1;\n";
134
        }
135
        $data .= "\n}";
136
137
        $this->writeToFile('referral-spam.conf', $data);
138
    }
139
140
    /**
141
     * @param string $date
142
     * @param array  $lines
143
     */
144
    public function createVarnish($date, array $lines)
145
    {
146
        $data = "# " . $this->projectUrl . "\n# Updated " . $date . "\nsub block_referral_spam {\n\tif (\n";
147 View Code Duplication
        foreach ($lines as $line) {
1 ignored issue
show
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...
148
            if ($line === end($lines)) {
149
                $data .= "\t\treq.http.Referer ~ \"(?i)" . preg_quote($line) . "\"\n";
150
                break;
151
            }
152
153
            $data .= "\t\treq.http.Referer ~ \"(?i)" . preg_quote($line) . "\" ||\n";
154
        }
155
156
        $data .= "\t) {\n\t\t\treturn (synth(444, \"No Response\"));\n\t}\n}";
157
158
        $this->writeToFile('referral-spam.vcl', $data);
159
    }
160
161
    /**
162
     * @param string $date
163
     * @param array  $lines
164
     */
165 View Code Duplication
    public function createIIS($date, array $lines)
1 ignored issue
show
This method seems to be duplicated in 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...
166
    {
167
        $data = "<!-- " . $this->projectUrl . " -->\n<!-- Updated " . $date . " -->\n" .
168
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
169
            "<configuration>\n\t<system.webServer>\n\t\t<rewrite>\n\t\t\t<rules>\n";
170
        foreach ($lines as $line) {
171
172
            $data .= "\t\t\t\t<rule name=\"Referrer Spam " . $line . "\" stopProcessing=\"true\">" .
173
                "<match url=\".*\" /><conditions><add input=\"{HTTP_REFERER}\" pattern=\"(" .
174
                preg_quote($line) .
175
                ")\"/></conditions><action type=\"AbortRequest\" /></rule>\n";
176
        }
177
178
        $data .= "\t\t\t</rules>\n\t\t</rewrite>\n\t</system.webServer>\n</configuration>";
179
180
        $this->writeToFile('web.config', $data);
181
    }
182
183
184
    /**
185
     * @param string $date
186
     * @param array  $lines
187
     */
188 View Code Duplication
    public function createuWSGI($date, array $lines)
1 ignored issue
show
This method seems to be duplicated in 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
    {
190
        $data = "# " . $this->projectUrl . "\n# Updated " . $date . "\n#\n" .
191
            "# Put referral-spam.res in /path/to/vassals, then include it from within /path/to/vassals/vassal.ini:\n" .
192
            "#\n# ini = referral_spam.res:blacklist_spam\n\n" .
193
            "[blacklist_spam]\n";
194
        foreach ($lines as $line) {
195
            $data .= "route-referer = (?i)" . preg_quote($line) . " break:403 Forbidden\n";
196
        }
197
        $data .= "route-label = referral_spam";
198
199
        $this->writeToFile('referral_spam.res', $data);
200
    }
201
202
    /**
203
     * @param array $lines
204
     */
205
    public function createGoogleExclude(array $lines)
206
    {
207
208
        $regexLines = [];
209
210
        foreach ($lines as $line) {
211
            $regexLines[] = preg_quote($line);
212
        }
213
        $data = implode('|', $regexLines);
214
215
        $googleLimit = 30000;
216
        $dataLength = strlen($data);
217
218
        // keep track of the last split
219
        $lastPosition = 0;
220
        for ($x = 1; $lastPosition < $dataLength; $x++) {
221
222
            // already in the boundary limits?
223
            if (($dataLength - $lastPosition) >= $googleLimit) {
224
                // search for the last occurrence of | in the boundary limits
225
                $pipePosition = strrpos(substr($data, $lastPosition, $googleLimit), '|');
226
227
                $dataSplit = substr($data, $lastPosition, $pipePosition);
228
229
                // without trailing pipe at the beginning of next round
230
                $lastPosition = $lastPosition + $pipePosition + 1;
231
            } else {
232
                // Rest of the regex (no pipe at the end)
233
                $dataSplit = substr($data, $lastPosition);
234
                $lastPosition = $dataLength; // Break
235
            }
236
237
            $this->writeToFile('google-exclude-' . $x . '.txt', $dataSplit);
238
        }
239
240
    }
241
}