Shield Security for WordPress - Version 16.1.14

Version Description

Download this release

Release Info

Developer paultgoodchild
Plugin Icon 128x128 Shield Security for WordPress
Version 16.1.14
Comparing to
See all releases

Code changes from version 16.1.13 to 16.1.14

Files changed (30) hide show
  1. cl.json +28 -2
  2. icwp-wpsf.php +1 -1
  3. plugin-spec.php +5 -4
  4. plugin.json +5 -4
  5. readme.txt +11 -11
  6. src/lib/src/Modules/Data/Lib/CleanDatabases.php +22 -0
  7. src/lib/src/Modules/HackGuard/Lib/Snapshots/StorageDir.php +46 -0
  8. src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php +15 -17
  9. src/lib/src/Modules/HackGuard/Lib/Utility/CleanOutOldGuardFiles.php +41 -0
  10. src/lib/src/Modules/HackGuard/ModCon.php +4 -0
  11. src/lib/src/Modules/HackGuard/Upgrade.php +14 -0
  12. src/lib/src/Modules/IPs/Lib/CrowdSec/Signals/EventsToSignals.php +2 -3
  13. src/lib/src/Modules/LoginGuard/Strings.php +13 -4
  14. src/lib/src/Modules/Plugin/Lib/Debug/Collate.php +6 -6
  15. src/lib/src/Modules/UserManagement/Lib/Session/FindSessions.php +7 -8
  16. src/lib/src/Modules/UserManagement/Lib/Suspend/UserSuspendController.php +78 -115
  17. src/lib/vendor/composer/autoload_classmap.php +1 -0
  18. src/lib/vendor/composer/autoload_static.php +1 -0
  19. src/lib/vendor/composer/installed.json +6 -6
  20. src/lib/vendor/composer/installed.php +9 -9
  21. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/BaseQuery.php +1 -19
  22. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/Delete.php +4 -6
  23. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/Insert.php +1 -1
  24. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/Update.php +1 -3
  25. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Common/Iterator.php +6 -5
  26. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Common/SubQueryLoader.php +1 -1
  27. src/lib/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php +148 -0
  28. src/lib/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php +67 -0
  29. src/lib/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php +45 -0
  30. src/lib/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php +191 -0
cl.json CHANGED
@@ -128,14 +128,40 @@
128
  ],
129
  "patches": [
130
  {
131
- "version": "13",
132
- "released_at": 1667298000,
133
  "items": [
134
  {
135
  "title": "Marks Shield 16.x as the final series supporting PHP 7.0 and 7.1. Shield 17 will require PHP 7.2.",
136
  "type": "changed",
137
  "href": "https://shsec.io/l8"
138
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  {
140
  "title": "Attempt to eliminate CrowdSec API issues.",
141
  "type": "improved"
128
  ],
129
  "patches": [
130
  {
131
+ "version": "14",
132
+ "released_at": 1669197000,
133
  "items": [
134
  {
135
  "title": "Marks Shield 16.x as the final series supporting PHP 7.0 and 7.1. Shield 17 will require PHP 7.2.",
136
  "type": "changed",
137
  "href": "https://shsec.io/l8"
138
  },
139
+ {
140
+ "title": "Performance improved when loading the WordPress Users page for sites with large users counts.",
141
+ "type": "improved"
142
+ },
143
+ {
144
+ "title": "Dashboard widget showing incorrect dates for user last login if it's never been recorded.",
145
+ "type": "fixed"
146
+ },
147
+ {
148
+ "title": "Tweaks to CrowdSec Signals map.",
149
+ "type": "fixed"
150
+ },
151
+ {
152
+ "title": "Plugin/Theme file scanner bug fixes.",
153
+ "type": "fixed"
154
+ },
155
+ {
156
+ "title": "Minor bug fixes.",
157
+ "type": "fixed"
158
+ }
159
+ ]
160
+ },
161
+ {
162
+ "version": "13",
163
+ "released_at": 1667298000,
164
+ "items": [
165
  {
166
  "title": "Attempt to eliminate CrowdSec API issues.",
167
  "type": "improved"
icwp-wpsf.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://shsec.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
- * Version: 16.1.13
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://shsec.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
+ * Version: 16.1.14
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
plugin-spec.php CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "16.1.13",
4
- "release_timestamp": 1667298000,
5
- "build": "202211.0101",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "text_domain": "wp-simple-firewall",
@@ -407,7 +407,8 @@
407
  "14.1.1",
408
  "14.1.4",
409
  "16.1.2",
410
- "16.1.7"
 
411
  ],
412
  "action_links": {
413
  "remove": null,
1
  {
2
  "properties": {
3
+ "version": "16.1.14",
4
+ "release_timestamp": 1669197000,
5
+ "build": "202211.2301",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "text_domain": "wp-simple-firewall",
407
  "14.1.1",
408
  "14.1.4",
409
  "16.1.2",
410
+ "16.1.7",
411
+ "16.1.14"
412
  ],
413
  "action_links": {
414
  "remove": null,
plugin.json CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "16.1.13",
4
- "release_timestamp": 1667298000,
5
- "build": "202211.0101",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "text_domain": "wp-simple-firewall",
@@ -407,7 +407,8 @@
407
  "14.1.1",
408
  "14.1.4",
409
  "16.1.2",
410
- "16.1.7"
 
411
  ],
412
  "action_links": {
413
  "remove": null,
1
  {
2
  "properties": {
3
+ "version": "16.1.14",
4
+ "release_timestamp": 1669197000,
5
+ "build": "202211.2301",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "text_domain": "wp-simple-firewall",
407
  "14.1.1",
408
  "14.1.4",
409
  "16.1.2",
410
+ "16.1.7",
411
+ "16.1.14"
412
  ],
413
  "action_links": {
414
  "remove": null,
readme.txt CHANGED
@@ -3,12 +3,12 @@ Contributors: paultgoodchild, getshieldsecurity
3
  Donate link: https://shsec.io/bw
4
  License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
- Tags: limit login, malware scan, firewall, two factor authentication, login protection
7
  Requires at least: 3.7
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 6.1
11
- Stable tag: 16.1.13
12
 
13
  Bad Bots Are Your #1 Security Risk. Are you playing whack-a-mole with malware & vulnerabilities? Discover the real security before marketing hype.
14
 
@@ -18,13 +18,13 @@ Shield is [now partnered with CrowdSec](https://shsec.io/l5) for global, crowd-s
18
 
19
  **We need to stop our obsession with malware**. Malware scanning is important *after* your site is hacked. Get a security plugin that [prioritises security *protection* before the worst happens](https://shsec.io/ky).
20
 
21
- Shield is the only security plugin for WordPress that fully prioritises protection over repair. Who cares about malware when you can stop it before it even happens?
22
 
23
- **No-Hype. No Scary Marketing. Just Great Security**. Shield is the only NO-nonsense security solution that defends and protects your WordPress sites against hackers and malicious bots, of all types. With our exclusive invisible "CAPTCHA"-replacement technology you can limit login attempts, block brute force attacks and prevent 100% bot comment SPAM.
24
 
25
  Our mission is to block bad IPs and requests before they can do any damage. Shield will block all automated Comment SPAM, brute force logins, plugin-vulnerability exploitation, malware injection, vulnerability scanning, password stuffing, contact form spam, and so much more. If you're disappointed with the performance of your current solution, give Shield a try - we promise that you won't be disappointed.
26
 
27
- **Use the power of the network**. ShieldNET is our new and exclusive network-based intelligence platform that draws-in information from all around the globe to help Shield Security plugins be smarter when assessing security threats and taking appropriate action. And with our new [Crowdsec partnership](https://shsec.io/l5) you've got even more data.
28
 
29
  #### Get the highest rated 5* Security Plugin for WordPress
30
 
@@ -36,19 +36,19 @@ Our Security solution isn't designed to scare you and make you feel unsafe.
36
 
37
  We're all about delivering powerful security without the scary stories and fear-based marketing. We're all about WordPress security without the marketing hype.
38
 
39
- Shield Security is full of great security tools that let it make intelligent decisions to protect your site and maintain your site security and integrity, so *you* don't have to.
40
 
41
  ## Your Goal And Ours: Peace Of Mind and Freedom From Hackers
42
 
43
- Bots are the #1 cause of WordPress security hacking.
44
 
45
- To stay protected, your WordPress Security must be smarter and remain uncomplicated. Shield Security is the only WordPress security plugin with our exclusive, built-in Bot Detection.
46
 
47
  ### 2 Key WordPress Security Strategies
48
 
49
  Shield Security uses 2 simple key strategies to protect your WordPress sites:
50
 
51
- 1. Prevention - Detect Bots, Intrusions, and Hacks
52
  1. Cure - Block Bad Bots and Repair Hacks
53
 
54
  #### Key Security Strategy #1: Hacking Prevention
@@ -209,9 +209,9 @@ Easy - we're just better! ;)
209
 
210
  Firstly, we don't modify any core WordPress or web hosting file. This is important and explains why randomly you upgrade your security plugin and your site dies.
211
 
212
- Ideally you shouldn't use this along side other Anti-SPAM plugins or security plugins. If there is a feature you need, please feel free to suggest it in the support forums.
213
 
214
- = My server has a securiy firewall, why do I need this plugin? =
215
 
216
  This plugin is an application layer firewall, not a server/network security firewall. It is designed to interpret web calls to your site to look for attempts to circumvent it and gain unauthorized access.
217
 
3
  Donate link: https://shsec.io/bw
4
  License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
+ Tags: limit login, malware scan, firewall, file scan, two factor authentication, intrusion prevention, security, login protection
7
  Requires at least: 3.7
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 6.1
11
+ Stable tag: 16.1.14
12
 
13
  Bad Bots Are Your #1 Security Risk. Are you playing whack-a-mole with malware & vulnerabilities? Discover the real security before marketing hype.
14
 
18
 
19
  **We need to stop our obsession with malware**. Malware scanning is important *after* your site is hacked. Get a security plugin that [prioritises security *protection* before the worst happens](https://shsec.io/ky).
20
 
21
+ Shield is the only security plugin for WordPress that fully prioritises protection over repair. With Shield, your site will start to block visitors as they probe your site looking for vulnerabilities, and before they can begin to do any damage.
22
 
23
+ **No other standalone WordPress security plugin** (including Wordfence, WP Cerber, Ninja Firewall, All-In-One Security) approaches security in this way. The 1st step in any good security system is Intrusion Detection/Prevention, the 2nd step is repair. Shield does both.
24
 
25
  Our mission is to block bad IPs and requests before they can do any damage. Shield will block all automated Comment SPAM, brute force logins, plugin-vulnerability exploitation, malware injection, vulnerability scanning, password stuffing, contact form spam, and so much more. If you're disappointed with the performance of your current solution, give Shield a try - we promise that you won't be disappointed.
26
 
27
+ **Use the power of the network**. ShieldNET is our new and exclusive network-based intelligence platform that draws-in information from all around the globe to help Shield Security plugins be smarter when assessing security threats and taking appropriate action. And with our new [Crowdsec partnership](https://shsec.io/l5) you've got even more data to make smarter decision.
28
 
29
  #### Get the highest rated 5* Security Plugin for WordPress
30
 
36
 
37
  We're all about delivering powerful security without the scary stories and fear-based marketing. We're all about WordPress security without the marketing hype.
38
 
39
+ Shield Security is full of powerful security mechanisms, making intelligent decisions to protect your site and maintain security and integrity, so *you don't have to*.
40
 
41
  ## Your Goal And Ours: Peace Of Mind and Freedom From Hackers
42
 
43
+ Bots are the #1 cause of WordPress security hacks and malware exploitation.
44
 
45
+ Better WordPress Security protection is smarter and uncomplicated.
46
 
47
  ### 2 Key WordPress Security Strategies
48
 
49
  Shield Security uses 2 simple key strategies to protect your WordPress sites:
50
 
51
+ 1. Prevention - Intrusion Prevention System: Detect Bots/Malicious IPs, WordPress Intrusions, and WordPress Hacks and Malware
52
  1. Cure - Block Bad Bots and Repair Hacks
53
 
54
  #### Key Security Strategy #1: Hacking Prevention
209
 
210
  Firstly, we don't modify any core WordPress or web hosting file. This is important and explains why randomly you upgrade your security plugin and your site dies.
211
 
212
+ Ideally you shouldn't use this alongside other Anti-SPAM plugins or security plugins. If there is a feature you need, please feel free to suggest it in the support forums.
213
 
214
+ = My server has a security firewall, why do I need this plugin? =
215
 
216
  This plugin is an application layer firewall, not a server/network security firewall. It is designed to interpret web calls to your site to look for attempts to circumvent it and gain unauthorized access.
217
 
src/lib/src/Modules/Data/Lib/CleanDatabases.php CHANGED
@@ -9,6 +9,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\{
9
  Traffic
10
  };
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
12
 
13
  class CleanDatabases extends ExecOnceModConsumer {
14
 
@@ -52,6 +53,27 @@ class CleanDatabases extends ExecOnceModConsumer {
52
  ->query();
53
  }
54
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
 
57
  private function cleanRequestLogs() {
9
  Traffic
10
  };
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
12
+ use FernleafSystems\Wordpress\Services\Services;
13
 
14
  class CleanDatabases extends ExecOnceModConsumer {
15
 
53
  ->query();
54
  }
55
  }
56
+
57
+ $this->cleanUserMeta();
58
+ }
59
+
60
+ /**
61
+ * Delete all the user meta rows where there is no corresponding User ID.
62
+ * WARNING: GREAT CARE MUST ALWAYS BE TAKEN WHEN EDITING THIS QUERY TO ENSURE WE DELETE ONLY FROM `meta`
63
+ */
64
+ private function cleanUserMeta() {
65
+ Services::WpDb()->doSql( sprintf(
66
+ 'DELETE `meta` FROM `%s` as `meta`
67
+ LEFT JOIN `%s` as `users` on `users`.`ID`=`meta`.`user_id` WHERE `users`.`ID` IS NULL',
68
+ $this->getCon()->getModule_Data()->getDbH_UserMeta()->getTableSchema()->table,
69
+ Services::WpDb()->getTable_Users()
70
+ ) );
71
+ // $res = Services::WpDb()->selectCustom( sprintf(
72
+ // 'SELECT `meta`.`user_id` as `meta_user_id`, `users`.`ID` as `wp_user_id` FROM `%s` as `meta`
73
+ // LEFT JOIN `%s` as `users` on `users`.`ID`=`meta`.`user_id` WHERE `users`.`ID` IS NULL',
74
+ // $userMetaData->getTableSchema()->table,
75
+ // Services::WpDb()->getTable_Users()
76
+ // ) );
77
  }
78
 
79
  private function cleanRequestLogs() {
src/lib/src/Modules/HackGuard/Lib/Snapshots/StorageDir.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class StorageDir {
9
+
10
+ use PluginControllerConsumer;
11
+
12
+ const SUFFIX_LENGTH = 16;
13
+
14
+ private $tempDir;
15
+
16
+ public function getTempDir() :string {
17
+ if ( is_null( $this->tempDir ) ) {
18
+ try {
19
+ $dir = $this->locateTempDir();
20
+ }
21
+ catch ( \Exception $e ) {
22
+ $dir = $this->getCon()->cache_dir_handler->buildSubDir( 'ptguard-'.wp_generate_password( self::SUFFIX_LENGTH, false ) );
23
+ }
24
+ $this->tempDir = $dir;
25
+ }
26
+ return $this->tempDir;
27
+ }
28
+
29
+ /**
30
+ * @throws \Exception
31
+ */
32
+ private function locateTempDir() :string {
33
+ $FS = Services::WpFs();
34
+ $dir = null;
35
+ foreach ( $FS->getAllFilesInDir( $this->getCon()->cache_dir_handler->dir() ) as $fileItem ) {
36
+ if ( $FS->isDir( $fileItem ) && preg_match( sprintf( '#^ptguard-[a-z0-9]{%s}$#i', self::SUFFIX_LENGTH ), basename( $fileItem ) ) ) {
37
+ $dir = $fileItem;
38
+ break;
39
+ }
40
+ }
41
+ if ( empty( $dir ) ) {
42
+ throw new \Exception( "Dir doesn't exist" );
43
+ }
44
+ return $dir;
45
+ }
46
+ }
src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StoreAction;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
@@ -11,38 +12,35 @@ class Base {
11
 
12
  private static $tempDir;
13
 
 
 
14
  protected function isTempDirAvailable() :bool {
15
  return !empty( $this->getTempDir() );
16
  }
17
 
18
  protected function getTempDir() :string {
19
- if ( empty( self::$tempDir ) ) {
20
- $FS = Services::WpFs();
21
- try {
22
- $dir = $this->findTempDir();
23
- if ( basename( $dir ) === 'ptguard' ) {
24
- $oldDir = $dir;
25
- $dir = $this->generateNewDirName();
26
- foreach ( [ 'plugins', 'themes' ] as $type ) {
27
- $FS->moveDirContents( path_join( $oldDir, $type ), path_join( $dir, $type ) );
28
- }
29
- $FS->deleteDir( $oldDir );
30
- }
31
- }
32
- catch ( \Exception $e ) {
33
- $dir = $this->generateNewDirName();
34
  }
35
- self::$tempDir = $dir;
36
  }
37
- return self::$tempDir;
 
 
 
 
38
  }
39
 
 
 
 
40
  private function generateNewDirName() :string {
41
  return $this->getCon()->cache_dir_handler->buildSubDir( 'ptguard-'.wp_generate_password( 16, false ) );
42
  }
43
 
44
  /**
45
  * @throws \Exception
 
46
  */
47
  private function findTempDir() :string {
48
  $FS = Services::WpFs();
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StoreAction;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StorageDir;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
12
 
13
  private static $tempDir;
14
 
15
+ private static $storageDir;
16
+
17
  protected function isTempDirAvailable() :bool {
18
  return !empty( $this->getTempDir() );
19
  }
20
 
21
  protected function getTempDir() :string {
22
+ { // TODO: remove this
23
+ if ( !empty( self::$tempDir ) ) {
24
+ return self::$tempDir;
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
 
26
  }
27
+
28
+ if ( empty( self::$storageDir ) ) {
29
+ self::$storageDir = ( new StorageDir() )->setCon( $this->getCon() );
30
+ }
31
+ return self::$storageDir->getTempDir();
32
  }
33
 
34
+ /**
35
+ * @deprecated 16.1.14
36
+ */
37
  private function generateNewDirName() :string {
38
  return $this->getCon()->cache_dir_handler->buildSubDir( 'ptguard-'.wp_generate_password( 16, false ) );
39
  }
40
 
41
  /**
42
  * @throws \Exception
43
+ * @deprecated 16.1.14
44
  */
45
  private function findTempDir() :string {
46
  $FS = Services::WpFs();
src/lib/src/Modules/HackGuard/Lib/Utility/CleanOutOldGuardFiles.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Utility;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StorageDir;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class CleanOutOldGuardFiles extends ExecOnceModConsumer {
10
+
11
+ protected function run( int $limit = 50 ) {
12
+ $FS = Services::WpFs();
13
+
14
+ $firstAcceptableDir = null;
15
+ $count = 0;
16
+ $root = $this->getCon()->cache_dir_handler->dir();
17
+ if ( !empty( $root ) ) {
18
+ foreach ( $FS->getAllFilesInDir( $root ) as $fileItem ) {
19
+ if ( $FS->isDir( $fileItem ) ) {
20
+ $dirBase = basename( $fileItem );
21
+ if ( $dirBase === 'ptguard' ) {
22
+ $FS->deleteDir( $fileItem );
23
+ }
24
+ elseif ( preg_match( sprintf( '#^ptguard-[a-z0-9]{%s}$#i', StorageDir::SUFFIX_LENGTH ), $dirBase ) ) {
25
+ if ( empty( $firstAcceptableDir ) ) {
26
+ $firstAcceptableDir = $fileItem;
27
+ }
28
+ else {
29
+ $count++;
30
+ $FS->deleteDir( $fileItem );
31
+ }
32
+ }
33
+ }
34
+
35
+ if ( $count > $limit ) {
36
+ break;
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
src/lib/src/Modules/HackGuard/ModCon.php CHANGED
@@ -220,6 +220,10 @@ class ModCon extends BaseShield\ModCon {
220
  ->setMod( $this )
221
  ->cleanStaleHashesOlderThan( $carbon->subWeek()->timestamp );
222
  }
 
 
 
 
223
  }
224
 
225
  /**
220
  ->setMod( $this )
221
  ->cleanStaleHashesOlderThan( $carbon->subWeek()->timestamp );
222
  }
223
+
224
+ ( new Lib\Utility\CleanOutOldGuardFiles() )
225
+ ->setMod( $this )
226
+ ->execute();
227
  }
228
 
229
  /**
src/lib/src/Modules/HackGuard/Upgrade.php CHANGED
@@ -3,9 +3,23 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StoreAction\MoveHashFiles;
 
6
 
7
  class Upgrade extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Upgrade {
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  protected function upgrade_1617() {
10
  ( new MoveHashFiles() )
11
  ->setMod( $this->getMod() )
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StoreAction\MoveHashFiles;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Utility\CleanOutOldGuardFiles;
7
 
8
  class Upgrade extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Upgrade {
9
 
10
+ /**
11
+ * Repairs the state where the PTGuard was recreating multiple directories for the ptguard files.
12
+ * Here we delete everything except the first valid PTGuard dir we find.
13
+ *
14
+ * Going forward from 16.1.14, we don't attempt to migrate. We should never have been repeatedly trying to migrate
15
+ * in the first place - it should have been an upgrade process.
16
+ */
17
+ protected function upgrade_16114() {
18
+ ( new CleanOutOldGuardFiles() )
19
+ ->setMod( $this->getMod() )
20
+ ->execute();
21
+ }
22
+
23
  protected function upgrade_1617() {
24
  ( new MoveHashFiles() )
25
  ->setMod( $this->getMod() )
src/lib/src/Modules/IPs/Lib/CrowdSec/Signals/EventsToSignals.php CHANGED
@@ -139,7 +139,7 @@ class EventsToSignals extends EventsListener {
139
  'scenario' => 'btloginfail',
140
  ],
141
  'bottrack_logininvalid' => [
142
- 'scenario' => 'btinvalidscript',
143
  ],
144
  'block_lostpassword' => [
145
  'scenario' => 'lostpasswordfail',
@@ -149,7 +149,6 @@ class EventsToSignals extends EventsListener {
149
  'scenario' => 'registerfail',
150
  'only_send_on_notbot_fail' => true,
151
  ],
152
-
153
  'bottrack_404' => [
154
  'scenario' => 'bt404',
155
  ],
@@ -160,7 +159,7 @@ class EventsToSignals extends EventsListener {
160
  'scenario' => 'btcheese',
161
  ],
162
  'bottrack_invalidscript' => [
163
- 'scenario' => 'btlogininvalid',
164
  ],
165
  'bottrack_useragent' => [
166
  'scenario' => 'btua',
139
  'scenario' => 'btloginfail',
140
  ],
141
  'bottrack_logininvalid' => [
142
+ 'scenario' => 'btlogininvalid',
143
  ],
144
  'block_lostpassword' => [
145
  'scenario' => 'lostpasswordfail',
149
  'scenario' => 'registerfail',
150
  'only_send_on_notbot_fail' => true,
151
  ],
 
152
  'bottrack_404' => [
153
  'scenario' => 'bt404',
154
  ],
159
  'scenario' => 'btcheese',
160
  ],
161
  'bottrack_invalidscript' => [
162
+ 'scenario' => 'btinvalidscript',
163
  ],
164
  'bottrack_useragent' => [
165
  'scenario' => 'btua',
src/lib/src/Modules/LoginGuard/Strings.php CHANGED
@@ -186,7 +186,13 @@ class Strings extends Base\Strings {
186
  $name = __( 'Hide WP Login & Admin', 'wp-simple-firewall' );
187
  $summary = __( 'Hide The WordPress Login And Admin Areas', 'wp-simple-firewall' );
188
  $desc = [
189
- __( 'Creating a path here will disable your wp-login.php', 'wp-simple-firewall' ),
 
 
 
 
 
 
190
  sprintf( __( 'Only letters and numbers are permitted: %s', 'wp-simple-firewall' ), '<strong>abc123</strong>' ),
191
  sprintf( __( 'Your current login URL is: %s', 'wp-simple-firewall' ), '<br /><strong>&nbsp;&nbsp;'.wp_login_url().'</strong>' )
192
  ];
@@ -196,14 +202,17 @@ class Strings extends Base\Strings {
196
  $name = __( 'WP Login & Admin Redirect', 'wp-simple-firewall' );
197
  $summary = __( 'Automatic Redirect URL For Hidden Pages', 'wp-simple-firewall' );
198
  $desc = [
199
- __( 'Automatically redirect requests to this location for the hidden pages.', 'wp-simple-firewall' ),
200
  sprintf( '%s: %s',
201
  __( 'Note', 'wp-simple-firewall' ),
202
- __( 'Leave this blank to serve a standard "404 Not Found" error page.', 'wp-simple-firewall' )
203
  ),
204
  sprintf( '%s: %s',
205
  __( 'Important', 'wp-simple-firewall' ),
206
- sprintf( __( 'Use relative paths e.g. %s redirects to your homepage.', 'wp-simple-firewall' ), '<code>/</code>' )
 
 
 
207
  ),
208
  ];
209
  break;
186
  $name = __( 'Hide WP Login & Admin', 'wp-simple-firewall' );
187
  $summary = __( 'Hide The WordPress Login And Admin Areas', 'wp-simple-firewall' );
188
  $desc = [
189
+ sprintf( '%s: %s',
190
+ __( 'Important', 'wp-simple-firewall' ),
191
+ sprintf( __( "This will cause %s and %s URLs to return HTTP 404 errors while you're not logged-in.", 'wp-simple-firewall' ),
192
+ '<code>/wp-admin/</code>',
193
+ '<code>/wp-login.php</code>'
194
+ )
195
+ ),
196
  sprintf( __( 'Only letters and numbers are permitted: %s', 'wp-simple-firewall' ), '<strong>abc123</strong>' ),
197
  sprintf( __( 'Your current login URL is: %s', 'wp-simple-firewall' ), '<br /><strong>&nbsp;&nbsp;'.wp_login_url().'</strong>' )
198
  ];
202
  $name = __( 'WP Login & Admin Redirect', 'wp-simple-firewall' );
203
  $summary = __( 'Automatic Redirect URL For Hidden Pages', 'wp-simple-firewall' );
204
  $desc = [
205
+ __( 'Automatically redirect here for any requests made to hidden pages.', 'wp-simple-firewall' ),
206
  sprintf( '%s: %s',
207
  __( 'Note', 'wp-simple-firewall' ),
208
+ sprintf( __( 'Leave this blank to serve a standard "%s" error page.', 'wp-simple-firewall' ), 'HTTP 404 Not Found' )
209
  ),
210
  sprintf( '%s: %s',
211
  __( 'Important', 'wp-simple-firewall' ),
212
+ sprintf( __( 'Use relative paths from your homepage URL e.g. %s redirects to your homepage (%s).', 'wp-simple-firewall' ),
213
+ '<code>/</code>',
214
+ sprintf( '<code>%s</code>', Services::WpGeneral()->getHomeUrl() )
215
+ )
216
  ),
217
  ];
218
  break;
src/lib/src/Modules/Plugin/Lib/Debug/Collate.php CHANGED
@@ -59,8 +59,8 @@ class Collate {
59
  }
60
  }
61
 
62
- $totalDisk = disk_total_space( ABSPATH );
63
- $freeDisk = disk_free_space( ABSPATH );
64
  try {
65
  $diff = ( new WorldTimeApi() )->diffServerWithReal();
66
  }
@@ -78,10 +78,10 @@ class Collate {
78
  'Server Name' => $req->server( 'SERVER_NAME' ),
79
  'Server Signature' => empty( $sig ) ? '-' : $sig,
80
  'Server Software' => empty( $soft ) ? '-' : $soft,
81
- 'Disk Space (Used/Available/Total)' => sprintf( '%s used out of %s (%s free)',
82
- FormatBytes::Format( $totalDisk - $freeDisk, 2, '' ),
83
- FormatBytes::Format( $totalDisk, 2, '' ),
84
- FormatBytes::Format( $freeDisk, 2, '' )
85
  )
86
  ];
87
  }
59
  }
60
  }
61
 
62
+ $totalDisk = function_exists( '\disk_total_space' ) ? \disk_total_space( ABSPATH ) : '-';
63
+ $freeDisk = function_exists( '\disk_free_space' ) ? \disk_free_space( ABSPATH ) : '-';
64
  try {
65
  $diff = ( new WorldTimeApi() )->diffServerWithReal();
66
  }
78
  'Server Name' => $req->server( 'SERVER_NAME' ),
79
  'Server Signature' => empty( $sig ) ? '-' : $sig,
80
  'Server Software' => empty( $soft ) ? '-' : $soft,
81
+ 'Disk Space' => sprintf( '%s used out of %s (unused: %s)',
82
+ ( is_numeric( $totalDisk ) && is_numeric( $freeDisk ) ) ? FormatBytes::Format( $totalDisk - $freeDisk, 2, '' ) : '-',
83
+ is_numeric( $totalDisk ) ? FormatBytes::Format( $totalDisk, 2, '' ) : '-',
84
+ is_numeric( $freeDisk ) ? FormatBytes::Format( $freeDisk, 2, '' ) : '-'
85
  )
86
  ];
87
  }
src/lib/src/Modules/UserManagement/Lib/Session/FindSessions.php CHANGED
@@ -10,12 +10,12 @@ class FindSessions {
10
  use ModConsumer;
11
 
12
  public function mostRecent() :array {
13
- return $this->lookupFromUserMeta();
14
  }
15
 
16
  public function byIP( string $ip ) :array {
17
  $sessions = [];
18
- foreach ( $this->lookupFromUserMeta( $ip ) as $userID => $userAtIP ) {
19
  $sessions[ $userID ] = array_map(
20
  function ( $sess ) use ( $userAtIP ) {
21
  $sess[ 'user_login' ] = $userAtIP[ 'user_login' ];
@@ -27,14 +27,9 @@ class FindSessions {
27
  return $sessions;
28
  }
29
 
30
- public function lookupFromUserMeta( string $ip = '', int $limit = 10, string $orderBy = '`user_meta`.last_login_at' ) :array {
31
  $modData = $this->getCon()->getModule_Data();
32
 
33
- $wheres = [];
34
- if ( !empty( $ip ) ) {
35
- $wheres[] = sprintf( "`ips`.ip=INET6_ATON('%s')", $ip );
36
- }
37
-
38
  $DB = Services::WpDb();
39
  $results = $DB->selectCustom(
40
  sprintf( 'SELECT `user_meta`.user_id as user_id,
@@ -66,4 +61,8 @@ class FindSessions {
66
 
67
  return $byUserIDs;
68
  }
 
 
 
 
69
  }
10
  use ModConsumer;
11
 
12
  public function mostRecent() :array {
13
+ return $this->lookupFromUserMeta( [ "`user_meta`.`last_login_at`!=0" ] );
14
  }
15
 
16
  public function byIP( string $ip ) :array {
17
  $sessions = [];
18
+ foreach ( $this->lookupFromUserMeta( [ $this->getWhere_IPEquals( $ip ) ] ) as $userID => $userAtIP ) {
19
  $sessions[ $userID ] = array_map(
20
  function ( $sess ) use ( $userAtIP ) {
21
  $sess[ 'user_login' ] = $userAtIP[ 'user_login' ];
27
  return $sessions;
28
  }
29
 
30
+ public function lookupFromUserMeta( array $wheres = [], int $limit = 10, string $orderBy = '`user_meta`.`last_login_at`' ) :array {
31
  $modData = $this->getCon()->getModule_Data();
32
 
 
 
 
 
 
33
  $DB = Services::WpDb();
34
  $results = $DB->selectCustom(
35
  sprintf( 'SELECT `user_meta`.user_id as user_id,
61
 
62
  return $byUserIDs;
63
  }
64
+
65
+ private function getWhere_IPEquals( string $ip ) :string {
66
+ return sprintf( "`ips`.ip=INET6_ATON('%s')", $ip );
67
+ }
68
  }
src/lib/src/Modules/UserManagement/Lib/Suspend/UserSuspendController.php CHANGED
@@ -83,127 +83,90 @@ class UserSuspendController extends ExecOnceModConsumer {
83
  /** @var Select $metaSelect */
84
  $metaSelect = $userMetaDB->getQuerySelector();
85
 
86
- if ( $opts->isSuspendManualEnabled() ) {
87
- $manual = array_map(
88
- function ( $res ) {
89
- return (int)array_pop( $res );
90
- },
91
- $metaSelect->filterByHardSuspended()
92
- ->setResultsAsVo( false )
93
- ->setSelectResultsFormat( ARRAY_A )
94
- ->setColumnsToSelect( [ 'user_id' ] )
95
- ->queryWithResult()
96
- );
97
- }
98
- else {
99
- $manual = [];
100
- }
101
-
102
- if ( $opts->isSuspendAutoPasswordEnabled() ) {
103
- $passwords = array_map(
104
- function ( $res ) {
105
- return (int)array_pop( $res );
106
- },
107
- $metaSelect->filterByPassExpired( $ts - $opts->getPassExpireTimeout() )
108
- ->setResultsAsVo( false )
109
- ->setSelectResultsFormat( ARRAY_A )
110
- ->setColumnsToSelect( [ 'user_id' ] )
111
- ->queryWithResult()
112
- );
113
- }
114
- else {
115
- $passwords = [];
116
- }
117
-
118
- if ( $opts->isSuspendAutoIdleEnabled() ) {
119
- $idle = array_map(
120
- function ( $res ) {
121
- return (int)array_pop( $res );
122
- },
123
- $metaSelect->filterByIdle( $ts - $opts->getSuspendAutoIdleTime() )
124
- ->setResultsAsVo( false )
125
- ->setSelectResultsFormat( ARRAY_A )
126
- ->setColumnsToSelect( [ 'user_id' ] )
127
- ->queryWithResult()
128
- );
129
- }
130
- else {
131
- $idle = [];
132
- }
133
-
134
- $cleaned = $this->cleanNonExistentUsers( array_merge( $manual, $passwords, $idle ) );
135
- if ( !empty( $cleaned ) ) {
136
- $manual = array_diff( $manual, $cleaned );
137
- $passwords = array_diff( $passwords, $cleaned );
138
- $idle = array_diff( $idle, $cleaned );
139
- }
140
-
141
- // Filter the user list database query
142
- add_filter( 'users_list_table_query_args', function ( $args ) use ( $manual, $idle, $passwords ) {
143
- $req = Services::Request();
144
- if ( is_array( $args ) ) {
145
- if ( !empty( $manual ) && $req->query( 'shield_users_suspended' ) ) {
146
- $args[ 'include' ] = $manual;
147
  }
148
- elseif ( !empty( $idle ) && $req->query( 'shield_users_idle' ) ) {
149
- $args[ 'include' ] = $idle;
150
- }
151
- elseif ( !empty( $passwords ) && $req->query( 'shield_users_pass' ) ) {
152
- $args[ 'include' ] = $passwords;
 
 
 
 
 
 
 
153
  }
154
- }
155
- return $args;
156
- } );
157
-
158
- // Provide the links above the table.
159
- add_filter( 'views_users', function ( $views ) use ( $manual, $idle, $passwords ) {
160
- $WP = Services::WpGeneral();
161
- if ( !empty( $manual ) ) {
162
- $views[ 'shield_users_suspended' ] = sprintf(
163
- '<a href="%s">%s <span class="count">(%s)</span></a>',
164
- URL::Build( $WP->getUrl_CurrentAdminPage(), [ 'shield_users_suspended' => 1 ] ),
165
- __( 'Manually Suspended', 'wp-simple-firewall' ), count( $manual )
166
- );
167
- }
168
 
169
- if ( !empty( $idle ) ) {
170
- $views[ 'shield_idle_users' ] = sprintf(
171
- '<a href="%s">%s <span class="count">(%s)</span></a>',
172
- URL::Build( $WP->getUrl_CurrentAdminPage(), [ 'shield_users_idle' => 1 ] ),
173
- __( 'Idle', 'wp-simple-firewall' ), count( $idle )
174
- );
175
- }
176
-
177
- if ( !empty( $passwords ) ) {
178
- $views[ 'shield_users_pass' ] = sprintf(
179
- '<a href="%s">%s <span class="count">(%s)</span></a>',
180
- URL::Build( $WP->getUrl_CurrentAdminPage(), [ 'shield_users_pass' => 1 ] ),
181
- __( 'Password Expired', 'wp-simple-firewall' ), count( $passwords )
182
- );
183
- }
184
 
185
- return $views;
186
- } );
187
- }
 
 
 
 
188
 
189
- private function cleanNonExistentUsers( array $IDs ) :array {
190
- $toClean = array_filter(
191
- array_unique( $IDs ),
192
- function ( $userID ) {
193
- return empty( Services::WpUsers()->getUserById( (int)$userID ) );
194
- }
195
- );
196
-
197
- if ( !empty( $toClean ) ) {
198
- $this->getCon()
199
- ->getModule_Data()
200
- ->getDbH_UserMeta()
201
- ->getQueryDeleter()
202
- ->addWhereIn( 'user_id', $toClean )
203
- ->query();
204
  }
205
-
206
- return $toClean;
207
  }
208
 
209
  public function addUserBlockOption( \WP_User $user ) {
83
  /** @var Select $metaSelect */
84
  $metaSelect = $userMetaDB->getQuerySelector();
85
 
86
+ $manual = $opts->isSuspendManualEnabled() ? $metaSelect->reset()->filterByHardSuspended()->count() : 0;
87
+ $passwords = $opts->isSuspendAutoPasswordEnabled() ?
88
+ $metaSelect->reset()->filterByPassExpired( $ts - $opts->getPassExpireTimeout() )->count() : 0;
89
+ $idle = $opts->isSuspendAutoPasswordEnabled() ?
90
+ $metaSelect->reset()->filterByPassExpired( $ts - $opts->getSuspendAutoIdleTime() )->count() : 0;
91
+
92
+ if ( $manual + $passwords + $idle > 0 ) {
93
+ // Filter the user list database query
94
+ add_filter( 'users_list_table_query_args', function ( $args ) use ( $manual, $idle, $passwords ) {
95
+ $req = Services::Request();
96
+ if ( is_array( $args ) ) {
97
+ /** @var UserManagement\Options $opts */
98
+ $opts = $this->getOptions();
99
+
100
+ /** @var Select $metaSelect */
101
+ $metaSelect = $this->getCon()
102
+ ->getModule_Data()
103
+ ->getDbH_UserMeta()
104
+ ->getQuerySelector();
105
+
106
+ if ( $manual > 0 && $req->query( 'shield_users_suspended' ) ) {
107
+ $filtered = true;
108
+ $metaSelect->filterByHardSuspended();
109
+ }
110
+ elseif ( $idle > 0 && $req->query( 'shield_users_idle' ) ) {
111
+ $filtered = true;
112
+ $metaSelect->filterByPassExpired( Services::Request()->ts() - $opts->getPassExpireTimeout() );
113
+ }
114
+ elseif ( $passwords > 0 && $req->query( 'shield_users_pass' ) ) {
115
+ $filtered = true;
116
+ $metaSelect->filterByIdle( Services::Request()->ts() - $opts->getSuspendAutoIdleTime() );
117
+ }
118
+ else {
119
+ $filtered = false;
120
+ }
121
+
122
+ if ( $filtered ) {
123
+ $idsToInclude = array_map(
124
+ function ( $res ) {
125
+ return (int)array_pop( $res );
126
+ },
127
+ $metaSelect->setResultsAsVo( false )
128
+ ->setSelectResultsFormat( ARRAY_A )
129
+ ->setColumnsToSelect( [ 'user_id' ] )
130
+ ->queryWithResult()
131
+ );
132
+ if ( !empty( $idsToInclude ) ) {
133
+ $args[ 'include' ] = $idsToInclude;
134
+ }
135
+ }
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
+ return $args;
138
+ } );
139
+
140
+ // Provide the links above the table.
141
+ add_filter( 'views_users', function ( $views ) use ( $manual, $idle, $passwords ) {
142
+ $WP = Services::WpGeneral();
143
+ if ( $manual > 0 ) {
144
+ $views[ 'shield_users_suspended' ] = sprintf(
145
+ '<a href="%s">%s <span class="count">(%s)</span></a>',
146
+ URL::Build( $WP->getUrl_CurrentAdminPage(), [ 'shield_users_suspended' => 1 ] ),
147
+ __( 'Manually Suspended', 'wp-simple-firewall' ), $manual
148
+ );
149
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
+ if ( $idle > 0 ) {
152
+ $views[ 'shield_idle_users' ] = sprintf(
153
+ '<a href="%s">%s <span class="count">(%s)</span></a>',
154
+ URL::Build( $WP->getUrl_CurrentAdminPage(), [ 'shield_users_idle' => 1 ] ),
155
+ __( 'Idle', 'wp-simple-firewall' ), $idle
156
+ );
157
+ }
 
 
 
 
 
 
 
 
158
 
159
+ if ( $passwords > 0 ) {
160
+ $views[ 'shield_users_pass' ] = sprintf(
161
+ '<a href="%s">%s <span class="count">(%s)</span></a>',
162
+ URL::Build( $WP->getUrl_CurrentAdminPage(), [ 'shield_users_pass' => 1 ] ),
163
+ __( 'Password Expired', 'wp-simple-firewall' ), $passwords
164
+ );
165
+ }
166
 
167
+ return $views;
168
+ } );
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  }
 
 
170
  }
171
 
172
  public function addUserBlockOption( \WP_User $user ) {
src/lib/vendor/composer/autoload_classmap.php CHANGED
@@ -452,6 +452,7 @@ return array(
452
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Build\\BuildHashesFromDir' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/Build/BuildHashesFromDir.php',
453
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\CrowdSourced\\SubmitHashes' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/CrowdSourced/SubmitHashes.php',
454
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\FindAssetsToSnap' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/FindAssetsToSnap.php',
 
455
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Store' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/Store.php',
456
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Base' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php',
457
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
452
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Build\\BuildHashesFromDir' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/Build/BuildHashesFromDir.php',
453
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\CrowdSourced\\SubmitHashes' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/CrowdSourced/SubmitHashes.php',
454
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\FindAssetsToSnap' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/FindAssetsToSnap.php',
455
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StorageDir' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StorageDir.php',
456
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Store' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/Store.php',
457
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Base' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php',
458
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
src/lib/vendor/composer/autoload_static.php CHANGED
@@ -647,6 +647,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
647
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Build\\BuildHashesFromDir' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/Build/BuildHashesFromDir.php',
648
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\CrowdSourced\\SubmitHashes' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/CrowdSourced/SubmitHashes.php',
649
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\FindAssetsToSnap' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/FindAssetsToSnap.php',
 
650
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Store' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/Store.php',
651
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php',
652
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
647
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Build\\BuildHashesFromDir' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/Build/BuildHashesFromDir.php',
648
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\CrowdSourced\\SubmitHashes' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/CrowdSourced/SubmitHashes.php',
649
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\FindAssetsToSnap' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/FindAssetsToSnap.php',
650
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StorageDir' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StorageDir.php',
651
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Store' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/Store.php',
652
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php',
653
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
src/lib/vendor/composer/installed.json CHANGED
@@ -245,17 +245,17 @@
245
  },
246
  {
247
  "name": "fernleafsystems/wordpress-plugin-core",
248
- "version": "1.1.0",
249
- "version_normalized": "1.1.0.0",
250
  "source": {
251
  "type": "git",
252
  "url": "git@gitlab.com:fernleafsystems/wordpress/wordpress-plugin-core.git",
253
- "reference": "a478148756e89341f360206ec10f7dd85bbebced"
254
  },
255
  "dist": {
256
  "type": "zip",
257
- "url": "https://gitlab.com/api/v4/projects/fernleafsystems%2Fwordpress%2Fwordpress-plugin-core/repository/archive.zip?sha=a478148756e89341f360206ec10f7dd85bbebced",
258
- "reference": "a478148756e89341f360206ec10f7dd85bbebced",
259
  "shasum": ""
260
  },
261
  "require": {
@@ -265,7 +265,7 @@
265
  "nullpunkt/lz-string-php": "^1.3",
266
  "php": ">=7.0"
267
  },
268
- "time": "2022-05-30T10:32:02+00:00",
269
  "type": "library",
270
  "installation-source": "dist",
271
  "autoload": {
245
  },
246
  {
247
  "name": "fernleafsystems/wordpress-plugin-core",
248
+ "version": "1.1.1",
249
+ "version_normalized": "1.1.1.0",
250
  "source": {
251
  "type": "git",
252
  "url": "git@gitlab.com:fernleafsystems/wordpress/wordpress-plugin-core.git",
253
+ "reference": "8156e7de0ea7315dfa6f9b6ddd9e47e2806dd928"
254
  },
255
  "dist": {
256
  "type": "zip",
257
+ "url": "https://gitlab.com/api/v4/projects/fernleafsystems%2Fwordpress%2Fwordpress-plugin-core/repository/archive.zip?sha=8156e7de0ea7315dfa6f9b6ddd9e47e2806dd928",
258
+ "reference": "8156e7de0ea7315dfa6f9b6ddd9e47e2806dd928",
259
  "shasum": ""
260
  },
261
  "require": {
265
  "nullpunkt/lz-string-php": "^1.3",
266
  "php": ">=7.0"
267
  },
268
+ "time": "2022-10-28T12:25:35+00:00",
269
  "type": "library",
270
  "installation-source": "dist",
271
  "autoload": {
src/lib/vendor/composer/installed.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php return array(
2
  'root' => array(
3
- 'pretty_version' => 'dev-master',
4
- 'version' => 'dev-master',
5
  'type' => 'library',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
- 'reference' => 'e7e5d1652fb897530552e6b174a1b403f0df014e',
9
  'name' => 'apto-shield/requirements',
10
  'dev' => true,
11
  ),
@@ -20,12 +20,12 @@
20
  'dev_requirement' => false,
21
  ),
22
  'apto-shield/requirements' => array(
23
- 'pretty_version' => 'dev-master',
24
- 'version' => 'dev-master',
25
  'type' => 'library',
26
  'install_path' => __DIR__ . '/../../',
27
  'aliases' => array(),
28
- 'reference' => 'e7e5d1652fb897530552e6b174a1b403f0df014e',
29
  'dev_requirement' => false,
30
  ),
31
  'christian-riesen/base32' => array(
@@ -65,12 +65,12 @@
65
  'dev_requirement' => false,
66
  ),
67
  'fernleafsystems/wordpress-plugin-core' => array(
68
- 'pretty_version' => '1.1.0',
69
- 'version' => '1.1.0.0',
70
  'type' => 'library',
71
  'install_path' => __DIR__ . '/../fernleafsystems/wordpress-plugin-core',
72
  'aliases' => array(),
73
- 'reference' => 'a478148756e89341f360206ec10f7dd85bbebced',
74
  'dev_requirement' => false,
75
  ),
76
  'fernleafsystems/wordpress-services' => array(
1
  <?php return array(
2
  'root' => array(
3
+ 'pretty_version' => 'dev-develop',
4
+ 'version' => 'dev-develop',
5
  'type' => 'library',
6
  'install_path' => __DIR__ . '/../../',
7
  'aliases' => array(),
8
+ 'reference' => '936fbb48ff742962d5034676fa847161e34d202c',
9
  'name' => 'apto-shield/requirements',
10
  'dev' => true,
11
  ),
20
  'dev_requirement' => false,
21
  ),
22
  'apto-shield/requirements' => array(
23
+ 'pretty_version' => 'dev-develop',
24
+ 'version' => 'dev-develop',
25
  'type' => 'library',
26
  'install_path' => __DIR__ . '/../../',
27
  'aliases' => array(),
28
+ 'reference' => '936fbb48ff742962d5034676fa847161e34d202c',
29
  'dev_requirement' => false,
30
  ),
31
  'christian-riesen/base32' => array(
65
  'dev_requirement' => false,
66
  ),
67
  'fernleafsystems/wordpress-plugin-core' => array(
68
+ 'pretty_version' => '1.1.1',
69
+ 'version' => '1.1.1.0',
70
  'type' => 'library',
71
  'install_path' => __DIR__ . '/../fernleafsystems/wordpress-plugin-core',
72
  'aliases' => array(),
73
+ 'reference' => '8156e7de0ea7315dfa6f9b6ddd9e47e2806dd928',
74
  'dev_requirement' => false,
75
  ),
76
  'fernleafsystems/wordpress-services' => array(
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/BaseQuery.php CHANGED
@@ -55,11 +55,6 @@ abstract class BaseQuery {
55
  protected function customInit() {
56
  }
57
 
58
- /**
59
- * @param string $columnLeft
60
- * @param string $columnRight
61
- * @param string $operator
62
- */
63
  public function addWhereCompareColumns( string $columnLeft, string $columnRight, string $operator = '=' ) {
64
  $schema = $this->getDbH()->getTableSchema();
65
  if ( !$schema->hasColumn( $columnLeft ) ) {
@@ -73,9 +68,7 @@ abstract class BaseQuery {
73
  }
74
 
75
  /**
76
- * @param string $column
77
  * @param string|array $value
78
- * @param string $operator
79
  * @return $this
80
  */
81
  public function addWhere( string $column, $value, string $operator = '=' ) {
@@ -104,7 +97,6 @@ abstract class BaseQuery {
104
  }
105
 
106
  /**
107
- * @param array $where
108
  * @return $this
109
  */
110
  public function addRawWhere( array $where ) {
@@ -114,7 +106,6 @@ abstract class BaseQuery {
114
  }
115
 
116
  /**
117
- * @param string $column
118
  * @param mixed $mValue
119
  * @return $this
120
  */
@@ -123,7 +114,6 @@ abstract class BaseQuery {
123
  }
124
 
125
  /**
126
- * @param string $column
127
  * @param array $values
128
  * @return $this
129
  */
@@ -135,7 +125,6 @@ abstract class BaseQuery {
135
  }
136
 
137
  /**
138
- * @param string $column
139
  * @param array $values
140
  * @return $this
141
  */
@@ -147,7 +136,6 @@ abstract class BaseQuery {
147
  }
148
 
149
  /**
150
- * @param string $column
151
  * @param string $like
152
  * @param string $left
153
  * @param string $right
@@ -215,7 +203,7 @@ abstract class BaseQuery {
215
  * @return int
216
  */
217
  protected function getOffset() {
218
- return (int)$this->getLimit()*( $this->getPage() - 1 );
219
  }
220
 
221
  public function buildWhere() :string {
@@ -262,7 +250,6 @@ abstract class BaseQuery {
262
  }
263
 
264
  /**
265
- * @param int $ts
266
  * @return $this
267
  */
268
  public function filterByBoundary_Day( int $ts ) {
@@ -271,7 +258,6 @@ abstract class BaseQuery {
271
  }
272
 
273
  /**
274
- * @param int $ts
275
  * @return $this
276
  */
277
  public function filterByBoundary_Hour( int $ts ) {
@@ -280,7 +266,6 @@ abstract class BaseQuery {
280
  }
281
 
282
  /**
283
- * @param int $ts
284
  * @return $this
285
  */
286
  public function filterByBoundary_Month( int $ts ) {
@@ -289,7 +274,6 @@ abstract class BaseQuery {
289
  }
290
 
291
  /**
292
- * @param int $ts
293
  * @return $this
294
  */
295
  public function filterByBoundary_Week( int $ts ) {
@@ -298,7 +282,6 @@ abstract class BaseQuery {
298
  }
299
 
300
  /**
301
- * @param int $ts
302
  * @return $this
303
  */
304
  public function filterByBoundary_Year( int $ts ) {
@@ -307,7 +290,6 @@ abstract class BaseQuery {
307
  }
308
 
309
  /**
310
- * @param array $ids
311
  * @return $this
312
  */
313
  public function filterByIDs( array $ids ) {
55
  protected function customInit() {
56
  }
57
 
 
 
 
 
 
58
  public function addWhereCompareColumns( string $columnLeft, string $columnRight, string $operator = '=' ) {
59
  $schema = $this->getDbH()->getTableSchema();
60
  if ( !$schema->hasColumn( $columnLeft ) ) {
68
  }
69
 
70
  /**
 
71
  * @param string|array $value
 
72
  * @return $this
73
  */
74
  public function addWhere( string $column, $value, string $operator = '=' ) {
97
  }
98
 
99
  /**
 
100
  * @return $this
101
  */
102
  public function addRawWhere( array $where ) {
106
  }
107
 
108
  /**
 
109
  * @param mixed $mValue
110
  * @return $this
111
  */
114
  }
115
 
116
  /**
 
117
  * @param array $values
118
  * @return $this
119
  */
125
  }
126
 
127
  /**
 
128
  * @param array $values
129
  * @return $this
130
  */
136
  }
137
 
138
  /**
 
139
  * @param string $like
140
  * @param string $left
141
  * @param string $right
203
  * @return int
204
  */
205
  protected function getOffset() {
206
+ return $this->getLimit()*( $this->getPage() - 1 );
207
  }
208
 
209
  public function buildWhere() :string {
250
  }
251
 
252
  /**
 
253
  * @return $this
254
  */
255
  public function filterByBoundary_Day( int $ts ) {
258
  }
259
 
260
  /**
 
261
  * @return $this
262
  */
263
  public function filterByBoundary_Hour( int $ts ) {
266
  }
267
 
268
  /**
 
269
  * @return $this
270
  */
271
  public function filterByBoundary_Month( int $ts ) {
274
  }
275
 
276
  /**
 
277
  * @return $this
278
  */
279
  public function filterByBoundary_Week( int $ts ) {
282
  }
283
 
284
  /**
 
285
  * @return $this
286
  */
287
  public function filterByBoundary_Year( int $ts ) {
290
  }
291
 
292
  /**
 
293
  * @return $this
294
  */
295
  public function filterByIDs( array $ids ) {
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/Delete.php CHANGED
@@ -26,13 +26,11 @@ class Delete extends BaseQuery {
26
  $success = $updater->query();
27
  $this->lastQueryResult = $updater->getLastQueryResult();
28
  }
 
 
 
29
  else {
30
- if ( empty( $this->buildWhere() ) && !$this->allowEmptyWhere ) {
31
- error_log( sprintf( 'Attempt to DELETE with empty WHERE with query: "%s"', $this->buildQuery() ) );
32
- }
33
- else {
34
- $success = parent::execQuerySql();
35
- }
36
  }
37
  return $success;
38
  }
26
  $success = $updater->query();
27
  $this->lastQueryResult = $updater->getLastQueryResult();
28
  }
29
+ elseif ( empty( $this->buildWhere() ) && !$this->allowEmptyWhere ) {
30
+ error_log( sprintf( 'Attempt to DELETE with empty WHERE with query: "%s"', $this->buildQuery() ) );
31
+ }
32
  else {
33
+ $success = parent::execQuerySql();
 
 
 
 
 
34
  }
35
  return $success;
36
  }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/Insert.php CHANGED
@@ -70,7 +70,7 @@ class Insert extends BaseQuery {
70
  */
71
  public function setInsertData( array $data ) {
72
  $this->insertData = array_intersect_key(
73
- is_array( $data ) ? $data : [],
74
  array_flip( $this->getDbH()->getTableSchema()->getColumnNames() )
75
  );
76
  return $this;
70
  */
71
  public function setInsertData( array $data ) {
72
  $this->insertData = array_intersect_key(
73
+ $data,
74
  array_flip( $this->getDbH()->getTableSchema()->getColumnNames() )
75
  );
76
  return $this;
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/Update.php CHANGED
@@ -93,11 +93,9 @@ class Update extends Insert {
93
  }
94
 
95
  /**
96
- * @param int $id
97
- * @param array $updateData
98
  * @return bool true is success or no update necessary
99
  */
100
- public function updateById( int $id, array $updateData = [] ) {
101
  return $this->setUpdateId( $id )
102
  ->setUpdateData( $updateData )
103
  ->query();
93
  }
94
 
95
  /**
 
 
96
  * @return bool true is success or no update necessary
97
  */
98
+ public function updateById( int $id, array $updateData = [] ) :bool {
99
  return $this->setUpdateId( $id )
100
  ->setUpdateData( $updateData )
101
  ->query();
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Common/Iterator.php CHANGED
@@ -8,9 +8,10 @@ use FernleafSystems\Wordpress\Plugin\Core\Databases\Base\Select;
8
 
9
  class Iterator extends AbstractPagedIterator {
10
 
11
- const PAGE_LIMIT = 50;
12
  use HandlerConsumer;
13
 
 
 
14
  /**
15
  * @var Select|mixed
16
  */
@@ -53,13 +54,13 @@ class Iterator extends AbstractPagedIterator {
53
  * @return array
54
  */
55
  public function getPage( $page ) {
56
- $aParams = $this->getFinalQueryFilters();
57
 
58
  $this->getSelector()
59
  ->setResultsAsVo( true )
60
  ->setPage( $page + 1 ) // Pages start at 1, not zero.
61
  ->setLimit( $this->getPageSize() )
62
- ->setOrderBy( $aParams[ 'orderby' ], $aParams[ 'order' ] );
63
 
64
  return $this->runQuery();
65
  }
@@ -95,11 +96,11 @@ class Iterator extends AbstractPagedIterator {
95
  * @return Record[]|mixed[]
96
  */
97
  protected function runQuery() {
98
- return ( clone $this->getSelector() )->query();
99
  }
100
 
101
  protected function runQueryCount() :int {
102
- return (int)( clone $this->getSelector() )->count();
103
  }
104
 
105
  /**
8
 
9
  class Iterator extends AbstractPagedIterator {
10
 
 
11
  use HandlerConsumer;
12
 
13
+ const PAGE_LIMIT = 50;
14
+
15
  /**
16
  * @var Select|mixed
17
  */
54
  * @return array
55
  */
56
  public function getPage( $page ) {
57
+ $params = $this->getFinalQueryFilters();
58
 
59
  $this->getSelector()
60
  ->setResultsAsVo( true )
61
  ->setPage( $page + 1 ) // Pages start at 1, not zero.
62
  ->setLimit( $this->getPageSize() )
63
+ ->setOrderBy( $params[ 'orderby' ], $params[ 'order' ] );
64
 
65
  return $this->runQuery();
66
  }
96
  * @return Record[]|mixed[]
97
  */
98
  protected function runQuery() {
99
+ return ( clone $this->getSelector() )->queryWithResult();
100
  }
101
 
102
  protected function runQueryCount() :int {
103
+ return ( clone $this->getSelector() )->count();
104
  }
105
 
106
  /**
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Common/SubQueryLoader.php CHANGED
@@ -18,7 +18,7 @@ class SubQueryLoader {
18
 
19
  public function loadClass( string $class ) {
20
  /** @var BaseQuery $o */
21
- $o = new $class;
22
  return method_exists( $o, 'setDbH' ) ? $o->setDbH( $this->getDbHandler() ) : $o;
23
  }
24
 
18
 
19
  public function loadClass( string $class ) {
20
  /** @var BaseQuery $o */
21
+ $o = new $class();
22
  return method_exists( $o, 'setDbH' ) ? $o->setDbH( $this->getDbHandler() ) : $o;
23
  }
24
 
src/lib/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Monolog package.
5
+ *
6
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Monolog\Handler;
13
+
14
+ use Monolog\Logger;
15
+ use Monolog\ResettableInterface;
16
+ use Monolog\Formatter\FormatterInterface;
17
+
18
+ /**
19
+ * Buffers all records until closing the handler and then pass them as batch.
20
+ *
21
+ * This is useful for a MailHandler to send only one mail per request instead of
22
+ * sending one per log message.
23
+ *
24
+ * @author Christophe Coevoet <stof@notk.org>
25
+ */
26
+ class BufferHandler extends AbstractHandler
27
+ {
28
+ protected $handler;
29
+ protected $bufferSize = 0;
30
+ protected $bufferLimit;
31
+ protected $flushOnOverflow;
32
+ protected $buffer = array();
33
+ protected $initialized = false;
34
+
35
+ /**
36
+ * @param HandlerInterface $handler Handler.
37
+ * @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
38
+ * @param int $level The minimum logging level at which this handler will be triggered
39
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
40
+ * @param bool $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
41
+ */
42
+ public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
43
+ {
44
+ parent::__construct($level, $bubble);
45
+ $this->handler = $handler;
46
+ $this->bufferLimit = (int) $bufferLimit;
47
+ $this->flushOnOverflow = $flushOnOverflow;
48
+ }
49
+
50
+ /**
51
+ * {@inheritdoc}
52
+ */
53
+ public function handle(array $record)
54
+ {
55
+ if ($record['level'] < $this->level) {
56
+ return false;
57
+ }
58
+
59
+ if (!$this->initialized) {
60
+ // __destructor() doesn't get called on Fatal errors
61
+ register_shutdown_function(array($this, 'close'));
62
+ $this->initialized = true;
63
+ }
64
+
65
+ if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) {
66
+ if ($this->flushOnOverflow) {
67
+ $this->flush();
68
+ } else {
69
+ array_shift($this->buffer);
70
+ $this->bufferSize--;
71
+ }
72
+ }
73
+
74
+ if ($this->processors) {
75
+ foreach ($this->processors as $processor) {
76
+ $record = call_user_func($processor, $record);
77
+ }
78
+ }
79
+
80
+ $this->buffer[] = $record;
81
+ $this->bufferSize++;
82
+
83
+ return false === $this->bubble;
84
+ }
85
+
86
+ public function flush()
87
+ {
88
+ if ($this->bufferSize === 0) {
89
+ return;
90
+ }
91
+
92
+ $this->handler->handleBatch($this->buffer);
93
+ $this->clear();
94
+ }
95
+
96
+ public function __destruct()
97
+ {
98
+ // suppress the parent behavior since we already have register_shutdown_function()
99
+ // to call close(), and the reference contained there will prevent this from being
100
+ // GC'd until the end of the request
101
+ }
102
+
103
+ /**
104
+ * {@inheritdoc}
105
+ */
106
+ public function close()
107
+ {
108
+ $this->flush();
109
+ }
110
+
111
+ /**
112
+ * Clears the buffer without flushing any messages down to the wrapped handler.
113
+ */
114
+ public function clear()
115
+ {
116
+ $this->bufferSize = 0;
117
+ $this->buffer = array();
118
+ }
119
+
120
+ public function reset()
121
+ {
122
+ $this->flush();
123
+
124
+ parent::reset();
125
+
126
+ if ($this->handler instanceof ResettableInterface) {
127
+ $this->handler->reset();
128
+ }
129
+ }
130
+
131
+ /**
132
+ * {@inheritdoc}
133
+ */
134
+ public function setFormatter(FormatterInterface $formatter)
135
+ {
136
+ $this->handler->setFormatter($formatter);
137
+
138
+ return $this;
139
+ }
140
+
141
+ /**
142
+ * {@inheritdoc}
143
+ */
144
+ public function getFormatter()
145
+ {
146
+ return $this->handler->getFormatter();
147
+ }
148
+ }
src/lib/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Monolog package.
5
+ *
6
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Monolog\Handler;
13
+
14
+ /**
15
+ * Base class for all mail handlers
16
+ *
17
+ * @author Gyula Sallai
18
+ */
19
+ abstract class MailHandler extends AbstractProcessingHandler
20
+ {
21
+ /**
22
+ * {@inheritdoc}
23
+ */
24
+ public function handleBatch(array $records)
25
+ {
26
+ $messages = array();
27
+
28
+ foreach ($records as $record) {
29
+ if ($record['level'] < $this->level) {
30
+ continue;
31
+ }
32
+ $messages[] = $this->processRecord($record);
33
+ }
34
+
35
+ if (!empty($messages)) {
36
+ $this->send((string) $this->getFormatter()->formatBatch($messages), $messages);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Send a mail with the given content
42
+ *
43
+ * @param string $content formatted email body to be sent
44
+ * @param array $records the array of log records that formed this content
45
+ */
46
+ abstract protected function send($content, array $records);
47
+
48
+ /**
49
+ * {@inheritdoc}
50
+ */
51
+ protected function write(array $record)
52
+ {
53
+ $this->send((string) $record['formatted'], array($record));
54
+ }
55
+
56
+ protected function getHighestRecord(array $records)
57
+ {
58
+ $highestRecord = null;
59
+ foreach ($records as $record) {
60
+ if ($highestRecord === null || $highestRecord['level'] < $record['level']) {
61
+ $highestRecord = $record;
62
+ }
63
+ }
64
+
65
+ return $highestRecord;
66
+ }
67
+ }
src/lib/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Monolog package.
5
+ *
6
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Monolog\Handler;
13
+
14
+ use Monolog\Logger;
15
+
16
+ /**
17
+ * Blackhole
18
+ *
19
+ * Any record it can handle will be thrown away. This can be used
20
+ * to put on top of an existing stack to override it temporarily.
21
+ *
22
+ * @author Jordi Boggiano <j.boggiano@seld.be>
23
+ */
24
+ class NullHandler extends AbstractHandler
25
+ {
26
+ /**
27
+ * @param int $level The minimum logging level at which this handler will be triggered
28
+ */
29
+ public function __construct($level = Logger::DEBUG)
30
+ {
31
+ parent::__construct($level, false);
32
+ }
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ */
37
+ public function handle(array $record)
38
+ {
39
+ if ($record['level'] < $this->level) {
40
+ return false;
41
+ }
42
+
43
+ return true;
44
+ }
45
+ }
src/lib/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Monolog package.
5
+ *
6
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Monolog\Handler;
13
+
14
+ use Monolog\Logger;
15
+ use Monolog\Utils;
16
+
17
+ /**
18
+ * Stores logs to files that are rotated every day and a limited number of files are kept.
19
+ *
20
+ * This rotation is only intended to be used as a workaround. Using logrotate to
21
+ * handle the rotation is strongly encouraged when you can use it.
22
+ *
23
+ * @author Christophe Coevoet <stof@notk.org>
24
+ * @author Jordi Boggiano <j.boggiano@seld.be>
25
+ */
26
+ class RotatingFileHandler extends StreamHandler
27
+ {
28
+ const FILE_PER_DAY = 'Y-m-d';
29
+ const FILE_PER_MONTH = 'Y-m';
30
+ const FILE_PER_YEAR = 'Y';
31
+
32
+ protected $filename;
33
+ protected $maxFiles;
34
+ protected $mustRotate;
35
+ protected $nextRotation;
36
+ protected $filenameFormat;
37
+ protected $dateFormat;
38
+
39
+ /**
40
+ * @param string $filename
41
+ * @param int $maxFiles The maximal amount of files to keep (0 means unlimited)
42
+ * @param int $level The minimum logging level at which this handler will be triggered
43
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
44
+ * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
45
+ * @param bool $useLocking Try to lock log file before doing any writes
46
+ */
47
+ public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
48
+ {
49
+ $this->filename = Utils::canonicalizePath($filename);
50
+ $this->maxFiles = (int) $maxFiles;
51
+ $this->nextRotation = new \DateTime('tomorrow');
52
+ $this->filenameFormat = '{filename}-{date}';
53
+ $this->dateFormat = 'Y-m-d';
54
+
55
+ parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking);
56
+ }
57
+
58
+ /**
59
+ * {@inheritdoc}
60
+ */
61
+ public function close()
62
+ {
63
+ parent::close();
64
+
65
+ if (true === $this->mustRotate) {
66
+ $this->rotate();
67
+ }
68
+ }
69
+
70
+ /**
71
+ * {@inheritdoc}
72
+ */
73
+ public function reset()
74
+ {
75
+ parent::reset();
76
+
77
+ if (true === $this->mustRotate) {
78
+ $this->rotate();
79
+ }
80
+ }
81
+
82
+ public function setFilenameFormat($filenameFormat, $dateFormat)
83
+ {
84
+ if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) {
85
+ trigger_error(
86
+ 'Invalid date format - format must be one of '.
87
+ 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '.
88
+ 'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the '.
89
+ 'date formats using slashes, underscores and/or dots instead of dashes.',
90
+ E_USER_DEPRECATED
91
+ );
92
+ }
93
+ if (substr_count($filenameFormat, '{date}') === 0) {
94
+ trigger_error(
95
+ 'Invalid filename format - format should contain at least `{date}`, because otherwise rotating is impossible.',
96
+ E_USER_DEPRECATED
97
+ );
98
+ }
99
+ $this->filenameFormat = $filenameFormat;
100
+ $this->dateFormat = $dateFormat;
101
+ $this->url = $this->getTimedFilename();
102
+ $this->close();
103
+ }
104
+
105
+ /**
106
+ * {@inheritdoc}
107
+ */
108
+ protected function write(array $record)
109
+ {
110
+ // on the first record written, if the log is new, we should rotate (once per day)
111
+ if (null === $this->mustRotate) {
112
+ $this->mustRotate = !file_exists($this->url);
113
+ }
114
+
115
+ if ($this->nextRotation < $record['datetime']) {
116
+ $this->mustRotate = true;
117
+ $this->close();
118
+ }
119
+
120
+ parent::write($record);
121
+ }
122
+
123
+ /**
124
+ * Rotates the files.
125
+ */
126
+ protected function rotate()
127
+ {
128
+ // update filename
129
+ $this->url = $this->getTimedFilename();
130
+ $this->nextRotation = new \DateTime('tomorrow');
131
+
132
+ // skip GC of old logs if files are unlimited
133
+ if (0 === $this->maxFiles) {
134
+ return;
135
+ }
136
+
137
+ $logFiles = glob($this->getGlobPattern());
138
+ if ($this->maxFiles >= count($logFiles)) {
139
+ // no files to remove
140
+ return;
141
+ }
142
+
143
+ // Sorting the files by name to remove the older ones
144
+ usort($logFiles, function ($a, $b) {
145
+ return strcmp($b, $a);
146
+ });
147
+
148
+ foreach (array_slice($logFiles, $this->maxFiles) as $file) {
149
+ if (is_writable($file)) {
150
+ // suppress errors here as unlink() might fail if two processes
151
+ // are cleaning up/rotating at the same time
152
+ set_error_handler(function ($errno, $errstr, $errfile, $errline) {});
153
+ unlink($file);
154
+ restore_error_handler();
155
+ }
156
+ }
157
+
158
+ $this->mustRotate = false;
159
+ }
160
+
161
+ protected function getTimedFilename()
162
+ {
163
+ $fileInfo = pathinfo($this->filename);
164
+ $timedFilename = str_replace(
165
+ array('{filename}', '{date}'),
166
+ array($fileInfo['filename'], date($this->dateFormat)),
167
+ $fileInfo['dirname'] . '/' . $this->filenameFormat
168
+ );
169
+
170
+ if (!empty($fileInfo['extension'])) {
171
+ $timedFilename .= '.'.$fileInfo['extension'];
172
+ }
173
+
174
+ return $timedFilename;
175
+ }
176
+
177
+ protected function getGlobPattern()
178
+ {
179
+ $fileInfo = pathinfo($this->filename);
180
+ $glob = str_replace(
181
+ array('{filename}', '{date}'),
182
+ array($fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'),
183
+ $fileInfo['dirname'] . '/' . $this->filenameFormat
184
+ );
185
+ if (!empty($fileInfo['extension'])) {
186
+ $glob .= '.'.$fileInfo['extension'];
187
+ }
188
+
189
+ return $glob;
190
+ }
191
+ }