Spider Blocker - Version 1.0.18

Version Description

Download this release

Release Info

Developer niteoweb
Plugin Icon 128x128 Spider Blocker
Version 1.0.18
Comparing to
See all releases

Code changes from version 1.0.17 to 1.0.18

Files changed (3) hide show
  1. index.php +857 -797
  2. langs/spiderblocker.pot +140 -0
  3. readme.txt +2 -2
index.php CHANGED
@@ -1,815 +1,875 @@
1
  <?php
 
2
  namespace Niteoweb\SpiderBlocker;
 
3
  /**
4
  * Plugin Name: Spider Blocker
5
  * Description: Spider Blocker will block most common bots that consume bandwidth and slow down your server.
6
- * Version: 1.0.17
7
  * Runtime: 5.3+
8
  * Author: Easy Blog Networks
 
 
9
  * Author URI: www.easyblognetworks.com
10
  */
11
 
12
- if (!function_exists('apache_get_version')) {
13
- function apache_get_version()
14
- {
15
- if (stristr($_ENV["SERVER_SOFTWARE"], 'Apache')) {
16
- return $_ENV["SERVER_SOFTWARE"];
17
- }
18
- if (stristr($_SERVER["SERVER_SOFTWARE"], 'Apache')) {
19
- return $_SERVER["SERVER_SOFTWARE"];
20
- }
21
- return false;
22
- }
 
 
 
 
23
  }
24
 
25
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
26
- ?>
27
- <div id="error-page">
28
- <p>This plugin requires PHP 5.3.0 or higher. Please contact your hosting provider about upgrading your
29
- server software. Your PHP version is <b><?php echo PHP_VERSION; ?></b></p>
30
- </div>
31
- <?php
32
- die();
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
-
36
- class SpiderBlocker
37
- {
38
-
39
- const OptionName = 'Niteoweb.SpiderBlocker.Bots';
40
- const nonce = 'Niteoweb.SpiderBlocker.Nonce';
41
- const CheckHook = 'Niteoweb.SpiderBlocker.CheckHook';
42
- private $default_bots = array(
43
- array(
44
- 'name' => 'Ahrefs Bot',
45
- 're' => 'AhrefsBot',
46
- 'desc' => 'https://ahrefs.com/robot/',
47
- 'state' => true,
48
- ),
49
- array(
50
- 'name' => 'MJ12 bot',
51
- 're' => 'MJ12bot',
52
- 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
53
- 'state' => true,
54
- ),
55
- array(
56
- 'name' => 'Roger Bot',
57
- 're' => 'Rogerbot',
58
- 'desc' => 'http://moz.com/help/pro/rogerbot-crawler',
59
- 'state' => true,
60
- ),
61
- array(
62
- 'name' => 'Semrush Bot',
63
- 're' => 'SemrushBot',
64
- 'desc' => 'http://www.semrush.com/bot.html',
65
- 'state' => true,
66
- ),
67
- array(
68
- 'name' => 'ia_archiver',
69
- 're' => 'ia_archiver',
70
- 'desc' => 'http://archive.org/about/exclude.php',
71
- 'state' => true,
72
- ),
73
- array(
74
- 'name' => 'ScoutJet',
75
- 're' => 'ScoutJet',
76
- 'desc' => 'http://scoutjet.com',
77
- 'state' => true,
78
- ),
79
- array(
80
- 'name' => 'sistrix',
81
- 're' => 'sistrix',
82
- 'desc' => 'http://crawler.sistrix.net',
83
- 'state' => true,
84
- ),
85
- array(
86
- 'name' => 'SearchmetricsBot',
87
- 're' => 'SearchmetricsBot',
88
- 'desc' => 'http://www.searchmetrics.com/en/searchmetrics-bot/',
89
- 'state' => true,
90
- ),
91
- array(
92
- 'name' => 'SEOkicks-Robot',
93
- 're' => 'SEOkicks-Robot',
94
- 'desc' => 'http://www.seokicks.de/robot.html',
95
- 'state' => true,
96
- ),
97
- array(
98
- 'name' => 'Lipperhey Spider',
99
- 're' => 'Lipperhey Spider',
100
- 'desc' => 'http://www.lipperhey.com/en/website-spider/',
101
- 'state' => true,
102
- ),
103
- array(
104
- 'name' => 'Exabot',
105
- 're' => 'Exabot',
106
- 'desc' => 'http://www.exalead.com/search/webmasterguide',
107
- 'state' => true,
108
- ),
109
- array(
110
- 'name' => 'NC Bot',
111
- 're' => 'NCBot',
112
- 'desc' => 'https://twitter.com/NetComber/status/334476871691550721',
113
- 'state' => true,
114
- ),
115
- array(
116
- 'name' => 'BacklinkCrawler',
117
- 're' => 'BacklinkCrawler',
118
- 'desc' => 'http://www.backlinktest.com/crawler.html',
119
- 'state' => true,
120
- ),
121
- array(
122
- 'name' => 'archive.org Bot',
123
- 're' => 'archive.org_bot',
124
- 'desc' => 'http://archive.org/details/archive.org_bot',
125
- 'state' => true,
126
- ),
127
- array(
128
- 'name' => 'MeanPath Bot',
129
- 're' => 'meanpathbot',
130
- 'desc' => 'https://meanpath.com/meanpathbot.html',
131
- 'state' => true,
132
- ),
133
- array(
134
- 'name' => 'PagesInventory Bot',
135
- 're' => 'PagesInventory',
136
- 'desc' => 'http://www.botsvsbrowsers.com/details/1002332/index.html',
137
- 'state' => true,
138
- ),
139
- array(
140
- 'name' => 'Aboundex Bot',
141
- 're' => 'Aboundexbot',
142
- 'desc' => 'http://www.aboundex.com/crawler/',
143
- 'state' => true,
144
- ),
145
- array(
146
- 'name' => 'SeoProfiler Bot',
147
- 're' => 'spbot',
148
- 'desc' => 'http://www.seoprofiler.com/bot/',
149
- 'state' => true,
150
- ),
151
- array(
152
- 'name' => 'Linkdex Bot',
153
- 're' => 'linkdexbot',
154
- 'desc' => 'http://www.linkdex.com/about/bots/',
155
- 'state' => true,
156
- ),
157
- array(
158
- 'name' => 'Gigabot',
159
- 're' => 'Gigabot',
160
- 'desc' => 'http://www.useragentstring.com/pages/Gigabot/',
161
- 'state' => true,
162
- ),
163
- array(
164
- 'name' => 'DotBot',
165
- 're' => 'dotbot',
166
- 'desc' => 'http://en.wikipedia.org/wiki/DotBot',
167
- 'state' => true,
168
- ),
169
- array(
170
- 'name' => 'Nutch',
171
- 're' => 'Nutch',
172
- 'desc' => 'http://nutch.apache.org/bot.html',
173
- 'state' => true,
174
- ),
175
- array(
176
- 'name' => 'BLEX Bot',
177
- 're' => 'BLEXBot',
178
- 'desc' => 'http://webmeup-crawler.com/',
179
- 'state' => true,
180
- ),
181
- array(
182
- 'name' => 'Ezooms',
183
- 're' => 'Ezooms',
184
- 'desc' => 'http://graphicline.co.za/blogs/what-is-ezooms-bot',
185
- 'state' => true,
186
- ),
187
- array(
188
- 'name' => 'Majestic 12',
189
- 're' => 'Majestic-12',
190
- 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
191
- 'state' => true,
192
- ),
193
- array(
194
- 'name' => 'Majestic SEO',
195
- 're' => 'Majestic-SEO',
196
- 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
197
- 'state' => true,
198
- ),
199
- array(
200
- 'name' => 'DSearch',
201
- 're' => 'DSearch',
202
- 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
203
- 'state' => true,
204
- ),
205
- array(
206
- 'name' => 'MJ12',
207
- 're' => 'MJ12',
208
- 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
209
- 'state' => true,
210
- ),
211
- array(
212
- 'name' => 'Blekko Bot',
213
- 're' => 'BlekkoBot',
214
- 'desc' => 'http://blekko.com/about/blekkobot',
215
- 'state' => true,
216
- ),
217
- array(
218
- 'name' => 'Yandex',
219
- 're' => 'Yandex',
220
- 'desc' => 'http://help.yandex.com/search/?id=1112030',
221
- 'state' => false,
222
- ),
223
- array(
224
- 'name' => 'Google Bot',
225
- 're' => 'googlebot',
226
- 'desc' => 'https://support.google.com/webmasters/answer/182072?hl=en',
227
- 'state' => false,
228
- ),
229
- array(
230
- 'name' => 'Feedfetcher Google',
231
- 're' => 'Feedfetcher-Google',
232
- 'desc' => 'https://support.google.com/webmasters/answer/178852',
233
- 'state' => false,
234
- ),
235
- array(
236
- 'name' => 'Bing Bot',
237
- 're' => 'BingBot',
238
- 'desc' => 'http://en.wikipedia.org/wiki/Bingbot',
239
- 'state' => false,
240
- ),
241
- array(
242
- 'name' => 'Nerdy Bot',
243
- 're' => 'NerdyBot',
244
- 'desc' => 'http://nerdybot.com/',
245
- 'state' => true,
246
- ),
247
- array(
248
- 'name' => 'James BOT',
249
- 're' => 'JamesBOT',
250
- 'desc' => 'http://cognitiveseo.com/bot.html',
251
- 'state' => true,
252
- ),
253
- array(
254
- 'name' => 'Tin Eye',
255
- 're' => 'TinEye',
256
- 'desc' => 'http://www.tineye.com/crawler.html',
257
- 'state' => true,
258
- ),
259
- array(
260
- 'state' => true,
261
- 're' => 'Baiduspider',
262
- 'name' => 'Baidu',
263
- 'desc' => 'http://www.baidu.com/search/robots_english.html',
264
- ),
265
- array(
266
- 'state' => true,
267
- 're' => 'serpstat',
268
- 'name' => 'Serpstat',
269
- 'desc' => 'https://serpstat.com/',
270
- ),
271
- array(
272
- 'state' => true,
273
- 'desc' => 'https://www.spyfu.com/',
274
- 're' => 'spyfu',
275
- 'name' => 'SpyFu',
276
- ),
277
- );
278
-
279
- function __construct()
280
- {
281
- if (is_admin()) {
282
- add_action('admin_notices', array(&$this, 'activatePluginNotice'));
283
- add_action('admin_menu', array(&$this, 'adminMenu'));
284
- add_action('wp_ajax_NSB-get_list', array(&$this, 'loadList'));
285
- add_action('wp_ajax_NSB-set_list', array(&$this, 'saveList'));
286
- add_action('wp_ajax_NSB-reset_list', array(&$this, 'resetList'));
287
- }
288
-
289
- // Filter (for robots.txt)
290
- add_filter( 'robots_txt', array (&$this, 'robotsFile' ), ~PHP_INT_MAX, 2 );
291
- add_action('generate_rewrite_rules', array(&$this, "generateRewriteRules"));
292
-
293
- }
294
-
295
- function generateRewriteRules($wp_rewrite)
296
- {
297
- // Protect plugin from direct access
298
- $wp_rewrite->add_external_rule($this->pluginURL() . 'index.php', 'index.php%{REQUEST_URI}');
299
- $wp_rewrite->add_external_rule($this->pluginURL() . 'readme.txt', 'index.php%{REQUEST_URI}');
300
- $wp_rewrite->add_external_rule($this->pluginURL(), 'index.php%{REQUEST_URI}');
301
- }
302
-
303
- /**
304
- * @codeCoverageIgnore
305
- * @return string
306
- */
307
- private function pluginURL()
308
- {
309
- $url = wp_make_link_relative(plugin_dir_url(__FILE__));
310
- $url = ltrim($url, "/");
311
-
312
- return $url;
313
- }
314
-
315
- function adminMenu()
316
- {
317
- add_management_page(
318
- 'SpiderBlocker', 'SpiderBlocker', 'manage_options', 'ni_spider_block', array(
319
- &$this,
320
- 'viewHandler'
321
- )
322
- );
323
- }
324
-
325
- /**
326
- * @codeCoverageIgnore
327
- */
328
- function activatePluginNotice()
329
- {
330
- if (get_option(self::OptionName) === false) {
331
- update_option(self::OptionName, $this->default_bots);
332
- ?>
333
- <div class="notice notice-success">
334
- <p>SpiderBlocker plugin has enabled blocking of some bots, please review settings by visiting <a
335
- href="<?php echo admin_url('tools.php?page=ni_spider_block'); ?>">Setting page</a>!</p>
336
- </div>
337
- <?php
338
- }
339
- }
340
-
341
- /**
342
- * @codeCoverageIgnore
343
- */
344
- function onPluginUpgrade()
345
- {
346
- $this->generateBlockRules();
347
- }
348
-
349
- /**
350
- * @codeCoverageIgnore
351
- */
352
- function activatePlugin()
353
- {
354
- if (!apache_get_version()) {
355
- ?>
356
- <div id="error-page">
357
- <p>This plugin requires Apache2 server with mod_rewrite support. Please contact your hosting provider
358
- about
359
- upgrading your server software. Your Apache version is <b><?php echo apache_get_version(); ?></b>
360
- </p>
361
- </div>
362
- <?php
363
- die();
364
- }
365
-
366
- if (!SpiderBlocker::isHtaccessWritable()) {
367
- $state = SpiderBlocker::chmodHtaccess();
368
- if (!SpiderBlocker::isHtaccessWritable() || !$state) {
369
- ?>
370
- <div id="error-page">
371
- <p>This plugin requires <b>.htaccess</b> file that is writable by the server. Please enable write
372
- access
373
- for file <b><?php echo ABSPATH . '.htaccess'; ?></b>.</p>
374
- </div>
375
- <?php
376
- die();
377
- }
378
- }
379
- $this->generateBlockRules();
380
-
381
- }
382
-
383
- /**
384
- * @codeCoverageIgnore
385
- * @return bool
386
- */
387
- static function isHtaccessWritable()
388
- {
389
- $htaccess_file = SpiderBlocker::joinPaths(ABSPATH, '.htaccess');
390
- return is_writable($htaccess_file);
391
- }
392
-
393
- /**
394
- * @codeCoverageIgnore
395
- * @return string
396
- */
397
- static function joinPaths()
398
- {
399
- $paths = array();
400
-
401
- foreach (func_get_args() as $arg) {
402
- if ($arg !== '') {
403
- $paths[] = $arg;
404
- }
405
- }
406
-
407
- return preg_replace('#/+#', '/', join('/', $paths));
408
- }
409
-
410
- /**
411
- * @codeCoverageIgnore
412
- *
413
- * @param int $mod octet value for chmod
414
- *
415
- * @return bool
416
- */
417
- static function chmodHtaccess($mod = 0644)
418
- {
419
- $home_path = function_exists('get_home_path') ? get_home_path() : ABSPATH;
420
- $htaccess_file = $home_path . '.htaccess';
421
-
422
- return chmod($htaccess_file, $mod);
423
- }
424
-
425
- function generateBlockRules()
426
- {
427
- global $wp_rewrite;
428
-
429
- $home_path = function_exists('get_home_path') ? get_home_path() : ABSPATH;
430
- $htaccess_file = $home_path . '.htaccess';
431
-
432
- if ((!file_exists($htaccess_file) && is_writable($home_path)) || is_writable($htaccess_file)) {
433
- insert_with_markers($htaccess_file, 'NiteowebSpiderBlocker', $this->getRules());
434
- }
435
-
436
- $wp_rewrite->flush_rules();
437
- }
438
-
439
- /**
440
- * Generate block rules based on enabled bots
441
- *
442
- * @return array
443
- */
444
- function getRules()
445
- {
446
- $list = array();
447
- foreach ($this->getBots() as $bot) {
448
- if(is_array($bot)){
449
- $bot = (object) $bot;
450
- }
451
- if ($bot->state) {
452
- $list[] = 'SetEnvIfNoCase User-Agent "' . $bot->re . '" block_bot';
453
- }
454
-
455
- }
456
- $list[] = "<Limit GET POST HEAD>";
457
- $list[] = "Order Allow,Deny";
458
- $list[] = "Allow from all";
459
- $list[] = "Deny from env=block_bot";
460
- $list[] = "</Limit>";
461
-
462
- return $list;
463
- }
464
-
465
- private function getBots()
466
- {
467
- $data = get_option(self::OptionName);
468
- if($data){
469
- return maybe_unserialize($data);
470
- }
471
- return $this->default_bots;
472
- }
473
-
474
-
475
- function loadList()
476
- {
477
- check_ajax_referer(self::nonce, 'nonce');
478
- wp_send_json_success($this->getBots());
479
- }
480
-
481
- function resetList()
482
- {
483
- check_ajax_referer(self::nonce, 'nonce');
484
- delete_option(self::OptionName);
485
- $this->generateBlockRules();
486
- add_filter( 'robots_txt', array (&$this, 'robotsFile' ), ~PHP_INT_MAX, 2 );
487
- wp_send_json_success($this->getBots());
488
- }
489
-
490
- function removeBlockRules()
491
- {
492
- global $wp_rewrite;
493
- delete_option(self::OptionName);
494
- $home_path = function_exists('get_home_path') ? get_home_path() : ABSPATH;
495
- $htaccess_file = $home_path . '.htaccess';
496
- $empty = array();
497
- if ((!file_exists($htaccess_file) && is_writable($home_path)) || is_writable($htaccess_file)) {
498
- insert_with_markers($htaccess_file, 'NiteowebSpiderBlocker', $empty);
499
- }
500
-
501
- $wp_rewrite->flush_rules();
502
- }
503
-
504
- function saveList()
505
- {
506
-
507
- check_ajax_referer(self::nonce, 'nonce');
508
- $data = json_decode(stripcslashes($_POST['data']), true);
509
-
510
- if (json_last_error()) {
511
- if (function_exists('json_last_error_msg')) {
512
- wp_send_json_error(json_last_error_msg());
513
- } else {
514
- wp_send_json_error('Failed parsing JSON');
515
- }
516
-
517
- }
518
- if (get_option(self::OptionName) !== false) {
519
- update_option(self::OptionName, maybe_serialize($data));
520
- } else {
521
- add_option(self::OptionName, maybe_serialize($data), null, 'no');
522
- }
523
-
524
- $this->generateBlockRules();
525
- add_filter( 'robots_txt', array (&$this, 'robotsFile' ), ~PHP_INT_MAX, 2 );
526
- wp_send_json_success($this->getBots());
527
-
528
- }
529
-
530
- function robotsFile( $output, $public ) {
531
-
532
- // Get bots list
533
- $data = $this->getBots();
534
-
535
- if ( $data ) {
536
- foreach ( $data as $entry ) {
537
- if ( ! empty( $entry['state'] ) ) {
538
- $output .= sprintf( "User-agent: %s\n", $entry['re'] );
539
- $output .= "Disallow: /\n";
540
- $output .= "\n";
541
- }
542
- }
543
- }
544
-
545
- return $output;
546
-
547
- }
548
-
549
- /**
550
- * @codeCoverageIgnore
551
- */
552
- function viewHandler()
553
- {
554
-
555
- add_thickbox();
556
- ?>
557
- <style>
558
- .notice.fixed {
559
- position: fixed;
560
- right: 1em;
561
- top: 3.5em;
562
- }
563
-
564
- tr.active {
565
- background-color: rgba(54, 204, 255, 0.05);
566
- }
567
-
568
- .active th.bot-re {
569
- border-left: 4px solid #2ea2cc;
570
- }
571
- </style>
572
- <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"
573
- type="text/javascript"></script>
574
- <script>
575
- window.sb_nonce = "<?php echo wp_create_nonce(self::nonce); ?>";
576
- -(function () {
577
- var spiderBlockApp = angular.module('spiderBlockApp', []);
578
-
579
- spiderBlockApp.directive('jsonText', function () {
580
- return {
581
- restrict: 'A',
582
- require: 'ngModel',
583
- link: function (scope, element, attr, ngModel) {
584
- function into(input) {
585
- return angular.fromJson(input);
586
- }
587
-
588
- function out(data) {
589
- return angular.toJson(data, true);
590
- }
591
-
592
- ngModel.$parsers.push(into);
593
- ngModel.$formatters.push(out);
594
- }
595
- };
596
- });
597
- spiderBlockApp.controller('NotificationsCtrl', function ($scope, $rootScope, $timeout) {
598
- $scope.notifications = [];
599
-
600
- $rootScope.$on('notification', function (event, data) {
601
- $scope.notifications.push(data);
602
- $timeout(function () {
603
- $scope.removeNotification(data);
604
- }, 3000);
605
- });
606
-
607
- $scope.removeNotification = function (notification) {
608
- var index;
609
- if ($scope.notifications !== undefined) {
610
- index = $scope.notifications.indexOf(notification);
611
- $scope.notifications.splice(index, 1);
612
- }
613
- }
614
- });
615
- spiderBlockApp.controller('BotListCtrl', function ($scope, $http, $rootScope) {
616
- var wp_ajax = function (_req) {
617
- _req.nonce = window.sb_nonce;
618
- return $http({
619
- method: 'POST',
620
- url: ajaxurl,
621
- data: jQuery.param(_req),
622
- headers: {'Content-Type': 'application/x-www-form-urlencoded'}
623
- })
624
- };
625
-
626
- var find_bot = function (re) {
627
- for (var i = $scope.bots.length - 1; i >= 0; i--) {
628
- if ($scope.bots[i]['re'] == re) {
629
- return i;
630
- }
631
- }
632
- return null;
633
- };
634
-
635
- $scope.bot = {"state": true};
636
-
637
- wp_ajax({
638
- action: 'NSB-get_list'
639
- }).success(function (res) {
640
- $scope.bots = res.data;
641
- });
642
-
643
- $scope.save = function () {
644
- wp_ajax({
645
- action: 'NSB-set_list',
646
- data: angular.toJson($scope.bots)
647
- }).success(function (res) {
648
- if (res.success) {
649
- $scope.bots = res.data;
650
- $rootScope.$emit('notification', {
651
- state: 'success',
652
- msg: 'List of bots was saved and new blocklist applied!'
653
- });
654
- } else {
655
- $rootScope.$emit('notification', {state: 'errror', msg: res.data});
656
- }
657
- });
658
- };
659
-
660
- $scope.reset = function () {
661
- wp_ajax({
662
- action: 'NSB-reset_list'
663
- }).success(function (res) {
664
- $scope.bots = res.data;
665
- $rootScope.$emit('notification', {
666
- state: 'success',
667
- msg: 'List of bots was reset to defaults!'
668
- });
669
- });
670
- };
671
-
672
- $scope.add = function () {
673
- $scope.bots.push($scope.bot);
674
- $rootScope.$emit('notification', {
675
- state: 'success',
676
- msg: 'Bot ' + $scope.bot.name + ' was added!'
677
- });
678
- $scope.bot = {"state": true};
679
- };
680
-
681
- $scope.remove = function (at) {
682
- $rootScope.$emit('notification', {state: 'success', msg: 'Bot was removed!'});
683
- $scope.bots.splice(find_bot(at), 1);
684
- };
685
- });
686
- })(angular, document, jQuery);
687
- </script>
688
- <h1>Spider Blocker</h1>
689
- <hr/>
690
- <div ng-app="spiderBlockApp">
691
- <div ng-controller="NotificationsCtrl">
692
- <div class="notice notice-{{ n.state }} fixed" ng-repeat="n in notifications"
693
- style="top: {{3.5*($index+1)}}em">
694
- <p>{{n.msg}}
695
- <a ng-click="removeNotification(notification)">
696
- <span class="dashicons dashicons-no-alt"></span>
697
- </a>
698
- </p>
699
- </div>
700
- </div>
701
-
702
-
703
- <div ng-controller="BotListCtrl">
704
- <h2>Add New Bot</h2>
705
-
706
- <form name="add_form" ng-submit="add()">
707
- <table class="form-table">
708
- <tbody>
709
- <tr>
710
- <th scope="row"><label>User Agent</label></th>
711
- <td><input bots="bots" ng-model='bot.re' class="regular-text"
712
- required/></td>
713
- </tr>
714
- <tr>
715
- <th scope="row"><label>Bot Name</label></th>
716
- <td><input type="text" ng-model='bot.name' class="regular-text" required/></td>
717
- </tr>
718
- <tr>
719
- <tr>
720
- <th scope="row"><label>Bot Description URL</label></th>
721
- <td><input type="url" ng-model='bot.desc' class="regular-text" placeholder="http://"/>
722
- </td>
723
- </tr>
724
- </tbody>
725
- </table>
726
- <p class="submit"><input ng-disabled="add_form.$invalid" type="submit"
727
- class="button button-primary" value="Add Bot"></p>
728
- </form>
729
- <h2>List of bots</h2>
730
- <ng-form class="search-box">
731
- <input size="35" type="search" id="ua-search-input" ng-model="query" placeholder="Filter...">
732
- </ng-form>
733
- <table class="wp-list-table widefat bots">
734
- <thead>
735
- <tr>
736
-
737
- <th scope="col" class="manage-column column-description">
738
- <a href=""
739
- ng-click="predicate = 're'; reverse=false">User
740
- Agent <span class="dashicons dashicons-sort"></span></a></th>
741
-
742
- <th scope="col" class="manage-column column-name">Name</th>
743
- <th scope="col" class="manage-column column-state">
744
- <a href=""
745
- ng-click="predicate = 'state'; reverse=false">State <span
746
- class="dashicons dashicons-sort"></span></a>
747
- </th>
748
- <th scope="col" id="action" class="manage-column column-action">Action</th>
749
- </tr>
750
- </thead>
751
-
752
- <tfoot>
753
- <tr>
754
-
755
- <th scope="col" class="manage-column column-description"><a href=""
756
- ng-click="predicate = 're'; reverse=false">User
757
- Agent</a></th>
758
-
759
- <th scope="col" class="manage-column column-name">Name</th>
760
- <th scope="col" class="manage-column column-state"><a href=""
761
- ng-click="predicate = 'state'; reverse=false">State</a>
762
- </th>
763
- <th scope="col" id="action" class="manage-column column-action">Action</th>
764
- </tr>
765
- </tfoot>
766
-
767
- <tbody id="the-list">
768
- <tr id="spider-blocker" ng-repeat="bot in bots | filter:query | orderBy:predicate:reverse"
769
- ng-class="{'active': bot.state}">
770
-
771
- <th class="bot-re"> {{ bot.re }}</th>
772
- <td class="bot-title"><strong>{{ bot.name }}</strong> <a target="_blank"
773
- ng-href="{{bot.desc}}">{{
774
- bot.desc }}</a></td>
775
- <th class="expression" ng-class="{'blocked':bot.state}"> {{ bot.state?"Blocked":"Allowed"
776
- }}
777
- </th>
778
- <td class="actions">
779
- <input ng-hide="bot.state" type="button" ng-click="bot.state=true"
780
- class="button button-primary" value="Block">
781
- <input ng-show="bot.state" type="button" ng-click="bot.state=false"
782
- class="button button-secondary" value="Allow">
783
- <input type="button" ng-click="remove(bot.re)" class="button button-secondary"
784
- value="Remove">
785
- </td>
786
- </tr>
787
- </tbody>
788
- </table>
789
- <div id="rules-export-import" style="display:none;">
790
- <textarea
791
- style="-webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;width: 100%;height: 99%;"
792
- json-text ng-model="bots"></textarea>
793
- </div>
794
- <p class="submit">
795
- <input type="button" class="button button-primary" ng-click="save()" value="Save">
796
- <input type="button" class="button button-primary" ng-click="reset()" value="Reset to Defaults">
797
- <a href="#TB_inline?width=540&height=360&inlineId=rules-export-import"
798
- class="thickbox button button-secondary">Import/Export Definitions</a>
799
- </p>
800
-
801
- </div>
802
- </div>
803
- <?php
804
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
805
 
806
  }
807
 
808
- // Inside WordPress
809
- if (defined('ABSPATH')) {
810
- $NiteowebSpiderBlocker_ins = new SpiderBlocker;
 
 
811
 
812
- add_action( "upgrader_process_complete", array(&$NiteowebSpiderBlocker_ins, 'onPluginUpgrade'), 10, 2);
813
- register_activation_hook(__FILE__, array(&$NiteowebSpiderBlocker_ins, 'activatePlugin'));
814
- register_deactivation_hook(__FILE__, array(&$NiteowebSpiderBlocker_ins, 'removeBlockRules'));
815
- }
 
 
1
  <?php
2
+
3
  namespace Niteoweb\SpiderBlocker;
4
+
5
  /**
6
  * Plugin Name: Spider Blocker
7
  * Description: Spider Blocker will block most common bots that consume bandwidth and slow down your server.
8
+ * Version: 1.0.18
9
  * Runtime: 5.3+
10
  * Author: Easy Blog Networks
11
+ * Text Domain: spiderblocker
12
+ * Domain Path: /langs/
13
  * Author URI: www.easyblognetworks.com
14
  */
15
 
16
+ if ( ! function_exists( 'apache_get_version' ) ) {
17
+ /**
18
+ * Fetch the Apache version.
19
+ *
20
+ * @return string|false
21
+ */
22
+ function apache_get_version() {
23
+ if ( stristr( $_ENV['SERVER_SOFTWARE'], 'Apache' ) ) {
24
+ return sanitize_text_field( $_ENV['SERVER_SOFTWARE'] );
25
+ }
26
+ if ( stristr( $_SERVER['SERVER_SOFTWARE'], 'Apache' ) ) {
27
+ return sanitize_text_field( $_SERVER['SERVER_SOFTWARE'] );
28
+ }
29
+ return false;
30
+ }
31
  }
32
 
33
+ /**
34
+ * Checks for PHP version and stop the plugin if the version is < 5.3.0.
35
+ */
36
+ if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) {
37
+ ?>
38
+ <div id="error-page">
39
+ <p>
40
+ <?php
41
+ esc_html_e(
42
+ 'This plugin requires PHP 5.3.0 or higher. Please contact your hosting provider about upgrading your
43
+ server software. Your PHP version is', 'spiderblocker'
44
+ );
45
+ ?>
46
+ <b><?php echo sanitize_text_field( PHP_VERSION ); ?></b></p>
47
+ </div>
48
+ <?php
49
+ die();
50
  }
51
 
52
+ /**
53
+ * Spiderblocker class where all the action happens.
54
+ *
55
+ * @package WordPress
56
+ * @subpackage spiderblocker
57
+ */
58
+ class SpiderBlocker {
59
+
60
+ const OPTIONNAME = 'Niteoweb.SpiderBlocker.Bots';
61
+ const NONCE = 'Niteoweb.SpiderBlocker.Nonce';
62
+ const CHECKHOOK = 'Niteoweb.SpiderBlocker.CheckHook';
63
+
64
+ /**
65
+ * Bots which can be blocked by the spiderblocker plugin
66
+ *
67
+ * @var array $default_bots Array of bots
68
+ */
69
+ private $default_bots = array(
70
+ array(
71
+ 'name' => 'Ahrefs Bot',
72
+ 're' => 'AhrefsBot',
73
+ 'desc' => 'https://ahrefs.com/robot/',
74
+ 'state' => true,
75
+ ),
76
+ array(
77
+ 'name' => 'MJ12 bot',
78
+ 're' => 'MJ12bot',
79
+ 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
80
+ 'state' => true,
81
+ ),
82
+ array(
83
+ 'name' => 'Roger Bot',
84
+ 're' => 'Rogerbot',
85
+ 'desc' => 'http://moz.com/help/pro/rogerbot-crawler',
86
+ 'state' => true,
87
+ ),
88
+ array(
89
+ 'name' => 'Semrush Bot',
90
+ 're' => 'SemrushBot',
91
+ 'desc' => 'http://www.semrush.com/bot.html',
92
+ 'state' => true,
93
+ ),
94
+ array(
95
+ 'name' => 'ia_archiver',
96
+ 're' => 'ia_archiver',
97
+ 'desc' => 'http://archive.org/about/exclude.php',
98
+ 'state' => true,
99
+ ),
100
+ array(
101
+ 'name' => 'ScoutJet',
102
+ 're' => 'ScoutJet',
103
+ 'desc' => 'http://scoutjet.com',
104
+ 'state' => true,
105
+ ),
106
+ array(
107
+ 'name' => 'sistrix',
108
+ 're' => 'sistrix',
109
+ 'desc' => 'http://crawler.sistrix.net',
110
+ 'state' => true,
111
+ ),
112
+ array(
113
+ 'name' => 'SearchmetricsBot',
114
+ 're' => 'SearchmetricsBot',
115
+ 'desc' => 'http://www.searchmetrics.com/en/searchmetrics-bot/',
116
+ 'state' => true,
117
+ ),
118
+ array(
119
+ 'name' => 'SEOkicks-Robot',
120
+ 're' => 'SEOkicks-Robot',
121
+ 'desc' => 'http://www.seokicks.de/robot.html',
122
+ 'state' => true,
123
+ ),
124
+ array(
125
+ 'name' => 'Lipperhey Spider',
126
+ 're' => 'Lipperhey Spider',
127
+ 'desc' => 'http://www.lipperhey.com/en/website-spider/',
128
+ 'state' => true,
129
+ ),
130
+ array(
131
+ 'name' => 'Exabot',
132
+ 're' => 'Exabot',
133
+ 'desc' => 'http://www.exalead.com/search/webmasterguide',
134
+ 'state' => true,
135
+ ),
136
+ array(
137
+ 'name' => 'NC Bot',
138
+ 're' => 'NCBot',
139
+ 'desc' => 'https://twitter.com/NetComber/status/334476871691550721',
140
+ 'state' => true,
141
+ ),
142
+ array(
143
+ 'name' => 'BacklinkCrawler',
144
+ 're' => 'BacklinkCrawler',
145
+ 'desc' => 'http://www.backlinktest.com/crawler.html',
146
+ 'state' => true,
147
+ ),
148
+ array(
149
+ 'name' => 'archive.org Bot',
150
+ 're' => 'archive.org_bot',
151
+ 'desc' => 'http://archive.org/details/archive.org_bot',
152
+ 'state' => true,
153
+ ),
154
+ array(
155
+ 'name' => 'MeanPath Bot',
156
+ 're' => 'meanpathbot',
157
+ 'desc' => 'https://meanpath.com/meanpathbot.html',
158
+ 'state' => true,
159
+ ),
160
+ array(
161
+ 'name' => 'PagesInventory Bot',
162
+ 're' => 'PagesInventory',
163
+ 'desc' => 'http://www.botsvsbrowsers.com/details/1002332/index.html',
164
+ 'state' => true,
165
+ ),
166
+ array(
167
+ 'name' => 'Aboundex Bot',
168
+ 're' => 'Aboundexbot',
169
+ 'desc' => 'http://www.aboundex.com/crawler/',
170
+ 'state' => true,
171
+ ),
172
+ array(
173
+ 'name' => 'SeoProfiler Bot',
174
+ 're' => 'spbot',
175
+ 'desc' => 'http://www.seoprofiler.com/bot/',
176
+ 'state' => true,
177
+ ),
178
+ array(
179
+ 'name' => 'Linkdex Bot',
180
+ 're' => 'linkdexbot',
181
+ 'desc' => 'http://www.linkdex.com/about/bots/',
182
+ 'state' => true,
183
+ ),
184
+ array(
185
+ 'name' => 'Gigabot',
186
+ 're' => 'Gigabot',
187
+ 'desc' => 'http://www.useragentstring.com/pages/Gigabot/',
188
+ 'state' => true,
189
+ ),
190
+ array(
191
+ 'name' => 'DotBot',
192
+ 're' => 'dotbot',
193
+ 'desc' => 'http://en.wikipedia.org/wiki/DotBot',
194
+ 'state' => true,
195
+ ),
196
+ array(
197
+ 'name' => 'Nutch',
198
+ 're' => 'Nutch',
199
+ 'desc' => 'http://nutch.apache.org/bot.html',
200
+ 'state' => true,
201
+ ),
202
+ array(
203
+ 'name' => 'BLEX Bot',
204
+ 're' => 'BLEXBot',
205
+ 'desc' => 'http://webmeup-crawler.com/',
206
+ 'state' => true,
207
+ ),
208
+ array(
209
+ 'name' => 'Ezooms',
210
+ 're' => 'Ezooms',
211
+ 'desc' => 'http://graphicline.co.za/blogs/what-is-ezooms-bot',
212
+ 'state' => true,
213
+ ),
214
+ array(
215
+ 'name' => 'Majestic 12',
216
+ 're' => 'Majestic-12',
217
+ 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
218
+ 'state' => true,
219
+ ),
220
+ array(
221
+ 'name' => 'Majestic SEO',
222
+ 're' => 'Majestic-SEO',
223
+ 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
224
+ 'state' => true,
225
+ ),
226
+ array(
227
+ 'name' => 'DSearch',
228
+ 're' => 'DSearch',
229
+ 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
230
+ 'state' => true,
231
+ ),
232
+ array(
233
+ 'name' => 'MJ12',
234
+ 're' => 'MJ12',
235
+ 'desc' => 'http://www.majestic12.co.uk/projects/dsearch/mj12bot.php',
236
+ 'state' => true,
237
+ ),
238
+ array(
239
+ 'name' => 'Blekko Bot',
240
+ 're' => 'BlekkoBot',
241
+ 'desc' => 'http://blekko.com/about/blekkobot',
242
+ 'state' => true,
243
+ ),
244
+ array(
245
+ 'name' => 'Yandex',
246
+ 're' => 'Yandex',
247
+ 'desc' => 'http://help.yandex.com/search/?id=1112030',
248
+ 'state' => false,
249
+ ),
250
+ array(
251
+ 'name' => 'Google Bot',
252
+ 're' => 'googlebot',
253
+ 'desc' => 'https://support.google.com/webmasters/answer/182072?hl=en',
254
+ 'state' => false,
255
+ ),
256
+ array(
257
+ 'name' => 'Feedfetcher Google',
258
+ 're' => 'Feedfetcher-Google',
259
+ 'desc' => 'https://support.google.com/webmasters/answer/178852',
260
+ 'state' => false,
261
+ ),
262
+ array(
263
+ 'name' => 'Bing Bot',
264
+ 're' => 'BingBot',
265
+ 'desc' => 'http://en.wikipedia.org/wiki/Bingbot',
266
+ 'state' => false,
267
+ ),
268
+ array(
269
+ 'name' => 'Nerdy Bot',
270
+ 're' => 'NerdyBot',
271
+ 'desc' => 'http://nerdybot.com/',
272
+ 'state' => true,
273
+ ),
274
+ array(
275
+ 'name' => 'James BOT',
276
+ 're' => 'JamesBOT',
277
+ 'desc' => 'http://cognitiveseo.com/bot.html',
278
+ 'state' => true,
279
+ ),
280
+ array(
281
+ 'name' => 'Tin Eye',
282
+ 're' => 'TinEye',
283
+ 'desc' => 'http://www.tineye.com/crawler.html',
284
+ 'state' => true,
285
+ ),
286
+ array(
287
+ 'state' => true,
288
+ 're' => 'Baiduspider',
289
+ 'name' => 'Baidu',
290
+ 'desc' => 'http://www.baidu.com/search/robots_english.html',
291
+ ),
292
+ array(
293
+ 'state' => true,
294
+ 're' => 'serpstat',
295
+ 'name' => 'Serpstat',
296
+ 'desc' => 'https://serpstat.com/',
297
+ ),
298
+ array(
299
+ 'state' => true,
300
+ 'desc' => 'https://www.spyfu.com/',
301
+ 're' => 'spyfu',
302
+ 'name' => 'SpyFu',
303
+ ),
304
+ );
305
+
306
+ /**
307
+ * Class Constructor.
308
+ */
309
+ public function __construct() {
310
+ if ( is_admin() ) {
311
+ add_action( 'admin_notices', array( &$this, 'activate_plugin_notice' ) );
312
+ add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
313
+ add_action( 'wp_ajax_NSB-get_list', array( &$this, 'load_list' ) );
314
+ add_action( 'wp_ajax_NSB-set_list', array( &$this, 'save_list' ) );
315
+ add_action( 'wp_ajax_NSB-reset_list', array( &$this, 'reset_list' ) );
316
+ }
317
+
318
+ // Filter for Robots file.
319
+ add_filter( 'robots_txt', array( &$this, 'robots_file' ), ~PHP_INT_MAX, 2 );
320
+ add_action( 'generate_rewrite_rules', array( &$this, 'generate_rewrite_rules' ) );
321
+
322
+ }
323
+
324
+ /**
325
+ * Protect plugin from direct access.
326
+ *
327
+ * @param type $wp_rewrite Class for managing the rewrite rules.
328
+ */
329
+ public function generate_rewrite_rules( $wp_rewrite ) {
330
+ $wp_rewrite->add_external_rule( $this->plugin_url() . 'index.php', 'index.php%{REQUEST_URI}' );
331
+ $wp_rewrite->add_external_rule( $this->plugin_url() . 'readme.txt', 'index.php%{REQUEST_URI}' );
332
+ $wp_rewrite->add_external_rule( $this->plugin_url(), 'index.php%{REQUEST_URI}' );
333
+ }
334
+
335
+ /**
336
+ * Fetch Plugin URL.
337
+ *
338
+ * @return string
339
+ * @codeCoverageIgnore
340
+ */
341
+ private function plugin_url() {
342
+ $url = wp_make_link_relative( plugin_dir_url( __FILE__ ) );
343
+ $url = ltrim( $url, '/' );
344
+
345
+ return $url;
346
+ }
347
+
348
+ /**
349
+ * Add submenu page to the Tools main menu.
350
+ */
351
+ public function admin_menu() {
352
+ $menu = add_management_page(
353
+ 'SpiderBlocker', 'SpiderBlocker', 'manage_options', 'ni_spider_block', array( &$this, 'view_handler' )
354
+ );
355
+
356
+ add_action( 'load-' . $menu, array( &$this, 'view_handler_load' ) );
357
+ }
358
+
359
+ /**
360
+ * Admin notice which gets fired on plugin activation.
361
+ *
362
+ * @codeCoverageIgnore
363
+ */
364
+ public function activate_plugin_notice() {
365
+ if ( get_option( self::OPTIONNAME ) === false ) {
366
+ update_option( self::OPTIONNAME, $this->default_bots );
367
+ ?>
368
+ <div class="notice notice-success">
369
+ <p><?php esc_html_e( 'SpiderBlocker plugin has enabled blocking of some bots, please review settings by visiting', 'spiderblocker' ); ?> <a href="<?php echo esc_url( admin_url( 'tools.php?page=ni_spider_block' ) ); ?>"><?php esc_html_e( 'Setting page', 'spiderblocker' ); ?></a>!</p>
370
+ </div>
371
+ <?php
372
+ }
373
+ }
374
+
375
+ /**
376
+ * Generate block rules when the download process for a plugin
377
+ * install or update finishes.
378
+ *
379
+ * @codeCoverageIgnore
380
+ */
381
+ public function on_plugin_upgrade() {
382
+ $this->generate_block_rules();
383
+ }
384
+
385
+ /**
386
+ * This gets fired on plugin activation.
387
+ *
388
+ * @codeCoverageIgnore
389
+ */
390
+ public function activate_plugin() {
391
+ if ( ! apache_get_version() ) {
392
+ ?>
393
+ <div id="error-page">
394
+ <p><?php esc_html_e( 'This plugin requires Apache2 server with mod_rewrite support. Please contact your hosting provider about upgrading your server software. Your Apache version is', 'spiderblocker' ); ?> <b><?php echo esc_html( apache_get_version() ); ?></b></p>
395
+ </div>
396
+ <?php
397
+ die();
398
+ }
399
+
400
+ if ( ! SpiderBlocker::is_htaccess_writable() ) {
401
+ $state = SpiderBlocker::chmod_htaccess();
402
+ if ( ! SpiderBlocker::is_htaccess_writable() || ! $state ) {
403
+ ?>
404
+ <div id="error-page">
405
+ <p>
406
+ <?php
407
+ printf(
408
+ esc_html__( '%1$s %2$s %3$s', 'spiderblocker' ),
409
+ esc_html__( 'This plugin requires', 'spiderblocker' ),
410
+ '<b>.htaccess</b>',
411
+ esc_html__( 'file that is writable by the server. Please enable write access for file', 'spiderblocker' )
412
+ );
413
+ ?>
414
+ <b><?php echo esc_html( ABSPATH . '.htaccess' ); ?></b>.</p>
415
+ </div>
416
+ <?php
417
+ die();
418
+ }
419
+ }
420
+ $this->generate_block_rules();
421
+
422
+ }
423
+
424
+ /**
425
+ * Check if the .htaccess file is writable.
426
+ *
427
+ * @return bool
428
+ * @codeCoverageIgnore
429
+ */
430
+ private static function is_htaccess_writable() {
431
+ $htaccess_file = SpiderBlocker::join_paths( ABSPATH, '.htaccess' );
432
+ return is_writable( $htaccess_file );
433
+ }
434
+
435
+ /**
436
+ * Function to join the supplied arguments together.
437
+ *
438
+ * @return string
439
+ * @codeCoverageIgnore
440
+ */
441
+ private static function join_paths() {
442
+ $paths = array();
443
+
444
+ foreach ( func_get_args() as $arg ) {
445
+ if ( '' !== $arg ) {
446
+ $paths[] = $arg;
447
+ }
448
+ }
449
+
450
+ return preg_replace( '#/+#', '/', join( '/', $paths ) );
451
+ }
452
+
453
+ /**
454
+ * Change file permission of the .htaccess file.
455
+ *
456
+ * @param int $mod octet value for chmod.
457
+ * @return bool
458
+ * @codeCoverageIgnore
459
+ */
460
+ private static function chmod_htaccess( $mod = 0644 ) {
461
+ $home_path = function_exists( 'get_home_path' ) ? get_home_path() : ABSPATH;
462
+ $htaccess_file = $home_path . '.htaccess';
463
+
464
+ return chmod( $htaccess_file, $mod );
465
+ }
466
+
467
+ /**
468
+ * Add our rules for bots in the .htaccess file.
469
+ */
470
+ public function generate_block_rules() {
471
+ global $wp_rewrite;
472
+
473
+ $home_path = function_exists( 'get_home_path' ) ? get_home_path() : ABSPATH;
474
+ $htaccess_file = $home_path . '.htaccess';
475
+
476
+ if ( ( ! file_exists( $htaccess_file ) && is_writable( $home_path ) ) || is_writable( $htaccess_file ) ) {
477
+ insert_with_markers( $htaccess_file, 'NiteowebSpiderBlocker', $this->get_rules() );
478
+ }
479
+
480
+ $wp_rewrite->flush_rules();
481
+ }
482
+
483
+ /**
484
+ * Generate block rules based on enabled bots.
485
+ *
486
+ * @return array
487
+ */
488
+ public function get_rules() {
489
+ $list = array();
490
+ foreach ( $this->get_bots() as $bot ) {
491
+ if ( is_array( $bot ) ) {
492
+ $bot = (object) $bot;
493
+ }
494
+ if ( $bot->state ) {
495
+ $list[] = 'SetEnvIfNoCase User-Agent "' . $bot->re . '" block_bot';
496
+ }
497
+ }
498
+ $list[] = '<Limit GET POST HEAD>';
499
+ $list[] = 'Order Allow,Deny';
500
+ $list[] = 'Allow from all';
501
+ $list[] = 'Deny from env=block_bot';
502
+ $list[] = '</Limit>';
503
+
504
+ return $list;
505
+ }
506
+
507
+ /**
508
+ * Get the list of bots from the database or return default
509
+ * list if nothing found in the database.
510
+ *
511
+ * @return array
512
+ */
513
+ public function get_bots() {
514
+ $data = get_option( self::OPTIONNAME );
515
+ if ( $data ) {
516
+ return maybe_unserialize( $data );
517
+ }
518
+ return $this->default_bots;
519
+ }
520
+
521
+ /**
522
+ * Gets called via AJAX to return the the list of bots.
523
+ */
524
+ public function load_list() {
525
+ check_ajax_referer( self::NONCE, 'nonce' );
526
+ wp_send_json_success( $this->get_bots() );
527
+ }
528
+
529
+ /**
530
+ * Gets called via AJAX to return the the list of default bots.
531
+ */
532
+ public function reset_list() {
533
+ check_ajax_referer( self::NONCE, 'nonce' );
534
+ delete_option( self::OPTIONNAME );
535
+ $this->generate_block_rules();
536
+ add_filter( 'robots_txt', array( &$this, 'robots_file' ), ~PHP_INT_MAX, 2 );
537
+ wp_send_json_success( $this->get_bots() );
538
+ }
539
+
540
+ /**
541
+ * Remove our bot rules from the .htaccess file.
542
+ */
543
+ public function remove_block_rules() {
544
+ global $wp_rewrite;
545
+
546
+ delete_option( self::OPTIONNAME );
547
+ $home_path = function_exists( 'get_home_path' ) ? get_home_path() : ABSPATH;
548
+ $htaccess_file = $home_path . '.htaccess';
549
+ $empty = array();
550
+ if ( ( ! file_exists( $htaccess_file ) && is_writable( $home_path ) ) || is_writable( $htaccess_file ) ) {
551
+ insert_with_markers( $htaccess_file, 'NiteowebSpiderBlocker', $empty );
552
+ }
553
+
554
+ $wp_rewrite->flush_rules();
555
+ }
556
+
557
+ /**
558
+ * Gets called via AJAX to update the bots list in the database.
559
+ */
560
+ public function save_list() {
561
+ check_ajax_referer( self::NONCE, 'nonce' );
562
+ if ( isset( $_POST['data'] ) && '' !== $_POST['data'] ) {
563
+ $data = json_decode( stripcslashes( $_POST['data'] ), true );
564
+
565
+ if ( json_last_error() ) {
566
+ if ( function_exists( 'json_last_error_msg' ) ) {
567
+ wp_send_json_error( json_last_error_msg() );
568
+ } else {
569
+ wp_send_json_error( esc_html__( 'Failed parsing JSON', 'spiderblocker' ) );
570
+ }
571
+ }
572
+
573
+ if ( get_option( self::OPTIONNAME ) !== false ) {
574
+ update_option( self::OPTIONNAME, maybe_serialize( $data ) );
575
+ } else {
576
+ add_option( self::OPTIONNAME, maybe_serialize( $data ), '', 'no' );
577
+ }
578
+
579
+ $this->generate_block_rules();
580
+ add_filter( 'robots_txt', array( &$this, 'robots_file' ), ~PHP_INT_MAX, 2 );
581
+ wp_send_json_success( $this->get_bots() );
582
+ } else {
583
+ wp_send_json_error( esc_html__( 'Unable to process the request as no data has been received.', 'spiderblocker' ) );
584
+ }
585
+ }
586
+
587
+ /**
588
+ * This function is supplied to robots_txt filter to add bots block
589
+ * rules to the robots.txt file.
590
+ *
591
+ * @param string $output Output of the robots.txt file before our additions.
592
+ * @param bool $public Blog's public status fetched from the database.
593
+ */
594
+ public function robots_file( $output, $public ) {
595
+ // Get bots list.
596
+ $data = $this->get_bots();
597
+
598
+ if ( $data ) {
599
+ foreach ( $data as $entry ) {
600
+ if ( ! empty( $entry['state'] ) ) {
601
+ $output .= sprintf( "User-agent: %s\n", $entry['re'] );
602
+ $output .= "Disallow: /\n";
603
+ $output .= "\n";
604
+ }
605
+ }
606
+ }
607
+
608
+ return $output;
609
+ }
610
+
611
+ /**
612
+ * Plugin HTML is rendered via this function.
613
+ *
614
+ * @codeCoverageIgnore
615
+ */
616
+ public function view_handler() {
617
+ ?>
618
+ <style>
619
+ .notice.fixed {
620
+ position: fixed;
621
+ right: 1em;
622
+ top: 3.5em;
623
+ }
624
+
625
+ tr.active {
626
+ background-color: rgba(54, 204, 255, 0.05);
627
+ }
628
+
629
+ .active th.bot-re {
630
+ border-left: 4px solid #2ea2cc;
631
+ }
632
+ </style>
633
+
634
+ <script>
635
+ window.sb_nonce = "<?php echo esc_html( wp_create_nonce( self::NONCE ) ); ?>";
636
+ -(function () {
637
+ var spiderBlockApp = angular.module('spiderBlockApp', []);
638
+
639
+ spiderBlockApp.directive('jsonText', function () {
640
+ return {
641
+ restrict: 'A',
642
+ require: 'ngModel',
643
+ link: function (scope, element, attr, ngModel) {
644
+ function into(input) {
645
+ return angular.fromJson(input);
646
+ }
647
+
648
+ function out(data) {
649
+ return angular.toJson(data, true);
650
+ }
651
+
652
+ ngModel.$parsers.push(into);
653
+ ngModel.$formatters.push(out);
654
+ }
655
+ };
656
+ });
657
+ spiderBlockApp.controller('NotificationsCtrl', function ($scope, $rootScope, $timeout) {
658
+ $scope.notifications = [];
659
+
660
+ $rootScope.$on('notification', function (event, data) {
661
+ $scope.notifications.push(data);
662
+ $timeout(function () {
663
+ $scope.removeNotification(data);
664
+ }, 3000);
665
+ });
666
+
667
+ $scope.removeNotification = function (notification) {
668
+ var index;
669
+ if ($scope.notifications !== undefined) {
670
+ index = $scope.notifications.indexOf(notification);
671
+ $scope.notifications.splice(index, 1);
672
+ }
673
+ }
674
+ });
675
+ spiderBlockApp.controller('BotListCtrl', function ($scope, $http, $rootScope) {
676
+ var wp_ajax = function (_req) {
677
+ _req.nonce = window.sb_nonce;
678
+ return $http({
679
+ method: 'POST',
680
+ url: ajaxurl,
681
+ data: jQuery.param(_req),
682
+ headers: {'Content-Type': 'application/x-www-form-urlencoded'}
683
+ })
684
+ };
685
+
686
+ var find_bot = function (re) {
687
+ for (var i = $scope.bots.length - 1; i >= 0; i--) {
688
+ if ($scope.bots[i]['re'] == re) {
689
+ return i;
690
+ }
691
+ }
692
+ return null;
693
+ };
694
+
695
+ $scope.bot = {"state": true};
696
+
697
+ wp_ajax({
698
+ action: 'NSB-get_list'
699
+ }).success(function (res) {
700
+ $scope.bots = res.data;
701
+ });
702
+
703
+ $scope.save = function () {
704
+ wp_ajax({
705
+ action: 'NSB-set_list',
706
+ data: angular.toJson($scope.bots)
707
+ }).success(function (res) {
708
+ if (res.success) {
709
+ $scope.bots = res.data;
710
+ $rootScope.$emit('notification', {
711
+ state: 'success',
712
+ msg: 'List of bots was saved and new blocklist applied!'
713
+ });
714
+ } else {
715
+ $rootScope.$emit('notification', {state: 'errror', msg: res.data});
716
+ }
717
+ });
718
+ };
719
+
720
+ $scope.reset = function () {
721
+ wp_ajax({
722
+ action: 'NSB-reset_list'
723
+ }).success(function (res) {
724
+ $scope.bots = res.data;
725
+ $rootScope.$emit('notification', {
726
+ state: 'success',
727
+ msg: 'List of bots was reset to defaults!'
728
+ });
729
+ });
730
+ };
731
+
732
+ $scope.add = function () {
733
+ $scope.bots.push($scope.bot);
734
+ $rootScope.$emit('notification', {
735
+ state: 'success',
736
+ msg: 'Bot ' + $scope.bot.name + ' was added!'
737
+ });
738
+ $scope.bot = {"state": true};
739
+ };
740
+
741
+ $scope.remove = function (at) {
742
+ $rootScope.$emit('notification', {state: 'success', msg: 'Bot was removed!'});
743
+ $scope.bots.splice(find_bot(at), 1);
744
+ };
745
+ });
746
+ })(angular, document, jQuery);
747
+ </script>
748
+ <h1><?php esc_html_e( 'Spider Blocker', 'spiderblocker' ); ?></h1>
749
+ <hr/>
750
+ <div ng-app="spiderBlockApp">
751
+ <div ng-controller="NotificationsCtrl">
752
+ <div class="notice notice-{{ n.state }} fixed" ng-repeat="n in notifications" style="top: {{3.5*($index+1)}}em">
753
+ <p>{{n.msg}}
754
+ <a ng-click="removeNotification(notification)">
755
+ <span class="dashicons dashicons-no-alt"></span>
756
+ </a>
757
+ </p>
758
+ </div>
759
+ </div>
760
+
761
+ <div ng-controller="BotListCtrl">
762
+ <h2><?php esc_html_e( 'Add New Bot', 'spiderblocker' ); ?></h2>
763
+
764
+ <form name="add_form" ng-submit="add()">
765
+ <table class="form-table">
766
+ <tbody>
767
+ <tr>
768
+ <th scope="row"><label><?php esc_html_e( 'User Agent', 'spiderblocker' ); ?></label></th>
769
+ <td><input bots="bots" ng-model='bot.re' class="regular-text" required/></td>
770
+ </tr>
771
+ <tr>
772
+ <th scope="row"><label><?php esc_html_e( 'Bot Name', 'spiderblocker' ); ?></label></th>
773
+ <td><input type="text" ng-model='bot.name' class="regular-text" required/></td>
774
+ </tr>
775
+ <tr>
776
+ <tr>
777
+ <th scope="row"><label><?php esc_html_e( 'Bot Description URL', 'spiderblocker' ); ?></label></th>
778
+ <td><input type="url" ng-model='bot.desc' class="regular-text" placeholder="http://"/>
779
+ </td>
780
+ </tr>
781
+ </tbody>
782
+ </table>
783
+
784
+ <p class="submit"><input ng-disabled="add_form.$invalid" type="submit" class="button button-primary" value="<?php esc_attr_e( 'Add Bot', 'spiderblocker' ); ?>"></p>
785
+ </form>
786
+
787
+ <h2><?php esc_html_e( 'List of bots', 'spiderblocker' ); ?></h2>
788
+ <ng-form class="search-box">
789
+ <input size="35" type="search" id="ua-search-input" ng-model="query" placeholder="<?php esc_attr_e( 'Filter...', 'spiderblocker' ); ?>">
790
+ </ng-form>
791
+
792
+ <table class="wp-list-table widefat bots">
793
+ <thead>
794
+ <tr>
795
+ <th scope="col" class="manage-column column-description">
796
+ <a href="" ng-click="predicate = 're'; reverse=false"><?php esc_html_e( 'User Agent', 'spiderblocker' ); ?> <span class="dashicons dashicons-sort"></span></a>
797
+ </th>
798
+ <th scope="col" class="manage-column column-name"><?php esc_html_e( 'Name', 'spiderblocker' ); ?></th>
799
+ <th scope="col" class="manage-column column-state">
800
+ <a href="" ng-click="predicate = 'state'; reverse=false"><?php esc_html_e( 'State', 'spiderblocker' ); ?> <span class="dashicons dashicons-sort"></span></a>
801
+ </th>
802
+ <th scope="col" id="action" class="manage-column column-action"><?php esc_html_e( 'Action', 'spiderblocker' ); ?></th>
803
+ </tr>
804
+ </thead>
805
+
806
+ <tfoot>
807
+ <tr>
808
+ <th scope="col" class="manage-column column-description"><a href="" ng-click="predicate = 're'; reverse=false"><?php esc_html_e( 'User Agent', 'spiderblocker' ); ?></a></th>
809
+ <th scope="col" class="manage-column column-name"><?php esc_html_e( 'Name', 'spiderblocker' ); ?></th>
810
+ <th scope="col" class="manage-column column-state"><a href="" ng-click="predicate = 'state'; reverse=false"><?php esc_html_e( 'State', 'spiderblocker' ); ?></a>
811
+ </th>
812
+ <th scope="col" id="action" class="manage-column column-action"><?php esc_html_e( 'Action', 'spiderblocker' ); ?></th>
813
+ </tr>
814
+ </tfoot>
815
+
816
+ <tbody id="the-list">
817
+ <tr id="spider-blocker" ng-repeat="bot in bots | filter:query | orderBy:predicate:reverse"
818
+ ng-class="{'active': bot.state}">
819
+
820
+ <th class="bot-re"> {{ bot.re }}</th>
821
+ <td class="bot-title"><strong>{{ bot.name }}</strong> <a target="_blank" ng-href="{{bot.desc}}">{{ bot.desc }}</a></td>
822
+ <th class="expression" ng-class="{'blocked':bot.state}"> {{ bot.state?"Blocked":"Allowed" }}</th>
823
+ <td class="actions">
824
+ <input ng-hide="bot.state" type="button" ng-click="bot.state=true" class="button button-primary" value="Block">
825
+ <input ng-show="bot.state" type="button" ng-click="bot.state=false" class="button button-secondary" value="Allow">
826
+ <input type="button" ng-click="remove(bot.re)" class="button button-secondary" value="Remove">
827
+ </td>
828
+ </tr>
829
+ </tbody>
830
+ </table>
831
+
832
+ <div id="rules-export-import" style="display:none;">
833
+ <textarea style="-webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;width: 100%;height: 99%;" json-text ng-model="bots"></textarea>
834
+ </div>
835
+
836
+ <p class="submit">
837
+ <input type="button" class="button button-primary" ng-click="save()" value="<?php esc_attr_e( 'Save', 'spiderblocker' ); ?>">
838
+ <input type="button" class="button button-primary" ng-click="reset()" value="<?php esc_attr_e( 'Reset to Defaults', 'spiderblocker' ); ?>">
839
+ <a href="#TB_inline?width=540&height=360&inlineId=rules-export-import" class="thickbox button button-secondary"><?php esc_html_e( 'Import/Export Definitions', 'spiderblocker' ); ?></a>
840
+ </p>
841
+ </div>
842
+ </div>
843
+ <?php
844
+ }
845
+
846
+ /**
847
+ * Adds action for admin scripts.
848
+ */
849
+ public function view_handler_load() {
850
+ add_action( 'admin_enqueue_scripts', array( &$this, 'view_handler_scripts' ) );
851
+ }
852
+
853
+ /**
854
+ * Registers & Enqueues the admin scripts for the view_handler() function.
855
+ */
856
+ public function view_handler_scripts() {
857
+ wp_register_script( 'spiderblocker-angular', 'https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js', array( 'jquery' ), '1.0.18', false );
858
+ wp_enqueue_script( 'spiderblocker-angular' );
859
+ wp_enqueue_media( 'thickbox' );
860
+ }
861
 
862
  }
863
 
864
+ // Initialize Plugin.
865
+ if ( defined( 'ABSPATH' ) ) {
866
+ $niteo_spider_blocker = new SpiderBlocker();
867
+
868
+ add_action( 'upgrader_process_complete', array( &$niteo_spider_blocker, 'on_plugin_upgrade' ), 10, 2 );
869
 
870
+ // Activation Hook.
871
+ register_activation_hook( __FILE__, array( &$niteo_spider_blocker, 'activate_plugin' ) );
872
+
873
+ // Deactivation Hook.
874
+ register_deactivation_hook( __FILE__, array( &$niteo_spider_blocker, 'remove_block_rules' ) );
875
+ }
langs/spiderblocker.pot ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #, fuzzy
2
+ msgid ""
3
+ msgstr ""
4
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
5
+ "Project-Id-Version: Spider Blocker\n"
6
+ "POT-Creation-Date: 2018-07-19 02:04+0530\n"
7
+ "PO-Revision-Date: 2018-07-19 02:04+0530\n"
8
+ "Last-Translator: \n"
9
+ "Language-Team: \n"
10
+ "MIME-Version: 1.0\n"
11
+ "Content-Type: text/plain; charset=UTF-8\n"
12
+ "Content-Transfer-Encoding: 8bit\n"
13
+ "X-Generator: Poedit 2.0.4\n"
14
+ "X-Poedit-Basepath: ..\n"
15
+ "X-Poedit-Flags-xgettext: --add-comments=translators:\n"
16
+ "X-Poedit-WPHeader: spiderblocker.php\n"
17
+ "X-Poedit-SourceCharset: UTF-8\n"
18
+ "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
19
+ "esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
20
+ "_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
21
+ "X-Poedit-SearchPath-0: .\n"
22
+ "X-Poedit-SearchPathExcluded-0: *.js\n"
23
+
24
+ #: classes/class-spiderblocker.php:323
25
+ msgid ""
26
+ "SpiderBlocker plugin has enabled blocking of some bots, please review "
27
+ "settings by visiting"
28
+ msgstr ""
29
+
30
+ #: classes/class-spiderblocker.php:323
31
+ msgid "Setting page"
32
+ msgstr ""
33
+
34
+ #: classes/class-spiderblocker.php:348
35
+ msgid ""
36
+ "This plugin requires Apache2 server with mod_rewrite support. Please contact "
37
+ "your hosting provider about upgrading your server software. Your Apache "
38
+ "version is"
39
+ msgstr ""
40
+
41
+ #: classes/class-spiderblocker.php:362
42
+ #, php-format
43
+ msgid "%1$s %2$s %3$s"
44
+ msgstr ""
45
+
46
+ #: classes/class-spiderblocker.php:363
47
+ msgid "This plugin requires"
48
+ msgstr ""
49
+
50
+ #: classes/class-spiderblocker.php:365
51
+ msgid ""
52
+ "file that is writable by the server. Please enable write access for file"
53
+ msgstr ""
54
+
55
+ #: classes/class-spiderblocker.php:523
56
+ msgid "Failed parsing JSON"
57
+ msgstr ""
58
+
59
+ #: classes/class-spiderblocker.php:537
60
+ msgid "Unable to process the request as no data has been received."
61
+ msgstr ""
62
+
63
+ #. Plugin Name of the plugin/theme
64
+ #: classes/class-spiderblocker.php:702
65
+ msgid "Spider Blocker"
66
+ msgstr ""
67
+
68
+ #: classes/class-spiderblocker.php:716
69
+ msgid "Add New Bot"
70
+ msgstr ""
71
+
72
+ #: classes/class-spiderblocker.php:722 classes/class-spiderblocker.php:750
73
+ #: classes/class-spiderblocker.php:762
74
+ msgid "User Agent"
75
+ msgstr ""
76
+
77
+ #: classes/class-spiderblocker.php:726
78
+ msgid "Bot Name"
79
+ msgstr ""
80
+
81
+ #: classes/class-spiderblocker.php:731
82
+ msgid "Bot Description URL"
83
+ msgstr ""
84
+
85
+ #: classes/class-spiderblocker.php:738
86
+ msgid "Add Bot"
87
+ msgstr ""
88
+
89
+ #: classes/class-spiderblocker.php:741
90
+ msgid "List of bots"
91
+ msgstr ""
92
+
93
+ #: classes/class-spiderblocker.php:743
94
+ msgid "Filter..."
95
+ msgstr ""
96
+
97
+ #: classes/class-spiderblocker.php:752 classes/class-spiderblocker.php:763
98
+ msgid "Name"
99
+ msgstr ""
100
+
101
+ #: classes/class-spiderblocker.php:754 classes/class-spiderblocker.php:764
102
+ msgid "State"
103
+ msgstr ""
104
+
105
+ #: classes/class-spiderblocker.php:756 classes/class-spiderblocker.php:766
106
+ msgid "Action"
107
+ msgstr ""
108
+
109
+ #: classes/class-spiderblocker.php:791
110
+ msgid "Save"
111
+ msgstr ""
112
+
113
+ #: classes/class-spiderblocker.php:792
114
+ msgid "Reset to Defaults"
115
+ msgstr ""
116
+
117
+ #: classes/class-spiderblocker.php:793
118
+ msgid "Import/Export Definitions"
119
+ msgstr ""
120
+
121
+ #: spiderblocker.php:46
122
+ msgid ""
123
+ "This plugin requires PHP 5.3.0 or higher. Please contact your hosting "
124
+ "provider about upgrading your\n"
125
+ "\t\t\tserver software. Your PHP version is"
126
+ msgstr ""
127
+
128
+ #. Description of the plugin/theme
129
+ msgid ""
130
+ "Spider Blocker will block most common bots that consume bandwidth and slow "
131
+ "down your server."
132
+ msgstr ""
133
+
134
+ #. Author of the plugin/theme
135
+ msgid "Easy Blog Networks"
136
+ msgstr ""
137
+
138
+ #. Author URI of the plugin/theme
139
+ msgid "www.easyblognetworks.com"
140
+ msgstr ""
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: niteoweb
3
  Tags: seo, block, bots, htaccess, apache, secure
4
  Requires at least: 4.0
5
- Tested up to: 4.7.3
6
- Stable tag: 1.0.16
7
 
8
  SpiderBlocker will block most common bots that consume bandwidth and slow down your server.
9
 
2
  Contributors: niteoweb
3
  Tags: seo, block, bots, htaccess, apache, secure
4
  Requires at least: 4.0
5
+ Tested up to: 4.9.7
6
+ Stable tag: 1.0.18
7
 
8
  SpiderBlocker will block most common bots that consume bandwidth and slow down your server.
9