AntiVirus - Version 1.3.10

Version Description

Download this release

Release Info

Developer Kau-Boy
Plugin Icon 128x128 AntiVirus
Version 1.3.10
Comparing to
See all releases

Code changes from version 1.3.9 to 1.3.10

README.md CHANGED
@@ -1,166 +1,117 @@
1
- # AntiVirus #
2
- * Contributors: pluginkollektiv
3
- * Tags: antivirus, malware, scanner, phishing, safe browsing, vulnerability
4
- * Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=LG5VC9KXMAYXJ
5
- * Requires at least: 3.8
6
- * Tested up to: 4.6
7
- * Stable tag: 1.3.9
8
- * License: GPLv2 or later
9
- * License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
-
11
-
12
- Security plugin to protect your blog or website against exploits and spam injections.
13
-
14
-
15
- ## Description ##
16
- *AntiVirus for WordPress* is a easy-to-use, safe tool to harden your WordPress site against exploits, malware and spam injections.
17
- You can configure *AntiVirus* to perform an automated daily scan of your theme files and database tables. If the plugin happens to detect any suspicious code injections, it will send out a notification to a previously configured e-mail address.
18
-
19
- In case your WordPress site has been hacked, *AntiVirus* will help you to become aware of the problem very quickly in order for you to take immediate action.
20
-
21
-
22
- ### Features ###
23
- * Virus alert in the admin bar
24
- * Cleaning up after plugin removal
25
- * Translations into many languages​​
26
- * Daily scan with email notifications
27
- * Database tables and theme templates checks
28
- * WordPress 3.x ready: both visually and technically
29
- * Whitelist solution: Mark suspected cases as "no virus"
30
- * Manual check of template files with alerts on suspected cases
31
- * Optional: Google Safe Browsing for malware and phishing monitoring.
32
-
33
-
34
- > #### Auf Deutsch? ####
35
- > Für eine ausführliche Dokumentation besuche bitte das [AntiVirus-Wiki](https://github.com/pluginkollektiv/antivirus/wiki).
36
- >
37
- > **Community-Support auf Deutsch** erhältst du in einem der [deutschsprachigen Foren](https://de.forums.wordpress.org/forum/plugins); im [Plugin-Forum für AntiVirus](https://wordpress.org/support/plugin/antivirus) wird, wie in allen Plugin-Foren auf wordpress.org, ausschließlich **Englisch** gesprochen.
38
-
39
-
40
- ### Languages ###
41
- * English
42
- * German
43
- * German formal
44
-
45
-
46
- ### Credits ###
47
- * Author: [Sergej Müller](https://sergejmueller.github.io/)
48
- * Maintainers: [pluginkollektiv](http://pluginkollektiv.org/)
49
-
50
-
51
- ## Installation ##
52
- * If you don’t know how to install a plugin for WordPress, [here’s how](http://codex.wordpress.org/Managing_Plugins#Installing_Plugins).
53
-
54
- ### Requirements ###
55
- * PHP 5.2.4 or greater
56
- * WordPress 3.8 or greater
57
-
58
- ## Frequently Asked Questions ##
59
-
60
- ### Will AntiVirus protect my site from being hacked? ###
61
- Not literally “protect from”. The plugin’s purpose is to _detect_ any “hack” that has already happened and enable you to take immediate action upon it.
62
-
63
-
64
- ## Changelog ##
65
- ### 1.3.9 ###
66
- * generated a POT file
67
- * added German formal translation
68
- * updated, translated + formatted README.md
69
- * updated expired link URLs in plugin and languages files
70
- * updated [plugin authors](https://gist.github.com/glueckpress/f058c0ab973d45a72720)
71
-
72
- ### 1.3.8 ###
73
- * Deutsch: Erkennung der [MailPoet-Sicherheitslücke](http://blog.sucuri.net/2014/07/mailpoet-vulnerability-exploited-in-the-wild-breaking-thousands-of-wordpress-sites.html)
74
- * English: Detection and warning for the [MailPoet Vulnerability](http://blog.sucuri.net/2014/07/mailpoet-vulnerability-exploited-in-the-wild-breaking-thousands-of-wordpress-sites.html)
75
-
76
- ### 1.3.7 ###
77
- * Deutsch: Aktualisierung auf Safe Browsing Lookup API 3.1
78
- * English: Update the Google Safe Browsing Lookup API to v3.1
79
-
80
- ### 1.3.6 ###
81
- * Deutsch: Code-Revision und Datenvalidierung
82
- * English: Code revision and data validation
83
-
84
- ### 1.3.5 ###
85
- * Deutsch: Optimierungen für WordPress 3.8
86
- * English: Optimizations for WordPress 3.8
87
-
88
- ### 1.3.4 ###
89
- * Deutsch: Benachrichtigung per E-Mail, sobald [Google Safe Browsing](http://en.wikipedia.org/wiki/Google_Safe_Browsing) Malware im Blog erkennt. [Mehr auf Google+](https://plus.google.com/110569673423509816572/posts/H72FFwvna1i)
90
- * English: [Google Safe Browsing](http://en.wikipedia.org/wiki/Google_Safe_Browsing) for malware and phishing monitoring.
91
-
92
- ### 1.3.3 ###
93
- * Add inspection for iFrames
94
- * Retina support for teaser and screenshot
95
-
96
- ### 1.3.2 ###
97
- * Remove the check for include and require commands (#wpforce)
98
-
99
- ### 1.3.1 ###
100
- * Compatibility with WordPress 3.4
101
- * High-resolution plugin icon for retina displays
102
- * Remove icon from the admin sidebar
103
- * System requirements: From PHP 5.0 to PHP 5.1
104
-
105
- ### 1.3 ###
106
- * Xmas Edition
107
-
108
- ### 1.2 ###
109
- * "Virus suspected" alert in the admin bar
110
- * Fix for the manual scan link on dashboard
111
- * More detailed checks for existing malware
112
- * Code adjustments for WordPress 3.3
113
-
114
- ### 1.1 ###
115
- * Testing for templates with empty content
116
- * Minimum requirement upgraded to 2.8 and PHP5
117
- * Code improvements for more speed
118
- * GUI changes
119
-
120
- ### 1.0 ###
121
- * More security checks (Email & Regexp)
122
-
123
- ### 0.9 ###
124
- * Changes for the current WordPress virus
125
-
126
- ### 0.8 ###
127
- * Support for WordPress 3.0
128
- * System requirements: WordPress 2.7
129
- * Code optimization
130
-
131
- ### 0.7 ###
132
- * Advanced templates check
133
-
134
- ### 0.6 ###
135
- * WordPress 2.9 support
136
-
137
- ### 0.5 ###
138
- * Add security scan for the current [WordPress permalink back door](http://mashable.com/2009/09/05/wordpress-attack/ "WordPress permalink back door")
139
- * Software architecture changes
140
-
141
- ### 0.4 ###
142
- * Adds support for WordPress new changelog readme.txt standard
143
- * Various changes for more speed, usability and security
144
-
145
- ### 0.3 ###
146
- * Add alternate e-mail address (admin e-mail address as default)
147
- * Admin notice on dashboard where it has found the virus suspicion
148
- * Added blog URL in e-mail
149
- * WordPress 2.8 support
150
- * Check for hidden iframes
151
- * Bugfix for IE problem with box positions
152
- * Cleanup the source code
153
- * Language support for Persian
154
-
155
- ### 0.2 ###
156
- * Whitelist: Mark the suspicion as "No virus"
157
- * Improving the output formatting
158
- * Add WPlize library for option data
159
- * Language support for Italian
160
-
161
- ### 0.1 ###
162
- * AntiVirus for WordPress goes online
163
-
164
-
165
- ## Screenshots ##
166
- 1. WordPress AntiVirus settings
1
+ # AntiVirus #
2
+ * Contributors: pluginkollektiv
3
+ * Tags: antivirus, malware, scanner, phishing, safe browsing, vulnerability
4
+ * Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=TD4AMD2D8EMZW
5
+ * Requires at least: 3.8
6
+ * Tested up to: 5.1
7
+ * Stable tag: 1.3.10
8
+ * License: GPLv2 or later
9
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
+
11
+ Security plugin to protect your blog or website against exploits and spam injections.
12
+
13
+ ## Description ##
14
+ *AntiVirus for WordPress* is a easy-to-use, safe tool to harden your WordPress site against exploits, malware and spam injections.
15
+ You can configure *AntiVirus* to perform an automated daily scan of your theme files and database tables. If the plugin happens to detect any suspicious code injections, it will send out a notification to a previously configured e-mail address.
16
+
17
+ In case your WordPress site has been hacked, *AntiVirus* will help you to become aware of the problem very quickly in order for you to take immediate action.
18
+
19
+ [](http://coderisk.com/wp/plugin/antivirus/RIPS-x1EDAuZC-C)
20
+
21
+ ### Features ###
22
+ * Virus alert in the admin bar
23
+ * Cleaning up after plugin removal
24
+ * Daily scan with email notifications
25
+ * Database tables and theme templates checks
26
+ * Whitelist solution: Mark suspected cases as "no virus"
27
+ * Manual check of template files with alerts on suspected cases
28
+ * Optional: Google Safe Browsing for malware and phishing monitoring.
29
+
30
+ ### Support ###
31
+ * Community support via the [support forums on wordpress.org](https://wordpress.org/support/plugin/antivirus)
32
+ * We don’t handle support via e-mail, Twitter, GitHub issues etc.
33
+
34
+ ### Contribute ###
35
+ * Active development of this plugin is handled [on GitHub](https://github.com/pluginkollektiv/antivirus).
36
+ * Pull requests for documented bugs are highly appreciated.
37
+ * If you think you’ve found a bug (e.g. you’re experiencing unexpected behavior), please post at the [support forums](https://wordpress.org/support/plugin/antivirus) first.
38
+ * If you want to help us translate this plugin you can do so [on WordPress Translate](https://translate.wordpress.org/projects/wp-plugins/antivirus).
39
+
40
+ ### Credits ###
41
+ * Author: [Sergej Müller](https://sergejmueller.github.io/)
42
+ * Maintainers: [pluginkollektiv](http://pluginkollektiv.org/)
43
+
44
+ ## Installation ##
45
+ * If you don’t know how to install a plugin for WordPress, [here’s how](https://codex.wordpress.org/Managing_Plugins#Installing_Plugins).
46
+
47
+ ### Requirements ###
48
+ * PHP 5.2.4 or greater
49
+ * WordPress 3.8 or greater
50
+
51
+ ## Frequently Asked Questions ##
52
+
53
+ ### Will AntiVirus protect my site from being hacked? ###
54
+ Not literally "protect from". The plugin’s purpose is to *detect* any "hack" that has already happened and enable you to take immediate action upon it.
55
+
56
+ A complete documentation is available in the [GitHub repository Wiki](https://github.com/pluginkollektiv/antivirus/wiki).
57
+
58
+ ## Changelog ##
59
+
60
+ ### 1.3.10 ###
61
+
62
+ * Updated PayPal link for donations
63
+ * Improve coding standards
64
+ * Translation fixes, improvements and cleanups
65
+ * Better documentation
66
+ * Some minor markup, styling, accessibility and security improvements
67
+ * Update to Safe Browsing API v4 (fixing false positive email notifications)
68
+ * PHP 7.x compatibility fixes
69
+ * Better regex to prevent false positives in file scans
70
+
71
+ ### 1.3.9 ###
72
+ * generated a POT file
73
+ * added German formal translation
74
+ * updated, translated + formatted README.md
75
+ * updated expired link URLs in plugin and languages files
76
+ * updated [plugin authors](https://gist.github.com/glueckpress/f058c0ab973d45a72720)
77
+
78
+ ### 1.3.8 ###
79
+ * Detection and warning for the [MailPoet Vulnerability](http://blog.sucuri.net/2014/07/mailpoet-vulnerability-exploited-in-the-wild-breaking-thousands-of-wordpress-sites.html)
80
+
81
+ ### 1.3.7 ###
82
+ * Update the Google Safe Browsing Lookup API to v3.1
83
+
84
+ ### 1.3.6 ###
85
+ * Code revision and data validation
86
+
87
+ ### 1.3.5 ###
88
+ * Optimizations for WordPress 3.8
89
+
90
+ ### 1.3.4 ###
91
+ * [Google Safe Browsing](http://en.wikipedia.org/wiki/Google_Safe_Browsing) for malware and phishing monitoring with e-mail notification. [Additional information on Google+](https://plus.google.com/110569673423509816572/posts/H72FFwvna1i) (only german)
92
+
93
+ ### 1.3.3 ###
94
+ * Add inspection for iFrames
95
+ * Retina support for teaser and screenshot
96
+
97
+ ### 1.3.2 ###
98
+ * Remove the check for include and require commands (#wpforce)
99
+
100
+ ### 1.3.1 ###
101
+ * Compatibility with WordPress 3.4
102
+ * High-resolution plugin icon for retina displays
103
+ * Remove icon from the admin sidebar
104
+ * System requirements: From PHP 5.0 to PHP 5.1
105
+
106
+ ### 1.3 ###
107
+ * Xmas Edition
108
+
109
+ For the complete changelog, check out our [GitHub repository](https://github.com/pluginkollektiv/antivirus).
110
+
111
+ ## Upgrade Notice ##
112
+
113
+ ### 1.3.10 ###
114
+ This is a maintenance release, fixing our Google Safe Browsing lookup and some minor issues.
115
+
116
+ ## Screenshots ##
117
+ 1. WordPress AntiVirus settings
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
antivirus.php CHANGED
@@ -1,1332 +1,1088 @@
1
- <?php
2
- /*
3
- Plugin Name: AntiVirus
4
- Description: Security plugin to protect your blog or website against exploits and spam injections.
5
- Author: pluginkollektiv
6
- Author URI: http://pluginkollektiv.org
7
- Plugin URI: https://wordpress.org/plugins/antivirus/
8
- Text Domain: antivirus
9
- Domain Path: /lang
10
- License: GPLv2 or later
11
- License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
- Version: 1.3.9
13
- */
14
-
15
- /*
16
- Copyright (C) 2009-2015 Sergej Müller
17
-
18
- This program is free software; you can redistribute it and/or modify
19
- it under the terms of the GNU General Public License as published by
20
- the Free Software Foundation; either version 2 of the License, or
21
- (at your option) any later version.
22
-
23
- This program is distributed in the hope that it will be useful,
24
- but WITHOUT ANY WARRANTY; without even the implied warranty of
25
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
- GNU General Public License for more details.
27
-
28
- You should have received a copy of the GNU General Public License along
29
- with this program; if not, write to the Free Software Foundation, Inc.,
30
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31
- */
32
-
33
-
34
- /* Sicherheitsabfrage */
35
- if ( ! class_exists('WP') ) {
36
- die();
37
- }
38
-
39
-
40
- /**
41
- * AntiVirus
42
- *
43
- * @since 0.1
44
- */
45
-
46
- class AntiVirus {
47
-
48
-
49
- /* Save me! */
50
- private static $base;
51
-
52
-
53
- /**
54
- * Pseudo-Konstruktor der Klasse
55
- *
56
- * @since 1.3.4
57
- * @change 1.3.4
58
- */
59
-
60
- public static function instance()
61
- {
62
- new self();
63
- }
64
-
65
-
66
- /**
67
- * Konstruktor der Klasse
68
- *
69
- * @since 0.1
70
- * @change 1.3.5
71
- */
72
-
73
- public function __construct()
74
- {
75
- /* AUTOSAVE */
76
- if ( ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) OR ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ) ) {
77
- return;
78
- }
79
-
80
- /* Plugin-Base */
81
- self::$base = plugin_basename(__FILE__);
82
-
83
- /* Cronjob */
84
- if ( defined('DOING_CRON') ) {
85
- add_action(
86
- 'antivirus_daily_cronjob',
87
- array(
88
- __CLASS__,
89
- 'do_daily_cronjob'
90
- )
91
- );
92
-
93
- /* Admin */
94
- } elseif ( is_admin() ) {
95
- /* AJAX */
96
- if ( defined('DOING_AJAX') ) {
97
- add_action(
98
- 'wp_ajax_get_ajax_response',
99
- array(
100
- __CLASS__,
101
- 'get_ajax_response'
102
- )
103
- );
104
-
105
- /* Backend */
106
- } else {
107
- /* Actions */
108
- add_action(
109
- 'init',
110
- array(
111
- __CLASS__,
112
- 'load_plugin_lang'
113
- )
114
- );
115
- add_action(
116
- 'admin_menu',
117
- array(
118
- __CLASS__,
119
- 'add_sidebar_menu'
120
- )
121
- );
122
- add_action(
123
- 'admin_notices',
124
- array(
125
- __CLASS__,
126
- 'show_dashboard_notice'
127
- )
128
- );
129
- add_action(
130
- 'deactivate_' .self::$base,
131
- array(
132
- __CLASS__,
133
- 'clear_scheduled_hook'
134
- )
135
- );
136
- add_filter(
137
- 'plugin_row_meta',
138
- array(
139
- __CLASS__,
140
- 'init_row_meta'
141
- ),
142
- 10,
143
- 2
144
- );
145
- add_filter(
146
- 'plugin_action_links_' .self::$base,
147
- array(
148
- __CLASS__,
149
- 'init_action_links'
150
- )
151
- );
152
- }
153
- }
154
- }
155
-
156
-
157
- /**
158
- * Einbindung der Sprache
159
- *
160
- * @since 0.8
161
- * @change 0.8
162
- */
163
-
164
- public static function load_plugin_lang()
165
- {
166
- load_plugin_textdomain(
167
- 'antivirus',
168
- false,
169
- 'antivirus/lang'
170
- );
171
- }
172
-
173
-
174
- /**
175
- * Hinzufügen der Action-Links (Einstellungen links)
176
- *
177
- * @since 1.1
178
- * @change 1.3.4
179
- *
180
- * @param array $data Array mit Links
181
- * @return array $data Array mit erweitertem Link
182
- */
183
-
184
- public static function init_action_links($data)
185
- {
186
- /* Rechte? */
187
- if ( ! current_user_can('manage_options') ) {
188
- return $data;
189
- }
190
-
191
- return array_merge(
192
- $data,
193
- array(
194
- sprintf(
195
- '<a href="%s">%s</a>',
196
- add_query_arg(
197
- array(
198
- 'page' => 'antivirus'
199
- ),
200
- admin_url('options-general.php')
201
- ),
202
- __('Settings')
203
- )
204
- )
205
- );
206
- }
207
-
208
-
209
- /**
210
- * Links in der Plugin-Verwaltung
211
- *
212
- * @since 0.1
213
- * @change 1.3.4
214
- *
215
- * @param array $data Array mit Links
216
- * @param string $page Aktuelle Seite
217
- * @return array $data Array mit erweitertem Link
218
- */
219
-
220
- public static function init_row_meta($data, $page)
221
- {
222
- if ( $page != self::$base ) {
223
- return $data;
224
- }
225
-
226
- return array_merge(
227
- $data,
228
- array(
229
- '<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=LG5VC9KXMAYXJ" target="_blank">PayPal</a>'
230
- )
231
- );
232
- }
233
-
234
-
235
- /**
236
- * Aktion bei Aktivierung des Plugins
237
- *
238
- * @since 0.1
239
- * @change 1.3.4
240
- */
241
-
242
- public static function install()
243
- {
244
- /* Option anlegen */
245
- add_option(
246
- 'antivirus',
247
- array(),
248
- '',
249
- 'no'
250
- );
251
-
252
- /* Cron aktivieren */
253
- if ( self::_get_option('cronjob_enable') ) {
254
- self::_add_scheduled_hook();
255
- }
256
- }
257
-
258
-
259
- /**
260
- * Aktionen bei der Deaktivierung des Plugins
261
- *
262
- * @since 1.3.4
263
- * @change 1.3.4
264
- */
265
-
266
- public static function deactivation()
267
- {
268
- self::clear_scheduled_hook();
269
- }
270
-
271
-
272
- /**
273
- * Uninstallation des Plugins pro MU-Blog
274
- *
275
- * @since 1.1
276
- * @change 1.3.5
277
- */
278
-
279
- public static function uninstall()
280
- {
281
- delete_option('antivirus');
282
- }
283
-
284
-
285
- /**
286
- * Rückgabe eines Optionsfeldes
287
- *
288
- * @since 0.1
289
- * @change 1.3.4
290
- *
291
- * @param string $field Name einer Option
292
- * @return mixed Wert einer Option
293
- */
294
-
295
- private static function _get_option($field)
296
- {
297
- $options = wp_parse_args(
298
- get_option('antivirus'),
299
- array(
300
- 'cronjob_enable' => 0,
301
- 'cronjob_alert' => 0,
302
- 'safe_browsing' => 0,
303
- 'notify_email' => '',
304
- 'white_list' => ''
305
- )
306
- );
307
-
308
- return ( empty($options[$field]) ? '' : $options[$field] );
309
- }
310
-
311
-
312
- /**
313
- * Aktualisiert ein Optionsfeld
314
- *
315
- * @since 0.1
316
- * @change 1.3.4
317
- *
318
- * @param string $field Name des Feldes
319
- * @param mixed Wert des Feldes
320
- */
321
-
322
- private static function _update_option($field, $value)
323
- {
324
- self::_update_options(
325
- array(
326
- $field => $value
327
- )
328
- );
329
- }
330
-
331
-
332
- /**
333
- * Aktualisiert mehrere Optionsfelder
334
- *
335
- * @since 0.1
336
- * @change 1.3.4
337
- *
338
- * @param array $data Array mit Feldern
339
- */
340
-
341
- private static function _update_options($data)
342
- {
343
- update_option(
344
- 'antivirus',
345
- array_merge(
346
- (array)get_option('antivirus'),
347
- $data
348
- )
349
- );
350
- }
351
-
352
-
353
- /**
354
- * Initialisierung des Cronjobs
355
- *
356
- * @since 1.3.4
357
- * @change 1.3.4
358
- */
359
-
360
- private static function _add_scheduled_hook()
361
- {
362
- if ( ! wp_next_scheduled('antivirus_daily_cronjob') ) {
363
- wp_schedule_event(
364
- time(),
365
- 'daily',
366
- 'antivirus_daily_cronjob'
367
- );
368
- }
369
- }
370
-
371
-
372
- /**
373
- * Beendigung des Cronjobs
374
- *
375
- * @since 0.1
376
- * @change 0.8
377
- */
378
-
379
- public static function clear_scheduled_hook()
380
- {
381
- if ( wp_next_scheduled('antivirus_daily_cronjob') ) {
382
- wp_clear_scheduled_hook('antivirus_daily_cronjob');
383
- }
384
- }
385
-
386
-
387
- /**
388
- * Ausführung des Cronjobs
389
- *
390
- * @since 0.1
391
- * @change 1.3.4
392
- */
393
-
394
- public static function do_daily_cronjob()
395
- {
396
- /* Kein Cronjob? */
397
- if ( ! self::_get_option('cronjob_enable') ) {
398
- return;
399
- }
400
-
401
- /* Load translation */
402
- self::load_plugin_lang();
403
-
404
- /* Safe Browsing API */
405
- self::_check_safe_browsing();
406
-
407
- /* Theme & Permalinks */
408
- self::_check_blog_internals();
409
- }
410
-
411
-
412
- /**
413
- * Führt die Safe Browsing Prüfung aus
414
- *
415
- * @since 1.3.4
416
- * @change 1.3.7
417
- */
418
-
419
- private static function _check_safe_browsing()
420
- {
421
- /* Not enabled? */
422
- if ( ! self::_get_option('safe_browsing') ) {
423
- return;
424
- }
425
-
426
- /* Start request */
427
- $response = wp_remote_get(
428
- sprintf(
429
- 'https://sb-ssl.google.com/safebrowsing/api/lookup?client=wpantivirus&key=%s&appver=1.3.7&pver=3.1&url=%s',
430
- 'AIzaSyALNYwuy-Pidn7vx3-In-hU0zgMH5Wr42U',
431
- urlencode( get_bloginfo('url') )
432
- )
433
- );
434
-
435
- /* API Error? */
436
- if ( is_wp_error($response) ) {
437
- return;
438
- }
439
-
440
- /* All clear */
441
- if ( wp_remote_retrieve_response_code($response) === 204 ) {
442
- return;
443
- }
444
-
445
- /* Send notification */
446
- self::_send_warning_notification(
447
- esc_html__('Safe Browsing Alert', 'antivirus'),
448
- sprintf(
449
- "%s\r\nhttps://www.google.com/safebrowsing/diagnostic?site=%s&hl=%s",
450
- esc_html__('Please check the Google Safe Browsing diagnostic page:', 'antivirus'),
451
- urlencode( get_bloginfo('url') ),
452
- substr(get_locale(), 0, 2)
453
- )
454
- );
455
- }
456
-
457
-
458
- /**
459
- * Führt die Blog-interne Prüfung aus
460
- *
461
- * @since 1.3.4
462
- * @change 1.3.4
463
- */
464
-
465
- private static function _check_blog_internals()
466
- {
467
- /* Execute checks */
468
- if ( ! self::_check_theme_files() && ! self::_check_permalink_structure() ) {
469
- return;
470
- }
471
-
472
- /* Send notification */
473
- self::_send_warning_notification(
474
- esc_html__('Virus suspected', 'antivirus'),
475
- sprintf(
476
- "%s\r\n%s",
477
- esc_html__('The daily antivirus scan of your blog suggests alarm.', 'antivirus'),
478
- get_bloginfo('url')
479
- )
480
- );
481
-
482
- /* Store alert */
483
- self::_update_option(
484
- 'cronjob_alert',
485
- 1
486
- );
487
- }
488
-
489
-
490
- /**
491
- * Führt die Safe Browsing Prüfung aus
492
- *
493
- * @since 1.3.4
494
- * @change 1.3.6
495
- *
496
- * @param string $subject Betreff der E-Mail
497
- * @param string $body Inhalt der E-Mail
498
- */
499
-
500
- private static function _send_warning_notification($subject, $body)
501
- {
502
- /* Receiver email address */
503
- $email = self::_get_option('notify_email');
504
-
505
- /* Email address fallback */
506
- if ( ! is_email($email) ) {
507
- $email = get_bloginfo('admin_email');
508
- }
509
-
510
- /* Send it! */
511
- wp_mail(
512
- $email,
513
- sprintf(
514
- '[%s] %s',
515
- get_bloginfo('name'),
516
- $subject
517
- ),
518
- sprintf(
519
- "%s\r\n\r\n\r\n%s\r\n%s\r\n",
520
- $body,
521
- esc_html__('Notify message by AntiVirus for WordPress', 'antivirus'),
522
- esc_html__('http://wpantivirus.com', 'antivirus')
523
- )
524
- );
525
- }
526
-
527
-
528
- /**
529
- * Initialisierung der GUI
530
- *
531
- * @since 0.1
532
- * @change 1.3.5
533
- */
534
-
535
- public static function add_sidebar_menu()
536
- {
537
- /* Menü anlegen */
538
- $page = add_options_page(
539
- 'AntiVirus',
540
- 'AntiVirus',
541
- 'manage_options',
542
- 'antivirus',
543
- array(
544
- __CLASS__,
545
- 'show_admin_menu'
546
- )
547
- );
548
-
549
- add_action(
550
- 'admin_print_styles-' . $page,
551
- array(
552
- __CLASS__,
553
- 'add_enqueue_style'
554
- )
555
- );
556
- add_action(
557
- 'admin_print_scripts-' . $page,
558
- array(
559
- __CLASS__,
560
- 'add_enqueue_script'
561
- )
562
- );
563
- }
564
-
565
-
566
- /**
567
- * Initialisierung von JavaScript
568
- *
569
- * @since 0.8
570
- * @change 1.3.5
571
- */
572
-
573
- public static function add_enqueue_script()
574
- {
575
- /* Infos auslesen */
576
- $data = get_plugin_data(__FILE__);
577
-
578
- /* JS einbinden */
579
- wp_register_script(
580
- 'av_script',
581
- plugins_url('js/script.min.js', __FILE__),
582
- array('jquery'),
583
- $data['Version']
584
- );
585
-
586
- /* Script einbinden */
587
- wp_enqueue_script('av_script');
588
-
589
- /* Script lokalisieren */
590
- wp_localize_script(
591
- 'av_script',
592
- 'av_settings',
593
- array(
594
- 'nonce' => wp_create_nonce('av_ajax_nonce'),
595
- 'theme' => esc_js(urlencode(self::_get_theme_name())),
596
- 'msg_1' => esc_js(__('There is no virus', 'antivirus')),
597
- 'msg_2' => esc_js(__('View line', 'antivirus')),
598
- 'msg_3' => esc_js(__('Scan finished', 'antivirus'))
599
- )
600
- );
601
- }
602
-
603
-
604
- /**
605
- * Initialisierung von Stylesheets
606
- *
607
- * @since 0.8
608
- * @change 1.3.4
609
- */
610
-
611
- public static function add_enqueue_style()
612
- {
613
- /* Infos auslesen */
614
- $data = get_plugin_data(__FILE__);
615
-
616
- /* CSS registrieren */
617
- wp_register_style(
618
- 'av_css',
619
- plugins_url('css/style.min.css', __FILE__),
620
- array(),
621
- $data['Version']
622
- );
623
-
624
- /* CSS einbinden */
625
- wp_enqueue_style('av_css');
626
- }
627
-
628
-
629
- /**
630
- * Rückgabe des aktuellen Theme
631
- *
632
- * @since 0.1
633
- * @change 1.3.6
634
- *
635
- * @return array $themes Array mit Theme-Eigenschaften
636
- */
637
-
638
- private static function _get_current_theme()
639
- {
640
- /* Init */
641
- $theme = wp_get_theme();
642
- $name = $theme->get('Name');
643
- $slug = $theme->get_stylesheet();
644
- $files = $theme->get_files('php', 1);
645
-
646
- /* Leer? */
647
- if ( empty($name) OR empty($files) ) {
648
- return false;
649
- }
650
-
651
- /* Rückgabe */
652
- return array(
653
- 'Name' => $name,
654
- 'Slug' => $slug,
655
- 'Template Files' => $files
656
- );
657
- }
658
-
659
-
660
- /**
661
- * Rückgabe von Dateien des aktuellen Theme
662
- *
663
- * @since 0.1
664
- * @change 1.3.4
665
- *
666
- * @return array $files Array mit Dateien
667
- */
668
-
669
- private static function _get_theme_files()
670
- {
671
- /* Theme vorhanden? */
672
- if ( ! $theme = self::_get_current_theme() ) {
673
- return false;
674
- }
675
-
676
- /* Keine Files? */
677
- if ( empty($theme['Template Files']) ) {
678
- return false;
679
- }
680
-
681
- /* Zurückgeben */
682
- return array_unique(
683
- array_map(
684
- create_function(
685
- '$v',
686
- 'return str_replace(array(WP_CONTENT_DIR, "wp-content"), "", $v);'
687
- ),
688
- $theme['Template Files']
689
- )
690
- );
691
- }
692
-
693
-
694
- /**
695
- * Rückgabe des Namen des aktuellen Theme
696
- *
697
- * @since 0.1
698
- * @change 1.3.4
699
- *
700
- * @return string $theme Name des aktuellen Theme
701
- */
702
-
703
- private static function _get_theme_name()
704
- {
705
- if ( $theme = self::_get_current_theme() ) {
706
- if ( ! empty($theme['Slug']) ) {
707
- return $theme['Slug'];
708
- }
709
- if ( ! empty($theme['Name']) ) {
710
- return $theme['Name'];
711
- }
712
- }
713
-
714
- return false;
715
- }
716
-
717
-
718
- /**
719
- * Rückgabe der WhiteList
720
- *
721
- * @since 0.1
722
- * @change 1.3.4
723
- *
724
- * @return array return Array mit MD5-Werten
725
- */
726
-
727
- private static function _get_white_list()
728
- {
729
- return explode(
730
- ':',
731
- self::_get_option('white_list')
732
- );
733
- }
734
-
735
-
736
- /**
737
- * Ausführung von AJAX
738
- *
739
- * @since 0.1
740
- * @change 1.3.4
741
- */
742
-
743
- public static function get_ajax_response()
744
- {
745
- /* Referer prüfen */
746
- check_ajax_referer('av_ajax_nonce');
747
-
748
- /* Zusätzliche Prüfung */
749
- if ( empty($_POST['_action_request']) ) {
750
- exit();
751
- }
752
-
753
- /* Capability check */
754
- if ( ! current_user_can('manage_options') ) {
755
- return;
756
- }
757
-
758
- /* Init */
759
- $values = array();
760
- $output = '';
761
-
762
- /* Ausgabe starten */
763
- switch ($_POST['_action_request']) {
764
- case 'get_theme_files':
765
- self::_update_option(
766
- 'cronjob_alert',
767
- 0
768
- );
769
-
770
- $values = self::_get_theme_files();
771
- break;
772
-
773
- case 'check_theme_file':
774
- if ( ! empty($_POST['_theme_file']) && $lines = self::_check_theme_file($_POST['_theme_file']) ) {
775
- foreach( $lines as $num => $line ) {
776
- foreach( $line as $string ) {
777
- $values[] = $num;
778
- $values[] = htmlentities($string, ENT_QUOTES);
779
- $values[] = md5($num . $string);
780
- }
781
- }
782
- }
783
- break;
784
-
785
- case 'update_white_list':
786
- if ( ! empty($_POST['_file_md5']) && preg_match('/^[a-f0-9]{32}$/', $_POST['_file_md5']) ) {
787
- self::_update_option(
788
- 'white_list',
789
- implode(
790
- ':',
791
- array_unique(
792
- array_merge(
793
- self::_get_white_list(),
794
- array($_POST['_file_md5'])
795
- )
796
- )
797
- )
798
- );
799
-
800
- $values = array($_POST['_file_md5']);
801
- }
802
- break;
803
-
804
- default:
805
- break;
806
- }
807
-
808
- /* Ausgabe starten */
809
- if ( $values ) {
810
- wp_send_json(
811
- array(
812
- 'data' => array_values($values),
813
- 'nonce' => $_POST['_ajax_nonce']
814
- )
815
- );
816
- }
817
-
818
- /* Raus! */
819
- exit();
820
- }
821
-
822
-
823
- /**
824
- * Rückgabe des Dateiinhaltes
825
- *
826
- * @since 0.1
827
- * @change 1.3.4
828
- *
829
- * @param string $file Dateipfad
830
- * @return array Array mit Dateizeilen
831
- */
832
-
833
- private static function _get_file_content($file)
834
- {
835
- return file(WP_CONTENT_DIR . $file);
836
- }
837
-
838
-
839
- /**
840
- * Kürzung eines Strings
841
- *
842
- * @since 0.1
843
- * @change 1.3.4
844
- *
845
- * @param string $line Eigenetliche Zeile als String
846
- * @param string $tag Gesuchtes Tag
847
- * @param integer $max Anzahl der Zeichen rechts und links
848
- * @return string $output Gekürzter String
849
- */
850
-
851
- private static function _get_dotted_line($line, $tag, $max = 100)
852
- {
853
- /* Keine Werte? */
854
- if ( ! $line OR ! $tag ) {
855
- return false;
856
- }
857
-
858
- /* Differenz ermitteln */
859
- if ( strlen($tag) > $max ) {
860
- return $tag;
861
- }
862
-
863
- /* Differenz ermitteln */
864
- $left = round( ($max - strlen($tag)) / 2 );
865
-
866
- /* Wert konvertieren */
867
- $tag = preg_quote($tag);
868
-
869
- /* String kürzen */
870
- $output = preg_replace(
871
- '/(' .$tag. ')(.{' .$left. '}).{0,}$/',
872
- '$1$2 ...',
873
- $line
874
- );
875
- $output = preg_replace(
876
- '/^.{0,}(.{' .$left. ',})(' .$tag. ')/',
877
- '... $1$2',
878
- $output
879
- );
880
-
881
- return $output;
882
- }
883
-
884
-
885
- /**
886
- * Definition des Regexp
887
- *
888
- * @since 0.1
889
- * @change 1.3.4
890
- *
891
- * @return string return Regulärer Ausdruck
892
- */
893
-
894
- private static function _php_match_pattern()
895
- {
896
- return '/(assert|file_get_contents|curl_exec|popen|proc_open|unserialize|eval|base64_encode|base64_decode|create_function|exec|shell_exec|system|passthru|ob_get_contents|file|curl_init|readfile|fopen|fsockopen|pfsockopen|fclose|fread|file_put_contents)\s*?\(/';
897
- }
898
-
899
-
900
- /**
901
- * Prüfung einer Zeile
902
- *
903
- * @since 0.1
904
- * @change 1.3.8
905
- *
906
- * @param string $line Zeile zur Prüfung
907
- * @param integer $num Nummer zur Prüfung
908
- * @return string $line Zeile mit Resultaten
909
- */
910
-
911
- private static function _check_file_line($line = '', $num)
912
- {
913
- /* Wert trimmen */
914
- $line = trim((string)$line);
915
-
916
- /* Leere Werte? */
917
- if ( ! $line OR ! isset($num) ) {
918
- return false;
919
- }
920
-
921
- /* Werte initialisieren */
922
- $results = array();
923
- $output = array();
924
-
925
- /* Befehle suchen */
926
- preg_match_all(
927
- self::_php_match_pattern(),
928
- $line,
929
- $matches
930
- );
931
-
932
- /* Ergebnis speichern */
933
- if ( $matches[1] ) {
934
- $results = $matches[1];
935
- }
936
-
937
-
938
- /* Base64 suchen */
939
- preg_match_all(
940
- '/[\'\"\$\\ \/]*?([a-zA-Z0-9]{' .strlen(base64_encode('sergej + swetlana = love.')). ',})/', /* get length of my life ;) */
941
- $line,
942
- $matches
943
- );
944
-
945
- /* Ergebnis speichern */
946
- if ( $matches[1] ) {
947
- $results = array_merge($results, $matches[1]);
948
- }
949
-
950
-
951
- /* Frames suchen */
952
- preg_match_all(
953
- '/<\s*?(i?frame)/',
954
- $line,
955
- $matches
956
- );
957
-
958
- /* Ergebnis speichern */
959
- if ( $matches[1] ) {
960
- $results = array_merge($results, $matches[1]);
961
- }
962
-
963
-
964
- /* MailPoet Vulnerability */
965
- preg_match_all(
966
- '/explode\s?\(chr\s?\(\s?\(\d{3}\s?-\s?\d{3}\s?\)\s?\)\s?,/',
967
- $line,
968
- $matches
969
- );
970
-
971
- /* Ergebnis speichern */
972
- if ( $matches[0] ) {
973
- $results = array_merge($results, $matches[0]);
974
- }
975
-
976
-
977
- /* Option suchen */
978
- preg_match(
979
- '/get_option\s*\(\s*[\'"](.*?)[\'"]\s*\)/',
980
- $line,
981
- $matches
982
- );
983
-
984
- /* Option prüfen */
985
- if ( $matches && $matches[1] && self::_check_file_line(get_option($matches[1]), $num) ) {
986
- array_push($results, 'get_option');
987
- }
988
-
989
- /* Ergebnisse? */
990
- if ( $results ) {
991
- /* Keine Duplikate */
992
- $results = array_unique($results);
993
-
994
- /* White-Liste */
995
- $md5 = self::_get_white_list();
996
-
997
- /* Resultate loopen */
998
- foreach( $results as $tag ) {
999
- $string = str_replace(
1000
- $tag,
1001
- '@span@' .$tag. '@/span@',
1002
- self::_get_dotted_line($line, $tag)
1003
- );
1004
-
1005
- /* In der Whitelist? */
1006
- if ( ! in_array(md5($num . $string), $md5) ) {
1007
- $output[] = $string;
1008
- }
1009
- }
1010
-
1011
- return $output;
1012
- }
1013
-
1014
- return false;
1015
- }
1016
-
1017
-
1018
- /**
1019
- * Prüfung der Dateien des aktuellen Theme
1020
- *
1021
- * @since 0.1
1022
- * @change 1.3.4
1023
- *
1024
- * @return mixed $results Array mit Ergebnissen | FALSE im Fehlerfall
1025
- */
1026
-
1027
- private static function _check_theme_files()
1028
- {
1029
- /* Files vorhanden? */
1030
- if ( ! $files = self::_get_theme_files() ) {
1031
- return false;
1032
- }
1033
-
1034
- /* Init */
1035
- $results = array();
1036
-
1037
- /* Files loopen */
1038
- foreach( $files as $file ) {
1039
- if ( $result = self::_check_theme_file($file) ) {
1040
- $results[$file] = $result;
1041
- }
1042
- }
1043
-
1044
- /* Werte vorhanden? */
1045
- if ( ! empty($results) ) {
1046
- return $results;
1047
- }
1048
-
1049
- return false;
1050
- }
1051
-
1052
-
1053
- /**
1054
- * Prüfung einer Datei
1055
- *
1056
- * @since 0.1
1057
- * @change 1.3.6
1058
- *
1059
- * @param string $file Datei zur Prüfung
1060
- * @return mixed $results Array mit Ergebnissen | FALSE im Fehlerfall
1061
- */
1062
-
1063
- private static function _check_theme_file($file)
1064
- {
1065
- /* Simple file path check */
1066
- if ( filter_var($file, FILTER_SANITIZE_URL) !== $file ) {
1067
- return false;
1068
- }
1069
-
1070
- /* Sanitize file string */
1071
- if ( validate_file($file) !== 0 ) {
1072
- return false;
1073
- }
1074
-
1075
- /* Kein File? */
1076
- if ( ! $file ) {
1077
- return false;
1078
- }
1079
-
1080
- /* Inhalt auslesen */
1081
- if ( ! $content = self::_get_file_content($file) ) {
1082
- return false;
1083
- }
1084
-
1085
- /* Init */
1086
- $results = array();
1087
-
1088
- /* Zeilen loopen */
1089
- foreach( $content as $num => $line ) {
1090
- if ( $result = self::_check_file_line($line, $num) ) {
1091
- $results[$num] = $result;
1092
- }
1093
- }
1094
-
1095
- /* Werte vorhanden? */
1096
- if ( ! empty($results) ) {
1097
- return $results;
1098
- }
1099
-
1100
- return false;
1101
- }
1102
-
1103
-
1104
- /**
1105
- * Prüfung des Permalinks
1106
- *
1107
- * @since 0.1
1108
- * @change 1.3.4
1109
- *
1110
- * @return mixed $matches FALSE im Fehlerfall
1111
- */
1112
-
1113
- private static function _check_permalink_structure()
1114
- {
1115
- if ( $structure = get_option('permalink_structure') ) {
1116
- /* Befehle suchen */
1117
- preg_match_all(
1118
- self::_php_match_pattern(),
1119
- $structure,
1120
- $matches
1121
- );
1122
-
1123
- /* Ergebnis speichern */
1124
- if ( $matches[1] ) {
1125
- return $matches[1];
1126
- }
1127
- }
1128
-
1129
- return false;
1130
- }
1131
-
1132
-
1133
- /**
1134
- * Anzeige des Dashboard-Hinweises
1135
- *
1136
- * @since 0.1
1137
- * @change 1.3.5
1138
- */
1139
-
1140
- public static function show_dashboard_notice() {
1141
- /* Kein Alert? */
1142
- if ( ! self::_get_option('cronjob_alert') ) {
1143
- return;
1144
- }
1145
-
1146
- /* Warnung */
1147
- echo sprintf(
1148
- '<div class="error"><p><strong>%1$s:</strong> %2$s <a href="%3$s">%4$s &rarr;</a></p></div>',
1149
- esc_html__('Virus suspected', 'antivirus'),
1150
- esc_html__('The daily antivirus scan of your blog suggests alarm.', 'antivirus'),
1151
- add_query_arg(
1152
- array(
1153
- 'page' => 'antivirus'
1154
- ),
1155
- admin_url('options-general.php')
1156
- ),
1157
- esc_html__('Manual malware scan', 'antivirus')
1158
- );
1159
- }
1160
-
1161
-
1162
- /**
1163
- * Anzeige der GUI
1164
- *
1165
- * @since 0.1
1166
- * @change 1.3.6
1167
- */
1168
-
1169
- public static function show_admin_menu() {
1170
- /* Updates speichern */
1171
- if ( ! empty($_POST) ) {
1172
- /* Referer prüfen */
1173
- check_admin_referer('antivirus');
1174
-
1175
- /* Werte zuweisen */
1176
- $options = array(
1177
- 'cronjob_enable' => (int)(!empty($_POST['av_cronjob_enable'])),
1178
- 'notify_email' => sanitize_email(@$_POST['av_notify_email']),
1179
- 'safe_browsing' => (int)(!empty($_POST['av_safe_browsing']))
1180
- );
1181
-
1182
- /* Kein Cronjob? */
1183
- if ( empty($options['cronjob_enable']) ) {
1184
- $options['notify_email'] = '';
1185
- $options['safe_browsing'] = 0;
1186
- }
1187
-
1188
- /* Cron stoppen? */
1189
- if ( $options['cronjob_enable'] && ! self::_get_option('cronjob_enable') ) {
1190
- self::_add_scheduled_hook();
1191
- } else if ( ! $options['cronjob_enable'] && self::_get_option('cronjob_enable') ) {
1192
- self::clear_scheduled_hook();
1193
- }
1194
-
1195
- /* Optionen speichern */
1196
- self::_update_options($options); ?>
1197
-
1198
- <div id="message" class="updated fade">
1199
- <p>
1200
- <strong>
1201
- <?php _e('Settings saved.') ?>
1202
- </strong>
1203
- </p>
1204
- </div>
1205
- <?php } ?>
1206
-
1207
- <div class="wrap" id="av_main">
1208
- <h2>
1209
- AntiVirus
1210
- </h2>
1211
-
1212
- <table class="form-table">
1213
- <tr valign="top">
1214
- <th scope="row">
1215
- <?php esc_html_e('Manual malware scan', 'antivirus') ?>
1216
- </th>
1217
- <td>
1218
- <div class="inside" id="av_manual_scan">
1219
- <p>
1220
- <a href="#" class="button button-primary">
1221
- <?php esc_html_e('Scan the theme templates now', 'antivirus') ?>
1222
- </a>
1223
- <span class="alert"></span>
1224
- </p>
1225
- <div class="output"></div>
1226
- </div>
1227
- </td>
1228
- </tr>
1229
- </table>
1230
-
1231
-
1232
- <form method="post" action="">
1233
- <?php wp_nonce_field('antivirus') ?>
1234
-
1235
- <table class="form-table">
1236
- <tr valign="top">
1237
- <th scope="row">
1238
- <?php esc_html_e('Daily malware scan', 'antivirus') ?>
1239
- </th>
1240
- <td>
1241
- <fieldset>
1242
- <label for="av_cronjob_enable">
1243
- <input type="checkbox" name="av_cronjob_enable" id="av_cronjob_enable" value="1" <?php checked(self::_get_option('cronjob_enable'), 1) ?> />
1244
- <?php esc_html_e('Check the theme templates for malware', 'antivirus') ?>
1245
- </label>
1246
-
1247
- <p class="description">
1248
- <?php if ( $timestamp = wp_next_scheduled('antivirus_daily_cronjob') ) {
1249
- echo sprintf(
1250
- '%s: %s',
1251
- esc_html__('Next Run', 'antivirus'),
1252
- date_i18n('d.m.Y H:i:s', $timestamp + get_option('gmt_offset') * 3600)
1253
- );
1254
- } ?>
1255
- </p>
1256
-
1257
-
1258
- <br />
1259
-
1260
-
1261
- <label for="av_safe_browsing">
1262
- <input type="checkbox" name="av_safe_browsing" id="av_safe_browsing" value="1" <?php checked(self::_get_option('safe_browsing'), 1) ?> />
1263
- <?php esc_html_e('Malware detection by Google Safe Browsing', 'antivirus') ?>
1264
- </label>
1265
-
1266
- <p class="description">
1267
- <?php esc_html_e('Diagnosis and notification in suspicion case', 'antivirus') ?>
1268
- </p>
1269
-
1270
-
1271
- <br />
1272
-
1273
-
1274
- <label for="av_notify_email">
1275
- <input type="text" name="av_notify_email" id="av_notify_email" value="<?php esc_attr_e(self::_get_option('notify_email')) ?>" class="regular-text" placeholder="<?php esc_attr_e('Email address for notifications', 'antivirus') ?>" />
1276
- </label>
1277
-
1278
- <p class="description">
1279
- <?php esc_html_e('If the field is empty, the blog admin will be notified', 'antivirus') ?>
1280
- </p>
1281
- </fieldset>
1282
- </td>
1283
- </tr>
1284
-
1285
- <tr valign="top">
1286
- <th scope="row">
1287
- <input type="submit" class="button button-primary" value="<?php _e('Save Changes') ?>" />
1288
- </th>
1289
- <td>
1290
- <?php if ( substr( get_locale(), 0, 3 ) === 'de_' ) { ?><a href="https://github.com/pluginkollektiv/antivirus/wiki" target="_blank">Handbuch</a> &bull; <?php } ?><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=LG5VC9KXMAYXJ" target="_blank">PayPal</a>
1291
- </td>
1292
- </tr>
1293
- </table>
1294
- </form>
1295
- </div>
1296
- <?php }
1297
- }
1298
-
1299
-
1300
- /* Fire */
1301
- add_action(
1302
- 'plugins_loaded',
1303
- array(
1304
- 'AntiVirus',
1305
- 'instance'
1306
- ),
1307
- 99
1308
- );
1309
-
1310
-
1311
- /* Hooks */
1312
- register_activation_hook(
1313
- __FILE__,
1314
- array(
1315
- 'AntiVirus',
1316
- 'install'
1317
- )
1318
- );
1319
- register_deactivation_hook(
1320
- __FILE__,
1321
- array(
1322
- 'AntiVirus',
1323
- 'deactivation'
1324
- )
1325
- );
1326
- register_uninstall_hook(
1327
- __FILE__,
1328
- array(
1329
- 'AntiVirus',
1330
- 'uninstall'
1331
- )
1332
- );
1
+ <?php
2
+ /**
3
+ * Plugin Name: AntiVirus
4
+ * Description: Security plugin to protect your blog or website against exploits and spam injections.
5
+ * Author: pluginkollektiv
6
+ * Author URI: https://pluginkollektiv.org
7
+ * Plugin URI: https://wordpress.org/plugins/antivirus/
8
+ * Text Domain: antivirus
9
+ * License: GPLv2 or later
10
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
+ * Version: 1.3.10
12
+ *
13
+ * @package AntiVirus
14
+ */
15
+
16
+ /*
17
+ Copyright (C) 2009-2015 Sergej Müller
18
+
19
+ This program is free software; you can redistribute it and/or modify
20
+ it under the terms of the GNU General Public License as published by
21
+ the Free Software Foundation; either version 2 of the License, or
22
+ (at your option) any later version.
23
+
24
+ This program is distributed in the hope that it will be useful,
25
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
26
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
+ GNU General Public License for more details.
28
+
29
+ You should have received a copy of the GNU General Public License along
30
+ with this program; if not, write to the Free Software Foundation, Inc.,
31
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32
+ */
33
+
34
+ // Make sure we don't expose any info if called directly.
35
+ if ( ! class_exists( 'WP' ) ) {
36
+ die();
37
+ }
38
+
39
+ /**
40
+ * Main plugin class.
41
+ */
42
+ class AntiVirus {
43
+ /**
44
+ * The basename of a plugin.
45
+ *
46
+ * @var string
47
+ */
48
+ private static $base;
49
+
50
+ /**
51
+ * Pseudo constructor.
52
+ */
53
+ public static function instance() {
54
+ new self();
55
+ }
56
+
57
+ /**
58
+ * Constructor.
59
+ *
60
+ * Should not be called directly,
61
+ *
62
+ * @see AntiVirus::instance()
63
+ */
64
+ public function __construct() {
65
+ // Don't run during autosave or XML-RPC request.
66
+ if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ) {
67
+ return;
68
+ }
69
+
70
+ // Save the plugin basename.
71
+ self::$base = plugin_basename( __FILE__ );
72
+
73
+ // Run the daily cronjob.
74
+ if ( defined( 'DOING_CRON' ) ) {
75
+ add_action( 'antivirus_daily_cronjob', array( __CLASS__, 'do_daily_cronjob' ) );
76
+ }
77
+
78
+ if ( is_admin() ) {
79
+ /* AJAX */
80
+ if ( defined( 'DOING_AJAX' ) ) {
81
+ add_action( 'wp_ajax_get_ajax_response', array( __CLASS__, 'get_ajax_response' ) );
82
+ } else {
83
+ /* Actions */
84
+ add_action( 'admin_menu', array( __CLASS__, 'add_sidebar_menu' ) );
85
+ add_action( 'admin_notices', array( __CLASS__, 'show_dashboard_notice' ) );
86
+ add_action( 'deactivate_' . self::$base, array( __CLASS__, 'clear_scheduled_hook' ) );
87
+ add_action( 'plugin_row_meta', array( __CLASS__, 'init_row_meta' ), 10, 2 );
88
+ add_action( 'plugin_action_links_' . self::$base, array( __CLASS__, 'init_action_links' ) );
89
+ }
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Adds a link to the plugin settings in the plugin list table.
95
+ *
96
+ * @param array $data Plugin action links.
97
+ * @return array The modified action links array.
98
+ */
99
+ public static function init_action_links( $data ) {
100
+ // Only add link if user has permissions to view them.
101
+ if ( ! current_user_can( 'manage_options' ) ) {
102
+ return $data;
103
+ }
104
+
105
+ return array_merge(
106
+ $data,
107
+ array(
108
+ sprintf(
109
+ '<a href="%s">%s</a>',
110
+ add_query_arg(
111
+ array(
112
+ 'page' => 'antivirus',
113
+ ),
114
+ admin_url( 'options-general.php' )
115
+ ),
116
+ __( 'Settings', 'antivirus' )
117
+ ),
118
+ )
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Adds a donation link to the second row in the plugin list table.
124
+ *
125
+ * @param array $data Plugin links array.
126
+ * @param string $page The current row identifier.
127
+ * @return array The modified links array.
128
+ */
129
+ public static function init_row_meta( $data, $page ) {
130
+ if ( $page !== self::$base ) {
131
+ return $data;
132
+ }
133
+
134
+ return array_merge(
135
+ $data,
136
+ array(
137
+ '<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=TD4AMD2D8EMZW" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Donate', 'antivirus' ) . '</a>',
138
+ '<a href="https://wordpress.org/support/plugin/antivirus" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Support', 'antivirus' ) . '</a>',
139
+ )
140
+ );
141
+ }
142
+
143
+ /**
144
+ * Plugin activation hook.
145
+ */
146
+ public static function activation() {
147
+ // Add default option.
148
+ add_option(
149
+ 'antivirus',
150
+ array(),
151
+ '',
152
+ 'no'
153
+ );
154
+
155
+ // Add cron schedule.
156
+ if ( self::_get_option( 'cronjob_enable' ) ) {
157
+ self::_add_scheduled_hook();
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Plugin deactivation hook.
163
+ */
164
+ public static function deactivation() {
165
+ self::clear_scheduled_hook();
166
+ }
167
+
168
+ /**
169
+ * Plugin uninstall hook.
170
+ */
171
+ public static function uninstall() {
172
+ delete_option( 'antivirus' );
173
+ }
174
+
175
+ /**
176
+ * Get a plugin option value.
177
+ *
178
+ * @param string $field Option name.
179
+ * @return string The option value.
180
+ */
181
+ private static function _get_option( $field ) {
182
+ $options = wp_parse_args(
183
+ get_option( 'antivirus' ),
184
+ array(
185
+ 'cronjob_enable' => 0,
186
+ 'cronjob_alert' => 0,
187
+ 'safe_browsing' => 0,
188
+ 'notify_email' => '',
189
+ 'white_list' => '',
190
+ )
191
+ );
192
+
193
+ return ( empty( $options[ $field ] ) ? '' : $options[ $field ] );
194
+ }
195
+
196
+ /**
197
+ * Update an option in the database.
198
+ *
199
+ * @param string $field The option name.
200
+ * @param string|int $value The option value.
201
+ */
202
+ private static function _update_option( $field, $value ) {
203
+ self::_update_options(
204
+ array(
205
+ $field => $value,
206
+ )
207
+ );
208
+ }
209
+
210
+ /**
211
+ * Update multiple options in the database.
212
+ *
213
+ * @param array $data An associative array of option fields and values.
214
+ */
215
+ private static function _update_options( $data ) {
216
+ update_option(
217
+ 'antivirus',
218
+ array_merge(
219
+ (array) get_option( 'antivirus' ),
220
+ $data
221
+ )
222
+ );
223
+ }
224
+
225
+ /**
226
+ * Initialize the cronjob.
227
+ *
228
+ * Schedules the AntiVirus cronjob to run daily.
229
+ */
230
+ private static function _add_scheduled_hook() {
231
+ if ( ! wp_next_scheduled( 'antivirus_daily_cronjob' ) ) {
232
+ wp_schedule_event(
233
+ time(),
234
+ 'daily',
235
+ 'antivirus_daily_cronjob'
236
+ );
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Cancel the daily cronjob.
242
+ */
243
+ public static function clear_scheduled_hook() {
244
+ if ( wp_next_scheduled( 'antivirus_daily_cronjob' ) ) {
245
+ wp_clear_scheduled_hook( 'antivirus_daily_cronjob' );
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Cronjob callback.
251
+ */
252
+ public static function do_daily_cronjob() {
253
+ // Check if cronjob is enabled in the plugin.
254
+ if ( ! self::_get_option( 'cronjob_enable' ) ) {
255
+ return;
256
+ }
257
+
258
+ // Check the Safe Browsing API.
259
+ self::_check_safe_browsing();
260
+
261
+ // Check the theme and permalinks.
262
+ self::_check_blog_internals();
263
+ }
264
+
265
+ /**
266
+ * Pings the Safe Browsing API to see if the website is infected.
267
+ */
268
+ private static function _check_safe_browsing() {
269
+ // Check if option is enabled in the plugin.
270
+ if ( ! self::_get_option( 'safe_browsing' ) ) {
271
+ return;
272
+ }
273
+
274
+ // Request the API.
275
+ $response = wp_remote_post(
276
+ sprintf(
277
+ 'https://safebrowsing.googleapis.com/v4/threatMatches:find?key=%s',
278
+ 'AIzaSyCGHXUd7vQAySRLNiC5y1M_wzR2W0kCVKI'
279
+ ),
280
+ array(
281
+ 'headers' => array(
282
+ 'Content-Type' => 'application/json',
283
+ ),
284
+ 'body' => json_encode(
285
+ array(
286
+ 'client' => array(
287
+ 'clientId' => 'wpantivirus',
288
+ 'clientVersion' => '1.3.10'
289
+ ),
290
+ 'threatInfo' => array(
291
+ 'threatTypes' => array(
292
+ 'THREAT_TYPE_UNSPECIFIED',
293
+ 'MALWARE',
294
+ 'SOCIAL_ENGINEERING',
295
+ 'UNWANTED_SOFTWARE',
296
+ 'POTENTIALLY_HARMFUL_APPLICATION'
297
+ ),
298
+ 'platformTypes' => array( 'ANY_PLATFORM' ),
299
+ 'threatEntryTypes' => array( 'URL' ),
300
+ 'threatEntries' => array(
301
+ array( 'url' => urlencode( get_bloginfo( 'url' ) ) ),
302
+ )
303
+ )
304
+ )
305
+ )
306
+ )
307
+ );
308
+
309
+ // API error?
310
+ if ( is_wp_error( $response ) ) {
311
+ return;
312
+ }
313
+
314
+ // Get the JSON response of the API request.
315
+ $response_json = json_decode(wp_remote_retrieve_body( $response ), true);
316
+
317
+ // All clear, nothing bad detected.
318
+ if ( wp_remote_retrieve_response_code( $response ) === 200 && empty( $response_json ) ) {
319
+ return;
320
+ }
321
+
322
+ // Send notification.
323
+ self::_send_warning_notification(
324
+ esc_html__( 'Safe Browsing Alert', 'antivirus' ),
325
+ sprintf(
326
+ "%s\r\nhttps://transparencyreport.google.com/safe-browsing/search?url=%s&hl=%s",
327
+ esc_html__( 'Please check the Google Safe Browsing diagnostic page:', 'antivirus' ),
328
+ urlencode( get_bloginfo( 'url' ) ),
329
+ substr( get_locale(), 0, 2 )
330
+ )
331
+ );
332
+ }
333
+
334
+ /**
335
+ * Check blog internals like theme files and the permalink structure.
336
+ */
337
+ private static function _check_blog_internals() {
338
+ // Execute checks.
339
+ if ( ! self::_check_theme_files() && ! self::_check_permalink_structure() ) {
340
+ return;
341
+ }
342
+
343
+ // Send notification.
344
+ self::_send_warning_notification(
345
+ esc_html__( 'Virus suspected', 'antivirus' ),
346
+ sprintf(
347
+ "%s\r\n%s",
348
+ esc_html__( 'The daily antivirus scan of your blog suggests alarm.', 'antivirus' ),
349
+ get_bloginfo( 'url' )
350
+ )
351
+ );
352
+
353
+ // Store alert in database.
354
+ self::_update_option(
355
+ 'cronjob_alert',
356
+ 1
357
+ );
358
+ }
359
+
360
+ /**
361
+ * Send a warning via email that something was detected.
362
+ *
363
+ * @param string $subject Subject of the notification email.
364
+ * @param string $body Email body.
365
+ */
366
+ private static function _send_warning_notification( $subject, $body ) {
367
+ // Get recipient email address.
368
+ $email = self::_get_option( 'notify_email' );
369
+
370
+ // Get admin email address if nothing is stored.
371
+ if ( ! is_email( $email ) ) {
372
+ $email = get_bloginfo( 'admin_email' );
373
+ }
374
+
375
+ // Send email.
376
+ wp_mail(
377
+ $email,
378
+ sprintf(
379
+ '[%s] %s',
380
+ get_bloginfo( 'name' ),
381
+ $subject
382
+ ),
383
+ sprintf(
384
+ "%s\r\n\r\n\r\n%s\r\n%s\r\n",
385
+ $body,
386
+ esc_html__( 'Notify message by AntiVirus for WordPress', 'antivirus' ),
387
+ esc_html__( 'http://wpantivirus.com', 'antivirus' )
388
+ )
389
+ );
390
+ }
391
+
392
+ /**
393
+ * Add sub menu page to the options main menu.
394
+ */
395
+ public static function add_sidebar_menu() {
396
+ $page = add_options_page(
397
+ __( 'AntiVirus', 'antivirus' ),
398
+ __( 'AntiVirus', 'antivirus' ),
399
+ 'manage_options',
400
+ 'antivirus',
401
+ array(
402
+ __CLASS__,
403
+ 'show_admin_menu',
404
+ )
405
+ );
406
+
407
+ add_action( 'admin_print_styles-' . $page, array( __CLASS__, 'add_enqueue_style' ) );
408
+ add_action( 'admin_print_scripts-' . $page, array( __CLASS__, 'add_enqueue_script' ) );
409
+ }
410
+
411
+ /**
412
+ * Enqueue our JavaScript.
413
+ */
414
+ public static function add_enqueue_script() {
415
+ // Get plugin data.
416
+ $data = get_plugin_data( __FILE__ );
417
+
418
+ // Enqueue the JavaScript.
419
+ wp_enqueue_script(
420
+ 'av_script',
421
+ plugins_url( 'js/script.min.js', __FILE__ ),
422
+ array( 'jquery' ),
423
+ $data['Version']
424
+ );
425
+
426
+ // Localize script data.
427
+ wp_localize_script(
428
+ 'av_script',
429
+ 'av_settings',
430
+ array(
431
+ 'nonce' => wp_create_nonce( 'av_ajax_nonce' ),
432
+ 'theme' => esc_js( urlencode( self::_get_theme_name() ) ),
433
+ 'msg_1' => esc_js( __( 'This is not a virus', 'antivirus' ) ),
434
+ 'msg_2' => esc_js( __( 'View line', 'antivirus' ) ),
435
+ 'msg_3' => esc_js( __( 'Scan finished', 'antivirus' ) ),
436
+ )
437
+ );
438
+ }
439
+
440
+ /**
441
+ * Enqueue our stylesheet.
442
+ */
443
+ public static function add_enqueue_style() {
444
+ // Get plugin data.
445
+ $data = get_plugin_data( __FILE__ );
446
+
447
+ // Enqueue the stylesheet.
448
+ wp_enqueue_style(
449
+ 'av_css',
450
+ plugins_url( 'css/style.min.css', __FILE__ ),
451
+ array(),
452
+ $data['Version']
453
+ );
454
+ }
455
+
456
+ /**
457
+ * Get the currently activated theme.
458
+ *
459
+ * @return array|false An array holding the theme data or false on failure.
460
+ */
461
+ private static function _get_current_theme() {
462
+ $theme = wp_get_theme();
463
+ $name = $theme->get( 'Name' );
464
+ $slug = $theme->get_stylesheet();
465
+ $files = $theme->get_files( 'php', 1 );
466
+
467
+ // Check if empty.
468
+ if ( empty( $name ) || empty( $files ) ) {
469
+ return false;
470
+ }
471
+
472
+ return array(
473
+ 'Name' => $name,
474
+ 'Slug' => $slug,
475
+ 'Template Files' => $files,
476
+ );
477
+ }
478
+
479
+ /**
480
+ * Get all the files belonging to the current theme.
481
+ *
482
+ * @return array|false Theme files or false on failure.
483
+ */
484
+ private static function _get_theme_files() {
485
+ // Check if the theme exists.
486
+ if ( ! $theme = self::_get_current_theme() ) {
487
+ return false;
488
+ }
489
+
490
+ // Check its files.
491
+ if ( empty( $theme['Template Files'] ) ) {
492
+ return false;
493
+ }
494
+
495
+ // Returns the files, stripping out the content dir from the paths.
496
+ return array_unique(
497
+ array_map(
498
+ array( 'AntiVirus', '_strip_content_dir' ),
499
+ $theme['Template Files']
500
+ )
501
+ );
502
+ }
503
+
504
+ /**
505
+ * Strip out the content dir from a path.
506
+ *
507
+ * @param string $string
508
+ *
509
+ * @return string
510
+ */
511
+ private static function _strip_content_dir( $string ) {
512
+ return str_replace( array( WP_CONTENT_DIR, "wp-content" ), "", $string );
513
+ }
514
+
515
+ /**
516
+ * Get the name of the currently activated theme.
517
+ *
518
+ * @return string|false The theme name or false on failure.
519
+ */
520
+ private static function _get_theme_name() {
521
+ if ( $theme = self::_get_current_theme() ) {
522
+ if ( ! empty( $theme['Slug'] ) ) {
523
+ return $theme['Slug'];
524
+ }
525
+ if ( ! empty( $theme['Name'] ) ) {
526
+ return $theme['Name'];
527
+ }
528
+ }
529
+
530
+ return false;
531
+ }
532
+
533
+ /**
534
+ * Get the whitelist.
535
+ *
536
+ * @return array MD5 hashes of whitelisted files.
537
+ */
538
+ private static function _get_white_list() {
539
+ return explode(
540
+ ':',
541
+ self::_get_option( 'white_list' )
542
+ );
543
+ }
544
+
545
+ /**
546
+ * Ajax response handler.
547
+ */
548
+ public static function get_ajax_response() {
549
+ // Check referer.
550
+ check_ajax_referer( 'av_ajax_nonce' );
551
+
552
+ // Check if there really is some data.
553
+ if ( empty( $_POST['_action_request'] ) ) {
554
+ exit();
555
+ }
556
+
557
+ // Check user permissions.
558
+ if ( ! current_user_can( 'manage_options' ) ) {
559
+ return;
560
+ }
561
+
562
+ $values = array();
563
+
564
+ // Get value based on request.
565
+ switch ( $_POST['_action_request'] ) {
566
+ case 'get_theme_files':
567
+ self::_update_option(
568
+ 'cronjob_alert',
569
+ 0
570
+ );
571
+
572
+ $values = self::_get_theme_files();
573
+ break;
574
+
575
+ case 'check_theme_file':
576
+ if ( ! empty( $_POST['_theme_file'] ) && $lines = self::_check_theme_file( $_POST['_theme_file'] ) ) {
577
+ foreach ( $lines as $num => $line ) {
578
+ foreach ( $line as $string ) {
579
+ $values[] = $num;
580
+ $values[] = htmlentities( $string, ENT_QUOTES );
581
+ $values[] = md5( $num . $string );
582
+ }
583
+ }
584
+ }
585
+ break;
586
+
587
+ case 'update_white_list':
588
+ if ( ! empty( $_POST['_file_md5'] ) && preg_match( '/^[a-f0-9]{32}$/', $_POST['_file_md5'] ) ) {
589
+ self::_update_option(
590
+ 'white_list',
591
+ implode(
592
+ ':',
593
+ array_unique(
594
+ array_merge(
595
+ self::_get_white_list(),
596
+ array( $_POST['_file_md5'] )
597
+ )
598
+ )
599
+ )
600
+ );
601
+
602
+ $values = array( $_POST['_file_md5'] );
603
+ }
604
+ break;
605
+
606
+ default:
607
+ break;
608
+ }
609
+
610
+ // Send response.
611
+ if ( $values ) {
612
+ wp_send_json(
613
+ array(
614
+ 'data' => array_values( $values ),
615
+ 'nonce' => $_POST['_ajax_nonce'],
616
+ )
617
+ );
618
+ }
619
+
620
+ exit();
621
+ }
622
+
623
+ /**
624
+ * Get file contents
625
+ *
626
+ * @param string $file File path.
627
+ * @return array An array containing all the lines of the file.
628
+ */
629
+ private static function _get_file_content( $file ) {
630
+ return file( WP_CONTENT_DIR . $file );
631
+ }
632
+
633
+ /**
634
+ * Shorten a string, append ellipsis.
635
+ *
636
+ * @param string $line The line.
637
+ * @param string $tag The tag we're looking for.
638
+ * @param int $max Maximum number of chars on each side.
639
+ * @return string|false The shortened string or false on failure.
640
+ */
641
+ private static function _get_dotted_line( $line, $tag, $max = 100 ) {
642
+ // No values?
643
+ if ( ! $line || ! $tag ) {
644
+ return false;
645
+ }
646
+
647
+ // Return tag if it's higher than the maximum.
648
+ if ( strlen( $tag ) > $max ) {
649
+ return $tag;
650
+ }
651
+
652
+ // Get difference between the tag and the maximum.
653
+ $left = round( ( $max - strlen( $tag ) ) / 2 );
654
+
655
+ // Quote regular expression characters.
656
+ $tag = preg_quote( $tag );
657
+
658
+ // Shorten string on the right side.
659
+ $output = preg_replace(
660
+ '/(' . $tag . ')(.{' . $left . '}).{0,}$/',
661
+ '$1$2 ...',
662
+ $line
663
+ );
664
+
665
+ // Shorten string on the left side.
666
+ $output = preg_replace(
667
+ '/^.{0,}(.{' . $left . ',})(' . $tag . ')/',
668
+ '... $1$2',
669
+ $output
670
+ );
671
+
672
+ return $output;
673
+ }
674
+
675
+ /**
676
+ * Get the regular expression for all disallowed words/functions.
677
+ *
678
+ * @return string Regular expression.
679
+ */
680
+ private static function _php_match_pattern() {
681
+ return '/\b(assert|file_get_contents|curl_exec|popen|proc_open|unserialize|eval|base64_encode|base64_decode|create_function|exec|shell_exec|system|passthru|ob_get_contents|file|curl_init|readfile|fopen|fsockopen|pfsockopen|fclose|fread|file_put_contents)\b\s*?\(/';
682
+ }
683
+
684
+ /**
685
+ * Check a specific line number.
686
+ *
687
+ * @param string $line The line to check.
688
+ * @param int $num Line number.
689
+ * @return array|bool An array of matched lines or false on failure.
690
+ */
691
+ private static function _check_file_line( $line = '', $num ) {
692
+ // Trim value.
693
+ $line = trim( (string) $line );
694
+
695
+ // Make sure the values aren't empty.
696
+ if ( ! $line || ! isset( $num ) ) {
697
+ return false;
698
+ }
699
+
700
+ $results = array();
701
+ $output = array();
702
+
703
+ // Check if the regex matches.
704
+ preg_match_all(
705
+ self::_php_match_pattern(),
706
+ $line,
707
+ $matches
708
+ );
709
+
710
+ // Save matches.
711
+ if ( $matches[1] ) {
712
+ $results = $matches[1];
713
+ }
714
+
715
+ // Search for base64 encoded strings.
716
+ preg_match_all(
717
+ '/[\'\"\$\\ \/]*?([a-zA-Z0-9]{' . strlen( base64_encode( 'sergej + swetlana = love.' ) ) . ',})/', /* get length of my life ;) */
718
+ $line,
719
+ $matches
720
+ );
721
+
722
+ // Save matches.
723
+ if ( $matches[1] ) {
724
+ $results = array_merge( $results, $matches[1] );
725
+ }
726
+
727
+ // Look for frames.
728
+ preg_match_all(
729
+ '/<\s*?(i?frame)/',
730
+ $line,
731
+ $matches
732
+ );
733
+
734
+ // Save matches.
735
+ if ( $matches[1] ) {
736
+ $results = array_merge( $results, $matches[1] );
737
+ }
738
+
739
+ // Look for the MailPoet vulnerability.
740
+ preg_match_all(
741
+ '/explode\s?\(chr\s?\(\s?\(\d{3}\s?-\s?\d{3}\s?\)\s?\)\s?,/',
742
+ $line,
743
+ $matches
744
+ );
745
+
746
+ // Save matches.
747
+ if ( $matches[0] ) {
748
+ $results = array_merge( $results, $matches[0] );
749
+ }
750
+
751
+ // Look for `get_option` calls.
752
+ preg_match(
753
+ '/get_option\s*\(\s*[\'"](.*?)[\'"]\s*\)/',
754
+ $line,
755
+ $matches
756
+ );
757
+
758
+ // Check option.
759
+ if ( $matches && $matches[1] && self::_check_file_line( get_option( $matches[1] ), $num ) ) {
760
+ array_push( $results, 'get_option' );
761
+ }
762
+
763
+ if ( $results ) {
764
+ // Remove duplicates.
765
+ $results = array_unique( $results );
766
+
767
+ // Get whitelist.
768
+ $md5 = self::_get_white_list();
769
+
770
+ // Loop through results.
771
+ foreach ( $results as $tag ) {
772
+ $string = str_replace(
773
+ $tag,
774
+ '@span@' . $tag . '@/span@',
775
+ self::_get_dotted_line( $line, $tag )
776
+ );
777
+
778
+ // Add line to output if it's not on the whitelist.
779
+ if ( ! in_array( md5( $num . $string ), $md5 ) ) {
780
+ $output[] = $string;
781
+ }
782
+ }
783
+
784
+ return $output;
785
+ }
786
+
787
+ return false;
788
+ }
789
+
790
+ /**
791
+ * Check the files of the currently activated theme.
792
+ *
793
+ * @return array|false Results array or false on failure.
794
+ */
795
+ private static function _check_theme_files() {
796
+ // Check if there are any files.
797
+ if ( ! $files = self::_get_theme_files() ) {
798
+ return false;
799
+ }
800
+
801
+ $results = array();
802
+
803
+ // Loop through files.
804
+ foreach ( $files as $file ) {
805
+ if ( $result = self::_check_theme_file( $file ) ) {
806
+ $results[ $file ] = $result;
807
+ }
808
+ }
809
+
810
+ // Return results if found.
811
+ if ( ! empty( $results ) ) {
812
+ return $results;
813
+ }
814
+
815
+ return false;
816
+ }
817
+
818
+ /**
819
+ * Check a single file.
820
+ *
821
+ * @param string $file File path.
822
+ * @return array|false Results array or false on failure.
823
+ */
824
+ private static function _check_theme_file( $file ) {
825
+ // Simple file path check.
826
+ if ( filter_var( $file, FILTER_SANITIZE_URL ) !== $file ) {
827
+ return false;
828
+ }
829
+
830
+ // Sanitize file string.
831
+ if ( validate_file( $file ) !== 0 ) {
832
+ return false;
833
+ }
834
+
835
+ // No file?
836
+ if ( ! $file ) {
837
+ return false;
838
+ }
839
+
840
+ // Get file content.
841
+ $content = self::_get_file_content( $file );
842
+
843
+ if ( ! $content ) {
844
+ return false;
845
+ }
846
+
847
+ $results = array();
848
+
849
+ // Loop through lines.
850
+ foreach ( $content as $num => $line ) {
851
+ if ( $result = self::_check_file_line( $line, $num ) ) {
852
+ $results[ $num ] = $result;
853
+ }
854
+ }
855
+
856
+ // Return results if found.
857
+ if ( ! empty( $results ) ) {
858
+ return $results;
859
+ }
860
+
861
+ return false;
862
+ }
863
+
864
+ /**
865
+ * Check the permalink structure.
866
+ *
867
+ * @return array|false Results array or false on failure.
868
+ */
869
+ private static function _check_permalink_structure() {
870
+ $structure = get_option( 'permalink_structure' );
871
+
872
+ if ( ! $structure ) {
873
+ return false;
874
+ }
875
+
876
+ // Regex check.
877
+ preg_match_all(
878
+ self::_php_match_pattern(),
879
+ $structure,
880
+ $matches
881
+ );
882
+
883
+ // Save matches.
884
+ if ( $matches[1] ) {
885
+ return $matches[1];
886
+ }
887
+
888
+ return false;
889
+ }
890
+
891
+ /**
892
+ * Show notice on the dashboard.
893
+ */
894
+ public static function show_dashboard_notice() {
895
+ // Only show notice if there's an alert.
896
+ if ( ! self::_get_option( 'cronjob_alert' ) ) {
897
+ return;
898
+ }
899
+
900
+ // Display warning.
901
+ echo sprintf(
902
+ '<div class="error"><p><strong>%1$s:</strong> %2$s <a href="%3$s">%4$s &rarr;</a></p></div>',
903
+ esc_html__( 'Virus suspected', 'antivirus' ),
904
+ esc_html__( 'The daily antivirus scan of your blog suggests alarm.', 'antivirus' ),
905
+ esc_url( add_query_arg(
906
+ array(
907
+ 'page' => 'antivirus',
908
+ ),
909
+ admin_url( 'options-general.php' )
910
+ ) ),
911
+ esc_html__( 'Manual malware scan', 'antivirus' )
912
+ );
913
+ }
914
+
915
+ /**
916
+ * Print the settings page.
917
+ */
918
+ public static function show_admin_menu() {
919
+ // Save updates.
920
+ if ( ! empty( $_POST ) ) {
921
+ // Check the referer.
922
+ check_admin_referer( 'antivirus' );
923
+
924
+ // Save values.
925
+ $options = array(
926
+ 'cronjob_enable' => (int) ( ! empty( $_POST['av_cronjob_enable'] ) ),
927
+ 'notify_email' => sanitize_email( @$_POST['av_notify_email'] ),
928
+ 'safe_browsing' => (int) ( ! empty( $_POST['av_safe_browsing'] ) ),
929
+ );
930
+
931
+ // No cronjob?
932
+ if ( empty( $options['cronjob_enable'] ) ) {
933
+ $options['notify_email'] = '';
934
+ $options['safe_browsing'] = 0;
935
+ }
936
+
937
+ // Stop cron if it was disabled.
938
+ if ( $options['cronjob_enable'] && ! self::_get_option( 'cronjob_enable' ) ) {
939
+ self::_add_scheduled_hook();
940
+ } else if ( ! $options['cronjob_enable'] && self::_get_option( 'cronjob_enable' ) ) {
941
+ self::clear_scheduled_hook();
942
+ }
943
+
944
+ // Save options.
945
+ self::_update_options( $options ); ?>
946
+
947
+ <div id="message" class="notice notice-success">
948
+ <p>
949
+ <strong>
950
+ <?php esc_html_e( 'Settings saved.', 'antivirus' ); ?>
951
+ </strong>
952
+ </p>
953
+ </div>
954
+ <?php } ?>
955
+
956
+ <div class="wrap" id="av_main">
957
+ <h1>
958
+ <?php esc_html_e( 'AntiVirus', 'antivirus' ); ?>
959
+ </h1>
960
+
961
+ <table class="form-table">
962
+ <tr>
963
+ <th scope="row">
964
+ <?php esc_html_e( 'Manual malware scan', 'antivirus' ); ?>
965
+ </th>
966
+ <td>
967
+ <div class="inside" id="av_manual_scan">
968
+ <p>
969
+ <a href="#" class="button button-primary">
970
+ <?php esc_html_e( 'Scan the theme templates now', 'antivirus' ); ?>
971
+ </a>
972
+ <span class="alert"></span>
973
+ </p>
974
+
975
+ <div class="output"></div>
976
+ </div>
977
+ </td>
978
+ </tr>
979
+ </table>
980
+
981
+
982
+ <form method="post" action="<?php echo esc_url( admin_url( 'options-general.php?page=antivirus' ) ); ?>">
983
+ <?php wp_nonce_field( 'antivirus' ) ?>
984
+
985
+ <table class="form-table">
986
+ <tr>
987
+ <th scope="row">
988
+ <?php esc_html_e( 'Daily malware scan', 'antivirus' ); ?>
989
+ </th>
990
+ <td>
991
+ <fieldset>
992
+ <label for="av_cronjob_enable">
993
+ <input type="checkbox" name="av_cronjob_enable" id="av_cronjob_enable"
994
+ value="1" <?php checked( self::_get_option( 'cronjob_enable' ), 1 ) ?> />
995
+ <?php esc_html_e( 'Check the theme templates for malware', 'antivirus' ); ?>
996
+ </label>
997
+
998
+ <p class="description">
999
+ <?php
1000
+ if ( $timestamp = wp_next_scheduled( 'antivirus_daily_cronjob' ) ) {
1001
+ echo sprintf(
1002
+ '%s: %s',
1003
+ esc_html__( 'Next Run', 'antivirus' ),
1004
+ date_i18n( 'd.m.Y H:i:s', $timestamp + get_option( 'gmt_offset' ) * 3600 )
1005
+ );
1006
+ }
1007
+ ?>
1008
+ </p>
1009
+
1010
+ <br/>
1011
+
1012
+ <label for="av_safe_browsing">
1013
+ <input type="checkbox" name="av_safe_browsing" id="av_safe_browsing"
1014
+ value="1" <?php checked( self::_get_option( 'safe_browsing' ), 1 ) ?> />
1015
+ <?php esc_html_e( 'Malware detection by Google Safe Browsing', 'antivirus' ); ?>
1016
+ </label>
1017
+
1018
+ <p class="description">
1019
+ <?php esc_html_e( 'Diagnosis and notification in suspicion case', 'antivirus' ); ?>
1020
+ </p>
1021
+
1022
+ <br/>
1023
+
1024
+ <label for="av_notify_email"><?php esc_html_e( 'Email address for notifications', 'antivirus' ); ?></label>
1025
+ <input type="text" name="av_notify_email" id="av_notify_email"
1026
+ value="<?php esc_attr_e( self::_get_option( 'notify_email' ) ); ?>"
1027
+ class="regular-text"
1028
+ placeholder="<?php esc_attr_e( 'Email address for notifications', 'antivirus' ); ?>" />
1029
+
1030
+
1031
+ <p class="description">
1032
+ <?php esc_html_e( 'If the field is empty, the blog admin will be notified', 'antivirus' ); ?>
1033
+ </p>
1034
+ </fieldset>
1035
+ </td>
1036
+ </tr>
1037
+
1038
+ <tr>
1039
+ <th scope="row">
1040
+ <input type="submit" class="button button-primary" value="<?php esc_attr_e( 'Save Changes', 'antivirus' ) ?>"/>
1041
+ </th>
1042
+ <td>
1043
+ <?php
1044
+ printf(
1045
+ '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
1046
+ 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=TD4AMD2D8EMZW',
1047
+ esc_html__( 'Donate', 'antivirus' )
1048
+ );
1049
+ ?>
1050
+ &bull;
1051
+ <?php
1052
+ printf(
1053
+ '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
1054
+ esc_attr__( 'https://wordpress.org/plugins/antivirus/faq/', 'antivirus' ),
1055
+ esc_html__( 'FAQ', 'antivirus' )
1056
+ );
1057
+ ?>
1058
+ &bull;
1059
+ <?php
1060
+ printf(
1061
+ '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
1062
+ 'https://github.com/pluginkollektiv/antivirus/wiki',
1063
+ esc_html__( 'Manual', 'antivirus' )
1064
+ );
1065
+ ?>
1066
+ &bull;
1067
+ <?php
1068
+ printf(
1069
+ '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
1070
+ 'https://wordpress.org/support/plugin/antivirus',
1071
+ esc_html__( 'Support', 'antivirus' )
1072
+ );
1073
+ ?>
1074
+ </td>
1075
+ </tr>
1076
+ </table>
1077
+ </form>
1078
+ </div>
1079
+ <?php }
1080
+ }
1081
+
1082
+ // Initialize the plugin.
1083
+ add_action( 'plugins_loaded', array( 'AntiVirus', 'instance' ), 99 );
1084
+
1085
+ /* Hooks */
1086
+ register_activation_hook( __FILE__, array( 'AntiVirus', 'activation' ) );
1087
+ register_deactivation_hook( __FILE__, array( 'AntiVirus', 'deactivation' ) );
1088
+ register_uninstall_hook( __FILE__, array( 'AntiVirus', 'uninstall' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/style.min.css CHANGED
@@ -1 +1 @@
1
- #av_manual_scan{height:1%;overflow:hidden;}#av_manual_scan a.button{float:left;}#av_manual_scan .alert{float:left;color:green;margin:0 10px;border:1px solid green;display:none;height:26px;line-height:26px;padding:0 10px;background:#fff;border-radius:3px;}#av_main .inside .output{clear:both;height:1%;margin:0 0 0 -6px;padding:0 0 6px;overflow:hidden;}#av_main .inside .output div{float:left;color:#FFF;margin:12px 6px 0;padding:8px 12px 10px;background:orange;border-radius:3px;transition:background-color 0.5s linear;-o-transition:background-color 0.5s linear;-ms-transition:background-color 0.5s linear;-moz-transition:background-color 0.5s linear;-webkit-transition:background-color 0.5s linear;}#av_main .inside .output div.done{background:green;}#av_main .inside .output div.danger{width:97%;background:red;}#av_main .inside .output div p{padding:10px;overflow:hidden;background:#f9f9f9;white-space:nowrap;border-radius:3px;}#av_main .inside .output div p a{float:left;color:#646464;margin:0 6px 12px 0;display:block;border:1px solid #b4b9be;padding:2px 5px;background:#f2f2f2;text-decoration:none;border-radius:3px;}#av_main .inside .output div p a:hover{color:#000;border:1px solid #646464;}#av_main .inside .output div p code{clear:both;float:left;color:#000;padding:2px 5px;border-radius:3px;}#av_main .inside .output div p code span{padding:2px;background:yellow;}#av_notify_email{line-height:1.5;}
1
+ #av_manual_scan{height:1%;overflow:hidden}#av_manual_scan a.button{float:left}#av_manual_scan .alert{float:left;color:green;margin:0 10px;border:1px solid green;display:none;height:26px;line-height:26px;padding:0 10px;background:#fff;border-radius:3px}#av_main .inside .output{clear:both;height:1%;margin:0 0 0 -6px;padding:0 0 6px;overflow:hidden}#av_main .inside .output div{float:left;color:#fff;margin:12px 6px 0;padding:8px 12px 10px;background:orange;border-radius:3px;transition:background-color .5s linear;-o-transition:background-color .5s linear;-ms-transition:background-color .5s linear;-moz-transition:background-color .5s linear;-webkit-transition:background-color .5s linear}#av_main .inside .output div.done{background:green}#av_main .inside .output div.danger{width:97%;background:red}#av_main .inside .output div p{padding:10px;overflow:hidden;background:#f9f9f9;white-space:nowrap;border-radius:3px}#av_main .inside .output div p a{float:left;color:#646464;margin:0 6px 12px 0;display:block;border:1px solid #b4b9be;padding:2px 5px;background:#f2f2f2;text-decoration:none;border-radius:3px}#av_main .inside .output div p a:hover{color:#000;border:1px solid #646464}#av_main .inside .output div p code{clear:both;float:left;color:#000;padding:2px 5px;border-radius:3px}#av_main .inside .output div p code span{padding:2px;background:#ff0}#av_notify_email{line-height:1.5}
js/script.min.js CHANGED
@@ -1,4 +1 @@
1
- jQuery(document).ready(function(b){function g(a){var d=parseInt(a||0);b.post(ajaxurl,{action:"get_ajax_response",_ajax_nonce:av_nonce,_theme_file:av_files[d],_action_request:"check_theme_file"},function(c){var a=b("#av_template_"+d);if(c){if(!c.nonce||c.nonce!=av_nonce)return;a.addClass("danger");var e=c.data,f=e.length;for(c=0;c<f;c+=3){parseInt(e[c]);var h=e[c+2],k=e[c+1].replace(/@span@/g,"<span>").replace(/@\/span@/g,"</span>");a.text();a.append('<p><a href="#" id="'+h+'">'+av_msg_1+"</a> <code>"+
2
- k+"</code></p>");b("#"+h).click(function(){b.post(ajaxurl,{action:"get_ajax_response",_ajax_nonce:av_nonce,_file_md5:b(this).attr("id"),_action_request:"update_white_list"},function(a){a&&a.nonce&&a.nonce==av_nonce&&(a=b("#"+a.data[0]).parent(),1>=a.parent().children().length&&a.parent().hide("slow").remove(),a.hide("slow").remove())});return!1})}}else a.addClass("done");av_files_loaded++;av_files_loaded>=av_files_total?b("#av_manual_scan .alert").text(av_msg_3).fadeIn().fadeOut().fadeIn().fadeOut().fadeIn().animate({opacity:1},
3
- 500).fadeOut("slow",function(){b(this).empty()}):g(d+1)})}function f(){var a=b("#av_cronjob_enable"),d=a.parents("fieldset").find(":text, :checkbox").not(a);"function"===typeof b.fn.prop?d.prop("disabled",!a.prop("checked")):d.attr("disabled",!a.attr("checked"))}av_nonce=av_settings.nonce;av_theme=av_settings.theme;av_msg_1=av_settings.msg_1;av_msg_2=av_settings.msg_2;av_msg_3=av_settings.msg_3;b("#av_manual_scan a.button").click(function(){b.post(ajaxurl,{action:"get_ajax_response",_ajax_nonce:av_nonce,
4
- _action_request:"get_theme_files"},function(a){if(a&&a.nonce&&a.nonce==av_nonce){var d="";av_files=a.data;av_files_total=av_files.length;av_files_loaded=0;jQuery.each(av_files,function(a,b){d+='<div id="av_template_'+a+'">'+b+"</div>"});b("#av_manual_scan .alert").empty();b("#av_manual_scan .output").empty().append(d);g()}});return!1});b("#av_cronjob_enable").click(f);f()});
1
+ jQuery(document).ready(function(l){function e(){var e=l("#av_cronjob_enable"),a=e.parents("fieldset").find(":text, :checkbox").not(e);"function"==typeof l.fn.prop?a.prop("disabled",!e.prop("checked")):a.attr("disabled",!e.attr("checked"))}av_nonce=av_settings.nonce,av_theme=av_settings.theme,av_msg_1=av_settings.msg_1,av_msg_2=av_settings.msg_2,av_msg_3=av_settings.msg_3,l("#av_manual_scan a.button").click(function(){return l.post(ajaxurl,{action:"get_ajax_response",_ajax_nonce:av_nonce,_action_request:"get_theme_files"},function(e){if(e&&e.nonce&&e.nonce==av_nonce){var n="";av_files=e.data,av_files_total=av_files.length,av_files_loaded=0,jQuery.each(av_files,function(e,a){n+='<div id="av_template_'+e+'">'+a+"</div>"}),l("#av_manual_scan .alert").empty(),l("#av_manual_scan .output").empty().append(n),function c(e){var i=parseInt(e||0),a=av_files[i];l.post(ajaxurl,{action:"get_ajax_response",_ajax_nonce:av_nonce,_theme_file:a,_action_request:"check_theme_file"},function(e){var a=l("#av_template_"+i);if(e){if(!e.nonce||e.nonce!=av_nonce)return;a.addClass("danger");var n,t=e.data,_=t.length;for(n=0;n<_;n+=3){parseInt(t[n]);var o=t[n+2],s=t[n+1].replace(/@span@/g,"<span>").replace(/@\/span@/g,"</span>");a.text(),a.append('<p><a href="#" id="'+o+'">'+av_msg_1+"</a> <code>"+s+"</code></p>"),l("#"+o).click(function(){return l.post(ajaxurl,{action:"get_ajax_response",_ajax_nonce:av_nonce,_file_md5:l(this).attr("id"),_action_request:"update_white_list"},function(e){if(e&&e.nonce&&e.nonce==av_nonce){var a=l("#"+e.data[0]).parent();a.parent().children().length<=1&&a.parent().hide("slow").remove(),a.hide("slow").remove()}}),!1})}}else a.addClass("done");av_files_loaded++,av_files_loaded>=av_files_total?l("#av_manual_scan .alert").text(av_msg_3).fadeIn().fadeOut().fadeIn().fadeOut().fadeIn().animate({opacity:1},500).fadeOut("slow",function(){l(this).empty()}):c(i+1)})}()}}),!1}),l("#av_cronjob_enable").click(e),e()});
 
 
 
lang/antivirus-de_DE.mo DELETED
Binary file
lang/antivirus-de_DE.po DELETED
@@ -1,112 +0,0 @@
1
- msgid ""
2
- msgstr ""
3
- "Project-Id-Version: AntiVirus\n"
4
- "Report-Msgid-Bugs-To: \n"
5
- "POT-Creation-Date: \n"
6
- "PO-Revision-Date: 2015-08-18 14:35+0100\n"
7
- "Last-Translator: Caspar Huebinger <caspar@glueckpress.com>\n"
8
- "Language-Team: Sergej Müller\n"
9
- "Language: de\n"
10
- "MIME-Version: 1.0\n"
11
- "Content-Type: text/plain; charset=utf-8\n"
12
- "Content-Transfer-Encoding: 8bit\n"
13
- "Plural-Forms: nplurals=2; plural=n != 1;\n"
14
- "X-Poedit-SourceCharset: utf-8\n"
15
- "X-Poedit-KeywordsList: _:1;gettext:1;dgettext:2;ngettext:1,2;dngettext:2,3;"
16
- "__:1;_e:1;_c:1;_n:1,2;_n_noop:1,2;_nc:1,2;__ngettext:1,2;"
17
- "__ngettext_noop:1,2;_x:1,2c;_ex:1,2c;_nx:1,2,4c;_nx_noop:1,2,3c;_n_js:1,2;"
18
- "_nx_js:1,2,3c;esc_attr__:1;esc_html__:1;esc_attr_e:1;esc_html_e:1;"
19
- "esc_attr_x:1,2c;esc_html_x:1,2c;comments_number_link:2,3;t:1;st:1;trans:1;"
20
- "transChoice:1,2\n"
21
- "X-Poedit-Basepath: .\n"
22
- "X-Loco-Target-Locale: de_DE\n"
23
- "X-Generator: Poedit 1.8\n"
24
- "X-Poedit-SearchPath-0: .\n"
25
-
26
- #: ../antivirus.php:447
27
- msgid "Safe Browsing Alert"
28
- msgstr "Safe Browsing Alarm"
29
-
30
- #: ../antivirus.php:450
31
- msgid "Please check the Google Safe Browsing diagnostic page:"
32
- msgstr "Für weitere Details die Google Safe Browsing Diagnoseseite aufsuchen:"
33
-
34
- #: ../antivirus.php:474 ../antivirus.php:1149
35
- msgid "Virus suspected"
36
- msgstr "Virusverdacht"
37
-
38
- #: ../antivirus.php:477 ../antivirus.php:1150
39
- msgid "The daily antivirus scan of your blog suggests alarm."
40
- msgstr "Die tägliche AntiVirus-Prüfung des Blogs schlägt Alarm."
41
-
42
- #: ../antivirus.php:521
43
- msgid "Notify message by AntiVirus for WordPress"
44
- msgstr "Benachrichtigung von AntiVirus für WordPress"
45
-
46
- #: ../antivirus.php:522
47
- msgid "http://wpantivirus.com"
48
- msgstr "http://wpantivirus.de"
49
-
50
- #: ../antivirus.php:596
51
- msgid "There is no virus"
52
- msgstr "Nicht erneut hinweisen"
53
-
54
- #: ../antivirus.php:597
55
- msgid "View line"
56
- msgstr "Zeige Zeile"
57
-
58
- #: ../antivirus.php:598
59
- msgid "Scan finished"
60
- msgstr "Prüfung abgeschlossen"
61
-
62
- #: ../antivirus.php:1157 ../antivirus.php:1215
63
- msgid "Manual malware scan"
64
- msgstr "Manuelle Prüfung"
65
-
66
- #: ../antivirus.php:1221
67
- msgid "Scan the theme templates now"
68
- msgstr "Theme-Templates jetzt prüfen"
69
-
70
- #: ../antivirus.php:1238
71
- msgid "Daily malware scan"
72
- msgstr "Tägliche Prüfung"
73
-
74
- #: ../antivirus.php:1244
75
- msgid "Check the theme templates for malware"
76
- msgstr "Überprüfung der Theme-Templates auf Malware"
77
-
78
- #: ../antivirus.php:1251
79
- msgid "Next Run"
80
- msgstr "Nächste Ausführung"
81
-
82
- #: ../antivirus.php:1263
83
- msgid "Malware detection by Google Safe Browsing"
84
- msgstr "Malware-Erkennung durch Google Safe Browsing"
85
-
86
- #: ../antivirus.php:1267
87
- msgid "Diagnosis and notification in suspicion case"
88
- msgstr "Diagnose und Benachrichtigung im Verdachtsfall"
89
-
90
- #: ../antivirus.php:1275
91
- msgid "Email address for notifications"
92
- msgstr "E-Mail-Adresse für Benachrichtigungen"
93
-
94
- #: ../antivirus.php:1279
95
- msgid "If the field is empty, the blog admin will be notified"
96
- msgstr "Bleibt das Eingabefeld leer, wird der Admin benachrichtigt"
97
-
98
- msgid ""
99
- "Security plugin to protect your blog or website against exploits and spam "
100
- "injections."
101
- msgstr ""
102
- "Kostenfreie Sicherheitslösung als Plugin zur Früherkennung und Warnung vor "
103
- "bösartigen Injektionen."
104
-
105
- msgid "pluginkollektiv"
106
- msgstr "pluginkollektiv"
107
-
108
- msgid "http://pluginkollektiv.org"
109
- msgstr "http://pluginkollektiv.org"
110
-
111
- msgid "https://wordpress.org/plugins/antivirus/"
112
- msgstr "https://wordpress.org/plugins/antivirus/"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lang/antivirus-de_DE_formal.mo DELETED
Binary file
lang/antivirus-de_DE_formal.po DELETED
@@ -1,105 +0,0 @@
1
- msgid ""
2
- msgstr ""
3
- "Project-Id-Version: AntiVirus\n"
4
- "Report-Msgid-Bugs-To: \n"
5
- "POT-Creation-Date: \n"
6
- "PO-Revision-Date: \n"
7
- "Last-Translator: Caspar Huebinger <caspar@glueckpress.com>\n"
8
- "Language-Team: pluginkollektiv\n"
9
- "Language: de_DE\n"
10
- "MIME-Version: 1.0\n"
11
- "Content-Type: text/plain; charset=utf-8\n"
12
- "Content-Transfer-Encoding: 8bit\n"
13
- "X-Poedit-SourceCharset: utf-8\n"
14
- "X-Poedit-KeywordsList: __;_e\n"
15
- "X-Poedit-Basepath: .\n"
16
- "X-Generator: Poedit 1.8\n"
17
- "X-Poedit-SearchPath-0: .\n"
18
-
19
- #: ../antivirus.php:447
20
- msgid "Safe Browsing Alert"
21
- msgstr "Safe Browsing Alarm"
22
-
23
- #: ../antivirus.php:450
24
- msgid "Please check the Google Safe Browsing diagnostic page:"
25
- msgstr "Für weitere Details die Google Safe Browsing Diagnoseseite aufsuchen:"
26
-
27
- #: ../antivirus.php:474 ../antivirus.php:1149
28
- msgid "Virus suspected"
29
- msgstr "Virusverdacht"
30
-
31
- #: ../antivirus.php:477 ../antivirus.php:1150
32
- msgid "The daily antivirus scan of your blog suggests alarm."
33
- msgstr "Die tägliche AntiVirus-Prüfung des Blogs schlägt Alarm."
34
-
35
- #: ../antivirus.php:521
36
- msgid "Notify message by AntiVirus for WordPress"
37
- msgstr "Benachrichtigung von AntiVirus für WordPress"
38
-
39
- #: ../antivirus.php:522
40
- msgid "http://wpantivirus.com"
41
- msgstr "http://wpantivirus.de"
42
-
43
- #: ../antivirus.php:596
44
- msgid "There is no virus"
45
- msgstr "Nicht erneut hinweisen"
46
-
47
- #: ../antivirus.php:597
48
- msgid "View line"
49
- msgstr "Zeige Zeile"
50
-
51
- #: ../antivirus.php:598
52
- msgid "Scan finished"
53
- msgstr "Prüfung abgeschlossen"
54
-
55
- #: ../antivirus.php:1157 ../antivirus.php:1215
56
- msgid "Manual malware scan"
57
- msgstr "Manuelle Prüfung"
58
-
59
- #: ../antivirus.php:1221
60
- msgid "Scan the theme templates now"
61
- msgstr "Theme-Templates jetzt prüfen"
62
-
63
- #: ../antivirus.php:1238
64
- msgid "Daily malware scan"
65
- msgstr "Tägliche Prüfung"
66
-
67
- #: ../antivirus.php:1244
68
- msgid "Check the theme templates for malware"
69
- msgstr "Überprüfung der Theme-Templates auf Malware"
70
-
71
- #: ../antivirus.php:1251
72
- msgid "Next Run"
73
- msgstr "Nächste Ausführung"
74
-
75
- #: ../antivirus.php:1263
76
- msgid "Malware detection by Google Safe Browsing"
77
- msgstr "Malware-Erkennung durch Google Safe Browsing"
78
-
79
- #: ../antivirus.php:1267
80
- msgid "Diagnosis and notification in suspicion case"
81
- msgstr "Diagnose und Benachrichtigung im Verdachtsfall"
82
-
83
- #: ../antivirus.php:1275
84
- msgid "Email address for notifications"
85
- msgstr "E-Mail-Adresse für Benachrichtigungen"
86
-
87
- #: ../antivirus.php:1279
88
- msgid "If the field is empty, the blog admin will be notified"
89
- msgstr "Bleibt das Eingabefeld leer, wird der Admin benachrichtigt"
90
-
91
- msgid ""
92
- "Security plugin to protect your blog or website against exploits and spam "
93
- "injections."
94
- msgstr ""
95
- "Kostenfreie Sicherheitslösung als Plugin zur Früherkennung und Warnung vor "
96
- "bösartigen Injektionen."
97
-
98
- msgid "pluginkollektiv"
99
- msgstr "pluginkollektiv"
100
-
101
- msgid "http://pluginkollektiv.org"
102
- msgstr "http://pluginkollektiv.org"
103
-
104
- msgid "https://wordpress.org/plugins/antivirus/"
105
- msgstr "https://wordpress.org/plugins/antivirus/"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lang/antivirus-es_ES.mo DELETED
Binary file
lang/antivirus-es_ES.po DELETED
@@ -1,162 +0,0 @@
1
- msgid ""
2
- msgstr ""
3
- "Project-Id-Version: AntiVirus v1.3.5\n"
4
- "Report-Msgid-Bugs-To: \n"
5
- "POT-Creation-Date: \n"
6
- "PO-Revision-Date: 2014-03-08 22:21:17+0000\n"
7
- "Last-Translator: Pablo Laguna <laguna.sanchez@gmail.com>\n"
8
- "Language-Team: \n"
9
- "MIME-Version: 1.0\n"
10
- "Content-Type: text/plain; charset=UTF-8\n"
11
- "Content-Transfer-Encoding: 8bit\n"
12
- "Plural-Forms: nplurals=2; plural=n != 1;\n"
13
- "X-Generator: CSL v1.x\n"
14
- "X-Poedit-Language: Spanish\n"
15
- "X-Poedit-Country: SPAIN\n"
16
- "X-Poedit-SourceCharset: utf-8\n"
17
- "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;\n"
18
- "X-Poedit-Basepath: ../\n"
19
- "X-Poedit-Bookmarks: \n"
20
- "X-Poedit-SearchPath-0: .\n"
21
- "X-Textdomain-Support: yes"
22
-
23
- #. translators: plugin header field 'Name'
24
- #: antivirus.php:0
25
- #@ antivirus
26
- msgid "AntiVirus"
27
- msgstr "AntiVirus"
28
-
29
- #. translators: plugin header field 'PluginURI'
30
- #: antivirus.php:0
31
- #: antivirus.php:505
32
- #@ antivirus
33
- msgid "http://wpantivirus.com"
34
- msgstr "http://wpantivirus.com"
35
-
36
- #. translators: plugin header field 'Description'
37
- #: antivirus.php:0
38
- #@ antivirus
39
- msgid "Security solution as a smart, effectively plugin to protect your blog against exploits and spam injections."
40
- msgstr "Solución de seguridad en un sencillo y efectivo plugin para proteger tu blog de agujeros e infecciones."
41
-
42
- #. translators: plugin header field 'Author'
43
- #: antivirus.php:0
44
- #@ antivirus
45
- msgid "Sergej M&uuml;ller"
46
- msgstr "Sergej M&uuml;ller"
47
-
48
- #. translators: plugin header field 'AuthorURI'
49
- #: antivirus.php:0
50
- #@ antivirus
51
- msgid "http://wpcoder.de"
52
- msgstr "http://wpcoder.de"
53
-
54
- #. translators: plugin header field 'Version'
55
- #: antivirus.php:0
56
- #@ antivirus
57
- msgid "1.3.5"
58
- msgstr "1.3.5"
59
-
60
- #: antivirus.php:182
61
- #@ default
62
- msgid "Settings"
63
- msgstr "Opciones"
64
-
65
- #: antivirus.php:431
66
- #@ antivirus
67
- msgid "Safe Browsing Alert"
68
- msgstr "Alerta de Safe Browsing"
69
-
70
- #: antivirus.php:434
71
- #@ antivirus
72
- msgid "Please check the Google Safe Browsing diagnostic page:"
73
- msgstr "Por favor, revisa la página de diagnóstico de Google Safe Browsing:"
74
-
75
- #: antivirus.php:458
76
- #: antivirus.php:1125
77
- #@ antivirus
78
- msgid "Virus suspected"
79
- msgstr "Sospecha de virus"
80
-
81
- #: antivirus.php:461
82
- #: antivirus.php:1126
83
- #@ antivirus
84
- msgid "The daily antivirus scan of your blog suggests alarm."
85
- msgstr "El análisis antivirus diario de tu blog ha dado una alarma."
86
-
87
- #: antivirus.php:504
88
- #@ antivirus
89
- msgid "Notify message by AntiVirus for WordPress"
90
- msgstr "Mensaje de notificación de AntiVirus para WordPress"
91
-
92
- #: antivirus.php:579
93
- #@ antivirus
94
- msgid "There is no virus"
95
- msgstr "No hay virus"
96
-
97
- #: antivirus.php:580
98
- #@ antivirus
99
- msgid "View line"
100
- msgstr "Ver línea"
101
-
102
- #: antivirus.php:581
103
- #@ antivirus
104
- msgid "Scan finished"
105
- msgstr "Escaneo finalizado"
106
-
107
- #: antivirus.php:1133
108
- #: antivirus.php:1191
109
- #@ antivirus
110
- msgid "Manual malware scan"
111
- msgstr "Escaneo manual de software malicioso"
112
-
113
- #: antivirus.php:1177
114
- #@ default
115
- msgid "Settings saved."
116
- msgstr "Opciones guardadas."
117
-
118
- #: antivirus.php:1197
119
- #@ antivirus
120
- msgid "Scan the theme templates now"
121
- msgstr "Escanear los ficheros del tema ahora"
122
-
123
- #: antivirus.php:1214
124
- #@ antivirus
125
- msgid "Daily malware scan"
126
- msgstr "Escaneo diario de software malicioso"
127
-
128
- #: antivirus.php:1220
129
- #@ antivirus
130
- msgid "Check the theme templates for malware"
131
- msgstr "Revisar los ficheros del tema en busca de software malicioso"
132
-
133
- #: antivirus.php:1227
134
- #@ antivirus
135
- msgid "Next Run"
136
- msgstr "Próxima ejecución"
137
-
138
- #: antivirus.php:1239
139
- #@ antivirus
140
- msgid "Malware detection by Google Safe Browsing"
141
- msgstr "Detección de software malicioso por Google Safe Browsing"
142
-
143
- #: antivirus.php:1243
144
- #@ antivirus
145
- msgid "Diagnosis and notification in suspicion case"
146
- msgstr "Diagnóstico y notificación en caso de sospecha"
147
-
148
- #: antivirus.php:1251
149
- #@ antivirus
150
- msgid "Email address for notifications"
151
- msgstr "Dirección electrónica para notificaciones"
152
-
153
- #: antivirus.php:1255
154
- #@ antivirus
155
- msgid "If the field is empty, the blog admin will be notified"
156
- msgstr "Si el campo está vacío, se enviarán las notificaciones al administrador del sitio"
157
-
158
- #: antivirus.php:1263
159
- #@ default
160
- msgid "Save Changes"
161
- msgstr "Guardar cambios"
162
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lang/antivirus.pot DELETED
@@ -1,111 +0,0 @@
1
- # Loco Gettext template
2
- #, fuzzy
3
- msgid ""
4
- msgstr ""
5
- "Project-Id-Version: AntiVirus\n"
6
- "Report-Msgid-Bugs-To: \n"
7
- "POT-Creation-Date: \n"
8
- "POT-Revision-Date: Tue Aug 18 2015 14:02:12 GMT+0200 (CEST)\n"
9
- "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
10
- "Last-Translator: Torsten Landsiedel <torsten.landsiedel@gmx.de>\n"
11
- "Language-Team: pluginkollektiv\n"
12
- "Language: \n"
13
- "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION\n"
14
- "MIME-Version: 1.0\n"
15
- "Content-Type: text/plain; charset=utf-8\n"
16
- "Content-Transfer-Encoding: 8bit\n"
17
- "X-Poedit-SourceCharset: utf-8\n"
18
- "X-Poedit-KeywordsList: _:1;gettext:1;dgettext:2;ngettext:1,2;dngettext:2,3;"
19
- "__:1;_e:1;_c:1;_n:1,2;_n_noop:1,2;_nc:1,2;__ngettext:1,2;__ngettext_noop:1,2;"
20
- "_x:1,2c;_ex:1,2c;_nx:1,2,4c;_nx_noop:1,2,3c;_n_js:1,2;_nx_js:1,2,3c;"
21
- "esc_attr__:1;esc_html__:1;esc_attr_e:1;esc_html_e:1;esc_attr_x:1,2c;"
22
- "esc_html_x:1,2c;comments_number_link:2,3;t:1;st:1;trans:1;transChoice:1,2\n"
23
- "X-Poedit-Basepath: .\n"
24
- "X-Generator: Loco - https://localise.biz/\n"
25
- "X-Poedit-SearchPath-0: ."
26
-
27
- #: ../antivirus.php:447
28
- msgid "Safe Browsing Alert"
29
- msgstr ""
30
-
31
- #: ../antivirus.php:450
32
- msgid "Please check the Google Safe Browsing diagnostic page:"
33
- msgstr ""
34
-
35
- #: ../antivirus.php:474 ../antivirus.php:1149
36
- msgid "Virus suspected"
37
- msgstr ""
38
-
39
- #: ../antivirus.php:477 ../antivirus.php:1150
40
- msgid "The daily antivirus scan of your blog suggests alarm."
41
- msgstr ""
42
-
43
- #: ../antivirus.php:521
44
- msgid "Notify message by AntiVirus for WordPress"
45
- msgstr ""
46
-
47
- #: ../antivirus.php:522
48
- msgid "http://wpantivirus.com"
49
- msgstr ""
50
-
51
- #: ../antivirus.php:596
52
- msgid "There is no virus"
53
- msgstr ""
54
-
55
- #: ../antivirus.php:597
56
- msgid "View line"
57
- msgstr ""
58
-
59
- #: ../antivirus.php:598
60
- msgid "Scan finished"
61
- msgstr ""
62
-
63
- #: ../antivirus.php:1157 ../antivirus.php:1215
64
- msgid "Manual malware scan"
65
- msgstr ""
66
-
67
- #: ../antivirus.php:1221
68
- msgid "Scan the theme templates now"
69
- msgstr ""
70
-
71
- #: ../antivirus.php:1238
72
- msgid "Daily malware scan"
73
- msgstr ""
74
-
75
- #: ../antivirus.php:1244
76
- msgid "Check the theme templates for malware"
77
- msgstr ""
78
-
79
- #: ../antivirus.php:1251
80
- msgid "Next Run"
81
- msgstr ""
82
-
83
- #: ../antivirus.php:1263
84
- msgid "Malware detection by Google Safe Browsing"
85
- msgstr ""
86
-
87
- #: ../antivirus.php:1267
88
- msgid "Diagnosis and notification in suspicion case"
89
- msgstr ""
90
-
91
- #: ../antivirus.php:1275
92
- msgid "Email address for notifications"
93
- msgstr ""
94
-
95
- #: ../antivirus.php:1279
96
- msgid "If the field is empty, the blog admin will be notified"
97
- msgstr ""
98
-
99
- msgid ""
100
- "Security plugin to protect your blog or website against exploits and spam "
101
- "injections."
102
- msgstr ""
103
-
104
- msgid "pluginkollektiv"
105
- msgstr ""
106
-
107
- msgid "http://pluginkollektiv.org"
108
- msgstr ""
109
-
110
- msgid "https://wordpress.org/plugins/antivirus/"
111
- msgstr ""