Version Description
Current Release = Released: 11th June, 2018 - Release Notes
(v.0) ADDED: [PRO] White Label - ability to re-brand the entire Shield Security plugin to your company brand.
(v.0) ADDED: [PRO] Option for all users to receive notification email upon login to their accounts.
(v.0) IMPROVED: Completely rebuilt the bot and reCAPTCHA login protection system.
(v.0) IMPROVED: Import/Export system hugely improved with respect to automated push of options from Master sites.
(v.0) IMPROVED: A different approach to sessions management that should handle sessions a bit better.
(v.0) IMPROVED: Expired user sessions are cleaned from the DB using a cron, and on Insights Dashboard load.
Download this release
Release Info
Developer | paultgoodchild |
Plugin | Shield Security for WordPress |
Version | 6.8.0 |
Comparing to | |
See all releases |
Code changes from version 6.7.2 to 6.8.0
- changelog.html +55 -55
- icwp-plugin-controller.php +25 -20
- icwp-wpsf.php +3 -3
- init.php +5 -1
- languages/wp-simple-firewall-nl_NL.mo +0 -0
- plugin-spec.php +7 -6
- readme.txt +42 -32
- resources/css/plugin.css +1 -0
- resources/images/pluginlogo_128x128.png +0 -0
- resources/js/plugin.js +16 -3
- src/common/icwp-data.php +9 -0
- src/common/icwp-foundation.php +17 -8
- src/common/icwp-render.php +2 -2
- src/common/icwp-wpfunctions-plugins.php +2 -2
- src/common/icwp-wpfunctions.php +2 -2
- src/common/lib/composer.lock +18 -23
- src/common/lib/vendor/composer/autoload_psr4.php +1 -1
- src/common/lib/vendor/composer/autoload_static.php +5 -8
- src/common/lib/vendor/composer/installed.json +88 -93
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Carbon.php +626 -71
- src/common/lib/vendor/nesbot/carbon/src/Carbon/CarbonInterval.php +499 -56
- src/common/lib/vendor/nesbot/carbon/src/Carbon/CarbonPeriod.php +1429 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/af.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/bg.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/bs_BA.php +31 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ca.php +19 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/cs.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/cy.php +29 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/da.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/de.php +28 -22
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/el.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/en.php +23 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/eo.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/es.php +19 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/et.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/fi.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/fo.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/fr.php +17 -12
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/gl.php +7 -7
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/gu.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/hi.php +31 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/is.php +31 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/it.php +20 -15
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ko.php +2 -2
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/mk.php +7 -7
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ne.php +31 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/nl.php +15 -10
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/no.php +19 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/oc.php +40 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/pl.php +19 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ps.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/pt.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/pt_BR.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sh.php +31 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sl.php +5 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sq.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php +5 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php +5 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php +5 -0
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sv.php +14 -14
- src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sw.php +31 -0
- src/common/lib/vendor/nesbot/carbon/src/JsonSerializable.php +16 -0
- src/common/lib/vendor/symfony/polyfill-mbstring/Mbstring.php +21 -21
- src/common/lib/vendor/symfony/translation/PluralizationRules.php +1 -0
- src/common/lib/vendor/symfony/translation/composer.json +1 -1
- src/common/wp-admin-notices.php +1 -1
- src/common/wp-comments.php +1 -1
- src/config/changelog.json +4 -4
- src/config/feature-admin_access_restriction.php +57 -33
- src/config/feature-audit_trail.php +18 -18
- src/config/feature-autoupdates.php +3 -3
- src/config/feature-comments_filter.php +16 -16
- src/config/feature-firewall.php +3 -3
- src/config/feature-hack_protect.php +19 -19
- src/config/feature-headers.php +11 -11
- src/config/feature-ips.php +5 -5
- src/config/feature-license.php +2 -2
- src/config/feature-lockdown.php +5 -5
- src/config/feature-login_protect.php +78 -60
- src/config/feature-plugin.php +6 -6
- src/config/feature-user_management.php +16 -2
- src/features/admin_access_restriction.php +49 -22
- src/features/audit_trail.php +2 -2
- src/features/autoupdates.php +2 -1
- src/features/base.php +24 -6
- src/features/base_wpsf.php +13 -2
- src/features/headers.php +1 -1
- src/features/insights.php +11 -8
- src/features/license.php +6 -4
- src/features/login_protect.php +100 -18
- src/features/plugin.php +32 -33
- src/features/user_management.php +65 -4
- src/processors/admin_access_restriction.php +13 -2
- src/processors/adminaccess_whitelabel.php +59 -23
- src/processors/audit_trail.php +6 -6
- src/processors/audit_trail_auditor_base.php +3 -3
- src/processors/autoupdates.php +1 -1
- src/processors/base.php +16 -21
- src/processors/base_plugin.php +1 -1
- src/processors/base_wpsf.php +21 -1
- src/processors/basedb.php +7 -7
- src/processors/comments_filter.php +1 -1
- src/processors/commentsfilter_antibotspam.php +8 -8
- src/processors/commentsfilter_googlerecaptcha.php +1 -1
- src/processors/commentsfilter_humanspam.php +2 -2
- src/processors/cronbase.php +7 -3
- src/processors/email.php +24 -20
- src/processors/firewall.php +5 -5
- src/processors/hack_protect.php +3 -3
- src/processors/hackprotect_corechecksumscan.php +9 -6
- src/processors/hackprotect_filecleanerscan.php +8 -5
- src/processors/hackprotect_pluginvulnerabilities.php +6 -5
- src/processors/hackprotect_ptguard.php +4 -4
- src/processors/hackprotect_wpvulnscan.php +6 -4
- src/processors/ips.php +7 -7
- src/processors/license.php +1 -1
- src/processors/lockdown.php +1 -1
- src/processors/login_protect.php +2 -2
- src/processors/loginprotect_base.php +309 -0
- src/processors/loginprotect_cooldown.php +33 -51
- src/processors/loginprotect_gasp.php +68 -107
- src/processors/loginprotect_googleauthenticator.php +12 -16
- src/processors/loginprotect_googlerecaptcha.php +25 -61
- src/processors/loginprotect_intent.php +55 -27
- src/processors/loginprotect_intentprovider_base.php +16 -10
- src/processors/loginprotect_track.php +2 -2
- src/processors/loginprotect_twofactorauth.php +18 -19
- src/processors/loginprotect_wplogin.php +3 -3
- src/processors/loginprotect_yubikey.php +12 -14
- src/processors/plugin.php +5 -1
- src/processors/plugin_badge.php +9 -6
- src/processors/plugin_importexport.php +69 -4
- src/processors/plugin_notes.php +3 -3
- src/processors/plugin_tracking.php +2 -2
- src/processors/sessions.php +59 -15
- src/processors/statistics.php +9 -9
- src/processors/statistics_reporting.php +5 -5
- src/processors/user_management.php +63 -19
- src/processors/usermanagement_sessions.php +63 -26
- src/query/sessions_terminate.php +40 -0
- src/query/statistics_base.php +1 -1
- src/wizards/base.php +16 -9
- src/wizards/plugin.php +3 -3
- templates/html/plugin_badge.html +1 -1
- templates/php/index.php +13 -3
- templates/php/notices/rate-plugin.php +1 -1
- templates/php/page/login_intent.php +9 -7
- templates/php/snippets/module-help-admin_access_restriction.php +2 -2
- templates/php/snippets/module-help-firewall.php +1 -1
- templates/php/snippets/module-help-headers.php +1 -1
- templates/php/snippets/module-help-login_protect.php +1 -1
- templates/php/snippets/module-help-plugin.php +1 -1
- templates/php/snippets/plugin_badge.php +1 -1
- templates/php/snippets/plugin_badge_widget.php +1 -1
- templates/php/snippets/pro.php +8 -6
- templates/php/snippets/widget_dashboard_plugin.php +7 -3
- templates/php/widgets/icwp_common_widgets.php +3 -3
- templates/twig/emails/user_management/user_login_notification.twig +0 -0
- templates/twig/features/feature-base.twig +1 -1
- templates/twig/snippets/widget_common.twig +3 -3
- templates/twig/wizard/pages/base.twig +1 -1
- templates/twig/wizard/slides/common/base.twig +21 -5
- templates/twig/wizard/slides/common/base_finish.twig +5 -3
- templates/twig/wizard/slides/common/base_start.twig +2 -1
- templates/twig/wizard/slides/common/no_access.twig +1 -1
- templates/twig/wizard/slides/welcome/optin.twig +1 -1
- templates/twig/wpadmin_pages/insights/index.twig +1 -1
- templates/twig/wpadmin_pages/insights/recent_events.twig +1 -1
- templates/twig/wpadmin_pages/insights/title.twig +4 -4
changelog.html
CHANGED
@@ -3821,9 +3821,9 @@ img {
|
|
3821 |
</style>
|
3822 |
<h2>Changelog: Shield Security for WordPress</h2>
|
3823 |
<p>= 6.5 Series =<br>
|
3824 |
-
<em>Released: 5th March, 2018</em> - <a href="
|
3825 |
<ul>
|
3826 |
-
<li><strong>(v.0)</strong> IMPROVED: <a href="
|
3827 |
<li><strong>(v.0)</strong> IMPROVED: Attempts to access the XML-RPC system when it’s disabled will now result in a transgression increment in the IP Black List</li>
|
3828 |
<li><strong>(v.0)</strong> IMPROVED: Try to prevent black listing the server’s own public IP address where visitor IP address detection is not correctly configured.</li>
|
3829 |
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] Provisional support for not processing 2FA logins for Woocommerce Social Login plugin.</li>
|
@@ -3831,26 +3831,26 @@ img {
|
|
3831 |
<li><strong>(v.0)</strong> FIXED: A few small bugs</li>
|
3832 |
</ul>
|
3833 |
<p>= 6.4 Series =<br>
|
3834 |
-
<em>Released: 26th February, 2018</em> - <a href="
|
3835 |
<ul>
|
3836 |
<li><strong>(v.1-4)</strong> FIXED: Various Fixes</li>
|
3837 |
-
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] New Scanner to <a href="
|
3838 |
-
<li><strong>(v.0)</strong> IMPROVED: Automatic updates for vulnerable plugins ignores <a href="
|
3839 |
<li><strong>(v.0)</strong> CHANGED: Email notifications for scanners will now link to the Wizard where possible, instead of listing files.</li>
|
3840 |
</ul>
|
3841 |
<p>= 6.3 Series =<br>
|
3842 |
-
<em>Released: 12th February, 2018</em> - <a href="
|
3843 |
<ul>
|
3844 |
<li><strong>(v.3)</strong> FIXED: Bug with automatic updates delay setting</li>
|
3845 |
<li><strong>(v.2)</strong> CHANGED: Changed a text that seems to cause servers to swallow-up emails. <a
|
3846 |
-
href="
|
3847 |
<li><strong>(v.1)</strong> FIXED: Options page javascript to work around conflicts.</li>
|
3848 |
-
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] <a href="
|
3849 |
-
<li><strong>(v.0)</strong> IMPROVED: Complete <a href="
|
3850 |
<li><strong>(v.0)</strong> FIXED: A few bugs with Google Authenticator.</li>
|
3851 |
</ul>
|
3852 |
<p>= 6.2 Series =<br>
|
3853 |
-
<em>Released: 31st January, 2018</em> - <a href="
|
3854 |
<ul>
|
3855 |
<li><strong>(v.2)</strong> FIXED: Fix for IP Manager PHP error.</li>
|
3856 |
<li><strong>(v.2)</strong> IMPROVED: Two-factor verification email.</li>
|
@@ -3863,7 +3863,7 @@ img {
|
|
3863 |
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] Add a “remember me” option, to allow users to skip Multi-factor authentication for a set number of days.</li>
|
3864 |
</ul>
|
3865 |
<p>= 6.1 Series =<br>
|
3866 |
-
<em>Released: 15th January, 2018</em> - <a href="
|
3867 |
<ul>
|
3868 |
<li><strong>(v.1)</strong> FIXED: Verify link missing from the two-factor authentication verification email.</li>
|
3869 |
<li><strong>(v.0)</strong> ADDED: 3x more Shield Wizards: Multi-factor Authentication, Core File Scanning, Unrecognised File Scanning.</li>
|
@@ -3876,9 +3876,9 @@ img {
|
|
3876 |
<em>Released: 18th December, 2017</em></p>
|
3877 |
<ul>
|
3878 |
<li><strong>(v.0)</strong> ADDED: All-new Shield Welcome and Setup Wizard - more helpful guided wizards to come.</li>
|
3879 |
-
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] <a href="
|
3880 |
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] In conjunction with import/export - Shield Security Network: automated options syncing.</li>
|
3881 |
-
<li><strong>(v.0)</strong> CHANGED: Going forward, new features and options will <a href="
|
3882 |
</ul>
|
3883 |
<p>= 5.20 Series =<br>
|
3884 |
<em>Released: 11th December, 2017</em></p>
|
@@ -3957,19 +3957,19 @@ img {
|
|
3957 |
<li><strong>(v.2)</strong> IMPROVEMENTS: Small adjustment to handling of Shield User sessions in conjunction with WordPress sessions.</li>
|
3958 |
<li><strong>(v.2)</strong> FIX: Restore display of help links for options.</li>
|
3959 |
<li><strong>(v.1)</strong> FIX: PHP 5.2 incompatibility.</li>
|
3960 |
-
<li><strong>(v.0)</strong> ADDED: New option for <a href="
|
3961 |
<li><strong>(v.0)</strong> ADDED: Option to provide custom list of files to be excluded from the <a
|
3962 |
-
href="
|
3963 |
</ul>
|
3964 |
<p>= 5.12 Series =<br>
|
3965 |
<em>Released: 3rd August, 2017</em></p>
|
3966 |
<ul>
|
3967 |
-
<li><strong>(v.2)</strong> IMPROVEMENTS: Improved support for Windows IIS hosting for <a href="
|
3968 |
<li><strong>(v.2)</strong> CHANGED: Removed the email-based 2FA automatic login link.</li>
|
3969 |
<li><strong>(v.2)</strong> FIX: Potential bug with Shield not recognising plugin configuration updates and not rebuilding options accordingly.</li>
|
3970 |
-
<li><strong>(v.1)</strong> ADDED: A few more exclusions for the <a href="
|
3971 |
<li><strong>(v.1)</strong> FIX: Fix for Fatal error.</li>
|
3972 |
-
<li><strong>(v.0)</strong> ADDED: <a href="
|
3973 |
any files present in core WordPress directories that aren’t part of your core installation.</li>
|
3974 |
<li><strong>(v.0)</strong> ADDED: Updated Firewall rules for SQL under the ‘Aggressive’ rule set.</li>
|
3975 |
</ul>
|
@@ -3977,14 +3977,14 @@ any files present in core WordPress directories that aren’t part of your core
|
|
3977 |
<em>Released: 26th July, 2017</em></p>
|
3978 |
<ul>
|
3979 |
<li><strong>(v.1)</strong> FIX: JSON syntax</li>
|
3980 |
-
<li><strong>(v.0)</strong> IMPROVEMENTS: Final preparation for <a href="
|
3981 |
</ul>
|
3982 |
<p>= 5.10 Series =<br>
|
3983 |
<em>Released: 19th June, 2017</em></p>
|
3984 |
<ul>
|
3985 |
<li><strong>(v.2)</strong> FIXED: Fatal error with GASP + Password Reset.</li>
|
3986 |
<li><strong>(v.2)</strong> FIXED: Fatal error with failing reCAPTCHA HTTP requests.</li>
|
3987 |
-
<li><strong>(v.1)</strong> IMPROVEMENTS: Further preparation for <a href="
|
3988 |
<li><strong>(v.0)</strong> ADDED: More in-depth reporting and statistics gathering - options for reports will be made available<br>
|
3989 |
in a later release.</li>
|
3990 |
</ul>
|
@@ -4007,8 +4007,8 @@ Protects existing, legitimate sessions from being forcefully expired.</li>
|
|
4007 |
<li><strong>(v.2)</strong> CHANGE: Changed timeout for two-factor authentication email to 5 minutes to account for slower email-sending providers.</li>
|
4008 |
<li><strong>(v.2)</strong> CHANGE: Added further clarification to the Login Notification email indicating that two-factor authentication was pending.</li>
|
4009 |
<li><strong>(v.1)</strong> FIXED: Fixed a couple of bugs with the Login Authentication Portal, for certain edge cases.</li>
|
4010 |
-
<li><strong>(v.0)</strong> CHANGE: Major overhaul of <a href="
|
4011 |
-
<li><strong>(v.0)</strong> CHANGE: <a href="
|
4012 |
<li><strong>(v.0)</strong> ADDED: Option to choose between two-factor or multi-factor login authentication.</li>
|
4013 |
<li><strong>(v.0)</strong> ADDED: Administrators can remove Google Authenticator from another user’s profile.</li>
|
4014 |
<li><strong>(v.0)</strong> ADDED: When Security Admin is active, only Security Admins may remove Google Authenticator from other admins.</li>
|
@@ -4016,18 +4016,18 @@ Protects existing, legitimate sessions from being forcefully expired.</li>
|
|
4016 |
<li><strong>(v.0)</strong> CHANGE: Email-based login authentication no longer uses a separate database table.</li>
|
4017 |
<li><strong>(v.0)</strong> FIXED: Core file scanning now adequately handles Windows/Unix new lines during scan.</li>
|
4018 |
<li><strong>(v.0)</strong> FIXED: Certain crons weren’t setup correctly.</li>
|
4019 |
-
<li><strong>(v.0)</strong> IMPROVEMENTS: Further preparation for <a href="
|
4020 |
</ul>
|
4021 |
<p>= 5.7 Series =</p>
|
4022 |
<ul>
|
4023 |
<li><strong>(v.3)</strong> FIXED: Attempt to improve the Google Authenticator flow for more reliable activation.</li>
|
4024 |
<li><strong>(v.2)</strong> IMPROVEMENTS: More admin notices when saving Google Authenticator settings.</li>
|
4025 |
-
<li><strong>(v.2)</strong> IMPROVEMENTS: Further preparation for <a href="
|
4026 |
<li><strong>(v.1)</strong> Skipped</li>
|
4027 |
<li><strong>(v.0)</strong> ADDED: Shortcode for displaying plugin badge in pages/posts.</li>
|
4028 |
<li><strong>(v.0)</strong> CHANGE: Enabled JS eval() for the Content Security Policy by default.</li>
|
4029 |
<li><strong>(v.0)</strong> IMPROVEMENTS: Replace YAML configuration files with JSON.</li>
|
4030 |
-
<li><strong>(v.0)</strong> IMPROVEMENTS: Preparation for <a href="
|
4031 |
<li><strong>(v.0)</strong> IMPROVEMENTS: Security Admin notices are more refined and optimized.</li>
|
4032 |
<li><strong>(v.0)</strong> IMPROVEMENTS: Removed unnecessary files/code.</li>
|
4033 |
</ul>
|
@@ -4094,7 +4094,7 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4094 |
</li>
|
4095 |
<li>
|
4096 |
<p><strong>(v.1)</strong> ADDED: Built-in forceful protection in the form of a wp_die() against the (currently) un-patched W3 Total Cache XSS vulnerability <a
|
4097 |
-
href="
|
4098 |
</li>
|
4099 |
<li>
|
4100 |
<p><strong>(v.1)</strong> IMPROVED: Better XMLRPC Lockdown - prevents ANY XMLRPC command processing.</p>
|
@@ -4153,7 +4153,7 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4153 |
<li><strong>(v.2)</strong> ADDED: A guard around certain modules like, User Sessions, to ensure the DB has been initiated properly before use.</li>
|
4154 |
<li><strong>(v.2)</strong> ADDED: Exclusion for Swedish license files that don’t exist in the SVN repo.</li>
|
4155 |
<li><strong>(v.2)</strong> ADDED: Parameter exclusion for reCAPTCHA.</li>
|
4156 |
-
<li><strong>(v.2)</strong> CHANGED: <a href="
|
4157 |
<li><strong>(v.1)</strong> FIXED: Nasty bug that caused an infinite loop bug in some configurations.</li>
|
4158 |
<li><strong>(v.0)</strong> ADDED: Per-site plugin statistics gathering - summary display on admin dashboard.</li>
|
4159 |
<li><strong>(v.0)</strong> ADDED: HTML class to the “I’m a human” checkbox field.</li>
|
@@ -4164,11 +4164,11 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4164 |
</ul>
|
4165 |
<p>= 5.3 Series =</p>
|
4166 |
<ul>
|
4167 |
-
<li><strong>(v.2)</strong> IMPROVED: <a href="
|
4168 |
<li><strong>(v.2)</strong> FIXED: Human Comment SPAM Feature didn’t fire under certain circumstances.</li>
|
4169 |
<li><strong>(v.2)</strong> FIXED: Fixed parsing of Human Comment SPAM dictionary words.</li>
|
4170 |
<li><strong>(v.1)</strong> TRANSLATIONS: Dutch (32%)</li>
|
4171 |
-
<li><strong>(v.0)</strong> ADDED: New Feature - <a href="
|
4172 |
<li><strong>(v.0)</strong> FIXED: Prevent renaming WP Login to “/login”</li>
|
4173 |
</ul>
|
4174 |
<p>= 5.2 Series =</p>
|
@@ -4177,7 +4177,7 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4177 |
<li><strong>(v.0)</strong> CHANGED: Logic for brute force login checking is improved - they all run before username/password checking</li>
|
4178 |
<li><strong>(v.0)</strong> FIXED: Certain older versions of PHP don’t like combined IPv4 and IPv6 filter flags</li>
|
4179 |
<li><strong>(v.0)</strong> FIXED: Google reCAPTCHA for WordPress sites that have restrictive settings for sockets etc.</li>
|
4180 |
-
<li><strong>(v.0)</strong> REMOVED: <a href="
|
4181 |
</ul>
|
4182 |
<p>= 5.1 Series =</p>
|
4183 |
<ul>
|
@@ -4190,17 +4190,17 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4190 |
<p>= 5.0 Series =</p>
|
4191 |
<ul>
|
4192 |
<li><strong>(v.3)</strong> FIXED: Issue with setting session cookies with PHP 7</li>
|
4193 |
-
<li><strong>(v.2)</strong> FIXED: <a href="
|
4194 |
<li><strong>(v.2)</strong> CHANGED: reCAPTCHA text usage corrected throughout plugin.</li>
|
4195 |
<li><strong>(v.1)</strong> CHANGED: Removed the whole ‘wp-content’ directory from the <a
|
4196 |
-
href="
|
4197 |
<li><strong>(v.1)</strong> CHANGED: A WordPress filter to change the plugin badge text content (see FAQ)</li>
|
4198 |
<li><strong>(v.1)</strong> CHANGED: Tweaked the plugin badge styling.</li>
|
4199 |
<li><strong>(v.1)</strong> CHANGED: All emails sent by the plugin contain the name of the site and the current plugin version in the email footer.</li>
|
4200 |
<li><strong>(v.1)</strong> ADDED: In-plugin links to blogs and info articles for Google ReCaptcha and <a
|
4201 |
-
href="
|
4202 |
<li><strong>(v.0)</strong> NEW: WordPress Simple Firewall plugin has been re-branded and is called <strong>Shield</strong></li>
|
4203 |
-
<li><strong>(v.0)</strong> ADDED: NEW feature - <a href="
|
4204 |
<li><strong>(v.0)</strong> ADDED: Support for this plugin is now Premium. Added Premium Support page that links to Helpdesk.</li>
|
4205 |
<li><strong>(v.0)</strong> CHANGED: Refactor of comment spam code.</li>
|
4206 |
<li><strong>(v.0)</strong> CHANGED: Core File Scanner now handles the odd Hungarian distribution.</li>
|
@@ -4208,8 +4208,8 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4208 |
<p>= 4.17 Series =<br>
|
4209 |
<em>Released: 17th February, 2016</em></p>
|
4210 |
<ul>
|
4211 |
-
<li><strong>(v.0)</strong> ADDED: NEW feature - <a href="
|
4212 |
-
<li><strong>(v.0)</strong> ADDED: <a href="
|
4213 |
<li><strong>(v.0)</strong> ADDED: NEW - if you already have a logged-in session and you open the login screen, you’ll be provided with a link to go straight to the admin area.</li>
|
4214 |
<li><strong>(v.0)</strong> CHANGED: Email-based Two-Factor Authentication is now stateless/session-less - it will not check validity per-page load.</li>
|
4215 |
<li><strong>(v.0)</strong> CHANGED: Changes to the email-based authentication system - now only 1 option and it no longer locks to IP or browser.</li>
|
@@ -4220,16 +4220,16 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4220 |
<p>= 4.16 Series =<br>
|
4221 |
<em>Released: 20th January, 2016</em></p>
|
4222 |
<ul>
|
4223 |
-
<li><strong>(v.2)</strong> CHANGED: Further changes and improvements to the <a href="
|
4224 |
-
<li><strong>(v.2)</strong> CHANGED: Improvements to the <a href="
|
4225 |
<li><strong>(v.2)</strong> TRANSLATIONS: Turkish (100%)</li>
|
4226 |
-
<li><strong>(v.1)</strong> CHANGED: Improved the contents of the <a href="
|
4227 |
<li><strong>(v.1)</strong> CHANGED: Now also excluding the /wp-content/languages/ directory since translations may update independently.</li>
|
4228 |
<li><strong>(v.1)</strong> CHANGED: Handles the special case of <a
|
4229 |
href="https://wordpress.org/support/topic/problem-with-checksum-hashes">old index.php files</a></li>
|
4230 |
-
<li><strong>(v.0)</strong> ADDED: Feature: <a href="
|
4231 |
<li><strong>(v.0)</strong> ADDED: Feature: to automatically attempt to repair/replace WordPress Core files that are discovered which have been altered.</li>
|
4232 |
-
<li><strong>(v.0)</strong> ADDED: Option to toggle the <a href="
|
4233 |
<li><strong>(v.0)</strong> ADDED: Two-Factor Authentication links now honour the WordPress ‘redirect_to’ parameter.</li>
|
4234 |
</ul>
|
4235 |
<p>= 4.15 Series =<br>
|
@@ -4250,7 +4250,7 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4250 |
<li><strong>(v.1)</strong> ADDED: Added ‘Unique Plugin Installation ID’ to be utilized in the future.</li>
|
4251 |
<li><strong>(v.1)</strong> FIXED: WordPress Comments bug where some comments didn’t pass through the SPAM filters in a certain scenario.</li>
|
4252 |
<li><strong>(v.0)</strong> ADDED: <a
|
4253 |
-
href="
|
4254 |
<li><strong>(v.0)</strong> ADDED: Filter to remove the admin area IP address footer text</li>
|
4255 |
<li><strong>(v.0)</strong> CHANGED: Added native support for PayPal return links - whitelisting “verify_sign” parameter.</li>
|
4256 |
<li><strong>(v.0)</strong> CHANGED: Tweak patterns for matching on ‘WordPress terms’.</li>
|
@@ -4274,14 +4274,14 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4274 |
<em>Released: 10th October, 2015</em></p>
|
4275 |
<ul>
|
4276 |
<li><strong>(v.0)</strong> NEW: Option to completely disable the XML-RPC system. <a
|
4277 |
-
href="
|
4278 |
<li><strong>(v.0)</strong> CHANGED: Logged-in users are automatically forwarded to the WordPress admin only if they are Administrators.</li>
|
4279 |
</ul>
|
4280 |
<p>= 4.11 Series =<br>
|
4281 |
<em>Released: 5th October, 2015</em></p>
|
4282 |
<ul>
|
4283 |
<li><strong>(v.0)</strong> NEW: Ability to now completely block the update/changing of certain WordPress site options. <a
|
4284 |
-
href="
|
4285 |
<li><strong>(v.0)</strong> FIXED: Various small bugs with the IP Manager UI ajax.</li>
|
4286 |
<li><strong>(v.0)</strong> FIXED: Uncaught PHP Exception when a site’s hosting isn’t properly configured to handle IPv6 addresses.</li>
|
4287 |
<li><strong>(v.0)</strong> TRANSLATIONS: Danish - 57%, Czech - 100%, Finnish - 94%</li>
|
@@ -4339,11 +4339,11 @@ or service authenticates the request it will be honoured, whether anonymous or n
|
|
4339 |
</li>
|
4340 |
<li>
|
4341 |
<p><strong>(v.1)</strong> ADDED: Ability to reset plugin options to default using ‘reset’ flag file. <a
|
4342 |
-
href="
|
4343 |
</li>
|
4344 |
<li>
|
4345 |
<p><strong>(v.0)</strong> NEW FEATURE: ‘FABLE’ - <a
|
4346 |
-
href="
|
4347 |
</li>
|
4348 |
</ul>
|
4349 |
<p>Simply put, FABLE will automatically block all malicious traffic by IP, based on their activity. This Security Plugin will track malicious behaviour<br>
|
@@ -4376,7 +4376,7 @@ will outright block any access they have to your WordPress site.</p>
|
|
4376 |
<li><strong>(v.8)</strong> FIX: Some server email programs can’t handle colons (:) in the email subject (because supporting all characters would be waaay too radical man).</li>
|
4377 |
<li><strong>(v.8)</strong> ADDED: Function to better get the WordPress home URL to prevent interference from other plugins.</li>
|
4378 |
<li><strong>(v.8)</strong> CHANGED: Updated Text For <a
|
4379 |
-
href="
|
4380 |
<li><strong>(v.7)</strong> CHANGED: How author query blocking works to be more reliable and stricter - only runs when users are not logged in, and it will DIE instead of redirect.</li>
|
4381 |
<li><strong>(v.6)</strong> ADDED: New Option: prevent detection of usernames using the ?author=N query. (location under section: Lockdown -> Obscurity)</li>
|
4382 |
<li><strong>(v.6)</strong> FIXED: Infinite redirect loop logic prevents redirect for rejected comment SPAM that’s posted in bulk. This results in email notifications for spam comments.</li>
|
@@ -4393,7 +4393,7 @@ will outright block any access they have to your WordPress site.</p>
|
|
4393 |
<li><strong>(v.2)</strong> FIX: Work around a WordPress inline plugin update Javascript bug.</li>
|
4394 |
<li><strong>(v.1)</strong> FIX: Fix syntax support for earlier versions of PHP.</li>
|
4395 |
<li><strong>(v.0)</strong> FEATURE: Plugin Vulnerabilities Detection: If you’re running plugins with known vulnerabilities you will be warned - <a
|
4396 |
-
href="
|
4397 |
</ul>
|
4398 |
<p>= 4.8 Series =<br>
|
4399 |
<em>Released: 21st June, 2015</em></p>
|
@@ -4435,8 +4435,8 @@ will outright block any access they have to your WordPress site.</p>
|
|
4435 |
<em>Released: 10th April, 2015</em></p>
|
4436 |
<ul>
|
4437 |
<li><strong>(v.3)</strong> SECURITY: Added protection against XSS vulnerability in WordPress comments. <a
|
4438 |
-
href="
|
4439 |
-
<li><strong>(v.3)</strong> SECURITY: Added extra precautions to WordPress URL redirects. <a href="
|
4440 |
<li><strong>(v.3)</strong> TRANSLATIONS: Russian (70%), Czech (67%)</li>
|
4441 |
<li><strong>(v.2)</strong> FIX: Bug with the database table verification logic.</li>
|
4442 |
<li><strong>(v.2)</strong> TRANSLATIONS: Russian (New- 54%), Romanian (100%), Turkish (89%), Czech (53%)</li>
|
@@ -4445,7 +4445,7 @@ will outright block any access they have to your WordPress site.</p>
|
|
4445 |
<li><strong>(v.1)</strong> UPDATED: Updated Czech(41%) and Spanish (60%) translations</li>
|
4446 |
<li><strong>(v.0)</strong> ADDED: New feature that displays the last login time for all users on the users listing page (User Management feature must be enabled).</li>
|
4447 |
<li><strong>(v.0)</strong> ADDED: <strong>Completely optional</strong> promotional Plugin Badge option - help us promote the plugin and reassure your site visitors at the same time. <a
|
4448 |
-
href="
|
4449 |
<li><strong>(v.0)</strong> UPDATED: Updated Czech(38%) translations</li>
|
4450 |
</ul>
|
4451 |
<p>= 4.5 Series =<br>
|
@@ -4481,7 +4481,7 @@ will outright block any access they have to your WordPress site.</p>
|
|
4481 |
<li><strong>(v.5)</strong> CHANGED: Streamlined the detection of whitelisting and added in-plugin notification if <strong>you</strong> are whitelisted</li>
|
4482 |
<li><strong>(v.4)</strong> FIXES: Work around for cases where PHP can’t successfully run parse_url()</li>
|
4483 |
<li><strong>(v.2)</strong> IMPROVED: Refactoring for better code organisation</li>
|
4484 |
-
<li>ADDED: New Feature - <a href="
|
4485 |
<li>ADDED: UI indicators on whether plugins will be automatically updated in the plugins listing.</li>
|
4486 |
<li>CHANGED: IP Address WhiteList is now global for the whole plugin, and can be accessed under the “Dashboard” area</li>
|
4487 |
<li>IMPROVED: Firewall processing code is simplified and more efficient.</li>
|
@@ -4639,7 +4639,7 @@ will outright block any access they have to your WordPress site.</p>
|
|
4639 |
<p>= 2.6.3 =</p>
|
4640 |
<ul>
|
4641 |
<li>ADDED: More in-line plugin links to help/blog resources</li>
|
4642 |
-
<li>ENHANCED: <a href="
|
4643 |
</ul>
|
4644 |
<ol>
|
4645 |
<li>More robust cookie values using MD5s</li>
|
@@ -4710,7 +4710,7 @@ will outright block any access they have to your WordPress site.</p>
|
|
4710 |
<p>= 2.5.0 =</p>
|
4711 |
<ul>
|
4712 |
<li>FEATURE: Two-Factor Authenticated Login using <a
|
4713 |
-
href="
|
4714 |
</ul>
|
4715 |
<p>= 2.4.3 =</p>
|
4716 |
<ul>
|
@@ -4832,7 +4832,7 @@ entries and was forcing users to re-login every 24hrs.</li>
|
|
4832 |
</ul>
|
4833 |
<p>= 1.8.1 =</p>
|
4834 |
<ul>
|
4835 |
-
<li>ADDED: Feature- Access Key Restriction <a href="
|
4836 |
<li>ADDED: Feature- WordPress Lockdown. Currently only provides 1 option, but more to come.</li>
|
4837 |
</ul>
|
4838 |
<p>= 1.7.3 =</p>
|
3821 |
</style>
|
3822 |
<h2>Changelog: Shield Security for WordPress</h2>
|
3823 |
<p>= 6.5 Series =<br>
|
3824 |
+
<em>Released: 5th March, 2018</em> - <a href="https://icwp.io/bu">Release Notes</a></p>
|
3825 |
<ul>
|
3826 |
+
<li><strong>(v.0)</strong> IMPROVED: <a href="https://icwp.io/bq">Plugin Guard</a> better handles the case where a plugin/theme has been entirely renamed/removed.</li>
|
3827 |
<li><strong>(v.0)</strong> IMPROVED: Attempts to access the XML-RPC system when it’s disabled will now result in a transgression increment in the IP Black List</li>
|
3828 |
<li><strong>(v.0)</strong> IMPROVED: Try to prevent black listing the server’s own public IP address where visitor IP address detection is not correctly configured.</li>
|
3829 |
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] Provisional support for not processing 2FA logins for Woocommerce Social Login plugin.</li>
|
3831 |
<li><strong>(v.0)</strong> FIXED: A few small bugs</li>
|
3832 |
</ul>
|
3833 |
<p>= 6.4 Series =<br>
|
3834 |
+
<em>Released: 26th February, 2018</em> - <a href="https://icwp.io/br">Release Notes</a></p>
|
3835 |
<ul>
|
3836 |
<li><strong>(v.1-4)</strong> FIXED: Various Fixes</li>
|
3837 |
+
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] New Scanner to <a href="https://icwp.io/bq">detect file changes for active plugins and themes</a></li>
|
3838 |
+
<li><strong>(v.0)</strong> IMPROVED: Automatic updates for vulnerable plugins ignores <a href="https://icwp.io/bc">automatic updates delay setting</a></li>
|
3839 |
<li><strong>(v.0)</strong> CHANGED: Email notifications for scanners will now link to the Wizard where possible, instead of listing files.</li>
|
3840 |
</ul>
|
3841 |
<p>= 6.3 Series =<br>
|
3842 |
+
<em>Released: 12th February, 2018</em> - <a href="https://icwp.io/bc">Release Notes</a></p>
|
3843 |
<ul>
|
3844 |
<li><strong>(v.3)</strong> FIXED: Bug with automatic updates delay setting</li>
|
3845 |
<li><strong>(v.2)</strong> CHANGED: Changed a text that seems to cause servers to swallow-up emails. <a
|
3846 |
+
href="https://icwp.io/bi">See here for more reliable email</a></li>
|
3847 |
<li><strong>(v.1)</strong> FIXED: Options page javascript to work around conflicts.</li>
|
3848 |
+
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] <a href="https://icwp.io/bc">Automatic updates stability delay</a></li>
|
3849 |
+
<li><strong>(v.0)</strong> IMPROVED: Complete <a href="https://icwp.io/bd">plugin UI rebuild</a>, using the new Bootstrap 4.</li>
|
3850 |
<li><strong>(v.0)</strong> FIXED: A few bugs with Google Authenticator.</li>
|
3851 |
</ul>
|
3852 |
<p>= 6.2 Series =<br>
|
3853 |
+
<em>Released: 31st January, 2018</em> - <a href="https://icwp.io/b6">Release Notes</a></p>
|
3854 |
<ul>
|
3855 |
<li><strong>(v.2)</strong> FIXED: Fix for IP Manager PHP error.</li>
|
3856 |
<li><strong>(v.2)</strong> IMPROVED: Two-factor verification email.</li>
|
3863 |
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] Add a “remember me” option, to allow users to skip Multi-factor authentication for a set number of days.</li>
|
3864 |
</ul>
|
3865 |
<p>= 6.1 Series =<br>
|
3866 |
+
<em>Released: 15th January, 2018</em> - <a href="https://icwp.io/ay">Release Notes</a></p>
|
3867 |
<ul>
|
3868 |
<li><strong>(v.1)</strong> FIXED: Verify link missing from the two-factor authentication verification email.</li>
|
3869 |
<li><strong>(v.0)</strong> ADDED: 3x more Shield Wizards: Multi-factor Authentication, Core File Scanning, Unrecognised File Scanning.</li>
|
3876 |
<em>Released: 18th December, 2017</em></p>
|
3877 |
<ul>
|
3878 |
<li><strong>(v.0)</strong> ADDED: All-new Shield Welcome and Setup Wizard - more helpful guided wizards to come.</li>
|
3879 |
+
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] <a href="https://icwp.io/at">Shield options import and export</a></li>
|
3880 |
<li><strong>(v.0)</strong> ADDED: [<strong>PRO</strong>] In conjunction with import/export - Shield Security Network: automated options syncing.</li>
|
3881 |
+
<li><strong>(v.0)</strong> CHANGED: Going forward, new features and options will <a href="https://icwp.io/au">support only PHP 5.4+</a>. Existing features will remain unaffected.</li>
|
3882 |
</ul>
|
3883 |
<p>= 5.20 Series =<br>
|
3884 |
<em>Released: 11th December, 2017</em></p>
|
3957 |
<li><strong>(v.2)</strong> IMPROVEMENTS: Small adjustment to handling of Shield User sessions in conjunction with WordPress sessions.</li>
|
3958 |
<li><strong>(v.2)</strong> FIX: Restore display of help links for options.</li>
|
3959 |
<li><strong>(v.1)</strong> FIX: PHP 5.2 incompatibility.</li>
|
3960 |
+
<li><strong>(v.0)</strong> ADDED: New option for <a href="https://icwp.io/94">Unrecognised File Scanner</a> to scan the Uploads folder for JS and PHP files.</li>
|
3961 |
<li><strong>(v.0)</strong> ADDED: Option to provide custom list of files to be excluded from the <a
|
3962 |
+
href="https://icwp.io/94">Unrecognised File Scanner</a>.</li>
|
3963 |
</ul>
|
3964 |
<p>= 5.12 Series =<br>
|
3965 |
<em>Released: 3rd August, 2017</em></p>
|
3966 |
<ul>
|
3967 |
+
<li><strong>(v.2)</strong> IMPROVEMENTS: Improved support for Windows IIS hosting for <a href="https://icwp.io/94">Unrecognised File Scanner</a></li>
|
3968 |
<li><strong>(v.2)</strong> CHANGED: Removed the email-based 2FA automatic login link.</li>
|
3969 |
<li><strong>(v.2)</strong> FIX: Potential bug with Shield not recognising plugin configuration updates and not rebuilding options accordingly.</li>
|
3970 |
+
<li><strong>(v.1)</strong> ADDED: A few more exclusions for the <a href="https://icwp.io/94">Unrecognised File Scanner</a></li>
|
3971 |
<li><strong>(v.1)</strong> FIX: Fix for Fatal error.</li>
|
3972 |
+
<li><strong>(v.0)</strong> ADDED: <a href="https://icwp.io/94">Unrecognised File Scanner</a> release. Automatically detect and delete<br>
|
3973 |
any files present in core WordPress directories that aren’t part of your core installation.</li>
|
3974 |
<li><strong>(v.0)</strong> ADDED: Updated Firewall rules for SQL under the ‘Aggressive’ rule set.</li>
|
3975 |
</ul>
|
3977 |
<em>Released: 26th July, 2017</em></p>
|
3978 |
<ul>
|
3979 |
<li><strong>(v.1)</strong> FIX: JSON syntax</li>
|
3980 |
+
<li><strong>(v.0)</strong> IMPROVEMENTS: Final preparation for <a href="https://icwp.io/83">Shield Central</a> release.</li>
|
3981 |
</ul>
|
3982 |
<p>= 5.10 Series =<br>
|
3983 |
<em>Released: 19th June, 2017</em></p>
|
3984 |
<ul>
|
3985 |
<li><strong>(v.2)</strong> FIXED: Fatal error with GASP + Password Reset.</li>
|
3986 |
<li><strong>(v.2)</strong> FIXED: Fatal error with failing reCAPTCHA HTTP requests.</li>
|
3987 |
+
<li><strong>(v.1)</strong> IMPROVEMENTS: Further preparation for <a href="https://icwp.io/83">Shield Central</a> release.</li>
|
3988 |
<li><strong>(v.0)</strong> ADDED: More in-depth reporting and statistics gathering - options for reports will be made available<br>
|
3989 |
in a later release.</li>
|
3990 |
</ul>
|
4007 |
<li><strong>(v.2)</strong> CHANGE: Changed timeout for two-factor authentication email to 5 minutes to account for slower email-sending providers.</li>
|
4008 |
<li><strong>(v.2)</strong> CHANGE: Added further clarification to the Login Notification email indicating that two-factor authentication was pending.</li>
|
4009 |
<li><strong>(v.1)</strong> FIXED: Fixed a couple of bugs with the Login Authentication Portal, for certain edge cases.</li>
|
4010 |
+
<li><strong>(v.0)</strong> CHANGE: Major overhaul of <a href="https://icwp.io/87">Two-Factor / Multi-Factor Login Authentication</a>.</li>
|
4011 |
+
<li><strong>(v.0)</strong> CHANGE: <a href="https://icwp.io/86">Introduction of Login Authentication Portal</a> for improved Multi-Factor Authentication.</li>
|
4012 |
<li><strong>(v.0)</strong> ADDED: Option to choose between two-factor or multi-factor login authentication.</li>
|
4013 |
<li><strong>(v.0)</strong> ADDED: Administrators can remove Google Authenticator from another user’s profile.</li>
|
4014 |
<li><strong>(v.0)</strong> ADDED: When Security Admin is active, only Security Admins may remove Google Authenticator from other admins.</li>
|
4016 |
<li><strong>(v.0)</strong> CHANGE: Email-based login authentication no longer uses a separate database table.</li>
|
4017 |
<li><strong>(v.0)</strong> FIXED: Core file scanning now adequately handles Windows/Unix new lines during scan.</li>
|
4018 |
<li><strong>(v.0)</strong> FIXED: Certain crons weren’t setup correctly.</li>
|
4019 |
+
<li><strong>(v.0)</strong> IMPROVEMENTS: Further preparation for <a href="https://icwp.io/83">Shield Central</a> release.</li>
|
4020 |
</ul>
|
4021 |
<p>= 5.7 Series =</p>
|
4022 |
<ul>
|
4023 |
<li><strong>(v.3)</strong> FIXED: Attempt to improve the Google Authenticator flow for more reliable activation.</li>
|
4024 |
<li><strong>(v.2)</strong> IMPROVEMENTS: More admin notices when saving Google Authenticator settings.</li>
|
4025 |
+
<li><strong>(v.2)</strong> IMPROVEMENTS: Further preparation for <a href="https://icwp.io/83">Shield Central</a> release.</li>
|
4026 |
<li><strong>(v.1)</strong> Skipped</li>
|
4027 |
<li><strong>(v.0)</strong> ADDED: Shortcode for displaying plugin badge in pages/posts.</li>
|
4028 |
<li><strong>(v.0)</strong> CHANGE: Enabled JS eval() for the Content Security Policy by default.</li>
|
4029 |
<li><strong>(v.0)</strong> IMPROVEMENTS: Replace YAML configuration files with JSON.</li>
|
4030 |
+
<li><strong>(v.0)</strong> IMPROVEMENTS: Preparation for <a href="https://icwp.io/83">Shield Central</a> release.</li>
|
4031 |
<li><strong>(v.0)</strong> IMPROVEMENTS: Security Admin notices are more refined and optimized.</li>
|
4032 |
<li><strong>(v.0)</strong> IMPROVEMENTS: Removed unnecessary files/code.</li>
|
4033 |
</ul>
|
4094 |
</li>
|
4095 |
<li>
|
4096 |
<p><strong>(v.1)</strong> ADDED: Built-in forceful protection in the form of a wp_die() against the (currently) un-patched W3 Total Cache XSS vulnerability <a
|
4097 |
+
href="https://icwp.io/7j">more info</a></p>
|
4098 |
</li>
|
4099 |
<li>
|
4100 |
<p><strong>(v.1)</strong> IMPROVED: Better XMLRPC Lockdown - prevents ANY XMLRPC command processing.</p>
|
4153 |
<li><strong>(v.2)</strong> ADDED: A guard around certain modules like, User Sessions, to ensure the DB has been initiated properly before use.</li>
|
4154 |
<li><strong>(v.2)</strong> ADDED: Exclusion for Swedish license files that don’t exist in the SVN repo.</li>
|
4155 |
<li><strong>(v.2)</strong> ADDED: Parameter exclusion for reCAPTCHA.</li>
|
4156 |
+
<li><strong>(v.2)</strong> CHANGED: <a href="https://icwp.io/7b">HTTP Security Headers</a> module is enabled by default on new installs.</li>
|
4157 |
<li><strong>(v.1)</strong> FIXED: Nasty bug that caused an infinite loop bug in some configurations.</li>
|
4158 |
<li><strong>(v.0)</strong> ADDED: Per-site plugin statistics gathering - summary display on admin dashboard.</li>
|
4159 |
<li><strong>(v.0)</strong> ADDED: HTML class to the “I’m a human” checkbox field.</li>
|
4164 |
</ul>
|
4165 |
<p>= 5.3 Series =</p>
|
4166 |
<ul>
|
4167 |
+
<li><strong>(v.2)</strong> IMPROVED: <a href="https://icwp.io/7b">HTTP Security Headers</a> Content Security Policy now supports specifying HTTPS for domains/hosts.</li>
|
4168 |
<li><strong>(v.2)</strong> FIXED: Human Comment SPAM Feature didn’t fire under certain circumstances.</li>
|
4169 |
<li><strong>(v.2)</strong> FIXED: Fixed parsing of Human Comment SPAM dictionary words.</li>
|
4170 |
<li><strong>(v.1)</strong> TRANSLATIONS: Dutch (32%)</li>
|
4171 |
+
<li><strong>(v.0)</strong> ADDED: New Feature - <a href="https://icwp.io/7b">HTTP Security Headers</a>.</li>
|
4172 |
<li><strong>(v.0)</strong> FIXED: Prevent renaming WP Login to “/login”</li>
|
4173 |
</ul>
|
4174 |
<p>= 5.2 Series =</p>
|
4177 |
<li><strong>(v.0)</strong> CHANGED: Logic for brute force login checking is improved - they all run before username/password checking</li>
|
4178 |
<li><strong>(v.0)</strong> FIXED: Certain older versions of PHP don’t like combined IPv4 and IPv6 filter flags</li>
|
4179 |
<li><strong>(v.0)</strong> FIXED: Google reCAPTCHA for WordPress sites that have restrictive settings for sockets etc.</li>
|
4180 |
+
<li><strong>(v.0)</strong> REMOVED: <a href="https://icwp.io/75">Plugin vulnerabilities scanner</a>. It’s out-of-date and unsuitable.</li>
|
4181 |
</ul>
|
4182 |
<p>= 5.1 Series =</p>
|
4183 |
<ul>
|
4190 |
<p>= 5.0 Series =</p>
|
4191 |
<ul>
|
4192 |
<li><strong>(v.3)</strong> FIXED: Issue with setting session cookies with PHP 7</li>
|
4193 |
+
<li><strong>(v.2)</strong> FIXED: <a href="https://icwp.io/5s">Rename WordPress Login URL</a> bug</li>
|
4194 |
<li><strong>(v.2)</strong> CHANGED: reCAPTCHA text usage corrected throughout plugin.</li>
|
4195 |
<li><strong>(v.1)</strong> CHANGED: Removed the whole ‘wp-content’ directory from the <a
|
4196 |
+
href="https://icwp.io/wpsf40">Core File Scanner</a> feature.</li>
|
4197 |
<li><strong>(v.1)</strong> CHANGED: A WordPress filter to change the plugin badge text content (see FAQ)</li>
|
4198 |
<li><strong>(v.1)</strong> CHANGED: Tweaked the plugin badge styling.</li>
|
4199 |
<li><strong>(v.1)</strong> CHANGED: All emails sent by the plugin contain the name of the site and the current plugin version in the email footer.</li>
|
4200 |
<li><strong>(v.1)</strong> ADDED: In-plugin links to blogs and info articles for Google ReCaptcha and <a
|
4201 |
+
href="https://icwp.io/wpsf43">Google Authenticator</a></li>
|
4202 |
<li><strong>(v.0)</strong> NEW: WordPress Simple Firewall plugin has been re-branded and is called <strong>Shield</strong></li>
|
4203 |
+
<li><strong>(v.0)</strong> ADDED: NEW feature - <a href="https://icwp.io/shld2">Google ReCaptcha</a> for Comment SPAM and Login protection.</li>
|
4204 |
<li><strong>(v.0)</strong> ADDED: Support for this plugin is now Premium. Added Premium Support page that links to Helpdesk.</li>
|
4205 |
<li><strong>(v.0)</strong> CHANGED: Refactor of comment spam code.</li>
|
4206 |
<li><strong>(v.0)</strong> CHANGED: Core File Scanner now handles the odd Hungarian distribution.</li>
|
4208 |
<p>= 4.17 Series =<br>
|
4209 |
<em>Released: 17th February, 2016</em></p>
|
4210 |
<ul>
|
4211 |
+
<li><strong>(v.0)</strong> ADDED: NEW feature - <a href="https://icwp.io/wpsf43">Google Authenticator Login option</a>.</li>
|
4212 |
+
<li><strong>(v.0)</strong> ADDED: <a href="https://icwp.io/wpsf40">Core File Scanner</a> now includes an automatic link to repair files (you must be logged in as admin for this link to work!).</li>
|
4213 |
<li><strong>(v.0)</strong> ADDED: NEW - if you already have a logged-in session and you open the login screen, you’ll be provided with a link to go straight to the admin area.</li>
|
4214 |
<li><strong>(v.0)</strong> CHANGED: Email-based Two-Factor Authentication is now stateless/session-less - it will not check validity per-page load.</li>
|
4215 |
<li><strong>(v.0)</strong> CHANGED: Changes to the email-based authentication system - now only 1 option and it no longer locks to IP or browser.</li>
|
4220 |
<p>= 4.16 Series =<br>
|
4221 |
<em>Released: 20th January, 2016</em></p>
|
4222 |
<ul>
|
4223 |
+
<li><strong>(v.2)</strong> CHANGED: Further changes and improvements to the <a href="https://icwp.io/wpsf40">Core File Scanner</a>.</li>
|
4224 |
+
<li><strong>(v.2)</strong> CHANGED: Improvements to the <a href="https://icwp.io/wpsf27">automatic black list system</a> for failed login attempts.</li>
|
4225 |
<li><strong>(v.2)</strong> TRANSLATIONS: Turkish (100%)</li>
|
4226 |
+
<li><strong>(v.1)</strong> CHANGED: Improved the contents of the <a href="https://icwp.io/wpsf40">Core File Scanner</a> notification email with links to original source files.</li>
|
4227 |
<li><strong>(v.1)</strong> CHANGED: Now also excluding the /wp-content/languages/ directory since translations may update independently.</li>
|
4228 |
<li><strong>(v.1)</strong> CHANGED: Handles the special case of <a
|
4229 |
href="https://wordpress.org/support/topic/problem-with-checksum-hashes">old index.php files</a></li>
|
4230 |
+
<li><strong>(v.0)</strong> ADDED: Feature: <a href="https://icwp.io/wpsf40">Automatically scans WordPress Core files</a> and detects alterations from the default WordPress Core File data</li>
|
4231 |
<li><strong>(v.0)</strong> ADDED: Feature: to automatically attempt to repair/replace WordPress Core files that are discovered which have been altered.</li>
|
4232 |
+
<li><strong>(v.0)</strong> ADDED: Option to toggle the <a href="https://icwp.io/wpsf41">Plugin Vulnerabilities cron</a>.</li>
|
4233 |
<li><strong>(v.0)</strong> ADDED: Two-Factor Authentication links now honour the WordPress ‘redirect_to’ parameter.</li>
|
4234 |
</ul>
|
4235 |
<p>= 4.15 Series =<br>
|
4250 |
<li><strong>(v.1)</strong> ADDED: Added ‘Unique Plugin Installation ID’ to be utilized in the future.</li>
|
4251 |
<li><strong>(v.1)</strong> FIXED: WordPress Comments bug where some comments didn’t pass through the SPAM filters in a certain scenario.</li>
|
4252 |
<li><strong>(v.0)</strong> ADDED: <a
|
4253 |
+
href="https://icwp.io/wpsf33">Custom Automatic Update Notifications Email</a> that runs separately to the in-built WordPress core notification email.</li>
|
4254 |
<li><strong>(v.0)</strong> ADDED: Filter to remove the admin area IP address footer text</li>
|
4255 |
<li><strong>(v.0)</strong> CHANGED: Added native support for PayPal return links - whitelisting “verify_sign” parameter.</li>
|
4256 |
<li><strong>(v.0)</strong> CHANGED: Tweak patterns for matching on ‘WordPress terms’.</li>
|
4274 |
<em>Released: 10th October, 2015</em></p>
|
4275 |
<ul>
|
4276 |
<li><strong>(v.0)</strong> NEW: Option to completely disable the XML-RPC system. <a
|
4277 |
+
href="https://icwp.io/wpsf31">more info</a></li>
|
4278 |
<li><strong>(v.0)</strong> CHANGED: Logged-in users are automatically forwarded to the WordPress admin only if they are Administrators.</li>
|
4279 |
</ul>
|
4280 |
<p>= 4.11 Series =<br>
|
4281 |
<em>Released: 5th October, 2015</em></p>
|
4282 |
<ul>
|
4283 |
<li><strong>(v.0)</strong> NEW: Ability to now completely block the update/changing of certain WordPress site options. <a
|
4284 |
+
href="https://icwp.io/wpsf30">more info</a></li>
|
4285 |
<li><strong>(v.0)</strong> FIXED: Various small bugs with the IP Manager UI ajax.</li>
|
4286 |
<li><strong>(v.0)</strong> FIXED: Uncaught PHP Exception when a site’s hosting isn’t properly configured to handle IPv6 addresses.</li>
|
4287 |
<li><strong>(v.0)</strong> TRANSLATIONS: Danish - 57%, Czech - 100%, Finnish - 94%</li>
|
4339 |
</li>
|
4340 |
<li>
|
4341 |
<p><strong>(v.1)</strong> ADDED: Ability to reset plugin options to default using ‘reset’ flag file. <a
|
4342 |
+
href="https://icwp.io/wpsf28">more info</a></p>
|
4343 |
</li>
|
4344 |
<li>
|
4345 |
<p><strong>(v.0)</strong> NEW FEATURE: ‘FABLE’ - <a
|
4346 |
+
href="https://icwp.io/wpsf27">Fully Automatic Black Listing Engine</a>.</p>
|
4347 |
</li>
|
4348 |
</ul>
|
4349 |
<p>Simply put, FABLE will automatically block all malicious traffic by IP, based on their activity. This Security Plugin will track malicious behaviour<br>
|
4376 |
<li><strong>(v.8)</strong> FIX: Some server email programs can’t handle colons (:) in the email subject (because supporting all characters would be waaay too radical man).</li>
|
4377 |
<li><strong>(v.8)</strong> ADDED: Function to better get the WordPress home URL to prevent interference from other plugins.</li>
|
4378 |
<li><strong>(v.8)</strong> CHANGED: Updated Text For <a
|
4379 |
+
href="https://icwp.io/6e">Author Scan Block</a> feature.</li>
|
4380 |
<li><strong>(v.7)</strong> CHANGED: How author query blocking works to be more reliable and stricter - only runs when users are not logged in, and it will DIE instead of redirect.</li>
|
4381 |
<li><strong>(v.6)</strong> ADDED: New Option: prevent detection of usernames using the ?author=N query. (location under section: Lockdown -> Obscurity)</li>
|
4382 |
<li><strong>(v.6)</strong> FIXED: Infinite redirect loop logic prevents redirect for rejected comment SPAM that’s posted in bulk. This results in email notifications for spam comments.</li>
|
4393 |
<li><strong>(v.2)</strong> FIX: Work around a WordPress inline plugin update Javascript bug.</li>
|
4394 |
<li><strong>(v.1)</strong> FIX: Fix syntax support for earlier versions of PHP.</li>
|
4395 |
<li><strong>(v.0)</strong> FEATURE: Plugin Vulnerabilities Detection: If you’re running plugins with known vulnerabilities you will be warned - <a
|
4396 |
+
href="https://icwp.io/wpsf22">more info</a></li>
|
4397 |
</ul>
|
4398 |
<p>= 4.8 Series =<br>
|
4399 |
<em>Released: 21st June, 2015</em></p>
|
4435 |
<em>Released: 10th April, 2015</em></p>
|
4436 |
<ul>
|
4437 |
<li><strong>(v.3)</strong> SECURITY: Added protection against XSS vulnerability in WordPress comments. <a
|
4438 |
+
href="https://icwp.io/63">Learn More</a> - Note: This is not a vulnerability with the Firewall plugin.</li>
|
4439 |
+
<li><strong>(v.3)</strong> SECURITY: Added extra precautions to WordPress URL redirects. <a href="https://icwp.io/64">Learn More</a>.</li>
|
4440 |
<li><strong>(v.3)</strong> TRANSLATIONS: Russian (70%), Czech (67%)</li>
|
4441 |
<li><strong>(v.2)</strong> FIX: Bug with the database table verification logic.</li>
|
4442 |
<li><strong>(v.2)</strong> TRANSLATIONS: Russian (New- 54%), Romanian (100%), Turkish (89%), Czech (53%)</li>
|
4445 |
<li><strong>(v.1)</strong> UPDATED: Updated Czech(41%) and Spanish (60%) translations</li>
|
4446 |
<li><strong>(v.0)</strong> ADDED: New feature that displays the last login time for all users on the users listing page (User Management feature must be enabled).</li>
|
4447 |
<li><strong>(v.0)</strong> ADDED: <strong>Completely optional</strong> promotional Plugin Badge option - help us promote the plugin and reassure your site visitors at the same time. <a
|
4448 |
+
href="https://icwp.io/5x">Learn More</a></li>
|
4449 |
<li><strong>(v.0)</strong> UPDATED: Updated Czech(38%) translations</li>
|
4450 |
</ul>
|
4451 |
<p>= 4.5 Series =<br>
|
4481 |
<li><strong>(v.5)</strong> CHANGED: Streamlined the detection of whitelisting and added in-plugin notification if <strong>you</strong> are whitelisted</li>
|
4482 |
<li><strong>(v.4)</strong> FIXES: Work around for cases where PHP can’t successfully run parse_url()</li>
|
4483 |
<li><strong>(v.2)</strong> IMPROVED: Refactoring for better code organisation</li>
|
4484 |
+
<li>ADDED: New Feature - <a href="https://icwp.io/5s">Rename WP Login Page</a>.</li>
|
4485 |
<li>ADDED: UI indicators on whether plugins will be automatically updated in the plugins listing.</li>
|
4486 |
<li>CHANGED: IP Address WhiteList is now global for the whole plugin, and can be accessed under the “Dashboard” area</li>
|
4487 |
<li>IMPROVED: Firewall processing code is simplified and more efficient.</li>
|
4639 |
<p>= 2.6.3 =</p>
|
4640 |
<ul>
|
4641 |
<li>ADDED: More in-line plugin links to help/blog resources</li>
|
4642 |
+
<li>ENHANCED: <a href="https://icwp.io/5b">Admin Access Protection</a> is further enhanced in 3 ways:</li>
|
4643 |
</ul>
|
4644 |
<ol>
|
4645 |
<li>More robust cookie values using MD5s</li>
|
4710 |
<p>= 2.5.0 =</p>
|
4711 |
<ul>
|
4712 |
<li>FEATURE: Two-Factor Authenticated Login using <a
|
4713 |
+
href="https://icwp.io/4i">Yubikey</a> One Time Passwords (OTP).</li>
|
4714 |
</ul>
|
4715 |
<p>= 2.4.3 =</p>
|
4716 |
<ul>
|
4832 |
</ul>
|
4833 |
<p>= 1.8.1 =</p>
|
4834 |
<ul>
|
4835 |
+
<li>ADDED: Feature- Access Key Restriction <a href="https://icwp.io/2s">more info</a>.</li>
|
4836 |
<li>ADDED: Feature- WordPress Lockdown. Currently only provides 1 option, but more to come.</li>
|
4837 |
</ul>
|
4838 |
<p>= 1.7.3 =</p>
|
icwp-plugin-controller.php
CHANGED
@@ -394,7 +394,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
394 |
* @uses die()
|
395 |
*/
|
396 |
private function downloadOptionsExport() {
|
397 |
-
$oDp = $this->
|
398 |
if ( $oDp->query( 'icwp_shield_export' ) == 1 ) {
|
399 |
$aExportOptions = apply_filters( $this->prefix( 'gather_options_for_export' ), array() );
|
400 |
if ( !empty( $aExportOptions ) && is_array( $aExportOptions ) ) {
|
@@ -492,7 +492,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
492 |
|
493 |
if ( $this->getPluginSpec_Menu( 'has_submenu' ) ) {
|
494 |
|
495 |
-
$aPluginMenuItems = apply_filters( $this->prefix( '
|
496 |
if ( !empty( $aPluginMenuItems ) ) {
|
497 |
foreach ( $aPluginMenuItems as $sMenuTitle => $aMenu ) {
|
498 |
list( $sMenuItemText, $sMenuItemId, $aMenuCallBack, $bShowItem ) = $aMenu;
|
@@ -714,7 +714,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
714 |
$oConOptions->update_first_detected = array();
|
715 |
}
|
716 |
if ( !isset( $oConOptions->update_first_detected[ $sNewVersion ] ) ) {
|
717 |
-
$oConOptions->update_first_detected[ $sNewVersion ] = $this->
|
718 |
}
|
719 |
|
720 |
// a bit of cleanup to remove the old-style entries which would gather foreva-eva
|
@@ -768,18 +768,12 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
768 |
$sNewVersion = $oWpPlugins->getUpdateNewVersion( $sFile );
|
769 |
if ( !empty( $sNewVersion ) ) {
|
770 |
$nFirstDetected = isset( $oConOptions->update_first_detected[ $sNewVersion ] ) ? $oConOptions->update_first_detected[ $sNewVersion ] : 0;
|
771 |
-
$nTimeUpdateAvailable = $this->
|
772 |
$bDoAutoUpdate = ( $nFirstDetected > 0 && ( $nTimeUpdateAvailable > DAY_IN_SECONDS*$nAutoupdateDays ) );
|
773 |
}
|
774 |
break;
|
775 |
|
776 |
case 'pass' :
|
777 |
-
// Add block to version 6.0 if PHP < 5.3
|
778 |
-
$sNewVersion = $oWpPlugins->getUpdateNewVersion( $sFile );
|
779 |
-
if ( version_compare( $sNewVersion, '6.0.0', '>=' ) && !$this->loadDataProcessor()
|
780 |
-
->getPhpVersionIsAtLeast( '5.3.0' ) ) {
|
781 |
-
$bDoAutoUpdate = false;
|
782 |
-
}
|
783 |
break;
|
784 |
|
785 |
default:
|
@@ -814,7 +808,18 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
814 |
* @return array
|
815 |
*/
|
816 |
public function getPluginLabels() {
|
817 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
818 |
}
|
819 |
|
820 |
/**
|
@@ -966,13 +971,6 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
966 |
protected function getPluginSpec_Labels( $sKey = '' ) {
|
967 |
$oConOptions = $this->getPluginControllerOptions();
|
968 |
$aLabels = isset( $oConOptions->plugin_spec[ 'labels' ] ) ? $oConOptions->plugin_spec[ 'labels' ] : array();
|
969 |
-
//Prep the icon urls
|
970 |
-
if ( !empty( $aLabels[ 'icon_url_16x16' ] ) ) {
|
971 |
-
$aLabels[ 'icon_url_16x16' ] = $this->getPluginUrl_Image( $aLabels[ 'icon_url_16x16' ] );
|
972 |
-
}
|
973 |
-
if ( !empty( $aLabels[ 'icon_url_32x32' ] ) ) {
|
974 |
-
$aLabels[ 'icon_url_32x32' ] = $this->getPluginUrl_Image( $aLabels[ 'icon_url_32x32' ] );
|
975 |
-
}
|
976 |
|
977 |
if ( empty( $sKey ) ) {
|
978 |
return $aLabels;
|
@@ -1108,7 +1106,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
1108 |
|
1109 |
$aFormSubmitOptions = array( 'plugin_form_submit', 'icwp_link_action' );
|
1110 |
|
1111 |
-
$oDp = $this->
|
1112 |
foreach ( $aFormSubmitOptions as $sOption ) {
|
1113 |
if ( !is_null( $oDp->request( $sOption, false ) ) ) {
|
1114 |
return true;
|
@@ -1445,6 +1443,13 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
1445 |
return (bool)$this->getPluginSpec_Property( 'enable_premium' );
|
1446 |
}
|
1447 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1448 |
/**
|
1449 |
*/
|
1450 |
protected function saveCurrentPluginControllerOptions() {
|
@@ -1527,7 +1532,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
|
|
1527 |
*/
|
1528 |
public function getUniqueRequestId( $bSetSessionIfNeeded = true ) {
|
1529 |
if ( !isset( self::$sRequestId ) ) {
|
1530 |
-
$oDp = $this->
|
1531 |
self::$sRequestId = md5( $this->getSessionId( $bSetSessionIfNeeded ).$oDp->loadIpService()
|
1532 |
->getRequestIp().$oDp->time() );
|
1533 |
}
|
394 |
* @uses die()
|
395 |
*/
|
396 |
private function downloadOptionsExport() {
|
397 |
+
$oDp = $this->loadDP();
|
398 |
if ( $oDp->query( 'icwp_shield_export' ) == 1 ) {
|
399 |
$aExportOptions = apply_filters( $this->prefix( 'gather_options_for_export' ), array() );
|
400 |
if ( !empty( $aExportOptions ) && is_array( $aExportOptions ) ) {
|
492 |
|
493 |
if ( $this->getPluginSpec_Menu( 'has_submenu' ) ) {
|
494 |
|
495 |
+
$aPluginMenuItems = apply_filters( $this->prefix( 'submenu_items' ), array() );
|
496 |
if ( !empty( $aPluginMenuItems ) ) {
|
497 |
foreach ( $aPluginMenuItems as $sMenuTitle => $aMenu ) {
|
498 |
list( $sMenuItemText, $sMenuItemId, $aMenuCallBack, $bShowItem ) = $aMenu;
|
714 |
$oConOptions->update_first_detected = array();
|
715 |
}
|
716 |
if ( !isset( $oConOptions->update_first_detected[ $sNewVersion ] ) ) {
|
717 |
+
$oConOptions->update_first_detected[ $sNewVersion ] = $this->loadDP()->time();
|
718 |
}
|
719 |
|
720 |
// a bit of cleanup to remove the old-style entries which would gather foreva-eva
|
768 |
$sNewVersion = $oWpPlugins->getUpdateNewVersion( $sFile );
|
769 |
if ( !empty( $sNewVersion ) ) {
|
770 |
$nFirstDetected = isset( $oConOptions->update_first_detected[ $sNewVersion ] ) ? $oConOptions->update_first_detected[ $sNewVersion ] : 0;
|
771 |
+
$nTimeUpdateAvailable = $this->loadDP()->time() - $nFirstDetected;
|
772 |
$bDoAutoUpdate = ( $nFirstDetected > 0 && ( $nTimeUpdateAvailable > DAY_IN_SECONDS*$nAutoupdateDays ) );
|
773 |
}
|
774 |
break;
|
775 |
|
776 |
case 'pass' :
|
|
|
|
|
|
|
|
|
|
|
|
|
777 |
break;
|
778 |
|
779 |
default:
|
808 |
* @return array
|
809 |
*/
|
810 |
public function getPluginLabels() {
|
811 |
+
|
812 |
+
$aLabels = array_map( 'stripslashes', apply_filters( $this->prefix( 'plugin_labels' ), $this->getPluginSpec_Labels() ) );
|
813 |
+
|
814 |
+
$oDP = $this->loadDP();
|
815 |
+
foreach ( array( '16x16', '32x32', '128x128' ) as $sSize ) {
|
816 |
+
$sKey = 'icon_url_'.$sSize;
|
817 |
+
if ( !empty( $aLabels[ $sKey ] ) && !$oDP->validUrl( $aLabels[ $sKey ] ) ) {
|
818 |
+
$aLabels[ $sKey ] = $this->getPluginUrl_Image( $aLabels[ $sKey ] );
|
819 |
+
}
|
820 |
+
}
|
821 |
+
|
822 |
+
return $aLabels;
|
823 |
}
|
824 |
|
825 |
/**
|
971 |
protected function getPluginSpec_Labels( $sKey = '' ) {
|
972 |
$oConOptions = $this->getPluginControllerOptions();
|
973 |
$aLabels = isset( $oConOptions->plugin_spec[ 'labels' ] ) ? $oConOptions->plugin_spec[ 'labels' ] : array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
974 |
|
975 |
if ( empty( $sKey ) ) {
|
976 |
return $aLabels;
|
1106 |
|
1107 |
$aFormSubmitOptions = array( 'plugin_form_submit', 'icwp_link_action' );
|
1108 |
|
1109 |
+
$oDp = $this->loadDP();
|
1110 |
foreach ( $aFormSubmitOptions as $sOption ) {
|
1111 |
if ( !is_null( $oDp->request( $sOption, false ) ) ) {
|
1112 |
return true;
|
1443 |
return (bool)$this->getPluginSpec_Property( 'enable_premium' );
|
1444 |
}
|
1445 |
|
1446 |
+
/**
|
1447 |
+
* @return bool
|
1448 |
+
*/
|
1449 |
+
public function isRelabelled() {
|
1450 |
+
return apply_filters( $this->prefix( 'is_relabelled' ), false );
|
1451 |
+
}
|
1452 |
+
|
1453 |
/**
|
1454 |
*/
|
1455 |
protected function saveCurrentPluginControllerOptions() {
|
1532 |
*/
|
1533 |
public function getUniqueRequestId( $bSetSessionIfNeeded = true ) {
|
1534 |
if ( !isset( self::$sRequestId ) ) {
|
1535 |
+
$oDp = $this->loadDP();
|
1536 |
self::$sRequestId = md5( $this->getSessionId( $bSetSessionIfNeeded ).$oDp->loadIpService()
|
1537 |
->getRequestIp().$oDp->time() );
|
1538 |
}
|
icwp-wpsf.php
CHANGED
@@ -1,13 +1,13 @@
|
|
1 |
<?php
|
2 |
/*
|
3 |
* Plugin Name: Shield Security
|
4 |
-
* Plugin URI:
|
5 |
* Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
|
6 |
-
* Version: 6.
|
7 |
* Text Domain: wp-simple-firewall
|
8 |
* Domain Path: /languages/
|
9 |
* Author: One Dollar Plugin
|
10 |
-
* Author URI:
|
11 |
*/
|
12 |
|
13 |
/**
|
1 |
<?php
|
2 |
/*
|
3 |
* Plugin Name: Shield Security
|
4 |
+
* Plugin URI: https://icwp.io/2f
|
5 |
* Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
|
6 |
+
* Version: 6.8.0
|
7 |
* Text Domain: wp-simple-firewall
|
8 |
* Domain Path: /languages/
|
9 |
* Author: One Dollar Plugin
|
10 |
+
* Author URI: https://icwp.io/bv
|
11 |
*/
|
12 |
|
13 |
/**
|
init.php
CHANGED
@@ -39,8 +39,12 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Foundation {
|
|
39 |
return self::$oPluginController;
|
40 |
}
|
41 |
|
|
|
|
|
|
|
|
|
42 |
public function getPluginsListUpdateMessage( $sMessage ) {
|
43 |
-
return _wpsf__( 'Upgrade Now To Keep Your
|
44 |
}
|
45 |
|
46 |
/**
|
39 |
return self::$oPluginController;
|
40 |
}
|
41 |
|
42 |
+
/**
|
43 |
+
* @param string $sMessage
|
44 |
+
* @return string
|
45 |
+
*/
|
46 |
public function getPluginsListUpdateMessage( $sMessage ) {
|
47 |
+
return _wpsf__( 'Upgrade Now To Keep Your Security Up-To-Date With The Latest Features.' );
|
48 |
}
|
49 |
|
50 |
/**
|
languages/wp-simple-firewall-nl_NL.mo
CHANGED
Binary file
|
plugin-spec.php
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
{
|
2 |
"properties": {
|
3 |
-
"version": "6.
|
4 |
-
"release_timestamp":
|
5 |
"slug_parent": "icwp",
|
6 |
"slug_plugin": "wpsf",
|
7 |
"human_name": "Shield",
|
@@ -67,15 +67,16 @@
|
|
67 |
"Title": "Shield Security",
|
68 |
"Author": "One Dollar Plugin",
|
69 |
"AuthorName": "One Dollar Plugin",
|
70 |
-
"PluginURI": "
|
71 |
-
"AuthorURI": "
|
72 |
"icon_url_16x16": "pluginlogo_16x16.png",
|
73 |
-
"icon_url_32x32": "pluginlogo_32x32.png"
|
|
|
74 |
},
|
75 |
"plugin_meta": [
|
76 |
{
|
77 |
"name": "5✩ Rate This Plugin",
|
78 |
-
"href": "
|
79 |
}
|
80 |
],
|
81 |
"action_links": {
|
1 |
{
|
2 |
"properties": {
|
3 |
+
"version": "6.8.0",
|
4 |
+
"release_timestamp": 1528704978,
|
5 |
"slug_parent": "icwp",
|
6 |
"slug_plugin": "wpsf",
|
7 |
"human_name": "Shield",
|
67 |
"Title": "Shield Security",
|
68 |
"Author": "One Dollar Plugin",
|
69 |
"AuthorName": "One Dollar Plugin",
|
70 |
+
"PluginURI": "https://icwp.io/2f",
|
71 |
+
"AuthorURI": "https://icwp.io/bv",
|
72 |
"icon_url_16x16": "pluginlogo_16x16.png",
|
73 |
+
"icon_url_32x32": "pluginlogo_32x32.png",
|
74 |
+
"icon_url_128x128": "pluginlogo_128x128.png"
|
75 |
},
|
76 |
"plugin_meta": [
|
77 |
{
|
78 |
"name": "5✩ Rate This Plugin",
|
79 |
+
"href": "https://icwp.io/wpsf29"
|
80 |
}
|
81 |
],
|
82 |
"action_links": {
|
readme.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
=== Shield Security for WordPress ===
|
2 |
Contributors: onedollarplugin, paultgoodchild
|
3 |
-
Donate link:
|
4 |
License: GPLv3
|
5 |
License URI: http://www.gnu.org/licenses/gpl.html
|
6 |
Tags: security, all in one, scan, firewall, two factor authentication, spam, wordfence, cerber, ithemes
|
@@ -8,7 +8,7 @@ Requires at least: 3.5.0
|
|
8 |
Requires PHP: 5.2.4
|
9 |
Recommended PHP: 5.4
|
10 |
Tested up to: 4.9
|
11 |
-
Stable tag: 6.
|
12 |
|
13 |
Complete All-In-One Protection for your WordPress sites, that makes Security Easy for Everyone - it doesn't have to be hard anymore.
|
14 |
|
@@ -95,9 +95,9 @@ From November 2017, Shield Security now has a Pro version for those that need to
|
|
95 |
### Dedicated Premium Support
|
96 |
|
97 |
The Shield Security team prioritises email technical support over the WordPress.org forums.
|
98 |
-
Individual, dedicated technical support is only available to customers who have [purchased Shield Pro](
|
99 |
|
100 |
-
Learn more on going Pro at [our One Dollar Plugin store](
|
101 |
|
102 |
= Our Mission =
|
103 |
|
@@ -124,19 +124,19 @@ downloading and installing Shield now
|
|
124 |
* Exclusive membership to a private security group where you can learn more about WordPress security.
|
125 |
|
126 |
= Super Admin Security Protection =
|
127 |
-
The **only** WordPress security plugin with a WordPress-independent security key to protect itself. [more info](
|
128 |
|
129 |
= Audit Trail Activity Monitor =
|
130 |
With the Audit Trail you can review all major actions that have taken place on your WordPress site, by all users.
|
131 |
|
132 |
= Firewall Protection =
|
133 |
-
Blocks all web requests to the site that violate the firewall security rules! [more info](
|
134 |
|
135 |
= Brute Force Login Guard and Two-Factor Authentication =
|
136 |
-
Provides effective security against Brute Force Hacking and email based Two-Factor Authenticated login. [more info](
|
137 |
|
138 |
= Comment SPAM (Full replacement and upgrade from Akismet) =
|
139 |
-
Blocks **ALL** automatic Bot-SPAM, and catches Human Comments SPAM without sending data to 3rd parties or charging subscription fees. [more info](
|
140 |
|
141 |
= FABLE - Fully Automatic Black Listing Engine =
|
142 |
No more manual IP Black lists. This plugin handles the blocking of IP addresses for hosts that are naughty.
|
@@ -160,9 +160,9 @@ and force users to verify themselves when they login.
|
|
160 |
|
161 |
Three core security features provide layers to protect the WordPress Login system.
|
162 |
|
163 |
-
1. [Email-based 2-Factor Login Authentication](
|
164 |
-
1. [Login Cooldown Interval](
|
165 |
-
1. [GASP Anti-Bot Login Form Protection](
|
166 |
|
167 |
These options alone will protect and secure your WordPress sites from nearly all forms of Brute Force login attacks.
|
168 |
|
@@ -215,7 +215,7 @@ A new menu item will appear on the left-hand side called 'Shield'.
|
|
215 |
|
216 |
== Frequently Asked Questions ==
|
217 |
|
218 |
-
Please see the dedicated [help centre](
|
219 |
|
220 |
= How does the Shield compare with other WordPress Security Plugins? =
|
221 |
|
@@ -306,15 +306,15 @@ When enabled the plugin will prevent more than 1 login attempt to your site ever
|
|
306 |
of 60 seconds, only 1 login attempt will be processed every 60 seconds. If you login incorrectly, you wont be able to attempt another
|
307 |
login for a further 60 seconds.
|
308 |
|
309 |
-
More Info:
|
310 |
|
311 |
= How does the GASP Login Guard work? =
|
312 |
|
313 |
-
This is best [described on the blog](
|
314 |
|
315 |
= How does the 2-factor authentication work? =
|
316 |
|
317 |
-
[2-Factor Authentication is best described here](
|
318 |
|
319 |
= I'm getting an update message although I have auto update enabled? =
|
320 |
|
@@ -346,28 +346,38 @@ Possible options are: network_admin, administrator, editor, author, contributor,
|
|
346 |
== Changelog ==
|
347 |
|
348 |
Our policy was to never restrict security features to Pro upgrades.
|
349 |
-
[This has now changed](
|
350 |
|
351 |
Shield Pro brings exclusive features to the serious webmaster to maximise site security. You'll also have access to our email technical support team.
|
352 |
-
|
353 |
|
354 |
-
|
355 |
|
356 |
-
= 6.
|
357 |
-
*Released:
|
358 |
|
359 |
-
* **(v.
|
360 |
-
* **(v.0)**
|
361 |
-
* **(v.
|
362 |
-
* **(v.
|
|
|
|
|
|
|
|
|
|
|
363 |
|
364 |
-
|
|
|
|
|
|
|
|
|
|
|
365 |
|
366 |
= 6.7 Series =
|
367 |
-
*Released: 21st May, 2018* - [Release Notes](
|
368 |
|
369 |
* **(v.2)** ADDED: [**PRO**] Admin Notes feature - Notes can now be easily deleted (editing will not be possible).
|
370 |
-
* **(v.
|
371 |
* **(v.2)** FIXED: A few bugs with the Insights Dashboard.
|
372 |
* **(v.2)** FIXED: Removed the dependency on jQuery with Invisible reCAPTCHA.
|
373 |
* **(v.1)** FIXED: A few bugs with the Insights Dashboard
|
@@ -382,7 +392,7 @@ Note: The Insights Dashboard is only available on sites with PHP v5.4.0 and abov
|
|
382 |
* **(v.0)** IMPROVED: Compatibility with AIO Events Cal - they like to force their old Twig libraries on everyone else.
|
383 |
|
384 |
= 6.6 Series =
|
385 |
-
*Released: 19th March, 2018* - [Release Notes](
|
386 |
|
387 |
* **(v.7)** IMPROVED: reCAPTCHA JS is only included on pages where it's actually used by Shield.
|
388 |
* **(v.7)** IMPROVED: Upgrade Bootstrap library to 4.1.0.
|
@@ -392,17 +402,17 @@ Note: The Insights Dashboard is only available on sites with PHP v5.4.0 and abov
|
|
392 |
* **(v.6)** ADDED: Workaround for a [ridiculous NGG bug](https://wordpress.org/support/topic/forcefully-executing-wp_footer-not-compatible-with-other-plugins/).
|
393 |
* **(v.1-4)** FIXED: Various small fixes and improvements
|
394 |
* **(v.4)** FIXED: PHP Fatal Error on wp object cache.
|
395 |
-
* **(v.0)** NEW: [**PRO**] [Keyless Activation of Pro licenses](
|
396 |
-
* **(v.0)** ADDED: [WordPress Password Policies](
|
397 |
* **(v.0)** ADDED: Pwned Passwords Detection.
|
398 |
* **(v.0)** IMPROVED: Major rewrite of plugin AJAX handling.
|
399 |
* **(v.0)** IMPROVED: Notices to indicate the time of the last scans.
|
400 |
* **(v.0)** FIXED: A few bugs
|
401 |
|
402 |
= 6.5 Series =
|
403 |
-
*Released: 5th March, 2018* - [Release Notes](
|
404 |
|
405 |
-
* **(v.0)** IMPROVED: [Plugin Guard](
|
406 |
* **(v.0)** IMPROVED: Attempts to access the XML-RPC system when it's disabled will now result in a transgression increment in the IP Black List
|
407 |
* **(v.0)** IMPROVED: Try to prevent black listing the server's own public IP address where visitor IP address detection is not correctly configured.
|
408 |
* **(v.0)** ADDED: [**PRO**] Provisional support for not processing 2FA logins for Woocommerce Social Login plugin.
|
1 |
=== Shield Security for WordPress ===
|
2 |
Contributors: onedollarplugin, paultgoodchild
|
3 |
+
Donate link: https://icwp.io/bw
|
4 |
License: GPLv3
|
5 |
License URI: http://www.gnu.org/licenses/gpl.html
|
6 |
Tags: security, all in one, scan, firewall, two factor authentication, spam, wordfence, cerber, ithemes
|
8 |
Requires PHP: 5.2.4
|
9 |
Recommended PHP: 5.4
|
10 |
Tested up to: 4.9
|
11 |
+
Stable tag: 6.8.0
|
12 |
|
13 |
Complete All-In-One Protection for your WordPress sites, that makes Security Easy for Everyone - it doesn't have to be hard anymore.
|
14 |
|
95 |
### Dedicated Premium Support
|
96 |
|
97 |
The Shield Security team prioritises email technical support over the WordPress.org forums.
|
98 |
+
Individual, dedicated technical support is only available to customers who have [purchased Shield Pro](https://icwp.io/ab).
|
99 |
|
100 |
+
Learn more on going Pro at [our One Dollar Plugin store](https://icwp.io/ab).
|
101 |
|
102 |
= Our Mission =
|
103 |
|
124 |
* Exclusive membership to a private security group where you can learn more about WordPress security.
|
125 |
|
126 |
= Super Admin Security Protection =
|
127 |
+
The **only** WordPress security plugin with a WordPress-independent security key to protect itself. [more info](https://icwp.io/wpsf05)
|
128 |
|
129 |
= Audit Trail Activity Monitor =
|
130 |
With the Audit Trail you can review all major actions that have taken place on your WordPress site, by all users.
|
131 |
|
132 |
= Firewall Protection =
|
133 |
+
Blocks all web requests to the site that violate the firewall security rules! [more info](https://icwp.io/wpsf06)
|
134 |
|
135 |
= Brute Force Login Guard and Two-Factor Authentication =
|
136 |
+
Provides effective security against Brute Force Hacking and email based Two-Factor Authenticated login. [more info](https://icwp.io/wpsf07)
|
137 |
|
138 |
= Comment SPAM (Full replacement and upgrade from Akismet) =
|
139 |
+
Blocks **ALL** automatic Bot-SPAM, and catches Human Comments SPAM without sending data to 3rd parties or charging subscription fees. [more info](https://icwp.io/wpsf08)
|
140 |
|
141 |
= FABLE - Fully Automatic Black Listing Engine =
|
142 |
No more manual IP Black lists. This plugin handles the blocking of IP addresses for hosts that are naughty.
|
160 |
|
161 |
Three core security features provide layers to protect the WordPress Login system.
|
162 |
|
163 |
+
1. [Email-based 2-Factor Login Authentication](https://icwp.io/2v) based on IP address! (prevents brute force login attacks)
|
164 |
+
1. [Login Cooldown Interval](https://icwp.io/2t) - WordPress will only process 1 login per interval in seconds (prevents brute force login attacks)
|
165 |
+
1. [GASP Anti-Bot Login Form Protection](https://icwp.io/2u) - Adds 2 protection checks for all WordPress login attempts (prevents brute force login attacks using Bots)
|
166 |
|
167 |
These options alone will protect and secure your WordPress sites from nearly all forms of Brute Force login attacks.
|
168 |
|
215 |
|
216 |
== Frequently Asked Questions ==
|
217 |
|
218 |
+
Please see the dedicated [help centre](https://icwp.io/firewallhelp) for details on features and some FAQs.
|
219 |
|
220 |
= How does the Shield compare with other WordPress Security Plugins? =
|
221 |
|
306 |
of 60 seconds, only 1 login attempt will be processed every 60 seconds. If you login incorrectly, you wont be able to attempt another
|
307 |
login for a further 60 seconds.
|
308 |
|
309 |
+
More Info: https://icwp.io/2t
|
310 |
|
311 |
= How does the GASP Login Guard work? =
|
312 |
|
313 |
+
This is best [described on the blog](https://icwp.io/2u)
|
314 |
|
315 |
= How does the 2-factor authentication work? =
|
316 |
|
317 |
+
[2-Factor Authentication is best described here](https://icwp.io/2v).
|
318 |
|
319 |
= I'm getting an update message although I have auto update enabled? =
|
320 |
|
346 |
== Changelog ==
|
347 |
|
348 |
Our policy was to never restrict security features to Pro upgrades.
|
349 |
+
[This has now changed](https://icwp.io/bs).
|
350 |
|
351 |
Shield Pro brings exclusive features to the serious webmaster to maximise site security. You'll also have access to our email technical support team.
|
352 |
+
You will always be able to use Shield Security and its free features in-full.
|
353 |
|
354 |
+
[Go Pro for just $1/month](https://icwp.io/aa).
|
355 |
|
356 |
+
= 6.8.0 - Current Release =
|
357 |
+
*Released: 11th June, 2018* - [Release Notes](https://icwp.io/d4)
|
358 |
|
359 |
+
* **(v.0)** ADDED: [**PRO**] White Label - ability to re-brand the entire Shield Security plugin to your company brand.
|
360 |
+
* **(v.0)** ADDED: [**PRO**] Option for all users to receive notification email upon login to their accounts.
|
361 |
+
* **(v.0)** IMPROVED: Completely rebuilt the bot and reCAPTCHA login protection system.
|
362 |
+
* **(v.0)** IMPROVED: Import/Export system hugely improved with respect to automated push of options from Master sites.
|
363 |
+
* **(v.0)** IMPROVED: A different approach to sessions management that should handle sessions a bit better.
|
364 |
+
* **(v.0)** IMPROVED: Expired user sessions are cleaned from the DB using a cron, and on Insights Dashboard load.
|
365 |
+
|
366 |
+
= 6.8 Series =
|
367 |
+
*Released: 11th June, 2018* - [Release Notes](https://icwp.io/d4)
|
368 |
|
369 |
+
* **(v.0)** ADDED: [**PRO**] White Label - ability to re-brand the entire Shield Security plugin to your company brand.
|
370 |
+
* **(v.0)** ADDED: [**PRO**] Option for all users to receive notification email upon login to their accounts.
|
371 |
+
* **(v.0)** IMPROVED: Completely rebuilt the bot and reCAPTCHA login protection system.
|
372 |
+
* **(v.0)** IMPROVED: Import/Export system hugely improved with respect to automated push of options from Master sites.
|
373 |
+
* **(v.0)** IMPROVED: A different approach to sessions management that should handle sessions a bit better.
|
374 |
+
* **(v.0)** IMPROVED: Expired user sessions are cleaned from the DB using a cron, and on Insights Dashboard load.
|
375 |
|
376 |
= 6.7 Series =
|
377 |
+
*Released: 21st May, 2018* - [Release Notes](https://icwp.io/cx)
|
378 |
|
379 |
* **(v.2)** ADDED: [**PRO**] Admin Notes feature - Notes can now be easily deleted (editing will not be possible).
|
380 |
+
* **(v.2)** UPDATED: Some translations.
|
381 |
* **(v.2)** FIXED: A few bugs with the Insights Dashboard.
|
382 |
* **(v.2)** FIXED: Removed the dependency on jQuery with Invisible reCAPTCHA.
|
383 |
* **(v.1)** FIXED: A few bugs with the Insights Dashboard
|
392 |
* **(v.0)** IMPROVED: Compatibility with AIO Events Cal - they like to force their old Twig libraries on everyone else.
|
393 |
|
394 |
= 6.6 Series =
|
395 |
+
*Released: 19th March, 2018* - [Release Notes](https://icwp.io/c3)
|
396 |
|
397 |
* **(v.7)** IMPROVED: reCAPTCHA JS is only included on pages where it's actually used by Shield.
|
398 |
* **(v.7)** IMPROVED: Upgrade Bootstrap library to 4.1.0.
|
402 |
* **(v.6)** ADDED: Workaround for a [ridiculous NGG bug](https://wordpress.org/support/topic/forcefully-executing-wp_footer-not-compatible-with-other-plugins/).
|
403 |
* **(v.1-4)** FIXED: Various small fixes and improvements
|
404 |
* **(v.4)** FIXED: PHP Fatal Error on wp object cache.
|
405 |
+
* **(v.0)** NEW: [**PRO**] [Keyless Activation of Pro licenses](https://icwp.io/c1).
|
406 |
+
* **(v.0)** ADDED: [WordPress Password Policies](https://icwp.io/c2).
|
407 |
* **(v.0)** ADDED: Pwned Passwords Detection.
|
408 |
* **(v.0)** IMPROVED: Major rewrite of plugin AJAX handling.
|
409 |
* **(v.0)** IMPROVED: Notices to indicate the time of the last scans.
|
410 |
* **(v.0)** FIXED: A few bugs
|
411 |
|
412 |
= 6.5 Series =
|
413 |
+
*Released: 5th March, 2018* - [Release Notes](https://icwp.io/bu)
|
414 |
|
415 |
+
* **(v.0)** IMPROVED: [Plugin Guard](https://icwp.io/bq) better handles the case where a plugin/theme has been entirely renamed/removed.
|
416 |
* **(v.0)** IMPROVED: Attempts to access the XML-RPC system when it's disabled will now result in a transgression increment in the IP Black List
|
417 |
* **(v.0)** IMPROVED: Try to prevent black listing the server's own public IP address where visitor IP address detection is not correctly configured.
|
418 |
* **(v.0)** ADDED: [**PRO**] Provisional support for not processing 2FA logins for Woocommerce Social Login plugin.
|
resources/css/plugin.css
CHANGED
@@ -666,6 +666,7 @@ input:checked + .icwp-slider:before {
|
|
666 |
|
667 |
height: 128px;
|
668 |
width: 128px;
|
|
|
669 |
|
670 |
margin-bottom: 7px;
|
671 |
position: relative;
|
666 |
|
667 |
height: 128px;
|
668 |
width: 128px;
|
669 |
+
background-size: 128px 128px;
|
670 |
|
671 |
margin-bottom: 7px;
|
672 |
position: relative;
|
resources/images/pluginlogo_128x128.png
ADDED
Binary file
|
resources/js/plugin.js
CHANGED
@@ -31,6 +31,21 @@ var iCWP_WPSF_OptionsPages = new function () {
|
|
31 |
jQuery( document ).on( "click", "a.icwp-carousel-1", moveCarousel1 );
|
32 |
jQuery( document ).on( "click", "a.icwp-carousel-2", moveCarousel2 );
|
33 |
jQuery( document ).on( "click", "a.icwp-carousel-3", moveCarousel3 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
} );
|
35 |
};
|
36 |
|
@@ -70,13 +85,11 @@ var iCWP_WPSF_OptionsFormSubmit = new function () {
|
|
70 |
else {
|
71 |
sMessage = oResponse.data.message;
|
72 |
}
|
73 |
-
/** TODO: div#icwpOptionsFormContainer no longer exists */
|
74 |
-
jQuery( 'div#icwpOptionsFormContainer' ).html( oResponse.data.options_form );
|
75 |
iCWP_WPSF_Growl.showMessage( sMessage, oResponse.success );
|
76 |
}
|
77 |
).always( function () {
|
78 |
bRequestCurrentlyRunning = false;
|
79 |
-
|
80 |
}
|
81 |
);
|
82 |
};
|
31 |
jQuery( document ).on( "click", "a.icwp-carousel-1", moveCarousel1 );
|
32 |
jQuery( document ).on( "click", "a.icwp-carousel-2", moveCarousel2 );
|
33 |
jQuery( document ).on( "click", "a.icwp-carousel-3", moveCarousel3 );
|
34 |
+
|
35 |
+
/** Track active tab */
|
36 |
+
jQuery( document ).on( "click", "#ModuleOptionsNav a.nav-link", function ( e ) {
|
37 |
+
e.preventDefault();
|
38 |
+
jQuery( this ).tab( 'show' );
|
39 |
+
jQuery( 'html,body' ).scrollTop( 0 );
|
40 |
+
} );
|
41 |
+
jQuery( document ).on( "shown.bs.tab", "#ModuleOptionsNav a.nav-link", function ( e ) {
|
42 |
+
window.location.hash = jQuery( e.target ).attr( "href" ).substr( 1 );
|
43 |
+
} );
|
44 |
+
|
45 |
+
var sActiveTabHash = window.location.hash;
|
46 |
+
if ( sActiveTabHash ) {
|
47 |
+
jQuery( '#ModuleOptionsNav a[href="' + window.location.hash + '"]' ).tab( 'show' );
|
48 |
+
}
|
49 |
} );
|
50 |
};
|
51 |
|
85 |
else {
|
86 |
sMessage = oResponse.data.message;
|
87 |
}
|
|
|
|
|
88 |
iCWP_WPSF_Growl.showMessage( sMessage, oResponse.success );
|
89 |
}
|
90 |
).always( function () {
|
91 |
bRequestCurrentlyRunning = false;
|
92 |
+
location.reload( true );
|
93 |
}
|
94 |
);
|
95 |
};
|
src/common/icwp-data.php
CHANGED
@@ -243,12 +243,21 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
|
|
243 |
}
|
244 |
|
245 |
/**
|
|
|
246 |
* @return boolean
|
247 |
*/
|
248 |
public function validEmail( $sEmail ) {
|
249 |
return ( !empty( $sEmail ) && function_exists( 'is_email' ) && is_email( $sEmail ) );
|
250 |
}
|
251 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
/**
|
253 |
* @param string $sRawList
|
254 |
* @return array
|
243 |
}
|
244 |
|
245 |
/**
|
246 |
+
* @param string $sEmail
|
247 |
* @return boolean
|
248 |
*/
|
249 |
public function validEmail( $sEmail ) {
|
250 |
return ( !empty( $sEmail ) && function_exists( 'is_email' ) && is_email( $sEmail ) );
|
251 |
}
|
252 |
|
253 |
+
/**
|
254 |
+
* @param string $sUrl
|
255 |
+
* @return bool
|
256 |
+
*/
|
257 |
+
public function validUrl( $sUrl ) {
|
258 |
+
return filter_var( $sUrl, FILTER_VALIDATE_URL );
|
259 |
+
}
|
260 |
+
|
261 |
/**
|
262 |
* @param string $sRawList
|
263 |
* @return array
|
src/common/icwp-foundation.php
CHANGED
@@ -93,13 +93,6 @@ class ICWP_WPSF_Foundation {
|
|
93 |
return self::$oDp;
|
94 |
}
|
95 |
|
96 |
-
/**
|
97 |
-
* @return ICWP_WPSF_DataProcessor
|
98 |
-
*/
|
99 |
-
static public function loadDataProcessor() {
|
100 |
-
return self::loadDP();
|
101 |
-
}
|
102 |
-
|
103 |
/**
|
104 |
* @return ICWP_WPSF_WpFilesystem
|
105 |
*/
|
@@ -308,7 +301,7 @@ class ICWP_WPSF_Foundation {
|
|
308 |
/**
|
309 |
* @return ICWP_WPSF_WpComments
|
310 |
*/
|
311 |
-
static public function
|
312 |
if ( !isset( self::$oWpComments ) ) {
|
313 |
self::requireCommonLib( 'wp-comments.php' );
|
314 |
self::$oWpComments = ICWP_WPSF_WpComments::GetInstance();
|
@@ -339,4 +332,20 @@ class ICWP_WPSF_Foundation {
|
|
339 |
static public function requireCommonLib( $sFile ) {
|
340 |
require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.$sFile );
|
341 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
342 |
}
|
93 |
return self::$oDp;
|
94 |
}
|
95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
/**
|
97 |
* @return ICWP_WPSF_WpFilesystem
|
98 |
*/
|
301 |
/**
|
302 |
* @return ICWP_WPSF_WpComments
|
303 |
*/
|
304 |
+
static public function loadWpComments() {
|
305 |
if ( !isset( self::$oWpComments ) ) {
|
306 |
self::requireCommonLib( 'wp-comments.php' );
|
307 |
self::$oWpComments = ICWP_WPSF_WpComments::GetInstance();
|
332 |
static public function requireCommonLib( $sFile ) {
|
333 |
require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.$sFile );
|
334 |
}
|
335 |
+
|
336 |
+
/**
|
337 |
+
* @deprecated
|
338 |
+
* @return ICWP_WPSF_WpComments
|
339 |
+
*/
|
340 |
+
static public function loadWpCommentsProcessor() {
|
341 |
+
return self::loadWpComments();
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* @deprecated
|
346 |
+
* @return ICWP_WPSF_DataProcessor
|
347 |
+
*/
|
348 |
+
static public function loadDataProcessor() {
|
349 |
+
return self::loadDP();
|
350 |
+
}
|
351 |
}
|
src/common/icwp-render.php
CHANGED
@@ -176,7 +176,7 @@ class ICWP_WPSF_Render extends ICWP_WPSF_Foundation {
|
|
176 |
* @return string
|
177 |
*/
|
178 |
public function getTemplate() {
|
179 |
-
$this->sTemplate = $this->
|
180 |
->addExtensionToFilePath( $this->sTemplate, $this->getEngineStub() );
|
181 |
return $this->sTemplate;
|
182 |
}
|
@@ -213,7 +213,7 @@ class ICWP_WPSF_Render extends ICWP_WPSF_Foundation {
|
|
213 |
if ( empty( $sTemplate ) ) {
|
214 |
$sTemplate = $this->getTemplate();
|
215 |
}
|
216 |
-
$sTemplate = $this->
|
217 |
return path_join( $this->getTemplateRoot(), $sTemplate );
|
218 |
}
|
219 |
|
176 |
* @return string
|
177 |
*/
|
178 |
public function getTemplate() {
|
179 |
+
$this->sTemplate = $this->loadDP()
|
180 |
->addExtensionToFilePath( $this->sTemplate, $this->getEngineStub() );
|
181 |
return $this->sTemplate;
|
182 |
}
|
213 |
if ( empty( $sTemplate ) ) {
|
214 |
$sTemplate = $this->getTemplate();
|
215 |
}
|
216 |
+
$sTemplate = $this->loadDP()->addExtensionToFilePath( $sTemplate, $this->getEngineStub() );
|
217 |
return path_join( $this->getTemplateRoot(), $sTemplate );
|
218 |
}
|
219 |
|
src/common/icwp-wpfunctions-plugins.php
CHANGED
@@ -490,7 +490,7 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
|
|
490 |
public function setActivePluginLoadPosition( $sFile, $nDesiredPosition = 0 ) {
|
491 |
$oWp = $this->loadWp();
|
492 |
|
493 |
-
$aActive = $this->
|
494 |
->setArrayValueToPosition(
|
495 |
$oWp->getOption( 'active_plugins' ),
|
496 |
$sFile,
|
@@ -499,7 +499,7 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
|
|
499 |
$oWp->updateOption( 'active_plugins', $aActive );
|
500 |
|
501 |
if ( $oWp->isMultisite() ) {
|
502 |
-
$aActive = $this->
|
503 |
->setArrayValueToPosition( $oWp->getOption( 'active_sitewide_plugins' ), $sFile, $nDesiredPosition );
|
504 |
$oWp->updateOption( 'active_sitewide_plugins', $aActive );
|
505 |
}
|
490 |
public function setActivePluginLoadPosition( $sFile, $nDesiredPosition = 0 ) {
|
491 |
$oWp = $this->loadWp();
|
492 |
|
493 |
+
$aActive = $this->loadDP()
|
494 |
->setArrayValueToPosition(
|
495 |
$oWp->getOption( 'active_plugins' ),
|
496 |
$sFile,
|
499 |
$oWp->updateOption( 'active_plugins', $aActive );
|
500 |
|
501 |
if ( $oWp->isMultisite() ) {
|
502 |
+
$aActive = $this->loadDP()
|
503 |
->setArrayValueToPosition( $oWp->getOption( 'active_sitewide_plugins' ), $sFile, $nDesiredPosition );
|
504 |
$oWp->updateOption( 'active_sitewide_plugins', $aActive );
|
505 |
}
|
src/common/icwp-wpfunctions.php
CHANGED
@@ -408,7 +408,7 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
|
|
408 |
}
|
409 |
|
410 |
public function redirectHere() {
|
411 |
-
$this->doRedirect( $this->
|
412 |
}
|
413 |
|
414 |
/**
|
@@ -853,7 +853,7 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
|
|
853 |
}
|
854 |
}
|
855 |
|
856 |
-
$nTime = is_null( $nTime ) ? $this->
|
857 |
return $nTime + ( $nTimezoneOffset*HOUR_IN_SECONDS );
|
858 |
}
|
859 |
|
408 |
}
|
409 |
|
410 |
public function redirectHere() {
|
411 |
+
$this->doRedirect( $this->loadDP()->getRequestUri() );
|
412 |
}
|
413 |
|
414 |
/**
|
853 |
}
|
854 |
}
|
855 |
|
856 |
+
$nTime = is_null( $nTime ) ? $this->loadDP()->time() : $nTime;
|
857 |
return $nTime + ( $nTimezoneOffset*HOUR_IN_SECONDS );
|
858 |
}
|
859 |
|
src/common/lib/composer.lock
CHANGED
@@ -87,16 +87,16 @@
|
|
87 |
},
|
88 |
{
|
89 |
"name": "nesbot/carbon",
|
90 |
-
"version": "1.
|
91 |
"source": {
|
92 |
"type": "git",
|
93 |
"url": "https://github.com/briannesbitt/Carbon.git",
|
94 |
-
"reference": "
|
95 |
},
|
96 |
"dist": {
|
97 |
"type": "zip",
|
98 |
-
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/
|
99 |
-
"reference": "
|
100 |
"shasum": ""
|
101 |
},
|
102 |
"require": {
|
@@ -108,14 +108,9 @@
|
|
108 |
"phpunit/phpunit": "^4.8.35 || ^5.7"
|
109 |
},
|
110 |
"type": "library",
|
111 |
-
"extra": {
|
112 |
-
"branch-alias": {
|
113 |
-
"dev-master": "1.23-dev"
|
114 |
-
}
|
115 |
-
},
|
116 |
"autoload": {
|
117 |
"psr-4": {
|
118 |
-
"
|
119 |
}
|
120 |
},
|
121 |
"notification-url": "https://packagist.org/downloads/",
|
@@ -136,20 +131,20 @@
|
|
136 |
"datetime",
|
137 |
"time"
|
138 |
],
|
139 |
-
"time": "2018-
|
140 |
},
|
141 |
{
|
142 |
"name": "symfony/polyfill-mbstring",
|
143 |
-
"version": "v1.
|
144 |
"source": {
|
145 |
"type": "git",
|
146 |
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
147 |
-
"reference": "
|
148 |
},
|
149 |
"dist": {
|
150 |
"type": "zip",
|
151 |
-
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/
|
152 |
-
"reference": "
|
153 |
"shasum": ""
|
154 |
},
|
155 |
"require": {
|
@@ -161,7 +156,7 @@
|
|
161 |
"type": "library",
|
162 |
"extra": {
|
163 |
"branch-alias": {
|
164 |
-
"dev-master": "1.
|
165 |
}
|
166 |
},
|
167 |
"autoload": {
|
@@ -195,20 +190,20 @@
|
|
195 |
"portable",
|
196 |
"shim"
|
197 |
],
|
198 |
-
"time": "2018-
|
199 |
},
|
200 |
{
|
201 |
"name": "symfony/translation",
|
202 |
-
"version": "v2.8.
|
203 |
"source": {
|
204 |
"type": "git",
|
205 |
"url": "https://github.com/symfony/translation.git",
|
206 |
-
"reference": "
|
207 |
},
|
208 |
"dist": {
|
209 |
"type": "zip",
|
210 |
-
"url": "https://api.github.com/repos/symfony/translation/zipball/
|
211 |
-
"reference": "
|
212 |
"shasum": ""
|
213 |
},
|
214 |
"require": {
|
@@ -225,7 +220,7 @@
|
|
225 |
"symfony/yaml": "~2.2|~3.0.0"
|
226 |
},
|
227 |
"suggest": {
|
228 |
-
"psr/log": "To use logging capability in translator",
|
229 |
"symfony/config": "",
|
230 |
"symfony/yaml": ""
|
231 |
},
|
@@ -259,7 +254,7 @@
|
|
259 |
],
|
260 |
"description": "Symfony Translation Component",
|
261 |
"homepage": "https://symfony.com",
|
262 |
-
"time": "2018-
|
263 |
},
|
264 |
{
|
265 |
"name": "twig/twig",
|
87 |
},
|
88 |
{
|
89 |
"name": "nesbot/carbon",
|
90 |
+
"version": "1.29.2",
|
91 |
"source": {
|
92 |
"type": "git",
|
93 |
"url": "https://github.com/briannesbitt/Carbon.git",
|
94 |
+
"reference": "ed6aa898982f441ccc9b2acdec51490f2bc5d337"
|
95 |
},
|
96 |
"dist": {
|
97 |
"type": "zip",
|
98 |
+
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/ed6aa898982f441ccc9b2acdec51490f2bc5d337",
|
99 |
+
"reference": "ed6aa898982f441ccc9b2acdec51490f2bc5d337",
|
100 |
"shasum": ""
|
101 |
},
|
102 |
"require": {
|
108 |
"phpunit/phpunit": "^4.8.35 || ^5.7"
|
109 |
},
|
110 |
"type": "library",
|
|
|
|
|
|
|
|
|
|
|
111 |
"autoload": {
|
112 |
"psr-4": {
|
113 |
+
"": "src/"
|
114 |
}
|
115 |
},
|
116 |
"notification-url": "https://packagist.org/downloads/",
|
131 |
"datetime",
|
132 |
"time"
|
133 |
],
|
134 |
+
"time": "2018-05-29T15:23:46+00:00"
|
135 |
},
|
136 |
{
|
137 |
"name": "symfony/polyfill-mbstring",
|
138 |
+
"version": "v1.8.0",
|
139 |
"source": {
|
140 |
"type": "git",
|
141 |
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
142 |
+
"reference": "3296adf6a6454a050679cde90f95350ad604b171"
|
143 |
},
|
144 |
"dist": {
|
145 |
"type": "zip",
|
146 |
+
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171",
|
147 |
+
"reference": "3296adf6a6454a050679cde90f95350ad604b171",
|
148 |
"shasum": ""
|
149 |
},
|
150 |
"require": {
|
156 |
"type": "library",
|
157 |
"extra": {
|
158 |
"branch-alias": {
|
159 |
+
"dev-master": "1.8-dev"
|
160 |
}
|
161 |
},
|
162 |
"autoload": {
|
190 |
"portable",
|
191 |
"shim"
|
192 |
],
|
193 |
+
"time": "2018-04-26T10:06:28+00:00"
|
194 |
},
|
195 |
{
|
196 |
"name": "symfony/translation",
|
197 |
+
"version": "v2.8.41",
|
198 |
"source": {
|
199 |
"type": "git",
|
200 |
"url": "https://github.com/symfony/translation.git",
|
201 |
+
"reference": "c6a27966a92fa361bf2c3a938abc6dee91f7ad67"
|
202 |
},
|
203 |
"dist": {
|
204 |
"type": "zip",
|
205 |
+
"url": "https://api.github.com/repos/symfony/translation/zipball/c6a27966a92fa361bf2c3a938abc6dee91f7ad67",
|
206 |
+
"reference": "c6a27966a92fa361bf2c3a938abc6dee91f7ad67",
|
207 |
"shasum": ""
|
208 |
},
|
209 |
"require": {
|
220 |
"symfony/yaml": "~2.2|~3.0.0"
|
221 |
},
|
222 |
"suggest": {
|
223 |
+
"psr/log-implementation": "To use logging capability in translator",
|
224 |
"symfony/config": "",
|
225 |
"symfony/yaml": ""
|
226 |
},
|
254 |
],
|
255 |
"description": "Symfony Translation Component",
|
256 |
"homepage": "https://symfony.com",
|
257 |
+
"time": "2018-05-21T09:59:10+00:00"
|
258 |
},
|
259 |
{
|
260 |
"name": "twig/twig",
|
src/common/lib/vendor/composer/autoload_psr4.php
CHANGED
@@ -11,5 +11,5 @@ return array(
|
|
11 |
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
12 |
'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
|
13 |
'FernleafSystems\\Utilities\\' => array($vendorDir . '/fernleafsystems/utilities/src'),
|
14 |
-
'
|
15 |
);
|
11 |
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
12 |
'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
|
13 |
'FernleafSystems\\Utilities\\' => array($vendorDir . '/fernleafsystems/utilities/src'),
|
14 |
+
'' => array($vendorDir . '/nesbot/carbon/src'),
|
15 |
);
|
src/common/lib/vendor/composer/autoload_static.php
CHANGED
@@ -28,10 +28,6 @@ class ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1
|
|
28 |
array (
|
29 |
'FernleafSystems\\Utilities\\' => 26,
|
30 |
),
|
31 |
-
'C' =>
|
32 |
-
array (
|
33 |
-
'Carbon\\' => 7,
|
34 |
-
),
|
35 |
);
|
36 |
|
37 |
public static $prefixDirsPsr4 = array (
|
@@ -55,10 +51,10 @@ class ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1
|
|
55 |
array (
|
56 |
0 => __DIR__ . '/..' . '/fernleafsystems/utilities/src',
|
57 |
),
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
);
|
63 |
|
64 |
public static $prefixesPsr0 = array (
|
@@ -76,6 +72,7 @@ class ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1
|
|
76 |
return \Closure::bind(function () use ($loader) {
|
77 |
$loader->prefixLengthsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixLengthsPsr4;
|
78 |
$loader->prefixDirsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixDirsPsr4;
|
|
|
79 |
$loader->prefixesPsr0 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixesPsr0;
|
80 |
|
81 |
}, null, ClassLoader::class);
|
28 |
array (
|
29 |
'FernleafSystems\\Utilities\\' => 26,
|
30 |
),
|
|
|
|
|
|
|
|
|
31 |
);
|
32 |
|
33 |
public static $prefixDirsPsr4 = array (
|
51 |
array (
|
52 |
0 => __DIR__ . '/..' . '/fernleafsystems/utilities/src',
|
53 |
),
|
54 |
+
);
|
55 |
+
|
56 |
+
public static $fallbackDirsPsr4 = array (
|
57 |
+
0 => __DIR__ . '/..' . '/nesbot/carbon/src',
|
58 |
);
|
59 |
|
60 |
public static $prefixesPsr0 = array (
|
72 |
return \Closure::bind(function () use ($loader) {
|
73 |
$loader->prefixLengthsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixLengthsPsr4;
|
74 |
$loader->prefixDirsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixDirsPsr4;
|
75 |
+
$loader->fallbackDirsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$fallbackDirsPsr4;
|
76 |
$loader->prefixesPsr0 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixesPsr0;
|
77 |
|
78 |
}, null, ClassLoader::class);
|
src/common/lib/vendor/composer/installed.json
CHANGED
@@ -82,19 +82,86 @@
|
|
82 |
],
|
83 |
"description": "Collection of simple utilities and traits"
|
84 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
{
|
86 |
"name": "symfony/polyfill-mbstring",
|
87 |
-
"version": "v1.
|
88 |
-
"version_normalized": "1.
|
89 |
"source": {
|
90 |
"type": "git",
|
91 |
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
92 |
-
"reference": "
|
93 |
},
|
94 |
"dist": {
|
95 |
"type": "zip",
|
96 |
-
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/
|
97 |
-
"reference": "
|
98 |
"shasum": ""
|
99 |
},
|
100 |
"require": {
|
@@ -103,11 +170,11 @@
|
|
103 |
"suggest": {
|
104 |
"ext-mbstring": "For best performance"
|
105 |
},
|
106 |
-
"time": "2018-
|
107 |
"type": "library",
|
108 |
"extra": {
|
109 |
"branch-alias": {
|
110 |
-
"dev-master": "1.
|
111 |
}
|
112 |
},
|
113 |
"installation-source": "dist",
|
@@ -145,17 +212,17 @@
|
|
145 |
},
|
146 |
{
|
147 |
"name": "symfony/translation",
|
148 |
-
"version": "v2.8.
|
149 |
-
"version_normalized": "2.8.
|
150 |
"source": {
|
151 |
"type": "git",
|
152 |
"url": "https://github.com/symfony/translation.git",
|
153 |
-
"reference": "
|
154 |
},
|
155 |
"dist": {
|
156 |
"type": "zip",
|
157 |
-
"url": "https://api.github.com/repos/symfony/translation/zipball/
|
158 |
-
"reference": "
|
159 |
"shasum": ""
|
160 |
},
|
161 |
"require": {
|
@@ -172,11 +239,11 @@
|
|
172 |
"symfony/yaml": "~2.2|~3.0.0"
|
173 |
},
|
174 |
"suggest": {
|
175 |
-
"psr/log": "To use logging capability in translator",
|
176 |
"symfony/config": "",
|
177 |
"symfony/yaml": ""
|
178 |
},
|
179 |
-
"time": "2018-
|
180 |
"type": "library",
|
181 |
"extra": {
|
182 |
"branch-alias": {
|
@@ -211,17 +278,17 @@
|
|
211 |
},
|
212 |
{
|
213 |
"name": "nesbot/carbon",
|
214 |
-
"version": "1.
|
215 |
-
"version_normalized": "1.
|
216 |
"source": {
|
217 |
"type": "git",
|
218 |
"url": "https://github.com/briannesbitt/Carbon.git",
|
219 |
-
"reference": "
|
220 |
},
|
221 |
"dist": {
|
222 |
"type": "zip",
|
223 |
-
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/
|
224 |
-
"reference": "
|
225 |
"shasum": ""
|
226 |
},
|
227 |
"require": {
|
@@ -232,17 +299,12 @@
|
|
232 |
"friendsofphp/php-cs-fixer": "~2",
|
233 |
"phpunit/phpunit": "^4.8.35 || ^5.7"
|
234 |
},
|
235 |
-
"time": "2018-
|
236 |
"type": "library",
|
237 |
-
"extra": {
|
238 |
-
"branch-alias": {
|
239 |
-
"dev-master": "1.23-dev"
|
240 |
-
}
|
241 |
-
},
|
242 |
"installation-source": "dist",
|
243 |
"autoload": {
|
244 |
"psr-4": {
|
245 |
-
"
|
246 |
}
|
247 |
},
|
248 |
"notification-url": "https://packagist.org/downloads/",
|
@@ -263,72 +325,5 @@
|
|
263 |
"datetime",
|
264 |
"time"
|
265 |
]
|
266 |
-
},
|
267 |
-
{
|
268 |
-
"name": "twig/twig",
|
269 |
-
"version": "v1.35.3",
|
270 |
-
"version_normalized": "1.35.3.0",
|
271 |
-
"source": {
|
272 |
-
"type": "git",
|
273 |
-
"url": "https://github.com/twigphp/Twig.git",
|
274 |
-
"reference": "b48680b6eb7d16b5025b9bfc4108d86f6b8af86f"
|
275 |
-
},
|
276 |
-
"dist": {
|
277 |
-
"type": "zip",
|
278 |
-
"url": "https://api.github.com/repos/twigphp/Twig/zipball/b48680b6eb7d16b5025b9bfc4108d86f6b8af86f",
|
279 |
-
"reference": "b48680b6eb7d16b5025b9bfc4108d86f6b8af86f",
|
280 |
-
"shasum": ""
|
281 |
-
},
|
282 |
-
"require": {
|
283 |
-
"php": ">=5.3.3"
|
284 |
-
},
|
285 |
-
"require-dev": {
|
286 |
-
"psr/container": "^1.0",
|
287 |
-
"symfony/debug": "^2.7",
|
288 |
-
"symfony/phpunit-bridge": "^3.3"
|
289 |
-
},
|
290 |
-
"time": "2018-03-20T04:25:58+00:00",
|
291 |
-
"type": "library",
|
292 |
-
"extra": {
|
293 |
-
"branch-alias": {
|
294 |
-
"dev-master": "1.35-dev"
|
295 |
-
}
|
296 |
-
},
|
297 |
-
"installation-source": "dist",
|
298 |
-
"autoload": {
|
299 |
-
"psr-0": {
|
300 |
-
"Twig_": "lib/"
|
301 |
-
},
|
302 |
-
"psr-4": {
|
303 |
-
"Twig\\": "src/"
|
304 |
-
}
|
305 |
-
},
|
306 |
-
"notification-url": "https://packagist.org/downloads/",
|
307 |
-
"license": [
|
308 |
-
"BSD-3-Clause"
|
309 |
-
],
|
310 |
-
"authors": [
|
311 |
-
{
|
312 |
-
"name": "Fabien Potencier",
|
313 |
-
"email": "fabien@symfony.com",
|
314 |
-
"homepage": "http://fabien.potencier.org",
|
315 |
-
"role": "Lead Developer"
|
316 |
-
},
|
317 |
-
{
|
318 |
-
"name": "Armin Ronacher",
|
319 |
-
"email": "armin.ronacher@active-4.com",
|
320 |
-
"role": "Project Founder"
|
321 |
-
},
|
322 |
-
{
|
323 |
-
"name": "Twig Team",
|
324 |
-
"homepage": "http://twig.sensiolabs.org/contributors",
|
325 |
-
"role": "Contributors"
|
326 |
-
}
|
327 |
-
],
|
328 |
-
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
329 |
-
"homepage": "http://twig.sensiolabs.org",
|
330 |
-
"keywords": [
|
331 |
-
"templating"
|
332 |
-
]
|
333 |
}
|
334 |
]
|
82 |
],
|
83 |
"description": "Collection of simple utilities and traits"
|
84 |
},
|
85 |
+
{
|
86 |
+
"name": "twig/twig",
|
87 |
+
"version": "v1.35.3",
|
88 |
+
"version_normalized": "1.35.3.0",
|
89 |
+
"source": {
|
90 |
+
"type": "git",
|
91 |
+
"url": "https://github.com/twigphp/Twig.git",
|
92 |
+
"reference": "b48680b6eb7d16b5025b9bfc4108d86f6b8af86f"
|
93 |
+
},
|
94 |
+
"dist": {
|
95 |
+
"type": "zip",
|
96 |
+
"url": "https://api.github.com/repos/twigphp/Twig/zipball/b48680b6eb7d16b5025b9bfc4108d86f6b8af86f",
|
97 |
+
"reference": "b48680b6eb7d16b5025b9bfc4108d86f6b8af86f",
|
98 |
+
"shasum": ""
|
99 |
+
},
|
100 |
+
"require": {
|
101 |
+
"php": ">=5.3.3"
|
102 |
+
},
|
103 |
+
"require-dev": {
|
104 |
+
"psr/container": "^1.0",
|
105 |
+
"symfony/debug": "^2.7",
|
106 |
+
"symfony/phpunit-bridge": "^3.3"
|
107 |
+
},
|
108 |
+
"time": "2018-03-20T04:25:58+00:00",
|
109 |
+
"type": "library",
|
110 |
+
"extra": {
|
111 |
+
"branch-alias": {
|
112 |
+
"dev-master": "1.35-dev"
|
113 |
+
}
|
114 |
+
},
|
115 |
+
"installation-source": "dist",
|
116 |
+
"autoload": {
|
117 |
+
"psr-0": {
|
118 |
+
"Twig_": "lib/"
|
119 |
+
},
|
120 |
+
"psr-4": {
|
121 |
+
"Twig\\": "src/"
|
122 |
+
}
|
123 |
+
},
|
124 |
+
"notification-url": "https://packagist.org/downloads/",
|
125 |
+
"license": [
|
126 |
+
"BSD-3-Clause"
|
127 |
+
],
|
128 |
+
"authors": [
|
129 |
+
{
|
130 |
+
"name": "Fabien Potencier",
|
131 |
+
"email": "fabien@symfony.com",
|
132 |
+
"homepage": "http://fabien.potencier.org",
|
133 |
+
"role": "Lead Developer"
|
134 |
+
},
|
135 |
+
{
|
136 |
+
"name": "Armin Ronacher",
|
137 |
+
"email": "armin.ronacher@active-4.com",
|
138 |
+
"role": "Project Founder"
|
139 |
+
},
|
140 |
+
{
|
141 |
+
"name": "Twig Team",
|
142 |
+
"homepage": "http://twig.sensiolabs.org/contributors",
|
143 |
+
"role": "Contributors"
|
144 |
+
}
|
145 |
+
],
|
146 |
+
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
147 |
+
"homepage": "http://twig.sensiolabs.org",
|
148 |
+
"keywords": [
|
149 |
+
"templating"
|
150 |
+
]
|
151 |
+
},
|
152 |
{
|
153 |
"name": "symfony/polyfill-mbstring",
|
154 |
+
"version": "v1.8.0",
|
155 |
+
"version_normalized": "1.8.0.0",
|
156 |
"source": {
|
157 |
"type": "git",
|
158 |
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
159 |
+
"reference": "3296adf6a6454a050679cde90f95350ad604b171"
|
160 |
},
|
161 |
"dist": {
|
162 |
"type": "zip",
|
163 |
+
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171",
|
164 |
+
"reference": "3296adf6a6454a050679cde90f95350ad604b171",
|
165 |
"shasum": ""
|
166 |
},
|
167 |
"require": {
|
170 |
"suggest": {
|
171 |
"ext-mbstring": "For best performance"
|
172 |
},
|
173 |
+
"time": "2018-04-26T10:06:28+00:00",
|
174 |
"type": "library",
|
175 |
"extra": {
|
176 |
"branch-alias": {
|
177 |
+
"dev-master": "1.8-dev"
|
178 |
}
|
179 |
},
|
180 |
"installation-source": "dist",
|
212 |
},
|
213 |
{
|
214 |
"name": "symfony/translation",
|
215 |
+
"version": "v2.8.41",
|
216 |
+
"version_normalized": "2.8.41.0",
|
217 |
"source": {
|
218 |
"type": "git",
|
219 |
"url": "https://github.com/symfony/translation.git",
|
220 |
+
"reference": "c6a27966a92fa361bf2c3a938abc6dee91f7ad67"
|
221 |
},
|
222 |
"dist": {
|
223 |
"type": "zip",
|
224 |
+
"url": "https://api.github.com/repos/symfony/translation/zipball/c6a27966a92fa361bf2c3a938abc6dee91f7ad67",
|
225 |
+
"reference": "c6a27966a92fa361bf2c3a938abc6dee91f7ad67",
|
226 |
"shasum": ""
|
227 |
},
|
228 |
"require": {
|
239 |
"symfony/yaml": "~2.2|~3.0.0"
|
240 |
},
|
241 |
"suggest": {
|
242 |
+
"psr/log-implementation": "To use logging capability in translator",
|
243 |
"symfony/config": "",
|
244 |
"symfony/yaml": ""
|
245 |
},
|
246 |
+
"time": "2018-05-21T09:59:10+00:00",
|
247 |
"type": "library",
|
248 |
"extra": {
|
249 |
"branch-alias": {
|
278 |
},
|
279 |
{
|
280 |
"name": "nesbot/carbon",
|
281 |
+
"version": "1.29.2",
|
282 |
+
"version_normalized": "1.29.2.0",
|
283 |
"source": {
|
284 |
"type": "git",
|
285 |
"url": "https://github.com/briannesbitt/Carbon.git",
|
286 |
+
"reference": "ed6aa898982f441ccc9b2acdec51490f2bc5d337"
|
287 |
},
|
288 |
"dist": {
|
289 |
"type": "zip",
|
290 |
+
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/ed6aa898982f441ccc9b2acdec51490f2bc5d337",
|
291 |
+
"reference": "ed6aa898982f441ccc9b2acdec51490f2bc5d337",
|
292 |
"shasum": ""
|
293 |
},
|
294 |
"require": {
|
299 |
"friendsofphp/php-cs-fixer": "~2",
|
300 |
"phpunit/phpunit": "^4.8.35 || ^5.7"
|
301 |
},
|
302 |
+
"time": "2018-05-29T15:23:46+00:00",
|
303 |
"type": "library",
|
|
|
|
|
|
|
|
|
|
|
304 |
"installation-source": "dist",
|
305 |
"autoload": {
|
306 |
"psr-4": {
|
307 |
+
"": "src/"
|
308 |
}
|
309 |
},
|
310 |
"notification-url": "https://packagist.org/downloads/",
|
325 |
"datetime",
|
326 |
"time"
|
327 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
}
|
329 |
]
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Carbon.php
CHANGED
@@ -18,6 +18,7 @@ use DateTime;
|
|
18 |
use DateTimeInterface;
|
19 |
use DateTimeZone;
|
20 |
use InvalidArgumentException;
|
|
|
21 |
use Symfony\Component\Translation\TranslatorInterface;
|
22 |
|
23 |
/**
|
@@ -51,8 +52,13 @@ use Symfony\Component\Translation\TranslatorInterface;
|
|
51 |
* @property-read string $timezoneName
|
52 |
* @property-read string $tzName
|
53 |
*/
|
54 |
-
class Carbon extends DateTime
|
55 |
{
|
|
|
|
|
|
|
|
|
|
|
56 |
/**
|
57 |
* The day constants.
|
58 |
*/
|
@@ -87,6 +93,7 @@ class Carbon extends DateTime
|
|
87 |
const MONTHS_PER_YEAR = 12;
|
88 |
const MONTHS_PER_QUARTER = 3;
|
89 |
const WEEKS_PER_YEAR = 52;
|
|
|
90 |
const DAYS_PER_WEEK = 7;
|
91 |
const HOURS_PER_DAY = 24;
|
92 |
const MINUTES_PER_HOUR = 60;
|
@@ -227,6 +234,20 @@ class Carbon extends DateTime
|
|
227 |
*/
|
228 |
protected static $lastErrors;
|
229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
/**
|
231 |
* Will UTF8 encoding be used to print localized date/time ?
|
232 |
*
|
@@ -255,6 +276,53 @@ class Carbon extends DateTime
|
|
255 |
*/
|
256 |
protected static $yearsOverflow = true;
|
257 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
258 |
/**
|
259 |
* Add microseconds to now on PHP < 7.1 and 7.1.3 if set to true,
|
260 |
* let microseconds to 0 on those PHP versions if false.
|
@@ -341,6 +409,26 @@ class Carbon extends DateTime
|
|
341 |
return static::$yearsOverflow;
|
342 |
}
|
343 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
/**
|
345 |
* Creates a DateTimeZone from a string, DateTimeZone or integer offset.
|
346 |
*
|
@@ -371,13 +459,25 @@ class Carbon extends DateTime
|
|
371 |
$object = $tzName;
|
372 |
}
|
373 |
|
374 |
-
$tz = @timezone_open((string) $object);
|
375 |
|
376 |
-
if ($tz
|
377 |
-
|
378 |
}
|
379 |
|
380 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
381 |
}
|
382 |
|
383 |
///////////////////////////////////////////////////////////////////
|
@@ -446,16 +546,18 @@ class Carbon extends DateTime
|
|
446 |
/**
|
447 |
* Create a Carbon instance from a DateTime one.
|
448 |
*
|
449 |
-
* @param \DateTime $date
|
450 |
*
|
451 |
* @return static
|
452 |
*/
|
453 |
-
public static function instance(
|
454 |
{
|
455 |
if ($date instanceof static) {
|
456 |
return clone $date;
|
457 |
}
|
458 |
|
|
|
|
|
459 |
return new static($date->format('Y-m-d H:i:s.u'), $date->getTimezone());
|
460 |
}
|
461 |
|
@@ -616,7 +718,7 @@ class Carbon extends DateTime
|
|
616 |
$year = 9999;
|
617 |
}
|
618 |
|
619 |
-
$instance = static::createFromFormat('Y-n-j G:i:s', sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz);
|
620 |
|
621 |
if ($fixYear !== null) {
|
622 |
$instance->addYears($fixYear);
|
@@ -744,6 +846,13 @@ class Carbon extends DateTime
|
|
744 |
return static::today($tz)->setTimeFromTimeString($time);
|
745 |
}
|
746 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
747 |
/**
|
748 |
* Create a Carbon instance from a specific format.
|
749 |
*
|
@@ -757,15 +866,32 @@ class Carbon extends DateTime
|
|
757 |
*/
|
758 |
public static function createFromFormat($format, $time, $tz = null)
|
759 |
{
|
760 |
-
|
761 |
-
|
762 |
-
} else {
|
763 |
-
$date = parent::createFromFormat($format, $time);
|
764 |
-
}
|
765 |
-
|
766 |
$lastErrors = parent::getLastErrors();
|
767 |
|
768 |
-
if ($date instanceof DateTime) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
769 |
$instance = static::instance($date);
|
770 |
$instance::setLastErrors($lastErrors);
|
771 |
|
@@ -834,6 +960,32 @@ class Carbon extends DateTime
|
|
834 |
return new static('@'.$timestamp);
|
835 |
}
|
836 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
837 |
/**
|
838 |
* Get a copy of the instance.
|
839 |
*
|
@@ -854,6 +1006,23 @@ class Carbon extends DateTime
|
|
854 |
return static::now($this->getTimezone());
|
855 |
}
|
856 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
857 |
/**
|
858 |
* Return the Carbon instance passed through, a now instance in the same timezone
|
859 |
* if null given or parse the input if string given.
|
@@ -872,12 +1041,7 @@ class Carbon extends DateTime
|
|
872 |
return static::parse($date, $this->getTimezone());
|
873 |
}
|
874 |
|
875 |
-
|
876 |
-
throw new InvalidArgumentException(
|
877 |
-
'Expected null, string, DateTime or DateTimeInterface, '.
|
878 |
-
(is_object($date) ? get_class($date) : gettype($date)).' given'
|
879 |
-
);
|
880 |
-
}
|
881 |
|
882 |
return $date instanceof self ? $date : static::instance($date);
|
883 |
}
|
@@ -1202,6 +1366,38 @@ class Carbon extends DateTime
|
|
1202 |
return $this;
|
1203 |
}
|
1204 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1205 |
/**
|
1206 |
* Get the days of the week
|
1207 |
*
|
@@ -1872,7 +2068,7 @@ class Carbon extends DateTime
|
|
1872 |
*
|
1873 |
* @param \Carbon\Carbon|\DateTimeInterface|mixed $date1
|
1874 |
* @param \Carbon\Carbon|\DateTimeInterface|mixed $date2
|
1875 |
-
* @param bool $equal Indicates if
|
1876 |
*
|
1877 |
* @return bool
|
1878 |
*/
|
@@ -1974,7 +2170,7 @@ class Carbon extends DateTime
|
|
1974 |
}
|
1975 |
|
1976 |
/**
|
1977 |
-
* Determines if the instance is a weekday
|
1978 |
*
|
1979 |
* @return bool
|
1980 |
*/
|
@@ -1984,7 +2180,7 @@ class Carbon extends DateTime
|
|
1984 |
}
|
1985 |
|
1986 |
/**
|
1987 |
-
* Determines if the instance is a weekend day
|
1988 |
*
|
1989 |
* @return bool
|
1990 |
*/
|
@@ -1994,7 +2190,7 @@ class Carbon extends DateTime
|
|
1994 |
}
|
1995 |
|
1996 |
/**
|
1997 |
-
* Determines if the instance is yesterday
|
1998 |
*
|
1999 |
* @return bool
|
2000 |
*/
|
@@ -2004,7 +2200,7 @@ class Carbon extends DateTime
|
|
2004 |
}
|
2005 |
|
2006 |
/**
|
2007 |
-
* Determines if the instance is today
|
2008 |
*
|
2009 |
* @return bool
|
2010 |
*/
|
@@ -2014,7 +2210,7 @@ class Carbon extends DateTime
|
|
2014 |
}
|
2015 |
|
2016 |
/**
|
2017 |
-
* Determines if the instance is tomorrow
|
2018 |
*
|
2019 |
* @return bool
|
2020 |
*/
|
@@ -2024,7 +2220,7 @@ class Carbon extends DateTime
|
|
2024 |
}
|
2025 |
|
2026 |
/**
|
2027 |
-
* Determines if the instance is within the next week
|
2028 |
*
|
2029 |
* @return bool
|
2030 |
*/
|
@@ -2034,7 +2230,7 @@ class Carbon extends DateTime
|
|
2034 |
}
|
2035 |
|
2036 |
/**
|
2037 |
-
* Determines if the instance is within the last week
|
2038 |
*
|
2039 |
* @return bool
|
2040 |
*/
|
@@ -2044,7 +2240,27 @@ class Carbon extends DateTime
|
|
2044 |
}
|
2045 |
|
2046 |
/**
|
2047 |
-
* Determines if the instance is within the next
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2048 |
*
|
2049 |
* @return bool
|
2050 |
*/
|
@@ -2054,7 +2270,7 @@ class Carbon extends DateTime
|
|
2054 |
}
|
2055 |
|
2056 |
/**
|
2057 |
-
* Determines if the instance is within the last month
|
2058 |
*
|
2059 |
* @return bool
|
2060 |
*/
|
@@ -2064,7 +2280,7 @@ class Carbon extends DateTime
|
|
2064 |
}
|
2065 |
|
2066 |
/**
|
2067 |
-
* Determines if the instance is within next year
|
2068 |
*
|
2069 |
* @return bool
|
2070 |
*/
|
@@ -2074,7 +2290,7 @@ class Carbon extends DateTime
|
|
2074 |
}
|
2075 |
|
2076 |
/**
|
2077 |
-
* Determines if the instance is within the previous year
|
2078 |
*
|
2079 |
* @return bool
|
2080 |
*/
|
@@ -2084,7 +2300,7 @@ class Carbon extends DateTime
|
|
2084 |
}
|
2085 |
|
2086 |
/**
|
2087 |
-
* Determines if the instance is in the future, ie. greater (after) than now
|
2088 |
*
|
2089 |
* @return bool
|
2090 |
*/
|
@@ -2094,7 +2310,7 @@ class Carbon extends DateTime
|
|
2094 |
}
|
2095 |
|
2096 |
/**
|
2097 |
-
* Determines if the instance is in the past, ie. less (before) than now
|
2098 |
*
|
2099 |
* @return bool
|
2100 |
*/
|
@@ -2104,7 +2320,7 @@ class Carbon extends DateTime
|
|
2104 |
}
|
2105 |
|
2106 |
/**
|
2107 |
-
* Determines if the instance is a leap year
|
2108 |
*
|
2109 |
* @return bool
|
2110 |
*/
|
@@ -2139,15 +2355,13 @@ class Carbon extends DateTime
|
|
2139 |
{
|
2140 |
$date = $date ?: static::now($this->tz);
|
2141 |
|
2142 |
-
|
2143 |
-
throw new InvalidArgumentException('Expected DateTime (or instanceof) object as argument.');
|
2144 |
-
}
|
2145 |
|
2146 |
return $this->format($format) === $date->format($format);
|
2147 |
}
|
2148 |
|
2149 |
/**
|
2150 |
-
* Determines if the instance is in the current year
|
2151 |
*
|
2152 |
* @return bool
|
2153 |
*/
|
@@ -2169,40 +2383,152 @@ class Carbon extends DateTime
|
|
2169 |
}
|
2170 |
|
2171 |
/**
|
2172 |
-
* Determines if the instance is in the current month
|
2173 |
*
|
2174 |
* @return bool
|
2175 |
*/
|
2176 |
-
public function
|
2177 |
{
|
2178 |
-
return $this->
|
2179 |
}
|
2180 |
|
2181 |
/**
|
2182 |
-
* Checks if the passed in date is in the same
|
2183 |
*
|
2184 |
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use current day.
|
2185 |
* @param bool $ofSameYear Check if it is the same month in the same year.
|
2186 |
*
|
2187 |
* @return bool
|
2188 |
*/
|
2189 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2190 |
{
|
|
|
|
|
2191 |
return $this->isSameAs($ofSameYear ? 'Y-m' : 'm', $date);
|
2192 |
}
|
2193 |
|
2194 |
/**
|
2195 |
-
*
|
2196 |
*
|
2197 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2198 |
*
|
2199 |
* @return bool
|
2200 |
*/
|
2201 |
-
public function isSameDay($date)
|
2202 |
{
|
2203 |
return $this->isSameAs('Y-m-d', $date);
|
2204 |
}
|
2205 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2206 |
/**
|
2207 |
* Checks if this day is a specific day of the week.
|
2208 |
*
|
@@ -2285,6 +2611,78 @@ class Carbon extends DateTime
|
|
2285 |
return $this->dayOfWeek === static::SATURDAY;
|
2286 |
}
|
2287 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2288 |
/**
|
2289 |
* Checks if the (date)time string is in a given format.
|
2290 |
*
|
@@ -3178,6 +3576,19 @@ class Carbon extends DateTime
|
|
3178 |
/////////////////////////// DIFFERENCES ///////////////////////////
|
3179 |
///////////////////////////////////////////////////////////////////
|
3180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3181 |
/**
|
3182 |
* Get the difference in years
|
3183 |
*
|
@@ -3283,7 +3694,7 @@ class Carbon extends DateTime
|
|
3283 |
}
|
3284 |
|
3285 |
$period = new DatePeriod($start, $ci, $end);
|
3286 |
-
$values = array_filter(iterator_to_array($period), function (
|
3287 |
return call_user_func($callback, Carbon::instance($date));
|
3288 |
});
|
3289 |
|
@@ -3512,7 +3923,14 @@ class Carbon extends DateTime
|
|
3512 |
}
|
3513 |
|
3514 |
if (count($interval) === 0) {
|
3515 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3516 |
$unit = $short ? 's' : 'second';
|
3517 |
$interval[] = static::translator()->transChoice($unit, $count, array(':count' => $count));
|
3518 |
}
|
@@ -3531,6 +3949,22 @@ class Carbon extends DateTime
|
|
3531 |
$transId = $isNow ? ($isFuture ? 'from_now' : 'ago') : ($isFuture ? 'after' : 'before');
|
3532 |
|
3533 |
if ($parts === 1) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3534 |
// Some langs have special pluralization for past and future tense.
|
3535 |
$key = $unit.'_'.$transId;
|
3536 |
$count = isset($count) ? $count : 1;
|
@@ -4024,27 +4458,9 @@ class Carbon extends DateTime
|
|
4024 |
return $this->addSeconds((int) ($this->diffInSeconds($this->resolveCarbon($date), false) / 2));
|
4025 |
}
|
4026 |
|
4027 |
-
|
4028 |
-
|
4029 |
-
|
4030 |
-
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use current day.
|
4031 |
-
*
|
4032 |
-
* @return bool
|
4033 |
-
*/
|
4034 |
-
public function isBirthday($date = null)
|
4035 |
-
{
|
4036 |
-
return $this->isSameAs('md', $date);
|
4037 |
-
}
|
4038 |
-
|
4039 |
-
/**
|
4040 |
-
* Check if today is the last day of the Month
|
4041 |
-
*
|
4042 |
-
* @return bool
|
4043 |
-
*/
|
4044 |
-
public function isLastOfMonth()
|
4045 |
-
{
|
4046 |
-
return $this->day === $this->daysInMonth;
|
4047 |
-
}
|
4048 |
|
4049 |
/**
|
4050 |
* Return a serialized string of the instance.
|
@@ -4087,4 +4503,143 @@ class Carbon extends DateTime
|
|
4087 |
{
|
4088 |
return static::instance(parent::__set_state($array));
|
4089 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4090 |
}
|
18 |
use DateTimeInterface;
|
19 |
use DateTimeZone;
|
20 |
use InvalidArgumentException;
|
21 |
+
use JsonSerializable;
|
22 |
use Symfony\Component\Translation\TranslatorInterface;
|
23 |
|
24 |
/**
|
52 |
* @property-read string $timezoneName
|
53 |
* @property-read string $tzName
|
54 |
*/
|
55 |
+
class Carbon extends DateTime implements JsonSerializable
|
56 |
{
|
57 |
+
const NO_ZERO_DIFF = 01;
|
58 |
+
const JUST_NOW = 02;
|
59 |
+
const ONE_DAY_WORDS = 04;
|
60 |
+
const TWO_DAY_WORDS = 010;
|
61 |
+
|
62 |
/**
|
63 |
* The day constants.
|
64 |
*/
|
93 |
const MONTHS_PER_YEAR = 12;
|
94 |
const MONTHS_PER_QUARTER = 3;
|
95 |
const WEEKS_PER_YEAR = 52;
|
96 |
+
const WEEKS_PER_MONTH = 4;
|
97 |
const DAYS_PER_WEEK = 7;
|
98 |
const HOURS_PER_DAY = 24;
|
99 |
const MINUTES_PER_HOUR = 60;
|
234 |
*/
|
235 |
protected static $lastErrors;
|
236 |
|
237 |
+
/**
|
238 |
+
* The custom Carbon JSON serializer.
|
239 |
+
*
|
240 |
+
* @var callable|null
|
241 |
+
*/
|
242 |
+
protected static $serializer;
|
243 |
+
|
244 |
+
/**
|
245 |
+
* The registered string macros.
|
246 |
+
*
|
247 |
+
* @var array
|
248 |
+
*/
|
249 |
+
protected static $localMacros = array();
|
250 |
+
|
251 |
/**
|
252 |
* Will UTF8 encoding be used to print localized date/time ?
|
253 |
*
|
276 |
*/
|
277 |
protected static $yearsOverflow = true;
|
278 |
|
279 |
+
/**
|
280 |
+
* Indicates if years are compared with month by default so isSameMonth and isSameQuarter have $ofSameYear set
|
281 |
+
* to true by default.
|
282 |
+
*
|
283 |
+
* @var bool
|
284 |
+
*/
|
285 |
+
protected static $compareYearWithMonth = false;
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Options for diffForHumans().
|
289 |
+
*
|
290 |
+
* @var int
|
291 |
+
*/
|
292 |
+
protected static $humanDiffOptions = self::NO_ZERO_DIFF;
|
293 |
+
|
294 |
+
/**
|
295 |
+
* @param int $humanDiffOptions
|
296 |
+
*/
|
297 |
+
public static function setHumanDiffOptions($humanDiffOptions)
|
298 |
+
{
|
299 |
+
static::$humanDiffOptions = $humanDiffOptions;
|
300 |
+
}
|
301 |
+
|
302 |
+
/**
|
303 |
+
* @param int $humanDiffOption
|
304 |
+
*/
|
305 |
+
public static function enableHumanDiffOption($humanDiffOption)
|
306 |
+
{
|
307 |
+
static::$humanDiffOptions = static::getHumanDiffOptions() | $humanDiffOption;
|
308 |
+
}
|
309 |
+
|
310 |
+
/**
|
311 |
+
* @param int $humanDiffOption
|
312 |
+
*/
|
313 |
+
public static function disableHumanDiffOption($humanDiffOption)
|
314 |
+
{
|
315 |
+
static::$humanDiffOptions = static::getHumanDiffOptions() & ~$humanDiffOption;
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* @return int
|
320 |
+
*/
|
321 |
+
public static function getHumanDiffOptions()
|
322 |
+
{
|
323 |
+
return static::$humanDiffOptions;
|
324 |
+
}
|
325 |
+
|
326 |
/**
|
327 |
* Add microseconds to now on PHP < 7.1 and 7.1.3 if set to true,
|
328 |
* let microseconds to 0 on those PHP versions if false.
|
409 |
return static::$yearsOverflow;
|
410 |
}
|
411 |
|
412 |
+
/**
|
413 |
+
* Get the month comparison default behavior.
|
414 |
+
*
|
415 |
+
* @return bool
|
416 |
+
*/
|
417 |
+
public static function compareYearWithMonth($compareYearWithMonth = true)
|
418 |
+
{
|
419 |
+
static::$compareYearWithMonth = $compareYearWithMonth;
|
420 |
+
}
|
421 |
+
|
422 |
+
/**
|
423 |
+
* Get the month comparison default behavior.
|
424 |
+
*
|
425 |
+
* @return bool
|
426 |
+
*/
|
427 |
+
public static function shouldCompareYearWithMonth()
|
428 |
+
{
|
429 |
+
return static::$compareYearWithMonth;
|
430 |
+
}
|
431 |
+
|
432 |
/**
|
433 |
* Creates a DateTimeZone from a string, DateTimeZone or integer offset.
|
434 |
*
|
459 |
$object = $tzName;
|
460 |
}
|
461 |
|
462 |
+
$tz = @timezone_open($object = (string) $object);
|
463 |
|
464 |
+
if ($tz !== false) {
|
465 |
+
return $tz;
|
466 |
}
|
467 |
|
468 |
+
// Work-around for a bug fixed in PHP 5.5.10 https://bugs.php.net/bug.php?id=45528
|
469 |
+
// See: https://stackoverflow.com/q/14068594/2646927
|
470 |
+
// @codeCoverageIgnoreStart
|
471 |
+
if (strpos($object, ':') !== false) {
|
472 |
+
try {
|
473 |
+
return static::createFromFormat('O', $object)->getTimezone();
|
474 |
+
} catch (InvalidArgumentException $e) {
|
475 |
+
//
|
476 |
+
}
|
477 |
+
}
|
478 |
+
// @codeCoverageIgnoreEnd
|
479 |
+
|
480 |
+
throw new InvalidArgumentException('Unknown or bad timezone ('.$object.')');
|
481 |
}
|
482 |
|
483 |
///////////////////////////////////////////////////////////////////
|
546 |
/**
|
547 |
* Create a Carbon instance from a DateTime one.
|
548 |
*
|
549 |
+
* @param \DateTime|\DateTimeInterface $date
|
550 |
*
|
551 |
* @return static
|
552 |
*/
|
553 |
+
public static function instance($date)
|
554 |
{
|
555 |
if ($date instanceof static) {
|
556 |
return clone $date;
|
557 |
}
|
558 |
|
559 |
+
static::expectDateTime($date);
|
560 |
+
|
561 |
return new static($date->format('Y-m-d H:i:s.u'), $date->getTimezone());
|
562 |
}
|
563 |
|
718 |
$year = 9999;
|
719 |
}
|
720 |
|
721 |
+
$instance = static::createFromFormat('!Y-n-j G:i:s', sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz);
|
722 |
|
723 |
if ($fixYear !== null) {
|
724 |
$instance->addYears($fixYear);
|
846 |
return static::today($tz)->setTimeFromTimeString($time);
|
847 |
}
|
848 |
|
849 |
+
private static function createFromFormatAndTimezone($format, $time, $tz)
|
850 |
+
{
|
851 |
+
return $tz !== null
|
852 |
+
? parent::createFromFormat($format, $time, static::safeCreateDateTimeZone($tz))
|
853 |
+
: parent::createFromFormat($format, $time);
|
854 |
+
}
|
855 |
+
|
856 |
/**
|
857 |
* Create a Carbon instance from a specific format.
|
858 |
*
|
866 |
*/
|
867 |
public static function createFromFormat($format, $time, $tz = null)
|
868 |
{
|
869 |
+
// First attempt to create an instance, so that error messages are based on the unmodified format.
|
870 |
+
$date = self::createFromFormatAndTimezone($format, $time, $tz);
|
|
|
|
|
|
|
|
|
871 |
$lastErrors = parent::getLastErrors();
|
872 |
|
873 |
+
if (($mock = static::getTestNow()) && ($date instanceof DateTime || $date instanceof DateTimeInterface)) {
|
874 |
+
// Set timezone from mock if custom timezone was neither given directly nor as a part of format.
|
875 |
+
// First let's skip the part that will be ignored by the parser.
|
876 |
+
$nonEscaped = '(?<!\\\\)(\\\\{2})*';
|
877 |
+
|
878 |
+
$nonIgnored = preg_replace("/^.*{$nonEscaped}!/s", '', $format);
|
879 |
+
|
880 |
+
if ($tz === null && !preg_match("/{$nonEscaped}[eOPT]/", $nonIgnored)) {
|
881 |
+
$tz = $mock->getTimezone();
|
882 |
+
}
|
883 |
+
|
884 |
+
// Prepend mock datetime only if the format does not contain non escaped unix epoch reset flag.
|
885 |
+
if (!preg_match("/{$nonEscaped}[!|]/", $format)) {
|
886 |
+
$format = static::MOCK_DATETIME_FORMAT.' '.$format;
|
887 |
+
$time = $mock->format(static::MOCK_DATETIME_FORMAT).' '.$time;
|
888 |
+
}
|
889 |
+
|
890 |
+
// Regenerate date from the modified format to base result on the mocked instance instead of now.
|
891 |
+
$date = self::createFromFormatAndTimezone($format, $time, $tz);
|
892 |
+
}
|
893 |
+
|
894 |
+
if ($date instanceof DateTime || $date instanceof DateTimeInterface) {
|
895 |
$instance = static::instance($date);
|
896 |
$instance::setLastErrors($lastErrors);
|
897 |
|
960 |
return new static('@'.$timestamp);
|
961 |
}
|
962 |
|
963 |
+
/**
|
964 |
+
* Make a Carbon instance from given variable if possible.
|
965 |
+
*
|
966 |
+
* Always return a new instance. Parse only strings and only these likely to be dates (skip intervals
|
967 |
+
* and recurrences). Throw an exception for invalid format, but otherwise return null.
|
968 |
+
*
|
969 |
+
* @param mixed $var
|
970 |
+
*
|
971 |
+
* @return static|null
|
972 |
+
*/
|
973 |
+
public static function make($var)
|
974 |
+
{
|
975 |
+
if ($var instanceof DateTime || $var instanceof DateTimeInterface) {
|
976 |
+
return static::instance($var);
|
977 |
+
}
|
978 |
+
|
979 |
+
if (is_string($var)) {
|
980 |
+
$var = trim($var);
|
981 |
+
$first = substr($var, 0, 1);
|
982 |
+
|
983 |
+
if (is_string($var) && $first !== 'P' && $first !== 'R' && preg_match('/[a-z0-9]/i', $var)) {
|
984 |
+
return static::parse($var);
|
985 |
+
}
|
986 |
+
}
|
987 |
+
}
|
988 |
+
|
989 |
/**
|
990 |
* Get a copy of the instance.
|
991 |
*
|
1006 |
return static::now($this->getTimezone());
|
1007 |
}
|
1008 |
|
1009 |
+
/**
|
1010 |
+
* Throws an exception if the given object is not a DateTime and does not implement DateTimeInterface.
|
1011 |
+
*
|
1012 |
+
* @param mixed $date
|
1013 |
+
*
|
1014 |
+
* @throws \InvalidArgumentException
|
1015 |
+
*/
|
1016 |
+
protected static function expectDateTime($date)
|
1017 |
+
{
|
1018 |
+
if (!$date instanceof DateTime && !$date instanceof DateTimeInterface) {
|
1019 |
+
throw new InvalidArgumentException(
|
1020 |
+
'Expected null, string, DateTime or DateTimeInterface, '.
|
1021 |
+
(is_object($date) ? get_class($date) : gettype($date)).' given'
|
1022 |
+
);
|
1023 |
+
}
|
1024 |
+
}
|
1025 |
+
|
1026 |
/**
|
1027 |
* Return the Carbon instance passed through, a now instance in the same timezone
|
1028 |
* if null given or parse the input if string given.
|
1041 |
return static::parse($date, $this->getTimezone());
|
1042 |
}
|
1043 |
|
1044 |
+
static::expectDateTime($date);
|
|
|
|
|
|
|
|
|
|
|
1045 |
|
1046 |
return $date instanceof self ? $date : static::instance($date);
|
1047 |
}
|
1366 |
return $this;
|
1367 |
}
|
1368 |
|
1369 |
+
/**
|
1370 |
+
* Set the year, month, and date for this instance to that of the passed instance.
|
1371 |
+
*
|
1372 |
+
* @param \Carbon\Carbon|\DateTimeInterface $date
|
1373 |
+
*
|
1374 |
+
* @return static
|
1375 |
+
*/
|
1376 |
+
public function setDateFrom($date)
|
1377 |
+
{
|
1378 |
+
$date = static::instance($date);
|
1379 |
+
|
1380 |
+
$this->setDate($date->year, $date->month, $date->day);
|
1381 |
+
|
1382 |
+
return $this;
|
1383 |
+
}
|
1384 |
+
|
1385 |
+
/**
|
1386 |
+
* Set the hour, day, and time for this instance to that of the passed instance.
|
1387 |
+
*
|
1388 |
+
* @param \Carbon\Carbon|\DateTimeInterface $date
|
1389 |
+
*
|
1390 |
+
* @return static
|
1391 |
+
*/
|
1392 |
+
public function setTimeFrom($date)
|
1393 |
+
{
|
1394 |
+
$date = static::instance($date);
|
1395 |
+
|
1396 |
+
$this->setTime($date->hour, $date->minute, $date->second);
|
1397 |
+
|
1398 |
+
return $this;
|
1399 |
+
}
|
1400 |
+
|
1401 |
/**
|
1402 |
* Get the days of the week
|
1403 |
*
|
2068 |
*
|
2069 |
* @param \Carbon\Carbon|\DateTimeInterface|mixed $date1
|
2070 |
* @param \Carbon\Carbon|\DateTimeInterface|mixed $date2
|
2071 |
+
* @param bool $equal Indicates if an equal to comparison should be done
|
2072 |
*
|
2073 |
* @return bool
|
2074 |
*/
|
2170 |
}
|
2171 |
|
2172 |
/**
|
2173 |
+
* Determines if the instance is a weekday.
|
2174 |
*
|
2175 |
* @return bool
|
2176 |
*/
|
2180 |
}
|
2181 |
|
2182 |
/**
|
2183 |
+
* Determines if the instance is a weekend day.
|
2184 |
*
|
2185 |
* @return bool
|
2186 |
*/
|
2190 |
}
|
2191 |
|
2192 |
/**
|
2193 |
+
* Determines if the instance is yesterday.
|
2194 |
*
|
2195 |
* @return bool
|
2196 |
*/
|
2200 |
}
|
2201 |
|
2202 |
/**
|
2203 |
+
* Determines if the instance is today.
|
2204 |
*
|
2205 |
* @return bool
|
2206 |
*/
|
2210 |
}
|
2211 |
|
2212 |
/**
|
2213 |
+
* Determines if the instance is tomorrow.
|
2214 |
*
|
2215 |
* @return bool
|
2216 |
*/
|
2220 |
}
|
2221 |
|
2222 |
/**
|
2223 |
+
* Determines if the instance is within the next week.
|
2224 |
*
|
2225 |
* @return bool
|
2226 |
*/
|
2230 |
}
|
2231 |
|
2232 |
/**
|
2233 |
+
* Determines if the instance is within the last week.
|
2234 |
*
|
2235 |
* @return bool
|
2236 |
*/
|
2240 |
}
|
2241 |
|
2242 |
/**
|
2243 |
+
* Determines if the instance is within the next quarter.
|
2244 |
+
*
|
2245 |
+
* @return bool
|
2246 |
+
*/
|
2247 |
+
public function isNextQuarter()
|
2248 |
+
{
|
2249 |
+
return $this->quarter === $this->nowWithSameTz()->addQuarter()->quarter;
|
2250 |
+
}
|
2251 |
+
|
2252 |
+
/**
|
2253 |
+
* Determines if the instance is within the last quarter.
|
2254 |
+
*
|
2255 |
+
* @return bool
|
2256 |
+
*/
|
2257 |
+
public function isLastQuarter()
|
2258 |
+
{
|
2259 |
+
return $this->quarter === $this->nowWithSameTz()->subQuarter()->quarter;
|
2260 |
+
}
|
2261 |
+
|
2262 |
+
/**
|
2263 |
+
* Determines if the instance is within the next month.
|
2264 |
*
|
2265 |
* @return bool
|
2266 |
*/
|
2270 |
}
|
2271 |
|
2272 |
/**
|
2273 |
+
* Determines if the instance is within the last month.
|
2274 |
*
|
2275 |
* @return bool
|
2276 |
*/
|
2280 |
}
|
2281 |
|
2282 |
/**
|
2283 |
+
* Determines if the instance is within next year.
|
2284 |
*
|
2285 |
* @return bool
|
2286 |
*/
|
2290 |
}
|
2291 |
|
2292 |
/**
|
2293 |
+
* Determines if the instance is within the previous year.
|
2294 |
*
|
2295 |
* @return bool
|
2296 |
*/
|
2300 |
}
|
2301 |
|
2302 |
/**
|
2303 |
+
* Determines if the instance is in the future, ie. greater (after) than now.
|
2304 |
*
|
2305 |
* @return bool
|
2306 |
*/
|
2310 |
}
|
2311 |
|
2312 |
/**
|
2313 |
+
* Determines if the instance is in the past, ie. less (before) than now.
|
2314 |
*
|
2315 |
* @return bool
|
2316 |
*/
|
2320 |
}
|
2321 |
|
2322 |
/**
|
2323 |
+
* Determines if the instance is a leap year.
|
2324 |
*
|
2325 |
* @return bool
|
2326 |
*/
|
2355 |
{
|
2356 |
$date = $date ?: static::now($this->tz);
|
2357 |
|
2358 |
+
static::expectDateTime($date);
|
|
|
|
|
2359 |
|
2360 |
return $this->format($format) === $date->format($format);
|
2361 |
}
|
2362 |
|
2363 |
/**
|
2364 |
+
* Determines if the instance is in the current year.
|
2365 |
*
|
2366 |
* @return bool
|
2367 |
*/
|
2383 |
}
|
2384 |
|
2385 |
/**
|
2386 |
+
* Determines if the instance is in the current month.
|
2387 |
*
|
2388 |
* @return bool
|
2389 |
*/
|
2390 |
+
public function isCurrentQuarter()
|
2391 |
{
|
2392 |
+
return $this->isSameQuarter();
|
2393 |
}
|
2394 |
|
2395 |
/**
|
2396 |
+
* Checks if the passed in date is in the same quarter as the instance quarter (and year if needed).
|
2397 |
*
|
2398 |
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use current day.
|
2399 |
* @param bool $ofSameYear Check if it is the same month in the same year.
|
2400 |
*
|
2401 |
* @return bool
|
2402 |
*/
|
2403 |
+
public function isSameQuarter($date = null, $ofSameYear = null)
|
2404 |
+
{
|
2405 |
+
$date = $date ? static::instance($date) : static::now($this->tz);
|
2406 |
+
|
2407 |
+
static::expectDateTime($date);
|
2408 |
+
|
2409 |
+
$ofSameYear = is_null($ofSameYear) ? static::shouldCompareYearWithMonth() : $ofSameYear;
|
2410 |
+
|
2411 |
+
return $this->quarter === $date->quarter && (!$ofSameYear || $this->isSameYear($date));
|
2412 |
+
}
|
2413 |
+
|
2414 |
+
/**
|
2415 |
+
* Determines if the instance is in the current month.
|
2416 |
+
*
|
2417 |
+
* @param bool $ofSameYear Check if it is the same month in the same year.
|
2418 |
+
*
|
2419 |
+
* @return bool
|
2420 |
+
*/
|
2421 |
+
public function isCurrentMonth($ofSameYear = null)
|
2422 |
+
{
|
2423 |
+
return $this->isSameMonth($ofSameYear);
|
2424 |
+
}
|
2425 |
+
|
2426 |
+
/**
|
2427 |
+
* Checks if the passed in date is in the same month as the instance´s month.
|
2428 |
+
*
|
2429 |
+
* Note that this defaults to only comparing the month while ignoring the year.
|
2430 |
+
* To test if it is the same exact month of the same year, pass in true as the second parameter.
|
2431 |
+
*
|
2432 |
+
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use the current date.
|
2433 |
+
* @param bool $ofSameYear Check if it is the same month in the same year.
|
2434 |
+
*
|
2435 |
+
* @return bool
|
2436 |
+
*/
|
2437 |
+
public function isSameMonth($date = null, $ofSameYear = null)
|
2438 |
{
|
2439 |
+
$ofSameYear = is_null($ofSameYear) ? static::shouldCompareYearWithMonth() : $ofSameYear;
|
2440 |
+
|
2441 |
return $this->isSameAs($ofSameYear ? 'Y-m' : 'm', $date);
|
2442 |
}
|
2443 |
|
2444 |
/**
|
2445 |
+
* Determines if the instance is in the current day.
|
2446 |
*
|
2447 |
+
* @return bool
|
2448 |
+
*/
|
2449 |
+
public function isCurrentDay()
|
2450 |
+
{
|
2451 |
+
return $this->isSameDay();
|
2452 |
+
}
|
2453 |
+
|
2454 |
+
/**
|
2455 |
+
* Checks if the passed in date is the same exact day as the instance´s day.
|
2456 |
+
*
|
2457 |
+
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use the current date.
|
2458 |
*
|
2459 |
* @return bool
|
2460 |
*/
|
2461 |
+
public function isSameDay($date = null)
|
2462 |
{
|
2463 |
return $this->isSameAs('Y-m-d', $date);
|
2464 |
}
|
2465 |
|
2466 |
+
/**
|
2467 |
+
* Determines if the instance is in the current hour.
|
2468 |
+
*
|
2469 |
+
* @return bool
|
2470 |
+
*/
|
2471 |
+
public function isCurrentHour()
|
2472 |
+
{
|
2473 |
+
return $this->isSameHour();
|
2474 |
+
}
|
2475 |
+
|
2476 |
+
/**
|
2477 |
+
* Checks if the passed in date is the same exact hour as the instance´s hour.
|
2478 |
+
*
|
2479 |
+
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use the current date.
|
2480 |
+
*
|
2481 |
+
* @return bool
|
2482 |
+
*/
|
2483 |
+
public function isSameHour($date = null)
|
2484 |
+
{
|
2485 |
+
return $this->isSameAs('Y-m-d H', $date);
|
2486 |
+
}
|
2487 |
+
|
2488 |
+
/**
|
2489 |
+
* Determines if the instance is in the current minute.
|
2490 |
+
*
|
2491 |
+
* @return bool
|
2492 |
+
*/
|
2493 |
+
public function isCurrentMinute()
|
2494 |
+
{
|
2495 |
+
return $this->isSameMinute();
|
2496 |
+
}
|
2497 |
+
|
2498 |
+
/**
|
2499 |
+
* Checks if the passed in date is the same exact minute as the instance´s minute.
|
2500 |
+
*
|
2501 |
+
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use the current date.
|
2502 |
+
*
|
2503 |
+
* @return bool
|
2504 |
+
*/
|
2505 |
+
public function isSameMinute($date = null)
|
2506 |
+
{
|
2507 |
+
return $this->isSameAs('Y-m-d H:i', $date);
|
2508 |
+
}
|
2509 |
+
|
2510 |
+
/**
|
2511 |
+
* Determines if the instance is in the current second.
|
2512 |
+
*
|
2513 |
+
* @return bool
|
2514 |
+
*/
|
2515 |
+
public function isCurrentSecond()
|
2516 |
+
{
|
2517 |
+
return $this->isSameSecond();
|
2518 |
+
}
|
2519 |
+
|
2520 |
+
/**
|
2521 |
+
* Checks if the passed in date is the same exact second as the instance´s second.
|
2522 |
+
*
|
2523 |
+
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use the current date.
|
2524 |
+
*
|
2525 |
+
* @return bool
|
2526 |
+
*/
|
2527 |
+
public function isSameSecond($date = null)
|
2528 |
+
{
|
2529 |
+
return $this->isSameAs('Y-m-d H:i:s', $date);
|
2530 |
+
}
|
2531 |
+
|
2532 |
/**
|
2533 |
* Checks if this day is a specific day of the week.
|
2534 |
*
|
2611 |
return $this->dayOfWeek === static::SATURDAY;
|
2612 |
}
|
2613 |
|
2614 |
+
/**
|
2615 |
+
* Check if its the birthday. Compares the date/month values of the two dates.
|
2616 |
+
*
|
2617 |
+
* @param \Carbon\Carbon|\DateTimeInterface|null $date The instance to compare with or null to use current day.
|
2618 |
+
*
|
2619 |
+
* @return bool
|
2620 |
+
*/
|
2621 |
+
public function isBirthday($date = null)
|
2622 |
+
{
|
2623 |
+
return $this->isSameAs('md', $date);
|
2624 |
+
}
|
2625 |
+
|
2626 |
+
/**
|
2627 |
+
* Check if today is the last day of the Month
|
2628 |
+
*
|
2629 |
+
* @return bool
|
2630 |
+
*/
|
2631 |
+
public function isLastOfMonth()
|
2632 |
+
{
|
2633 |
+
return $this->day === $this->daysInMonth;
|
2634 |
+
}
|
2635 |
+
|
2636 |
+
/**
|
2637 |
+
* Check if the instance is start of day / midnight.
|
2638 |
+
*
|
2639 |
+
* @param bool $checkMicroseconds check time at microseconds precision
|
2640 |
+
* /!\ Warning, this is not reliable with PHP < 7.1.4
|
2641 |
+
*
|
2642 |
+
* @return bool
|
2643 |
+
*/
|
2644 |
+
public function isStartOfDay($checkMicroseconds = false)
|
2645 |
+
{
|
2646 |
+
return $checkMicroseconds
|
2647 |
+
? $this->format('H:i:s.u') === '00:00:00.000000'
|
2648 |
+
: $this->format('H:i:s') === '00:00:00';
|
2649 |
+
}
|
2650 |
+
|
2651 |
+
/**
|
2652 |
+
* Check if the instance is end of day.
|
2653 |
+
*
|
2654 |
+
* @param bool $checkMicroseconds check time at microseconds precision
|
2655 |
+
* /!\ Warning, this is not reliable with PHP < 7.1.4
|
2656 |
+
*
|
2657 |
+
* @return bool
|
2658 |
+
*/
|
2659 |
+
public function isEndOfDay($checkMicroseconds = false)
|
2660 |
+
{
|
2661 |
+
return $checkMicroseconds
|
2662 |
+
? $this->format('H:i:s.u') === '23:59:59.999999'
|
2663 |
+
: $this->format('H:i:s') === '23:59:59';
|
2664 |
+
}
|
2665 |
+
|
2666 |
+
/**
|
2667 |
+
* Check if the instance is start of day / midnight.
|
2668 |
+
*
|
2669 |
+
* @return bool
|
2670 |
+
*/
|
2671 |
+
public function isMidnight()
|
2672 |
+
{
|
2673 |
+
return $this->isStartOfDay();
|
2674 |
+
}
|
2675 |
+
|
2676 |
+
/**
|
2677 |
+
* Check if the instance is midday.
|
2678 |
+
*
|
2679 |
+
* @return bool
|
2680 |
+
*/
|
2681 |
+
public function isMidday()
|
2682 |
+
{
|
2683 |
+
return $this->format('G:i:s') === static::$midDayAt.':00:00';
|
2684 |
+
}
|
2685 |
+
|
2686 |
/**
|
2687 |
* Checks if the (date)time string is in a given format.
|
2688 |
*
|
3576 |
/////////////////////////// DIFFERENCES ///////////////////////////
|
3577 |
///////////////////////////////////////////////////////////////////
|
3578 |
|
3579 |
+
/**
|
3580 |
+
* Get the difference as a CarbonInterval instance
|
3581 |
+
*
|
3582 |
+
* @param \Carbon\Carbon|\DateTimeInterface|string|null $date
|
3583 |
+
* @param bool $absolute Get the absolute of the difference
|
3584 |
+
*
|
3585 |
+
* @return CarbonInterval
|
3586 |
+
*/
|
3587 |
+
public function diffAsCarbonInterval($date = null, $absolute = true)
|
3588 |
+
{
|
3589 |
+
return CarbonInterval::instance($this->diff($this->resolveCarbon($date), $absolute));
|
3590 |
+
}
|
3591 |
+
|
3592 |
/**
|
3593 |
* Get the difference in years
|
3594 |
*
|
3694 |
}
|
3695 |
|
3696 |
$period = new DatePeriod($start, $ci, $end);
|
3697 |
+
$values = array_filter(iterator_to_array($period), function ($date) use ($callback) {
|
3698 |
return call_user_func($callback, Carbon::instance($date));
|
3699 |
});
|
3700 |
|
3923 |
}
|
3924 |
|
3925 |
if (count($interval) === 0) {
|
3926 |
+
if ($isNow && static::getHumanDiffOptions() & self::JUST_NOW) {
|
3927 |
+
$key = 'diff_now';
|
3928 |
+
$translation = static::translator()->trans($key);
|
3929 |
+
if ($translation !== $key) {
|
3930 |
+
return $translation;
|
3931 |
+
}
|
3932 |
+
}
|
3933 |
+
$count = static::getHumanDiffOptions() & self::NO_ZERO_DIFF ? 1 : 0;
|
3934 |
$unit = $short ? 's' : 'second';
|
3935 |
$interval[] = static::translator()->transChoice($unit, $count, array(':count' => $count));
|
3936 |
}
|
3949 |
$transId = $isNow ? ($isFuture ? 'from_now' : 'ago') : ($isFuture ? 'after' : 'before');
|
3950 |
|
3951 |
if ($parts === 1) {
|
3952 |
+
if ($isNow && $unit === 'day') {
|
3953 |
+
if ($count === 1 && static::getHumanDiffOptions() & self::ONE_DAY_WORDS) {
|
3954 |
+
$key = $isFuture ? 'diff_tomorrow' : 'diff_yesterday';
|
3955 |
+
$translation = static::translator()->trans($key);
|
3956 |
+
if ($translation !== $key) {
|
3957 |
+
return $translation;
|
3958 |
+
}
|
3959 |
+
}
|
3960 |
+
if ($count === 2 && static::getHumanDiffOptions() & self::TWO_DAY_WORDS) {
|
3961 |
+
$key = $isFuture ? 'diff_after_tomorrow' : 'diff_before_yesterday';
|
3962 |
+
$translation = static::translator()->trans($key);
|
3963 |
+
if ($translation !== $key) {
|
3964 |
+
return $translation;
|
3965 |
+
}
|
3966 |
+
}
|
3967 |
+
}
|
3968 |
// Some langs have special pluralization for past and future tense.
|
3969 |
$key = $unit.'_'.$transId;
|
3970 |
$count = isset($count) ? $count : 1;
|
4458 |
return $this->addSeconds((int) ($this->diffInSeconds($this->resolveCarbon($date), false) / 2));
|
4459 |
}
|
4460 |
|
4461 |
+
///////////////////////////////////////////////////////////////////
|
4462 |
+
/////////////////////////// SERIALIZATION /////////////////////////
|
4463 |
+
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4464 |
|
4465 |
/**
|
4466 |
* Return a serialized string of the instance.
|
4503 |
{
|
4504 |
return static::instance(parent::__set_state($array));
|
4505 |
}
|
4506 |
+
|
4507 |
+
/**
|
4508 |
+
* Prepare the object for JSON serialization.
|
4509 |
+
*
|
4510 |
+
* @return array|string
|
4511 |
+
*/
|
4512 |
+
public function jsonSerialize()
|
4513 |
+
{
|
4514 |
+
if (static::$serializer) {
|
4515 |
+
return call_user_func(static::$serializer, $this);
|
4516 |
+
}
|
4517 |
+
|
4518 |
+
$carbon = $this;
|
4519 |
+
|
4520 |
+
return call_user_func(function () use ($carbon) {
|
4521 |
+
return get_object_vars($carbon);
|
4522 |
+
});
|
4523 |
+
}
|
4524 |
+
|
4525 |
+
/**
|
4526 |
+
* JSON serialize all Carbon instances using the given callback.
|
4527 |
+
*
|
4528 |
+
* @param callable $callback
|
4529 |
+
*
|
4530 |
+
* @return void
|
4531 |
+
*/
|
4532 |
+
public static function serializeUsing($callback)
|
4533 |
+
{
|
4534 |
+
static::$serializer = $callback;
|
4535 |
+
}
|
4536 |
+
|
4537 |
+
///////////////////////////////////////////////////////////////////
|
4538 |
+
/////////////////////////////// MACRO /////////////////////////////
|
4539 |
+
///////////////////////////////////////////////////////////////////
|
4540 |
+
|
4541 |
+
/**
|
4542 |
+
* Register a custom macro.
|
4543 |
+
*
|
4544 |
+
* @param string $name
|
4545 |
+
* @param object|callable $macro
|
4546 |
+
*
|
4547 |
+
* @return void
|
4548 |
+
*/
|
4549 |
+
public static function macro($name, $macro)
|
4550 |
+
{
|
4551 |
+
static::$localMacros[$name] = $macro;
|
4552 |
+
}
|
4553 |
+
|
4554 |
+
/**
|
4555 |
+
* Mix another object into the class.
|
4556 |
+
*
|
4557 |
+
* @param object $mixin
|
4558 |
+
*
|
4559 |
+
* @return void
|
4560 |
+
*/
|
4561 |
+
public static function mixin($mixin)
|
4562 |
+
{
|
4563 |
+
$reflection = new \ReflectionClass($mixin);
|
4564 |
+
$methods = $reflection->getMethods(
|
4565 |
+
\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED
|
4566 |
+
);
|
4567 |
+
|
4568 |
+
foreach ($methods as $method) {
|
4569 |
+
$method->setAccessible(true);
|
4570 |
+
|
4571 |
+
static::macro($method->name, $method->invoke($mixin));
|
4572 |
+
}
|
4573 |
+
}
|
4574 |
+
|
4575 |
+
/**
|
4576 |
+
* Checks if macro is registered.
|
4577 |
+
*
|
4578 |
+
* @param string $name
|
4579 |
+
*
|
4580 |
+
* @return bool
|
4581 |
+
*/
|
4582 |
+
public static function hasMacro($name)
|
4583 |
+
{
|
4584 |
+
return isset(static::$localMacros[$name]);
|
4585 |
+
}
|
4586 |
+
|
4587 |
+
/**
|
4588 |
+
* Dynamically handle calls to the class.
|
4589 |
+
*
|
4590 |
+
* @param string $method
|
4591 |
+
* @param array $parameters
|
4592 |
+
*
|
4593 |
+
* @throws \BadMethodCallException
|
4594 |
+
*
|
4595 |
+
* @return mixed
|
4596 |
+
*/
|
4597 |
+
public static function __callStatic($method, $parameters)
|
4598 |
+
{
|
4599 |
+
if (!static::hasMacro($method)) {
|
4600 |
+
throw new \BadMethodCallException("Method $method does not exist.");
|
4601 |
+
}
|
4602 |
+
|
4603 |
+
if (static::$localMacros[$method] instanceof Closure && method_exists('Closure', 'bind')) {
|
4604 |
+
return call_user_func_array(Closure::bind(static::$localMacros[$method], null, get_called_class()), $parameters);
|
4605 |
+
}
|
4606 |
+
|
4607 |
+
return call_user_func_array(static::$localMacros[$method], $parameters);
|
4608 |
+
}
|
4609 |
+
|
4610 |
+
/**
|
4611 |
+
* Dynamically handle calls to the class.
|
4612 |
+
*
|
4613 |
+
* @param string $method
|
4614 |
+
* @param array $parameters
|
4615 |
+
*
|
4616 |
+
* @throws \BadMethodCallException|\ReflectionException
|
4617 |
+
*
|
4618 |
+
* @return mixed
|
4619 |
+
*/
|
4620 |
+
public function __call($method, $parameters)
|
4621 |
+
{
|
4622 |
+
if (!static::hasMacro($method)) {
|
4623 |
+
throw new \BadMethodCallException("Method $method does not exist.");
|
4624 |
+
}
|
4625 |
+
|
4626 |
+
$macro = static::$localMacros[$method];
|
4627 |
+
|
4628 |
+
$reflexion = new \ReflectionFunction($macro);
|
4629 |
+
$reflectionParameters = $reflexion->getParameters();
|
4630 |
+
$expectedCount = count($reflectionParameters);
|
4631 |
+
$actualCount = count($parameters);
|
4632 |
+
if ($expectedCount > $actualCount && $reflectionParameters[$expectedCount - 1]->name === 'self') {
|
4633 |
+
for ($i = $actualCount; $i < $expectedCount - 1; $i++) {
|
4634 |
+
$parameters[] = $reflectionParameters[$i]->getDefaultValue();
|
4635 |
+
}
|
4636 |
+
$parameters[] = $this;
|
4637 |
+
}
|
4638 |
+
|
4639 |
+
if ($macro instanceof Closure && method_exists($macro, 'bindTo')) {
|
4640 |
+
return call_user_func_array($macro->bindTo($this, get_class($this)), $parameters);
|
4641 |
+
}
|
4642 |
+
|
4643 |
+
return call_user_func_array($macro, $parameters);
|
4644 |
+
}
|
4645 |
}
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/CarbonInterval.php
CHANGED
@@ -11,8 +11,12 @@
|
|
11 |
|
12 |
namespace Carbon;
|
13 |
|
|
|
14 |
use DateInterval;
|
15 |
use InvalidArgumentException;
|
|
|
|
|
|
|
16 |
use Symfony\Component\Translation\TranslatorInterface;
|
17 |
|
18 |
/**
|
@@ -29,6 +33,14 @@ use Symfony\Component\Translation\TranslatorInterface;
|
|
29 |
* @property int $seconds Total seconds of the current interval.
|
30 |
* @property-read int $dayzExcludeWeeks Total days remaining in the final week of the current instance (days % 7).
|
31 |
* @property-read int $daysExcludeWeeks alias of dayzExcludeWeeks
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
*
|
33 |
* @method static CarbonInterval years($years = 1) Create instance specifying a number of years.
|
34 |
* @method static CarbonInterval year($years = 1) Alias for years()
|
@@ -82,12 +94,77 @@ class CarbonInterval extends DateInterval
|
|
82 |
*/
|
83 |
protected static $translator;
|
84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
/**
|
86 |
* Before PHP 5.4.20/5.5.4 instead of FALSE days will be set to -99999 when the interval instance
|
87 |
-
* was created by DateTime
|
88 |
*/
|
89 |
const PHP_DAYS_FALSE = -99999;
|
90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
/**
|
92 |
* Determine if the interval was created via DateTime:diff() or not.
|
93 |
*
|
@@ -126,7 +203,7 @@ class CarbonInterval extends DateInterval
|
|
126 |
$spec .= $months > 0 ? $months.static::PERIOD_MONTHS : '';
|
127 |
|
128 |
$specDays = 0;
|
129 |
-
$specDays += $weeks > 0 ? $weeks *
|
130 |
$specDays += $days > 0 ? $days : 0;
|
131 |
|
132 |
$spec .= $specDays > 0 ? $specDays.static::PERIOD_DAYS : '';
|
@@ -147,6 +224,69 @@ class CarbonInterval extends DateInterval
|
|
147 |
parent::__construct($spec);
|
148 |
}
|
149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
/**
|
151 |
* Create a new CarbonInterval instance from specific values.
|
152 |
* This is an alias for the constructor that allows better fluent
|
@@ -168,6 +308,19 @@ class CarbonInterval extends DateInterval
|
|
168 |
return new static($years, $months, $weeks, $days, $hours, $minutes, $seconds);
|
169 |
}
|
170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
/**
|
172 |
* Provide static helpers to create instances. Allows CarbonInterval::years(3).
|
173 |
*
|
@@ -213,10 +366,16 @@ class CarbonInterval extends DateInterval
|
|
213 |
case 'second':
|
214 |
return new static(null, null, null, null, null, null, $arg);
|
215 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
}
|
217 |
|
218 |
/**
|
219 |
-
* Creates a CarbonInterval from string
|
220 |
*
|
221 |
* Format:
|
222 |
*
|
@@ -278,8 +437,8 @@ class CarbonInterval extends DateInterval
|
|
278 |
case 'weeks':
|
279 |
case 'w':
|
280 |
$weeks += $intValue;
|
281 |
-
if ($fraction
|
282 |
-
$parts[] = array(null, $fraction *
|
283 |
}
|
284 |
break;
|
285 |
|
@@ -287,8 +446,8 @@ class CarbonInterval extends DateInterval
|
|
287 |
case 'days':
|
288 |
case 'd':
|
289 |
$days += $intValue;
|
290 |
-
if ($fraction
|
291 |
-
$parts[] = array(null, $fraction *
|
292 |
}
|
293 |
break;
|
294 |
|
@@ -296,8 +455,8 @@ class CarbonInterval extends DateInterval
|
|
296 |
case 'hours':
|
297 |
case 'h':
|
298 |
$hours += $intValue;
|
299 |
-
if ($fraction
|
300 |
-
$parts[] = array(null, $fraction *
|
301 |
}
|
302 |
break;
|
303 |
|
@@ -305,8 +464,8 @@ class CarbonInterval extends DateInterval
|
|
305 |
case 'minutes':
|
306 |
case 'm':
|
307 |
$minutes += $intValue;
|
308 |
-
if ($fraction
|
309 |
-
$seconds += round($fraction *
|
310 |
}
|
311 |
break;
|
312 |
|
@@ -333,23 +492,45 @@ class CarbonInterval extends DateInterval
|
|
333 |
*
|
334 |
* @param DateInterval $di
|
335 |
*
|
336 |
-
* @throws \InvalidArgumentException
|
337 |
-
*
|
338 |
* @return static
|
339 |
*/
|
340 |
public static function instance(DateInterval $di)
|
341 |
{
|
342 |
-
|
343 |
-
throw new InvalidArgumentException('Can not instance a DateInterval object created from DateTime::diff().');
|
344 |
-
}
|
345 |
-
|
346 |
-
$instance = new static($di->y, $di->m, 0, $di->d, $di->h, $di->i, $di->s);
|
347 |
$instance->invert = $di->invert;
|
348 |
-
$instance->days = $di->days;
|
349 |
|
350 |
return $instance;
|
351 |
}
|
352 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
353 |
///////////////////////////////////////////////////////////////////
|
354 |
/////////////////////// LOCALIZATION //////////////////////////////
|
355 |
///////////////////////////////////////////////////////////////////
|
@@ -369,7 +550,7 @@ class CarbonInterval extends DateInterval
|
|
369 |
}
|
370 |
|
371 |
/**
|
372 |
-
* Get the translator instance in use
|
373 |
*
|
374 |
* @return \Symfony\Component\Translation\TranslatorInterface
|
375 |
*/
|
@@ -379,7 +560,7 @@ class CarbonInterval extends DateInterval
|
|
379 |
}
|
380 |
|
381 |
/**
|
382 |
-
* Set the translator instance to use
|
383 |
*
|
384 |
* @param TranslatorInterface $translator
|
385 |
*/
|
@@ -389,7 +570,7 @@ class CarbonInterval extends DateInterval
|
|
389 |
}
|
390 |
|
391 |
/**
|
392 |
-
* Get the current translator locale
|
393 |
*
|
394 |
* @return string
|
395 |
*/
|
@@ -399,7 +580,7 @@ class CarbonInterval extends DateInterval
|
|
399 |
}
|
400 |
|
401 |
/**
|
402 |
-
* Set the current translator locale
|
403 |
*
|
404 |
* @param string $locale
|
405 |
*/
|
@@ -413,16 +594,20 @@ class CarbonInterval extends DateInterval
|
|
413 |
///////////////////////////////////////////////////////////////////
|
414 |
|
415 |
/**
|
416 |
-
* Get a part of the CarbonInterval object
|
417 |
*
|
418 |
* @param string $name
|
419 |
*
|
420 |
* @throws \InvalidArgumentException
|
421 |
*
|
422 |
-
* @return int
|
423 |
*/
|
424 |
public function __get($name)
|
425 |
{
|
|
|
|
|
|
|
|
|
426 |
switch ($name) {
|
427 |
case 'years':
|
428 |
return $this->y;
|
@@ -443,11 +628,11 @@ class CarbonInterval extends DateInterval
|
|
443 |
return $this->s;
|
444 |
|
445 |
case 'weeks':
|
446 |
-
return (int) floor($this->d /
|
447 |
|
448 |
case 'daysExcludeWeeks':
|
449 |
case 'dayzExcludeWeeks':
|
450 |
-
return $this->d %
|
451 |
|
452 |
default:
|
453 |
throw new InvalidArgumentException(sprintf("Unknown getter '%s'", $name));
|
@@ -455,7 +640,7 @@ class CarbonInterval extends DateInterval
|
|
455 |
}
|
456 |
|
457 |
/**
|
458 |
-
* Set a part of the CarbonInterval object
|
459 |
*
|
460 |
* @param string $name
|
461 |
* @param int $val
|
@@ -474,7 +659,7 @@ class CarbonInterval extends DateInterval
|
|
474 |
break;
|
475 |
|
476 |
case 'weeks':
|
477 |
-
$this->d = $val *
|
478 |
break;
|
479 |
|
480 |
case 'dayz':
|
@@ -505,11 +690,94 @@ class CarbonInterval extends DateInterval
|
|
505 |
*/
|
506 |
public function weeksAndDays($weeks, $days)
|
507 |
{
|
508 |
-
$this->dayz = ($weeks *
|
509 |
|
510 |
return $this;
|
511 |
}
|
512 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
513 |
/**
|
514 |
* Allow fluent calls on the setters... CarbonInterval::years(3)->months(5)->day().
|
515 |
*
|
@@ -523,6 +791,10 @@ class CarbonInterval extends DateInterval
|
|
523 |
*/
|
524 |
public function __call($name, $args)
|
525 |
{
|
|
|
|
|
|
|
|
|
526 |
$arg = count($args) === 0 ? 1 : $args[0];
|
527 |
|
528 |
switch ($name) {
|
@@ -538,7 +810,7 @@ class CarbonInterval extends DateInterval
|
|
538 |
|
539 |
case 'weeks':
|
540 |
case 'week':
|
541 |
-
$this->dayz = $arg *
|
542 |
break;
|
543 |
|
544 |
case 'days':
|
@@ -569,24 +841,27 @@ class CarbonInterval extends DateInterval
|
|
569 |
/**
|
570 |
* Get the current interval in a human readable format in the current locale.
|
571 |
*
|
|
|
|
|
572 |
* @return string
|
573 |
*/
|
574 |
-
public function forHumans()
|
575 |
{
|
576 |
$periods = array(
|
577 |
-
'year' => $this->years,
|
578 |
-
'month' => $this->months,
|
579 |
-
'week' => $this->weeks,
|
580 |
-
'day' => $this->daysExcludeWeeks,
|
581 |
-
'hour' => $this->hours,
|
582 |
-
'minute' => $this->minutes,
|
583 |
-
'second' => $this->seconds,
|
584 |
);
|
585 |
|
586 |
$parts = array();
|
587 |
-
foreach ($periods as $unit => $
|
|
|
588 |
if ($count > 0) {
|
589 |
-
$parts[] = static::translator()->transChoice($unit, $count, array(':count' => $count));
|
590 |
}
|
591 |
}
|
592 |
|
@@ -604,7 +879,31 @@ class CarbonInterval extends DateInterval
|
|
604 |
}
|
605 |
|
606 |
/**
|
607 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
608 |
*
|
609 |
* @param DateInterval $interval
|
610 |
*
|
@@ -629,22 +928,48 @@ class CarbonInterval extends DateInterval
|
|
629 |
}
|
630 |
|
631 |
/**
|
632 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
633 |
*
|
634 |
* @return string
|
635 |
*/
|
636 |
-
public function
|
637 |
{
|
638 |
$date = array_filter(array(
|
639 |
-
static::PERIOD_YEARS => $
|
640 |
-
static::PERIOD_MONTHS => $
|
641 |
-
static::PERIOD_DAYS => $
|
642 |
));
|
643 |
|
644 |
$time = array_filter(array(
|
645 |
-
static::PERIOD_HOURS => $
|
646 |
-
static::PERIOD_MINUTES => $
|
647 |
-
static::PERIOD_SECONDS => $
|
648 |
));
|
649 |
|
650 |
$specString = static::PERIOD_PREFIX;
|
@@ -664,24 +989,142 @@ class CarbonInterval extends DateInterval
|
|
664 |
}
|
665 |
|
666 |
/**
|
667 |
-
*
|
668 |
*
|
669 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
670 |
*
|
671 |
* @return int
|
672 |
*/
|
673 |
-
public function
|
674 |
{
|
675 |
$current = Carbon::now();
|
676 |
-
$passed = $current->copy()->add($
|
677 |
-
$current->add($
|
678 |
|
679 |
if ($current < $passed) {
|
680 |
return -1;
|
681 |
-
}
|
|
|
682 |
return 1;
|
683 |
}
|
684 |
|
685 |
return 0;
|
686 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
687 |
}
|
11 |
|
12 |
namespace Carbon;
|
13 |
|
14 |
+
use Closure;
|
15 |
use DateInterval;
|
16 |
use InvalidArgumentException;
|
17 |
+
use ReflectionClass;
|
18 |
+
use ReflectionFunction;
|
19 |
+
use ReflectionMethod;
|
20 |
use Symfony\Component\Translation\TranslatorInterface;
|
21 |
|
22 |
/**
|
33 |
* @property int $seconds Total seconds of the current interval.
|
34 |
* @property-read int $dayzExcludeWeeks Total days remaining in the final week of the current instance (days % 7).
|
35 |
* @property-read int $daysExcludeWeeks alias of dayzExcludeWeeks
|
36 |
+
* @property-read float $totalYears Number of years equivalent to the interval.
|
37 |
+
* @property-read float $totalMonths Number of months equivalent to the interval.
|
38 |
+
* @property-read float $totalWeeks Number of weeks equivalent to the interval.
|
39 |
+
* @property-read float $totalDays Number of days equivalent to the interval.
|
40 |
+
* @property-read float $totalDayz Alias for totalDays.
|
41 |
+
* @property-read float $totalHours Number of hours equivalent to the interval.
|
42 |
+
* @property-read float $totalMinutes Number of minutes equivalent to the interval.
|
43 |
+
* @property-read float $totalSeconds Number of seconds equivalent to the interval.
|
44 |
*
|
45 |
* @method static CarbonInterval years($years = 1) Create instance specifying a number of years.
|
46 |
* @method static CarbonInterval year($years = 1) Alias for years()
|
94 |
*/
|
95 |
protected static $translator;
|
96 |
|
97 |
+
/**
|
98 |
+
* @var array|null
|
99 |
+
*/
|
100 |
+
protected static $cascadeFactors;
|
101 |
+
|
102 |
+
/**
|
103 |
+
* @var array|null
|
104 |
+
*/
|
105 |
+
private static $flipCascadeFactors;
|
106 |
+
|
107 |
+
/**
|
108 |
+
* The registered macros.
|
109 |
+
*
|
110 |
+
* @var array
|
111 |
+
*/
|
112 |
+
protected static $macros = array();
|
113 |
+
|
114 |
/**
|
115 |
* Before PHP 5.4.20/5.5.4 instead of FALSE days will be set to -99999 when the interval instance
|
116 |
+
* was created by DateTime::diff().
|
117 |
*/
|
118 |
const PHP_DAYS_FALSE = -99999;
|
119 |
|
120 |
+
/**
|
121 |
+
* Mapping of units and factors for cascading.
|
122 |
+
*
|
123 |
+
* Should only be modified by changing the factors or referenced constants.
|
124 |
+
*
|
125 |
+
* @return array
|
126 |
+
*/
|
127 |
+
public static function getCascadeFactors()
|
128 |
+
{
|
129 |
+
return static::$cascadeFactors ?: array(
|
130 |
+
'minutes' => array(Carbon::SECONDS_PER_MINUTE, 'seconds'),
|
131 |
+
'hours' => array(Carbon::MINUTES_PER_HOUR, 'minutes'),
|
132 |
+
'dayz' => array(Carbon::HOURS_PER_DAY, 'hours'),
|
133 |
+
'months' => array(Carbon::DAYS_PER_WEEK * Carbon::WEEKS_PER_MONTH, 'dayz'),
|
134 |
+
'years' => array(Carbon::MONTHS_PER_YEAR, 'months'),
|
135 |
+
);
|
136 |
+
}
|
137 |
+
|
138 |
+
private static function standardizeUnit($unit)
|
139 |
+
{
|
140 |
+
$unit = rtrim($unit, 'sz').'s';
|
141 |
+
|
142 |
+
return $unit === 'days' ? 'dayz' : $unit;
|
143 |
+
}
|
144 |
+
|
145 |
+
private static function getFlipCascadeFactors()
|
146 |
+
{
|
147 |
+
if (!self::$flipCascadeFactors) {
|
148 |
+
self::$flipCascadeFactors = array();
|
149 |
+
foreach (static::getCascadeFactors() as $to => $tuple) {
|
150 |
+
list($factor, $from) = $tuple;
|
151 |
+
|
152 |
+
self::$flipCascadeFactors[self::standardizeUnit($from)] = array(self::standardizeUnit($to), $factor);
|
153 |
+
}
|
154 |
+
}
|
155 |
+
|
156 |
+
return self::$flipCascadeFactors;
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* @param array $cascadeFactors
|
161 |
+
*/
|
162 |
+
public static function setCascadeFactors(array $cascadeFactors)
|
163 |
+
{
|
164 |
+
self::$flipCascadeFactors = null;
|
165 |
+
static::$cascadeFactors = $cascadeFactors;
|
166 |
+
}
|
167 |
+
|
168 |
/**
|
169 |
* Determine if the interval was created via DateTime:diff() or not.
|
170 |
*
|
203 |
$spec .= $months > 0 ? $months.static::PERIOD_MONTHS : '';
|
204 |
|
205 |
$specDays = 0;
|
206 |
+
$specDays += $weeks > 0 ? $weeks * static::getDaysPerWeek() : 0;
|
207 |
$specDays += $days > 0 ? $days : 0;
|
208 |
|
209 |
$spec .= $specDays > 0 ? $specDays.static::PERIOD_DAYS : '';
|
224 |
parent::__construct($spec);
|
225 |
}
|
226 |
|
227 |
+
/**
|
228 |
+
* Returns the factor for a given source-to-target couple.
|
229 |
+
*
|
230 |
+
* @param string $source
|
231 |
+
* @param string $target
|
232 |
+
*
|
233 |
+
* @return int|null
|
234 |
+
*/
|
235 |
+
public static function getFactor($source, $target)
|
236 |
+
{
|
237 |
+
$source = self::standardizeUnit($source);
|
238 |
+
$target = self::standardizeUnit($target);
|
239 |
+
$factors = static::getFlipCascadeFactors();
|
240 |
+
if (isset($factors[$source])) {
|
241 |
+
list($to, $factor) = $factors[$source];
|
242 |
+
if ($to === $target) {
|
243 |
+
return $factor;
|
244 |
+
}
|
245 |
+
}
|
246 |
+
|
247 |
+
return null;
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Returns current config for days per week.
|
252 |
+
*
|
253 |
+
* @return int
|
254 |
+
*/
|
255 |
+
public static function getDaysPerWeek()
|
256 |
+
{
|
257 |
+
return static::getFactor('dayz', 'weeks') ?: Carbon::DAYS_PER_WEEK;
|
258 |
+
}
|
259 |
+
|
260 |
+
/**
|
261 |
+
* Returns current config for hours per day.
|
262 |
+
*
|
263 |
+
* @return int
|
264 |
+
*/
|
265 |
+
public static function getHoursPerDay()
|
266 |
+
{
|
267 |
+
return static::getFactor('hours', 'dayz') ?: Carbon::HOURS_PER_DAY;
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Returns current config for minutes per hour.
|
272 |
+
*
|
273 |
+
* @return int
|
274 |
+
*/
|
275 |
+
public static function getMinutesPerHours()
|
276 |
+
{
|
277 |
+
return static::getFactor('minutes', 'hours') ?: Carbon::MINUTES_PER_HOUR;
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Returns current config for seconds per minute.
|
282 |
+
*
|
283 |
+
* @return int
|
284 |
+
*/
|
285 |
+
public static function getSecondsPerMinutes()
|
286 |
+
{
|
287 |
+
return static::getFactor('seconds', 'minutes') ?: Carbon::SECONDS_PER_MINUTE;
|
288 |
+
}
|
289 |
+
|
290 |
/**
|
291 |
* Create a new CarbonInterval instance from specific values.
|
292 |
* This is an alias for the constructor that allows better fluent
|
308 |
return new static($years, $months, $weeks, $days, $hours, $minutes, $seconds);
|
309 |
}
|
310 |
|
311 |
+
/**
|
312 |
+
* Get a copy of the instance.
|
313 |
+
*
|
314 |
+
* @return static
|
315 |
+
*/
|
316 |
+
public function copy()
|
317 |
+
{
|
318 |
+
$date = new static($this->spec());
|
319 |
+
$date->invert = $this->invert;
|
320 |
+
|
321 |
+
return $date;
|
322 |
+
}
|
323 |
+
|
324 |
/**
|
325 |
* Provide static helpers to create instances. Allows CarbonInterval::years(3).
|
326 |
*
|
366 |
case 'second':
|
367 |
return new static(null, null, null, null, null, null, $arg);
|
368 |
}
|
369 |
+
|
370 |
+
if (static::hasMacro($name)) {
|
371 |
+
return call_user_func_array(
|
372 |
+
array(new static(0), $name), $args
|
373 |
+
);
|
374 |
+
}
|
375 |
}
|
376 |
|
377 |
/**
|
378 |
+
* Creates a CarbonInterval from string.
|
379 |
*
|
380 |
* Format:
|
381 |
*
|
437 |
case 'weeks':
|
438 |
case 'w':
|
439 |
$weeks += $intValue;
|
440 |
+
if ($fraction) {
|
441 |
+
$parts[] = array(null, $fraction * static::getDaysPerWeek(), 'd');
|
442 |
}
|
443 |
break;
|
444 |
|
446 |
case 'days':
|
447 |
case 'd':
|
448 |
$days += $intValue;
|
449 |
+
if ($fraction) {
|
450 |
+
$parts[] = array(null, $fraction * static::getHoursPerDay(), 'h');
|
451 |
}
|
452 |
break;
|
453 |
|
455 |
case 'hours':
|
456 |
case 'h':
|
457 |
$hours += $intValue;
|
458 |
+
if ($fraction) {
|
459 |
+
$parts[] = array(null, $fraction * static::getMinutesPerHours(), 'm');
|
460 |
}
|
461 |
break;
|
462 |
|
464 |
case 'minutes':
|
465 |
case 'm':
|
466 |
$minutes += $intValue;
|
467 |
+
if ($fraction) {
|
468 |
+
$seconds += round($fraction * static::getSecondsPerMinutes());
|
469 |
}
|
470 |
break;
|
471 |
|
492 |
*
|
493 |
* @param DateInterval $di
|
494 |
*
|
|
|
|
|
495 |
* @return static
|
496 |
*/
|
497 |
public static function instance(DateInterval $di)
|
498 |
{
|
499 |
+
$instance = new static(static::getDateIntervalSpec($di));
|
|
|
|
|
|
|
|
|
500 |
$instance->invert = $di->invert;
|
|
|
501 |
|
502 |
return $instance;
|
503 |
}
|
504 |
|
505 |
+
/**
|
506 |
+
* Make a CarbonInterval instance from given variable if possible.
|
507 |
+
*
|
508 |
+
* Always return a new instance. Parse only strings and only these likely to be intervals (skip dates
|
509 |
+
* and recurrences). Throw an exception for invalid format, but otherwise return null.
|
510 |
+
*
|
511 |
+
* @param mixed $var
|
512 |
+
*
|
513 |
+
* @return static|null
|
514 |
+
*/
|
515 |
+
public static function make($var)
|
516 |
+
{
|
517 |
+
if ($var instanceof DateInterval) {
|
518 |
+
return static::instance($var);
|
519 |
+
}
|
520 |
+
|
521 |
+
if (is_string($var)) {
|
522 |
+
$var = trim($var);
|
523 |
+
|
524 |
+
if (substr($var, 0, 1) === 'P') {
|
525 |
+
return new static($var);
|
526 |
+
}
|
527 |
+
|
528 |
+
if (preg_match('/^(?:\h*\d+(?:\.\d+)?\h*[a-z]+)+$/i', $var)) {
|
529 |
+
return static::fromString($var);
|
530 |
+
}
|
531 |
+
}
|
532 |
+
}
|
533 |
+
|
534 |
///////////////////////////////////////////////////////////////////
|
535 |
/////////////////////// LOCALIZATION //////////////////////////////
|
536 |
///////////////////////////////////////////////////////////////////
|
550 |
}
|
551 |
|
552 |
/**
|
553 |
+
* Get the translator instance in use.
|
554 |
*
|
555 |
* @return \Symfony\Component\Translation\TranslatorInterface
|
556 |
*/
|
560 |
}
|
561 |
|
562 |
/**
|
563 |
+
* Set the translator instance to use.
|
564 |
*
|
565 |
* @param TranslatorInterface $translator
|
566 |
*/
|
570 |
}
|
571 |
|
572 |
/**
|
573 |
+
* Get the current translator locale.
|
574 |
*
|
575 |
* @return string
|
576 |
*/
|
580 |
}
|
581 |
|
582 |
/**
|
583 |
+
* Set the current translator locale.
|
584 |
*
|
585 |
* @param string $locale
|
586 |
*/
|
594 |
///////////////////////////////////////////////////////////////////
|
595 |
|
596 |
/**
|
597 |
+
* Get a part of the CarbonInterval object.
|
598 |
*
|
599 |
* @param string $name
|
600 |
*
|
601 |
* @throws \InvalidArgumentException
|
602 |
*
|
603 |
+
* @return int|float
|
604 |
*/
|
605 |
public function __get($name)
|
606 |
{
|
607 |
+
if (substr($name, 0, 5) === 'total') {
|
608 |
+
return $this->total(substr($name, 5));
|
609 |
+
}
|
610 |
+
|
611 |
switch ($name) {
|
612 |
case 'years':
|
613 |
return $this->y;
|
628 |
return $this->s;
|
629 |
|
630 |
case 'weeks':
|
631 |
+
return (int) floor($this->d / static::getDaysPerWeek());
|
632 |
|
633 |
case 'daysExcludeWeeks':
|
634 |
case 'dayzExcludeWeeks':
|
635 |
+
return $this->d % static::getDaysPerWeek();
|
636 |
|
637 |
default:
|
638 |
throw new InvalidArgumentException(sprintf("Unknown getter '%s'", $name));
|
640 |
}
|
641 |
|
642 |
/**
|
643 |
+
* Set a part of the CarbonInterval object.
|
644 |
*
|
645 |
* @param string $name
|
646 |
* @param int $val
|
659 |
break;
|
660 |
|
661 |
case 'weeks':
|
662 |
+
$this->d = $val * static::getDaysPerWeek();
|
663 |
break;
|
664 |
|
665 |
case 'dayz':
|
690 |
*/
|
691 |
public function weeksAndDays($weeks, $days)
|
692 |
{
|
693 |
+
$this->dayz = ($weeks * static::getDaysPerWeek()) + $days;
|
694 |
|
695 |
return $this;
|
696 |
}
|
697 |
|
698 |
+
/**
|
699 |
+
* Register a custom macro.
|
700 |
+
*
|
701 |
+
* @param string $name
|
702 |
+
* @param object|callable $macro
|
703 |
+
*
|
704 |
+
* @return void
|
705 |
+
*/
|
706 |
+
public static function macro($name, $macro)
|
707 |
+
{
|
708 |
+
static::$macros[$name] = $macro;
|
709 |
+
}
|
710 |
+
|
711 |
+
/**
|
712 |
+
* Register macros from a mixin object.
|
713 |
+
*
|
714 |
+
* @param object $mixin
|
715 |
+
*
|
716 |
+
* @throws \ReflectionException
|
717 |
+
*
|
718 |
+
* @return void
|
719 |
+
*/
|
720 |
+
public static function mixin($mixin)
|
721 |
+
{
|
722 |
+
$reflection = new ReflectionClass($mixin);
|
723 |
+
|
724 |
+
$methods = $reflection->getMethods(
|
725 |
+
ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
|
726 |
+
);
|
727 |
+
|
728 |
+
foreach ($methods as $method) {
|
729 |
+
$method->setAccessible(true);
|
730 |
+
|
731 |
+
static::macro($method->name, $method->invoke($mixin));
|
732 |
+
}
|
733 |
+
}
|
734 |
+
|
735 |
+
/**
|
736 |
+
* Check if macro is registered.
|
737 |
+
*
|
738 |
+
* @param string $name
|
739 |
+
*
|
740 |
+
* @return bool
|
741 |
+
*/
|
742 |
+
public static function hasMacro($name)
|
743 |
+
{
|
744 |
+
return isset(static::$macros[$name]);
|
745 |
+
}
|
746 |
+
|
747 |
+
/**
|
748 |
+
* Call given macro.
|
749 |
+
*
|
750 |
+
* @param string $name
|
751 |
+
* @param array $parameters
|
752 |
+
*
|
753 |
+
* @return mixed
|
754 |
+
*/
|
755 |
+
protected function callMacro($name, $parameters)
|
756 |
+
{
|
757 |
+
$macro = static::$macros[$name];
|
758 |
+
|
759 |
+
$reflection = new ReflectionFunction($macro);
|
760 |
+
|
761 |
+
$reflectionParameters = $reflection->getParameters();
|
762 |
+
|
763 |
+
$expectedCount = count($reflectionParameters);
|
764 |
+
$actualCount = count($parameters);
|
765 |
+
|
766 |
+
if ($expectedCount > $actualCount && $reflectionParameters[$expectedCount - 1]->name === 'self') {
|
767 |
+
for ($i = $actualCount; $i < $expectedCount - 1; $i++) {
|
768 |
+
$parameters[] = $reflectionParameters[$i]->getDefaultValue();
|
769 |
+
}
|
770 |
+
|
771 |
+
$parameters[] = $this;
|
772 |
+
}
|
773 |
+
|
774 |
+
if ($macro instanceof Closure && method_exists($macro, 'bindTo')) {
|
775 |
+
$macro = $macro->bindTo($this, get_class($this));
|
776 |
+
}
|
777 |
+
|
778 |
+
return call_user_func_array($macro, $parameters);
|
779 |
+
}
|
780 |
+
|
781 |
/**
|
782 |
* Allow fluent calls on the setters... CarbonInterval::years(3)->months(5)->day().
|
783 |
*
|
791 |
*/
|
792 |
public function __call($name, $args)
|
793 |
{
|
794 |
+
if (static::hasMacro($name)) {
|
795 |
+
return $this->callMacro($name, $args);
|
796 |
+
}
|
797 |
+
|
798 |
$arg = count($args) === 0 ? 1 : $args[0];
|
799 |
|
800 |
switch ($name) {
|
810 |
|
811 |
case 'weeks':
|
812 |
case 'week':
|
813 |
+
$this->dayz = $arg * static::getDaysPerWeek();
|
814 |
break;
|
815 |
|
816 |
case 'days':
|
841 |
/**
|
842 |
* Get the current interval in a human readable format in the current locale.
|
843 |
*
|
844 |
+
* @param bool $short (false by default), returns short units if true
|
845 |
+
*
|
846 |
* @return string
|
847 |
*/
|
848 |
+
public function forHumans($short = false)
|
849 |
{
|
850 |
$periods = array(
|
851 |
+
'year' => array('y', $this->years),
|
852 |
+
'month' => array('m', $this->months),
|
853 |
+
'week' => array('w', $this->weeks),
|
854 |
+
'day' => array('d', $this->daysExcludeWeeks),
|
855 |
+
'hour' => array('h', $this->hours),
|
856 |
+
'minute' => array('min', $this->minutes),
|
857 |
+
'second' => array('s', $this->seconds),
|
858 |
);
|
859 |
|
860 |
$parts = array();
|
861 |
+
foreach ($periods as $unit => $options) {
|
862 |
+
list($shortUnit, $count) = $options;
|
863 |
if ($count > 0) {
|
864 |
+
$parts[] = static::translator()->transChoice($short ? $shortUnit : $unit, $count, array(':count' => $count));
|
865 |
}
|
866 |
}
|
867 |
|
879 |
}
|
880 |
|
881 |
/**
|
882 |
+
* Convert the interval to a CarbonPeriod.
|
883 |
+
*
|
884 |
+
* @return CarbonPeriod
|
885 |
+
*/
|
886 |
+
public function toPeriod()
|
887 |
+
{
|
888 |
+
return CarbonPeriod::createFromArray(
|
889 |
+
array_merge(array($this), func_get_args())
|
890 |
+
);
|
891 |
+
}
|
892 |
+
|
893 |
+
/**
|
894 |
+
* Invert the interval.
|
895 |
+
*
|
896 |
+
* @return $this
|
897 |
+
*/
|
898 |
+
public function invert()
|
899 |
+
{
|
900 |
+
$this->invert = $this->invert ? 0 : 1;
|
901 |
+
|
902 |
+
return $this;
|
903 |
+
}
|
904 |
+
|
905 |
+
/**
|
906 |
+
* Add the passed interval to the current instance.
|
907 |
*
|
908 |
* @param DateInterval $interval
|
909 |
*
|
928 |
}
|
929 |
|
930 |
/**
|
931 |
+
* Multiply current instance given number of times
|
932 |
+
*
|
933 |
+
* @param float $factor
|
934 |
+
*
|
935 |
+
* @return $this
|
936 |
+
*/
|
937 |
+
public function times($factor)
|
938 |
+
{
|
939 |
+
if ($factor < 0) {
|
940 |
+
$this->invert = $this->invert ? 0 : 1;
|
941 |
+
$factor = -$factor;
|
942 |
+
}
|
943 |
+
|
944 |
+
$this->years = round($this->years * $factor);
|
945 |
+
$this->months = round($this->months * $factor);
|
946 |
+
$this->dayz = round($this->dayz * $factor);
|
947 |
+
$this->hours = round($this->hours * $factor);
|
948 |
+
$this->minutes = round($this->minutes * $factor);
|
949 |
+
$this->seconds = round($this->seconds * $factor);
|
950 |
+
|
951 |
+
return $this;
|
952 |
+
}
|
953 |
+
|
954 |
+
/**
|
955 |
+
* Get the interval_spec string of a date interval.
|
956 |
+
*
|
957 |
+
* @param DateInterval $interval
|
958 |
*
|
959 |
* @return string
|
960 |
*/
|
961 |
+
public static function getDateIntervalSpec(DateInterval $interval)
|
962 |
{
|
963 |
$date = array_filter(array(
|
964 |
+
static::PERIOD_YEARS => $interval->y,
|
965 |
+
static::PERIOD_MONTHS => $interval->m,
|
966 |
+
static::PERIOD_DAYS => $interval->d,
|
967 |
));
|
968 |
|
969 |
$time = array_filter(array(
|
970 |
+
static::PERIOD_HOURS => $interval->h,
|
971 |
+
static::PERIOD_MINUTES => $interval->i,
|
972 |
+
static::PERIOD_SECONDS => $interval->s,
|
973 |
));
|
974 |
|
975 |
$specString = static::PERIOD_PREFIX;
|
989 |
}
|
990 |
|
991 |
/**
|
992 |
+
* Get the interval_spec string.
|
993 |
*
|
994 |
+
* @return string
|
995 |
+
*/
|
996 |
+
public function spec()
|
997 |
+
{
|
998 |
+
return static::getDateIntervalSpec($this);
|
999 |
+
}
|
1000 |
+
|
1001 |
+
/**
|
1002 |
+
* Comparing 2 date intervals.
|
1003 |
+
*
|
1004 |
+
* @param DateInterval $a
|
1005 |
+
* @param DateInterval $b
|
1006 |
*
|
1007 |
* @return int
|
1008 |
*/
|
1009 |
+
public static function compareDateIntervals(DateInterval $a, DateInterval $b)
|
1010 |
{
|
1011 |
$current = Carbon::now();
|
1012 |
+
$passed = $current->copy()->add($b);
|
1013 |
+
$current->add($a);
|
1014 |
|
1015 |
if ($current < $passed) {
|
1016 |
return -1;
|
1017 |
+
}
|
1018 |
+
if ($current > $passed) {
|
1019 |
return 1;
|
1020 |
}
|
1021 |
|
1022 |
return 0;
|
1023 |
}
|
1024 |
+
|
1025 |
+
/**
|
1026 |
+
* Comparing with passed interval.
|
1027 |
+
*
|
1028 |
+
* @param DateInterval $interval
|
1029 |
+
*
|
1030 |
+
* @return int
|
1031 |
+
*/
|
1032 |
+
public function compare(DateInterval $interval)
|
1033 |
+
{
|
1034 |
+
return static::compareDateIntervals($this, $interval);
|
1035 |
+
}
|
1036 |
+
|
1037 |
+
/**
|
1038 |
+
* Convert overflowed values into bigger units.
|
1039 |
+
*
|
1040 |
+
* @return $this
|
1041 |
+
*/
|
1042 |
+
public function cascade()
|
1043 |
+
{
|
1044 |
+
foreach (static::getFlipCascadeFactors() as $source => $cascade) {
|
1045 |
+
list($target, $factor) = $cascade;
|
1046 |
+
|
1047 |
+
if ($source === 'dayz' && $target === 'weeks') {
|
1048 |
+
continue;
|
1049 |
+
}
|
1050 |
+
|
1051 |
+
$value = $this->$source;
|
1052 |
+
$this->$source = $modulo = $value % $factor;
|
1053 |
+
$this->$target += ($value - $modulo) / $factor;
|
1054 |
+
}
|
1055 |
+
|
1056 |
+
return $this;
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
/**
|
1060 |
+
* Get amount of given unit equivalent to the interval.
|
1061 |
+
*
|
1062 |
+
* @param string $unit
|
1063 |
+
*
|
1064 |
+
* @throws \InvalidArgumentException
|
1065 |
+
*
|
1066 |
+
* @return float
|
1067 |
+
*/
|
1068 |
+
public function total($unit)
|
1069 |
+
{
|
1070 |
+
$realUnit = $unit = strtolower($unit);
|
1071 |
+
|
1072 |
+
if (in_array($unit, array('days', 'weeks'))) {
|
1073 |
+
$realUnit = 'dayz';
|
1074 |
+
} elseif (!in_array($unit, array('seconds', 'minutes', 'hours', 'dayz', 'months', 'years'))) {
|
1075 |
+
throw new InvalidArgumentException("Unknown unit '$unit'.");
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
$result = 0;
|
1079 |
+
$cumulativeFactor = 0;
|
1080 |
+
$unitFound = false;
|
1081 |
+
|
1082 |
+
foreach (static::getFlipCascadeFactors() as $source => $cascade) {
|
1083 |
+
list($target, $factor) = $cascade;
|
1084 |
+
|
1085 |
+
if ($source === $realUnit) {
|
1086 |
+
$unitFound = true;
|
1087 |
+
$result += $this->$source;
|
1088 |
+
$cumulativeFactor = 1;
|
1089 |
+
}
|
1090 |
+
|
1091 |
+
if ($factor === false) {
|
1092 |
+
if ($unitFound) {
|
1093 |
+
break;
|
1094 |
+
}
|
1095 |
+
|
1096 |
+
$result = 0;
|
1097 |
+
$cumulativeFactor = 0;
|
1098 |
+
|
1099 |
+
continue;
|
1100 |
+
}
|
1101 |
+
|
1102 |
+
if ($target === $realUnit) {
|
1103 |
+
$unitFound = true;
|
1104 |
+
}
|
1105 |
+
|
1106 |
+
if ($cumulativeFactor) {
|
1107 |
+
$cumulativeFactor *= $factor;
|
1108 |
+
$result += $this->$target * $cumulativeFactor;
|
1109 |
+
|
1110 |
+
continue;
|
1111 |
+
}
|
1112 |
+
|
1113 |
+
$result = ($result + $this->$source) / $factor;
|
1114 |
+
}
|
1115 |
+
|
1116 |
+
if (isset($target) && !$cumulativeFactor) {
|
1117 |
+
$result += $this->$target;
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
if (!$unitFound) {
|
1121 |
+
throw new \InvalidArgumentException("Unit $unit have no configuration to get total from other units.");
|
1122 |
+
}
|
1123 |
+
|
1124 |
+
if ($unit === 'weeks') {
|
1125 |
+
return $result / static::getDaysPerWeek();
|
1126 |
+
}
|
1127 |
+
|
1128 |
+
return $result;
|
1129 |
+
}
|
1130 |
}
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/CarbonPeriod.php
ADDED
@@ -0,0 +1,1429 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of the Carbon package.
|
5 |
+
*
|
6 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
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 Carbon;
|
13 |
+
|
14 |
+
use BadMethodCallException;
|
15 |
+
use Closure;
|
16 |
+
use Countable;
|
17 |
+
use DateInterval;
|
18 |
+
use DateTime;
|
19 |
+
use DateTimeInterface;
|
20 |
+
use InvalidArgumentException;
|
21 |
+
use Iterator;
|
22 |
+
use ReflectionClass;
|
23 |
+
use ReflectionFunction;
|
24 |
+
use ReflectionMethod;
|
25 |
+
use RuntimeException;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Substitution of DatePeriod with some modifications and many more features.
|
29 |
+
* Fully compatible with PHP 5.3+!
|
30 |
+
*
|
31 |
+
* @method static CarbonPeriod start($date, $inclusive = null) Create instance specifying start date.
|
32 |
+
* @method static CarbonPeriod since($date, $inclusive = null) Alias for start().
|
33 |
+
* @method static CarbonPeriod sinceNow($inclusive = null) Create instance with start date set to now.
|
34 |
+
* @method static CarbonPeriod end($date = null, $inclusive = null) Create instance specifying end date.
|
35 |
+
* @method static CarbonPeriod until($date = null, $inclusive = null) Alias for end().
|
36 |
+
* @method static CarbonPeriod untilNow($inclusive = null) Create instance with end date set to now.
|
37 |
+
* @method static CarbonPeriod dates($start, $end = null) Create instance with start and end date.
|
38 |
+
* @method static CarbonPeriod between($start, $end = null) Create instance with start and end date.
|
39 |
+
* @method static CarbonPeriod recurrences($recurrences = null) Create instance with maximum number of recurrences.
|
40 |
+
* @method static CarbonPeriod times($recurrences = null) Alias for recurrences().
|
41 |
+
* @method static CarbonPeriod options($options = null) Create instance with options.
|
42 |
+
* @method static CarbonPeriod toggle($options, $state = null) Create instance with options toggled on or off.
|
43 |
+
* @method static CarbonPeriod filter($callback, $name = null) Create instance with filter added to the stack.
|
44 |
+
* @method static CarbonPeriod push($callback, $name = null) Alias for filter().
|
45 |
+
* @method static CarbonPeriod prepend($callback, $name = null) Create instance with filter prepened to the stack.
|
46 |
+
* @method static CarbonPeriod filters(array $filters) Create instance with filters stack.
|
47 |
+
* @method static CarbonPeriod interval($interval) Create instance with given date interval.
|
48 |
+
* @method static CarbonPeriod each($interval) Create instance with given date interval.
|
49 |
+
* @method static CarbonPeriod every($interval) Create instance with given date interval.
|
50 |
+
* @method static CarbonPeriod step($interval) Create instance with given date interval.
|
51 |
+
* @method static CarbonPeriod stepBy($interval) Create instance with given date interval.
|
52 |
+
* @method static CarbonPeriod invert() Create instance with inverted date interval.
|
53 |
+
* @method static CarbonPeriod years($years = 1) Create instance specifying a number of years for date interval.
|
54 |
+
* @method static CarbonPeriod year($years = 1) Alias for years().
|
55 |
+
* @method static CarbonPeriod months($months = 1) Create instance specifying a number of months for date interval.
|
56 |
+
* @method static CarbonPeriod month($months = 1) Alias for months().
|
57 |
+
* @method static CarbonPeriod weeks($weeks = 1) Create instance specifying a number of weeks for date interval.
|
58 |
+
* @method static CarbonPeriod week($weeks = 1) Alias for weeks().
|
59 |
+
* @method static CarbonPeriod days($days = 1) Create instance specifying a number of days for date interval.
|
60 |
+
* @method static CarbonPeriod dayz($days = 1) Alias for days().
|
61 |
+
* @method static CarbonPeriod day($days = 1) Alias for days().
|
62 |
+
* @method static CarbonPeriod hours($hours = 1) Create instance specifying a number of hours for date interval.
|
63 |
+
* @method static CarbonPeriod hour($hours = 1) Alias for hours().
|
64 |
+
* @method static CarbonPeriod minutes($minutes = 1) Create instance specifying a number of minutes for date interval.
|
65 |
+
* @method static CarbonPeriod minute($minutes = 1) Alias for minutes().
|
66 |
+
* @method static CarbonPeriod seconds($seconds = 1) Create instance specifying a number of seconds for date interval.
|
67 |
+
* @method static CarbonPeriod second($seconds = 1) Alias for seconds().
|
68 |
+
* @method CarbonPeriod start($date, $inclusive = null) Change the period start date.
|
69 |
+
* @method CarbonPeriod since($date, $inclusive = null) Alias for start().
|
70 |
+
* @method CarbonPeriod sinceNow($inclusive = null) Change the period start date to now.
|
71 |
+
* @method CarbonPeriod end($date = null, $inclusive = null) Change the period end date.
|
72 |
+
* @method CarbonPeriod until($date = null, $inclusive = null) Alias for end().
|
73 |
+
* @method CarbonPeriod untilNow($inclusive = null) Change the period end date to now.
|
74 |
+
* @method CarbonPeriod dates($start, $end = null) Change the period start and end date.
|
75 |
+
* @method CarbonPeriod recurrences($recurrences = null) Change the maximum number of recurrences.
|
76 |
+
* @method CarbonPeriod times($recurrences = null) Alias for recurrences().
|
77 |
+
* @method CarbonPeriod options($options = null) Change the period options.
|
78 |
+
* @method CarbonPeriod toggle($options, $state = null) Toggle given options on or off.
|
79 |
+
* @method CarbonPeriod filter($callback, $name = null) Add a filter to the stack.
|
80 |
+
* @method CarbonPeriod push($callback, $name = null) Alias for filter().
|
81 |
+
* @method CarbonPeriod prepend($callback, $name = null) Prepend a filter to the stack.
|
82 |
+
* @method CarbonPeriod filters(array $filters = array()) Set filters stack.
|
83 |
+
* @method CarbonPeriod interval($interval) Change the period date interval.
|
84 |
+
* @method CarbonPeriod invert() Invert the period date interval.
|
85 |
+
* @method CarbonPeriod years($years = 1) Set the years portion of the date interval.
|
86 |
+
* @method CarbonPeriod year($years = 1) Alias for years().
|
87 |
+
* @method CarbonPeriod months($months = 1) Set the months portion of the date interval.
|
88 |
+
* @method CarbonPeriod month($months = 1) Alias for months().
|
89 |
+
* @method CarbonPeriod weeks($weeks = 1) Set the weeks portion of the date interval.
|
90 |
+
* @method CarbonPeriod week($weeks = 1) Alias for weeks().
|
91 |
+
* @method CarbonPeriod days($days = 1) Set the days portion of the date interval.
|
92 |
+
* @method CarbonPeriod dayz($days = 1) Alias for days().
|
93 |
+
* @method CarbonPeriod day($days = 1) Alias for days().
|
94 |
+
* @method CarbonPeriod hours($hours = 1) Set the hours portion of the date interval.
|
95 |
+
* @method CarbonPeriod hour($hours = 1) Alias for hours().
|
96 |
+
* @method CarbonPeriod minutes($minutes = 1) Set the minutes portion of the date interval.
|
97 |
+
* @method CarbonPeriod minute($minutes = 1) Alias for minutes().
|
98 |
+
* @method CarbonPeriod seconds($seconds = 1) Set the seconds portion of the date interval.
|
99 |
+
* @method CarbonPeriod second($seconds = 1) Alias for seconds().
|
100 |
+
*/
|
101 |
+
class CarbonPeriod implements Iterator, Countable
|
102 |
+
{
|
103 |
+
/**
|
104 |
+
* Built-in filters.
|
105 |
+
*
|
106 |
+
* @var string
|
107 |
+
*/
|
108 |
+
const RECURRENCES_FILTER = 'Carbon\CarbonPeriod::filterRecurrences';
|
109 |
+
const END_DATE_FILTER = 'Carbon\CarbonPeriod::filterEndDate';
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Special value which can be returned by filters to end iteration. Also a filter.
|
113 |
+
*
|
114 |
+
* @var string
|
115 |
+
*/
|
116 |
+
const END_ITERATION = 'Carbon\CarbonPeriod::endIteration';
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Available options.
|
120 |
+
*
|
121 |
+
* @var int
|
122 |
+
*/
|
123 |
+
const EXCLUDE_START_DATE = 1;
|
124 |
+
const EXCLUDE_END_DATE = 2;
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Number of maximum attempts before giving up on finding next valid date.
|
128 |
+
*
|
129 |
+
* @var int
|
130 |
+
*/
|
131 |
+
const NEXT_MAX_ATTEMPTS = 1000;
|
132 |
+
|
133 |
+
/**
|
134 |
+
* The registered macros.
|
135 |
+
*
|
136 |
+
* @var array
|
137 |
+
*/
|
138 |
+
protected static $macros = array();
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Underlying date interval instance. Always present, one day by default.
|
142 |
+
*
|
143 |
+
* @var CarbonInterval
|
144 |
+
*/
|
145 |
+
protected $dateInterval;
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Whether current date interval was set by default.
|
149 |
+
*
|
150 |
+
* @var bool
|
151 |
+
*/
|
152 |
+
protected $isDefaultInterval;
|
153 |
+
|
154 |
+
/**
|
155 |
+
* The filters stack.
|
156 |
+
*
|
157 |
+
* @var array
|
158 |
+
*/
|
159 |
+
protected $filters = array();
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Period start date. Applied on rewind. Always present, now by default.
|
163 |
+
*
|
164 |
+
* @var Carbon
|
165 |
+
*/
|
166 |
+
protected $startDate;
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Period end date. For inverted interval should be before the start date. Applied via a filter.
|
170 |
+
*
|
171 |
+
* @var Carbon|null
|
172 |
+
*/
|
173 |
+
protected $endDate;
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Limit for number of recurrences. Applied via a filter.
|
177 |
+
*
|
178 |
+
* @var int|null
|
179 |
+
*/
|
180 |
+
protected $recurrences;
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Iteration options.
|
184 |
+
*
|
185 |
+
* @var int
|
186 |
+
*/
|
187 |
+
protected $options;
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Index of current date. Always sequential, even if some dates are skipped by filters.
|
191 |
+
* Equal to null only before the first iteration.
|
192 |
+
*
|
193 |
+
* @var int
|
194 |
+
*/
|
195 |
+
protected $key;
|
196 |
+
|
197 |
+
/**
|
198 |
+
* Current date. May temporarily hold unaccepted value when looking for a next valid date.
|
199 |
+
* Equal to null only before the first iteration.
|
200 |
+
*
|
201 |
+
* @var Carbon
|
202 |
+
*/
|
203 |
+
protected $current;
|
204 |
+
|
205 |
+
/**
|
206 |
+
* Timezone of current date. Taken from the start date.
|
207 |
+
*
|
208 |
+
* @var \DateTimeZone|null
|
209 |
+
*/
|
210 |
+
protected $timezone;
|
211 |
+
|
212 |
+
/**
|
213 |
+
* The cached validation result for current date.
|
214 |
+
*
|
215 |
+
* @var bool|static::END_ITERATION
|
216 |
+
*/
|
217 |
+
protected $validationResult;
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Create a new instance.
|
221 |
+
*
|
222 |
+
* @return static
|
223 |
+
*/
|
224 |
+
public static function create()
|
225 |
+
{
|
226 |
+
return static::createFromArray(func_get_args());
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Create a new instance from an array of parameters.
|
231 |
+
*
|
232 |
+
* @param array $params
|
233 |
+
*
|
234 |
+
* @return static
|
235 |
+
*/
|
236 |
+
public static function createFromArray(array $params)
|
237 |
+
{
|
238 |
+
// PHP 5.3 equivalent of new static(...$params).
|
239 |
+
$reflection = new ReflectionClass(get_class());
|
240 |
+
|
241 |
+
return $reflection->newInstanceArgs($params);
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Create CarbonPeriod from ISO 8601 string.
|
246 |
+
*
|
247 |
+
* @param string $iso
|
248 |
+
* @param int|null $options
|
249 |
+
*
|
250 |
+
* @return static
|
251 |
+
*/
|
252 |
+
public static function createFromIso($iso, $options = null)
|
253 |
+
{
|
254 |
+
$params = static::parseIso8601($iso);
|
255 |
+
|
256 |
+
$instance = static::createFromArray($params);
|
257 |
+
|
258 |
+
if ($options !== null) {
|
259 |
+
$instance->setOptions($options);
|
260 |
+
}
|
261 |
+
|
262 |
+
return $instance;
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Return whether given interval contains non zero value of any time unit.
|
267 |
+
*
|
268 |
+
* @param \DateInterval $interval
|
269 |
+
*
|
270 |
+
* @return bool
|
271 |
+
*/
|
272 |
+
protected static function intervalHasTime(DateInterval $interval)
|
273 |
+
{
|
274 |
+
// The array_key_exists and get_object_vars are used as a workaround to check microsecond support.
|
275 |
+
// Both isset and property_exists will fail on PHP 7.0.14 - 7.0.21 due to the following bug:
|
276 |
+
// https://bugs.php.net/bug.php?id=74852
|
277 |
+
return $interval->h || $interval->i || $interval->s || array_key_exists('f', get_object_vars($interval)) && $interval->f;
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Return whether given callable is a string pointing to one of Carbon's is* methods
|
282 |
+
* and should be automatically converted to a filter callback.
|
283 |
+
*
|
284 |
+
* @param callable $callable
|
285 |
+
*
|
286 |
+
* @return bool
|
287 |
+
*/
|
288 |
+
protected static function isCarbonPredicateMethod($callable)
|
289 |
+
{
|
290 |
+
return is_string($callable) && substr($callable, 0, 2) === 'is' && (method_exists('Carbon\Carbon', $callable) || Carbon::hasMacro($callable));
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Return whether given variable is an ISO 8601 specification.
|
295 |
+
*
|
296 |
+
* Note: Check is very basic, as actual validation will be done later when parsing.
|
297 |
+
* We just want to ensure that variable is not any other type of a valid parameter.
|
298 |
+
*
|
299 |
+
* @param mixed $var
|
300 |
+
*
|
301 |
+
* @return bool
|
302 |
+
*/
|
303 |
+
protected static function isIso8601($var)
|
304 |
+
{
|
305 |
+
if (!is_string($var)) {
|
306 |
+
return false;
|
307 |
+
}
|
308 |
+
|
309 |
+
// Match slash but not within a timezone name.
|
310 |
+
$part = '[a-z]+(?:[_-][a-z]+)*';
|
311 |
+
|
312 |
+
preg_match("#\b$part/$part\b|(/)#i", $var, $match);
|
313 |
+
|
314 |
+
return isset($match[1]);
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Parse given ISO 8601 string into an array of arguments.
|
319 |
+
*
|
320 |
+
* @param string $iso
|
321 |
+
*
|
322 |
+
* @return array
|
323 |
+
*/
|
324 |
+
protected static function parseIso8601($iso)
|
325 |
+
{
|
326 |
+
$result = array();
|
327 |
+
|
328 |
+
$interval = null;
|
329 |
+
$start = null;
|
330 |
+
$end = null;
|
331 |
+
|
332 |
+
foreach (explode('/', $iso) as $key => $part) {
|
333 |
+
if ($key === 0 && preg_match('/^R([0-9]*)$/', $part, $match)) {
|
334 |
+
$parsed = strlen($match[1]) ? (int) $match[1] : null;
|
335 |
+
} elseif ($interval === null && $parsed = CarbonInterval::make($part)) {
|
336 |
+
$interval = $part;
|
337 |
+
} elseif ($start === null && $parsed = Carbon::make($part)) {
|
338 |
+
$start = $part;
|
339 |
+
} elseif ($end === null && $parsed = Carbon::make(static::addMissingParts($start, $part))) {
|
340 |
+
$end = $part;
|
341 |
+
} else {
|
342 |
+
throw new InvalidArgumentException("Invalid ISO 8601 specification: $iso.");
|
343 |
+
}
|
344 |
+
|
345 |
+
$result[] = $parsed;
|
346 |
+
}
|
347 |
+
|
348 |
+
return $result;
|
349 |
+
}
|
350 |
+
|
351 |
+
/**
|
352 |
+
* Add missing parts of the target date from the soure date.
|
353 |
+
*
|
354 |
+
* @param string $source
|
355 |
+
* @param string $target
|
356 |
+
*
|
357 |
+
* @return string
|
358 |
+
*/
|
359 |
+
protected static function addMissingParts($source, $target)
|
360 |
+
{
|
361 |
+
$pattern = '/'.preg_replace('/[0-9]+/', '[0-9]+', preg_quote($target, '/')).'$/';
|
362 |
+
|
363 |
+
$result = preg_replace($pattern, $target, $source, 1, $count);
|
364 |
+
|
365 |
+
return $count ? $result : $target;
|
366 |
+
}
|
367 |
+
|
368 |
+
/**
|
369 |
+
* Register a custom macro.
|
370 |
+
*
|
371 |
+
* @param string $name
|
372 |
+
* @param object|callable $macro
|
373 |
+
*
|
374 |
+
* @return void
|
375 |
+
*/
|
376 |
+
public static function macro($name, $macro)
|
377 |
+
{
|
378 |
+
static::$macros[$name] = $macro;
|
379 |
+
}
|
380 |
+
|
381 |
+
/**
|
382 |
+
* Register macros from a mixin object.
|
383 |
+
*
|
384 |
+
* @param object $mixin
|
385 |
+
*
|
386 |
+
* @throws \ReflectionException
|
387 |
+
*
|
388 |
+
* @return void
|
389 |
+
*/
|
390 |
+
public static function mixin($mixin)
|
391 |
+
{
|
392 |
+
$reflection = new ReflectionClass($mixin);
|
393 |
+
|
394 |
+
$methods = $reflection->getMethods(
|
395 |
+
ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
|
396 |
+
);
|
397 |
+
|
398 |
+
foreach ($methods as $method) {
|
399 |
+
$method->setAccessible(true);
|
400 |
+
|
401 |
+
static::macro($method->name, $method->invoke($mixin));
|
402 |
+
}
|
403 |
+
}
|
404 |
+
|
405 |
+
/**
|
406 |
+
* Check if macro is registered.
|
407 |
+
*
|
408 |
+
* @param string $name
|
409 |
+
*
|
410 |
+
* @return bool
|
411 |
+
*/
|
412 |
+
public static function hasMacro($name)
|
413 |
+
{
|
414 |
+
return isset(static::$macros[$name]);
|
415 |
+
}
|
416 |
+
|
417 |
+
/**
|
418 |
+
* Provide static proxy for instance aliases.
|
419 |
+
*
|
420 |
+
* @param string $method
|
421 |
+
* @param array $parameters
|
422 |
+
*
|
423 |
+
* @return mixed
|
424 |
+
*/
|
425 |
+
public static function __callStatic($method, $parameters)
|
426 |
+
{
|
427 |
+
return call_user_func_array(
|
428 |
+
array(new static, $method), $parameters
|
429 |
+
);
|
430 |
+
}
|
431 |
+
|
432 |
+
/**
|
433 |
+
* CarbonPeriod constructor.
|
434 |
+
*
|
435 |
+
* @throws InvalidArgumentException
|
436 |
+
*/
|
437 |
+
public function __construct()
|
438 |
+
{
|
439 |
+
// Parse and assign arguments one by one. First argument may be an ISO 8601 spec,
|
440 |
+
// which will be first parsed into parts and then processed the same way.
|
441 |
+
$arguments = func_get_args();
|
442 |
+
|
443 |
+
if (count($arguments) && static::isIso8601($iso = $arguments[0])) {
|
444 |
+
array_splice($arguments, 0, 1, static::parseIso8601($iso));
|
445 |
+
}
|
446 |
+
|
447 |
+
foreach ($arguments as $argument) {
|
448 |
+
if ($this->dateInterval === null && $parsed = CarbonInterval::make($argument)) {
|
449 |
+
$this->setDateInterval($parsed);
|
450 |
+
} elseif ($this->startDate === null && $parsed = Carbon::make($argument)) {
|
451 |
+
$this->setStartDate($parsed);
|
452 |
+
} elseif ($this->endDate === null && $parsed = Carbon::make($argument)) {
|
453 |
+
$this->setEndDate($parsed);
|
454 |
+
} elseif ($this->recurrences === null && $this->endDate === null && is_numeric($argument)) {
|
455 |
+
$this->setRecurrences($argument);
|
456 |
+
} elseif ($this->options === null && (is_int($argument) || $argument === null)) {
|
457 |
+
$this->setOptions($argument);
|
458 |
+
} else {
|
459 |
+
throw new InvalidArgumentException('Invalid constructor parameters.');
|
460 |
+
}
|
461 |
+
}
|
462 |
+
|
463 |
+
if ($this->startDate === null) {
|
464 |
+
$this->setStartDate(Carbon::now());
|
465 |
+
}
|
466 |
+
|
467 |
+
if ($this->dateInterval === null) {
|
468 |
+
$this->setDateInterval(CarbonInterval::day());
|
469 |
+
|
470 |
+
$this->isDefaultInterval = true;
|
471 |
+
}
|
472 |
+
|
473 |
+
if ($this->options === null) {
|
474 |
+
$this->setOptions(0);
|
475 |
+
}
|
476 |
+
}
|
477 |
+
|
478 |
+
/**
|
479 |
+
* Change the period date interval.
|
480 |
+
*
|
481 |
+
* @param DateInterval|string $interval
|
482 |
+
*
|
483 |
+
* @throws \InvalidArgumentException
|
484 |
+
*
|
485 |
+
* @return $this
|
486 |
+
*/
|
487 |
+
public function setDateInterval($interval)
|
488 |
+
{
|
489 |
+
if (!$interval = CarbonInterval::make($interval)) {
|
490 |
+
throw new InvalidArgumentException('Invalid interval.');
|
491 |
+
}
|
492 |
+
|
493 |
+
if ($interval->spec() === 'PT0S') {
|
494 |
+
throw new InvalidArgumentException('Empty interval is not accepted.');
|
495 |
+
}
|
496 |
+
|
497 |
+
$this->dateInterval = $interval;
|
498 |
+
|
499 |
+
$this->isDefaultInterval = false;
|
500 |
+
|
501 |
+
$this->handleChangedParameters();
|
502 |
+
|
503 |
+
return $this;
|
504 |
+
}
|
505 |
+
|
506 |
+
/**
|
507 |
+
* Invert the period date interval.
|
508 |
+
*
|
509 |
+
* @return $this
|
510 |
+
*/
|
511 |
+
public function invertDateInterval()
|
512 |
+
{
|
513 |
+
$interval = $this->dateInterval->invert();
|
514 |
+
|
515 |
+
return $this->setDateInterval($interval);
|
516 |
+
}
|
517 |
+
|
518 |
+
/**
|
519 |
+
* Set start and end date.
|
520 |
+
*
|
521 |
+
* @param DateTime|DateTimeInterface|string $start
|
522 |
+
* @param DateTime|DateTimeInterface|string|null $end
|
523 |
+
*
|
524 |
+
* @return $this
|
525 |
+
*/
|
526 |
+
public function setDates($start, $end)
|
527 |
+
{
|
528 |
+
$this->setStartDate($start);
|
529 |
+
$this->setEndDate($end);
|
530 |
+
|
531 |
+
return $this;
|
532 |
+
}
|
533 |
+
|
534 |
+
/**
|
535 |
+
* Change the period options.
|
536 |
+
*
|
537 |
+
* @param int|null $options
|
538 |
+
*
|
539 |
+
* @throws \InvalidArgumentException
|
540 |
+
*
|
541 |
+
* @return $this
|
542 |
+
*/
|
543 |
+
public function setOptions($options)
|
544 |
+
{
|
545 |
+
if (!is_int($options) && !is_null($options)) {
|
546 |
+
throw new InvalidArgumentException('Invalid options.');
|
547 |
+
}
|
548 |
+
|
549 |
+
$this->options = $options ?: 0;
|
550 |
+
|
551 |
+
$this->handleChangedParameters();
|
552 |
+
|
553 |
+
return $this;
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* Get the period options.
|
558 |
+
*
|
559 |
+
* @return int
|
560 |
+
*/
|
561 |
+
public function getOptions()
|
562 |
+
{
|
563 |
+
return $this->options;
|
564 |
+
}
|
565 |
+
|
566 |
+
/**
|
567 |
+
* Toggle given options on or off.
|
568 |
+
*
|
569 |
+
* @param int $options
|
570 |
+
* @param bool|null $state
|
571 |
+
*
|
572 |
+
* @throws \InvalidArgumentException
|
573 |
+
*
|
574 |
+
* @return $this
|
575 |
+
*/
|
576 |
+
public function toggleOptions($options, $state = null)
|
577 |
+
{
|
578 |
+
if ($state === null) {
|
579 |
+
$state = ($this->options & $options) !== $options;
|
580 |
+
}
|
581 |
+
|
582 |
+
return $this->setOptions($state ?
|
583 |
+
$this->options | $options :
|
584 |
+
$this->options & ~$options
|
585 |
+
);
|
586 |
+
}
|
587 |
+
|
588 |
+
/**
|
589 |
+
* Toggle EXCLUDE_START_DATE option.
|
590 |
+
*
|
591 |
+
* @param bool $state
|
592 |
+
*
|
593 |
+
* @return $this
|
594 |
+
*/
|
595 |
+
public function excludeStartDate($state = true)
|
596 |
+
{
|
597 |
+
return $this->toggleOptions(static::EXCLUDE_START_DATE, $state);
|
598 |
+
}
|
599 |
+
|
600 |
+
/**
|
601 |
+
* Toggle EXCLUDE_END_DATE option.
|
602 |
+
*
|
603 |
+
* @param bool $state
|
604 |
+
*
|
605 |
+
* @return $this
|
606 |
+
*/
|
607 |
+
public function excludeEndDate($state = true)
|
608 |
+
{
|
609 |
+
return $this->toggleOptions(static::EXCLUDE_END_DATE, $state);
|
610 |
+
}
|
611 |
+
|
612 |
+
/**
|
613 |
+
* Get the underlying date interval.
|
614 |
+
*
|
615 |
+
* @return CarbonInterval
|
616 |
+
*/
|
617 |
+
public function getDateInterval()
|
618 |
+
{
|
619 |
+
return $this->dateInterval->copy();
|
620 |
+
}
|
621 |
+
|
622 |
+
/**
|
623 |
+
* Get start date of the period.
|
624 |
+
*
|
625 |
+
* @return Carbon
|
626 |
+
*/
|
627 |
+
public function getStartDate()
|
628 |
+
{
|
629 |
+
return $this->startDate->copy();
|
630 |
+
}
|
631 |
+
|
632 |
+
/**
|
633 |
+
* Get end date of the period.
|
634 |
+
*
|
635 |
+
* @return Carbon|null
|
636 |
+
*/
|
637 |
+
public function getEndDate()
|
638 |
+
{
|
639 |
+
if ($this->endDate) {
|
640 |
+
return $this->endDate->copy();
|
641 |
+
}
|
642 |
+
}
|
643 |
+
|
644 |
+
/**
|
645 |
+
* Get number of recurrences.
|
646 |
+
*
|
647 |
+
* @return int|null
|
648 |
+
*/
|
649 |
+
public function getRecurrences()
|
650 |
+
{
|
651 |
+
return $this->recurrences;
|
652 |
+
}
|
653 |
+
|
654 |
+
/**
|
655 |
+
* Returns true if the start date should be excluded.
|
656 |
+
*
|
657 |
+
* @return bool
|
658 |
+
*/
|
659 |
+
public function isStartExcluded()
|
660 |
+
{
|
661 |
+
return ($this->options & static::EXCLUDE_START_DATE) !== 0;
|
662 |
+
}
|
663 |
+
|
664 |
+
/**
|
665 |
+
* Returns true if the end date should be excluded.
|
666 |
+
*
|
667 |
+
* @return bool
|
668 |
+
*/
|
669 |
+
public function isEndExcluded()
|
670 |
+
{
|
671 |
+
return ($this->options & static::EXCLUDE_END_DATE) !== 0;
|
672 |
+
}
|
673 |
+
|
674 |
+
/**
|
675 |
+
* Add a filter to the stack.
|
676 |
+
*
|
677 |
+
* @param callable $callback
|
678 |
+
* @param string $name
|
679 |
+
*
|
680 |
+
* @return $this
|
681 |
+
*/
|
682 |
+
public function addFilter($callback, $name = null)
|
683 |
+
{
|
684 |
+
$tuple = $this->createFilterTuple(func_get_args());
|
685 |
+
|
686 |
+
$this->filters[] = $tuple;
|
687 |
+
|
688 |
+
$this->handleChangedParameters();
|
689 |
+
|
690 |
+
return $this;
|
691 |
+
}
|
692 |
+
|
693 |
+
/**
|
694 |
+
* Prepend a filter to the stack.
|
695 |
+
*
|
696 |
+
* @param callable $callback
|
697 |
+
* @param string $name
|
698 |
+
*
|
699 |
+
* @return $this
|
700 |
+
*/
|
701 |
+
public function prependFilter($callback, $name = null)
|
702 |
+
{
|
703 |
+
$tuple = $this->createFilterTuple(func_get_args());
|
704 |
+
|
705 |
+
array_unshift($this->filters, $tuple);
|
706 |
+
|
707 |
+
$this->handleChangedParameters();
|
708 |
+
|
709 |
+
return $this;
|
710 |
+
}
|
711 |
+
|
712 |
+
/**
|
713 |
+
* Create a filter tuple from raw parameters.
|
714 |
+
*
|
715 |
+
* Will create an automatic filter callback for one of Carbon's is* methods.
|
716 |
+
*
|
717 |
+
* @param array $parameters
|
718 |
+
*
|
719 |
+
* @return array
|
720 |
+
*/
|
721 |
+
protected function createFilterTuple(array $parameters)
|
722 |
+
{
|
723 |
+
$method = array_shift($parameters);
|
724 |
+
|
725 |
+
if (!$this->isCarbonPredicateMethod($method)) {
|
726 |
+
return array($method, array_shift($parameters));
|
727 |
+
}
|
728 |
+
|
729 |
+
return array(function ($date) use ($method, $parameters) {
|
730 |
+
return call_user_func_array(array($date, $method), $parameters);
|
731 |
+
}, $method);
|
732 |
+
}
|
733 |
+
|
734 |
+
/**
|
735 |
+
* Remove a filter by instance or name.
|
736 |
+
*
|
737 |
+
* @param callable|string $filter
|
738 |
+
*
|
739 |
+
* @return $this
|
740 |
+
*/
|
741 |
+
public function removeFilter($filter)
|
742 |
+
{
|
743 |
+
$key = is_callable($filter) ? 0 : 1;
|
744 |
+
|
745 |
+
$this->filters = array_values(array_filter(
|
746 |
+
$this->filters,
|
747 |
+
function ($tuple) use ($key, $filter) {
|
748 |
+
return $tuple[$key] !== $filter;
|
749 |
+
}
|
750 |
+
));
|
751 |
+
|
752 |
+
$this->updateInternalState();
|
753 |
+
|
754 |
+
$this->handleChangedParameters();
|
755 |
+
|
756 |
+
return $this;
|
757 |
+
}
|
758 |
+
|
759 |
+
/**
|
760 |
+
* Return whether given instance or name is in the filter stack.
|
761 |
+
*
|
762 |
+
* @param callable|string $filter
|
763 |
+
*
|
764 |
+
* @return bool
|
765 |
+
*/
|
766 |
+
public function hasFilter($filter)
|
767 |
+
{
|
768 |
+
$key = is_callable($filter) ? 0 : 1;
|
769 |
+
|
770 |
+
foreach ($this->filters as $tuple) {
|
771 |
+
if ($tuple[$key] === $filter) {
|
772 |
+
return true;
|
773 |
+
}
|
774 |
+
}
|
775 |
+
|
776 |
+
return false;
|
777 |
+
}
|
778 |
+
|
779 |
+
/**
|
780 |
+
* Get filters stack.
|
781 |
+
*
|
782 |
+
* @return array
|
783 |
+
*/
|
784 |
+
public function getFilters()
|
785 |
+
{
|
786 |
+
return $this->filters;
|
787 |
+
}
|
788 |
+
|
789 |
+
/**
|
790 |
+
* Set filters stack.
|
791 |
+
*
|
792 |
+
* @param array $filters
|
793 |
+
*
|
794 |
+
* @return $this
|
795 |
+
*/
|
796 |
+
public function setFilters(array $filters)
|
797 |
+
{
|
798 |
+
$this->filters = $filters;
|
799 |
+
|
800 |
+
$this->updateInternalState();
|
801 |
+
|
802 |
+
$this->handleChangedParameters();
|
803 |
+
|
804 |
+
return $this;
|
805 |
+
}
|
806 |
+
|
807 |
+
/**
|
808 |
+
* Reset filters stack.
|
809 |
+
*
|
810 |
+
* @return $this
|
811 |
+
*/
|
812 |
+
public function resetFilters()
|
813 |
+
{
|
814 |
+
$this->filters = array();
|
815 |
+
|
816 |
+
if ($this->endDate !== null) {
|
817 |
+
$this->filters[] = array(static::END_DATE_FILTER, null);
|
818 |
+
}
|
819 |
+
|
820 |
+
if ($this->recurrences !== null) {
|
821 |
+
$this->filters[] = array(static::RECURRENCES_FILTER, null);
|
822 |
+
}
|
823 |
+
|
824 |
+
$this->handleChangedParameters();
|
825 |
+
|
826 |
+
return $this;
|
827 |
+
}
|
828 |
+
|
829 |
+
/**
|
830 |
+
* Update properties after removing built-in filters.
|
831 |
+
*
|
832 |
+
* @return void
|
833 |
+
*/
|
834 |
+
protected function updateInternalState()
|
835 |
+
{
|
836 |
+
if (!$this->hasFilter(static::END_DATE_FILTER)) {
|
837 |
+
$this->endDate = null;
|
838 |
+
}
|
839 |
+
|
840 |
+
if (!$this->hasFilter(static::RECURRENCES_FILTER)) {
|
841 |
+
$this->recurrences = null;
|
842 |
+
}
|
843 |
+
}
|
844 |
+
|
845 |
+
/**
|
846 |
+
* Add a recurrences filter (set maximum number of recurrences).
|
847 |
+
*
|
848 |
+
* @param int|null $recurrences
|
849 |
+
*
|
850 |
+
* @throws \InvalidArgumentException
|
851 |
+
*
|
852 |
+
* @return $this
|
853 |
+
*/
|
854 |
+
public function setRecurrences($recurrences)
|
855 |
+
{
|
856 |
+
if (!is_numeric($recurrences) && !is_null($recurrences) || $recurrences < 0) {
|
857 |
+
throw new InvalidArgumentException('Invalid number of recurrences.');
|
858 |
+
}
|
859 |
+
|
860 |
+
if ($recurrences === null) {
|
861 |
+
return $this->removeFilter(static::RECURRENCES_FILTER);
|
862 |
+
}
|
863 |
+
|
864 |
+
$this->recurrences = (int) $recurrences;
|
865 |
+
|
866 |
+
if (!$this->hasFilter(static::RECURRENCES_FILTER)) {
|
867 |
+
return $this->addFilter(static::RECURRENCES_FILTER);
|
868 |
+
}
|
869 |
+
|
870 |
+
$this->handleChangedParameters();
|
871 |
+
|
872 |
+
return $this;
|
873 |
+
}
|
874 |
+
|
875 |
+
/**
|
876 |
+
* Recurrences filter callback (limits number of recurrences).
|
877 |
+
*
|
878 |
+
* @param \Carbon\Carbon $current
|
879 |
+
* @param int $key
|
880 |
+
*
|
881 |
+
* @return bool|static::END_ITERATION
|
882 |
+
*/
|
883 |
+
protected function filterRecurrences($current, $key)
|
884 |
+
{
|
885 |
+
if ($key < $this->recurrences) {
|
886 |
+
return true;
|
887 |
+
}
|
888 |
+
|
889 |
+
return static::END_ITERATION;
|
890 |
+
}
|
891 |
+
|
892 |
+
/**
|
893 |
+
* Change the period start date.
|
894 |
+
*
|
895 |
+
* @param DateTime|DateTimeInterface|string $date
|
896 |
+
* @param bool|null $inclusive
|
897 |
+
*
|
898 |
+
* @throws \InvalidArgumentException
|
899 |
+
*
|
900 |
+
* @return $this
|
901 |
+
*/
|
902 |
+
public function setStartDate($date, $inclusive = null)
|
903 |
+
{
|
904 |
+
if (!$date = Carbon::make($date)) {
|
905 |
+
throw new InvalidArgumentException('Invalid start date.');
|
906 |
+
}
|
907 |
+
|
908 |
+
$this->startDate = $date;
|
909 |
+
|
910 |
+
if ($inclusive !== null) {
|
911 |
+
$this->toggleOptions(static::EXCLUDE_START_DATE, !$inclusive);
|
912 |
+
}
|
913 |
+
|
914 |
+
return $this;
|
915 |
+
}
|
916 |
+
|
917 |
+
/**
|
918 |
+
* Change the period end date.
|
919 |
+
*
|
920 |
+
* @param DateTime|DateTimeInterface|string|null $date
|
921 |
+
* @param bool|null $inclusive
|
922 |
+
*
|
923 |
+
* @throws \InvalidArgumentException
|
924 |
+
*
|
925 |
+
* @return $this
|
926 |
+
*/
|
927 |
+
public function setEndDate($date, $inclusive = null)
|
928 |
+
{
|
929 |
+
if (!is_null($date) && !$date = Carbon::make($date)) {
|
930 |
+
throw new InvalidArgumentException('Invalid end date.');
|
931 |
+
}
|
932 |
+
|
933 |
+
if (!$date) {
|
934 |
+
return $this->removeFilter(static::END_DATE_FILTER);
|
935 |
+
}
|
936 |
+
|
937 |
+
$this->endDate = $date;
|
938 |
+
|
939 |
+
if ($inclusive !== null) {
|
940 |
+
$this->toggleOptions(static::EXCLUDE_END_DATE, !$inclusive);
|
941 |
+
}
|
942 |
+
|
943 |
+
if (!$this->hasFilter(static::END_DATE_FILTER)) {
|
944 |
+
return $this->addFilter(static::END_DATE_FILTER);
|
945 |
+
}
|
946 |
+
|
947 |
+
$this->handleChangedParameters();
|
948 |
+
|
949 |
+
return $this;
|
950 |
+
}
|
951 |
+
|
952 |
+
/**
|
953 |
+
* End date filter callback.
|
954 |
+
*
|
955 |
+
* @param \Carbon\Carbon $current
|
956 |
+
*
|
957 |
+
* @return bool|static::END_ITERATION
|
958 |
+
*/
|
959 |
+
protected function filterEndDate($current)
|
960 |
+
{
|
961 |
+
if (!$this->isEndExcluded() && $current == $this->endDate) {
|
962 |
+
return true;
|
963 |
+
}
|
964 |
+
|
965 |
+
if ($this->dateInterval->invert ? $current > $this->endDate : $current < $this->endDate) {
|
966 |
+
return true;
|
967 |
+
}
|
968 |
+
|
969 |
+
return static::END_ITERATION;
|
970 |
+
}
|
971 |
+
|
972 |
+
/**
|
973 |
+
* End iteration filter callback.
|
974 |
+
*
|
975 |
+
* @return static::END_ITERATION
|
976 |
+
*/
|
977 |
+
protected function endIteration()
|
978 |
+
{
|
979 |
+
return static::END_ITERATION;
|
980 |
+
}
|
981 |
+
|
982 |
+
/**
|
983 |
+
* Handle change of the parameters.
|
984 |
+
*
|
985 |
+
* @return void
|
986 |
+
*/
|
987 |
+
protected function handleChangedParameters()
|
988 |
+
{
|
989 |
+
$this->validationResult = null;
|
990 |
+
}
|
991 |
+
|
992 |
+
/**
|
993 |
+
* Validate current date and stop iteration when necessary.
|
994 |
+
*
|
995 |
+
* Returns true when current date is valid, false if it is not, or static::END_ITERATION
|
996 |
+
* when iteration should be stopped.
|
997 |
+
*
|
998 |
+
* @return bool|static::END_ITERATION
|
999 |
+
*/
|
1000 |
+
protected function validateCurrentDate()
|
1001 |
+
{
|
1002 |
+
if ($this->current === null) {
|
1003 |
+
$this->rewind();
|
1004 |
+
}
|
1005 |
+
|
1006 |
+
// Check after the first rewind to avoid repeating the initial validation.
|
1007 |
+
if ($this->validationResult !== null) {
|
1008 |
+
return $this->validationResult;
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
return $this->validationResult = $this->checkFilters();
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
/**
|
1015 |
+
* Check whether current value and key pass all the filters.
|
1016 |
+
*
|
1017 |
+
* @return bool|static::END_ITERATION
|
1018 |
+
*/
|
1019 |
+
protected function checkFilters()
|
1020 |
+
{
|
1021 |
+
$current = $this->prepareForReturn($this->current);
|
1022 |
+
|
1023 |
+
foreach ($this->filters as $tuple) {
|
1024 |
+
$result = call_user_func(
|
1025 |
+
$tuple[0], $current->copy(), $this->key, $this
|
1026 |
+
);
|
1027 |
+
|
1028 |
+
if ($result === static::END_ITERATION) {
|
1029 |
+
return static::END_ITERATION;
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
if (!$result) {
|
1033 |
+
return false;
|
1034 |
+
}
|
1035 |
+
}
|
1036 |
+
|
1037 |
+
return true;
|
1038 |
+
}
|
1039 |
+
|
1040 |
+
/**
|
1041 |
+
* Prepare given date to be returned to the external logic.
|
1042 |
+
*
|
1043 |
+
* @param Carbon $date
|
1044 |
+
*
|
1045 |
+
* @return Carbon
|
1046 |
+
*/
|
1047 |
+
protected function prepareForReturn(Carbon $date)
|
1048 |
+
{
|
1049 |
+
$date = $date->copy();
|
1050 |
+
|
1051 |
+
if ($this->timezone) {
|
1052 |
+
$date->setTimezone($this->timezone);
|
1053 |
+
}
|
1054 |
+
|
1055 |
+
return $date;
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
/**
|
1059 |
+
* Check if the current position is valid.
|
1060 |
+
*
|
1061 |
+
* @return bool
|
1062 |
+
*/
|
1063 |
+
public function valid()
|
1064 |
+
{
|
1065 |
+
return $this->validateCurrentDate() === true;
|
1066 |
+
}
|
1067 |
+
|
1068 |
+
/**
|
1069 |
+
* Return the current key.
|
1070 |
+
*
|
1071 |
+
* @return int|null
|
1072 |
+
*/
|
1073 |
+
public function key()
|
1074 |
+
{
|
1075 |
+
if ($this->valid()) {
|
1076 |
+
return $this->key;
|
1077 |
+
}
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
/**
|
1081 |
+
* Return the current date.
|
1082 |
+
*
|
1083 |
+
* @return Carbon|null
|
1084 |
+
*/
|
1085 |
+
public function current()
|
1086 |
+
{
|
1087 |
+
if ($this->valid()) {
|
1088 |
+
return $this->prepareForReturn($this->current);
|
1089 |
+
}
|
1090 |
+
}
|
1091 |
+
|
1092 |
+
/**
|
1093 |
+
* Move forward to the next date.
|
1094 |
+
*
|
1095 |
+
* @throws \RuntimeException
|
1096 |
+
*
|
1097 |
+
* @return void
|
1098 |
+
*/
|
1099 |
+
public function next()
|
1100 |
+
{
|
1101 |
+
if ($this->current === null) {
|
1102 |
+
$this->rewind();
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
if ($this->validationResult !== static::END_ITERATION) {
|
1106 |
+
$this->key++;
|
1107 |
+
|
1108 |
+
$this->incrementCurrentDateUntilValid();
|
1109 |
+
}
|
1110 |
+
}
|
1111 |
+
|
1112 |
+
/**
|
1113 |
+
* Rewind to the start date.
|
1114 |
+
*
|
1115 |
+
* Iterating over a date in the UTC timezone avoids bug during backward DST change.
|
1116 |
+
*
|
1117 |
+
* @see https://bugs.php.net/bug.php?id=72255
|
1118 |
+
* @see https://bugs.php.net/bug.php?id=74274
|
1119 |
+
* @see https://wiki.php.net/rfc/datetime_and_daylight_saving_time
|
1120 |
+
*
|
1121 |
+
* @throws \RuntimeException
|
1122 |
+
*
|
1123 |
+
* @return void
|
1124 |
+
*/
|
1125 |
+
public function rewind()
|
1126 |
+
{
|
1127 |
+
$this->key = 0;
|
1128 |
+
$this->current = $this->startDate->copy();
|
1129 |
+
$this->timezone = static::intervalHasTime($this->dateInterval) ? $this->current->getTimezone() : null;
|
1130 |
+
|
1131 |
+
if ($this->timezone) {
|
1132 |
+
$this->current->setTimezone('UTC');
|
1133 |
+
}
|
1134 |
+
|
1135 |
+
$this->validationResult = null;
|
1136 |
+
|
1137 |
+
if ($this->isStartExcluded() || $this->validateCurrentDate() === false) {
|
1138 |
+
$this->incrementCurrentDateUntilValid();
|
1139 |
+
}
|
1140 |
+
}
|
1141 |
+
|
1142 |
+
/**
|
1143 |
+
* Keep incrementing the current date until a valid date is found or the iteration is ended.
|
1144 |
+
*
|
1145 |
+
* @throws \RuntimeException
|
1146 |
+
*
|
1147 |
+
* @return void
|
1148 |
+
*/
|
1149 |
+
protected function incrementCurrentDateUntilValid()
|
1150 |
+
{
|
1151 |
+
$attempts = 0;
|
1152 |
+
|
1153 |
+
do {
|
1154 |
+
$this->current->add($this->dateInterval);
|
1155 |
+
|
1156 |
+
$this->validationResult = null;
|
1157 |
+
|
1158 |
+
if (++$attempts > static::NEXT_MAX_ATTEMPTS) {
|
1159 |
+
throw new RuntimeException('Could not find next valid date.');
|
1160 |
+
}
|
1161 |
+
} while ($this->validateCurrentDate() === false);
|
1162 |
+
}
|
1163 |
+
|
1164 |
+
/**
|
1165 |
+
* Format the date period as ISO 8601.
|
1166 |
+
*
|
1167 |
+
* @return string
|
1168 |
+
*/
|
1169 |
+
public function toIso8601String()
|
1170 |
+
{
|
1171 |
+
$parts = array();
|
1172 |
+
|
1173 |
+
if ($this->recurrences !== null) {
|
1174 |
+
$parts[] = 'R'.$this->recurrences;
|
1175 |
+
}
|
1176 |
+
|
1177 |
+
$parts[] = $this->startDate->toIso8601String();
|
1178 |
+
|
1179 |
+
$parts[] = $this->dateInterval->spec();
|
1180 |
+
|
1181 |
+
if ($this->endDate !== null) {
|
1182 |
+
$parts[] = $this->endDate->toIso8601String();
|
1183 |
+
}
|
1184 |
+
|
1185 |
+
return implode('/', $parts);
|
1186 |
+
}
|
1187 |
+
|
1188 |
+
/**
|
1189 |
+
* Convert the date period into a string.
|
1190 |
+
*
|
1191 |
+
* @return string
|
1192 |
+
*/
|
1193 |
+
public function toString()
|
1194 |
+
{
|
1195 |
+
$translator = Carbon::getTranslator();
|
1196 |
+
|
1197 |
+
$parts = array();
|
1198 |
+
|
1199 |
+
$format = !$this->startDate->isStartOfDay() || $this->endDate && !$this->endDate->isStartOfDay()
|
1200 |
+
? 'Y-m-d H:i:s'
|
1201 |
+
: 'Y-m-d';
|
1202 |
+
|
1203 |
+
if ($this->recurrences !== null) {
|
1204 |
+
$parts[] = $translator->transChoice('period_recurrences', $this->recurrences, array(':count' => $this->recurrences));
|
1205 |
+
}
|
1206 |
+
|
1207 |
+
$parts[] = $translator->trans('period_interval', array(':interval' => $this->dateInterval->forHumans()));
|
1208 |
+
|
1209 |
+
$parts[] = $translator->trans('period_start_date', array(':date' => $this->startDate->format($format)));
|
1210 |
+
|
1211 |
+
if ($this->endDate !== null) {
|
1212 |
+
$parts[] = $translator->trans('period_end_date', array(':date' => $this->endDate->format($format)));
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
$result = implode(' ', $parts);
|
1216 |
+
|
1217 |
+
return mb_strtoupper(mb_substr($result, 0, 1)).mb_substr($result, 1);
|
1218 |
+
}
|
1219 |
+
|
1220 |
+
/**
|
1221 |
+
* Format the date period as ISO 8601.
|
1222 |
+
*
|
1223 |
+
* @return string
|
1224 |
+
*/
|
1225 |
+
public function spec()
|
1226 |
+
{
|
1227 |
+
return $this->toIso8601String();
|
1228 |
+
}
|
1229 |
+
|
1230 |
+
/**
|
1231 |
+
* Convert the date period into an array without changing current iteration state.
|
1232 |
+
*
|
1233 |
+
* @return array
|
1234 |
+
*/
|
1235 |
+
public function toArray()
|
1236 |
+
{
|
1237 |
+
$state = array(
|
1238 |
+
$this->key,
|
1239 |
+
$this->current ? $this->current->copy() : null,
|
1240 |
+
$this->validationResult,
|
1241 |
+
);
|
1242 |
+
|
1243 |
+
$result = iterator_to_array($this);
|
1244 |
+
|
1245 |
+
list(
|
1246 |
+
$this->key,
|
1247 |
+
$this->current,
|
1248 |
+
$this->validationResult
|
1249 |
+
) = $state;
|
1250 |
+
|
1251 |
+
return $result;
|
1252 |
+
}
|
1253 |
+
|
1254 |
+
/**
|
1255 |
+
* Count dates in the date period.
|
1256 |
+
*
|
1257 |
+
* @return int
|
1258 |
+
*/
|
1259 |
+
public function count()
|
1260 |
+
{
|
1261 |
+
return count($this->toArray());
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
/**
|
1265 |
+
* Return the first date in the date period.
|
1266 |
+
*
|
1267 |
+
* @return Carbon|null
|
1268 |
+
*/
|
1269 |
+
public function first()
|
1270 |
+
{
|
1271 |
+
if ($array = $this->toArray()) {
|
1272 |
+
return $array[0];
|
1273 |
+
}
|
1274 |
+
}
|
1275 |
+
|
1276 |
+
/**
|
1277 |
+
* Return the last date in the date period.
|
1278 |
+
*
|
1279 |
+
* @return Carbon|null
|
1280 |
+
*/
|
1281 |
+
public function last()
|
1282 |
+
{
|
1283 |
+
if ($array = $this->toArray()) {
|
1284 |
+
return $array[count($array) - 1];
|
1285 |
+
}
|
1286 |
+
}
|
1287 |
+
|
1288 |
+
/**
|
1289 |
+
* Call given macro.
|
1290 |
+
*
|
1291 |
+
* @param string $name
|
1292 |
+
* @param array $parameters
|
1293 |
+
*
|
1294 |
+
* @return mixed
|
1295 |
+
*/
|
1296 |
+
protected function callMacro($name, $parameters)
|
1297 |
+
{
|
1298 |
+
$macro = static::$macros[$name];
|
1299 |
+
|
1300 |
+
$reflection = new ReflectionFunction($macro);
|
1301 |
+
|
1302 |
+
$reflectionParameters = $reflection->getParameters();
|
1303 |
+
|
1304 |
+
$expectedCount = count($reflectionParameters);
|
1305 |
+
$actualCount = count($parameters);
|
1306 |
+
|
1307 |
+
if ($expectedCount > $actualCount && $reflectionParameters[$expectedCount - 1]->name === 'self') {
|
1308 |
+
for ($i = $actualCount; $i < $expectedCount - 1; $i++) {
|
1309 |
+
$parameters[] = $reflectionParameters[$i]->getDefaultValue();
|
1310 |
+
}
|
1311 |
+
|
1312 |
+
$parameters[] = $this;
|
1313 |
+
}
|
1314 |
+
|
1315 |
+
if ($macro instanceof Closure && method_exists($macro, 'bindTo')) {
|
1316 |
+
$macro = $macro->bindTo($this, get_class($this));
|
1317 |
+
}
|
1318 |
+
|
1319 |
+
return call_user_func_array($macro, $parameters);
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
/**
|
1323 |
+
* Convert the date period into a string.
|
1324 |
+
*
|
1325 |
+
* @return string
|
1326 |
+
*/
|
1327 |
+
public function __toString()
|
1328 |
+
{
|
1329 |
+
return $this->toString();
|
1330 |
+
}
|
1331 |
+
|
1332 |
+
/**
|
1333 |
+
* Add aliases for setters.
|
1334 |
+
*
|
1335 |
+
* CarbonPeriod::days(3)->hours(5)->invert()
|
1336 |
+
* ->sinceNow()->until('2010-01-10')
|
1337 |
+
* ->filter(...)
|
1338 |
+
* ->count()
|
1339 |
+
*
|
1340 |
+
* Note: We use magic method to let static and instance aliases with the same names.
|
1341 |
+
*
|
1342 |
+
* @param string $method
|
1343 |
+
* @param array $parameters
|
1344 |
+
*
|
1345 |
+
* @return mixed
|
1346 |
+
*/
|
1347 |
+
public function __call($method, $parameters)
|
1348 |
+
{
|
1349 |
+
if (static::hasMacro($method)) {
|
1350 |
+
return $this->callMacro($method, $parameters);
|
1351 |
+
}
|
1352 |
+
|
1353 |
+
$first = count($parameters) >= 1 ? $parameters[0] : null;
|
1354 |
+
$second = count($parameters) >= 2 ? $parameters[1] : null;
|
1355 |
+
|
1356 |
+
switch ($method) {
|
1357 |
+
case 'start':
|
1358 |
+
case 'since':
|
1359 |
+
return $this->setStartDate($first, $second);
|
1360 |
+
|
1361 |
+
case 'sinceNow':
|
1362 |
+
return $this->setStartDate(new Carbon, $first);
|
1363 |
+
|
1364 |
+
case 'end':
|
1365 |
+
case 'until':
|
1366 |
+
return $this->setEndDate($first, $second);
|
1367 |
+
|
1368 |
+
case 'untilNow':
|
1369 |
+
return $this->setEndDate(new Carbon, $first);
|
1370 |
+
|
1371 |
+
case 'dates':
|
1372 |
+
case 'between':
|
1373 |
+
return $this->setDates($first, $second);
|
1374 |
+
|
1375 |
+
case 'recurrences':
|
1376 |
+
case 'times':
|
1377 |
+
return $this->setRecurrences($first);
|
1378 |
+
|
1379 |
+
case 'options':
|
1380 |
+
return $this->setOptions($first);
|
1381 |
+
|
1382 |
+
case 'toggle':
|
1383 |
+
return $this->toggleOptions($first, $second);
|
1384 |
+
|
1385 |
+
case 'filter':
|
1386 |
+
case 'push':
|
1387 |
+
return $this->addFilter($first, $second);
|
1388 |
+
|
1389 |
+
case 'prepend':
|
1390 |
+
return $this->prependFilter($first, $second);
|
1391 |
+
|
1392 |
+
case 'filters':
|
1393 |
+
return $this->setFilters($first ?: array());
|
1394 |
+
|
1395 |
+
case 'interval':
|
1396 |
+
case 'each':
|
1397 |
+
case 'every':
|
1398 |
+
case 'step':
|
1399 |
+
case 'stepBy':
|
1400 |
+
return $this->setDateInterval($first);
|
1401 |
+
|
1402 |
+
case 'invert':
|
1403 |
+
return $this->invertDateInterval();
|
1404 |
+
|
1405 |
+
case 'years':
|
1406 |
+
case 'year':
|
1407 |
+
case 'months':
|
1408 |
+
case 'month':
|
1409 |
+
case 'weeks':
|
1410 |
+
case 'week':
|
1411 |
+
case 'days':
|
1412 |
+
case 'dayz':
|
1413 |
+
case 'day':
|
1414 |
+
case 'hours':
|
1415 |
+
case 'hour':
|
1416 |
+
case 'minutes':
|
1417 |
+
case 'minute':
|
1418 |
+
case 'seconds':
|
1419 |
+
case 'second':
|
1420 |
+
return $this->setDateInterval(call_user_func(
|
1421 |
+
// Override default P1D when instantiating via fluent setters.
|
1422 |
+
array($this->isDefaultInterval ? new CarbonInterval('PT0S') : $this->dateInterval, $method),
|
1423 |
+
count($parameters) === 0 ? 1 : $first
|
1424 |
+
));
|
1425 |
+
}
|
1426 |
+
|
1427 |
+
throw new BadMethodCallException("Method $method does not exist.");
|
1428 |
+
}
|
1429 |
+
}
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/af.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time terug',
|
28 |
'from_now' => ':time van nou af',
|
29 |
'after' => ':time na',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count jaar|:count jare',
|
14 |
+
'y' => ':count jaar|:count jare',
|
15 |
+
'month' => ':count maand|:count maande',
|
16 |
+
'm' => ':count maand|:count maande',
|
17 |
+
'week' => ':count week|:count weke',
|
18 |
+
'w' => ':count week|:count weke',
|
19 |
+
'day' => ':count dag|:count dae',
|
20 |
+
'd' => ':count dag|:count dae',
|
21 |
+
'hour' => ':count uur|:count ure',
|
22 |
+
'h' => ':count uur|:count ure',
|
23 |
+
'minute' => ':count minuut|:count minute',
|
24 |
+
'min' => ':count minuut|:count minute',
|
25 |
+
'second' => ':count sekond|:count sekondes',
|
26 |
+
's' => ':count sekond|:count sekondes',
|
27 |
'ago' => ':time terug',
|
28 |
'from_now' => ':time van nou af',
|
29 |
'after' => ':time na',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/bg.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => 'преди :time',
|
28 |
'from_now' => ':time от сега',
|
29 |
'after' => 'след :time',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count година|:count години',
|
14 |
+
'y' => ':count година|:count години',
|
15 |
+
'month' => ':count месец|:count месеца',
|
16 |
+
'm' => ':count месец|:count месеца',
|
17 |
+
'week' => ':count седмица|:count седмици',
|
18 |
+
'w' => ':count седмица|:count седмици',
|
19 |
+
'day' => ':count ден|:count дни',
|
20 |
+
'd' => ':count ден|:count дни',
|
21 |
+
'hour' => ':count час|:count часа',
|
22 |
+
'h' => ':count час|:count часа',
|
23 |
+
'minute' => ':count минута|:count минути',
|
24 |
+
'min' => ':count минута|:count минути',
|
25 |
+
'second' => ':count секунда|:count секунди',
|
26 |
+
's' => ':count секунда|:count секунди',
|
27 |
'ago' => 'преди :time',
|
28 |
'from_now' => ':time от сега',
|
29 |
'after' => 'след :time',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/bs_BA.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of the Carbon package.
|
5 |
+
*
|
6 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
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 |
+
return array(
|
13 |
+
'year' => ':count godina|:count godine|:count godina',
|
14 |
+
'y' => ':count godina|:count godine|:count godina',
|
15 |
+
'month' => ':count mjesec|:count mjeseca|:count mjeseci',
|
16 |
+
'm' => ':count mjesec|:count mjeseca|:count mjeseci',
|
17 |
+
'week' => ':count nedjelja|:count nedjelje|:count nedjelja',
|
18 |
+
'w' => ':count nedjelja|:count nedjelje|:count nedjelja',
|
19 |
+
'day' => ':count dan|:count dana|:count dana',
|
20 |
+
'd' => ':count dan|:count dana|:count dana',
|
21 |
+
'hour' => ':count sat|:count sata|:count sati',
|
22 |
+
'h' => ':count sat|:count sata|:count sati',
|
23 |
+
'minute' => ':count minut|:count minuta|:count minuta',
|
24 |
+
'min' => ':count minut|:count minuta|:count minuta',
|
25 |
+
'second' => ':count sekund|:count sekunda|:count sekundi',
|
26 |
+
's' => ':count sekund|:count sekunda|:count sekundi',
|
27 |
+
'ago' => 'prije :time',
|
28 |
+
'from_now' => 'za :time',
|
29 |
+
'after' => 'nakon :time',
|
30 |
+
'before' => ':time ranije',
|
31 |
+
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ca.php
CHANGED
@@ -10,22 +10,27 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => 'fa :time',
|
28 |
'from_now' => 'dins de :time',
|
29 |
'after' => ':time després',
|
30 |
'before' => ':time abans',
|
|
|
|
|
|
|
|
|
|
|
31 |
);
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count any|:count anys',
|
14 |
+
'y' => ':count any|:count anys',
|
15 |
+
'month' => ':count mes|:count mesos',
|
16 |
+
'm' => ':count mes|:count mesos',
|
17 |
+
'week' => ':count setmana|:count setmanes',
|
18 |
+
'w' => ':count setmana|:count setmanes',
|
19 |
+
'day' => ':count dia|:count dies',
|
20 |
+
'd' => ':count dia|:count dies',
|
21 |
+
'hour' => ':count hora|:count hores',
|
22 |
+
'h' => ':count hora|:count hores',
|
23 |
+
'minute' => ':count minut|:count minuts',
|
24 |
+
'min' => ':count minut|:count minuts',
|
25 |
+
'second' => ':count segon|:count segons',
|
26 |
+
's' => ':count segon|:count segons',
|
27 |
'ago' => 'fa :time',
|
28 |
'from_now' => 'dins de :time',
|
29 |
'after' => ':time després',
|
30 |
'before' => ':time abans',
|
31 |
+
'diff_now' => 'ara mateix',
|
32 |
+
'diff_yesterday' => 'ahir',
|
33 |
+
'diff_tomorrow' => 'demà',
|
34 |
+
'diff_before_yesterday' => "abans d'ahir",
|
35 |
+
'diff_after_tomorrow' => 'demà passat',
|
36 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/cs.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time nazpět',
|
28 |
'from_now' => 'za :time',
|
29 |
'after' => ':time později',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count rok|:count roky|:count let',
|
14 |
+
'y' => ':count rok|:count roky|:count let',
|
15 |
+
'month' => ':count měsíc|:count měsíce|:count měsíců',
|
16 |
+
'm' => ':count měsíc|:count měsíce|:count měsíců',
|
17 |
+
'week' => ':count týden|:count týdny|:count týdnů',
|
18 |
+
'w' => ':count týden|:count týdny|:count týdnů',
|
19 |
+
'day' => ':count den|:count dny|:count dní',
|
20 |
+
'd' => ':count den|:count dny|:count dní',
|
21 |
+
'hour' => ':count hodinu|:count hodiny|:count hodin',
|
22 |
+
'h' => ':count hodinu|:count hodiny|:count hodin',
|
23 |
+
'minute' => ':count minutu|:count minuty|:count minut',
|
24 |
+
'min' => ':count minutu|:count minuty|:count minut',
|
25 |
+
'second' => ':count sekundu|:count sekundy|:count sekund',
|
26 |
+
's' => ':count sekundu|:count sekundy|:count sekund',
|
27 |
'ago' => ':time nazpět',
|
28 |
'from_now' => 'za :time',
|
29 |
'after' => ':time později',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/cy.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* This file is part of the Carbon package.
|
4 |
+
*
|
5 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
6 |
+
*
|
7 |
+
* For the full copyright and license information, please view the LICENSE
|
8 |
+
* file that was distributed with this source code.
|
9 |
+
*/
|
10 |
+
return array(
|
11 |
+
'year' => '1 flwyddyn|:count blynedd',
|
12 |
+
'y' => ':countbl',
|
13 |
+
'month' => '1 mis|:count fis',
|
14 |
+
'm' => ':countmi',
|
15 |
+
'week' => ':count wythnos',
|
16 |
+
'w' => ':countw',
|
17 |
+
'day' => ':count diwrnod',
|
18 |
+
'd' => ':countd',
|
19 |
+
'hour' => ':count awr',
|
20 |
+
'h' => ':counth',
|
21 |
+
'minute' => ':count munud',
|
22 |
+
'min' => ':countm',
|
23 |
+
'second' => ':count eiliad',
|
24 |
+
's' => ':counts',
|
25 |
+
'ago' => ':time yn ôl',
|
26 |
+
'from_now' => ':time o hyn ymlaen',
|
27 |
+
'after' => ':time ar ôl',
|
28 |
+
'before' => ':time o\'r blaen',
|
29 |
+
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/da.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time siden',
|
28 |
'from_now' => 'om :time',
|
29 |
'after' => ':time efter',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count år|:count år',
|
14 |
+
'y' => ':count år|:count år',
|
15 |
+
'month' => ':count måned|:count måneder',
|
16 |
+
'm' => ':count måned|:count måneder',
|
17 |
+
'week' => ':count uge|:count uger',
|
18 |
+
'w' => ':count uge|:count uger',
|
19 |
+
'day' => ':count dag|:count dage',
|
20 |
+
'd' => ':count dag|:count dage',
|
21 |
+
'hour' => ':count time|:count timer',
|
22 |
+
'h' => ':count time|:count timer',
|
23 |
+
'minute' => ':count minut|:count minutter',
|
24 |
+
'min' => ':count minut|:count minutter',
|
25 |
+
'second' => ':count sekund|:count sekunder',
|
26 |
+
's' => ':count sekund|:count sekunder',
|
27 |
'ago' => ':time siden',
|
28 |
'from_now' => 'om :time',
|
29 |
'after' => ':time efter',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/de.php
CHANGED
@@ -10,31 +10,37 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => 'vor :time',
|
28 |
'from_now' => 'in :time',
|
29 |
'after' => ':time später',
|
30 |
'before' => ':time zuvor',
|
31 |
|
32 |
-
'year_from_now' => '
|
33 |
-
'month_from_now' => '
|
34 |
-
'week_from_now' => '
|
35 |
-
'day_from_now' => '
|
36 |
-
'year_ago' => '
|
37 |
-
'month_ago' => '
|
38 |
-
'week_ago' => '
|
39 |
-
'day_ago' => '
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
);
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count Jahr|:count Jahre',
|
14 |
+
'y' => ':countJ|:countJ',
|
15 |
+
'month' => ':count Monat|:count Monate',
|
16 |
+
'm' => ':countMon|:countMon',
|
17 |
+
'week' => ':count Woche|:count Wochen',
|
18 |
+
'w' => ':countWo|:countWo',
|
19 |
+
'day' => ':count Tag|:count Tage',
|
20 |
+
'd' => ':countTg|:countTg',
|
21 |
+
'hour' => ':count Stunde|:count Stunden',
|
22 |
+
'h' => ':countStd|:countStd',
|
23 |
+
'minute' => ':count Minute|:count Minuten',
|
24 |
+
'min' => ':countMin|:countMin',
|
25 |
+
'second' => ':count Sekunde|:count Sekunden',
|
26 |
+
's' => ':countSek|:countSek',
|
27 |
'ago' => 'vor :time',
|
28 |
'from_now' => 'in :time',
|
29 |
'after' => ':time später',
|
30 |
'before' => ':time zuvor',
|
31 |
|
32 |
+
'year_from_now' => ':count Jahr|:count Jahren',
|
33 |
+
'month_from_now' => ':count Monat|:count Monaten',
|
34 |
+
'week_from_now' => ':count Woche|:count Wochen',
|
35 |
+
'day_from_now' => ':count Tag|:count Tagen',
|
36 |
+
'year_ago' => ':count Jahr|:count Jahren',
|
37 |
+
'month_ago' => ':count Monat|:count Monaten',
|
38 |
+
'week_ago' => ':count Woche|:count Wochen',
|
39 |
+
'day_ago' => ':count Tag|:count Tagen',
|
40 |
+
|
41 |
+
'diff_now' => 'Gerade eben',
|
42 |
+
'diff_yesterday' => 'Gestern',
|
43 |
+
'diff_tomorrow' => 'Heute',
|
44 |
+
'diff_before_yesterday' => 'Vorgestern',
|
45 |
+
'diff_after_tomorrow' => 'Übermorgen',
|
46 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/el.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => 'πριν από :time',
|
28 |
'from_now' => 'σε :time από τώρα',
|
29 |
'after' => ':time μετά',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count χρόνος|:count χρόνια',
|
14 |
+
'y' => ':count χρόνος|:count χρόνια',
|
15 |
+
'month' => ':count μήνας|:count μήνες',
|
16 |
+
'm' => ':count μήνας|:count μήνες',
|
17 |
+
'week' => ':count εβδομάδα|:count εβδομάδες',
|
18 |
+
'w' => ':count εβδομάδα|:count εβδομάδες',
|
19 |
+
'day' => ':count μέρα|:count μέρες',
|
20 |
+
'd' => ':count μέρα|:count μέρες',
|
21 |
+
'hour' => ':count ώρα|:count ώρες',
|
22 |
+
'h' => ':count ώρα|:count ώρες',
|
23 |
+
'minute' => ':count λεπτό|:count λεπτά',
|
24 |
+
'min' => ':count λεπτό|:count λεπτά',
|
25 |
+
'second' => ':count δευτερόλεπτο|:count δευτερόλεπτα',
|
26 |
+
's' => ':count δευτερόλεπτο|:count δευτερόλεπτα',
|
27 |
'ago' => 'πριν από :time',
|
28 |
'from_now' => 'σε :time από τώρα',
|
29 |
'after' => ':time μετά',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/en.php
CHANGED
@@ -10,22 +10,31 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time ago',
|
28 |
'from_now' => ':time from now',
|
29 |
'after' => ':time after',
|
30 |
'before' => ':time before',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
);
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count year|:count years',
|
14 |
+
'y' => ':countyr|:countyrs',
|
15 |
+
'month' => ':count month|:count months',
|
16 |
+
'm' => ':countmo|:countmos',
|
17 |
+
'week' => ':count week|:count weeks',
|
18 |
+
'w' => ':countw|:countw',
|
19 |
+
'day' => ':count day|:count days',
|
20 |
+
'd' => ':countd|:countd',
|
21 |
+
'hour' => ':count hour|:count hours',
|
22 |
+
'h' => ':counth|:counth',
|
23 |
+
'minute' => ':count minute|:count minutes',
|
24 |
+
'min' => ':countm|:countm',
|
25 |
+
'second' => ':count second|:count seconds',
|
26 |
+
's' => ':counts|:counts',
|
27 |
'ago' => ':time ago',
|
28 |
'from_now' => ':time from now',
|
29 |
'after' => ':time after',
|
30 |
'before' => ':time before',
|
31 |
+
'diff_now' => 'just now',
|
32 |
+
'diff_yesterday' => 'yesterday',
|
33 |
+
'diff_tomorrow' => 'tomorrow',
|
34 |
+
'diff_before_yesterday' => 'before yesterday',
|
35 |
+
'diff_after_tomorrow' => 'after tomorrow',
|
36 |
+
'period_recurrences' => 'once|:count times',
|
37 |
+
'period_interval' => 'every :interval',
|
38 |
+
'period_start_date' => 'from :date',
|
39 |
+
'period_end_date' => 'to :date',
|
40 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/eo.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => 'antaŭ :time',
|
28 |
'from_now' => 'je :time',
|
29 |
'after' => ':time poste',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count jaro|:count jaroj',
|
14 |
+
'y' => ':count jaro|:count jaroj',
|
15 |
+
'month' => ':count monato|:count monatoj',
|
16 |
+
'm' => ':count monato|:count monatoj',
|
17 |
+
'week' => ':count semajno|:count semajnoj',
|
18 |
+
'w' => ':count semajno|:count semajnoj',
|
19 |
+
'day' => ':count tago|:count tagoj',
|
20 |
+
'd' => ':count tago|:count tagoj',
|
21 |
+
'hour' => ':count horo|:count horoj',
|
22 |
+
'h' => ':count horo|:count horoj',
|
23 |
+
'minute' => ':count minuto|:count minutoj',
|
24 |
+
'min' => ':count minuto|:count minutoj',
|
25 |
+
'second' => ':count sekundo|:count sekundoj',
|
26 |
+
's' => ':count sekundo|:count sekundoj',
|
27 |
'ago' => 'antaŭ :time',
|
28 |
'from_now' => 'je :time',
|
29 |
'after' => ':time poste',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/es.php
CHANGED
@@ -10,22 +10,27 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => 'hace :time',
|
28 |
'from_now' => 'dentro de :time',
|
29 |
'after' => ':time después',
|
30 |
'before' => ':time antes',
|
|
|
|
|
|
|
|
|
|
|
31 |
);
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count año|:count años',
|
14 |
+
'y' => ':count año|:count años',
|
15 |
+
'month' => ':count mes|:count meses',
|
16 |
+
'm' => ':count mes|:count meses',
|
17 |
+
'week' => ':count semana|:count semanas',
|
18 |
+
'w' => ':count semana|:count semanas',
|
19 |
+
'day' => ':count día|:count días',
|
20 |
+
'd' => ':count día|:count días',
|
21 |
+
'hour' => ':count hora|:count horas',
|
22 |
+
'h' => ':count hora|:count horas',
|
23 |
+
'minute' => ':count minuto|:count minutos',
|
24 |
+
'min' => ':count minuto|:count minutos',
|
25 |
+
'second' => ':count segundo|:count segundos',
|
26 |
+
's' => ':count segundo|:count segundos',
|
27 |
'ago' => 'hace :time',
|
28 |
'from_now' => 'dentro de :time',
|
29 |
'after' => ':time después',
|
30 |
'before' => ':time antes',
|
31 |
+
'diff_now' => 'ahora mismo',
|
32 |
+
'diff_yesterday' => 'ayer',
|
33 |
+
'diff_tomorrow' => 'mañana',
|
34 |
+
'diff_before_yesterday' => 'anteayer',
|
35 |
+
'diff_after_tomorrow' => 'pasado mañana',
|
36 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/et.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time tagasi',
|
28 |
'from_now' => ':time pärast',
|
29 |
'after' => ':time pärast',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count aasta|:count aastat',
|
14 |
+
'y' => ':count aasta|:count aastat',
|
15 |
+
'month' => ':count kuu|:count kuud',
|
16 |
+
'm' => ':count kuu|:count kuud',
|
17 |
+
'week' => ':count nädal|:count nädalat',
|
18 |
+
'w' => ':count nädal|:count nädalat',
|
19 |
+
'day' => ':count päev|:count päeva',
|
20 |
+
'd' => ':count päev|:count päeva',
|
21 |
+
'hour' => ':count tund|:count tundi',
|
22 |
+
'h' => ':count tund|:count tundi',
|
23 |
+
'minute' => ':count minut|:count minutit',
|
24 |
+
'min' => ':count minut|:count minutit',
|
25 |
+
'second' => ':count sekund|:count sekundit',
|
26 |
+
's' => ':count sekund|:count sekundit',
|
27 |
'ago' => ':time tagasi',
|
28 |
'from_now' => ':time pärast',
|
29 |
'after' => ':time pärast',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/fi.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time sitten',
|
28 |
'from_now' => ':time tästä hetkestä',
|
29 |
'after' => ':time sen jälkeen',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count vuosi|:count vuotta',
|
14 |
+
'y' => ':count vuosi|:count vuotta',
|
15 |
+
'month' => ':count kuukausi|:count kuukautta',
|
16 |
+
'm' => ':count kuukausi|:count kuukautta',
|
17 |
+
'week' => ':count viikko|:count viikkoa',
|
18 |
+
'w' => ':count viikko|:count viikkoa',
|
19 |
+
'day' => ':count päivä|:count päivää',
|
20 |
+
'd' => ':count päivä|:count päivää',
|
21 |
+
'hour' => ':count tunti|:count tuntia',
|
22 |
+
'h' => ':count tunti|:count tuntia',
|
23 |
+
'minute' => ':count minuutti|:count minuuttia',
|
24 |
+
'min' => ':count minuutti|:count minuuttia',
|
25 |
+
'second' => ':count sekunti|:count sekuntia',
|
26 |
+
's' => ':count sekunti|:count sekuntia',
|
27 |
'ago' => ':time sitten',
|
28 |
'from_now' => ':time tästä hetkestä',
|
29 |
'after' => ':time sen jälkeen',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/fo.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time síðan',
|
28 |
'from_now' => 'um :time',
|
29 |
'after' => ':time aftaná',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count ár|:count ár',
|
14 |
+
'y' => ':count ár|:count ár',
|
15 |
+
'month' => ':count mánaður|:count mánaðir',
|
16 |
+
'm' => ':count mánaður|:count mánaðir',
|
17 |
+
'week' => ':count vika|:count vikur',
|
18 |
+
'w' => ':count vika|:count vikur',
|
19 |
+
'day' => ':count dag|:count dagar',
|
20 |
+
'd' => ':count dag|:count dagar',
|
21 |
+
'hour' => ':count tími|:count tímar',
|
22 |
+
'h' => ':count tími|:count tímar',
|
23 |
+
'minute' => ':count minutt|:count minuttir',
|
24 |
+
'min' => ':count minutt|:count minuttir',
|
25 |
+
'second' => ':count sekund|:count sekundir',
|
26 |
+
's' => ':count sekund|:count sekundir',
|
27 |
'ago' => ':time síðan',
|
28 |
'from_now' => 'um :time',
|
29 |
'after' => ':time aftaná',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/fr.php
CHANGED
@@ -10,22 +10,27 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
'month' => ':count mois',
|
16 |
'm' => ':count mois',
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => 'il y a :time',
|
28 |
'from_now' => 'dans :time',
|
29 |
'after' => ':time après',
|
30 |
'before' => ':time avant',
|
|
|
|
|
|
|
|
|
|
|
31 |
);
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count an|:count ans',
|
14 |
+
'y' => ':count an|:count ans',
|
15 |
'month' => ':count mois',
|
16 |
'm' => ':count mois',
|
17 |
+
'week' => ':count semaine|:count semaines',
|
18 |
+
'w' => ':count sem.',
|
19 |
+
'day' => ':count jour|:count jours',
|
20 |
+
'd' => ':count j.',
|
21 |
+
'hour' => ':count heure|:count heures',
|
22 |
+
'h' => ':count h.',
|
23 |
+
'minute' => ':count minute|:count minutes',
|
24 |
+
'min' => ':count min.',
|
25 |
+
'second' => ':count seconde|:count secondes',
|
26 |
+
's' => ':count sec.',
|
27 |
'ago' => 'il y a :time',
|
28 |
'from_now' => 'dans :time',
|
29 |
'after' => ':time après',
|
30 |
'before' => ':time avant',
|
31 |
+
'diff_now' => "à l'instant",
|
32 |
+
'diff_yesterday' => 'hier',
|
33 |
+
'diff_tomorrow' => 'demain',
|
34 |
+
'diff_before_yesterday' => 'avant-hier',
|
35 |
+
'diff_after_tomorrow' => 'après-demain',
|
36 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/gl.php
CHANGED
@@ -10,13 +10,13 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'month' => '
|
15 |
-
'week' => '
|
16 |
-
'day' => '
|
17 |
-
'hour' => '
|
18 |
-
'minute' => '
|
19 |
-
'second' => '
|
20 |
'ago' => 'fai :time',
|
21 |
'from_now' => 'dentro de :time',
|
22 |
'after' => ':time despois',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count ano|:count anos',
|
14 |
+
'month' => ':count mes|:count meses',
|
15 |
+
'week' => ':count semana|:count semanas',
|
16 |
+
'day' => ':count día|:count días',
|
17 |
+
'hour' => ':count hora|:count horas',
|
18 |
+
'minute' => ':count minuto|:count minutos',
|
19 |
+
'second' => ':count segundo|:count segundos',
|
20 |
'ago' => 'fai :time',
|
21 |
'from_now' => 'dentro de :time',
|
22 |
'after' => ':time despois',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/gu.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time પહેલા',
|
28 |
'from_now' => ':time અત્યારથી',
|
29 |
'after' => ':time પછી',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count વર્ષ|:count વર્ષો',
|
14 |
+
'y' => ':countવર્ષ|:countવર્ષો',
|
15 |
+
'month' => ':count મહિનો|:count મહિના',
|
16 |
+
'm' => ':countમહિનો|:countમહિના',
|
17 |
+
'week' => ':count અઠવાડિયું|:count અઠવાડિયા',
|
18 |
+
'w' => ':countઅઠ.|:countઅઠ.',
|
19 |
+
'day' => ':count દિવસ|:count દિવસો',
|
20 |
+
'd' => ':countદિ.|:countદિ.',
|
21 |
+
'hour' => ':count કલાક|:count કલાકો',
|
22 |
+
'h' => ':countક.|:countક.',
|
23 |
+
'minute' => ':count મિનિટ|:count મિનિટ',
|
24 |
+
'min' => ':countમિ.|:countમિ.',
|
25 |
+
'second' => ':count સેકેન્ડ|:count સેકેન્ડ',
|
26 |
+
's' => ':countસે.|:countસે.',
|
27 |
'ago' => ':time પહેલા',
|
28 |
'from_now' => ':time અત્યારથી',
|
29 |
'after' => ':time પછી',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/hi.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of the Carbon package.
|
5 |
+
*
|
6 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
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 |
+
return array(
|
13 |
+
'year' => '1 वर्ष|:count वर्षों',
|
14 |
+
'y' => '1 वर्ष|:count वर्षों',
|
15 |
+
'month' => '1 माह|:count महीने',
|
16 |
+
'm' => '1 माह|:count महीने',
|
17 |
+
'week' => '1 सप्ताह|:count सप्ताह',
|
18 |
+
'w' => '1 सप्ताह|:count सप्ताह',
|
19 |
+
'day' => '1 दिन|:count दिनों',
|
20 |
+
'd' => '1 दिन|:count दिनों',
|
21 |
+
'hour' => '1 घंटा|:count घंटे',
|
22 |
+
'h' => '1 घंटा|:count घंटे',
|
23 |
+
'minute' => '1 मिनट|:count मिनटों',
|
24 |
+
'min' => '1 मिनट|:count मिनटों',
|
25 |
+
'second' => '1 सेकंड|:count सेकंड',
|
26 |
+
's' => '1 सेकंड|:count सेकंड',
|
27 |
+
'ago' => ':time पूर्व',
|
28 |
+
'from_now' => ':time से',
|
29 |
+
'after' => ':time के बाद',
|
30 |
+
'before' => ':time के पहले',
|
31 |
+
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/is.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of the Carbon package.
|
5 |
+
*
|
6 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
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 |
+
return array(
|
13 |
+
'year' => '1 ár|:count ár',
|
14 |
+
'y' => '1 ár|:count ár',
|
15 |
+
'month' => '1 mánuður|:count mánuðir',
|
16 |
+
'm' => '1 mánuður|:count mánuðir',
|
17 |
+
'week' => '1 vika|:count vikur',
|
18 |
+
'w' => '1 vika|:count vikur',
|
19 |
+
'day' => '1 dagur|:count dagar',
|
20 |
+
'd' => '1 dagur|:count dagar',
|
21 |
+
'hour' => '1 klukkutími|:count klukkutímar',
|
22 |
+
'h' => '1 klukkutími|:count klukkutímar',
|
23 |
+
'minute' => '1 mínúta|:count mínútur',
|
24 |
+
'min' => '1 mínúta|:count mínútur',
|
25 |
+
'second' => '1 sekúnda|:count sekúndur',
|
26 |
+
's' => '1 sekúnda|:count sekúndur',
|
27 |
+
'ago' => ':time síðan',
|
28 |
+
'from_now' => ':time síðan',
|
29 |
+
'after' => ':time eftir',
|
30 |
+
'before' => ':time fyrir',
|
31 |
+
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/it.php
CHANGED
@@ -10,22 +10,27 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time fa',
|
28 |
-
'from_now' => ':time
|
29 |
'after' => ':time dopo',
|
30 |
'before' => ':time prima',
|
|
|
|
|
|
|
|
|
|
|
31 |
);
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count anno|:count anni',
|
14 |
+
'y' => ':count anno|:count anni',
|
15 |
+
'month' => ':count mese|:count mesi',
|
16 |
+
'm' => ':count mese|:count mesi',
|
17 |
+
'week' => ':count settimana|:count settimane',
|
18 |
+
'w' => ':count settimana|:count settimane',
|
19 |
+
'day' => ':count giorno|:count giorni',
|
20 |
+
'd' => ':count giorno|:count giorni',
|
21 |
+
'hour' => ':count ora|:count ore',
|
22 |
+
'h' => ':count ora|:count ore',
|
23 |
+
'minute' => ':count minuto|:count minuti',
|
24 |
+
'min' => ':count minuto|:count minuti',
|
25 |
+
'second' => ':count secondo|:count secondi',
|
26 |
+
's' => ':count secondo|:count secondi',
|
27 |
'ago' => ':time fa',
|
28 |
+
'from_now' => 'tra :time',
|
29 |
'after' => ':time dopo',
|
30 |
'before' => ':time prima',
|
31 |
+
'diff_now' => 'proprio ora',
|
32 |
+
'diff_yesterday' => 'ieri',
|
33 |
+
'diff_tomorrow' => 'domani',
|
34 |
+
'diff_before_yesterday' => "l'altro ieri",
|
35 |
+
'diff_after_tomorrow' => 'dopodomani',
|
36 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ko.php
CHANGED
@@ -26,6 +26,6 @@ return array(
|
|
26 |
's' => ':count 초',
|
27 |
'ago' => ':time 전',
|
28 |
'from_now' => ':time 후',
|
29 |
-
'after' => ':time
|
30 |
-
'before' => ':time
|
31 |
);
|
26 |
's' => ':count 초',
|
27 |
'ago' => ':time 전',
|
28 |
'from_now' => ':time 후',
|
29 |
+
'after' => ':time 이후',
|
30 |
+
'before' => ':time 이전',
|
31 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/mk.php
CHANGED
@@ -10,13 +10,13 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'month' => '
|
15 |
-
'week' => '
|
16 |
-
'day' => '
|
17 |
-
'hour' => '
|
18 |
-
'minute' => '
|
19 |
-
'second' => '
|
20 |
'ago' => 'пред :time',
|
21 |
'from_now' => ':time од сега',
|
22 |
'after' => 'по :time',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count година|:count години',
|
14 |
+
'month' => ':count месец|:count месеци',
|
15 |
+
'week' => ':count седмица|:count седмици',
|
16 |
+
'day' => ':count ден|:count дена',
|
17 |
+
'hour' => ':count час|:count часа',
|
18 |
+
'minute' => ':count минута|:count минути',
|
19 |
+
'second' => ':count секунда|:count секунди',
|
20 |
'ago' => 'пред :time',
|
21 |
'from_now' => ':time од сега',
|
22 |
'after' => 'по :time',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ne.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of the Carbon package.
|
5 |
+
*
|
6 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
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 |
+
return array(
|
13 |
+
'year' => ':count वर्ष',
|
14 |
+
'y' => ':count वर्ष',
|
15 |
+
'month' => ':count महिना',
|
16 |
+
'm' => ':count महिना',
|
17 |
+
'week' => ':count हप्ता',
|
18 |
+
'w' => ':count हप्ता',
|
19 |
+
'day' => ':count दिन',
|
20 |
+
'd' => ':count दिन',
|
21 |
+
'hour' => ':count घण्टा',
|
22 |
+
'h' => ':count घण्टा',
|
23 |
+
'minute' => ':count मिनेट',
|
24 |
+
'min' => ':count मिनेट',
|
25 |
+
'second' => ':count सेकेण्ड',
|
26 |
+
's' => ':count सेकेण्ड',
|
27 |
+
'ago' => ':time पहिले',
|
28 |
+
'from_now' => ':time देखि',
|
29 |
+
'after' => ':time पछि',
|
30 |
+
'before' => ':time अघि',
|
31 |
+
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/nl.php
CHANGED
@@ -12,20 +12,25 @@
|
|
12 |
return array(
|
13 |
'year' => ':count jaar',
|
14 |
'y' => ':count jaar',
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
'hour' => ':count uur',
|
22 |
'h' => ':count uur',
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time geleden',
|
28 |
'from_now' => 'over :time',
|
29 |
'after' => ':time later',
|
30 |
'before' => ':time eerder',
|
|
|
|
|
|
|
|
|
|
|
31 |
);
|
12 |
return array(
|
13 |
'year' => ':count jaar',
|
14 |
'y' => ':count jaar',
|
15 |
+
'month' => ':count maand|:count maanden',
|
16 |
+
'm' => ':count maand|:count maanden',
|
17 |
+
'week' => ':count week|:count weken',
|
18 |
+
'w' => ':count week|:count weken',
|
19 |
+
'day' => ':count dag|:count dagen',
|
20 |
+
'd' => ':count dag|:count dagen',
|
21 |
'hour' => ':count uur',
|
22 |
'h' => ':count uur',
|
23 |
+
'minute' => ':count minuut|:count minuten',
|
24 |
+
'min' => ':count minuut|:count minuten',
|
25 |
+
'second' => ':count seconde|:count seconden',
|
26 |
+
's' => ':count seconde|:count seconden',
|
27 |
'ago' => ':time geleden',
|
28 |
'from_now' => 'over :time',
|
29 |
'after' => ':time later',
|
30 |
'before' => ':time eerder',
|
31 |
+
'diff_now' => 'nu',
|
32 |
+
'diff_yesterday' => 'gisteren',
|
33 |
+
'diff_tomorrow' => 'morgen',
|
34 |
+
'diff_after_tomorrow' => 'overmorgen',
|
35 |
+
'diff_before_yesterday' => 'eergisteren',
|
36 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/no.php
CHANGED
@@ -10,22 +10,27 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time siden',
|
28 |
'from_now' => 'om :time',
|
29 |
'after' => ':time etter',
|
30 |
'before' => ':time før',
|
|
|
|
|
|
|
|
|
|
|
31 |
);
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count år|:count år',
|
14 |
+
'y' => ':count år|:count år',
|
15 |
+
'month' => ':count måned|:count måneder',
|
16 |
+
'm' => ':count måned|:count måneder',
|
17 |
+
'week' => ':count uke|:count uker',
|
18 |
+
'w' => ':count uke|:count uker',
|
19 |
+
'day' => ':count dag|:count dager',
|
20 |
+
'd' => ':count dag|:count dager',
|
21 |
+
'hour' => ':count time|:count timer',
|
22 |
+
'h' => ':count time|:count timer',
|
23 |
+
'minute' => ':count minutt|:count minutter',
|
24 |
+
'min' => ':count minutt|:count minutter',
|
25 |
+
'second' => ':count sekund|:count sekunder',
|
26 |
+
's' => ':count sekund|:count sekunder',
|
27 |
'ago' => ':time siden',
|
28 |
'from_now' => 'om :time',
|
29 |
'after' => ':time etter',
|
30 |
'before' => ':time før',
|
31 |
+
'diff_now' => 'akkurat nå',
|
32 |
+
'diff_yesterday' => 'i går',
|
33 |
+
'diff_tomorrow' => 'i morgen',
|
34 |
+
'diff_before_yesterday' => 'i forgårs',
|
35 |
+
'diff_after_tomorrow' => 'i overmorgen',
|
36 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/oc.php
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of the Carbon package.
|
5 |
+
*
|
6 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
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 |
+
\Symfony\Component\Translation\PluralizationRules::set(function ($number) {
|
13 |
+
return $number == 1 ? 0 : 1;
|
14 |
+
}, 'oc');
|
15 |
+
|
16 |
+
return array(
|
17 |
+
'year' => ':count an|:count ans',
|
18 |
+
'y' => ':count an|:count ans',
|
19 |
+
'month' => ':count mes|:count meses',
|
20 |
+
'm' => ':count mes|:count meses',
|
21 |
+
'week' => ':count setmana|:count setmanas',
|
22 |
+
'w' => ':count setmana|:count setmanas',
|
23 |
+
'day' => ':count jorn|:count jorns',
|
24 |
+
'd' => ':count jorn|:count jorns',
|
25 |
+
'hour' => ':count ora|:count oras',
|
26 |
+
'h' => ':count ora|:count oras',
|
27 |
+
'minute' => ':count minuta|:count minutas',
|
28 |
+
'min' => ':count minuta|:count minutas',
|
29 |
+
'second' => ':count segonda|:count segondas',
|
30 |
+
's' => ':count segonda|:count segondas',
|
31 |
+
'ago' => 'fa :time',
|
32 |
+
'from_now' => 'dins :time',
|
33 |
+
'after' => ':time aprèp',
|
34 |
+
'before' => ':time abans',
|
35 |
+
'diff_now' => 'ara meteis',
|
36 |
+
'diff_yesterday' => 'ièr',
|
37 |
+
'diff_tomorrow' => 'deman',
|
38 |
+
'diff_before_yesterday' => 'ièr delà',
|
39 |
+
'diff_after_tomorrow' => 'deman passat',
|
40 |
+
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/pl.php
CHANGED
@@ -10,22 +10,27 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time temu',
|
28 |
'from_now' => ':time od teraz',
|
29 |
'after' => ':time po',
|
30 |
'before' => ':time przed',
|
|
|
|
|
|
|
|
|
|
|
31 |
);
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count rok|:count lata|:count lat',
|
14 |
+
'y' => ':countr|:countl',
|
15 |
+
'month' => ':count miesiąc|:count miesiące|:count miesięcy',
|
16 |
+
'm' => ':countmies',
|
17 |
+
'week' => ':count tydzień|:count tygodnie|:count tygodni',
|
18 |
+
'w' => ':counttyg',
|
19 |
+
'day' => ':count dzień|:count dni|:count dni',
|
20 |
+
'd' => ':countd',
|
21 |
+
'hour' => ':count godzina|:count godziny|:count godzin',
|
22 |
+
'h' => ':countg',
|
23 |
+
'minute' => ':count minuta|:count minuty|:count minut',
|
24 |
+
'min' => ':countm',
|
25 |
+
'second' => ':count sekunda|:count sekundy|:count sekund',
|
26 |
+
's' => ':counts',
|
27 |
'ago' => ':time temu',
|
28 |
'from_now' => ':time od teraz',
|
29 |
'after' => ':time po',
|
30 |
'before' => ':time przed',
|
31 |
+
'diff_now' => 'przed chwilą',
|
32 |
+
'diff_yesterday' => 'wczoraj',
|
33 |
+
'diff_tomorrow' => 'jutro',
|
34 |
+
'diff_before_yesterday' => 'przedwczoraj',
|
35 |
+
'diff_after_tomorrow' => 'pojutrze',
|
36 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ps.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time دمخه',
|
28 |
'from_now' => ':time له اوس څخه',
|
29 |
'after' => ':time وروسته',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count کال|:count کاله',
|
14 |
+
'y' => ':countکال|:countکاله',
|
15 |
+
'month' => ':count مياشت|:count مياشتي',
|
16 |
+
'm' => ':countمياشت|:countمياشتي',
|
17 |
+
'week' => ':count اونۍ|:count اونۍ',
|
18 |
+
'w' => ':countاونۍ|:countاونۍ',
|
19 |
+
'day' => ':count ورځ|:count ورځي',
|
20 |
+
'd' => ':countورځ|:countورځي',
|
21 |
+
'hour' => ':count ساعت|:count ساعته',
|
22 |
+
'h' => ':countساعت|:countساعته',
|
23 |
+
'minute' => ':count دقيقه|:count دقيقې',
|
24 |
+
'min' => ':countدقيقه|:countدقيقې',
|
25 |
+
'second' => ':count ثانيه|:count ثانيې',
|
26 |
+
's' => ':countثانيه|:countثانيې',
|
27 |
'ago' => ':time دمخه',
|
28 |
'from_now' => ':time له اوس څخه',
|
29 |
'after' => ':time وروسته',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/pt.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time atrás',
|
28 |
'from_now' => 'em :time',
|
29 |
'after' => ':time depois',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count ano|:count anos',
|
14 |
+
'y' => ':count ano|:count anos',
|
15 |
+
'month' => ':count mês|:count meses',
|
16 |
+
'm' => ':count mês|:count meses',
|
17 |
+
'week' => ':count semana|:count semanas',
|
18 |
+
'w' => ':count semana|:count semanas',
|
19 |
+
'day' => ':count dia|:count dias',
|
20 |
+
'd' => ':count dia|:count dias',
|
21 |
+
'hour' => ':count hora|:count horas',
|
22 |
+
'h' => ':count hora|:count horas',
|
23 |
+
'minute' => ':count minuto|:count minutos',
|
24 |
+
'min' => ':count minuto|:count minutos',
|
25 |
+
'second' => ':count segundo|:count segundos',
|
26 |
+
's' => ':count segundo|:count segundos',
|
27 |
'ago' => ':time atrás',
|
28 |
'from_now' => 'em :time',
|
29 |
'after' => ':time depois',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/pt_BR.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => 'há :time',
|
28 |
'from_now' => 'em :time',
|
29 |
'after' => 'após :time',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count ano|:count anos',
|
14 |
+
'y' => ':count ano|:count anos',
|
15 |
+
'month' => ':count mês|:count meses',
|
16 |
+
'm' => ':count mês|:count meses',
|
17 |
+
'week' => ':count semana|:count semanas',
|
18 |
+
'w' => ':count semana|:count semanas',
|
19 |
+
'day' => ':count dia|:count dias',
|
20 |
+
'd' => ':count dia|:count dias',
|
21 |
+
'hour' => ':count hora|:count horas',
|
22 |
+
'h' => ':count hora|:count horas',
|
23 |
+
'minute' => ':count minuto|:count minutos',
|
24 |
+
'min' => ':count minuto|:count minutos',
|
25 |
+
'second' => ':count segundo|:count segundos',
|
26 |
+
's' => ':count segundo|:count segundos',
|
27 |
'ago' => 'há :time',
|
28 |
'from_now' => 'em :time',
|
29 |
'after' => 'após :time',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sh.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of the Carbon package.
|
5 |
+
*
|
6 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
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 |
+
return array(
|
13 |
+
'year' => ':count godina|:count godine|:count godina',
|
14 |
+
'y' => ':count godina|:count godine|:count godina',
|
15 |
+
'month' => ':count mesec|:count meseca|:count meseci',
|
16 |
+
'm' => ':count mesec|:count meseca|:count meseci',
|
17 |
+
'week' => ':count nedelja|:count nedelje|:count nedelja',
|
18 |
+
'w' => ':count nedelja|:count nedelje|:count nedelja',
|
19 |
+
'day' => ':count dan|:count dana|:count dana',
|
20 |
+
'd' => ':count dan|:count dana|:count dana',
|
21 |
+
'hour' => ':count čas|:count časa|:count časova',
|
22 |
+
'h' => ':count čas|:count časa|:count časova',
|
23 |
+
'minute' => ':count minut|:count minuta|:count minuta',
|
24 |
+
'min' => ':count minut|:count minuta|:count minuta',
|
25 |
+
'second' => ':count sekund|:count sekunda|:count sekundi',
|
26 |
+
's' => ':count sekund|:count sekunda|:count sekundi',
|
27 |
+
'ago' => 'pre :time',
|
28 |
+
'from_now' => 'za :time',
|
29 |
+
'after' => 'nakon :time',
|
30 |
+
'before' => ':time raniјe',
|
31 |
+
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sl.php
CHANGED
@@ -35,4 +35,9 @@ return array(
|
|
35 |
'from_now' => 'čez :time',
|
36 |
'after' => 'čez :time',
|
37 |
'before' => 'pred :time',
|
|
|
|
|
|
|
|
|
|
|
38 |
);
|
35 |
'from_now' => 'čez :time',
|
36 |
'after' => 'čez :time',
|
37 |
'before' => 'pred :time',
|
38 |
+
'diff_now' => 'ravnokar',
|
39 |
+
'diff_yesterday' => 'včeraj',
|
40 |
+
'diff_tomorrow' => 'jutri',
|
41 |
+
'diff_before_yesterday' => 'predvčerajšnjim',
|
42 |
+
'diff_after_tomorrow' => 'pojutrišnjem',
|
43 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sq.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time më parë',
|
28 |
'from_now' => ':time nga tani',
|
29 |
'after' => ':time pas',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count vit|:count vjet',
|
14 |
+
'y' => ':count vit|:count vjet',
|
15 |
+
'month' => ':count muaj|:count muaj',
|
16 |
+
'm' => ':count muaj|:count muaj',
|
17 |
+
'week' => ':count javë|:count javë',
|
18 |
+
'w' => ':count javë|:count javë',
|
19 |
+
'day' => ':count ditë|:count ditë',
|
20 |
+
'd' => ':count ditë|:count ditë',
|
21 |
+
'hour' => ':count orë|:count orë',
|
22 |
+
'h' => ':count orë|:count orë',
|
23 |
+
'minute' => ':count minutë|:count minuta',
|
24 |
+
'min' => ':count minutë|:count minuta',
|
25 |
+
'second' => ':count sekondë|:count sekonda',
|
26 |
+
's' => ':count sekondë|:count sekonda',
|
27 |
'ago' => ':time më parë',
|
28 |
'from_now' => ':time nga tani',
|
29 |
'after' => ':time pas',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php
CHANGED
@@ -35,4 +35,9 @@ return array(
|
|
35 |
'week_from_now' => '{1} :count недељу|{2,3,4} :count недеље|[5,Inf[ :count недеља',
|
36 |
'week_ago' => '{1} :count недељу|{2,3,4} :count недеље|[5,Inf[ :count недеља',
|
37 |
|
|
|
|
|
|
|
|
|
|
|
38 |
);
|
35 |
'week_from_now' => '{1} :count недељу|{2,3,4} :count недеље|[5,Inf[ :count недеља',
|
36 |
'week_ago' => '{1} :count недељу|{2,3,4} :count недеље|[5,Inf[ :count недеља',
|
37 |
|
38 |
+
'diff_now' => 'управо сада',
|
39 |
+
'diff_yesterday' => 'јуче',
|
40 |
+
'diff_tomorrow' => 'сутра',
|
41 |
+
'diff_before_yesterday' => 'прекјуче',
|
42 |
+
'diff_after_tomorrow' => 'прекосутра',
|
43 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php
CHANGED
@@ -35,4 +35,9 @@ return array(
|
|
35 |
'week_from_now' => '{1} :count недјељу|{2,3,4} :count недјеље|[5,Inf[ :count недјеља',
|
36 |
'week_ago' => '{1} :count недјељу|{2,3,4} :count недјеље|[5,Inf[ :count недјеља',
|
37 |
|
|
|
|
|
|
|
|
|
|
|
38 |
);
|
35 |
'week_from_now' => '{1} :count недјељу|{2,3,4} :count недјеље|[5,Inf[ :count недјеља',
|
36 |
'week_ago' => '{1} :count недјељу|{2,3,4} :count недјеље|[5,Inf[ :count недјеља',
|
37 |
|
38 |
+
'diff_now' => 'управо сада',
|
39 |
+
'diff_yesterday' => 'јуче',
|
40 |
+
'diff_tomorrow' => 'сутра',
|
41 |
+
'diff_before_yesterday' => 'прекјуче',
|
42 |
+
'diff_after_tomorrow' => 'прекосјутра',
|
43 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php
CHANGED
@@ -35,4 +35,9 @@ return array(
|
|
35 |
'week_from_now' => '{1} :count nedjelju|{2,3,4} :count nedjelje|[5,Inf[ :count nedjelja',
|
36 |
'week_ago' => '{1} :count nedjelju|{2,3,4} :count nedjelje|[5,Inf[ :count nedjelja',
|
37 |
|
|
|
|
|
|
|
|
|
|
|
38 |
);
|
35 |
'week_from_now' => '{1} :count nedjelju|{2,3,4} :count nedjelje|[5,Inf[ :count nedjelja',
|
36 |
'week_ago' => '{1} :count nedjelju|{2,3,4} :count nedjelje|[5,Inf[ :count nedjelja',
|
37 |
|
38 |
+
'diff_now' => 'upravo sada',
|
39 |
+
'diff_yesterday' => 'juče',
|
40 |
+
'diff_tomorrow' => 'sutra',
|
41 |
+
'diff_before_yesterday' => 'prekjuče',
|
42 |
+
'diff_after_tomorrow' => 'preksutra',
|
43 |
);
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sv.php
CHANGED
@@ -10,20 +10,20 @@
|
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
-
'year' => '
|
14 |
-
'y' => '
|
15 |
-
'month' => '
|
16 |
-
'm' => '
|
17 |
-
'week' => '
|
18 |
-
'w' => '
|
19 |
-
'day' => '
|
20 |
-
'd' => '
|
21 |
-
'hour' => '
|
22 |
-
'h' => '
|
23 |
-
'minute' => '
|
24 |
-
'min' => '
|
25 |
-
'second' => '
|
26 |
-
's' => '
|
27 |
'ago' => ':time sedan',
|
28 |
'from_now' => 'om :time',
|
29 |
'after' => ':time efter',
|
10 |
*/
|
11 |
|
12 |
return array(
|
13 |
+
'year' => ':count år|:count år',
|
14 |
+
'y' => ':count år|:count år',
|
15 |
+
'month' => ':count månad|:count månader',
|
16 |
+
'm' => ':count månad|:count månader',
|
17 |
+
'week' => ':count vecka|:count veckor',
|
18 |
+
'w' => ':count vecka|:count veckor',
|
19 |
+
'day' => ':count dag|:count dagar',
|
20 |
+
'd' => ':count dag|:count dagar',
|
21 |
+
'hour' => ':count timme|:count timmar',
|
22 |
+
'h' => ':count timme|:count timmar',
|
23 |
+
'minute' => ':count minut|:count minuter',
|
24 |
+
'min' => ':count minut|:count minuter',
|
25 |
+
'second' => ':count sekund|:count sekunder',
|
26 |
+
's' => ':count sekund|:count sekunder',
|
27 |
'ago' => ':time sedan',
|
28 |
'from_now' => 'om :time',
|
29 |
'after' => ':time efter',
|
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/sw.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of the Carbon package.
|
5 |
+
*
|
6 |
+
* (c) Brian Nesbitt <brian@nesbot.com>
|
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 |
+
return array(
|
13 |
+
'year' => 'mwaka 1|miaka :count',
|
14 |
+
'y' => 'mwaka 1|miaka :count',
|
15 |
+
'month' => 'mwezi 1|miezi :count',
|
16 |
+
'm' => 'mwezi 1|miezi :count',
|
17 |
+
'week' => 'wiki 1|wiki :count',
|
18 |
+
'w' => 'wiki 1|wiki :count',
|
19 |
+
'day' => 'siku 1|siku :count',
|
20 |
+
'd' => 'siku 1|siku :count',
|
21 |
+
'hour' => 'saa 1|masaa :count',
|
22 |
+
'h' => 'saa 1|masaa :count',
|
23 |
+
'minute' => 'dakika 1|dakika :count',
|
24 |
+
'min' => 'dakika 1|dakika :count',
|
25 |
+
'second' => 'sekunde 1|sekunde :count',
|
26 |
+
's' => 'sekunde 1|sekunde :count',
|
27 |
+
'ago' => ':time ziliyopita',
|
28 |
+
'from_now' => ':time kwanzia sasa',
|
29 |
+
'after' => ':time baada',
|
30 |
+
'before' => ':time kabla',
|
31 |
+
);
|
src/common/lib/vendor/nesbot/carbon/src/JsonSerializable.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
interface JsonSerializable
|
4 |
+
{
|
5 |
+
/**
|
6 |
+
* Specify data which should be serialized to JSON.
|
7 |
+
*
|
8 |
+
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
|
9 |
+
*
|
10 |
+
* @return mixed data which can be serialized by <b>json_encode</b>,
|
11 |
+
* which is a value of any type other than a resource.
|
12 |
+
*
|
13 |
+
* @since 5.4.0
|
14 |
+
*/
|
15 |
+
public function jsonSerialize();
|
16 |
+
}
|
src/common/lib/vendor/symfony/polyfill-mbstring/Mbstring.php
CHANGED
@@ -78,7 +78,7 @@ final class Mbstring
|
|
78 |
|
79 |
public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
|
80 |
{
|
81 |
-
if (is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
|
82 |
$fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
|
83 |
} else {
|
84 |
$fromEncoding = self::getEncoding($fromEncoding);
|
@@ -140,16 +140,16 @@ final class Mbstring
|
|
140 |
|
141 |
public static function mb_decode_numericentity($s, $convmap, $encoding = null)
|
142 |
{
|
143 |
-
if (null !== $s &&
|
144 |
trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.gettype($s).' given', E_USER_WARNING);
|
145 |
return null;
|
146 |
}
|
147 |
|
148 |
-
if (
|
149 |
return false;
|
150 |
}
|
151 |
|
152 |
-
if (null !== $encoding &&
|
153 |
trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.gettype($s).' given', E_USER_WARNING);
|
154 |
return ''; // Instead of null (cf. mb_encode_numericentity).
|
155 |
}
|
@@ -170,7 +170,7 @@ final class Mbstring
|
|
170 |
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
|
171 |
}
|
172 |
|
173 |
-
$cnt = floor(count($convmap) / 4) * 4;
|
174 |
|
175 |
for ($i = 0; $i < $cnt; $i += 4) {
|
176 |
// collector_decode_htmlnumericentity ignores $convmap[$i + 3]
|
@@ -197,21 +197,21 @@ final class Mbstring
|
|
197 |
|
198 |
public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
|
199 |
{
|
200 |
-
if (null !== $s &&
|
201 |
trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.gettype($s).' given', E_USER_WARNING);
|
202 |
return null;
|
203 |
}
|
204 |
|
205 |
-
if (
|
206 |
return false;
|
207 |
}
|
208 |
|
209 |
-
if (null !== $encoding &&
|
210 |
trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.gettype($s).' given', E_USER_WARNING);
|
211 |
return null; // Instead of '' (cf. mb_decode_numericentity).
|
212 |
}
|
213 |
|
214 |
-
if (null !== $is_hex &&
|
215 |
trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.gettype($s).' given', E_USER_WARNING);
|
216 |
return null;
|
217 |
}
|
@@ -234,9 +234,9 @@ final class Mbstring
|
|
234 |
|
235 |
static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
|
236 |
|
237 |
-
$cnt = floor(count($convmap) / 4) * 4;
|
238 |
$i = 0;
|
239 |
-
$len = strlen($s);
|
240 |
$result = '';
|
241 |
|
242 |
while ($i < $len) {
|
@@ -305,7 +305,7 @@ final class Mbstring
|
|
305 |
static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
|
306 |
|
307 |
$i = 0;
|
308 |
-
$len = strlen($s);
|
309 |
|
310 |
while ($i < $len) {
|
311 |
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
|
@@ -314,7 +314,7 @@ final class Mbstring
|
|
314 |
|
315 |
if (isset($map[$uchr])) {
|
316 |
$uchr = $map[$uchr];
|
317 |
-
$nlen = strlen($uchr);
|
318 |
|
319 |
if ($nlen == $ulen) {
|
320 |
$nlen = $i;
|
@@ -404,7 +404,7 @@ final class Mbstring
|
|
404 |
if (null === $encodingList) {
|
405 |
$encodingList = self::$encodingList;
|
406 |
} else {
|
407 |
-
if (
|
408 |
$encodingList = array_map('trim', explode(',', $encodingList));
|
409 |
}
|
410 |
$encodingList = array_map('strtoupper', $encodingList);
|
@@ -441,7 +441,7 @@ final class Mbstring
|
|
441 |
return self::$encodingList;
|
442 |
}
|
443 |
|
444 |
-
if (
|
445 |
$encodingList = array_map('trim', explode(',', $encodingList));
|
446 |
}
|
447 |
$encodingList = array_map('strtoupper', $encodingList);
|
@@ -467,7 +467,7 @@ final class Mbstring
|
|
467 |
{
|
468 |
$encoding = self::getEncoding($encoding);
|
469 |
if ('CP850' === $encoding || 'ASCII' === $encoding) {
|
470 |
-
return strlen($s);
|
471 |
}
|
472 |
|
473 |
return @iconv_strlen($s, $encoding);
|
@@ -679,13 +679,13 @@ final class Mbstring
|
|
679 |
public static function mb_chr($code, $encoding = null)
|
680 |
{
|
681 |
if (0x80 > $code %= 0x200000) {
|
682 |
-
$s = chr($code);
|
683 |
} elseif (0x800 > $code) {
|
684 |
-
$s = chr(0xC0 | $code >> 6)
|
685 |
} elseif (0x10000 > $code) {
|
686 |
-
$s = chr(0xE0 | $code >> 12)
|
687 |
} else {
|
688 |
-
$s = chr(0xF0 | $code >> 18)
|
689 |
}
|
690 |
|
691 |
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
|
@@ -735,7 +735,7 @@ final class Mbstring
|
|
735 |
|
736 |
while (isset($m[$i])) {
|
737 |
if (0x80 > $m[$i]) {
|
738 |
-
$entities .= chr($m[$i++]);
|
739 |
continue;
|
740 |
}
|
741 |
if (0xF0 <= $m[$i]) {
|
78 |
|
79 |
public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
|
80 |
{
|
81 |
+
if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
|
82 |
$fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
|
83 |
} else {
|
84 |
$fromEncoding = self::getEncoding($fromEncoding);
|
140 |
|
141 |
public static function mb_decode_numericentity($s, $convmap, $encoding = null)
|
142 |
{
|
143 |
+
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
|
144 |
trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.gettype($s).' given', E_USER_WARNING);
|
145 |
return null;
|
146 |
}
|
147 |
|
148 |
+
if (!\is_array($convmap) || !$convmap) {
|
149 |
return false;
|
150 |
}
|
151 |
|
152 |
+
if (null !== $encoding && !\is_scalar($encoding)) {
|
153 |
trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.gettype($s).' given', E_USER_WARNING);
|
154 |
return ''; // Instead of null (cf. mb_encode_numericentity).
|
155 |
}
|
170 |
$s = iconv($encoding, 'UTF-8//IGNORE', $s);
|
171 |
}
|
172 |
|
173 |
+
$cnt = floor(\count($convmap) / 4) * 4;
|
174 |
|
175 |
for ($i = 0; $i < $cnt; $i += 4) {
|
176 |
// collector_decode_htmlnumericentity ignores $convmap[$i + 3]
|
197 |
|
198 |
public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
|
199 |
{
|
200 |
+
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
|
201 |
trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.gettype($s).' given', E_USER_WARNING);
|
202 |
return null;
|
203 |
}
|
204 |
|
205 |
+
if (!\is_array($convmap) || !$convmap) {
|
206 |
return false;
|
207 |
}
|
208 |
|
209 |
+
if (null !== $encoding && !\is_scalar($encoding)) {
|
210 |
trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.gettype($s).' given', E_USER_WARNING);
|
211 |
return null; // Instead of '' (cf. mb_decode_numericentity).
|
212 |
}
|
213 |
|
214 |
+
if (null !== $is_hex && !\is_scalar($is_hex)) {
|
215 |
trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.gettype($s).' given', E_USER_WARNING);
|
216 |
return null;
|
217 |
}
|
234 |
|
235 |
static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
|
236 |
|
237 |
+
$cnt = floor(\count($convmap) / 4) * 4;
|
238 |
$i = 0;
|
239 |
+
$len = \strlen($s);
|
240 |
$result = '';
|
241 |
|
242 |
while ($i < $len) {
|
305 |
static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
|
306 |
|
307 |
$i = 0;
|
308 |
+
$len = \strlen($s);
|
309 |
|
310 |
while ($i < $len) {
|
311 |
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
|
314 |
|
315 |
if (isset($map[$uchr])) {
|
316 |
$uchr = $map[$uchr];
|
317 |
+
$nlen = \strlen($uchr);
|
318 |
|
319 |
if ($nlen == $ulen) {
|
320 |
$nlen = $i;
|
404 |
if (null === $encodingList) {
|
405 |
$encodingList = self::$encodingList;
|
406 |
} else {
|
407 |
+
if (!\is_array($encodingList)) {
|
408 |
$encodingList = array_map('trim', explode(',', $encodingList));
|
409 |
}
|
410 |
$encodingList = array_map('strtoupper', $encodingList);
|
441 |
return self::$encodingList;
|
442 |
}
|
443 |
|
444 |
+
if (!\is_array($encodingList)) {
|
445 |
$encodingList = array_map('trim', explode(',', $encodingList));
|
446 |
}
|
447 |
$encodingList = array_map('strtoupper', $encodingList);
|
467 |
{
|
468 |
$encoding = self::getEncoding($encoding);
|
469 |
if ('CP850' === $encoding || 'ASCII' === $encoding) {
|
470 |
+
return \strlen($s);
|
471 |
}
|
472 |
|
473 |
return @iconv_strlen($s, $encoding);
|
679 |
public static function mb_chr($code, $encoding = null)
|
680 |
{
|
681 |
if (0x80 > $code %= 0x200000) {
|
682 |
+
$s = \chr($code);
|
683 |
} elseif (0x800 > $code) {
|
684 |
+
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
|
685 |
} elseif (0x10000 > $code) {
|
686 |
+
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
|
687 |
} else {
|
688 |
+
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
|
689 |
}
|
690 |
|
691 |
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
|
735 |
|
736 |
while (isset($m[$i])) {
|
737 |
if (0x80 > $m[$i]) {
|
738 |
+
$entities .= \chr($m[$i++]);
|
739 |
continue;
|
740 |
}
|
741 |
if (0xF0 <= $m[$i]) {
|
src/common/lib/vendor/symfony/translation/PluralizationRules.php
CHANGED
@@ -107,6 +107,7 @@ class PluralizationRules
|
|
107 |
case 'nl':
|
108 |
case 'nn':
|
109 |
case 'no':
|
|
|
110 |
case 'om':
|
111 |
case 'or':
|
112 |
case 'pa':
|
107 |
case 'nl':
|
108 |
case 'nn':
|
109 |
case 'no':
|
110 |
+
case 'oc':
|
111 |
case 'om':
|
112 |
case 'or':
|
113 |
case 'pa':
|
src/common/lib/vendor/symfony/translation/composer.json
CHANGED
@@ -31,7 +31,7 @@
|
|
31 |
"suggest": {
|
32 |
"symfony/config": "",
|
33 |
"symfony/yaml": "",
|
34 |
-
"psr/log": "To use logging capability in translator"
|
35 |
},
|
36 |
"autoload": {
|
37 |
"psr-4": { "Symfony\\Component\\Translation\\": "" },
|
31 |
"suggest": {
|
32 |
"symfony/config": "",
|
33 |
"symfony/yaml": "",
|
34 |
+
"psr/log-implementation": "To use logging capability in translator"
|
35 |
},
|
36 |
"autoload": {
|
37 |
"psr-4": { "Symfony\\Component\\Translation\\": "" },
|
src/common/wp-admin-notices.php
CHANGED
@@ -233,7 +233,7 @@ class ICWP_WPSF_WpAdminNotices extends ICWP_WPSF_Foundation {
|
|
233 |
*/
|
234 |
public function flushFlashMessage() {
|
235 |
|
236 |
-
$oDp = $this->
|
237 |
$sCookieName = $this->getActionPrefix().'flash';
|
238 |
$this->sFlashMessage = $oDp->FetchCookie( $sCookieName, '' );
|
239 |
if ( !empty( $this->sFlashMessage ) ) {
|
233 |
*/
|
234 |
public function flushFlashMessage() {
|
235 |
|
236 |
+
$oDp = $this->loadDP();
|
237 |
$sCookieName = $this->getActionPrefix().'flash';
|
238 |
$this->sFlashMessage = $oDp->FetchCookie( $sCookieName, '' );
|
239 |
if ( !empty( $this->sFlashMessage ) ) {
|
src/common/wp-comments.php
CHANGED
@@ -54,7 +54,7 @@ class ICWP_WPSF_WpComments extends ICWP_WPSF_Foundation {
|
|
54 |
*/
|
55 |
public function isCommentAuthorPreviouslyApproved( $sAuthorEmail ) {
|
56 |
|
57 |
-
if ( !$this->
|
58 |
return false;
|
59 |
}
|
60 |
|
54 |
*/
|
55 |
public function isCommentAuthorPreviouslyApproved( $sAuthorEmail ) {
|
56 |
|
57 |
+
if ( !$this->loadDP()->validEmail( $sAuthorEmail ) ) {
|
58 |
return false;
|
59 |
}
|
60 |
|
src/config/changelog.json
CHANGED
@@ -356,7 +356,7 @@
|
|
356 |
"timestamp": "1491523200",
|
357 |
"name": "",
|
358 |
"summary": "Introduction of Login Authentication Portal",
|
359 |
-
"link": "
|
360 |
"is_patch": false,
|
361 |
"options_added": true,
|
362 |
"options_removed": true
|
@@ -700,13 +700,13 @@
|
|
700 |
{
|
701 |
"type": "changed",
|
702 |
"summary": "Major overhaul of Two-Factor / Multi-Factor Login Authentication",
|
703 |
-
"link": "
|
704 |
"version": "5.8.0"
|
705 |
},
|
706 |
{
|
707 |
"type": "changed",
|
708 |
"summary": "Introduction of Login Authentication Portal for improved Multi-Factor Authentication",
|
709 |
-
"link": "
|
710 |
"version": "5.8.0"
|
711 |
},
|
712 |
{
|
@@ -747,7 +747,7 @@
|
|
747 |
{
|
748 |
"type": "improvements",
|
749 |
"summary": "Further preparation for Shield Central release",
|
750 |
-
"link": "
|
751 |
"version": "5.8.0"
|
752 |
}
|
753 |
]
|
356 |
"timestamp": "1491523200",
|
357 |
"name": "",
|
358 |
"summary": "Introduction of Login Authentication Portal",
|
359 |
+
"link": "https://icwp.io/86",
|
360 |
"is_patch": false,
|
361 |
"options_added": true,
|
362 |
"options_removed": true
|
700 |
{
|
701 |
"type": "changed",
|
702 |
"summary": "Major overhaul of Two-Factor / Multi-Factor Login Authentication",
|
703 |
+
"link": "https://icwp.io/87",
|
704 |
"version": "5.8.0"
|
705 |
},
|
706 |
{
|
707 |
"type": "changed",
|
708 |
"summary": "Introduction of Login Authentication Portal for improved Multi-Factor Authentication",
|
709 |
+
"link": "https://icwp.io/86",
|
710 |
"version": "5.8.0"
|
711 |
},
|
712 |
{
|
747 |
{
|
748 |
"type": "improvements",
|
749 |
"summary": "Further preparation for Shield Central release",
|
750 |
+
"link": "https://icwp.io/83",
|
751 |
"version": "5.8.0"
|
752 |
}
|
753 |
]
|
src/config/feature-admin_access_restriction.php
CHANGED
@@ -75,8 +75,8 @@
|
|
75 |
"section": "section_enable_plugin_feature_admin_access_restriction",
|
76 |
"default": "Y",
|
77 |
"type": "checkbox",
|
78 |
-
"link_info": "
|
79 |
-
"link_blog": "
|
80 |
"name": "Enable Security Admin",
|
81 |
"summary": "Enforce Security Admin Access Restriction",
|
82 |
"description": "Enable this with great care and consideration. When this Access Key option is enabled, you must specify a key below and use it to gain access to this plugin."
|
@@ -87,7 +87,7 @@
|
|
87 |
"sensitive": true,
|
88 |
"default": "",
|
89 |
"type": "password",
|
90 |
-
"link_info": "
|
91 |
"link_blog": "",
|
92 |
"name": "Security Admin Access Key",
|
93 |
"summary": "Provide/Update Security Admin Access Key",
|
@@ -99,7 +99,8 @@
|
|
99 |
"section": "section_admin_access_restriction_settings",
|
100 |
"default": 30,
|
101 |
"type": "integer",
|
102 |
-
"
|
|
|
103 |
"link_blog": "",
|
104 |
"name": "Security Admin Timeout",
|
105 |
"summary": "Specify An Automatic Timeout Interval For Security Admin Access",
|
@@ -110,8 +111,8 @@
|
|
110 |
"section": "section_admin_access_restriction_areas",
|
111 |
"default": "Y",
|
112 |
"type": "checkbox",
|
113 |
-
"link_info": "
|
114 |
-
"link_blog": "
|
115 |
"name": "Pages",
|
116 |
"summary": "Restrict Access To Key WordPress Posts And Pages Actions",
|
117 |
"description": "Careful: This will restrict access to page/post creation, editing and deletion. Note: Selecting 'Edit' will also restrict all other options."
|
@@ -121,7 +122,7 @@
|
|
121 |
"section": "section_admin_access_restriction_areas",
|
122 |
"default": "N",
|
123 |
"type": "checkbox",
|
124 |
-
"link_info": "
|
125 |
"link_blog": "",
|
126 |
"name": "Admin Users",
|
127 |
"summary": "Restrict Access To Create/Delete/Modify Other Admin Users",
|
@@ -150,8 +151,8 @@
|
|
150 |
"text": "Delete"
|
151 |
}
|
152 |
],
|
153 |
-
"link_info": "
|
154 |
-
"link_blog": "
|
155 |
"summary": "Restrict Access To Key WordPress Plugin Actions",
|
156 |
"description": "Careful: This will restrict access to plugin installation, update, activation and deletion. Note: Selecting 'Activate' will also restrict all other options."
|
157 |
|
@@ -183,8 +184,8 @@
|
|
183 |
"text": "Delete"
|
184 |
}
|
185 |
],
|
186 |
-
"link_info": "
|
187 |
-
"link_blog": "
|
188 |
"summary": "Restrict Access To WordPress Theme Actions",
|
189 |
"description": "Careful: This will restrict access to theme installation, update, activation and deletion."
|
190 |
},
|
@@ -207,14 +208,14 @@
|
|
207 |
"text": "Delete"
|
208 |
}
|
209 |
],
|
210 |
-
"link_info": "
|
211 |
-
"link_blog": "
|
212 |
"summary": "Restrict Access To Key WordPress Posts And Pages Actions",
|
213 |
"description": "Careful: This will restrict access to page/post creation, editing and deletion."
|
214 |
},
|
215 |
{
|
216 |
"key": "whitelabel_enable",
|
217 |
-
"section": "
|
218 |
"premium": true,
|
219 |
"default": "N",
|
220 |
"type": "checkbox",
|
@@ -225,9 +226,8 @@
|
|
225 |
"description": "Use this option to turn on/off the whole White Label feature."
|
226 |
},
|
227 |
{
|
228 |
-
"key": "
|
229 |
-
"section": "
|
230 |
-
"premium": true,
|
231 |
"default": "Y",
|
232 |
"type": "checkbox",
|
233 |
"link_info": "",
|
@@ -237,10 +237,10 @@
|
|
237 |
"description": "Hides the availability of Shield updates from non-security admins."
|
238 |
},
|
239 |
{
|
240 |
-
"key": "
|
|
|
241 |
"sensitive": true,
|
242 |
-
"
|
243 |
-
"default": "Shield Security",
|
244 |
"type": "text",
|
245 |
"link_info": "",
|
246 |
"link_blog": "",
|
@@ -249,10 +249,10 @@
|
|
249 |
"description": "The Name Of The Plugin."
|
250 |
},
|
251 |
{
|
252 |
-
"key": "
|
|
|
253 |
"sensitive": true,
|
254 |
-
"
|
255 |
-
"default": "",
|
256 |
"type": "text",
|
257 |
"link_info": "",
|
258 |
"link_blog": "",
|
@@ -261,9 +261,21 @@
|
|
261 |
"description": "The Main Menu Title Of The Plugin. If left empty, the Plugin Name will be used."
|
262 |
},
|
263 |
{
|
264 |
-
"key": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
265 |
"sensitive": true,
|
266 |
-
"section": "section_non_ui",
|
267 |
"default": "Secure Your Sites With The World's Most Powerful WordPress Security Plugin",
|
268 |
"type": "text",
|
269 |
"link_info": "",
|
@@ -273,10 +285,10 @@
|
|
273 |
"description": "The Tag Line Of The Plugin."
|
274 |
},
|
275 |
{
|
276 |
-
"key": "
|
|
|
277 |
"sensitive": true,
|
278 |
-
"
|
279 |
-
"default": "http://icwp.io/home",
|
280 |
"type": "text",
|
281 |
"link_info": "",
|
282 |
"link_blog": "",
|
@@ -285,16 +297,28 @@
|
|
285 |
"description": "When a user clicks the home link for this plugin, this is where they'll be directed."
|
286 |
},
|
287 |
{
|
288 |
-
"key": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
"sensitive": true,
|
290 |
-
"section": "section_non_ui",
|
291 |
"default": "",
|
292 |
"type": "text",
|
293 |
"link_info": "",
|
294 |
"link_blog": "",
|
295 |
-
"name": "
|
296 |
-
"summary": "
|
297 |
-
"description": "The URL of the
|
298 |
}
|
299 |
],
|
300 |
"definitions": {
|
75 |
"section": "section_enable_plugin_feature_admin_access_restriction",
|
76 |
"default": "Y",
|
77 |
"type": "checkbox",
|
78 |
+
"link_info": "https://icwp.io/40",
|
79 |
+
"link_blog": "https://icwp.io/wpsf02",
|
80 |
"name": "Enable Security Admin",
|
81 |
"summary": "Enforce Security Admin Access Restriction",
|
82 |
"description": "Enable this with great care and consideration. When this Access Key option is enabled, you must specify a key below and use it to gain access to this plugin."
|
87 |
"sensitive": true,
|
88 |
"default": "",
|
89 |
"type": "password",
|
90 |
+
"link_info": "https://icwp.io/42",
|
91 |
"link_blog": "",
|
92 |
"name": "Security Admin Access Key",
|
93 |
"summary": "Provide/Update Security Admin Access Key",
|
99 |
"section": "section_admin_access_restriction_settings",
|
100 |
"default": 30,
|
101 |
"type": "integer",
|
102 |
+
"min": 1,
|
103 |
+
"link_info": "https://icwp.io/41",
|
104 |
"link_blog": "",
|
105 |
"name": "Security Admin Timeout",
|
106 |
"summary": "Specify An Automatic Timeout Interval For Security Admin Access",
|
111 |
"section": "section_admin_access_restriction_areas",
|
112 |
"default": "Y",
|
113 |
"type": "checkbox",
|
114 |
+
"link_info": "https://icwp.io/a0",
|
115 |
+
"link_blog": "https://icwp.io/wpsf32",
|
116 |
"name": "Pages",
|
117 |
"summary": "Restrict Access To Key WordPress Posts And Pages Actions",
|
118 |
"description": "Careful: This will restrict access to page/post creation, editing and deletion. Note: Selecting 'Edit' will also restrict all other options."
|
122 |
"section": "section_admin_access_restriction_areas",
|
123 |
"default": "N",
|
124 |
"type": "checkbox",
|
125 |
+
"link_info": "https://icwp.io/a0",
|
126 |
"link_blog": "",
|
127 |
"name": "Admin Users",
|
128 |
"summary": "Restrict Access To Create/Delete/Modify Other Admin Users",
|
151 |
"text": "Delete"
|
152 |
}
|
153 |
],
|
154 |
+
"link_info": "https://icwp.io/a0",
|
155 |
+
"link_blog": "https://icwp.io/wpsf21",
|
156 |
"summary": "Restrict Access To Key WordPress Plugin Actions",
|
157 |
"description": "Careful: This will restrict access to plugin installation, update, activation and deletion. Note: Selecting 'Activate' will also restrict all other options."
|
158 |
|
184 |
"text": "Delete"
|
185 |
}
|
186 |
],
|
187 |
+
"link_info": "https://icwp.io/a0",
|
188 |
+
"link_blog": "https://icwp.io/wpsf21",
|
189 |
"summary": "Restrict Access To WordPress Theme Actions",
|
190 |
"description": "Careful: This will restrict access to theme installation, update, activation and deletion."
|
191 |
},
|
208 |
"text": "Delete"
|
209 |
}
|
210 |
],
|
211 |
+
"link_info": "https://icwp.io/a0",
|
212 |
+
"link_blog": "https://icwp.io/wpsf21",
|
213 |
"summary": "Restrict Access To Key WordPress Posts And Pages Actions",
|
214 |
"description": "Careful: This will restrict access to page/post creation, editing and deletion."
|
215 |
},
|
216 |
{
|
217 |
"key": "whitelabel_enable",
|
218 |
+
"section": "section_whitelabel",
|
219 |
"premium": true,
|
220 |
"default": "N",
|
221 |
"type": "checkbox",
|
226 |
"description": "Use this option to turn on/off the whole White Label feature."
|
227 |
},
|
228 |
{
|
229 |
+
"key": "wl_hide_updates",
|
230 |
+
"section": "section_whitelabel",
|
|
|
231 |
"default": "Y",
|
232 |
"type": "checkbox",
|
233 |
"link_info": "",
|
237 |
"description": "Hides the availability of Shield updates from non-security admins."
|
238 |
},
|
239 |
{
|
240 |
+
"key": "wl_pluginnamemain",
|
241 |
+
"section": "section_whitelabel",
|
242 |
"sensitive": true,
|
243 |
+
"default": "Shield",
|
|
|
244 |
"type": "text",
|
245 |
"link_info": "",
|
246 |
"link_blog": "",
|
249 |
"description": "The Name Of The Plugin."
|
250 |
},
|
251 |
{
|
252 |
+
"key": "wl_namemenu",
|
253 |
+
"section": "section_whitelabel",
|
254 |
"sensitive": true,
|
255 |
+
"default": "Shield Security",
|
|
|
256 |
"type": "text",
|
257 |
"link_info": "",
|
258 |
"link_blog": "",
|
261 |
"description": "The Main Menu Title Of The Plugin. If left empty, the Plugin Name will be used."
|
262 |
},
|
263 |
{
|
264 |
+
"key": "wl_companyname",
|
265 |
+
"section": "section_whitelabel",
|
266 |
+
"sensitive": true,
|
267 |
+
"default": "One Dollar Plugin",
|
268 |
+
"type": "text",
|
269 |
+
"link_info": "",
|
270 |
+
"link_blog": "",
|
271 |
+
"name": "Company Name",
|
272 |
+
"summary": "The Name Of Your Company",
|
273 |
+
"description": "Provide the name of your company."
|
274 |
+
},
|
275 |
+
{
|
276 |
+
"key": "wl_description",
|
277 |
+
"section": "section_whitelabel",
|
278 |
"sensitive": true,
|
|
|
279 |
"default": "Secure Your Sites With The World's Most Powerful WordPress Security Plugin",
|
280 |
"type": "text",
|
281 |
"link_info": "",
|
285 |
"description": "The Tag Line Of The Plugin."
|
286 |
},
|
287 |
{
|
288 |
+
"key": "wl_homeurl",
|
289 |
+
"section": "section_whitelabel",
|
290 |
"sensitive": true,
|
291 |
+
"default": "https://icwp.io/7f",
|
|
|
292 |
"type": "text",
|
293 |
"link_info": "",
|
294 |
"link_blog": "",
|
297 |
"description": "When a user clicks the home link for this plugin, this is where they'll be directed."
|
298 |
},
|
299 |
{
|
300 |
+
"key": "wl_menuiconurl",
|
301 |
+
"section": "section_whitelabel",
|
302 |
+
"sensitive": true,
|
303 |
+
"default": "",
|
304 |
+
"type": "text",
|
305 |
+
"link_info": "",
|
306 |
+
"link_blog": "",
|
307 |
+
"name": "Menu Icon",
|
308 |
+
"summary": "Menu Icon URL",
|
309 |
+
"description": "The URL of the icon displayed in the menu."
|
310 |
+
},
|
311 |
+
{
|
312 |
+
"key": "wl_dashboardlogourl",
|
313 |
+
"section": "section_whitelabel",
|
314 |
"sensitive": true,
|
|
|
315 |
"default": "",
|
316 |
"type": "text",
|
317 |
"link_info": "",
|
318 |
"link_blog": "",
|
319 |
+
"name": "Dashboard Logo",
|
320 |
+
"summary": "Dashboard Logo URL",
|
321 |
+
"description": "The URL of the logo displayed in the main dashboard. Should be 128x128px"
|
322 |
}
|
323 |
],
|
324 |
"definitions": {
|
src/config/feature-audit_trail.php
CHANGED
@@ -53,8 +53,8 @@
|
|
53 |
"section": "section_enable_plugin_feature_audit_trail",
|
54 |
"default": "Y",
|
55 |
"type": "checkbox",
|
56 |
-
"link_info": "
|
57 |
-
"link_blog": "
|
58 |
"name": "Enable Audit Trail",
|
59 |
"summary": "Enable (or Disable) The Audit Trail module",
|
60 |
"description": "Un-Checking this option will completely disable the Audit Trail module"
|
@@ -65,8 +65,8 @@
|
|
65 |
"section": "section_audit_trail_options",
|
66 |
"default": 14,
|
67 |
"type": "integer",
|
68 |
-
"link_info": "
|
69 |
-
"link_blog": "
|
70 |
"name": "Auto Clean",
|
71 |
"summary": "Enable Audit Auto Cleaning",
|
72 |
"description": "Events older than the number of days specified will be automatically cleaned from the database"
|
@@ -88,8 +88,8 @@
|
|
88 |
"section": "section_enable_audit_contexts",
|
89 |
"default": "Y",
|
90 |
"type": "checkbox",
|
91 |
-
"link_info": "
|
92 |
-
"link_blog": "
|
93 |
"name": "Users And Logins",
|
94 |
"summary": "Enable Audit Context - Users And Logins",
|
95 |
"description": "When this context is enabled, the audit trail will track activity relating to: Users And Logins"
|
@@ -99,8 +99,8 @@
|
|
99 |
"section": "section_enable_audit_contexts",
|
100 |
"default": "Y",
|
101 |
"type": "checkbox",
|
102 |
-
"link_info": "
|
103 |
-
"link_blog": "
|
104 |
"name": "Plugins",
|
105 |
"summary": "Enable Audit Context - Plugins",
|
106 |
"description": "When this context is enabled, the audit trail will track activity relating to: WordPress Plugins"
|
@@ -110,8 +110,8 @@
|
|
110 |
"section": "section_enable_audit_contexts",
|
111 |
"default": "Y",
|
112 |
"type": "checkbox",
|
113 |
-
"link_info": "
|
114 |
-
"link_blog": "
|
115 |
"name": "Themes",
|
116 |
"summary": "Enable Audit Context - Themes",
|
117 |
"description": "When this context is enabled, the audit trail will track activity relating to: WordPress Themes"
|
@@ -121,8 +121,8 @@
|
|
121 |
"section": "section_enable_audit_contexts",
|
122 |
"default": "Y",
|
123 |
"type": "checkbox",
|
124 |
-
"link_info": "
|
125 |
-
"link_blog": "
|
126 |
"name": "Posts And Pages",
|
127 |
"summary": "Enable Audit Context - Posts And Pages",
|
128 |
"description": "When this context is enabled, the audit trail will track activity relating to: Editing and publishing of posts and pages"
|
@@ -132,8 +132,8 @@
|
|
132 |
"section": "section_enable_audit_contexts",
|
133 |
"default": "Y",
|
134 |
"type": "checkbox",
|
135 |
-
"link_info": "
|
136 |
-
"link_blog": "
|
137 |
"name": "WordPress And Settings",
|
138 |
"summary": "Enable Audit Context - WordPress And Settings",
|
139 |
"description": "When this context is enabled, the audit trail will track activity relating to: WordPress upgrades and changes to particular WordPress settings"
|
@@ -143,8 +143,8 @@
|
|
143 |
"section": "section_enable_audit_contexts",
|
144 |
"default": "Y",
|
145 |
"type": "checkbox",
|
146 |
-
"link_info": "
|
147 |
-
"link_blog": "
|
148 |
"name": "Emails",
|
149 |
"summary": "Enable Audit Context - Emails",
|
150 |
"description": "When this context is enabled, the audit trail will track activity relating to: Email Sending"
|
@@ -154,8 +154,8 @@
|
|
154 |
"section": "section_enable_audit_contexts",
|
155 |
"default": "Y",
|
156 |
"type": "checkbox",
|
157 |
-
"link_info": "
|
158 |
-
"link_blog": "
|
159 |
"name": "Shield",
|
160 |
"summary": "Enable Audit Context - Shield",
|
161 |
"description": "When this context is enabled, the audit trail will track activity relating to: Shield"
|
53 |
"section": "section_enable_plugin_feature_audit_trail",
|
54 |
"default": "Y",
|
55 |
"type": "checkbox",
|
56 |
+
"link_info": "https://icwp.io/5p",
|
57 |
+
"link_blog": "https://icwp.io/a1",
|
58 |
"name": "Enable Audit Trail",
|
59 |
"summary": "Enable (or Disable) The Audit Trail module",
|
60 |
"description": "Un-Checking this option will completely disable the Audit Trail module"
|
65 |
"section": "section_audit_trail_options",
|
66 |
"default": 14,
|
67 |
"type": "integer",
|
68 |
+
"link_info": "https://icwp.io/a2",
|
69 |
+
"link_blog": "https://icwp.io/a1",
|
70 |
"name": "Auto Clean",
|
71 |
"summary": "Enable Audit Auto Cleaning",
|
72 |
"description": "Events older than the number of days specified will be automatically cleaned from the database"
|
88 |
"section": "section_enable_audit_contexts",
|
89 |
"default": "Y",
|
90 |
"type": "checkbox",
|
91 |
+
"link_info": "https://icwp.io/a3",
|
92 |
+
"link_blog": "https://icwp.io/a1",
|
93 |
"name": "Users And Logins",
|
94 |
"summary": "Enable Audit Context - Users And Logins",
|
95 |
"description": "When this context is enabled, the audit trail will track activity relating to: Users And Logins"
|
99 |
"section": "section_enable_audit_contexts",
|
100 |
"default": "Y",
|
101 |
"type": "checkbox",
|
102 |
+
"link_info": "https://icwp.io/a3",
|
103 |
+
"link_blog": "https://icwp.io/a1",
|
104 |
"name": "Plugins",
|
105 |
"summary": "Enable Audit Context - Plugins",
|
106 |
"description": "When this context is enabled, the audit trail will track activity relating to: WordPress Plugins"
|
110 |
"section": "section_enable_audit_contexts",
|
111 |
"default": "Y",
|
112 |
"type": "checkbox",
|
113 |
+
"link_info": "https://icwp.io/a3",
|
114 |
+
"link_blog": "https://icwp.io/a1",
|
115 |
"name": "Themes",
|
116 |
"summary": "Enable Audit Context - Themes",
|
117 |
"description": "When this context is enabled, the audit trail will track activity relating to: WordPress Themes"
|
121 |
"section": "section_enable_audit_contexts",
|
122 |
"default": "Y",
|
123 |
"type": "checkbox",
|
124 |
+
"link_info": "https://icwp.io/a3",
|
125 |
+
"link_blog": "https://icwp.io/a1",
|
126 |
"name": "Posts And Pages",
|
127 |
"summary": "Enable Audit Context - Posts And Pages",
|
128 |
"description": "When this context is enabled, the audit trail will track activity relating to: Editing and publishing of posts and pages"
|
132 |
"section": "section_enable_audit_contexts",
|
133 |
"default": "Y",
|
134 |
"type": "checkbox",
|
135 |
+
"link_info": "https://icwp.io/a3",
|
136 |
+
"link_blog": "https://icwp.io/a1",
|
137 |
"name": "WordPress And Settings",
|
138 |
"summary": "Enable Audit Context - WordPress And Settings",
|
139 |
"description": "When this context is enabled, the audit trail will track activity relating to: WordPress upgrades and changes to particular WordPress settings"
|
143 |
"section": "section_enable_audit_contexts",
|
144 |
"default": "Y",
|
145 |
"type": "checkbox",
|
146 |
+
"link_info": "https://icwp.io/a3",
|
147 |
+
"link_blog": "https://icwp.io/a1",
|
148 |
"name": "Emails",
|
149 |
"summary": "Enable Audit Context - Emails",
|
150 |
"description": "When this context is enabled, the audit trail will track activity relating to: Email Sending"
|
154 |
"section": "section_enable_audit_contexts",
|
155 |
"default": "Y",
|
156 |
"type": "checkbox",
|
157 |
+
"link_info": "https://icwp.io/a4",
|
158 |
+
"link_blog": "https://icwp.io/a1",
|
159 |
"name": "Shield",
|
160 |
"summary": "Enable Audit Context - Shield",
|
161 |
"description": "When this context is enabled, the audit trail will track activity relating to: Shield"
|
src/config/feature-autoupdates.php
CHANGED
@@ -48,7 +48,7 @@
|
|
48 |
"section": "section_enable_plugin_feature_automatic_updates_control",
|
49 |
"default": "Y",
|
50 |
"type": "checkbox",
|
51 |
-
"link_info": "
|
52 |
"link_blog": "",
|
53 |
"name": "Enable Automatic Updates",
|
54 |
"summary": "Enable (or Disable) The Automatic Updates module",
|
@@ -59,7 +59,7 @@
|
|
59 |
"section": "section_automatic_updates_for_wordpress_components",
|
60 |
"default": "N",
|
61 |
"type": "checkbox",
|
62 |
-
"link_info": "
|
63 |
"link_blog": "",
|
64 |
"name": "Disable All",
|
65 |
"summary": "Completely Disable WordPress Automatic Updates",
|
@@ -84,7 +84,7 @@
|
|
84 |
"text": "Major and Minor Versions"
|
85 |
}
|
86 |
],
|
87 |
-
"link_info": "
|
88 |
"link_blog": "",
|
89 |
"name": "WordPress Core Updates",
|
90 |
"summary": "Decide how the WordPress Core will automatically update, if at all",
|
48 |
"section": "section_enable_plugin_feature_automatic_updates_control",
|
49 |
"default": "Y",
|
50 |
"type": "checkbox",
|
51 |
+
"link_info": "https://icwp.io/3w",
|
52 |
"link_blog": "",
|
53 |
"name": "Enable Automatic Updates",
|
54 |
"summary": "Enable (or Disable) The Automatic Updates module",
|
59 |
"section": "section_automatic_updates_for_wordpress_components",
|
60 |
"default": "N",
|
61 |
"type": "checkbox",
|
62 |
+
"link_info": "https://icwp.io/3v",
|
63 |
"link_blog": "",
|
64 |
"name": "Disable All",
|
65 |
"summary": "Completely Disable WordPress Automatic Updates",
|
84 |
"text": "Major and Minor Versions"
|
85 |
}
|
86 |
],
|
87 |
+
"link_info": "https://icwp.io/3x",
|
88 |
"link_blog": "",
|
89 |
"name": "WordPress Core Updates",
|
90 |
"summary": "Decide how the WordPress Core will automatically update, if at all",
|
src/config/feature-comments_filter.php
CHANGED
@@ -84,8 +84,8 @@
|
|
84 |
"section": "section_enable_plugin_feature_spam_comments_protection_filter",
|
85 |
"default": "Y",
|
86 |
"type": "checkbox",
|
87 |
-
"link_info": "
|
88 |
-
"link_blog": "
|
89 |
"name": "Enable SPAM Protection",
|
90 |
"summary": "Enable (or Disable) The Comments SPAM Protection module",
|
91 |
"description": "Un-Checking this option will completely disable the Comments SPAM Protection module"
|
@@ -95,8 +95,8 @@
|
|
95 |
"section": "section_bot_comment_spam_protection_filter",
|
96 |
"default": "N",
|
97 |
"type": "checkbox",
|
98 |
-
"link_info": "
|
99 |
-
"link_blog": "
|
100 |
"name": "GASP Protection",
|
101 |
"summary": "Block Bot Comment SPAM",
|
102 |
"description": "Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection."
|
@@ -106,7 +106,7 @@
|
|
106 |
"section": "section_bot_comment_spam_protection_filter",
|
107 |
"default": 10,
|
108 |
"type": "integer",
|
109 |
-
"link_info": "
|
110 |
"link_blog": "",
|
111 |
"name": "Comments Cooldown",
|
112 |
"summary": "Limit posting comments to X seconds after the page has loaded",
|
@@ -135,7 +135,7 @@
|
|
135 |
"text": "Reject And Redirect"
|
136 |
}
|
137 |
],
|
138 |
-
"link_info": "
|
139 |
"link_blog": "",
|
140 |
"name": "Default SPAM Action",
|
141 |
"summary": "How To Categorise Comments When Identified To Be SPAM",
|
@@ -146,8 +146,8 @@
|
|
146 |
"section": "section_human_spam_filter",
|
147 |
"default": "N",
|
148 |
"type": "checkbox",
|
149 |
-
"link_info": "
|
150 |
-
"link_blog": "
|
151 |
"name": "Human SPAM Filter",
|
152 |
"summary": "Enable (or Disable) The Human SPAM Filter module",
|
153 |
"description": "Scans the content of WordPress comments for keywords that are indicative of SPAM and marks the comment according to your preferred setting below."
|
@@ -190,7 +190,7 @@
|
|
190 |
"text": "Browser User Agent"
|
191 |
}
|
192 |
],
|
193 |
-
"link_info": "
|
194 |
"link_blog": "",
|
195 |
"name": "Comment Filter Items",
|
196 |
"summary": "Select The Items To Scan For SPAM",
|
@@ -228,7 +228,7 @@
|
|
228 |
"section": "section_recaptcha",
|
229 |
"default": "N",
|
230 |
"type": "checkbox",
|
231 |
-
"link_info": "
|
232 |
"link_blog": "",
|
233 |
"name": "Google reCAPTCHA",
|
234 |
"summary": "Enable Google reCAPTCHA For Comments",
|
@@ -273,8 +273,8 @@
|
|
273 |
"section": "section_bot_comment_spam_protection_filter",
|
274 |
"default": 600,
|
275 |
"type": "integer",
|
276 |
-
"link_info": "
|
277 |
-
"link_blog": "
|
278 |
"name": "Comment Token Expire",
|
279 |
"summary": "A visitor has X seconds within which to post a comment",
|
280 |
"description": "Default: 600 seconds (10 minutes). Each visitor is given a unique 'Token' so they can comment. This restricts spambots, but we need to force these tokens to expire and at the same time not bother the visitors."
|
@@ -285,7 +285,7 @@
|
|
285 |
"sensitive": true,
|
286 |
"default": "default",
|
287 |
"type": "text",
|
288 |
-
"link_info": "
|
289 |
"link_blog": "",
|
290 |
"name": "Custom Checkbox Message",
|
291 |
"summary": "If you want a custom checkbox message, please provide this here",
|
@@ -297,7 +297,7 @@
|
|
297 |
"sensitive": true,
|
298 |
"default": "default",
|
299 |
"type": "text",
|
300 |
-
"link_info": "
|
301 |
"link_blog": "",
|
302 |
"name": "Custom Alert Message",
|
303 |
"summary": "If you want a custom alert message, please provide this here",
|
@@ -309,7 +309,7 @@
|
|
309 |
"sensitive": true,
|
310 |
"default": "default",
|
311 |
"type": "text",
|
312 |
-
"link_info": "
|
313 |
"link_blog": "",
|
314 |
"name": "Custom Wait Message",
|
315 |
"summary": "If you want a custom submit-button wait message, please provide this here.",
|
@@ -321,7 +321,7 @@
|
|
321 |
"sensitive": true,
|
322 |
"default": "default",
|
323 |
"type": "text",
|
324 |
-
"link_info": "
|
325 |
"link_blog": "",
|
326 |
"name": "Custom Reload Message",
|
327 |
"summary": "If you want a custom message when the comment token has expired, please provide this here.",
|
84 |
"section": "section_enable_plugin_feature_spam_comments_protection_filter",
|
85 |
"default": "Y",
|
86 |
"type": "checkbox",
|
87 |
+
"link_info": "https://icwp.io/3z",
|
88 |
+
"link_blog": "https://icwp.io/wpsf04",
|
89 |
"name": "Enable SPAM Protection",
|
90 |
"summary": "Enable (or Disable) The Comments SPAM Protection module",
|
91 |
"description": "Un-Checking this option will completely disable the Comments SPAM Protection module"
|
95 |
"section": "section_bot_comment_spam_protection_filter",
|
96 |
"default": "N",
|
97 |
"type": "checkbox",
|
98 |
+
"link_info": "https://icwp.io/3n",
|
99 |
+
"link_blog": "https://icwp.io/2n",
|
100 |
"name": "GASP Protection",
|
101 |
"summary": "Block Bot Comment SPAM",
|
102 |
"description": "Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection."
|
106 |
"section": "section_bot_comment_spam_protection_filter",
|
107 |
"default": 10,
|
108 |
"type": "integer",
|
109 |
+
"link_info": "https://icwp.io/3o",
|
110 |
"link_blog": "",
|
111 |
"name": "Comments Cooldown",
|
112 |
"summary": "Limit posting comments to X seconds after the page has loaded",
|
135 |
"text": "Reject And Redirect"
|
136 |
}
|
137 |
],
|
138 |
+
"link_info": "https://icwp.io/6j",
|
139 |
"link_blog": "",
|
140 |
"name": "Default SPAM Action",
|
141 |
"summary": "How To Categorise Comments When Identified To Be SPAM",
|
146 |
"section": "section_human_spam_filter",
|
147 |
"default": "N",
|
148 |
"type": "checkbox",
|
149 |
+
"link_info": "https://icwp.io/57",
|
150 |
+
"link_blog": "https://icwp.io/9w",
|
151 |
"name": "Human SPAM Filter",
|
152 |
"summary": "Enable (or Disable) The Human SPAM Filter module",
|
153 |
"description": "Scans the content of WordPress comments for keywords that are indicative of SPAM and marks the comment according to your preferred setting below."
|
190 |
"text": "Browser User Agent"
|
191 |
}
|
192 |
],
|
193 |
+
"link_info": "https://icwp.io/58",
|
194 |
"link_blog": "",
|
195 |
"name": "Comment Filter Items",
|
196 |
"summary": "Select The Items To Scan For SPAM",
|
228 |
"section": "section_recaptcha",
|
229 |
"default": "N",
|
230 |
"type": "checkbox",
|
231 |
+
"link_info": "https://icwp.io/shld5",
|
232 |
"link_blog": "",
|
233 |
"name": "Google reCAPTCHA",
|
234 |
"summary": "Enable Google reCAPTCHA For Comments",
|
273 |
"section": "section_bot_comment_spam_protection_filter",
|
274 |
"default": 600,
|
275 |
"type": "integer",
|
276 |
+
"link_info": "https://icwp.io/3o",
|
277 |
+
"link_blog": "https://icwp.io/9v",
|
278 |
"name": "Comment Token Expire",
|
279 |
"summary": "A visitor has X seconds within which to post a comment",
|
280 |
"description": "Default: 600 seconds (10 minutes). Each visitor is given a unique 'Token' so they can comment. This restricts spambots, but we need to force these tokens to expire and at the same time not bother the visitors."
|
285 |
"sensitive": true,
|
286 |
"default": "default",
|
287 |
"type": "text",
|
288 |
+
"link_info": "https://icwp.io/3p",
|
289 |
"link_blog": "",
|
290 |
"name": "Custom Checkbox Message",
|
291 |
"summary": "If you want a custom checkbox message, please provide this here",
|
297 |
"sensitive": true,
|
298 |
"default": "default",
|
299 |
"type": "text",
|
300 |
+
"link_info": "https://icwp.io/3p",
|
301 |
"link_blog": "",
|
302 |
"name": "Custom Alert Message",
|
303 |
"summary": "If you want a custom alert message, please provide this here",
|
309 |
"sensitive": true,
|
310 |
"default": "default",
|
311 |
"type": "text",
|
312 |
+
"link_info": "https://icwp.io/3p",
|
313 |
"link_blog": "",
|
314 |
"name": "Custom Wait Message",
|
315 |
"summary": "If you want a custom submit-button wait message, please provide this here.",
|
321 |
"sensitive": true,
|
322 |
"default": "default",
|
323 |
"type": "text",
|
324 |
+
"link_info": "https://icwp.io/3p",
|
325 |
"link_blog": "",
|
326 |
"name": "Custom Reload Message",
|
327 |
"summary": "If you want a custom message when the comment token has expired, please provide this here.",
|
src/config/feature-firewall.php
CHANGED
@@ -71,8 +71,8 @@
|
|
71 |
"section": "section_enable_plugin_feature_wordpress_firewall",
|
72 |
"default": "Y",
|
73 |
"type": "checkbox",
|
74 |
-
"link_info": "
|
75 |
-
"link_blog": "
|
76 |
"name": "Enable Firewall",
|
77 |
"summary": "Enable (or Disable) The Firewall module",
|
78 |
"description": "Un-Checking this option will completely disable the Firewall module"
|
@@ -221,7 +221,7 @@
|
|
221 |
"section": "section_whitelist",
|
222 |
"default": "",
|
223 |
"type": "comma_separated_lists",
|
224 |
-
"link_info": "
|
225 |
"link_blog": "",
|
226 |
"name": "Whitelist Parameters",
|
227 |
"summary": "Detail pages and parameters that are whitelisted (ignored by the firewall)",
|
71 |
"section": "section_enable_plugin_feature_wordpress_firewall",
|
72 |
"default": "Y",
|
73 |
"type": "checkbox",
|
74 |
+
"link_info": "https://icwp.io/43",
|
75 |
+
"link_blog": "https://icwp.io/wpsf01",
|
76 |
"name": "Enable Firewall",
|
77 |
"summary": "Enable (or Disable) The Firewall module",
|
78 |
"description": "Un-Checking this option will completely disable the Firewall module"
|
221 |
"section": "section_whitelist",
|
222 |
"default": "",
|
223 |
"type": "comma_separated_lists",
|
224 |
+
"link_info": "https://icwp.io/2a",
|
225 |
"link_blog": "",
|
226 |
"name": "Whitelist Parameters",
|
227 |
"summary": "Detail pages and parameters that are whitelisted (ignored by the firewall)",
|
src/config/feature-hack_protect.php
CHANGED
@@ -94,8 +94,8 @@
|
|
94 |
"section": "section_enable_plugin_feature_hack_protection_tools",
|
95 |
"default": "Y",
|
96 |
"type": "checkbox",
|
97 |
-
"link_info": "
|
98 |
-
"link_blog": "
|
99 |
"name": "Enable Hack Guard",
|
100 |
"summary": "Enable (or Disable) The Hack Guard Module",
|
101 |
"description": "Un-Checking this option will completely disable the Hack Guard module"
|
@@ -120,7 +120,7 @@
|
|
120 |
"text": "Enabled - No Email Notification"
|
121 |
}
|
122 |
],
|
123 |
-
"link_info": "
|
124 |
"link_blog": "",
|
125 |
"name": "Vulnerability Scanner",
|
126 |
"summary": "Enable The Vulnerability Scanner",
|
@@ -168,8 +168,8 @@
|
|
168 |
"section": "section_core_file_integrity_scan",
|
169 |
"default": "Y",
|
170 |
"type": "checkbox",
|
171 |
-
"link_info": "
|
172 |
-
"link_blog": "
|
173 |
"name": "Core File Scanner",
|
174 |
"summary": "Scans WordPress Core Files For Alterations",
|
175 |
"description": "Compares all WordPress core files on your site against the official WordPress files. WordPress Core files should never be altered for any reason."
|
@@ -179,8 +179,8 @@
|
|
179 |
"section": "section_core_file_integrity_scan",
|
180 |
"default": "N",
|
181 |
"type": "checkbox",
|
182 |
-
"link_info": "
|
183 |
-
"link_blog": "
|
184 |
"name": "Auto Repair",
|
185 |
"summary": "Automatically Repair WordPress Core Files That Have Been Altered",
|
186 |
"description": "Attempts to automatically repair WordPress Core files with the official WordPress file data, for files that have been altered or are missing."
|
@@ -225,7 +225,7 @@
|
|
225 |
"text": "24 Times (scan every hour)"
|
226 |
}
|
227 |
],
|
228 |
-
"link_info": "
|
229 |
"link_blog": "",
|
230 |
"name": "Scan Frequency",
|
231 |
"summary": "Number Of Times To Automatically Scan Core Files In 24 Hours",
|
@@ -254,8 +254,8 @@
|
|
254 |
"text": "Auto Delete Files and Email Report"
|
255 |
}
|
256 |
],
|
257 |
-
"link_info": "
|
258 |
-
"link_blog": "
|
259 |
"name": "Unrecognised Files Scanner",
|
260 |
"summary": "Scans Core Directories For Unrecognised Files",
|
261 |
"description": "Scans for, and automatically deletes, any files in your core WordPress folders that are not part of your WordPress installation."
|
@@ -265,7 +265,7 @@
|
|
265 |
"section": "section_unrecognised_file_scan",
|
266 |
"default": "N",
|
267 |
"type": "checkbox",
|
268 |
-
"link_info": "
|
269 |
"link_blog": "",
|
270 |
"name": "Scan Uploads",
|
271 |
"summary": "Scan Uploads Folder For PHP and Javascript",
|
@@ -285,8 +285,8 @@
|
|
285 |
"mail.log"
|
286 |
],
|
287 |
"type": "array",
|
288 |
-
"link_info": "
|
289 |
-
"link_blog": "
|
290 |
"name": "File Exclusions",
|
291 |
"summary": "Provide A List Of Files To Be Excluded From The Scan",
|
292 |
"description": "Take a new line for each file you wish to exclude from the scan. No commas are necessary."
|
@@ -329,8 +329,8 @@
|
|
329 |
"text": "Scan Enabled"
|
330 |
}
|
331 |
],
|
332 |
-
"link_info": "
|
333 |
-
"link_blog": "
|
334 |
"name": "Enable/Disable Guard",
|
335 |
"summary": "Enable The Guard For Plugin And Theme Files",
|
336 |
"description": "When enabled the Guard will automatically scan for changes to your Plugin and Theme files."
|
@@ -341,8 +341,8 @@
|
|
341 |
"type": "integer",
|
342 |
"default": 1,
|
343 |
"min": 0,
|
344 |
-
"link_info": "
|
345 |
-
"link_blog": "
|
346 |
"name": "Guard/Scan Depth",
|
347 |
"summary": "How Deep Into The Plugin Directories To Scan And Guard",
|
348 |
"description": "The Guard normally operates scan only the top level of a plugin folder. Increasing depth increases scan times."
|
@@ -358,7 +358,7 @@
|
|
358 |
"htaccess"
|
359 |
],
|
360 |
"type": "array",
|
361 |
-
"link_info": "
|
362 |
"link_blog": "",
|
363 |
"name": "File Types",
|
364 |
"summary": "The File Types Included In The Scan",
|
@@ -369,7 +369,7 @@
|
|
369 |
"section": "section_pluginthemes_guard",
|
370 |
"type": "checkbox",
|
371 |
"default": "Y",
|
372 |
-
"link_info": "
|
373 |
"link_blog": "",
|
374 |
"name": "Show Re-Install Links",
|
375 |
"summary": "Show Re-Install Links For Plugins",
|
94 |
"section": "section_enable_plugin_feature_hack_protection_tools",
|
95 |
"default": "Y",
|
96 |
"type": "checkbox",
|
97 |
+
"link_info": "https://icwp.io/wpsf38",
|
98 |
+
"link_blog": "https://icwp.io/9x",
|
99 |
"name": "Enable Hack Guard",
|
100 |
"summary": "Enable (or Disable) The Hack Guard Module",
|
101 |
"description": "Un-Checking this option will completely disable the Hack Guard module"
|
120 |
"text": "Enabled - No Email Notification"
|
121 |
}
|
122 |
],
|
123 |
+
"link_info": "https://icwp.io/ah",
|
124 |
"link_blog": "",
|
125 |
"name": "Vulnerability Scanner",
|
126 |
"summary": "Enable The Vulnerability Scanner",
|
168 |
"section": "section_core_file_integrity_scan",
|
169 |
"default": "Y",
|
170 |
"type": "checkbox",
|
171 |
+
"link_info": "https://icwp.io/wpsf36",
|
172 |
+
"link_blog": "https://icwp.io/wpsf37",
|
173 |
"name": "Core File Scanner",
|
174 |
"summary": "Scans WordPress Core Files For Alterations",
|
175 |
"description": "Compares all WordPress core files on your site against the official WordPress files. WordPress Core files should never be altered for any reason."
|
179 |
"section": "section_core_file_integrity_scan",
|
180 |
"default": "N",
|
181 |
"type": "checkbox",
|
182 |
+
"link_info": "https://icwp.io/wpsf36",
|
183 |
+
"link_blog": "https://icwp.io/wpsf37",
|
184 |
"name": "Auto Repair",
|
185 |
"summary": "Automatically Repair WordPress Core Files That Have Been Altered",
|
186 |
"description": "Attempts to automatically repair WordPress Core files with the official WordPress file data, for files that have been altered or are missing."
|
225 |
"text": "24 Times (scan every hour)"
|
226 |
}
|
227 |
],
|
228 |
+
"link_info": "https://icwp.io/b2",
|
229 |
"link_blog": "",
|
230 |
"name": "Scan Frequency",
|
231 |
"summary": "Number Of Times To Automatically Scan Core Files In 24 Hours",
|
254 |
"text": "Auto Delete Files and Email Report"
|
255 |
}
|
256 |
],
|
257 |
+
"link_info": "https://icwp.io/9y",
|
258 |
+
"link_blog": "https://icwp.io/95",
|
259 |
"name": "Unrecognised Files Scanner",
|
260 |
"summary": "Scans Core Directories For Unrecognised Files",
|
261 |
"description": "Scans for, and automatically deletes, any files in your core WordPress folders that are not part of your WordPress installation."
|
265 |
"section": "section_unrecognised_file_scan",
|
266 |
"default": "N",
|
267 |
"type": "checkbox",
|
268 |
+
"link_info": "https://icwp.io/95",
|
269 |
"link_blog": "",
|
270 |
"name": "Scan Uploads",
|
271 |
"summary": "Scan Uploads Folder For PHP and Javascript",
|
285 |
"mail.log"
|
286 |
],
|
287 |
"type": "array",
|
288 |
+
"link_info": "https://icwp.io/9z",
|
289 |
+
"link_blog": "https://icwp.io/95",
|
290 |
"name": "File Exclusions",
|
291 |
"summary": "Provide A List Of Files To Be Excluded From The Scan",
|
292 |
"description": "Take a new line for each file you wish to exclude from the scan. No commas are necessary."
|
329 |
"text": "Scan Enabled"
|
330 |
}
|
331 |
],
|
332 |
+
"link_info": "https://icwp.io/bl",
|
333 |
+
"link_blog": "https://icwp.io/bm",
|
334 |
"name": "Enable/Disable Guard",
|
335 |
"summary": "Enable The Guard For Plugin And Theme Files",
|
336 |
"description": "When enabled the Guard will automatically scan for changes to your Plugin and Theme files."
|
341 |
"type": "integer",
|
342 |
"default": 1,
|
343 |
"min": 0,
|
344 |
+
"link_info": "https://icwp.io/bn",
|
345 |
+
"link_blog": "https://icwp.io/bm",
|
346 |
"name": "Guard/Scan Depth",
|
347 |
"summary": "How Deep Into The Plugin Directories To Scan And Guard",
|
348 |
"description": "The Guard normally operates scan only the top level of a plugin folder. Increasing depth increases scan times."
|
358 |
"htaccess"
|
359 |
],
|
360 |
"type": "array",
|
361 |
+
"link_info": "https://icwp.io/bo",
|
362 |
"link_blog": "",
|
363 |
"name": "File Types",
|
364 |
"summary": "The File Types Included In The Scan",
|
369 |
"section": "section_pluginthemes_guard",
|
370 |
"type": "checkbox",
|
371 |
"default": "Y",
|
372 |
+
"link_info": "https://icwp.io/bp",
|
373 |
"link_blog": "",
|
374 |
"name": "Show Re-Install Links",
|
375 |
"summary": "Show Re-Install Links For Plugins",
|
src/config/feature-headers.php
CHANGED
@@ -51,8 +51,8 @@
|
|
51 |
"section": "section_enable_plugin_feature_headers",
|
52 |
"default": "Y",
|
53 |
"type": "checkbox",
|
54 |
-
"link_info": "
|
55 |
-
"link_blog": "
|
56 |
"name": "Enable HTTP Headers",
|
57 |
"summary": "Enable (or Disable) The HTTP Headers module",
|
58 |
"description": "Un-Checking this option will completely disable the HTTP Headers module"
|
@@ -76,8 +76,8 @@
|
|
76 |
"text": "On: Block All iFrames"
|
77 |
}
|
78 |
],
|
79 |
-
"link_info": "
|
80 |
-
"link_blog": "
|
81 |
"name": "Block iFrames",
|
82 |
"summary": "Block Remote iFrames Of This Site",
|
83 |
"description": "The setting prevents any external website from embedding your site in an iFrame. This is useful for preventing so-called ClickJack attacks."
|
@@ -87,8 +87,8 @@
|
|
87 |
"section": "section_security_headers",
|
88 |
"default": "Y",
|
89 |
"type": "checkbox",
|
90 |
-
"link_info": "
|
91 |
-
"link_blog": "
|
92 |
"name": "XSS Protection",
|
93 |
"summary": "Employ Built-In Browser XSS Protection",
|
94 |
"description": "Directs compatible browsers to block what they detect as Reflective XSS attacks."
|
@@ -98,8 +98,8 @@
|
|
98 |
"section": "section_security_headers",
|
99 |
"default": "Y",
|
100 |
"type": "checkbox",
|
101 |
-
"link_info": "
|
102 |
-
"link_blog": "
|
103 |
"name": "Prevent Mime-Sniff",
|
104 |
"summary": "Turn-Off Browser Mime-Sniff",
|
105 |
"description": "Reduces visitor exposure to malicious user-uploaded content."
|
@@ -152,7 +152,7 @@
|
|
152 |
"text": "Don't Send This Header"
|
153 |
}
|
154 |
],
|
155 |
-
"link_info": "
|
156 |
"link_blog": "",
|
157 |
"name": "Referrer Policy",
|
158 |
"summary": "Referrer Policy Header",
|
@@ -163,8 +163,8 @@
|
|
163 |
"section": "section_content_security_policy",
|
164 |
"default": "N",
|
165 |
"type": "checkbox",
|
166 |
-
"link_info": "
|
167 |
-
"link_blog": "
|
168 |
"name": "Enable Content Security Policy",
|
169 |
"summary": "Enable (or Disable) The Content Security Policy module",
|
170 |
"description": "Allows for permission and restriction of all resources loaded on your site."
|
51 |
"section": "section_enable_plugin_feature_headers",
|
52 |
"default": "Y",
|
53 |
"type": "checkbox",
|
54 |
+
"link_info": "https://icwp.io/7c",
|
55 |
+
"link_blog": "https://icwp.io/7c",
|
56 |
"name": "Enable HTTP Headers",
|
57 |
"summary": "Enable (or Disable) The HTTP Headers module",
|
58 |
"description": "Un-Checking this option will completely disable the HTTP Headers module"
|
76 |
"text": "On: Block All iFrames"
|
77 |
}
|
78 |
],
|
79 |
+
"link_info": "https://icwp.io/78",
|
80 |
+
"link_blog": "https://icwp.io/7c",
|
81 |
"name": "Block iFrames",
|
82 |
"summary": "Block Remote iFrames Of This Site",
|
83 |
"description": "The setting prevents any external website from embedding your site in an iFrame. This is useful for preventing so-called ClickJack attacks."
|
87 |
"section": "section_security_headers",
|
88 |
"default": "Y",
|
89 |
"type": "checkbox",
|
90 |
+
"link_info": "https://icwp.io/79",
|
91 |
+
"link_blog": "https://icwp.io/7c",
|
92 |
"name": "XSS Protection",
|
93 |
"summary": "Employ Built-In Browser XSS Protection",
|
94 |
"description": "Directs compatible browsers to block what they detect as Reflective XSS attacks."
|
98 |
"section": "section_security_headers",
|
99 |
"default": "Y",
|
100 |
"type": "checkbox",
|
101 |
+
"link_info": "https://icwp.io/7a",
|
102 |
+
"link_blog": "https://icwp.io/7c",
|
103 |
"name": "Prevent Mime-Sniff",
|
104 |
"summary": "Turn-Off Browser Mime-Sniff",
|
105 |
"description": "Reduces visitor exposure to malicious user-uploaded content."
|
152 |
"text": "Don't Send This Header"
|
153 |
}
|
154 |
],
|
155 |
+
"link_info": "https://icwp.io/a5",
|
156 |
"link_blog": "",
|
157 |
"name": "Referrer Policy",
|
158 |
"summary": "Referrer Policy Header",
|
163 |
"section": "section_content_security_policy",
|
164 |
"default": "N",
|
165 |
"type": "checkbox",
|
166 |
+
"link_info": "https://icwp.io/7d",
|
167 |
+
"link_blog": "https://icwp.io/7c",
|
168 |
"name": "Enable Content Security Policy",
|
169 |
"summary": "Enable (or Disable) The Content Security Policy module",
|
170 |
"description": "Allows for permission and restriction of all resources loaded on your site."
|
src/config/feature-ips.php
CHANGED
@@ -85,7 +85,7 @@
|
|
85 |
"section": "section_enable_plugin_feature_ips",
|
86 |
"default": "Y",
|
87 |
"type": "checkbox",
|
88 |
-
"link_info": "
|
89 |
"link_blog": "",
|
90 |
"name": "Enable IP Manager",
|
91 |
"summary": "Enable (or Disable) The IP Manager module",
|
@@ -96,8 +96,8 @@
|
|
96 |
"section": "section_auto_black_list",
|
97 |
"default": 10,
|
98 |
"type": "integer",
|
99 |
-
"link_info": "
|
100 |
-
"link_blog": "
|
101 |
"name": "Transgression Limit",
|
102 |
"summary": "Visitor IP address will be Black Listed after X bad actions on your site",
|
103 |
"description": "A black mark is set against an IP address each time a visitor trips the defenses of the Shield plugin. When the number of these transgressions exceeds specified limit, they are automatically blocked from accessing the site. Set this to 0 to turn off the Automatic IP Black List feature."
|
@@ -125,8 +125,8 @@
|
|
125 |
"text": "Week"
|
126 |
}
|
127 |
],
|
128 |
-
"link_info": "
|
129 |
-
"link_blog": "
|
130 |
"name": "Auto Block Expiration",
|
131 |
"summary": "After 1 'X' a black listed IP will be removed from the black list",
|
132 |
"description": "Permanent and lengthy IP Black Lists are harmful to performance. You should allow IP addresses on the black list to be eventually removed over time. Shorter IP black lists are more efficient and a more intelligent use of an IP-based blocking system."
|
85 |
"section": "section_enable_plugin_feature_ips",
|
86 |
"default": "Y",
|
87 |
"type": "checkbox",
|
88 |
+
"link_info": "https://icwp.io/wpsf26",
|
89 |
"link_blog": "",
|
90 |
"name": "Enable IP Manager",
|
91 |
"summary": "Enable (or Disable) The IP Manager module",
|
96 |
"section": "section_auto_black_list",
|
97 |
"default": 10,
|
98 |
"type": "integer",
|
99 |
+
"link_info": "https://icwp.io/wpsf24",
|
100 |
+
"link_blog": "https://icwp.io/wpsf26",
|
101 |
"name": "Transgression Limit",
|
102 |
"summary": "Visitor IP address will be Black Listed after X bad actions on your site",
|
103 |
"description": "A black mark is set against an IP address each time a visitor trips the defenses of the Shield plugin. When the number of these transgressions exceeds specified limit, they are automatically blocked from accessing the site. Set this to 0 to turn off the Automatic IP Black List feature."
|
125 |
"text": "Week"
|
126 |
}
|
127 |
],
|
128 |
+
"link_info": "https://icwp.io/wpsf25",
|
129 |
+
"link_blog": "https://icwp.io/wpsf26",
|
130 |
"name": "Auto Block Expiration",
|
131 |
"summary": "After 1 'X' a black listed IP will be removed from the black list",
|
132 |
"description": "Permanent and lengthy IP Black Lists are harmful to performance. You should allow IP addresses on the black list to be eventually removed over time. Shorter IP black lists are more efficient and a more intelligent use of an IP-based blocking system."
|
src/config/feature-license.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
"slug": "license",
|
3 |
"properties": {
|
4 |
"slug": "license",
|
5 |
-
"name": "
|
6 |
"tagline": "The Best In WordPress Security, Only Better.",
|
7 |
"auto_enabled": true,
|
8 |
"show_module_menu_item": true,
|
@@ -126,7 +126,7 @@
|
|
126 |
],
|
127 |
"definitions": {
|
128 |
"license_store_url": "https://onedollarplugin.com/edd-sl/",
|
129 |
-
"keyless_cp": "
|
130 |
"license_item_name": "Shield Security Pro",
|
131 |
"license_item_id": "6047",
|
132 |
"license_item_name_sc": "Shield Security Pro (via Shield Central)",
|
2 |
"slug": "license",
|
3 |
"properties": {
|
4 |
"slug": "license",
|
5 |
+
"name": "Pro Security",
|
6 |
"tagline": "The Best In WordPress Security, Only Better.",
|
7 |
"auto_enabled": true,
|
8 |
"show_module_menu_item": true,
|
126 |
],
|
127 |
"definitions": {
|
128 |
"license_store_url": "https://onedollarplugin.com/edd-sl/",
|
129 |
+
"keyless_cp": "https://icwp.io/c5",
|
130 |
"license_item_name": "Shield Security Pro",
|
131 |
"license_item_id": "6047",
|
132 |
"license_item_name_sc": "Shield Security Pro (via Shield Central)",
|
src/config/feature-lockdown.php
CHANGED
@@ -60,7 +60,7 @@
|
|
60 |
"section": "section_enable_plugin_feature_wordpress_lockdown",
|
61 |
"default": "Y",
|
62 |
"type": "checkbox",
|
63 |
-
"link_info": "
|
64 |
"link_blog": "",
|
65 |
"name": "Enable Lockdown",
|
66 |
"summary": "Enable (or Disable) The Lockdown module",
|
@@ -108,7 +108,7 @@
|
|
108 |
"section": "section_permission_access_options",
|
109 |
"default": "N",
|
110 |
"type": "checkbox",
|
111 |
-
"link_info": "
|
112 |
"link_blog": "",
|
113 |
"name": "Disable File Editing",
|
114 |
"summary": "Disable Ability To Edit Files From Within WordPress",
|
@@ -119,7 +119,7 @@
|
|
119 |
"section": "section_permission_access_options",
|
120 |
"default": "N",
|
121 |
"type": "checkbox",
|
122 |
-
"link_info": "
|
123 |
"link_blog": "",
|
124 |
"name": "Force SSL Admin",
|
125 |
"summary": "Forces WordPress Admin Dashboard To Be Delivered Over SSL",
|
@@ -130,7 +130,7 @@
|
|
130 |
"section": "section_wordpress_obscurity_options",
|
131 |
"default": "",
|
132 |
"type": "text",
|
133 |
-
"link_info": "
|
134 |
"link_blog": "",
|
135 |
"name": "Mask WordPress Version",
|
136 |
"summary": "Prevents Public Display Of Your WordPress Version",
|
@@ -152,7 +152,7 @@
|
|
152 |
"section": "section_wordpress_obscurity_options",
|
153 |
"default": "Y",
|
154 |
"type": "checkbox",
|
155 |
-
"link_info": "
|
156 |
"link_blog": "",
|
157 |
"name": "Block Username Fishing",
|
158 |
"summary": "Block the ability to discover WordPress usernames based on author IDs",
|
60 |
"section": "section_enable_plugin_feature_wordpress_lockdown",
|
61 |
"default": "Y",
|
62 |
"type": "checkbox",
|
63 |
+
"link_info": "https://icwp.io/4r",
|
64 |
"link_blog": "",
|
65 |
"name": "Enable Lockdown",
|
66 |
"summary": "Enable (or Disable) The Lockdown module",
|
108 |
"section": "section_permission_access_options",
|
109 |
"default": "N",
|
110 |
"type": "checkbox",
|
111 |
+
"link_info": "https://icwp.io/4q",
|
112 |
"link_blog": "",
|
113 |
"name": "Disable File Editing",
|
114 |
"summary": "Disable Ability To Edit Files From Within WordPress",
|
119 |
"section": "section_permission_access_options",
|
120 |
"default": "N",
|
121 |
"type": "checkbox",
|
122 |
+
"link_info": "https://icwp.io/4t",
|
123 |
"link_blog": "",
|
124 |
"name": "Force SSL Admin",
|
125 |
"summary": "Forces WordPress Admin Dashboard To Be Delivered Over SSL",
|
130 |
"section": "section_wordpress_obscurity_options",
|
131 |
"default": "",
|
132 |
"type": "text",
|
133 |
+
"link_info": "https://icwp.io/43",
|
134 |
"link_blog": "",
|
135 |
"name": "Mask WordPress Version",
|
136 |
"summary": "Prevents Public Display Of Your WordPress Version",
|
152 |
"section": "section_wordpress_obscurity_options",
|
153 |
"default": "Y",
|
154 |
"type": "checkbox",
|
155 |
+
"link_info": "https://icwp.io/wpsf23",
|
156 |
"link_blog": "",
|
157 |
"name": "Block Username Fishing",
|
158 |
"summary": "Block the ability to discover WordPress usernames based on author IDs",
|
src/config/feature-login_protect.php
CHANGED
@@ -117,8 +117,8 @@
|
|
117 |
"section": "section_enable_plugin_feature_login_protection",
|
118 |
"default": "Y",
|
119 |
"type": "checkbox",
|
120 |
-
"link_info": "
|
121 |
-
"link_blog": "
|
122 |
"name": "Enable Login Guard",
|
123 |
"summary": "Enable (or Disable) The Login Guard Module",
|
124 |
"description": "Un-Checking this option will completely disable the Login Guard module"
|
@@ -129,8 +129,8 @@
|
|
129 |
"sensitive": true,
|
130 |
"default": "",
|
131 |
"type": "text",
|
132 |
-
"link_info": "
|
133 |
-
"link_blog": "
|
134 |
"name": "Hide Login Page",
|
135 |
"summary": "Rename The WordPress Login Page",
|
136 |
"description": "Creating a path here will disable your 'wp-login.php'. Only letters and numbers are permitted: abc123"
|
@@ -140,8 +140,8 @@
|
|
140 |
"section": "section_multifactor_authentication",
|
141 |
"default": "N",
|
142 |
"type": "checkbox",
|
143 |
-
"link_info": "
|
144 |
-
"link_blog": "
|
145 |
"name": "Multi-Factor Authentication",
|
146 |
"summary": "Require All Active Authentication Factors",
|
147 |
"description": "When enabled, all multi-factor authentication methods will be applied to a user login. Disable to only require one to pass."
|
@@ -152,7 +152,7 @@
|
|
152 |
"premium": true,
|
153 |
"default": 0,
|
154 |
"type": "integer",
|
155 |
-
"link_info": "
|
156 |
"link_blog": "",
|
157 |
"name": "Multi-Factor By-Pass",
|
158 |
"summary": "A User Can By-Pass Multi-Factor Authentication (MFA) For The Set Number Of Days",
|
@@ -163,8 +163,8 @@
|
|
163 |
"section": "section_2fa_ga",
|
164 |
"default": "N",
|
165 |
"type": "checkbox",
|
166 |
-
"link_info": "
|
167 |
-
"link_blog": "
|
168 |
"name": "Enable Google Authenticator",
|
169 |
"summary": "Allow Users To Use Google Authenticator",
|
170 |
"description": "When enabled, users will have the option to add Google Authenticator to their WordPress user profile."
|
@@ -174,8 +174,8 @@
|
|
174 |
"section": "section_2fa_email",
|
175 |
"default": "N",
|
176 |
"type": "checkbox",
|
177 |
-
"link_info": "
|
178 |
-
"link_blog": "
|
179 |
"name": "Enable Email Authentication",
|
180 |
"summary": "Two-Factor Login Authentication By Email",
|
181 |
"description": "All users will be required to verify their login by email-based two-factor authentication."
|
@@ -212,93 +212,111 @@
|
|
212 |
"text": "Administrators"
|
213 |
}
|
214 |
],
|
215 |
-
"link_info": "
|
216 |
"link_blog": "",
|
217 |
"name": "Enforce - Email Authentication",
|
218 |
"summary": "All User Roles Subject To Email Authentication",
|
219 |
"description": "Enforces email-based authentication on all users with the selected roles. Note: This setting only applies to email authentication."
|
220 |
},
|
221 |
{
|
222 |
-
"key":
|
223 |
-
"section":
|
224 |
-
"
|
225 |
-
"
|
226 |
-
"link_info": "http://icwp.io/9m",
|
227 |
-
"link_blog": "http://icwp.io/shld5",
|
228 |
-
"name": "Google reCAPTCHA",
|
229 |
-
"summary": "Enable Google reCAPTCHA",
|
230 |
-
"description": "Use Google reCAPTCHA on the login screen."
|
231 |
-
},
|
232 |
-
{
|
233 |
-
"key": "google_recaptcha_style_login",
|
234 |
-
"section": "section_recaptcha",
|
235 |
-
"premium": true,
|
236 |
-
"default": "default",
|
237 |
-
"type": "select",
|
238 |
"value_options": [
|
239 |
{
|
240 |
-
"value_key": "
|
241 |
-
"text": "
|
242 |
},
|
243 |
{
|
244 |
-
"value_key": "
|
245 |
-
"text": "
|
246 |
},
|
247 |
{
|
248 |
-
"value_key": "
|
249 |
-
"text": "
|
250 |
},
|
251 |
{
|
252 |
-
"value_key": "
|
253 |
-
"text": "
|
254 |
}
|
255 |
],
|
256 |
"link_info": "",
|
257 |
"link_blog": "",
|
258 |
-
"name": "
|
259 |
"summary": "How Google reCAPTCHA Will Be Displayed",
|
260 |
-
"description": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
261 |
},
|
262 |
{
|
263 |
"key": "enable_login_gasp_check",
|
264 |
"section": "section_brute_force_login_protection",
|
265 |
"default": "N",
|
266 |
"type": "checkbox",
|
267 |
-
"link_info": "
|
268 |
-
"link_blog": "
|
269 |
"name": "Bot Protection",
|
270 |
"summary": "Protect WP Login From Automated Login Attempts By Bots",
|
271 |
"description": "Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques. Recommended: ON."
|
272 |
},
|
273 |
{
|
274 |
-
"key": "
|
275 |
"section": "section_brute_force_login_protection",
|
276 |
-
"default":
|
277 |
-
"type":
|
278 |
-
"
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
283 |
},
|
284 |
{
|
285 |
"key": "enable_user_register_checking",
|
286 |
-
"section": "
|
287 |
-
"default": "Y",
|
288 |
-
"type": "checkbox",
|
289 |
-
"link_info": "http://icwp.io/9p",
|
290 |
-
"link_blog": "",
|
291 |
-
"name": "User Registration",
|
292 |
-
"summary": "Apply Brute Force Protection To User Registration And Lost Passwords",
|
293 |
-
"description": "When enabled, settings in this section will also apply to new user registration and users trying to reset passwords."
|
294 |
},
|
295 |
{
|
296 |
"key": "enable_yubikey",
|
297 |
"section": "section_yubikey_authentication",
|
298 |
"default": "N",
|
299 |
"type": "checkbox",
|
300 |
-
"link_info": "
|
301 |
-
"link_blog": "
|
302 |
"name": "Enable Yubikey Authentication",
|
303 |
"summary": "Turn On / Off Yubikey Authentication On This Site",
|
304 |
"description": "Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication."
|
@@ -309,7 +327,7 @@
|
|
309 |
"sensitive": true,
|
310 |
"default": "",
|
311 |
"type": "text",
|
312 |
-
"link_info": "
|
313 |
"link_blog": "",
|
314 |
"name": "Yubikey App ID",
|
315 |
"summary": "Your Unique Yubikey App ID",
|
@@ -321,7 +339,7 @@
|
|
321 |
"sensitive": true,
|
322 |
"default": "",
|
323 |
"type": "text",
|
324 |
-
"link_info": "
|
325 |
"link_blog": "",
|
326 |
"name": "Yubikey API Key",
|
327 |
"summary": "Your Unique Yubikey App API Key",
|
117 |
"section": "section_enable_plugin_feature_login_protection",
|
118 |
"default": "Y",
|
119 |
"type": "checkbox",
|
120 |
+
"link_info": "https://icwp.io/51",
|
121 |
+
"link_blog": "https://icwp.io/wpsf03",
|
122 |
"name": "Enable Login Guard",
|
123 |
"summary": "Enable (or Disable) The Login Guard Module",
|
124 |
"description": "Un-Checking this option will completely disable the Login Guard module"
|
129 |
"sensitive": true,
|
130 |
"default": "",
|
131 |
"type": "text",
|
132 |
+
"link_info": "https://icwp.io/5q",
|
133 |
+
"link_blog": "https://icwp.io/5r",
|
134 |
"name": "Hide Login Page",
|
135 |
"summary": "Rename The WordPress Login Page",
|
136 |
"description": "Creating a path here will disable your 'wp-login.php'. Only letters and numbers are permitted: abc123"
|
140 |
"section": "section_multifactor_authentication",
|
141 |
"default": "N",
|
142 |
"type": "checkbox",
|
143 |
+
"link_info": "https://icwp.io/9r",
|
144 |
+
"link_blog": "https://icwp.io/84",
|
145 |
"name": "Multi-Factor Authentication",
|
146 |
"summary": "Require All Active Authentication Factors",
|
147 |
"description": "When enabled, all multi-factor authentication methods will be applied to a user login. Disable to only require one to pass."
|
152 |
"premium": true,
|
153 |
"default": 0,
|
154 |
"type": "integer",
|
155 |
+
"link_info": "https://icwp.io/b1",
|
156 |
"link_blog": "",
|
157 |
"name": "Multi-Factor By-Pass",
|
158 |
"summary": "A User Can By-Pass Multi-Factor Authentication (MFA) For The Set Number Of Days",
|
163 |
"section": "section_2fa_ga",
|
164 |
"default": "N",
|
165 |
"type": "checkbox",
|
166 |
+
"link_info": "https://icwp.io/shld7",
|
167 |
+
"link_blog": "https://icwp.io/shld6",
|
168 |
"name": "Enable Google Authenticator",
|
169 |
"summary": "Allow Users To Use Google Authenticator",
|
170 |
"description": "When enabled, users will have the option to add Google Authenticator to their WordPress user profile."
|
174 |
"section": "section_2fa_email",
|
175 |
"default": "N",
|
176 |
"type": "checkbox",
|
177 |
+
"link_info": "https://icwp.io/3t",
|
178 |
+
"link_blog": "https://icwp.io/9q",
|
179 |
"name": "Enable Email Authentication",
|
180 |
"summary": "Two-Factor Login Authentication By Email",
|
181 |
"description": "All users will be required to verify their login by email-based two-factor authentication."
|
212 |
"text": "Administrators"
|
213 |
}
|
214 |
],
|
215 |
+
"link_info": "https://icwp.io/4v",
|
216 |
"link_blog": "",
|
217 |
"name": "Enforce - Email Authentication",
|
218 |
"summary": "All User Roles Subject To Email Authentication",
|
219 |
"description": "Enforces email-based authentication on all users with the selected roles. Note: This setting only applies to email authentication."
|
220 |
},
|
221 |
{
|
222 |
+
"key": "bot_protection_locations",
|
223 |
+
"section": "section_brute_force_login_protection",
|
224 |
+
"type": "multiple_select",
|
225 |
+
"default": [ "login" ],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
"value_options": [
|
227 |
{
|
228 |
+
"value_key": "login",
|
229 |
+
"text": "Login"
|
230 |
},
|
231 |
{
|
232 |
+
"value_key": "register",
|
233 |
+
"text": "Register"
|
234 |
},
|
235 |
{
|
236 |
+
"value_key": "password",
|
237 |
+
"text": "Lost Password"
|
238 |
},
|
239 |
{
|
240 |
+
"value_key": "checkout_woo",
|
241 |
+
"text": "Checkout (WooCommerce)"
|
242 |
}
|
243 |
],
|
244 |
"link_info": "",
|
245 |
"link_blog": "",
|
246 |
+
"name": "Protection Locations",
|
247 |
"summary": "How Google reCAPTCHA Will Be Displayed",
|
248 |
+
"description": "Choose for which forms bot protection measures will be deployed."
|
249 |
+
},
|
250 |
+
{
|
251 |
+
"key": "login_limit_interval",
|
252 |
+
"section": "section_brute_force_login_protection",
|
253 |
+
"default": "10",
|
254 |
+
"type": "integer",
|
255 |
+
"link_info": "https://icwp.io/3q",
|
256 |
+
"link_blog": "https://icwp.io/9o",
|
257 |
+
"name": "Login Cooldown Interval",
|
258 |
+
"summary": "Limit login attempts to every X seconds",
|
259 |
+
"description": "WordPress will process only ONE login attempt for every number of seconds specified. Zero (0) turns this off."
|
260 |
},
|
261 |
{
|
262 |
"key": "enable_login_gasp_check",
|
263 |
"section": "section_brute_force_login_protection",
|
264 |
"default": "N",
|
265 |
"type": "checkbox",
|
266 |
+
"link_info": "https://icwp.io/3r",
|
267 |
+
"link_blog": "https://icwp.io/9n",
|
268 |
"name": "Bot Protection",
|
269 |
"summary": "Protect WP Login From Automated Login Attempts By Bots",
|
270 |
"description": "Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques. Recommended: ON."
|
271 |
},
|
272 |
{
|
273 |
+
"key": "enable_google_recaptcha_login",
|
274 |
"section": "section_brute_force_login_protection",
|
275 |
+
"default": "disabled",
|
276 |
+
"type": "select",
|
277 |
+
"value_options": [
|
278 |
+
{
|
279 |
+
"value_key": "disabled",
|
280 |
+
"text": "Disabled"
|
281 |
+
},
|
282 |
+
{
|
283 |
+
"value_key": "default",
|
284 |
+
"text": "Default Style"
|
285 |
+
},
|
286 |
+
{
|
287 |
+
"value_key": "light",
|
288 |
+
"text": "Light Theme"
|
289 |
+
},
|
290 |
+
{
|
291 |
+
"value_key": "dark",
|
292 |
+
"text": "Dark Theme"
|
293 |
+
},
|
294 |
+
{
|
295 |
+
"value_key": "invisible",
|
296 |
+
"text": "Invisible reCAPTCHA"
|
297 |
+
}
|
298 |
+
],
|
299 |
+
"link_info": "https://icwp.io/9m",
|
300 |
+
"link_blog": "https://icwp.io/shld5",
|
301 |
+
"name": "Google reCAPTCHA",
|
302 |
+
"summary": "Enable Google reCAPTCHA",
|
303 |
+
"description": "Use Google reCAPTCHA on the login screen."
|
304 |
+
},
|
305 |
+
{
|
306 |
+
"key": "google_recaptcha_style_login",
|
307 |
+
"section": "section_non_ui"
|
308 |
},
|
309 |
{
|
310 |
"key": "enable_user_register_checking",
|
311 |
+
"section": "section_non_ui"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
312 |
},
|
313 |
{
|
314 |
"key": "enable_yubikey",
|
315 |
"section": "section_yubikey_authentication",
|
316 |
"default": "N",
|
317 |
"type": "checkbox",
|
318 |
+
"link_info": "https://icwp.io/4f",
|
319 |
+
"link_blog": "https://icwp.io/9t",
|
320 |
"name": "Enable Yubikey Authentication",
|
321 |
"summary": "Turn On / Off Yubikey Authentication On This Site",
|
322 |
"description": "Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication."
|
327 |
"sensitive": true,
|
328 |
"default": "",
|
329 |
"type": "text",
|
330 |
+
"link_info": "https://icwp.io/4g",
|
331 |
"link_blog": "",
|
332 |
"name": "Yubikey App ID",
|
333 |
"summary": "Your Unique Yubikey App ID",
|
339 |
"sensitive": true,
|
340 |
"default": "",
|
341 |
"type": "text",
|
342 |
+
"link_info": "https://icwp.io/4g",
|
343 |
"link_blog": "",
|
344 |
"name": "Yubikey API Key",
|
345 |
"summary": "Your Unique Yubikey App API Key",
|
src/config/feature-plugin.php
CHANGED
@@ -111,7 +111,7 @@
|
|
111 |
"section": "section_general_plugin_options",
|
112 |
"default": "N",
|
113 |
"type": "checkbox",
|
114 |
-
"link_info": "
|
115 |
"link_blog": "",
|
116 |
"name": "Enable Information Gathering",
|
117 |
"summary": "Permit Anonymous Usage Information Gathering",
|
@@ -199,8 +199,8 @@
|
|
199 |
"section": "section_general_plugin_options",
|
200 |
"default": "N",
|
201 |
"type": "checkbox",
|
202 |
-
"link_info": "
|
203 |
-
"link_blog": "
|
204 |
"name": "Show Plugin Badge",
|
205 |
"summary": "Display Plugin Badge On Your Site",
|
206 |
"description": "Enabling this option helps support the plugin by spreading the word about it on your website. The plugin badge also demonstrates to visitors that you take your website security seriously."
|
@@ -318,7 +318,7 @@
|
|
318 |
"sensitive": true,
|
319 |
"default": "",
|
320 |
"type": "text",
|
321 |
-
"link_info": "
|
322 |
"link_blog": "",
|
323 |
"name": "reCAPTCHA Secret",
|
324 |
"summary": "Google reCAPTCHA Secret Key",
|
@@ -330,7 +330,7 @@
|
|
330 |
"sensitive": true,
|
331 |
"default": "",
|
332 |
"type": "text",
|
333 |
-
"link_info": "
|
334 |
"link_blog": "",
|
335 |
"name": "reCAPTCHA Site Key",
|
336 |
"summary": "Google reCAPTCHA Site Key",
|
@@ -398,7 +398,7 @@
|
|
398 |
"tracking_cron_handle": "plugin_tracking_cron",
|
399 |
"tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
|
400 |
"importexport_cron_name": "autoimport",
|
401 |
-
"href_privacy_policy": "
|
402 |
"db_notes_name": "notes",
|
403 |
"db_notes_table_columns": [
|
404 |
"id",
|
111 |
"section": "section_general_plugin_options",
|
112 |
"default": "N",
|
113 |
"type": "checkbox",
|
114 |
+
"link_info": "https://icwp.io/7i",
|
115 |
"link_blog": "",
|
116 |
"name": "Enable Information Gathering",
|
117 |
"summary": "Permit Anonymous Usage Information Gathering",
|
199 |
"section": "section_general_plugin_options",
|
200 |
"default": "N",
|
201 |
"type": "checkbox",
|
202 |
+
"link_info": "https://icwp.io/5v",
|
203 |
+
"link_blog": "https://icwp.io/wpsf20",
|
204 |
"name": "Show Plugin Badge",
|
205 |
"summary": "Display Plugin Badge On Your Site",
|
206 |
"description": "Enabling this option helps support the plugin by spreading the word about it on your website. The plugin badge also demonstrates to visitors that you take your website security seriously."
|
318 |
"sensitive": true,
|
319 |
"default": "",
|
320 |
"type": "text",
|
321 |
+
"link_info": "https://icwp.io/shld5",
|
322 |
"link_blog": "",
|
323 |
"name": "reCAPTCHA Secret",
|
324 |
"summary": "Google reCAPTCHA Secret Key",
|
330 |
"sensitive": true,
|
331 |
"default": "",
|
332 |
"type": "text",
|
333 |
+
"link_info": "https://icwp.io/shld5",
|
334 |
"link_blog": "",
|
335 |
"name": "reCAPTCHA Site Key",
|
336 |
"summary": "Google reCAPTCHA Site Key",
|
398 |
"tracking_cron_handle": "plugin_tracking_cron",
|
399 |
"tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
|
400 |
"importexport_cron_name": "autoimport",
|
401 |
+
"href_privacy_policy": "https://icwp.io/wpshieldprivacypolicy",
|
402 |
"db_notes_name": "notes",
|
403 |
"db_notes_table_columns": [
|
404 |
"id",
|
src/config/feature-user_management.php
CHANGED
@@ -70,6 +70,19 @@
|
|
70 |
"summary": "Enable (or Disable) The User Management module",
|
71 |
"description": "Un-Checking this option will completely disable the User Management module"
|
72 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
{
|
74 |
"key": "enable_admin_login_email_notification",
|
75 |
"section": "section_admin_login_notification",
|
@@ -131,7 +144,7 @@
|
|
131 |
"section": "section_passwords",
|
132 |
"type": "checkbox",
|
133 |
"default": "N",
|
134 |
-
"link_info": "
|
135 |
"link_blog": "",
|
136 |
"name": "Enable Password Policies",
|
137 |
"summary": "Enable The Password Policies Below",
|
@@ -142,7 +155,7 @@
|
|
142 |
"section": "section_passwords",
|
143 |
"type": "checkbox",
|
144 |
"default": "Y",
|
145 |
-
"link_info": "
|
146 |
"link_blog": "",
|
147 |
"name": "Prevent Pwned Passwords",
|
148 |
"summary": "Prevent Use Of Pwned Passwords",
|
@@ -241,6 +254,7 @@
|
|
241 |
}
|
242 |
],
|
243 |
"definitions": {
|
|
|
244 |
"pwned_api_url_password_single": "https://api.pwnedpasswords.com/pwnedpassword/",
|
245 |
"pwned_api_url_password_range": "https://api.pwnedpasswords.com/range/"
|
246 |
}
|
70 |
"summary": "Enable (or Disable) The User Management module",
|
71 |
"description": "Un-Checking this option will completely disable the User Management module"
|
72 |
},
|
73 |
+
{
|
74 |
+
"key": "enable_user_login_email_notification",
|
75 |
+
"section": "section_admin_login_notification",
|
76 |
+
"premium": true,
|
77 |
+
"sensitive": false,
|
78 |
+
"default": "N",
|
79 |
+
"type": "checkbox",
|
80 |
+
"link_info": "",
|
81 |
+
"link_blog": "",
|
82 |
+
"name": "User Login Notification Email",
|
83 |
+
"summary": "Send Email Notification To Each User Upon Successful Login",
|
84 |
+
"description": "A notification is sent to each user when a successful login occurs for their account."
|
85 |
+
},
|
86 |
{
|
87 |
"key": "enable_admin_login_email_notification",
|
88 |
"section": "section_admin_login_notification",
|
144 |
"section": "section_passwords",
|
145 |
"type": "checkbox",
|
146 |
"default": "N",
|
147 |
+
"link_info": "https://icwp.io/c4",
|
148 |
"link_blog": "",
|
149 |
"name": "Enable Password Policies",
|
150 |
"summary": "Enable The Password Policies Below",
|
155 |
"section": "section_passwords",
|
156 |
"type": "checkbox",
|
157 |
"default": "Y",
|
158 |
+
"link_info": "https://icwp.io/by",
|
159 |
"link_blog": "",
|
160 |
"name": "Prevent Pwned Passwords",
|
161 |
"summary": "Prevent Use Of Pwned Passwords",
|
254 |
}
|
255 |
],
|
256 |
"definitions": {
|
257 |
+
"cron_name_sessionscleanup": "sessionscleanup",
|
258 |
"pwned_api_url_password_single": "https://api.pwnedpasswords.com/pwnedpassword/",
|
259 |
"pwned_api_url_password_range": "https://api.pwnedpasswords.com/range/"
|
260 |
}
|
src/features/admin_access_restriction.php
CHANGED
@@ -247,12 +247,13 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
247 |
protected function setSaveUserResponse() {
|
248 |
if ( $this->isAccessKeyRequest() ) {
|
249 |
$bSuccess = $this->doCheckHasPermissionToSubmit();
|
|
|
|
|
250 |
if ( $bSuccess ) {
|
251 |
-
$sMessage = sprintf( _wpsf__( '%s Security Admin key accepted.' ),
|
252 |
}
|
253 |
else {
|
254 |
-
$sMessage = sprintf( _wpsf__( '%s Security Admin key not accepted.' ),
|
255 |
-
->getHumanName() );
|
256 |
}
|
257 |
$this->loadAdminNoticesProcessor()
|
258 |
->addFlashMessage( $sMessage, $bSuccess ? 'updated' : 'error' );
|
@@ -313,18 +314,20 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
313 |
* @return array
|
314 |
*/
|
315 |
public function getWhitelabelOptions() {
|
316 |
-
$sMain = $this->getOpt( '
|
317 |
$sMenu = $this->getOpt( 'wl_namemenu' );
|
318 |
if ( empty( $sMenu ) ) {
|
319 |
$sMenu = $sMain;
|
320 |
}
|
321 |
|
322 |
return array(
|
323 |
-
'name_main'
|
324 |
-
'name_menu'
|
325 |
-
'
|
326 |
-
'
|
327 |
-
'
|
|
|
|
|
328 |
);
|
329 |
}
|
330 |
|
@@ -401,6 +404,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
401 |
protected function loadStrings_SectionTitles( $aOptionsParams ) {
|
402 |
|
403 |
$sSectionSlug = $aOptionsParams[ 'slug' ];
|
|
|
404 |
switch ( $sSectionSlug ) {
|
405 |
|
406 |
case 'section_enable_plugin_feature_admin_access_restriction' :
|
@@ -432,11 +436,18 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
432 |
break;
|
433 |
|
434 |
case 'section_whitelabel' :
|
435 |
-
$sTitle = _wpsf__( '
|
436 |
$aSummary = array(
|
437 |
-
sprintf(
|
|
|
438 |
sprintf( _wpsf__( 'Rename and re-brand the %s plugin for your client site installations.' ),
|
439 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
440 |
);
|
441 |
$sTitleShort = _wpsf__( 'White Label' );
|
442 |
break;
|
@@ -458,6 +469,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
458 |
protected function loadStrings_Options( $aOptionsParams ) {
|
459 |
|
460 |
$sKey = $aOptionsParams[ 'key' ];
|
|
|
461 |
switch ( $sKey ) {
|
462 |
|
463 |
case 'enable_admin_access_restriction' :
|
@@ -533,9 +545,9 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
533 |
case 'wl_hide_updates' :
|
534 |
$sName = _wpsf__( 'Hide Updates' );
|
535 |
$sSummary = _wpsf__( 'Hide Plugin Updates From Non-Security Admins' );
|
536 |
-
$sDescription = _wpsf__( '
|
537 |
break;
|
538 |
-
case '
|
539 |
$sName = _wpsf__( 'Plugin Name' );
|
540 |
$sSummary = _wpsf__( 'The Name Of The Plugin' );
|
541 |
$sDescription = _wpsf__( 'The name of the plugin that will be displayed to your site users.' );
|
@@ -545,6 +557,11 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
545 |
$sSummary = _wpsf__( 'The Main Menu Title Of The Plugin' );
|
546 |
$sDescription = sprintf( _wpsf__( 'The Main Menu Title Of The Plugin. If left empty, the "%s" will be used.' ), _wpsf__( 'Plugin Name' ) );
|
547 |
break;
|
|
|
|
|
|
|
|
|
|
|
548 |
case 'wl_description' :
|
549 |
$sName = _wpsf__( 'Description' );
|
550 |
$sSummary = _wpsf__( 'The Description Of The Plugin' );
|
@@ -555,10 +572,17 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
555 |
$sSummary = _wpsf__( 'Plugin Home Page URL' );
|
556 |
$sDescription = _wpsf__( "When a user clicks the home link for this plugin, this is where they'll be directed." );
|
557 |
break;
|
558 |
-
case '
|
559 |
-
$sName = _wpsf__( 'Icon
|
560 |
-
$sSummary = _wpsf__( '
|
561 |
-
$sDescription = _wpsf__( 'The URL of the icon
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
562 |
break;
|
563 |
|
564 |
default:
|
@@ -576,10 +600,6 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
576 |
*/
|
577 |
protected function doPrePluginOptionsSave() {
|
578 |
|
579 |
-
if ( $this->getOpt( 'admin_access_timeout' ) < 1 ) {
|
580 |
-
$this->getOptionsVo()->resetOptToDefault( 'admin_access_timeout' );
|
581 |
-
}
|
582 |
-
|
583 |
// Restricting Activate Plugins also means restricting the rest.
|
584 |
$aPluginsRestrictions = $this->getAdminAccessArea_Plugins();
|
585 |
if ( in_array( 'activate_plugins', $aPluginsRestrictions ) ) {
|
@@ -613,5 +633,12 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
|
|
613 |
array_unique( array_merge( $aPostRestrictions, array( 'create', 'publish', 'delete' ) ) )
|
614 |
);
|
615 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
616 |
}
|
617 |
}
|
247 |
protected function setSaveUserResponse() {
|
248 |
if ( $this->isAccessKeyRequest() ) {
|
249 |
$bSuccess = $this->doCheckHasPermissionToSubmit();
|
250 |
+
|
251 |
+
$sPluginName = $this->getConn()->getHumanName();
|
252 |
if ( $bSuccess ) {
|
253 |
+
$sMessage = sprintf( _wpsf__( '%s Security Admin key accepted.' ), $sPluginName );
|
254 |
}
|
255 |
else {
|
256 |
+
$sMessage = sprintf( _wpsf__( '%s Security Admin key not accepted.' ), $sPluginName );
|
|
|
257 |
}
|
258 |
$this->loadAdminNoticesProcessor()
|
259 |
->addFlashMessage( $sMessage, $bSuccess ? 'updated' : 'error' );
|
314 |
* @return array
|
315 |
*/
|
316 |
public function getWhitelabelOptions() {
|
317 |
+
$sMain = $this->getOpt( 'wl_pluginnamemain' );
|
318 |
$sMenu = $this->getOpt( 'wl_namemenu' );
|
319 |
if ( empty( $sMenu ) ) {
|
320 |
$sMenu = $sMain;
|
321 |
}
|
322 |
|
323 |
return array(
|
324 |
+
'name_main' => $sMain,
|
325 |
+
'name_menu' => $sMenu,
|
326 |
+
'name_company' => $this->getOpt( 'wl_companyname' ),
|
327 |
+
'description' => $this->getOpt( 'wl_description' ),
|
328 |
+
'url_home' => $this->getOpt( 'wl_homeurl' ),
|
329 |
+
'url_icon' => $this->getOpt( 'wl_menuiconurl' ),
|
330 |
+
'url_dashboardlogourl' => $this->getOpt( 'wl_dashboardlogourl' ),
|
331 |
);
|
332 |
}
|
333 |
|
404 |
protected function loadStrings_SectionTitles( $aOptionsParams ) {
|
405 |
|
406 |
$sSectionSlug = $aOptionsParams[ 'slug' ];
|
407 |
+
$sPluginName = $this->getConn()->getHumanName();
|
408 |
switch ( $sSectionSlug ) {
|
409 |
|
410 |
case 'section_enable_plugin_feature_admin_access_restriction' :
|
436 |
break;
|
437 |
|
438 |
case 'section_whitelabel' :
|
439 |
+
$sTitle = _wpsf__( 'White Label' );
|
440 |
$aSummary = array(
|
441 |
+
sprintf( '%s - %s',
|
442 |
+
_wpsf__( 'Purpose' ),
|
443 |
sprintf( _wpsf__( 'Rename and re-brand the %s plugin for your client site installations.' ),
|
444 |
+
$sPluginName )
|
445 |
+
),
|
446 |
+
sprintf( '%s - %s',
|
447 |
+
_wpsf__( 'Important' ),
|
448 |
+
sprintf( _wpsf__( 'The Security Admin system must be active for these settings to apply.' ),
|
449 |
+
$sPluginName )
|
450 |
+
)
|
451 |
);
|
452 |
$sTitleShort = _wpsf__( 'White Label' );
|
453 |
break;
|
469 |
protected function loadStrings_Options( $aOptionsParams ) {
|
470 |
|
471 |
$sKey = $aOptionsParams[ 'key' ];
|
472 |
+
$sPluginName = $this->getConn()->getHumanName();
|
473 |
switch ( $sKey ) {
|
474 |
|
475 |
case 'enable_admin_access_restriction' :
|
545 |
case 'wl_hide_updates' :
|
546 |
$sName = _wpsf__( 'Hide Updates' );
|
547 |
$sSummary = _wpsf__( 'Hide Plugin Updates From Non-Security Admins' );
|
548 |
+
$sDescription = sprintf( _wpsf__( 'Hide available %s updates from non-security administrators.' ), $sPluginName );
|
549 |
break;
|
550 |
+
case 'wl_pluginnamemain' :
|
551 |
$sName = _wpsf__( 'Plugin Name' );
|
552 |
$sSummary = _wpsf__( 'The Name Of The Plugin' );
|
553 |
$sDescription = _wpsf__( 'The name of the plugin that will be displayed to your site users.' );
|
557 |
$sSummary = _wpsf__( 'The Main Menu Title Of The Plugin' );
|
558 |
$sDescription = sprintf( _wpsf__( 'The Main Menu Title Of The Plugin. If left empty, the "%s" will be used.' ), _wpsf__( 'Plugin Name' ) );
|
559 |
break;
|
560 |
+
case 'wl_companyname' :
|
561 |
+
$sName = _wpsf__( 'Company Name' );
|
562 |
+
$sSummary = _wpsf__( 'The Name Of Your Company' );
|
563 |
+
$sDescription = _wpsf__( 'Provide the name of your company.' );
|
564 |
+
break;
|
565 |
case 'wl_description' :
|
566 |
$sName = _wpsf__( 'Description' );
|
567 |
$sSummary = _wpsf__( 'The Description Of The Plugin' );
|
572 |
$sSummary = _wpsf__( 'Plugin Home Page URL' );
|
573 |
$sDescription = _wpsf__( "When a user clicks the home link for this plugin, this is where they'll be directed." );
|
574 |
break;
|
575 |
+
case 'wl_menuiconurl' :
|
576 |
+
$sName = _wpsf__( 'Menu Icon' );
|
577 |
+
$sSummary = _wpsf__( 'Menu Icon URL' );
|
578 |
+
$sDescription = _wpsf__( 'The URL of the icon to display in the menu.' )
|
579 |
+
.' '.sprintf( _wpsf__( 'The %s should measure %s.' ), _wpsf__( 'icon' ), '32px x 32px' );
|
580 |
+
break;
|
581 |
+
case 'wl_dashboardlogourl' :
|
582 |
+
$sName = _wpsf__( 'Dashboard Logo' );
|
583 |
+
$sSummary = _wpsf__( 'Dashboard Logo URL' );
|
584 |
+
$sDescription = _wpsf__( 'The URL of the logo to display in the admin pages.' )
|
585 |
+
.' '.sprintf( _wpsf__( 'The %s should measure %s.' ), _wpsf__( 'logo' ), '128px x 128px' );
|
586 |
break;
|
587 |
|
588 |
default:
|
600 |
*/
|
601 |
protected function doPrePluginOptionsSave() {
|
602 |
|
|
|
|
|
|
|
|
|
603 |
// Restricting Activate Plugins also means restricting the rest.
|
604 |
$aPluginsRestrictions = $this->getAdminAccessArea_Plugins();
|
605 |
if ( in_array( 'activate_plugins', $aPluginsRestrictions ) ) {
|
633 |
array_unique( array_merge( $aPostRestrictions, array( 'create', 'publish', 'delete' ) ) )
|
634 |
);
|
635 |
}
|
636 |
+
|
637 |
+
if ( !filter_var( $this->getOpt( 'wl_menuiconurl' ), FILTER_VALIDATE_URL ) ) {
|
638 |
+
$this->setOpt( 'wl_menuiconurl', '' );
|
639 |
+
}
|
640 |
+
if ( !filter_var( $this->getOpt( 'wl_dashboardlogourl' ), FILTER_VALIDATE_URL ) ) {
|
641 |
+
$this->setOpt( 'wl_dashboardlogourl', '' );
|
642 |
+
}
|
643 |
}
|
644 |
}
|
src/features/audit_trail.php
CHANGED
@@ -162,7 +162,7 @@ class ICWP_WPSF_FeatureHandler_AuditTrail extends ICWP_WPSF_FeatureHandler_BaseW
|
|
162 |
protected function getContentCustomActionsData() {
|
163 |
$aContexts = array(
|
164 |
'all' => 'All', //special
|
165 |
-
'wpsf' =>
|
166 |
'wordpress' => 'WordPress',
|
167 |
'users' => 'Users',
|
168 |
'posts' => 'Posts',
|
@@ -277,7 +277,7 @@ class ICWP_WPSF_FeatureHandler_AuditTrail extends ICWP_WPSF_FeatureHandler_BaseW
|
|
277 |
->setColumns( array( 'wp_username' ) )
|
278 |
->setResultsAsVo( false )
|
279 |
->all();
|
280 |
-
$aData[ 'messages' ][] = '
|
281 |
}
|
282 |
catch ( Exception $oE ) {
|
283 |
}
|
162 |
protected function getContentCustomActionsData() {
|
163 |
$aContexts = array(
|
164 |
'all' => 'All', //special
|
165 |
+
'wpsf' => $this->getConn()->getHumanName(),
|
166 |
'wordpress' => 'WordPress',
|
167 |
'users' => 'Users',
|
168 |
'posts' => 'Posts',
|
277 |
->setColumns( array( 'wp_username' ) )
|
278 |
->setResultsAsVo( false )
|
279 |
->all();
|
280 |
+
$aData[ 'messages' ][] = sprintf( '%s Audit Entries deleted', $this->getConn()->getHumanName() );
|
281 |
}
|
282 |
catch ( Exception $oE ) {
|
283 |
}
|
src/features/autoupdates.php
CHANGED
@@ -237,6 +237,7 @@ class ICWP_WPSF_FeatureHandler_Autoupdates extends ICWP_WPSF_FeatureHandler_Base
|
|
237 |
protected function loadStrings_Options( $aOptionsParams ) {
|
238 |
|
239 |
$sKey = $aOptionsParams[ 'key' ];
|
|
|
240 |
switch ( $sKey ) {
|
241 |
|
242 |
case 'enable_autoupdates' :
|
@@ -309,7 +310,7 @@ class ICWP_WPSF_FeatureHandler_Autoupdates extends ICWP_WPSF_FeatureHandler_Base
|
|
309 |
case 'update_delay' :
|
310 |
$sName = _wpsf__( 'Update Delay' );
|
311 |
$sSummary = _wpsf__( 'Delay Automatic Updates For Period Of Stability' );
|
312 |
-
$sDescription = _wpsf__( '
|
313 |
.'<br />'._wpsf__( "This helps ensure updates are more stable before they're automatically applied to your site." );
|
314 |
break;
|
315 |
|
237 |
protected function loadStrings_Options( $aOptionsParams ) {
|
238 |
|
239 |
$sKey = $aOptionsParams[ 'key' ];
|
240 |
+
$sPlugName = $this->getConn()->getHumanName();
|
241 |
switch ( $sKey ) {
|
242 |
|
243 |
case 'enable_autoupdates' :
|
310 |
case 'update_delay' :
|
311 |
$sName = _wpsf__( 'Update Delay' );
|
312 |
$sSummary = _wpsf__( 'Delay Automatic Updates For Period Of Stability' );
|
313 |
+
$sDescription = sprintf( _wpsf__( '%s will delay upgrades until the new update has been available for the set number of days.' ), $sPlugName )
|
314 |
.'<br />'._wpsf__( "This helps ensure updates are more stable before they're automatically applied to your site." );
|
315 |
break;
|
316 |
|
src/features/base.php
CHANGED
@@ -60,6 +60,11 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
|
|
60 |
*/
|
61 |
protected static $bForceOffFileExists;
|
62 |
|
|
|
|
|
|
|
|
|
|
|
63 |
/**
|
64 |
* @var ICWP_WPSF_FeatureHandler_Email
|
65 |
*/
|
@@ -118,7 +123,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
|
|
118 |
}
|
119 |
|
120 |
$nMenuPriority = isset( $aModProps[ 'menu_priority' ] ) ? $aModProps[ 'menu_priority' ] : 100;
|
121 |
-
add_filter( $this->prefix( '
|
122 |
add_filter( $this->prefix( 'collect_module_summary_data' ), array( $this, 'addModuleSummaryData' ), $nMenuPriority );
|
123 |
add_filter( $this->prefix( 'collect_notices' ), array( $this, 'addInsightsNoticeData' ) );
|
124 |
add_action( $this->prefix( 'plugin_shutdown' ), array( $this, 'action_doFeatureShutdown' ) );
|
@@ -255,7 +260,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
|
|
255 |
if ( !empty( $aPhpReqs ) ) {
|
256 |
|
257 |
if ( !empty( $aPhpReqs[ 'version' ] ) ) {
|
258 |
-
$bMeetsReqs = $bMeetsReqs && $this->
|
259 |
->getPhpVersionIsAtLeast( $aPhpReqs[ 'version' ] );
|
260 |
}
|
261 |
if ( !empty( $aPhpReqs[ 'functions' ] ) && is_array( $aPhpReqs[ 'functions' ] ) ) {
|
@@ -334,7 +339,9 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
|
|
334 |
*/
|
335 |
public function onWpInit() {
|
336 |
$this->runWizards();
|
337 |
-
$this->
|
|
|
|
|
338 |
|
339 |
// GDPR
|
340 |
if ( $this->isPremium() ) {
|
@@ -567,7 +574,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
|
|
567 |
* @param array $aItems
|
568 |
* @return array
|
569 |
*/
|
570 |
-
public function
|
571 |
$sMenuTitleName = $this->getOptionsVo()->getFeatureProperty( 'menu_title' );
|
572 |
if ( is_null( $sMenuTitleName ) ) {
|
573 |
$sMenuTitleName = $this->getMainFeatureName();
|
@@ -907,6 +914,9 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
|
|
907 |
->setIsPremiumLicensed( $this->isPremium() )
|
908 |
->setNeedSave( true );
|
909 |
}
|
|
|
|
|
|
|
910 |
$this->store();
|
911 |
}
|
912 |
|
@@ -1298,7 +1308,15 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
|
|
1298 |
$this->setOpt( $sOptionKey, $sOptionValue );
|
1299 |
}
|
1300 |
}
|
|
|
1301 |
$this->savePluginOptions();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1302 |
}
|
1303 |
|
1304 |
/**
|
@@ -1481,8 +1499,8 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
|
|
1481 |
'has_wizard' => $this->hasWizard(),
|
1482 |
),
|
1483 |
'hrefs' => array(
|
1484 |
-
'go_pro' => '
|
1485 |
-
'goprofooter' => '
|
1486 |
'wizard_link' => $this->getUrl_WizardLanding(),
|
1487 |
'wizard_landing' => $this->getUrl_WizardLanding()
|
1488 |
),
|
60 |
*/
|
61 |
protected static $bForceOffFileExists;
|
62 |
|
63 |
+
/**
|
64 |
+
* @var boolean
|
65 |
+
*/
|
66 |
+
protected $bImportExportWhitelistNotify = false;
|
67 |
+
|
68 |
/**
|
69 |
* @var ICWP_WPSF_FeatureHandler_Email
|
70 |
*/
|
123 |
}
|
124 |
|
125 |
$nMenuPriority = isset( $aModProps[ 'menu_priority' ] ) ? $aModProps[ 'menu_priority' ] : 100;
|
126 |
+
add_filter( $this->prefix( 'submenu_items' ), array( $this, 'supplySubMenuItem' ), $nMenuPriority );
|
127 |
add_filter( $this->prefix( 'collect_module_summary_data' ), array( $this, 'addModuleSummaryData' ), $nMenuPriority );
|
128 |
add_filter( $this->prefix( 'collect_notices' ), array( $this, 'addInsightsNoticeData' ) );
|
129 |
add_action( $this->prefix( 'plugin_shutdown' ), array( $this, 'action_doFeatureShutdown' ) );
|
260 |
if ( !empty( $aPhpReqs ) ) {
|
261 |
|
262 |
if ( !empty( $aPhpReqs[ 'version' ] ) ) {
|
263 |
+
$bMeetsReqs = $bMeetsReqs && $this->loadDP()
|
264 |
->getPhpVersionIsAtLeast( $aPhpReqs[ 'version' ] );
|
265 |
}
|
266 |
if ( !empty( $aPhpReqs[ 'functions' ] ) && is_array( $aPhpReqs[ 'functions' ] ) ) {
|
339 |
*/
|
340 |
public function onWpInit() {
|
341 |
$this->runWizards();
|
342 |
+
if ( $this->getIsUpgrading() ) {
|
343 |
+
$this->updateHandler();
|
344 |
+
}
|
345 |
|
346 |
// GDPR
|
347 |
if ( $this->isPremium() ) {
|
574 |
* @param array $aItems
|
575 |
* @return array
|
576 |
*/
|
577 |
+
public function supplySubMenuItem( $aItems ) {
|
578 |
$sMenuTitleName = $this->getOptionsVo()->getFeatureProperty( 'menu_title' );
|
579 |
if ( is_null( $sMenuTitleName ) ) {
|
580 |
$sMenuTitleName = $this->getMainFeatureName();
|
914 |
->setIsPremiumLicensed( $this->isPremium() )
|
915 |
->setNeedSave( true );
|
916 |
}
|
917 |
+
|
918 |
+
// we set the flag that options have been updated. (only use this flag if it's a MANUAL options update)
|
919 |
+
$this->bImportExportWhitelistNotify = $this->getOptionsVo()->getNeedSave();
|
920 |
$this->store();
|
921 |
}
|
922 |
|
1308 |
$this->setOpt( $sOptionKey, $sOptionValue );
|
1309 |
}
|
1310 |
}
|
1311 |
+
|
1312 |
$this->savePluginOptions();
|
1313 |
+
|
1314 |
+
// only use this flag when the options are being updated with a MANUAL save.
|
1315 |
+
if ( isset( $this->bImportExportWhitelistNotify ) && $this->bImportExportWhitelistNotify ) {
|
1316 |
+
if ( !wp_next_scheduled( $this->prefix( 'importexport_notify' ) ) ) {
|
1317 |
+
wp_schedule_single_event( $this->loadDP()->time() + 15, $this->prefix( 'importexport_notify' ) );
|
1318 |
+
}
|
1319 |
+
}
|
1320 |
}
|
1321 |
|
1322 |
/**
|
1499 |
'has_wizard' => $this->hasWizard(),
|
1500 |
),
|
1501 |
'hrefs' => array(
|
1502 |
+
'go_pro' => 'https://icwp.io/shieldgoprofeature',
|
1503 |
+
'goprofooter' => 'https://icwp.io/goprofooter',
|
1504 |
'wizard_link' => $this->getUrl_WizardLanding(),
|
1505 |
'wizard_landing' => $this->getUrl_WizardLanding()
|
1506 |
),
|
src/features/base_wpsf.php
CHANGED
@@ -43,7 +43,7 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
|
|
43 |
if ( !is_array( $aConfig ) ) {
|
44 |
$aConfig = array();
|
45 |
}
|
46 |
-
|
47 |
array(
|
48 |
'key' => '',
|
49 |
'secret' => '',
|
@@ -51,6 +51,10 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
|
|
51 |
),
|
52 |
$aConfig
|
53 |
);
|
|
|
|
|
|
|
|
|
54 |
}
|
55 |
|
56 |
/**
|
@@ -99,6 +103,13 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
|
|
99 |
return $aAjaxData;
|
100 |
}
|
101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
/**
|
103 |
* @param bool $bRenderEmbeddedContent
|
104 |
* @return array
|
@@ -136,7 +147,7 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
|
|
136 |
'has_session' => $this->hasSession()
|
137 |
),
|
138 |
'hrefs' => array(
|
139 |
-
'aar_forget_key' => '
|
140 |
)
|
141 |
)
|
142 |
);
|
43 |
if ( !is_array( $aConfig ) ) {
|
44 |
$aConfig = array();
|
45 |
}
|
46 |
+
$aConfig = array_merge(
|
47 |
array(
|
48 |
'key' => '',
|
49 |
'secret' => '',
|
51 |
),
|
52 |
$aConfig
|
53 |
);
|
54 |
+
if ( !$this->isPremium() && $aConfig[ 'style' ] != 'light' ) {
|
55 |
+
$aConfig[ 'style' ] = 'light'; // hard-coded light style for non-pro
|
56 |
+
}
|
57 |
+
return $aConfig;
|
58 |
}
|
59 |
|
60 |
/**
|
103 |
return $aAjaxData;
|
104 |
}
|
105 |
|
106 |
+
/**
|
107 |
+
* @return string
|
108 |
+
*/
|
109 |
+
public function getPluginDefaultRecipientAddress() {
|
110 |
+
return apply_filters( $this->prefix( 'report_email_address' ), $this->loadWp()->getSiteAdminEmail() );
|
111 |
+
}
|
112 |
+
|
113 |
/**
|
114 |
* @param bool $bRenderEmbeddedContent
|
115 |
* @return array
|
147 |
'has_session' => $this->hasSession()
|
148 |
),
|
149 |
'hrefs' => array(
|
150 |
+
'aar_forget_key' => 'https://icwp.io/b5',
|
151 |
)
|
152 |
)
|
153 |
);
|
src/features/headers.php
CHANGED
@@ -46,7 +46,7 @@ class ICWP_WPSF_FeatureHandler_Headers extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
46 |
protected function doExtraSubmitProcessing() {
|
47 |
$aDomains = $this->getCspHosts();
|
48 |
if ( !empty( $aDomains ) && is_array( $aDomains ) ) {
|
49 |
-
$oDP = $this->
|
50 |
$aValidDomains = array();
|
51 |
foreach ( $aDomains as $sDomain ) {
|
52 |
$bValidDomain = false;
|
46 |
protected function doExtraSubmitProcessing() {
|
47 |
$aDomains = $this->getCspHosts();
|
48 |
if ( !empty( $aDomains ) && is_array( $aDomains ) ) {
|
49 |
+
$oDP = $this->loadDP();
|
50 |
$aValidDomains = array();
|
51 |
foreach ( $aDomains as $sDomain ) {
|
52 |
$bValidDomain = false;
|
src/features/insights.php
CHANGED
@@ -44,8 +44,8 @@ class ICWP_WPSF_FeatureHandler_Insights extends ICWP_WPSF_FeatureHandler_BaseWps
|
|
44 |
'admin_notes_delete' => $this->getAjaxActionData( 'admin_notes_delete' ),
|
45 |
),
|
46 |
'hrefs' => array(
|
47 |
-
'shield_pro_url' => '
|
48 |
-
'shield_pro_more_info_url' => '
|
49 |
),
|
50 |
'flags' => array(
|
51 |
'has_audit_trail_entries' => !empty( $aRecentAuditTrail ),
|
@@ -115,7 +115,7 @@ class ICWP_WPSF_FeatureHandler_Insights extends ICWP_WPSF_FeatureHandler_BaseWps
|
|
115 |
|
116 |
$bSuccess = false;
|
117 |
if ( !$oMod->getCanAdminNotes() ) {
|
118 |
-
$sMessage = _wpsf__( 'Sorry, Admin Notes is only available for
|
119 |
}
|
120 |
else if ( empty( $sNote ) ) {
|
121 |
$sMessage = _wpsf__( 'Sorry, but it appears your note was empty.' );
|
@@ -187,12 +187,15 @@ class ICWP_WPSF_FeatureHandler_Insights extends ICWP_WPSF_FeatureHandler_BaseWps
|
|
187 |
* @return array
|
188 |
*/
|
189 |
protected function getDisplayStrings() {
|
|
|
190 |
return $this->loadDP()->mergeArraysRecursive(
|
191 |
parent::getDisplayStrings(),
|
192 |
array(
|
193 |
-
'
|
194 |
-
'
|
195 |
-
|
|
|
|
|
196 |
)
|
197 |
);
|
198 |
}
|
@@ -518,7 +521,7 @@ class ICWP_WPSF_FeatureHandler_Insights extends ICWP_WPSF_FeatureHandler_BaseWps
|
|
518 |
'pro' => array(
|
519 |
'title' => _wpsf__( 'Pro' ),
|
520 |
'val' => $this->isPremium() ? _wpsf__( 'Yes' ) : _wpsf__( 'No' ),
|
521 |
-
'tooltip' => _wpsf__( 'Is this site running
|
522 |
),
|
523 |
);
|
524 |
}
|
@@ -592,7 +595,7 @@ class ICWP_WPSF_FeatureHandler_Insights extends ICWP_WPSF_FeatureHandler_BaseWps
|
|
592 |
'insights_last_comment_block_at' => _wpsf__( 'Comment SPAM Block' ),
|
593 |
'insights_xml_block_at' => _wpsf__( 'XML-RPC Block' ),
|
594 |
'insights_restapi_block_at' => _wpsf__( 'Anonymous Rest API Block' ),
|
595 |
-
'insights_last_transgression_at' => _wpsf__( '
|
596 |
'insights_last_ip_block_at' => _wpsf__( 'IP Connection Blocked' ),
|
597 |
);
|
598 |
}
|
44 |
'admin_notes_delete' => $this->getAjaxActionData( 'admin_notes_delete' ),
|
45 |
),
|
46 |
'hrefs' => array(
|
47 |
+
'shield_pro_url' => 'https://icwp.io/shieldpro',
|
48 |
+
'shield_pro_more_info_url' => 'https://icwp.io/shld1',
|
49 |
),
|
50 |
'flags' => array(
|
51 |
'has_audit_trail_entries' => !empty( $aRecentAuditTrail ),
|
115 |
|
116 |
$bSuccess = false;
|
117 |
if ( !$oMod->getCanAdminNotes() ) {
|
118 |
+
$sMessage = _wpsf__( 'Sorry, Admin Notes is only available for Pro subscriptions.' );
|
119 |
}
|
120 |
else if ( empty( $sNote ) ) {
|
121 |
$sMessage = _wpsf__( 'Sorry, but it appears your note was empty.' );
|
187 |
* @return array
|
188 |
*/
|
189 |
protected function getDisplayStrings() {
|
190 |
+
$sName = $this->getConn()->getHumanName();
|
191 |
return $this->loadDP()->mergeArraysRecursive(
|
192 |
parent::getDisplayStrings(),
|
193 |
array(
|
194 |
+
'page_title' => sprintf( _wpsf__( '%s Security Insights' ), $sName ),
|
195 |
+
'recommendation' => ucfirst( _wpsf__( 'recommendation' ) ),
|
196 |
+
'suggestion' => ucfirst( _wpsf__( 'suggestion' ) ),
|
197 |
+
'box_welcome_title' => sprintf( _wpsf__( 'Welcome To %s Security Insights Dashboard' ), $sName ),
|
198 |
+
'box_receve_subtitle' => sprintf( _wpsf__( 'Some of the most recent %s events' ), $sName )
|
199 |
)
|
200 |
);
|
201 |
}
|
521 |
'pro' => array(
|
522 |
'title' => _wpsf__( 'Pro' ),
|
523 |
'val' => $this->isPremium() ? _wpsf__( 'Yes' ) : _wpsf__( 'No' ),
|
524 |
+
'tooltip' => sprintf( _wpsf__( 'Is this site running %s Pro' ), $oConn->getHumanName() )
|
525 |
),
|
526 |
);
|
527 |
}
|
595 |
'insights_last_comment_block_at' => _wpsf__( 'Comment SPAM Block' ),
|
596 |
'insights_xml_block_at' => _wpsf__( 'XML-RPC Block' ),
|
597 |
'insights_restapi_block_at' => _wpsf__( 'Anonymous Rest API Block' ),
|
598 |
+
'insights_last_transgression_at' => sprintf( _wpsf__( '%s Transgression' ), $this->getConn()->getHumanName() ),
|
599 |
'insights_last_ip_block_at' => _wpsf__( 'IP Connection Blocked' ),
|
600 |
);
|
601 |
}
|
src/features/license.php
CHANGED
@@ -57,8 +57,8 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
57 |
'connection_debug' => $this->getAjaxActionData( 'connection_debug' )
|
58 |
),
|
59 |
'aHrefs' => array(
|
60 |
-
'shield_pro_url' => '
|
61 |
-
'shield_pro_more_info_url' => '
|
62 |
'iframe_url' => $this->getDef( 'landing_page_url' ),
|
63 |
'keyless_cp' => $this->getDef( 'keyless_cp' ),
|
64 |
),
|
@@ -562,7 +562,8 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
562 |
* @return boolean
|
563 |
*/
|
564 |
public function getIfShowModuleMenuItem() {
|
565 |
-
return parent::getIfShowModuleMenuItem() && self::getConn()->isPremiumExtensionsEnabled()
|
|
|
566 |
}
|
567 |
|
568 |
/**
|
@@ -643,13 +644,14 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
643 |
*/
|
644 |
protected function loadStrings_SectionTitles( $aOptionsParams ) {
|
645 |
|
|
|
646 |
switch ( $aOptionsParams[ 'slug' ] ) {
|
647 |
|
648 |
case 'section_license_options' :
|
649 |
$sTitle = _wpsf__( 'License Options' );
|
650 |
$sTitleShort = _wpsf__( 'License Options' );
|
651 |
$aSummary = array(
|
652 |
-
sprintf( _wpsf__( 'Purpose - %s' ), _wpsf__( 'Activate
|
653 |
sprintf( _wpsf__( 'Recommendation - %s' ), _wpsf__( 'TODO.' ) )
|
654 |
);
|
655 |
break;
|
57 |
'connection_debug' => $this->getAjaxActionData( 'connection_debug' )
|
58 |
),
|
59 |
'aHrefs' => array(
|
60 |
+
'shield_pro_url' => 'https://icwp.io/shieldpro',
|
61 |
+
'shield_pro_more_info_url' => 'https://icwp.io/shld1',
|
62 |
'iframe_url' => $this->getDef( 'landing_page_url' ),
|
63 |
'keyless_cp' => $this->getDef( 'keyless_cp' ),
|
64 |
),
|
562 |
* @return boolean
|
563 |
*/
|
564 |
public function getIfShowModuleMenuItem() {
|
565 |
+
return parent::getIfShowModuleMenuItem() && self::getConn()->isPremiumExtensionsEnabled()
|
566 |
+
&& $this->getConn()->getHasPermissionToManage();
|
567 |
}
|
568 |
|
569 |
/**
|
644 |
*/
|
645 |
protected function loadStrings_SectionTitles( $aOptionsParams ) {
|
646 |
|
647 |
+
$sName = $this->getConn()->getHumanName();
|
648 |
switch ( $aOptionsParams[ 'slug' ] ) {
|
649 |
|
650 |
case 'section_license_options' :
|
651 |
$sTitle = _wpsf__( 'License Options' );
|
652 |
$sTitleShort = _wpsf__( 'License Options' );
|
653 |
$aSummary = array(
|
654 |
+
sprintf( _wpsf__( 'Purpose - %s' ), sprintf( _wpsf__( 'Activate %s Pro Extensions.' ), $sName ) ),
|
655 |
sprintf( _wpsf__( 'Recommendation - %s' ), _wpsf__( 'TODO.' ) )
|
656 |
);
|
657 |
break;
|
src/features/login_protect.php
CHANGED
@@ -62,11 +62,6 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
62 |
$this->getOptionsVo()->resetOptToDefault( 'login_limit_interval' );
|
63 |
}
|
64 |
|
65 |
-
$aTwoFactorAuthRoles = $this->getOpt( 'two_factor_auth_user_roles' );
|
66 |
-
if ( empty( $aTwoFactorAuthRoles ) || !is_array( $aTwoFactorAuthRoles ) ) {
|
67 |
-
$this->setOpt( 'two_factor_auth_user_roles', $this->getTwoFactorUserAuthRoles( true ) );
|
68 |
-
}
|
69 |
-
|
70 |
$this->cleanLoginUrlPath();
|
71 |
}
|
72 |
|
@@ -75,6 +70,27 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
75 |
if ( !is_numeric( $nSkipDays ) || $nSkipDays < 0 ) {
|
76 |
$this->getOptionsVo()->resetOptToDefault( 'mfa_skip' );
|
77 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
}
|
79 |
|
80 |
/**
|
@@ -121,7 +137,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
121 |
|
122 |
$sEmailSubject = _wpsf__( 'Email Sending Verification' );
|
123 |
return $this->getEmailProcessor()
|
124 |
-
->
|
125 |
}
|
126 |
|
127 |
/**
|
@@ -135,6 +151,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
135 |
}
|
136 |
|
137 |
/**
|
|
|
138 |
* @return bool
|
139 |
*/
|
140 |
public function getIsCheckingUserRegistrations() {
|
@@ -142,10 +159,51 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
142 |
}
|
143 |
|
144 |
/**
|
145 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
* @return array
|
147 |
*/
|
148 |
-
protected function
|
149 |
$aTwoAuthRoles = array(
|
150 |
'type' => 'multiple_select',
|
151 |
0 => _wpsf__( 'Subscribers' ),
|
@@ -154,7 +212,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
154 |
3 => _wpsf__( 'Editors' ),
|
155 |
8 => _wpsf__( 'Administrators' )
|
156 |
);
|
157 |
-
if ( $
|
158 |
unset( $aTwoAuthRoles[ 'type' ] );
|
159 |
unset( $aTwoAuthRoles[ 0 ] );
|
160 |
return array_keys( $aTwoAuthRoles );
|
@@ -303,8 +361,8 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
303 |
/**
|
304 |
* @return bool
|
305 |
*/
|
306 |
-
public function
|
307 |
-
return (
|
308 |
}
|
309 |
|
310 |
/**
|
@@ -332,6 +390,21 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
332 |
return $sStyle;
|
333 |
}
|
334 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
/**
|
336 |
* @return bool
|
337 |
*/
|
@@ -354,7 +427,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
354 |
public function setIfCanSendEmail( $bCan ) {
|
355 |
$nCurrentDateAt = $this->getCanSendEmailVerifiedAt();
|
356 |
if ( $bCan ) {
|
357 |
-
$nDateAt = ( $nCurrentDateAt <= 0 ) ? $this->
|
358 |
}
|
359 |
else {
|
360 |
$nDateAt = 0;
|
@@ -491,7 +564,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
491 |
|
492 |
case 'section_brute_force_login_protection' :
|
493 |
$sTitle = _wpsf__( 'Brute Force Login Protection' );
|
494 |
-
$sTitleShort = _wpsf__( '
|
495 |
$aSummary = array(
|
496 |
sprintf( _wpsf__( 'Purpose - %s' ), _wpsf__( 'Blocks brute force hacking attacks against your login and registration pages.' ) ),
|
497 |
sprintf( _wpsf__( 'Recommendation - %s' ), _wpsf__( 'Use of this feature is highly recommend.' ) )
|
@@ -575,8 +648,10 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
575 |
|
576 |
case 'enable_google_recaptcha_login' :
|
577 |
$sName = _wpsf__( 'Google reCAPTCHA' );
|
578 |
-
$sSummary = _wpsf__( '
|
579 |
-
$sDescription = _wpsf__( 'Use Google reCAPTCHA on the login
|
|
|
|
|
580 |
break;
|
581 |
|
582 |
case 'google_recaptcha_style_login' :
|
@@ -585,6 +660,13 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
585 |
$sDescription = _wpsf__( 'You can choose the reCAPTCHA display format that best suits your site, including the new Invisible Recaptcha' );
|
586 |
break;
|
587 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
588 |
case 'enable_login_gasp_check' :
|
589 |
$sName = _wpsf__( 'Bot Protection' );
|
590 |
$sSummary = _wpsf__( 'Protect WP Login From Automated Login Attempts By Bots' );
|
@@ -593,9 +675,9 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
|
|
593 |
break;
|
594 |
|
595 |
case 'login_limit_interval' :
|
596 |
-
$sName = _wpsf__( '
|
597 |
-
$sSummary = _wpsf__( 'Limit
|
598 |
-
$sDescription = _wpsf__( 'WordPress will process only ONE
|
599 |
.'<br />'._wpsf__( 'Zero (0) turns this off.' )
|
600 |
.' '.sprintf( _wpsf__( 'Default: "%s".' ), $this->getOptionsVo()
|
601 |
->getOptDefault( 'login_limit_interval' ) );
|
62 |
$this->getOptionsVo()->resetOptToDefault( 'login_limit_interval' );
|
63 |
}
|
64 |
|
|
|
|
|
|
|
|
|
|
|
65 |
$this->cleanLoginUrlPath();
|
66 |
}
|
67 |
|
70 |
if ( !is_numeric( $nSkipDays ) || $nSkipDays < 0 ) {
|
71 |
$this->getOptionsVo()->resetOptToDefault( 'mfa_skip' );
|
72 |
}
|
73 |
+
|
74 |
+
$this->updateHandler();
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
*/
|
79 |
+
protected function updateHandler() {
|
80 |
+
|
81 |
+
// v6.8.0: reCAPTCHA options restructure
|
82 |
+
|
83 |
+
// These can be removed eventually and are used to migrate old recaptcha settings to new structure
|
84 |
+
if ( $this->getOpt( 'enable_google_recaptcha_login' ) == 'Y' ) {
|
85 |
+
$this->setOpt( 'enable_google_recaptcha_login', $this->getOpt( 'google_recaptcha_style_login' ) );
|
86 |
+
}
|
87 |
+
if ( $this->getIsCheckingUserRegistrations() ) {
|
88 |
+
$this->setOpt( 'bot_protection_locations', array_merge( $this->getBotProtectionLocations(), array(
|
89 |
+
'register',
|
90 |
+
'password'
|
91 |
+
) ) )
|
92 |
+
->setOpt( 'enable_user_register_checking', 'N' );
|
93 |
+
}
|
94 |
}
|
95 |
|
96 |
/**
|
137 |
|
138 |
$sEmailSubject = _wpsf__( 'Email Sending Verification' );
|
139 |
return $this->getEmailProcessor()
|
140 |
+
->sendEmailWithWrap( $sEmail, $sEmailSubject, $aMessage );
|
141 |
}
|
142 |
|
143 |
/**
|
151 |
}
|
152 |
|
153 |
/**
|
154 |
+
* @deprecated
|
155 |
* @return bool
|
156 |
*/
|
157 |
public function getIsCheckingUserRegistrations() {
|
159 |
}
|
160 |
|
161 |
/**
|
162 |
+
* @return bool
|
163 |
+
*/
|
164 |
+
public function isProtectLogin() {
|
165 |
+
return $this->isProtect( 'login' );
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* @return bool
|
170 |
+
*/
|
171 |
+
public function isProtectLostPassword() {
|
172 |
+
return $this->isProtect( 'password' );
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* @return bool
|
177 |
+
*/
|
178 |
+
public function isProtectRegister() {
|
179 |
+
return $this->isProtect( 'register' );
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* @param string $sLocationKey - see config for keys, e.g. login, register, password, checkout_woo
|
184 |
+
* @return bool
|
185 |
+
*/
|
186 |
+
public function isProtect( $sLocationKey ) {
|
187 |
+
return in_array( $sLocationKey, $this->getBotProtectionLocations() );
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* @return array
|
192 |
+
*/
|
193 |
+
public function getEmail2FaRoles() {
|
194 |
+
$aRoles = $this->getOpt( 'two_factor_auth_user_roles', array() );
|
195 |
+
if ( empty( $aRoles ) || !is_array( $aRoles ) ) {
|
196 |
+
$aRoles = $this->getOptEmailTwoFactorRolesDefaults();
|
197 |
+
$this->setOpt( 'two_factor_auth_user_roles', $aRoles );
|
198 |
+
}
|
199 |
+
return $aRoles;
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* @param boolean $bAsOptDefaults
|
204 |
* @return array
|
205 |
*/
|
206 |
+
protected function getOptEmailTwoFactorRolesDefaults( $bAsOptDefaults = true ) {
|
207 |
$aTwoAuthRoles = array(
|
208 |
'type' => 'multiple_select',
|
209 |
0 => _wpsf__( 'Subscribers' ),
|
212 |
3 => _wpsf__( 'Editors' ),
|
213 |
8 => _wpsf__( 'Administrators' )
|
214 |
);
|
215 |
+
if ( $bAsOptDefaults ) {
|
216 |
unset( $aTwoAuthRoles[ 'type' ] );
|
217 |
unset( $aTwoAuthRoles[ 0 ] );
|
218 |
return array_keys( $aTwoAuthRoles );
|
361 |
/**
|
362 |
* @return bool
|
363 |
*/
|
364 |
+
public function isGoogleRecaptchaEnabled() {
|
365 |
+
return ( !$this->getOptIs( 'enable_google_recaptcha_login', 'disabled' ) && $this->getIsGoogleRecaptchaReady() );
|
366 |
}
|
367 |
|
368 |
/**
|
390 |
return $sStyle;
|
391 |
}
|
392 |
|
393 |
+
/**
|
394 |
+
* @return array
|
395 |
+
*/
|
396 |
+
public function getBotProtectionLocations() {
|
397 |
+
$aLocs = $this->getOpt( 'bot_protection_locations' );
|
398 |
+
return is_array( $aLocs ) ? $aLocs : $this->getOptionsVo()->getOptDefault( 'bot_protection_locations' );
|
399 |
+
}
|
400 |
+
|
401 |
+
/**
|
402 |
+
* @return bool
|
403 |
+
*/
|
404 |
+
public function isCooldownEnabled() {
|
405 |
+
return $this->getOpt( 'login_limit_interval' ) > 0;
|
406 |
+
}
|
407 |
+
|
408 |
/**
|
409 |
* @return bool
|
410 |
*/
|
427 |
public function setIfCanSendEmail( $bCan ) {
|
428 |
$nCurrentDateAt = $this->getCanSendEmailVerifiedAt();
|
429 |
if ( $bCan ) {
|
430 |
+
$nDateAt = ( $nCurrentDateAt <= 0 ) ? $this->loadDP()->time() : $nCurrentDateAt;
|
431 |
}
|
432 |
else {
|
433 |
$nDateAt = 0;
|
564 |
|
565 |
case 'section_brute_force_login_protection' :
|
566 |
$sTitle = _wpsf__( 'Brute Force Login Protection' );
|
567 |
+
$sTitleShort = _wpsf__( 'reCAPTCHA & Bots' );
|
568 |
$aSummary = array(
|
569 |
sprintf( _wpsf__( 'Purpose - %s' ), _wpsf__( 'Blocks brute force hacking attacks against your login and registration pages.' ) ),
|
570 |
sprintf( _wpsf__( 'Recommendation - %s' ), _wpsf__( 'Use of this feature is highly recommend.' ) )
|
648 |
|
649 |
case 'enable_google_recaptcha_login' :
|
650 |
$sName = _wpsf__( 'Google reCAPTCHA' );
|
651 |
+
$sSummary = _wpsf__( 'Protect WordPress Account Access Requests With Google reCAPTCHA' );
|
652 |
+
$sDescription = _wpsf__( 'Use Google reCAPTCHA on the user account forms such as login, register, etc.' ).'<br />'
|
653 |
+
.sprintf( _wpsf__( 'Use of any theme other than "%s", requires a Pro license.' ), _wpsf__( 'Light Theme' ) )
|
654 |
+
.'<br/>'.sprintf( '%s - %s', _wpsf__( 'Note' ), _wpsf__( "You'll need to setup your Google reCAPTCHA API Keys in 'General' settings." ) );
|
655 |
break;
|
656 |
|
657 |
case 'google_recaptcha_style_login' :
|
660 |
$sDescription = _wpsf__( 'You can choose the reCAPTCHA display format that best suits your site, including the new Invisible Recaptcha' );
|
661 |
break;
|
662 |
|
663 |
+
case 'bot_protection_locations' :
|
664 |
+
$sName = _wpsf__( 'Protection Locations' );
|
665 |
+
$sSummary = _wpsf__( 'Which Forms Should Be Protected' );
|
666 |
+
$sDescription = _wpsf__( 'Choose the forms for which bot protection measures will be deployed.' ).'<br />'
|
667 |
+
.sprintf( _wpsf__( 'Note - %s' ), sprintf( _wpsf__( "Use with 3rd party systems such as %s, requires a Pro license." ), 'WooCommerce' ) );
|
668 |
+
break;
|
669 |
+
|
670 |
case 'enable_login_gasp_check' :
|
671 |
$sName = _wpsf__( 'Bot Protection' );
|
672 |
$sSummary = _wpsf__( 'Protect WP Login From Automated Login Attempts By Bots' );
|
675 |
break;
|
676 |
|
677 |
case 'login_limit_interval' :
|
678 |
+
$sName = _wpsf__( 'Cooldown Period' );
|
679 |
+
$sSummary = _wpsf__( 'Limit account access requests to every X seconds' );
|
680 |
+
$sDescription = _wpsf__( 'WordPress will process only ONE account access attempt per number of seconds specified.' )
|
681 |
.'<br />'._wpsf__( 'Zero (0) turns this off.' )
|
682 |
.' '.sprintf( _wpsf__( 'Default: "%s".' ), $this->getOptionsVo()
|
683 |
->getOptDefault( 'login_limit_interval' ) );
|
src/features/plugin.php
CHANGED
@@ -10,7 +10,7 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
10 |
|
11 |
protected function doPostConstruction() {
|
12 |
add_action( 'deactivate_plugin', array( $this, 'onWpHookDeactivatePlugin' ), 1, 1 );
|
13 |
-
add_filter( $this->prefix( 'report_email_address' ), array( $this, '
|
14 |
add_filter( $this->prefix( 'globally_disabled' ), array( $this, 'filter_IsPluginGloballyDisabled' ) );
|
15 |
add_filter( $this->prefix( 'google_recaptcha_config' ), array( $this, 'supplyGoogleRecaptchaConfig' ), 10, 0 );
|
16 |
$this->setVisitorIp();
|
@@ -49,15 +49,6 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
49 |
);
|
50 |
}
|
51 |
|
52 |
-
/**
|
53 |
-
* @return ICWP_WPSF_Processor_Plugin_ImportExport
|
54 |
-
*/
|
55 |
-
protected function getImportProcessor() {
|
56 |
-
/** @var ICWP_WPSF_Processor_Plugin $oP */
|
57 |
-
$oP = $this->getProcessor();
|
58 |
-
return $oP->getSubProcessorImportExport();
|
59 |
-
}
|
60 |
-
|
61 |
/**
|
62 |
* @return bool
|
63 |
*/
|
@@ -313,26 +304,21 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
313 |
* @return $this
|
314 |
*/
|
315 |
public function setTrackingLastSentAt() {
|
316 |
-
return $this->setOpt( 'tracking_last_sent_at', $this->
|
317 |
}
|
318 |
|
319 |
/**
|
320 |
* @return bool
|
321 |
*/
|
322 |
public function readyToSendTrackingData() {
|
323 |
-
return ( ( $this->
|
324 |
}
|
325 |
|
326 |
/**
|
327 |
-
* @param $sEmail
|
328 |
* @return string
|
329 |
*/
|
330 |
-
public function
|
331 |
-
|
332 |
-
if ( $this->loadDataProcessor()->validEmail( $sReportEmail ) ) {
|
333 |
-
$sEmail = $sReportEmail;
|
334 |
-
}
|
335 |
-
return $sEmail;
|
336 |
}
|
337 |
|
338 |
/**
|
@@ -342,11 +328,11 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
342 |
|
343 |
$nInstalledAt = $this->getPluginInstallationTime();
|
344 |
if ( empty( $nInstalledAt ) || $nInstalledAt <= 0 ) {
|
345 |
-
$this->setOpt( 'installation_time', $this->
|
346 |
}
|
347 |
|
348 |
if ( $this->isTrackingEnabled() && !$this->isTrackingPermissionSet() ) {
|
349 |
-
$this->setOpt( 'tracking_permission_set_at', $this->
|
350 |
}
|
351 |
|
352 |
$this->cleanRecaptchaKey( 'google_recaptcha_site_key' );
|
@@ -427,6 +413,13 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
427 |
return !empty( $sMaster ) && ( rtrim( $this->loadWp()->getHomeUrl(), '/' ) != $sMaster );
|
428 |
}
|
429 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
430 |
/**
|
431 |
* @return int
|
432 |
*/
|
@@ -466,7 +459,7 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
466 |
* @return bool
|
467 |
*/
|
468 |
public function isImportExportPermitted() {
|
469 |
-
return $this->getOptIs( 'importexport_enable', 'Y' );
|
470 |
}
|
471 |
|
472 |
/**
|
@@ -577,7 +570,7 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
577 |
$aOptionData = $this->getOptionsVo()->getRawData_SingleOption( 'visitor_address_source' );
|
578 |
$aValueOptions = $aOptionData[ 'value_options' ];
|
579 |
|
580 |
-
$oDp = $this->
|
581 |
$aMap = array();
|
582 |
$aEmpties = array();
|
583 |
foreach ( $aValueOptions as $aOptionValue ) {
|
@@ -675,7 +668,7 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
675 |
* @return bool
|
676 |
*/
|
677 |
public function getCanAdminNotes() {
|
678 |
-
return
|
679 |
}
|
680 |
|
681 |
/**
|
@@ -692,12 +685,12 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
692 |
*/
|
693 |
protected function loadStrings_SectionTitles( $aOptionsParams ) {
|
694 |
|
695 |
-
$
|
696 |
-
switch ( $
|
697 |
|
698 |
case 'section_global_security_options' :
|
699 |
$sTitle = _wpsf__( 'Global Security Plugin Disable' );
|
700 |
-
$sTitleShort = sprintf( _wpsf__( 'Disable %s' ), $
|
701 |
break;
|
702 |
|
703 |
case 'section_defaults' :
|
@@ -726,9 +719,15 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
726 |
$sTitle = _wpsf__( 'Google' );
|
727 |
$sTitleShort = _wpsf__( 'Google' );
|
728 |
$aSummary = array(
|
729 |
-
sprintf(
|
730 |
-
sprintf(
|
731 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
732 |
);
|
733 |
break;
|
734 |
|
@@ -738,7 +737,7 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
738 |
break;
|
739 |
|
740 |
default:
|
741 |
-
throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $
|
742 |
}
|
743 |
$aOptionsParams[ 'title' ] = $sTitle;
|
744 |
$aOptionsParams[ 'summary' ] = ( isset( $aSummary ) && is_array( $aSummary ) ) ? $aSummary : array();
|
@@ -803,7 +802,7 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
803 |
$sSummary = _wpsf__( 'Display Plugin Badge On Your Site' );
|
804 |
$sDescription = _wpsf__( 'Enabling this option helps support the plugin by spreading the word about it on your website.' )
|
805 |
.' '._wpsf__( 'The plugin badge also lets visitors know your are taking your website security seriously.' )
|
806 |
-
.sprintf( '<br /><strong><a href="%s" target="_blank">%s</a></strong>', '
|
807 |
break;
|
808 |
|
809 |
case 'delete_on_deactivate' :
|
@@ -837,7 +836,7 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
|
|
837 |
$sName = _wpsf__( 'Master Import Site' );
|
838 |
$sSummary = _wpsf__( 'Automatically Import Options From This Site URL' );
|
839 |
$sDescription = _wpsf__( "Supplying a site URL here will make this site an 'Options Slave'." )
|
840 |
-
.'<br />'._wpsf__( 'Options will be automatically
|
841 |
.'<br />'.sprintf( '%s: %s', _wpsf__( 'Warning' ), _wpsf__( 'Use of this feature will overwrite existing options and replace them with those from the Master Import Site.' ) );
|
842 |
break;
|
843 |
|
10 |
|
11 |
protected function doPostConstruction() {
|
12 |
add_action( 'deactivate_plugin', array( $this, 'onWpHookDeactivatePlugin' ), 1, 1 );
|
13 |
+
add_filter( $this->prefix( 'report_email_address' ), array( $this, 'supplyPluginReportEmail' ) );
|
14 |
add_filter( $this->prefix( 'globally_disabled' ), array( $this, 'filter_IsPluginGloballyDisabled' ) );
|
15 |
add_filter( $this->prefix( 'google_recaptcha_config' ), array( $this, 'supplyGoogleRecaptchaConfig' ), 10, 0 );
|
16 |
$this->setVisitorIp();
|
49 |
);
|
50 |
}
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
/**
|
53 |
* @return bool
|
54 |
*/
|
304 |
* @return $this
|
305 |
*/
|
306 |
public function setTrackingLastSentAt() {
|
307 |
+
return $this->setOpt( 'tracking_last_sent_at', $this->loadDP()->time() );
|
308 |
}
|
309 |
|
310 |
/**
|
311 |
* @return bool
|
312 |
*/
|
313 |
public function readyToSendTrackingData() {
|
314 |
+
return ( ( $this->loadDP()->time() - $this->getTrackingLastSentAt() ) > WEEK_IN_SECONDS );
|
315 |
}
|
316 |
|
317 |
/**
|
|
|
318 |
* @return string
|
319 |
*/
|
320 |
+
public function supplyPluginReportEmail() {
|
321 |
+
return $this->getOpt( 'block_send_email_address' );
|
|
|
|
|
|
|
|
|
322 |
}
|
323 |
|
324 |
/**
|
328 |
|
329 |
$nInstalledAt = $this->getPluginInstallationTime();
|
330 |
if ( empty( $nInstalledAt ) || $nInstalledAt <= 0 ) {
|
331 |
+
$this->setOpt( 'installation_time', $this->loadDP()->time() );
|
332 |
}
|
333 |
|
334 |
if ( $this->isTrackingEnabled() && !$this->isTrackingPermissionSet() ) {
|
335 |
+
$this->setOpt( 'tracking_permission_set_at', $this->loadDP()->time() );
|
336 |
}
|
337 |
|
338 |
$this->cleanRecaptchaKey( 'google_recaptcha_site_key' );
|
413 |
return !empty( $sMaster ) && ( rtrim( $this->loadWp()->getHomeUrl(), '/' ) != $sMaster );
|
414 |
}
|
415 |
|
416 |
+
/**
|
417 |
+
* @return bool
|
418 |
+
*/
|
419 |
+
public function hasImportExportWhitelistSites() {
|
420 |
+
return ( count( $this->getImportExportWhitelist() ) > 0 );
|
421 |
+
}
|
422 |
+
|
423 |
/**
|
424 |
* @return int
|
425 |
*/
|
459 |
* @return bool
|
460 |
*/
|
461 |
public function isImportExportPermitted() {
|
462 |
+
return $this->isPremium() && $this->getOptIs( 'importexport_enable', 'Y' );
|
463 |
}
|
464 |
|
465 |
/**
|
570 |
$aOptionData = $this->getOptionsVo()->getRawData_SingleOption( 'visitor_address_source' );
|
571 |
$aValueOptions = $aOptionData[ 'value_options' ];
|
572 |
|
573 |
+
$oDp = $this->loadDP();
|
574 |
$aMap = array();
|
575 |
$aEmpties = array();
|
576 |
foreach ( $aValueOptions as $aOptionValue ) {
|
668 |
* @return bool
|
669 |
*/
|
670 |
public function getCanAdminNotes() {
|
671 |
+
return $this->isPremium();
|
672 |
}
|
673 |
|
674 |
/**
|
685 |
*/
|
686 |
protected function loadStrings_SectionTitles( $aOptionsParams ) {
|
687 |
|
688 |
+
$sName = $this->getConn()->getHumanName();
|
689 |
+
switch ( $aOptionsParams[ 'slug' ] ) {
|
690 |
|
691 |
case 'section_global_security_options' :
|
692 |
$sTitle = _wpsf__( 'Global Security Plugin Disable' );
|
693 |
+
$sTitleShort = sprintf( _wpsf__( 'Disable %s' ), $sName );
|
694 |
break;
|
695 |
|
696 |
case 'section_defaults' :
|
719 |
$sTitle = _wpsf__( 'Google' );
|
720 |
$sTitleShort = _wpsf__( 'Google' );
|
721 |
$aSummary = array(
|
722 |
+
sprintf( '%s - %s', _wpsf__( 'Purpose' ), sprintf( _wpsf__( 'Setup Google reCAPTCHA for use across %s.' ), $sName ) ),
|
723 |
+
sprintf( '%s - %s',
|
724 |
+
_wpsf__( 'Recommendation' ),
|
725 |
+
sprintf( _wpsf__( 'Use of this feature is highly recommend.' ).' '
|
726 |
+
.sprintf( '%s: %s', _wpsf__( 'Note' ), _wpsf__( 'You must create your own Google reCAPTCHA API Keys.' ) )
|
727 |
+
)
|
728 |
+
.sprintf( '<br/><a href="%s" target="_blank">%s</a>', 'https://www.google.com/recaptcha/admin', _wpsf__( 'API Keys' ) )
|
729 |
+
),
|
730 |
+
sprintf( '%s - %s', _wpsf__( 'Note' ), sprintf( _wpsf__( 'Invisible Google reCAPTCHA is available with %s Pro.' ), $sName ) )
|
731 |
);
|
732 |
break;
|
733 |
|
737 |
break;
|
738 |
|
739 |
default:
|
740 |
+
throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $aOptionsParams[ 'slug' ] ) );
|
741 |
}
|
742 |
$aOptionsParams[ 'title' ] = $sTitle;
|
743 |
$aOptionsParams[ 'summary' ] = ( isset( $aSummary ) && is_array( $aSummary ) ) ? $aSummary : array();
|
802 |
$sSummary = _wpsf__( 'Display Plugin Badge On Your Site' );
|
803 |
$sDescription = _wpsf__( 'Enabling this option helps support the plugin by spreading the word about it on your website.' )
|
804 |
.' '._wpsf__( 'The plugin badge also lets visitors know your are taking your website security seriously.' )
|
805 |
+
.sprintf( '<br /><strong><a href="%s" target="_blank">%s</a></strong>', 'https://icwp.io/wpsf20', _wpsf__( 'Read this carefully before enabling this option.' ) );
|
806 |
break;
|
807 |
|
808 |
case 'delete_on_deactivate' :
|
836 |
$sName = _wpsf__( 'Master Import Site' );
|
837 |
$sSummary = _wpsf__( 'Automatically Import Options From This Site URL' );
|
838 |
$sDescription = _wpsf__( "Supplying a site URL here will make this site an 'Options Slave'." )
|
839 |
+
.'<br />'._wpsf__( 'Options will be automatically exported from the Master site each day.' )
|
840 |
.'<br />'.sprintf( '%s: %s', _wpsf__( 'Warning' ), _wpsf__( 'Use of this feature will overwrite existing options and replace them with those from the Master Import Site.' ) );
|
841 |
break;
|
842 |
|
src/features/user_management.php
CHANGED
@@ -15,6 +15,9 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_B
|
|
15 |
return $this->getUserSessionsData();
|
16 |
}
|
17 |
|
|
|
|
|
|
|
18 |
protected function getUserSessionsData() {
|
19 |
$aActiveSessions = $this->getActiveSessionsData();
|
20 |
|
@@ -61,13 +64,58 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_B
|
|
61 |
}
|
62 |
|
63 |
/**
|
|
|
64 |
* @return ICWP_WPSF_SessionVO[]
|
65 |
*/
|
66 |
-
public function getActiveSessionsData() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
return $this->getSessionsProcessor()
|
68 |
->queryGetActiveSessions();
|
69 |
}
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
/**
|
72 |
* @return bool
|
73 |
*/
|
@@ -77,7 +125,7 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_B
|
|
77 |
|
78 |
protected function doExtraSubmitProcessing() {
|
79 |
$sAdminEmail = $this->getOpt( 'enable_admin_login_email_notification' );
|
80 |
-
if ( !$this->
|
81 |
$this->getOptionsVo()->resetOptToDefault( 'enable_admin_login_email_notification' );
|
82 |
}
|
83 |
|
@@ -135,8 +183,15 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_B
|
|
135 |
/**
|
136 |
* @return bool
|
137 |
*/
|
138 |
-
public function
|
139 |
-
return $this->loadDP()->validEmail( $this->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
}
|
141 |
|
142 |
/**
|
@@ -334,6 +389,12 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_B
|
|
334 |
.'<br />'._wpsf__( 'No email address - No Notification.' );
|
335 |
break;
|
336 |
|
|
|
|
|
|
|
|
|
|
|
|
|
337 |
case 'session_timeout_interval' :
|
338 |
$sName = _wpsf__( 'Session Timeout' );
|
339 |
$sSummary = _wpsf__( 'Specify How Many Days After Login To Automatically Force Re-Login' );
|
15 |
return $this->getUserSessionsData();
|
16 |
}
|
17 |
|
18 |
+
/**
|
19 |
+
* @return array
|
20 |
+
*/
|
21 |
protected function getUserSessionsData() {
|
22 |
$aActiveSessions = $this->getActiveSessionsData();
|
23 |
|
64 |
}
|
65 |
|
66 |
/**
|
67 |
+
* @param bool $bCleanFirst
|
68 |
* @return ICWP_WPSF_SessionVO[]
|
69 |
*/
|
70 |
+
public function getActiveSessionsData( $bCleanFirst = true ) {
|
71 |
+
// we first clean the sessions.
|
72 |
+
if ( $bCleanFirst ) {
|
73 |
+
/** @var ICWP_WPSF_Processor_UserManagement $oProc */
|
74 |
+
$oProc = $this->getProcessor();
|
75 |
+
$oProc->getProcessorSessions()
|
76 |
+
->cleanExpiredSessions();
|
77 |
+
}
|
78 |
+
|
79 |
return $this->getSessionsProcessor()
|
80 |
->queryGetActiveSessions();
|
81 |
}
|
82 |
|
83 |
+
/**
|
84 |
+
* Should have no default email. If no email is set, no notification is sent.
|
85 |
+
* @return string
|
86 |
+
*/
|
87 |
+
public function getAdminLoginNotificationEmail() {
|
88 |
+
return $this->getOpt( 'enable_admin_login_email_notification', '' );
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* @return int
|
93 |
+
*/
|
94 |
+
public function getSessionIdleTimeoutInterval() {
|
95 |
+
return $this->getOpt( 'session_idle_timeout_interval' )*HOUR_IN_SECONDS;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* @return int
|
100 |
+
*/
|
101 |
+
public function getSessionTimeoutInterval() {
|
102 |
+
return $this->getOpt( 'session_timeout_interval' )*DAY_IN_SECONDS;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* @return bool
|
107 |
+
*/
|
108 |
+
public function hasSessionIdleTimeout() {
|
109 |
+
return $this->isModuleEnabled() && ( $this->getSessionIdleTimeoutInterval() > 0 );
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* @return bool
|
114 |
+
*/
|
115 |
+
public function hasSessionTimeoutInterval() {
|
116 |
+
return $this->isModuleEnabled() && ( $this->getSessionTimeoutInterval() > 0 );
|
117 |
+
}
|
118 |
+
|
119 |
/**
|
120 |
* @return bool
|
121 |
*/
|
125 |
|
126 |
protected function doExtraSubmitProcessing() {
|
127 |
$sAdminEmail = $this->getOpt( 'enable_admin_login_email_notification' );
|
128 |
+
if ( !$this->loadDP()->validEmail( $sAdminEmail ) ) {
|
129 |
$this->getOptionsVo()->resetOptToDefault( 'enable_admin_login_email_notification' );
|
130 |
}
|
131 |
|
183 |
/**
|
184 |
* @return bool
|
185 |
*/
|
186 |
+
public function isSendAdminEmailLoginNotification() {
|
187 |
+
return $this->loadDP()->validEmail( $this->getAdminLoginNotificationEmail() );
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* @return bool
|
192 |
+
*/
|
193 |
+
public function isSendUserEmailLoginNotification() {
|
194 |
+
return $this->isPremium() && $this->getOptIs( 'enable_user_login_email_notification', 'Y' );
|
195 |
}
|
196 |
|
197 |
/**
|
389 |
.'<br />'._wpsf__( 'No email address - No Notification.' );
|
390 |
break;
|
391 |
|
392 |
+
case 'enable_user_login_email_notification' :
|
393 |
+
$sName = _wpsf__( 'User Login Notification Email' );
|
394 |
+
$sSummary = _wpsf__( 'Send Email Notification To Each User Upon Successful Login' );
|
395 |
+
$sDescription = _wpsf__( 'A notification is sent to each user when a successful login occurs for their account.' );
|
396 |
+
break;
|
397 |
+
|
398 |
case 'session_timeout_interval' :
|
399 |
$sName = _wpsf__( 'Session Timeout' );
|
400 |
$sSummary = _wpsf__( 'Specify How Many Days After Login To Automatically Force Re-Login' );
|
src/processors/admin_access_restriction.php
CHANGED
@@ -129,7 +129,7 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
|
|
129 |
}
|
130 |
|
131 |
$oWpUsers = $this->loadWpUsers();
|
132 |
-
$oDp = $this->
|
133 |
|
134 |
/** @var string $sRequestedCapability */
|
135 |
$sRequestedCapability = $aArgs[ 0 ];
|
@@ -324,9 +324,20 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
|
|
324 |
|
325 |
/** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
|
326 |
$oFO = $this->getFeature();
|
|
|
327 |
|
328 |
/** @var string $sRequestedCapability */
|
329 |
$sRequestedCapability = $aArgs[ 0 ];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
330 |
$aEditCapabilities = array( 'activate_plugins', 'delete_plugins', 'install_plugins', 'update_plugins' );
|
331 |
|
332 |
if ( in_array( $sRequestedCapability, $aEditCapabilities ) ) {
|
@@ -450,7 +461,7 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
|
|
450 |
'js_snippets' => array(
|
451 |
'options_to_restrict' => "'".implode( "','", $oFO->getOptionsToRestrict() )."'",
|
452 |
),
|
453 |
-
'ajax'
|
454 |
'sec_admin_login_box' => $oFO->getAjaxActionData( 'sec_admin_login_box', true )
|
455 |
)
|
456 |
);
|
129 |
}
|
130 |
|
131 |
$oWpUsers = $this->loadWpUsers();
|
132 |
+
$oDp = $this->loadDP();
|
133 |
|
134 |
/** @var string $sRequestedCapability */
|
135 |
$sRequestedCapability = $aArgs[ 0 ];
|
324 |
|
325 |
/** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
|
326 |
$oFO = $this->getFeature();
|
327 |
+
$oDp = $this->loadDP();
|
328 |
|
329 |
/** @var string $sRequestedCapability */
|
330 |
$sRequestedCapability = $aArgs[ 0 ];
|
331 |
+
|
332 |
+
// special case for plugin info thickbox for changelog
|
333 |
+
$bIsChangelog = defined( 'IFRAME_REQUEST' )
|
334 |
+
&& ( $sRequestedCapability === 'install_plugins' )
|
335 |
+
&& ( $oDp->query( 'section' ) == 'changelog' )
|
336 |
+
&& $oDp->query( 'plugin' );
|
337 |
+
if ( $bIsChangelog ) {
|
338 |
+
return $aAllCaps;
|
339 |
+
}
|
340 |
+
|
341 |
$aEditCapabilities = array( 'activate_plugins', 'delete_plugins', 'install_plugins', 'update_plugins' );
|
342 |
|
343 |
if ( in_array( $sRequestedCapability, $aEditCapabilities ) ) {
|
461 |
'js_snippets' => array(
|
462 |
'options_to_restrict' => "'".implode( "','", $oFO->getOptionsToRestrict() )."'",
|
463 |
),
|
464 |
+
'ajax' => array(
|
465 |
'sec_admin_login_box' => $oFO->getAjaxActionData( 'sec_admin_login_box', true )
|
466 |
)
|
467 |
);
|
src/processors/adminaccess_whitelabel.php
CHANGED
@@ -13,12 +13,52 @@ class ICWP_WPSF_Processor_AdminAccess_Whitelabel extends ICWP_WPSF_Processor_Bas
|
|
13 |
public function run() {
|
14 |
/** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
|
15 |
$oFO = $this->getFeature();
|
16 |
-
add_filter( $this->
|
|
|
17 |
add_filter( 'plugin_row_meta', array( $this, 'fRemoveDetailsMetaLink' ), 200, 2 );
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
add_filter( 'site_transient_update_plugins', array( $this, 'hidePluginUpdatesFromUI' ) );
|
20 |
}
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
}
|
23 |
|
24 |
public function hideFromPluginEditor() {
|
@@ -39,13 +79,12 @@ class ICWP_WPSF_Processor_AdminAccess_Whitelabel extends ICWP_WPSF_Processor_Bas
|
|
39 |
|
40 |
// these are the old white labelling keys which will be replaced upon final release of white labelling.
|
41 |
$sServiceName = $aWhiteLabels[ 'name_main' ];
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
}
|
49 |
$sTagLine = $aWhiteLabels[ 'description' ];
|
50 |
if ( !empty( $sTagLine ) ) {
|
51 |
$aPluginLabels[ 'Description' ] = $sTagLine;
|
@@ -58,13 +97,14 @@ class ICWP_WPSF_Processor_AdminAccess_Whitelabel extends ICWP_WPSF_Processor_Bas
|
|
58 |
}
|
59 |
|
60 |
$sIconUrl = $aWhiteLabels[ 'url_icon' ];
|
61 |
-
if ( !empty( $
|
62 |
$aPluginLabels[ 'icon_url_16x16' ] = $sIconUrl;
|
|
|
63 |
}
|
64 |
|
65 |
-
$
|
66 |
-
if ( !empty( $
|
67 |
-
$aPluginLabels[ '
|
68 |
}
|
69 |
|
70 |
return $aPluginLabels;
|
@@ -85,17 +125,14 @@ class ICWP_WPSF_Processor_AdminAccess_Whitelabel extends ICWP_WPSF_Processor_Bas
|
|
85 |
}
|
86 |
|
87 |
/**
|
|
|
88 |
* @param stdClass $oPlugins
|
89 |
* @return stdClass
|
90 |
*/
|
91 |
public function hidePluginUpdatesFromUI( $oPlugins ) {
|
92 |
-
$
|
93 |
-
|
94 |
-
|
95 |
-
$sFile = $oCon->getPluginBaseFile();
|
96 |
-
if ( isset( $oPlugins->response[ $sFile ] ) ) {
|
97 |
-
unset( $oPlugins->response[ $sFile ] );
|
98 |
-
}
|
99 |
}
|
100 |
return $oPlugins;
|
101 |
}
|
@@ -105,7 +142,6 @@ class ICWP_WPSF_Processor_AdminAccess_Whitelabel extends ICWP_WPSF_Processor_Bas
|
|
105 |
*/
|
106 |
private function isNeedToHideUpdates() {
|
107 |
$oWp = $this->loadWp();
|
108 |
-
return is_admin() && !$oWp->isCron()
|
109 |
-
&& ( in_array( $oWp->getCurrentPage(), array( 'plugins.php', 'update-core.php' ) ) );
|
110 |
}
|
111 |
}
|
13 |
public function run() {
|
14 |
/** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
|
15 |
$oFO = $this->getFeature();
|
16 |
+
add_filter( $this->prefix( 'is_relabelled' ), '__return_true' );
|
17 |
+
add_filter( $oFO->prefix( 'plugin_labels' ), array( $this, 'doRelabelPlugin' ) );
|
18 |
add_filter( 'plugin_row_meta', array( $this, 'fRemoveDetailsMetaLink' ), 200, 2 );
|
19 |
+
add_action( 'init', array( $this, 'onWpInit' ) );
|
20 |
+
add_action( 'admin_print_footer_scripts-plugin-editor.php', array( $this, 'hideFromPluginEditor' ) );
|
21 |
+
}
|
22 |
+
|
23 |
+
public function onWpInit() {
|
24 |
+
/** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
|
25 |
+
$oFO = $this->getFeature();
|
26 |
+
$oCon = $this->getController();
|
27 |
+
|
28 |
+
if ( $oFO->isWlHideUpdates() && $this->isNeedToHideUpdates()
|
29 |
+
&& !$oCon->getHasPermissionToManage() ) {
|
30 |
+
$this->hideUpdates();
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Depending on the page, we hide the update data,
|
36 |
+
* or we adjust the number of displayed updates counts
|
37 |
+
*/
|
38 |
+
protected function hideUpdates() {
|
39 |
+
$sCurrent = $this->loadWp()->getCurrentPage();
|
40 |
+
if ( in_array( $sCurrent, array( 'plugins.php', 'update-core.php' ) ) ) {
|
41 |
add_filter( 'site_transient_update_plugins', array( $this, 'hidePluginUpdatesFromUI' ) );
|
42 |
}
|
43 |
+
else {
|
44 |
+
add_filter( 'wp_get_update_data', array( $this, 'adjustUpdateDataCount' ) );
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Adjusts the available updates count so as not to include Shield updates if they're hidden
|
50 |
+
* @param array $aUpdateData
|
51 |
+
* @return array
|
52 |
+
*/
|
53 |
+
public function adjustUpdateDataCount( $aUpdateData ) {
|
54 |
+
|
55 |
+
$sFile = $this->getController()->getPluginBaseFile();
|
56 |
+
if ( $this->loadWpPlugins()->isUpdateAvailable( $sFile ) ) {
|
57 |
+
$aUpdateData[ 'counts' ][ 'total' ]--;
|
58 |
+
$aUpdateData[ 'counts' ][ 'plugins' ]--;
|
59 |
+
}
|
60 |
+
|
61 |
+
return $aUpdateData;
|
62 |
}
|
63 |
|
64 |
public function hideFromPluginEditor() {
|
79 |
|
80 |
// these are the old white labelling keys which will be replaced upon final release of white labelling.
|
81 |
$sServiceName = $aWhiteLabels[ 'name_main' ];
|
82 |
+
$aPluginLabels[ 'Name' ] = $sServiceName;
|
83 |
+
$aPluginLabels[ 'Title' ] = $sServiceName;
|
84 |
+
$aPluginLabels[ 'Author' ] = $aWhiteLabels[ 'name_company' ];
|
85 |
+
$aPluginLabels[ 'AuthorName' ] = $aWhiteLabels[ 'name_company' ];
|
86 |
+
$aPluginLabels[ 'MenuTitle' ] = $aWhiteLabels[ 'name_menu' ];
|
87 |
+
|
|
|
88 |
$sTagLine = $aWhiteLabels[ 'description' ];
|
89 |
if ( !empty( $sTagLine ) ) {
|
90 |
$aPluginLabels[ 'Description' ] = $sTagLine;
|
97 |
}
|
98 |
|
99 |
$sIconUrl = $aWhiteLabels[ 'url_icon' ];
|
100 |
+
if ( !empty( $sIconUrl ) ) {
|
101 |
$aPluginLabels[ 'icon_url_16x16' ] = $sIconUrl;
|
102 |
+
$aPluginLabels[ 'icon_url_32x32' ] = $sIconUrl;
|
103 |
}
|
104 |
|
105 |
+
$sLogoUrl = $aWhiteLabels[ 'url_dashboardlogourl' ];
|
106 |
+
if ( !empty( $sLogoUrl ) ) {
|
107 |
+
$aPluginLabels[ 'icon_url_128x128' ] = $sLogoUrl;
|
108 |
}
|
109 |
|
110 |
return $aPluginLabels;
|
125 |
}
|
126 |
|
127 |
/**
|
128 |
+
* Hides the update if the page loaded is the plugins page or the updates page.
|
129 |
* @param stdClass $oPlugins
|
130 |
* @return stdClass
|
131 |
*/
|
132 |
public function hidePluginUpdatesFromUI( $oPlugins ) {
|
133 |
+
$sFile = $this->getController()->getPluginBaseFile();
|
134 |
+
if ( isset( $oPlugins->response[ $sFile ] ) ) {
|
135 |
+
unset( $oPlugins->response[ $sFile ] );
|
|
|
|
|
|
|
|
|
136 |
}
|
137 |
return $oPlugins;
|
138 |
}
|
142 |
*/
|
143 |
private function isNeedToHideUpdates() {
|
144 |
$oWp = $this->loadWp();
|
145 |
+
return is_admin() && !$oWp->isCron();
|
|
|
146 |
}
|
147 |
}
|
src/processors/audit_trail.php
CHANGED
@@ -25,14 +25,14 @@ class ICWP_WPSF_Processor_AuditTrail extends ICWP_WPSF_BaseDbProcessor {
|
|
25 |
}
|
26 |
|
27 |
/**
|
28 |
-
* @param ICWP_WPSF_FeatureHandler_AuditTrail $
|
29 |
*/
|
30 |
-
public function __construct( ICWP_WPSF_FeatureHandler_AuditTrail $
|
31 |
-
parent::__construct( $
|
32 |
}
|
33 |
|
34 |
-
public function
|
35 |
-
parent::
|
36 |
if ( !$this->getFeature()->isPluginDeleting() ) {
|
37 |
$this->commitAuditTrial();
|
38 |
}
|
@@ -41,7 +41,7 @@ class ICWP_WPSF_Processor_AuditTrail extends ICWP_WPSF_BaseDbProcessor {
|
|
41 |
/**
|
42 |
*/
|
43 |
public function run() {
|
44 |
-
if ( !$this->
|
45 |
return;
|
46 |
}
|
47 |
|
25 |
}
|
26 |
|
27 |
/**
|
28 |
+
* @param ICWP_WPSF_FeatureHandler_AuditTrail $oModCon
|
29 |
*/
|
30 |
+
public function __construct( ICWP_WPSF_FeatureHandler_AuditTrail $oModCon ) {
|
31 |
+
parent::__construct( $oModCon, $oModCon->getAuditTrailTableName() );
|
32 |
}
|
33 |
|
34 |
+
public function onModuleShutdown() {
|
35 |
+
parent::onModuleShutdown();
|
36 |
if ( !$this->getFeature()->isPluginDeleting() ) {
|
37 |
$this->commitAuditTrial();
|
38 |
}
|
41 |
/**
|
42 |
*/
|
43 |
public function run() {
|
44 |
+
if ( !$this->isReadyToRun() ) {
|
45 |
return;
|
46 |
}
|
47 |
|
src/processors/audit_trail_auditor_base.php
CHANGED
@@ -15,7 +15,7 @@ class ICWP_WPSF_AuditTrail_Auditor_Base extends ICWP_WPSF_Foundation {
|
|
15 |
* @param string $sWpUsername
|
16 |
*/
|
17 |
public function add( $sContext, $sEvent, $nCategory, $sMessage = '', $sWpUsername = '' ) {
|
18 |
-
$oDp = $this->
|
19 |
|
20 |
if ( empty( $sWpUsername ) ) {
|
21 |
$oCurrentUser = $this->loadWpUsers()->getCurrentWpUser();
|
@@ -24,11 +24,11 @@ class ICWP_WPSF_AuditTrail_Auditor_Base extends ICWP_WPSF_Foundation {
|
|
24 |
$sWpUsername = 'WP Cron';
|
25 |
}
|
26 |
else {
|
27 |
-
$sWpUsername = '
|
28 |
}
|
29 |
}
|
30 |
else {
|
31 |
-
$sWpUsername = $oCurrentUser->
|
32 |
}
|
33 |
}
|
34 |
|
15 |
* @param string $sWpUsername
|
16 |
*/
|
17 |
public function add( $sContext, $sEvent, $nCategory, $sMessage = '', $sWpUsername = '' ) {
|
18 |
+
$oDp = $this->loadDP();
|
19 |
|
20 |
if ( empty( $sWpUsername ) ) {
|
21 |
$oCurrentUser = $this->loadWpUsers()->getCurrentWpUser();
|
24 |
$sWpUsername = 'WP Cron';
|
25 |
}
|
26 |
else {
|
27 |
+
$sWpUsername = 'unidentified';
|
28 |
}
|
29 |
}
|
30 |
else {
|
31 |
+
$sWpUsername = $oCurrentUser->user_login;
|
32 |
}
|
33 |
}
|
34 |
|
src/processors/autoupdates.php
CHANGED
@@ -490,7 +490,7 @@ class ICWP_WPSF_Processor_Autoupdates extends ICWP_WPSF_Processor_BaseWpsf {
|
|
490 |
|
491 |
$sTitle = sprintf( _wpsf__( "Notice: %s" ), _wpsf__( "Automatic Updates Completed" ) );
|
492 |
$this->getEmailProcessor()
|
493 |
-
->
|
494 |
}
|
495 |
|
496 |
/**
|
490 |
|
491 |
$sTitle = sprintf( _wpsf__( "Notice: %s" ), _wpsf__( "Automatic Updates Completed" ) );
|
492 |
$this->getEmailProcessor()
|
493 |
+
->sendEmailWithWrap( $this->getOption( 'override_email_address' ), $sTitle, $aEmailContent );
|
494 |
}
|
495 |
|
496 |
/**
|
src/processors/base.php
CHANGED
@@ -9,7 +9,7 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
|
|
9 |
/**
|
10 |
* @var ICWP_WPSF_FeatureHandler_Base
|
11 |
*/
|
12 |
-
protected $
|
13 |
|
14 |
/**
|
15 |
* @var int
|
@@ -22,17 +22,14 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
|
|
22 |
protected $aSubProcessors;
|
23 |
|
24 |
/**
|
25 |
-
* @param ICWP_WPSF_FeatureHandler_Base $
|
26 |
*/
|
27 |
-
public function __construct( $
|
28 |
-
$this->
|
29 |
-
add_action( $
|
30 |
-
|
31 |
-
'action_doFeatureProcessorShutdown'
|
32 |
-
) );
|
33 |
-
add_action( $oFeatureOptions->prefix( 'generate_admin_notices' ), array( $this, 'autoAddToAdminNotices' ) );
|
34 |
if ( method_exists( $this, 'addToAdminNotices' ) ) {
|
35 |
-
add_action( $
|
36 |
}
|
37 |
$this->init();
|
38 |
}
|
@@ -109,9 +106,15 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
|
|
109 |
return true;
|
110 |
}
|
111 |
|
|
|
|
|
|
|
112 |
public function action_doFeatureProcessorShutdown() {
|
113 |
}
|
114 |
|
|
|
|
|
|
|
115 |
/**
|
116 |
*/
|
117 |
public function init() {
|
@@ -120,7 +123,7 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
|
|
120 |
/**
|
121 |
* @return bool
|
122 |
*/
|
123 |
-
|
124 |
return true;
|
125 |
}
|
126 |
|
@@ -141,7 +144,7 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
|
|
141 |
}
|
142 |
|
143 |
$bCantDismiss = isset( $aNoticeData[ 'notice_attributes' ][ 'can_dismiss' ] )
|
144 |
-
|
145 |
|
146 |
$oNotices = $this->loadAdminNoticesProcessor();
|
147 |
if ( !$oNotices->isDismissed( $aAttrs[ 'id' ] ) || $bCantDismiss ) {
|
@@ -187,14 +190,6 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
|
|
187 |
return str_replace( '_', '-', $this->loadWp()->getLocale() );
|
188 |
}
|
189 |
|
190 |
-
/**
|
191 |
-
* @return mixed
|
192 |
-
*/
|
193 |
-
public function getPluginDefaultRecipientAddress() {
|
194 |
-
return apply_filters( $this->getFeature()->prefix( 'report_email_address' ), $this->loadWp()
|
195 |
-
->getSiteAdminEmail() );
|
196 |
-
}
|
197 |
-
|
198 |
/**
|
199 |
* @return ICWP_WPSF_Processor_Email
|
200 |
*/
|
@@ -206,7 +201,7 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
|
|
206 |
* @return ICWP_WPSF_FeatureHandler_Base
|
207 |
*/
|
208 |
protected function getFeature() {
|
209 |
-
return $this->
|
210 |
}
|
211 |
|
212 |
/**
|
9 |
/**
|
10 |
* @var ICWP_WPSF_FeatureHandler_Base
|
11 |
*/
|
12 |
+
protected $oModCon;
|
13 |
|
14 |
/**
|
15 |
* @var int
|
22 |
protected $aSubProcessors;
|
23 |
|
24 |
/**
|
25 |
+
* @param ICWP_WPSF_FeatureHandler_Base $oModCon
|
26 |
*/
|
27 |
+
public function __construct( $oModCon ) {
|
28 |
+
$this->oModCon = $oModCon;
|
29 |
+
add_action( $oModCon->prefix( 'plugin_shutdown' ), array( $this, 'onModuleShutdown' ) );
|
30 |
+
add_action( $oModCon->prefix( 'generate_admin_notices' ), array( $this, 'autoAddToAdminNotices' ) );
|
|
|
|
|
|
|
31 |
if ( method_exists( $this, 'addToAdminNotices' ) ) {
|
32 |
+
add_action( $oModCon->prefix( 'generate_admin_notices' ), array( $this, 'addToAdminNotices' ) );
|
33 |
}
|
34 |
$this->init();
|
35 |
}
|
106 |
return true;
|
107 |
}
|
108 |
|
109 |
+
/**
|
110 |
+
* @deprecated remove next release
|
111 |
+
*/
|
112 |
public function action_doFeatureProcessorShutdown() {
|
113 |
}
|
114 |
|
115 |
+
public function onModuleShutdown() {
|
116 |
+
}
|
117 |
+
|
118 |
/**
|
119 |
*/
|
120 |
public function init() {
|
123 |
/**
|
124 |
* @return bool
|
125 |
*/
|
126 |
+
public function isReadyToRun() {
|
127 |
return true;
|
128 |
}
|
129 |
|
144 |
}
|
145 |
|
146 |
$bCantDismiss = isset( $aNoticeData[ 'notice_attributes' ][ 'can_dismiss' ] )
|
147 |
+
&& !$aNoticeData[ 'notice_attributes' ][ 'can_dismiss' ];
|
148 |
|
149 |
$oNotices = $this->loadAdminNoticesProcessor();
|
150 |
if ( !$oNotices->isDismissed( $aAttrs[ 'id' ] ) || $bCantDismiss ) {
|
190 |
return str_replace( '_', '-', $this->loadWp()->getLocale() );
|
191 |
}
|
192 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
/**
|
194 |
* @return ICWP_WPSF_Processor_Email
|
195 |
*/
|
201 |
* @return ICWP_WPSF_FeatureHandler_Base
|
202 |
*/
|
203 |
protected function getFeature() {
|
204 |
+
return $this->oModCon;
|
205 |
}
|
206 |
|
207 |
/**
|
src/processors/base_plugin.php
CHANGED
@@ -127,7 +127,7 @@ class ICWP_WPSF_Processor_BasePlugin extends ICWP_WPSF_Processor_BaseWpsf {
|
|
127 |
'help' => _wpsf__( 'Dropping support for PHP 5.2 and 5.3' )
|
128 |
),
|
129 |
'hrefs' => array(
|
130 |
-
'help' => '
|
131 |
)
|
132 |
);
|
133 |
$this->insertAdminNotice( $aRenderData );
|
127 |
'help' => _wpsf__( 'Dropping support for PHP 5.2 and 5.3' )
|
128 |
),
|
129 |
'hrefs' => array(
|
130 |
+
'help' => 'https://icwp.io/aq',
|
131 |
)
|
132 |
);
|
133 |
$this->insertAdminNotice( $aRenderData );
|
src/processors/base_wpsf.php
CHANGED
@@ -54,6 +54,23 @@ abstract class ICWP_WPSF_Processor_BaseWpsf extends ICWP_WPSF_Processor_Base {
|
|
54 |
return (int)round( ( $this->loadDP()->time() - $nTimeInstalled )/DAY_IN_SECONDS );
|
55 |
}
|
56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
/**
|
58 |
* @return bool
|
59 |
*/
|
@@ -88,7 +105,10 @@ abstract class ICWP_WPSF_Processor_BaseWpsf extends ICWP_WPSF_Processor_Base {
|
|
88 |
->getGoogleRecaptchaLib( $oFO->getGoogleRecaptchaSecretKey() )
|
89 |
->verify( $sCaptchaResponse, $this->ip() );
|
90 |
if ( empty( $oResponse ) || !$oResponse->isSuccess() ) {
|
91 |
-
throw new Exception(
|
|
|
|
|
|
|
92 |
}
|
93 |
}
|
94 |
return true;
|
54 |
return (int)round( ( $this->loadDP()->time() - $nTimeInstalled )/DAY_IN_SECONDS );
|
55 |
}
|
56 |
|
57 |
+
/**
|
58 |
+
* @param WP_User $oUser
|
59 |
+
* @return bool
|
60 |
+
*/
|
61 |
+
protected function isUserSubjectToLoginIntent( $oUser = null ) {
|
62 |
+
$oWpUsers = $this->loadWpUsers();
|
63 |
+
if ( !is_a( $oUser, 'WP_User' ) ) {
|
64 |
+
if ( $oWpUsers->isUserLoggedIn() ) {
|
65 |
+
$oUser = $oWpUsers->getCurrentWpUser();
|
66 |
+
}
|
67 |
+
else {
|
68 |
+
return false; // If we can't get a valid WP_User, then always false.
|
69 |
+
}
|
70 |
+
}
|
71 |
+
return apply_filters( $this->prefix( 'user_subject_to_login_intent' ), false, $oUser );
|
72 |
+
}
|
73 |
+
|
74 |
/**
|
75 |
* @return bool
|
76 |
*/
|
105 |
->getGoogleRecaptchaLib( $oFO->getGoogleRecaptchaSecretKey() )
|
106 |
->verify( $sCaptchaResponse, $this->ip() );
|
107 |
if ( empty( $oResponse ) || !$oResponse->isSuccess() ) {
|
108 |
+
throw new Exception(
|
109 |
+
_wpsf__( 'Whoops.' ).' '._wpsf__( 'Google reCAPTCHA verification failed.' )
|
110 |
+
.( $this->loadWp()->isAjax() ? ' '._wpsf__( 'Maybe refresh the page and try again.' ) : '' ),
|
111 |
+
2 );
|
112 |
}
|
113 |
}
|
114 |
return true;
|
src/processors/basedb.php
CHANGED
@@ -25,12 +25,12 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
|
|
25 |
protected $nAutoExpirePeriod = null;
|
26 |
|
27 |
/**
|
28 |
-
* @param ICWP_WPSF_FeatureHandler_Base $
|
29 |
* @param string $sTableName
|
30 |
* @throws Exception
|
31 |
*/
|
32 |
-
public function __construct( $
|
33 |
-
parent::__construct( $
|
34 |
$this->setTableName( $sTableName );
|
35 |
$this->createCleanupCron();
|
36 |
$this->initializeTable();
|
@@ -40,8 +40,8 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
|
|
40 |
/**
|
41 |
* @return bool
|
42 |
*/
|
43 |
-
|
44 |
-
return ( parent::
|
45 |
}
|
46 |
|
47 |
/**
|
@@ -280,8 +280,8 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
|
|
280 |
* 1 in 10 page loads will clean the databases. This ensures that even if the crons don't run
|
281 |
* correctly, we'll keep it trim.
|
282 |
*/
|
283 |
-
public function
|
284 |
-
parent::
|
285 |
if ( rand( 1, 10 ) === 1 ) {
|
286 |
$this->cleanupDatabase();
|
287 |
}
|
25 |
protected $nAutoExpirePeriod = null;
|
26 |
|
27 |
/**
|
28 |
+
* @param ICWP_WPSF_FeatureHandler_Base $oModCon
|
29 |
* @param string $sTableName
|
30 |
* @throws Exception
|
31 |
*/
|
32 |
+
public function __construct( $oModCon, $sTableName = null ) {
|
33 |
+
parent::__construct( $oModCon );
|
34 |
$this->setTableName( $sTableName );
|
35 |
$this->createCleanupCron();
|
36 |
$this->initializeTable();
|
40 |
/**
|
41 |
* @return bool
|
42 |
*/
|
43 |
+
public function isReadyToRun() {
|
44 |
+
return ( parent::isReadyToRun() && $this->getTableExists() );
|
45 |
}
|
46 |
|
47 |
/**
|
280 |
* 1 in 10 page loads will clean the databases. This ensures that even if the crons don't run
|
281 |
* correctly, we'll keep it trim.
|
282 |
*/
|
283 |
+
public function onModuleShutdown() {
|
284 |
+
parent::onModuleShutdown();
|
285 |
if ( rand( 1, 10 ) === 1 ) {
|
286 |
$this->cleanupDatabase();
|
287 |
}
|
src/processors/comments_filter.php
CHANGED
@@ -21,7 +21,7 @@ class ICWP_WPSF_Processor_CommentsFilter extends ICWP_WPSF_Processor_BaseWpsf {
|
|
21 |
$oBotSpamProcessor->run();
|
22 |
}
|
23 |
|
24 |
-
if ( $this->getIsOption( 'enable_comments_human_spam_filter', 'Y' ) && $this->
|
25 |
->isCommentPost() ) {
|
26 |
require_once( dirname( __FILE__ ).'/commentsfilter_humanspam.php' );
|
27 |
$oHumanSpamProcessor = new ICWP_WPSF_Processor_CommentsFilter_HumanSpam( $oFO );
|
21 |
$oBotSpamProcessor->run();
|
22 |
}
|
23 |
|
24 |
+
if ( $this->getIsOption( 'enable_comments_human_spam_filter', 'Y' ) && $this->loadWpComments()
|
25 |
->isCommentPost() ) {
|
26 |
require_once( dirname( __FILE__ ).'/commentsfilter_humanspam.php' );
|
27 |
$oHumanSpamProcessor = new ICWP_WPSF_Processor_CommentsFilter_HumanSpam( $oFO );
|
src/processors/commentsfilter_antibotspam.php
CHANGED
@@ -36,10 +36,10 @@ class ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam extends ICWP_WPSF_BaseDbPro
|
|
36 |
private $aRawCommentData;
|
37 |
|
38 |
/**
|
39 |
-
* @param ICWP_WPSF_FeatureHandler_CommentsFilter $
|
40 |
*/
|
41 |
-
public function __construct( ICWP_WPSF_FeatureHandler_CommentsFilter $
|
42 |
-
parent::__construct( $
|
43 |
}
|
44 |
|
45 |
/**
|
@@ -59,7 +59,7 @@ class ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam extends ICWP_WPSF_BaseDbPro
|
|
59 |
return $fIfDoCheck;
|
60 |
}
|
61 |
|
62 |
-
$oWpComments = $this->
|
63 |
|
64 |
// 1st are comments enabled on this post?
|
65 |
$nPostId = $this->getRawCommentData( 'comment_post_ID' );
|
@@ -79,7 +79,7 @@ class ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam extends ICWP_WPSF_BaseDbPro
|
|
79 |
/**
|
80 |
*/
|
81 |
public function run() {
|
82 |
-
if ( !$this->
|
83 |
return;
|
84 |
}
|
85 |
|
@@ -172,7 +172,7 @@ class ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam extends ICWP_WPSF_BaseDbPro
|
|
172 |
$sStatKey = '';
|
173 |
$sExplanation = '';
|
174 |
|
175 |
-
$oDp = $this->
|
176 |
$sFieldCheckboxName = $oDp->FetchPost( 'cb_nombre' );
|
177 |
$sFieldHoney = $oDp->FetchPost( 'sugar_sweet_email' );
|
178 |
$sFieldCommentToken = $oDp->FetchPost( 'comment_token' );
|
@@ -231,7 +231,7 @@ class ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam extends ICWP_WPSF_BaseDbPro
|
|
231 |
}
|
232 |
else if ( function_exists( 'WPWall_Init' ) ) {
|
233 |
// Compatibility with shoutbox WP Wall Plugin http://wordpress.org/plugins/wp-wall/
|
234 |
-
if ( !is_null( $this->
|
235 |
$bCheck = false;
|
236 |
}
|
237 |
}
|
@@ -244,7 +244,7 @@ class ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam extends ICWP_WPSF_BaseDbPro
|
|
244 |
*/
|
245 |
protected function getUniqueFormId() {
|
246 |
if ( !isset( $this->sFormId ) ) {
|
247 |
-
$oDp = $this->
|
248 |
$sId = $oDp->GenerateRandomLetter().$oDp->GenerateRandomString( rand( 7, 23 ), 7 );
|
249 |
$this->sFormId = preg_replace(
|
250 |
'#[^a-zA-Z0-9]#', '',
|
36 |
private $aRawCommentData;
|
37 |
|
38 |
/**
|
39 |
+
* @param ICWP_WPSF_FeatureHandler_CommentsFilter $oModCon
|
40 |
*/
|
41 |
+
public function __construct( ICWP_WPSF_FeatureHandler_CommentsFilter $oModCon ) {
|
42 |
+
parent::__construct( $oModCon, $oModCon->getCommentsFilterTableName() );
|
43 |
}
|
44 |
|
45 |
/**
|
59 |
return $fIfDoCheck;
|
60 |
}
|
61 |
|
62 |
+
$oWpComments = $this->loadWpComments();
|
63 |
|
64 |
// 1st are comments enabled on this post?
|
65 |
$nPostId = $this->getRawCommentData( 'comment_post_ID' );
|
79 |
/**
|
80 |
*/
|
81 |
public function run() {
|
82 |
+
if ( !$this->isReadyToRun() ) {
|
83 |
return;
|
84 |
}
|
85 |
|
172 |
$sStatKey = '';
|
173 |
$sExplanation = '';
|
174 |
|
175 |
+
$oDp = $this->loadDP();
|
176 |
$sFieldCheckboxName = $oDp->FetchPost( 'cb_nombre' );
|
177 |
$sFieldHoney = $oDp->FetchPost( 'sugar_sweet_email' );
|
178 |
$sFieldCommentToken = $oDp->FetchPost( 'comment_token' );
|
231 |
}
|
232 |
else if ( function_exists( 'WPWall_Init' ) ) {
|
233 |
// Compatibility with shoutbox WP Wall Plugin http://wordpress.org/plugins/wp-wall/
|
234 |
+
if ( !is_null( $this->loadDP()->FetchPost( 'submit_wall_post' ) ) ) {
|
235 |
$bCheck = false;
|
236 |
}
|
237 |
}
|
244 |
*/
|
245 |
protected function getUniqueFormId() {
|
246 |
if ( !isset( $this->sFormId ) ) {
|
247 |
+
$oDp = $this->loadDP();
|
248 |
$sId = $oDp->GenerateRandomLetter().$oDp->GenerateRandomString( rand( 7, 23 ), 7 );
|
249 |
$this->sFormId = preg_replace(
|
250 |
'#[^a-zA-Z0-9]#', '',
|
src/processors/commentsfilter_googlerecaptcha.php
CHANGED
@@ -25,7 +25,7 @@ class ICWP_WPSF_Processor_CommentsFilter_GoogleRecaptcha extends ICWP_WPSF_Proce
|
|
25 |
* The WP Query is alive and well at this stage so we can assume certain data is available.
|
26 |
*/
|
27 |
public function setup() {
|
28 |
-
if ( $this->
|
29 |
add_action( 'wp_enqueue_scripts', array( $this, 'registerGoogleRecaptchaJs' ), 99 );
|
30 |
add_action( 'comment_form_after_fields', array( $this, 'printGoogleRecaptchaCheck' ) );
|
31 |
}
|
25 |
* The WP Query is alive and well at this stage so we can assume certain data is available.
|
26 |
*/
|
27 |
public function setup() {
|
28 |
+
if ( $this->loadWpComments()->isCommentsOpen() ) {
|
29 |
add_action( 'wp_enqueue_scripts', array( $this, 'registerGoogleRecaptchaJs' ), 99 );
|
30 |
add_action( 'comment_form_after_fields', array( $this, 'printGoogleRecaptchaCheck' ) );
|
31 |
}
|
src/processors/commentsfilter_humanspam.php
CHANGED
@@ -26,7 +26,7 @@ class ICWP_WPSF_Processor_CommentsFilter_HumanSpam extends ICWP_WPSF_Processor_C
|
|
26 |
return $fIfDoCheck;
|
27 |
}
|
28 |
|
29 |
-
$oWpComments = $this->
|
30 |
|
31 |
// 1st are comments enabled on this post?
|
32 |
$nPostId = $this->getRawCommentData( 'comment_post_ID' );
|
@@ -77,7 +77,7 @@ class ICWP_WPSF_Processor_CommentsFilter_HumanSpam extends ICWP_WPSF_Processor_C
|
|
77 |
$aCommentData[ 'comment_author_url' ],
|
78 |
$aCommentData[ 'comment_content' ],
|
79 |
$this->ip(),
|
80 |
-
substr( $this->
|
81 |
);
|
82 |
}
|
83 |
|
26 |
return $fIfDoCheck;
|
27 |
}
|
28 |
|
29 |
+
$oWpComments = $this->loadWpComments();
|
30 |
|
31 |
// 1st are comments enabled on this post?
|
32 |
$nPostId = $this->getRawCommentData( 'comment_post_ID' );
|
77 |
$aCommentData[ 'comment_author_url' ],
|
78 |
$aCommentData[ 'comment_content' ],
|
79 |
$this->ip(),
|
80 |
+
substr( $this->loadDP()->FetchServer( 'HTTP_USER_AGENT', '' ), 0, 254 )
|
81 |
);
|
82 |
}
|
83 |
|
src/processors/cronbase.php
CHANGED
@@ -32,7 +32,9 @@ abstract class ICWP_WPSF_Processor_CronBase extends ICWP_WPSF_Processor_BaseWpsf
|
|
32 |
* @return string
|
33 |
*/
|
34 |
protected function getCronRecurrence() {
|
35 |
-
|
|
|
|
|
36 |
}
|
37 |
|
38 |
/**
|
@@ -41,9 +43,11 @@ abstract class ICWP_WPSF_Processor_CronBase extends ICWP_WPSF_Processor_BaseWpsf
|
|
41 |
abstract protected function getCronCallback();
|
42 |
|
43 |
/**
|
44 |
-
* @return int
|
45 |
*/
|
46 |
-
|
|
|
|
|
47 |
|
48 |
/**
|
49 |
* @return string
|
32 |
* @return string
|
33 |
*/
|
34 |
protected function getCronRecurrence() {
|
35 |
+
$sFreq = $this->getCronFrequency();
|
36 |
+
$aStdIntervals = array_keys( wp_get_schedules() );
|
37 |
+
return in_array( $sFreq, $aStdIntervals ) ? $sFreq : $this->prefix( sprintf( 'per-day-%s', $sFreq ) );
|
38 |
}
|
39 |
|
40 |
/**
|
43 |
abstract protected function getCronCallback();
|
44 |
|
45 |
/**
|
46 |
+
* @return int|string
|
47 |
*/
|
48 |
+
protected function getCronFrequency() {
|
49 |
+
return 'daily';
|
50 |
+
}
|
51 |
|
52 |
/**
|
53 |
* @return string
|
src/processors/email.php
CHANGED
@@ -10,8 +10,6 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
|
|
10 |
|
11 |
const Slug = 'email';
|
12 |
|
13 |
-
protected $m_sRecipientAddress;
|
14 |
-
|
15 |
/**
|
16 |
* @var string
|
17 |
*/
|
@@ -43,10 +41,10 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
|
|
43 |
protected $bEmailIsThrottled;
|
44 |
|
45 |
/**
|
46 |
-
* @param ICWP_WPSF_FeatureHandler_Email $
|
47 |
*/
|
48 |
-
public function __construct( ICWP_WPSF_FeatureHandler_Email $
|
49 |
-
parent::__construct( $
|
50 |
}
|
51 |
|
52 |
public function init() {
|
@@ -86,27 +84,38 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
|
|
86 |
}
|
87 |
|
88 |
/**
|
|
|
89 |
* @param string $sAddress
|
90 |
* @param string $sSubject
|
91 |
* @param array $aMessage
|
92 |
* @return boolean
|
93 |
-
* @uses wp_mail
|
94 |
*/
|
95 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
$this->updateEmailThrottle();
|
98 |
-
// We make it appear to have "succeeded" if the throttle is applied.
|
99 |
if ( $this->bEmailIsThrottled ) {
|
100 |
return true;
|
101 |
}
|
102 |
|
103 |
-
$aMessage = array_merge( $this->getEmailHeader(), $aMessage, $this->getEmailFooter() );
|
104 |
-
|
105 |
$this->emailFilters( true );
|
106 |
$bSuccess = wp_mail(
|
107 |
$this->verifyEmailAddress( $sAddress ),
|
108 |
wp_specialchars_decode( sprintf( '[%s] %s', $this->loadWp()->getSiteName(), $sSubject ) ),
|
109 |
-
|
110 |
);
|
111 |
$this->emailFilters( false );
|
112 |
|
@@ -185,7 +194,7 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
|
|
185 |
* @return boolean
|
186 |
*/
|
187 |
public function sendEmail( $sEmailSubject, $aMessage ) {
|
188 |
-
return $this->
|
189 |
}
|
190 |
|
191 |
/**
|
@@ -246,17 +255,12 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
|
|
246 |
}
|
247 |
}
|
248 |
|
249 |
-
public function setDefaultRecipientAddress( $insEmailAddress ) {
|
250 |
-
$this->m_sRecipientAddress = $insEmailAddress;
|
251 |
-
}
|
252 |
-
|
253 |
/**
|
254 |
-
* @param string $
|
255 |
* @return string
|
256 |
*/
|
257 |
-
public function verifyEmailAddress( $
|
258 |
-
return $this->loadDP()
|
259 |
-
->validEmail( $sEmailAddress ) ? $sEmailAddress : $this->getPluginDefaultRecipientAddress();
|
260 |
}
|
261 |
|
262 |
public function getThrottleLimit() {
|
10 |
|
11 |
const Slug = 'email';
|
12 |
|
|
|
|
|
13 |
/**
|
14 |
* @var string
|
15 |
*/
|
41 |
protected $bEmailIsThrottled;
|
42 |
|
43 |
/**
|
44 |
+
* @param ICWP_WPSF_FeatureHandler_Email $oModCon
|
45 |
*/
|
46 |
+
public function __construct( ICWP_WPSF_FeatureHandler_Email $oModCon ) {
|
47 |
+
parent::__construct( $oModCon );
|
48 |
}
|
49 |
|
50 |
public function init() {
|
84 |
}
|
85 |
|
86 |
/**
|
87 |
+
* Wraps up a message with header and footer
|
88 |
* @param string $sAddress
|
89 |
* @param string $sSubject
|
90 |
* @param array $aMessage
|
91 |
* @return boolean
|
|
|
92 |
*/
|
93 |
+
public function sendEmailWithWrap( $sAddress = '', $sSubject = '', $aMessage = array() ) {
|
94 |
+
return $this->send(
|
95 |
+
$sAddress,
|
96 |
+
$sSubject,
|
97 |
+
'<html>'.implode( "<br />", array_merge( $this->getEmailHeader(), $aMessage, $this->getEmailFooter() ) ).'</html>'
|
98 |
+
);
|
99 |
+
}
|
100 |
|
101 |
+
/**
|
102 |
+
* @uses wp_mail
|
103 |
+
* @param string $sAddress
|
104 |
+
* @param string $sSubject
|
105 |
+
* @param string $sMessageBody
|
106 |
+
* @return bool
|
107 |
+
*/
|
108 |
+
public function send( $sAddress = '', $sSubject = '', $sMessageBody = '' ) {
|
109 |
$this->updateEmailThrottle();
|
|
|
110 |
if ( $this->bEmailIsThrottled ) {
|
111 |
return true;
|
112 |
}
|
113 |
|
|
|
|
|
114 |
$this->emailFilters( true );
|
115 |
$bSuccess = wp_mail(
|
116 |
$this->verifyEmailAddress( $sAddress ),
|
117 |
wp_specialchars_decode( sprintf( '[%s] %s', $this->loadWp()->getSiteName(), $sSubject ) ),
|
118 |
+
$sMessageBody
|
119 |
);
|
120 |
$this->emailFilters( false );
|
121 |
|
194 |
* @return boolean
|
195 |
*/
|
196 |
public function sendEmail( $sEmailSubject, $aMessage ) {
|
197 |
+
return $this->sendEmailWithWrap( null, $sEmailSubject, $aMessage );
|
198 |
}
|
199 |
|
200 |
/**
|
255 |
}
|
256 |
}
|
257 |
|
|
|
|
|
|
|
|
|
258 |
/**
|
259 |
+
* @param string $sEmail
|
260 |
* @return string
|
261 |
*/
|
262 |
+
public function verifyEmailAddress( $sEmail = '' ) {
|
263 |
+
return $this->loadDP()->validEmail( $sEmail ) ? $sEmail : $this->loadWp()->getSiteAdminEmail();
|
|
|
264 |
}
|
265 |
|
266 |
public function getThrottleLimit() {
|
src/processors/firewall.php
CHANGED
@@ -63,7 +63,7 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
|
|
63 |
*/
|
64 |
protected function getIfPerformFirewallScan() {
|
65 |
$bPerformScan = true;
|
66 |
-
$oDp = $this->
|
67 |
|
68 |
if ( count( $this->getRawRequestParams() ) == 0 ) {
|
69 |
$bPerformScan = false;
|
@@ -277,7 +277,7 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
|
|
277 |
|
278 |
if ( $this->getIsOption( 'block_send_email', 'Y' ) ) {
|
279 |
|
280 |
-
$sRecipient = $
|
281 |
if ( $this->sendBlockEmail( $sRecipient ) ) {
|
282 |
$this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Firewall Block email alert to: %s' ), $sRecipient ) );
|
283 |
}
|
@@ -361,7 +361,7 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
|
|
361 |
return $this->aPageParams;
|
362 |
}
|
363 |
|
364 |
-
$oDp = $this->
|
365 |
$this->aPageParams = $this->getRawRequestParams();
|
366 |
$aWhitelistPages = $this->getWhitelistPages();
|
367 |
$aRequestUriParts = $oDp->getRequestUriParts();
|
@@ -411,7 +411,7 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
|
|
411 |
*/
|
412 |
protected function getRawRequestParams() {
|
413 |
if ( !isset( $this->aRawRequestParams ) ) {
|
414 |
-
$this->aRawRequestParams = $this->
|
415 |
->getRawRequestParams( $this->getIsOption( 'include_cookie_checks', 'Y' ) );
|
416 |
}
|
417 |
return $this->aRawRequestParams;
|
@@ -477,7 +477,7 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
|
|
477 |
$sEmailSubject = _wpsf__( 'Firewall Block Alert' );
|
478 |
|
479 |
return $this->getEmailProcessor()
|
480 |
-
->
|
481 |
}
|
482 |
|
483 |
/**
|
63 |
*/
|
64 |
protected function getIfPerformFirewallScan() {
|
65 |
$bPerformScan = true;
|
66 |
+
$oDp = $this->loadDP();
|
67 |
|
68 |
if ( count( $this->getRawRequestParams() ) == 0 ) {
|
69 |
$bPerformScan = false;
|
277 |
|
278 |
if ( $this->getIsOption( 'block_send_email', 'Y' ) ) {
|
279 |
|
280 |
+
$sRecipient = $oFO->getPluginDefaultRecipientAddress();
|
281 |
if ( $this->sendBlockEmail( $sRecipient ) ) {
|
282 |
$this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Firewall Block email alert to: %s' ), $sRecipient ) );
|
283 |
}
|
361 |
return $this->aPageParams;
|
362 |
}
|
363 |
|
364 |
+
$oDp = $this->loadDP();
|
365 |
$this->aPageParams = $this->getRawRequestParams();
|
366 |
$aWhitelistPages = $this->getWhitelistPages();
|
367 |
$aRequestUriParts = $oDp->getRequestUriParts();
|
411 |
*/
|
412 |
protected function getRawRequestParams() {
|
413 |
if ( !isset( $this->aRawRequestParams ) ) {
|
414 |
+
$this->aRawRequestParams = $this->loadDP()
|
415 |
->getRawRequestParams( $this->getIsOption( 'include_cookie_checks', 'Y' ) );
|
416 |
}
|
417 |
return $this->aRawRequestParams;
|
477 |
$sEmailSubject = _wpsf__( 'Firewall Block Alert' );
|
478 |
|
479 |
return $this->getEmailProcessor()
|
480 |
+
->sendEmailWithWrap( $sRecipient, $sEmailSubject, $aMessage );
|
481 |
}
|
482 |
|
483 |
/**
|
src/processors/hack_protect.php
CHANGED
@@ -15,7 +15,7 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
|
|
15 |
/** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
|
16 |
$oFO = $this->getFeature();
|
17 |
|
18 |
-
$sPath = $this->
|
19 |
if ( !empty( $sPath ) && ( strpos( $sPath, '/wp-admin/admin-ajax.php' ) !== false ) ) {
|
20 |
$this->revSliderPatch_LFI();
|
21 |
$this->revSliderPatch_AFU();
|
@@ -160,7 +160,7 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
|
|
160 |
}
|
161 |
|
162 |
protected function revSliderPatch_LFI() {
|
163 |
-
$oDp = $this->
|
164 |
|
165 |
$sAction = $oDp->query( 'action', '' );
|
166 |
$sFileExt = strtolower( $oDp->getExtension( $oDp->query( 'img', '' ) ) );
|
@@ -172,7 +172,7 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
|
|
172 |
}
|
173 |
|
174 |
protected function revSliderPatch_AFU() {
|
175 |
-
$oDp = $this->
|
176 |
|
177 |
$sAction = strtolower( $oDp->request( 'action', '' ) );
|
178 |
$sClientAction = strtolower( $oDp->request( 'client_action', '' ) );
|
15 |
/** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
|
16 |
$oFO = $this->getFeature();
|
17 |
|
18 |
+
$sPath = $this->loadDP()->getRequestPath();
|
19 |
if ( !empty( $sPath ) && ( strpos( $sPath, '/wp-admin/admin-ajax.php' ) !== false ) ) {
|
20 |
$this->revSliderPatch_LFI();
|
21 |
$this->revSliderPatch_AFU();
|
160 |
}
|
161 |
|
162 |
protected function revSliderPatch_LFI() {
|
163 |
+
$oDp = $this->loadDP();
|
164 |
|
165 |
$sAction = $oDp->query( 'action', '' );
|
166 |
$sFileExt = strtolower( $oDp->getExtension( $oDp->query( 'img', '' ) ) );
|
172 |
}
|
173 |
|
174 |
protected function revSliderPatch_AFU() {
|
175 |
+
$oDp = $this->loadDP();
|
176 |
|
177 |
$sAction = strtolower( $oDp->request( 'action', '' ) );
|
178 |
$sClientAction = strtolower( $oDp->request( 'client_action', '' ) );
|
src/processors/hackprotect_corechecksumscan.php
CHANGED
@@ -253,18 +253,21 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
|
|
253 |
$oFO->canRunWizards() ? $this->buildEmailBody( $aFiles ) : $this->buildEmailBody_Legacy( $aFiles )
|
254 |
);
|
255 |
|
256 |
-
|
257 |
-
|
|
|
|
|
258 |
|
|
|
259 |
$this->getEmailProcessor()
|
260 |
-
->
|
261 |
-
$
|
262 |
sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Modified Core WordPress Files Discovered' ) ),
|
263 |
$aContent
|
264 |
);
|
265 |
|
266 |
$this->addToAuditEntry(
|
267 |
-
sprintf( _wpsf__( 'Sent Checksum Scan Notification email alert to: %s' ), $
|
268 |
);
|
269 |
}
|
270 |
|
@@ -338,7 +341,7 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
|
|
338 |
else {
|
339 |
$aContent[] = _wpsf__( 'You should review these files and replace them with official versions if required.' );
|
340 |
$aContent[] = _wpsf__( 'Alternatively you can have the plugin attempt to repair/replace these files automatically.' )
|
341 |
-
.' [<a href="
|
342 |
}
|
343 |
|
344 |
return $aContent;
|
253 |
$oFO->canRunWizards() ? $this->buildEmailBody( $aFiles ) : $this->buildEmailBody_Legacy( $aFiles )
|
254 |
);
|
255 |
|
256 |
+
if ( !$oFO->getConn()->isRelabelled() ) {
|
257 |
+
$aContent[] = '';
|
258 |
+
$aContent[] = '[ <a href="https://icwp.io/moreinfochecksum">'._wpsf__( 'More Info On This Scanner' ).' ]</a>';
|
259 |
+
}
|
260 |
|
261 |
+
$sTo = $oFO->getPluginDefaultRecipientAddress();
|
262 |
$this->getEmailProcessor()
|
263 |
+
->sendEmailWithWrap(
|
264 |
+
$sTo,
|
265 |
sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Modified Core WordPress Files Discovered' ) ),
|
266 |
$aContent
|
267 |
);
|
268 |
|
269 |
$this->addToAuditEntry(
|
270 |
+
sprintf( _wpsf__( 'Sent Checksum Scan Notification email alert to: %s' ), $sTo )
|
271 |
);
|
272 |
}
|
273 |
|
341 |
else {
|
342 |
$aContent[] = _wpsf__( 'You should review these files and replace them with official versions if required.' );
|
343 |
$aContent[] = _wpsf__( 'Alternatively you can have the plugin attempt to repair/replace these files automatically.' )
|
344 |
+
.' [<a href="https://icwp.io/moreinfochecksum">'._wpsf__( 'More Info' ).']</a>';
|
345 |
}
|
346 |
|
347 |
return $aContent;
|
src/processors/hackprotect_filecleanerscan.php
CHANGED
@@ -237,18 +237,21 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
|
|
237 |
$oFO->canRunWizards() ? $this->buildEmailBody( $aFiles ) : $this->buildEmailBody_Legacy( $aFiles )
|
238 |
);
|
239 |
|
240 |
-
|
241 |
-
|
|
|
|
|
242 |
|
|
|
243 |
$this->getEmailProcessor()
|
244 |
-
->
|
245 |
-
$
|
246 |
sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Unrecognised WordPress Files Detected' ) ),
|
247 |
$aContent
|
248 |
);
|
249 |
|
250 |
$this->addToAuditEntry(
|
251 |
-
sprintf( _wpsf__( 'Sent Unrecognised File Scan Notification email alert to: %s' ), $
|
252 |
);
|
253 |
}
|
254 |
|
237 |
$oFO->canRunWizards() ? $this->buildEmailBody( $aFiles ) : $this->buildEmailBody_Legacy( $aFiles )
|
238 |
);
|
239 |
|
240 |
+
if ( !$oFO->getConn()->isRelabelled() ) {
|
241 |
+
$aContent[] = '';
|
242 |
+
$aContent[] = '[ <a href="https://icwp.io/moreinfochecksum">'._wpsf__( 'More Info On This Scanner' ).' ]</a>';
|
243 |
+
}
|
244 |
|
245 |
+
$sTo = $oFO->getPluginDefaultRecipientAddress();
|
246 |
$this->getEmailProcessor()
|
247 |
+
->sendEmailWithWrap(
|
248 |
+
$sTo,
|
249 |
sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Unrecognised WordPress Files Detected' ) ),
|
250 |
$aContent
|
251 |
);
|
252 |
|
253 |
$this->addToAuditEntry(
|
254 |
+
sprintf( _wpsf__( 'Sent Unrecognised File Scan Notification email alert to: %s' ), $sTo )
|
255 |
);
|
256 |
}
|
257 |
|
src/processors/hackprotect_pluginvulnerabilities.php
CHANGED
@@ -53,10 +53,11 @@ if ( !class_exists( 'ICWP_WPSF_Processor_HackProtect_PluginVulnerabilities', fal
|
|
53 |
}
|
54 |
|
55 |
public function cron_dailyPluginVulnerabilitiesScan() {
|
|
|
|
|
56 |
|
57 |
$aPlugins = $this->loadWpPlugins()->getPlugins();
|
58 |
|
59 |
-
$sRecipient = $this->getPluginDefaultRecipientAddress();
|
60 |
foreach( $aPlugins as $sPluginFile => $aPluginData ) {
|
61 |
$aPluginVulnerabilityData = $this->getPluginVulnerabilityData( $sPluginFile, $aPluginData );
|
62 |
if ( is_array( $aPluginVulnerabilityData ) ) {
|
@@ -64,7 +65,7 @@ if ( !class_exists( 'ICWP_WPSF_Processor_HackProtect_PluginVulnerabilities', fal
|
|
64 |
}
|
65 |
}
|
66 |
|
67 |
-
$this->sendVulnerabilityNotification( $
|
68 |
}
|
69 |
|
70 |
/**
|
@@ -109,7 +110,7 @@ if ( !class_exists( 'ICWP_WPSF_Processor_HackProtect_PluginVulnerabilities', fal
|
|
109 |
$sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugin(s) Discovered With Known Security Vulnerabilities.' ) );
|
110 |
|
111 |
$bSendSuccess = $this->getEmailProcessor()
|
112 |
-
->
|
113 |
|
114 |
if ( $bSendSuccess ) {
|
115 |
$this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin Vulnerability Notification email alert to: %s' ), $sRecipient ) );
|
@@ -215,7 +216,7 @@ if ( !class_exists( 'ICWP_WPSF_Processor_HackProtect_PluginVulnerabilities', fal
|
|
215 |
$oWp = $this->loadWp();
|
216 |
$oFO = $this->getFeature();
|
217 |
|
218 |
-
$sSource = $oFO->
|
219 |
$sRawSource = $this->loadFS()->getUrlContent( $sSource );
|
220 |
if ( $sRawSource === false ) {
|
221 |
return false;
|
@@ -234,7 +235,7 @@ if ( !class_exists( 'ICWP_WPSF_Processor_HackProtect_PluginVulnerabilities', fal
|
|
234 |
*/
|
235 |
protected function getCronName() {
|
236 |
$oFO = $this->getFeature();
|
237 |
-
return $oFO->prefix( $oFO->
|
238 |
}
|
239 |
}
|
240 |
|
53 |
}
|
54 |
|
55 |
public function cron_dailyPluginVulnerabilitiesScan() {
|
56 |
+
/** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
|
57 |
+
$oFO = $this->getFeature();
|
58 |
|
59 |
$aPlugins = $this->loadWpPlugins()->getPlugins();
|
60 |
|
|
|
61 |
foreach( $aPlugins as $sPluginFile => $aPluginData ) {
|
62 |
$aPluginVulnerabilityData = $this->getPluginVulnerabilityData( $sPluginFile, $aPluginData );
|
63 |
if ( is_array( $aPluginVulnerabilityData ) ) {
|
65 |
}
|
66 |
}
|
67 |
|
68 |
+
$this->sendVulnerabilityNotification( $oFO->getPluginDefaultRecipientAddress() );
|
69 |
}
|
70 |
|
71 |
/**
|
110 |
$sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugin(s) Discovered With Known Security Vulnerabilities.' ) );
|
111 |
|
112 |
$bSendSuccess = $this->getEmailProcessor()
|
113 |
+
->sendEmailWithWrap( $sRecipient, $sEmailSubject, $this->aEmailContents );
|
114 |
|
115 |
if ( $bSendSuccess ) {
|
116 |
$this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin Vulnerability Notification email alert to: %s' ), $sRecipient ) );
|
216 |
$oWp = $this->loadWp();
|
217 |
$oFO = $this->getFeature();
|
218 |
|
219 |
+
$sSource = $oFO->getDef( 'plugin_vulnerabilities_data_source' );
|
220 |
$sRawSource = $this->loadFS()->getUrlContent( $sSource );
|
221 |
if ( $sRawSource === false ) {
|
222 |
return false;
|
235 |
*/
|
236 |
protected function getCronName() {
|
237 |
$oFO = $this->getFeature();
|
238 |
+
return $oFO->prefix( $oFO->getDef( 'notifications_cron_name' ) );
|
239 |
}
|
240 |
}
|
241 |
|
src/processors/hackprotect_ptguard.php
CHANGED
@@ -487,16 +487,16 @@ class ICWP_WPSF_Processor_HackProtect_PTGuard extends ICWP_WPSF_Processor_CronBa
|
|
487 |
$aContent[] = '';
|
488 |
}
|
489 |
|
490 |
-
$
|
491 |
$sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugins/Themes Have Been Altered' ) );
|
492 |
$bSendSuccess = $this->getEmailProcessor()
|
493 |
-
->
|
494 |
|
495 |
if ( $bSendSuccess ) {
|
496 |
-
$this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin/Theme Guard email alert to: %s' ), $
|
497 |
}
|
498 |
else {
|
499 |
-
$this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Plugin/Theme Guard email alert to: %s' ), $
|
500 |
}
|
501 |
}
|
502 |
|
487 |
$aContent[] = '';
|
488 |
}
|
489 |
|
490 |
+
$sTo = $oFO->getPluginDefaultRecipientAddress();
|
491 |
$sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugins/Themes Have Been Altered' ) );
|
492 |
$bSendSuccess = $this->getEmailProcessor()
|
493 |
+
->sendEmailWithWrap( $sTo, $sEmailSubject, $aContent );
|
494 |
|
495 |
if ( $bSendSuccess ) {
|
496 |
+
$this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin/Theme Guard email alert to: %s' ), $sTo ) );
|
497 |
}
|
498 |
else {
|
499 |
+
$this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Plugin/Theme Guard email alert to: %s' ), $sTo ) );
|
500 |
}
|
501 |
}
|
502 |
|
src/processors/hackprotect_wpvulnscan.php
CHANGED
@@ -202,6 +202,8 @@ class ICWP_WPSF_Processor_HackProtect_WpVulnScan extends ICWP_WPSF_Processor_Bas
|
|
202 |
if ( empty( $this->aNotifEmail ) ) {
|
203 |
return true;
|
204 |
}
|
|
|
|
|
205 |
$oWp = $this->loadWp();
|
206 |
$oConn = $this->getController();
|
207 |
|
@@ -216,15 +218,15 @@ class ICWP_WPSF_Processor_HackProtect_WpVulnScan extends ICWP_WPSF_Processor_Bas
|
|
216 |
$this->aNotifEmail[] = sprintf( _wpsf__( 'Go To Your Plugins: %s' ), $oWp->getAdminUrl_Plugins( $oConn->getIsWpmsNetworkAdminOnly() ) );
|
217 |
|
218 |
$sSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugin(s) Discovered With Known Security Vulnerabilities.' ) );
|
219 |
-
$
|
220 |
$bSendSuccess = $this->getEmailProcessor()
|
221 |
-
->
|
222 |
|
223 |
if ( $bSendSuccess ) {
|
224 |
-
$this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin Vulnerability Notification email alert to: %s' ), $
|
225 |
}
|
226 |
else {
|
227 |
-
$this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Plugin Vulnerability Notification email alert to: %s' ), $
|
228 |
}
|
229 |
return $bSendSuccess;
|
230 |
}
|
202 |
if ( empty( $this->aNotifEmail ) ) {
|
203 |
return true;
|
204 |
}
|
205 |
+
/** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
|
206 |
+
$oFO = $this->getFeature();
|
207 |
$oWp = $this->loadWp();
|
208 |
$oConn = $this->getController();
|
209 |
|
218 |
$this->aNotifEmail[] = sprintf( _wpsf__( 'Go To Your Plugins: %s' ), $oWp->getAdminUrl_Plugins( $oConn->getIsWpmsNetworkAdminOnly() ) );
|
219 |
|
220 |
$sSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugin(s) Discovered With Known Security Vulnerabilities.' ) );
|
221 |
+
$sTo = $oFO->getPluginDefaultRecipientAddress();
|
222 |
$bSendSuccess = $this->getEmailProcessor()
|
223 |
+
->sendEmailWithWrap( $sTo, $sSubject, $this->aNotifEmail );
|
224 |
|
225 |
if ( $bSendSuccess ) {
|
226 |
+
$this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin Vulnerability Notification email alert to: %s' ), $sTo ) );
|
227 |
}
|
228 |
else {
|
229 |
+
$this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Plugin Vulnerability Notification email alert to: %s' ), $sTo ) );
|
230 |
}
|
231 |
return $bSendSuccess;
|
232 |
}
|
src/processors/ips.php
CHANGED
@@ -19,23 +19,23 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
|
|
19 |
protected $bVisitorIsWhitelisted;
|
20 |
|
21 |
/**
|
22 |
-
* @param ICWP_WPSF_FeatureHandler_Ips $
|
23 |
*/
|
24 |
-
public function __construct( ICWP_WPSF_FeatureHandler_Ips $
|
25 |
-
parent::__construct( $
|
26 |
}
|
27 |
|
28 |
/**
|
29 |
* @return bool
|
30 |
*/
|
31 |
-
|
32 |
-
return ( parent::
|
33 |
}
|
34 |
|
35 |
/**
|
36 |
*/
|
37 |
public function run() {
|
38 |
-
if ( !$this->
|
39 |
return;
|
40 |
}
|
41 |
|
@@ -64,7 +64,7 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
|
|
64 |
$this->setIpTransgressed(); // We now black mark this IP
|
65 |
}
|
66 |
$this->addToAuditEntry(
|
67 |
-
sprintf( _wpsf__( '404 detected at "%s"' ), $this->
|
68 |
2, 'request_tracking_404'
|
69 |
);
|
70 |
}
|
19 |
protected $bVisitorIsWhitelisted;
|
20 |
|
21 |
/**
|
22 |
+
* @param ICWP_WPSF_FeatureHandler_Ips $oModCon
|
23 |
*/
|
24 |
+
public function __construct( ICWP_WPSF_FeatureHandler_Ips $oModCon ) {
|
25 |
+
parent::__construct( $oModCon, $oModCon->getIpListsTableName() );
|
26 |
}
|
27 |
|
28 |
/**
|
29 |
* @return bool
|
30 |
*/
|
31 |
+
public function isReadyToRun() {
|
32 |
+
return ( parent::isReadyToRun() && $this->loadIpService()->isValidIp_PublicRemote( $this->ip() ) );
|
33 |
}
|
34 |
|
35 |
/**
|
36 |
*/
|
37 |
public function run() {
|
38 |
+
if ( !$this->isReadyToRun() ) {
|
39 |
return;
|
40 |
}
|
41 |
|
64 |
$this->setIpTransgressed(); // We now black mark this IP
|
65 |
}
|
66 |
$this->addToAuditEntry(
|
67 |
+
sprintf( _wpsf__( '404 detected at "%s"' ), $this->loadDP()->getRequestPath() ),
|
68 |
2, 'request_tracking_404'
|
69 |
);
|
70 |
}
|
src/processors/license.php
CHANGED
@@ -32,7 +32,7 @@ class ICWP_WPSF_Processor_License extends ICWP_WPSF_Processor_BaseWpsf {
|
|
32 |
break;
|
33 |
|
34 |
case 'license_check':
|
35 |
-
if ( !wp_next_scheduled( $oFO->prefix( '
|
36 |
wp_schedule_single_event( $oDp->time() + 12, $oFO->prefix( 'adhoc_cron_license_check' ) );
|
37 |
}
|
38 |
break;
|
32 |
break;
|
33 |
|
34 |
case 'license_check':
|
35 |
+
if ( !wp_next_scheduled( $oFO->prefix( 'adhoc_cron_license_check' ) ) ) {
|
36 |
wp_schedule_single_event( $oDp->time() + 12, $oFO->prefix( 'adhoc_cron_license_check' ) );
|
37 |
}
|
38 |
break;
|
src/processors/lockdown.php
CHANGED
@@ -215,7 +215,7 @@ class ICWP_WPSF_Processor_Lockdown extends ICWP_WPSF_Processor_BaseWpsf {
|
|
215 |
$this->loadWp()->wpDie( sprintf(
|
216 |
_wpsf__( 'The "author" query parameter has been blocked by %s to protect against user login name fishing.' )
|
217 |
.sprintf( '<br /><a href="%s" target="_blank">%s</a>',
|
218 |
-
'
|
219 |
_wpsf__( 'Learn More.' )
|
220 |
),
|
221 |
$this->getController()->getHumanName()
|
215 |
$this->loadWp()->wpDie( sprintf(
|
216 |
_wpsf__( 'The "author" query parameter has been blocked by %s to protect against user login name fishing.' )
|
217 |
.sprintf( '<br /><a href="%s" target="_blank">%s</a>',
|
218 |
+
'https://icwp.io/7l',
|
219 |
_wpsf__( 'Learn More.' )
|
220 |
),
|
221 |
$this->getController()->getHumanName()
|
src/processors/login_protect.php
CHANGED
@@ -29,11 +29,11 @@ class ICWP_WPSF_Processor_LoginProtect extends ICWP_WPSF_Processor_BaseWpsf {
|
|
29 |
$this->getProcessorGasp()->run();
|
30 |
}
|
31 |
|
32 |
-
if ( $
|
33 |
$this->getProcessorCooldown()->run();
|
34 |
}
|
35 |
|
36 |
-
if ( $oFO->
|
37 |
$this->getProcessorGoogleRecaptcha()->run();
|
38 |
}
|
39 |
|
29 |
$this->getProcessorGasp()->run();
|
30 |
}
|
31 |
|
32 |
+
if ( $oFO->isCooldownEnabled() && $this->loadDP()->isMethodPost() ) {
|
33 |
$this->getProcessorCooldown()->run();
|
34 |
}
|
35 |
|
36 |
+
if ( $oFO->isGoogleRecaptchaEnabled() ) {
|
37 |
$this->getProcessorGoogleRecaptcha()->run();
|
38 |
}
|
39 |
|
src/processors/loginprotect_base.php
CHANGED
@@ -8,6 +8,275 @@ require_once( dirname( __FILE__ ).'/base_wpsf.php' );
|
|
8 |
|
9 |
abstract class ICWP_WPSF_Processor_LoginProtect_Base extends ICWP_WPSF_Processor_BaseWpsf {
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
protected function setLoginAsFailed( $sStatToIncrement ) {
|
12 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
13 |
$oFO = $this->getFeature();
|
@@ -19,4 +288,44 @@ abstract class ICWP_WPSF_Processor_LoginProtect_Base extends ICWP_WPSF_Processor
|
|
19 |
$this->doStatIncrement( $sStatToIncrement );
|
20 |
$this->setIpTransgressed(); // We now black mark this IP
|
21 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
}
|
8 |
|
9 |
abstract class ICWP_WPSF_Processor_LoginProtect_Base extends ICWP_WPSF_Processor_BaseWpsf {
|
10 |
|
11 |
+
/**
|
12 |
+
* @var string
|
13 |
+
*/
|
14 |
+
private $sActionToAudit;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @var string
|
18 |
+
*/
|
19 |
+
private $sUserToAudit;
|
20 |
+
|
21 |
+
/**
|
22 |
+
*/
|
23 |
+
public function run() {
|
24 |
+
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
25 |
+
$oFO = $this->getFeature();
|
26 |
+
$b3rdParty = $oFO->getIfSupport3rdParty();
|
27 |
+
|
28 |
+
if ( $oFO->isProtectLogin() ) {
|
29 |
+
// We give it a priority of 10 so that we can jump in before WordPress does its own validation.
|
30 |
+
add_filter( 'authenticate', array( $this, 'checkReqLogin_Wp' ), 10, 3 );
|
31 |
+
|
32 |
+
add_action( 'login_form', array( $this, 'printLoginFormItems' ), 100 );
|
33 |
+
add_filter( 'login_form_middle', array( $this, 'provideLoginFormItems' ), 100 );
|
34 |
+
|
35 |
+
if ( $b3rdParty ) {
|
36 |
+
add_action( 'edd_login_fields_after', array( $this, 'printLoginFormItems' ), 10 );
|
37 |
+
|
38 |
+
add_action( 'woocommerce_login_form', array( $this, 'printLoginFormItems_Woo' ), 100 );
|
39 |
+
add_filter( 'woocommerce_process_login_errors', array( $this, 'checkReqLogin_Woo' ), 10, 2 );
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
if ( $oFO->isProtectLostPassword() ) {
|
44 |
+
add_action( 'lostpassword_form', array( $this, 'printLoginFormItems' ) );
|
45 |
+
add_action( 'lostpassword_post', array( $this, 'checkReqLostPassword_Wp' ), 10, 1 );
|
46 |
+
|
47 |
+
if ( $b3rdParty ) {
|
48 |
+
add_action( 'woocommerce_lostpassword_form', array( $this, 'printLoginFormItems' ), 10 );
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
if ( $oFO->isProtectRegister() ) {
|
53 |
+
add_action( 'register_form', array( $this, 'printLoginFormItems' ) );
|
54 |
+
// add_action( 'register_post', array( $this, 'checkReqRegistration_Wp' ), 10, 1 );
|
55 |
+
add_filter( 'registration_errors', array( $this, 'checkReqRegistrationErrors_Wp' ), 10, 2 );
|
56 |
+
|
57 |
+
if ( $b3rdParty ) {
|
58 |
+
add_action( 'bp_before_registration_submit_buttons', array( $this, 'printLoginFormItems_Bp' ), 10 );
|
59 |
+
add_action( 'bp_signup_validate', array( $this, 'checkReqRegistration_Bp' ), 10 );
|
60 |
+
|
61 |
+
add_action( 'edd_register_form_fields_before_submit', array( $this, 'printLoginFormItems' ), 10 );
|
62 |
+
add_action( 'edd_process_register_form', array( $this, 'checkReqRegistration_Edd' ), 10 );
|
63 |
+
|
64 |
+
add_action( 'woocommerce_register_form', array( $this, 'printLoginFormItems' ), 10 );
|
65 |
+
add_filter( 'woocommerce_process_registration_errors', array( $this, 'checkReqRegistration_Woo' ), 10, 2 );
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
if ( $b3rdParty && $oFO->isProtect( 'checkout_woo' ) ) {
|
70 |
+
add_action( 'woocommerce_after_checkout_registration_form', array( $this, 'printRegistrationFormItems_Woo' ), 10 );
|
71 |
+
add_action( 'woocommerce_after_checkout_validation', array( $this, 'checkReqCheckout_Woo' ), 10, 2 );
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @throws Exception
|
77 |
+
*/
|
78 |
+
protected function performCheckWithException() {
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
*/
|
83 |
+
protected function performCheckWithDie() {
|
84 |
+
try {
|
85 |
+
$this->performCheckWithException();
|
86 |
+
}
|
87 |
+
catch ( Exception $oE ) {
|
88 |
+
$this->loadWp()->wpDie( $oE->getMessage() );
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* @param WP_Error $oWpError
|
94 |
+
* @param string $sUsername
|
95 |
+
* @return WP_Error
|
96 |
+
*/
|
97 |
+
public function checkReqLogin_Woo( $oWpError, $sUsername ) {
|
98 |
+
try {
|
99 |
+
$this->setUserToAudit( $sUsername )
|
100 |
+
->setActionToAudit( 'woo-login' )
|
101 |
+
->performCheckWithException();
|
102 |
+
}
|
103 |
+
catch ( Exception $oE ) {
|
104 |
+
$oWpError = $this->giveMeWpError( $oWpError );
|
105 |
+
$oWpError->add( $this->prefix( rand() ), $oE->getMessage() );
|
106 |
+
}
|
107 |
+
return $oWpError;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Should be a filter added to WordPress's "authenticate" filter, but before WordPress performs
|
112 |
+
* it's own authentication (theirs is priority 30, so we could go in at around 20).
|
113 |
+
* @param null|WP_User|WP_Error $oUserOrError
|
114 |
+
* @param string $sUsername
|
115 |
+
* @param string $sPassword
|
116 |
+
* @return WP_User|WP_Error
|
117 |
+
*/
|
118 |
+
public function checkReqLogin_Wp( $oUserOrError, $sUsername, $sPassword ) {
|
119 |
+
try {
|
120 |
+
if ( !is_wp_error( $oUserOrError ) && !empty( $sUsername ) && !empty( $sPassword ) ) {
|
121 |
+
$this->setUserToAudit( $sUsername )
|
122 |
+
->setActionToAudit( 'login' )
|
123 |
+
->performCheckWithException();
|
124 |
+
}
|
125 |
+
}
|
126 |
+
catch ( Exception $oE ) {
|
127 |
+
$oUserOrError = $this->giveMeWpError( $oUserOrError );
|
128 |
+
$oUserOrError->add( $this->prefix( rand() ), $oE->getMessage() );
|
129 |
+
}
|
130 |
+
return $oUserOrError;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* @param WP_Error $oWpError
|
135 |
+
* @return WP_Error
|
136 |
+
*/
|
137 |
+
public function checkReqLostPassword_Wp( $oWpError ) {
|
138 |
+
try {
|
139 |
+
$this->setUserToAudit( $this->loadDP()->post( 'user_login', '' ) )
|
140 |
+
->setActionToAudit( 'reset-password' )
|
141 |
+
->performCheckWithException();
|
142 |
+
}
|
143 |
+
catch ( Exception $oE ) {
|
144 |
+
$oWpError = $this->giveMeWpError( $oWpError );
|
145 |
+
$oWpError->add( $this->prefix( rand() ), $oE->getMessage() );
|
146 |
+
}
|
147 |
+
return $oWpError;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* @param string $sUsername
|
152 |
+
*/
|
153 |
+
public function checkReqRegistration_Wp( $sUsername ) {
|
154 |
+
return $this->setUserToAudit( $sUsername )
|
155 |
+
->setActionToAudit( 'register' )
|
156 |
+
->performCheckWithDie();
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* see class-wc-checkout.php
|
161 |
+
* @param WP_Error $oWpError
|
162 |
+
* @param array $aPostedData
|
163 |
+
* @return WP_Error
|
164 |
+
*/
|
165 |
+
public function checkReqCheckout_Woo( $aPostedData, $oWpError ) {
|
166 |
+
try {
|
167 |
+
$this->setActionToAudit( 'woo-checkout' )
|
168 |
+
->performCheckWithException();
|
169 |
+
}
|
170 |
+
catch ( Exception $oE ) {
|
171 |
+
$oWpError = $this->giveMeWpError( $oWpError );
|
172 |
+
$oWpError->add( $this->prefix( rand() ), $oE->getMessage() );
|
173 |
+
}
|
174 |
+
return $oWpError;
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
*/
|
179 |
+
public function checkReqRegistration_Edd() {
|
180 |
+
try {
|
181 |
+
$this->setActionToAudit( 'edd-register' )
|
182 |
+
->performCheckWithException();
|
183 |
+
}
|
184 |
+
catch ( Exception $oE ) {
|
185 |
+
if ( function_exists( 'edd_set_error' ) ) {
|
186 |
+
edd_set_error( $this->prefix( rand() ), $oE->getMessage() );
|
187 |
+
}
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* @param WP_Error $oWpError
|
193 |
+
* @param string $sUsername
|
194 |
+
* @return WP_Error
|
195 |
+
*/
|
196 |
+
public function checkReqRegistration_Woo( $oWpError, $sUsername ) {
|
197 |
+
try {
|
198 |
+
$this->setUserToAudit( $sUsername )
|
199 |
+
->setActionToAudit( 'woo-register' )
|
200 |
+
->performCheckWithException();
|
201 |
+
}
|
202 |
+
catch ( Exception $oE ) {
|
203 |
+
$oWpError = $this->giveMeWpError( $oWpError );
|
204 |
+
$oWpError->add( $this->prefix( rand() ), $oE->getMessage() );
|
205 |
+
}
|
206 |
+
return $oWpError;
|
207 |
+
}
|
208 |
+
|
209 |
+
/**
|
210 |
+
* @param WP_Error $oWpError
|
211 |
+
* @param string $sUsername
|
212 |
+
* @return WP_Error
|
213 |
+
*/
|
214 |
+
public function checkReqRegistrationErrors_Wp( $oWpError, $sUsername ) {
|
215 |
+
try {
|
216 |
+
$this->setUserToAudit( $sUsername )
|
217 |
+
->setActionToAudit( 'register' )
|
218 |
+
->performCheckWithException();
|
219 |
+
}
|
220 |
+
catch ( Exception $oE ) {
|
221 |
+
$oWpError = $this->giveMeWpError( $oWpError );
|
222 |
+
$oWpError->add( $this->prefix( rand() ), $oE->getMessage() );
|
223 |
+
}
|
224 |
+
return $oWpError;
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* @return bool
|
229 |
+
*/
|
230 |
+
public function checkReqRegistration_Bp() {
|
231 |
+
return $this->performCheckWithDie();
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* @return string
|
236 |
+
*/
|
237 |
+
protected function buildLoginFormItems() {
|
238 |
+
return '';
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* @return void
|
243 |
+
*/
|
244 |
+
public function printLoginFormItems() {
|
245 |
+
echo $this->buildLoginFormItems();
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* @return void
|
250 |
+
*/
|
251 |
+
public function printLoginFormItems_Woo() {
|
252 |
+
$this->printLoginFormItems();
|
253 |
+
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* see form-billing.php
|
257 |
+
* @param WP_Checkout $oCheckout
|
258 |
+
* @return void
|
259 |
+
*/
|
260 |
+
public function printRegistrationFormItems_Woo( $oCheckout ) {
|
261 |
+
if ( $oCheckout instanceof WC_Checkout && $oCheckout->get_checkout_fields( 'account' ) ) {
|
262 |
+
$this->printLoginFormItems();
|
263 |
+
}
|
264 |
+
}
|
265 |
+
|
266 |
+
/**
|
267 |
+
* @return void
|
268 |
+
*/
|
269 |
+
public function printLoginFormItems_Bp() {
|
270 |
+
$this->printLoginFormItems();
|
271 |
+
}
|
272 |
+
|
273 |
+
/**
|
274 |
+
* @return string
|
275 |
+
*/
|
276 |
+
public function provideLoginFormItems() {
|
277 |
+
return $this->buildLoginFormItems();
|
278 |
+
}
|
279 |
+
|
280 |
protected function setLoginAsFailed( $sStatToIncrement ) {
|
281 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
282 |
$oFO = $this->getFeature();
|
288 |
$this->doStatIncrement( $sStatToIncrement );
|
289 |
$this->setIpTransgressed(); // We now black mark this IP
|
290 |
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* @param WP_Error $oMaybeWpError
|
294 |
+
* @return WP_Error
|
295 |
+
*/
|
296 |
+
protected function giveMeWpError( $oMaybeWpError ) {
|
297 |
+
return is_wp_error( $oMaybeWpError ) ? $oMaybeWpError : new WP_Error();
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* @return string
|
302 |
+
*/
|
303 |
+
protected function getActionToAudit() {
|
304 |
+
return empty( $this->sActionToAudit ) ? 'unknown-action' : $this->sActionToAudit;
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* @return string
|
309 |
+
*/
|
310 |
+
protected function getUserToAudit() {
|
311 |
+
return empty( $this->sUserToAudit ) ? 'unknown' : $this->sUserToAudit;
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* @param string $sActionToAudit
|
316 |
+
* @return $this
|
317 |
+
*/
|
318 |
+
protected function setActionToAudit( $sActionToAudit ) {
|
319 |
+
$this->sActionToAudit = $sActionToAudit;
|
320 |
+
return $this;
|
321 |
+
}
|
322 |
+
|
323 |
+
/**
|
324 |
+
* @param string $sUserToAudit
|
325 |
+
* @return $this
|
326 |
+
*/
|
327 |
+
protected function setUserToAudit( $sUserToAudit ) {
|
328 |
+
$this->sUserToAudit = sanitize_user( $sUserToAudit );
|
329 |
+
return $this;
|
330 |
+
}
|
331 |
}
|
src/processors/loginprotect_cooldown.php
CHANGED
@@ -4,7 +4,7 @@ if ( class_exists( 'ICWP_WPSF_Processor_LoginProtect_Cooldown', false ) ) {
|
|
4 |
return;
|
5 |
}
|
6 |
|
7 |
-
require_once( dirname(__FILE__ ).'/loginprotect_base.php' );
|
8 |
|
9 |
class ICWP_WPSF_Processor_LoginProtect_Cooldown extends ICWP_WPSF_Processor_LoginProtect_Base {
|
10 |
|
@@ -14,60 +14,35 @@ class ICWP_WPSF_Processor_LoginProtect_Cooldown extends ICWP_WPSF_Processor_Logi
|
|
14 |
private $bCooldownUpdated = false;
|
15 |
|
16 |
/**
|
|
|
17 |
*/
|
18 |
-
|
19 |
-
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
20 |
-
$oFO = $this->getFeature();
|
21 |
|
22 |
-
|
23 |
-
add_filter( 'authenticate', array( $this, 'checkLoginInterval' ), 10, 1 );
|
24 |
|
25 |
-
|
26 |
-
|
27 |
-
add_filter( 'registration_errors', array( $this, 'checkLoginInterval' ), 10, 2 );
|
28 |
-
}
|
29 |
-
}
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Should be a filter added to WordPress's "authenticate" filter, but before WordPress performs
|
33 |
-
* it's own authentication (theirs is priority 30, so we could go in at around 20).
|
34 |
-
*
|
35 |
-
* @param null|WP_User|WP_Error $oUserOrError
|
36 |
-
* @return WP_User|WP_Error
|
37 |
-
*/
|
38 |
-
public function checkLoginInterval( $oUserOrError ) {
|
39 |
-
if ( !$this->loadWp()->isRequestUserLogin() || $this->bCooldownUpdated ) {
|
40 |
-
return $oUserOrError;
|
41 |
-
}
|
42 |
-
|
43 |
-
// If we're outside the interval, let the login process proceed as per normal and
|
44 |
-
// update our last login time.
|
45 |
-
$bWithinCooldownPeriod = $this->getIsWithinCooldownPeriod();
|
46 |
-
if ( !$bWithinCooldownPeriod ) {
|
47 |
$this->updateLastLoginTime();
|
48 |
-
$this->doStatIncrement( 'login.cooldown.success' );
|
49 |
-
return $oUserOrError;
|
50 |
-
}
|
51 |
-
|
52 |
-
// At this point someone has attempted to login within the previous login wait interval
|
53 |
-
// So we remove WordPress's authentication filter and our own user check authentication
|
54 |
-
// And finally return a WP_Error which will be reflected back to the user.
|
55 |
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
}
|
66 |
-
$oUserOrError->add( 'wpsf_logininterval', $sErrorString );
|
67 |
-
|
68 |
-
$this->setLoginAsFailed( 'login.cooldown.fail' );
|
69 |
-
|
70 |
-
return $oUserOrError;
|
71 |
}
|
72 |
|
73 |
/**
|
@@ -96,19 +71,19 @@ class ICWP_WPSF_Processor_LoginProtect_Cooldown extends ICWP_WPSF_Processor_Logi
|
|
96 |
*/
|
97 |
protected function updateLastLoginTime() {
|
98 |
$this->bCooldownUpdated = true;
|
|
|
99 |
$this->loadFS()->touch( $this->getLastLoginTimeFilePath(), $this->time() );
|
100 |
}
|
101 |
|
102 |
/**
|
103 |
* @return bool
|
104 |
*/
|
105 |
-
|
106 |
// Is there an interval set?
|
107 |
$nCooldown = $this->getLoginCooldownInterval();
|
108 |
if ( empty( $nCooldown ) || $nCooldown <= 0 ) {
|
109 |
return false;
|
110 |
}
|
111 |
-
|
112 |
return ( $this->getSecondsSinceLastLogin() < $nCooldown );
|
113 |
}
|
114 |
|
@@ -118,4 +93,11 @@ class ICWP_WPSF_Processor_LoginProtect_Cooldown extends ICWP_WPSF_Processor_Logi
|
|
118 |
protected function getSecondsSinceLastLogin() {
|
119 |
return ( $this->time() - $this->getLastLoginTime() );
|
120 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
}
|
4 |
return;
|
5 |
}
|
6 |
|
7 |
+
require_once( dirname( __FILE__ ).'/loginprotect_base.php' );
|
8 |
|
9 |
class ICWP_WPSF_Processor_LoginProtect_Cooldown extends ICWP_WPSF_Processor_LoginProtect_Base {
|
10 |
|
14 |
private $bCooldownUpdated = false;
|
15 |
|
16 |
/**
|
17 |
+
* @throws Exception
|
18 |
*/
|
19 |
+
protected function performCheckWithException() {
|
|
|
|
|
20 |
|
21 |
+
if ( !$this->isCooldownAlreadyUpdated() ) {
|
|
|
22 |
|
23 |
+
$bWithinCooldownPeriod = $this->isWithinCooldownPeriod();
|
24 |
+
$nRemaining = $this->getLoginCooldownInterval() - $this->getSecondsSinceLastLogin();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
$this->updateLastLoginTime();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
|
27 |
+
// At this point someone has attempted to login within the previous login wait interval
|
28 |
+
// So we remove WordPress's authentication filter and our own user check authentication
|
29 |
+
// And finally return a WP_Error which will be reflected back to the user.
|
30 |
+
if ( $bWithinCooldownPeriod ) {
|
31 |
+
|
32 |
+
$sErrorString = _wpsf__( "Login Cooldown in effect." ).' '
|
33 |
+
.sprintf(
|
34 |
+
_wpsf__( "You must wait %s seconds before attempting this action again." ),
|
35 |
+
$nRemaining
|
36 |
+
);
|
37 |
+
|
38 |
+
$this->setLoginAsFailed( 'login.cooldown.fail' );
|
39 |
+
$this->addToAuditEntry( _wpsf__( 'Cooldown triggered and request (login/register/lost-password) was blocked.' ) );
|
40 |
+
throw new Exception( $sErrorString );
|
41 |
+
}
|
42 |
+
else {
|
43 |
+
$this->doStatIncrement( 'login.cooldown.success' );
|
44 |
+
}
|
45 |
}
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
|
48 |
/**
|
71 |
*/
|
72 |
protected function updateLastLoginTime() {
|
73 |
$this->bCooldownUpdated = true;
|
74 |
+
$this->loadFS()->deleteFile( $this->getLastLoginTimeFilePath() );
|
75 |
$this->loadFS()->touch( $this->getLastLoginTimeFilePath(), $this->time() );
|
76 |
}
|
77 |
|
78 |
/**
|
79 |
* @return bool
|
80 |
*/
|
81 |
+
private function isWithinCooldownPeriod() {
|
82 |
// Is there an interval set?
|
83 |
$nCooldown = $this->getLoginCooldownInterval();
|
84 |
if ( empty( $nCooldown ) || $nCooldown <= 0 ) {
|
85 |
return false;
|
86 |
}
|
|
|
87 |
return ( $this->getSecondsSinceLastLogin() < $nCooldown );
|
88 |
}
|
89 |
|
93 |
protected function getSecondsSinceLastLogin() {
|
94 |
return ( $this->time() - $this->getLastLoginTime() );
|
95 |
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* @return bool
|
99 |
+
*/
|
100 |
+
protected function isCooldownAlreadyUpdated() {
|
101 |
+
return (bool)$this->bCooldownUpdated;
|
102 |
+
}
|
103 |
}
|
src/processors/loginprotect_gasp.php
CHANGED
@@ -4,106 +4,21 @@ if ( class_exists( 'ICWP_WPSF_Processor_LoginProtect_Gasp', false ) ) {
|
|
4 |
return;
|
5 |
}
|
6 |
|
7 |
-
require_once( dirname( __FILE__ ).'/
|
8 |
|
9 |
-
class ICWP_WPSF_Processor_LoginProtect_Gasp extends
|
10 |
-
|
11 |
-
/**
|
12 |
-
*/
|
13 |
-
public function run() {
|
14 |
-
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
15 |
-
$oFO = $this->getFeature();
|
16 |
-
|
17 |
-
// Add GASP checking to the login form.
|
18 |
-
add_action( 'login_form', array( $this, 'printGaspLoginCheck_Action' ), 100 );
|
19 |
-
add_filter( 'login_form_middle', array( $this, 'printGaspLoginCheck_Filter' ) );
|
20 |
-
|
21 |
-
// before username/password check (20)
|
22 |
-
add_filter( 'authenticate', array( $this, 'checkLoginForGasp_Filter' ), 12, 2 );
|
23 |
-
|
24 |
-
$b3rdParty = $oFO->getIfSupport3rdParty();
|
25 |
-
if ( $b3rdParty ) {
|
26 |
-
add_action( 'woocommerce_login_form', array( $this, 'printGaspLoginCheck_Action' ), 10 );
|
27 |
-
add_action( 'edd_login_fields_after', array( $this, 'printGaspLoginCheck_Action' ), 10 );
|
28 |
-
}
|
29 |
-
|
30 |
-
// apply to user registrations if set to do so.
|
31 |
-
if ( $oFO->getIsCheckingUserRegistrations() ) {
|
32 |
-
//print the checkbox code:
|
33 |
-
add_action( 'register_form', array( $this, 'printGaspLoginCheck_Action' ) );
|
34 |
-
add_action( 'lostpassword_form', array( $this, 'printGaspLoginCheck_Action' ) );
|
35 |
-
|
36 |
-
//verify the checkbox is present:
|
37 |
-
add_action( 'register_post', array( $this, 'checkRegisterForGasp_Action' ), 10, 1 );
|
38 |
-
add_action( 'lostpassword_post', array( $this, 'checkResetPasswordForGasp_Action' ), 10 );
|
39 |
-
|
40 |
-
if ( $b3rdParty ) {
|
41 |
-
add_action( 'woocommerce_lostpassword_form', array( $this, 'printGaspLoginCheck_Action' ), 10 );
|
42 |
-
add_action( 'edd_register_form_fields_before_submit', array(
|
43 |
-
$this,
|
44 |
-
'printGaspLoginCheck_Action'
|
45 |
-
), 10 );
|
46 |
-
|
47 |
-
// Buddypress custom registration page.
|
48 |
-
add_action( 'bp_before_registration_submit_buttons', array( $this, 'printGaspLoginCheck_Action' ), 10 );
|
49 |
-
add_action( 'bp_signup_validate', array( $this, 'checkRegisterForGasp_Action' ), 10 );
|
50 |
-
}
|
51 |
-
}
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
*/
|
56 |
-
public function printGaspLoginCheck_Action() {
|
57 |
-
echo $this->getGaspLoginHtml();
|
58 |
-
}
|
59 |
|
60 |
/**
|
61 |
* @return string
|
62 |
*/
|
63 |
-
|
64 |
return $this->getGaspLoginHtml();
|
65 |
}
|
66 |
|
67 |
-
/**
|
68 |
-
* @param $oUser
|
69 |
-
* @param $sUsername
|
70 |
-
* @return WP_Error
|
71 |
-
*/
|
72 |
-
public function checkLoginForGasp_Filter( $oUser, $sUsername ) {
|
73 |
-
if ( !$this->loadWp()->isRequestUserLogin() ) {
|
74 |
-
return $oUser;
|
75 |
-
}
|
76 |
-
|
77 |
-
if ( empty( $sUsername ) || is_wp_error( $oUser ) ) {
|
78 |
-
return $oUser;
|
79 |
-
}
|
80 |
-
if ( $this->doGaspChecks( $sUsername, _wpsf__( 'login' ) ) ) {
|
81 |
-
return $oUser;
|
82 |
-
}
|
83 |
-
//This doesn't actually ever get returned because we die() within doGaspChecks()
|
84 |
-
return new WP_Error( 'wpsf_gaspfail', _wpsf__( 'Bot Checking Failed.' ) );
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* @param string $sSanitizedUsername
|
89 |
-
* @return void
|
90 |
-
*/
|
91 |
-
public function checkRegisterForGasp_Action( $sSanitizedUsername ) {
|
92 |
-
$this->doGaspChecks( $sSanitizedUsername, 'register' );
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* @return void
|
97 |
-
*/
|
98 |
-
public function checkResetPasswordForGasp_Action() {
|
99 |
-
$sSanitizedUsername = sanitize_user( $this->loadDataProcessor()->FetchPost( 'user_login', '' ) );
|
100 |
-
$this->doGaspChecks( $sSanitizedUsername, 'reset-password' );
|
101 |
-
}
|
102 |
-
|
103 |
/**
|
104 |
* @return string
|
105 |
*/
|
106 |
-
|
107 |
|
108 |
$sLabel = $this->getTextImAHuman();
|
109 |
$sAlert = $this->getTextPleaseCheckBox();
|
@@ -171,47 +86,93 @@ class ICWP_WPSF_Processor_LoginProtect_Gasp extends ICWP_WPSF_Processor_BaseWpsf
|
|
171 |
}
|
172 |
|
173 |
/**
|
174 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
* @param string $sUsername
|
176 |
* @param string $sActionAttempted - one of 'login', 'register', 'reset-password'
|
177 |
-
* @return bool
|
|
|
178 |
*/
|
179 |
protected function doGaspChecks( $sUsername, $sActionAttempted = 'login' ) {
|
180 |
-
$oDp = $this->
|
181 |
-
$sGaspCheckBox = $oDp->
|
182 |
-
$sHoney = $oDp->
|
183 |
|
184 |
-
$
|
185 |
$sDieMessage = '';
|
186 |
if ( empty( $sGaspCheckBox ) ) {
|
187 |
-
$sAuditMessage = sprintf(
|
|
|
|
|
|
|
188 |
$this->addToAuditEntry( $sAuditMessage, 3, $sActionAttempted.'_protect_block_gasp_checkbox' );
|
189 |
$this->doStatIncrement( $sActionAttempted.'.gasp.checkbox.fail' );
|
190 |
-
|
191 |
$sDieMessage = _wpsf__( "You must check that box to say you're not a bot." );
|
192 |
-
$bDie = true;
|
193 |
}
|
194 |
else if ( !empty( $sHoney ) ) {
|
195 |
-
$sAuditMessage = sprintf(
|
|
|
|
|
|
|
196 |
$this->addToAuditEntry( $sAuditMessage, 3, $sActionAttempted.'_protect_block_gasp_honeypot' );
|
197 |
$this->doStatIncrement( $sActionAttempted.'.gasp.honeypot.fail' );
|
198 |
-
|
199 |
$sDieMessage = sprintf( _wpsf__( 'You appear to be a bot - terminating %s attempt.' ), $sActionAttempted );
|
200 |
-
|
|
|
|
|
201 |
}
|
202 |
|
203 |
-
if (
|
204 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
205 |
$oFO = $this->getFeature();
|
206 |
$oFO->setOptInsightsAt( sprintf( 'last_%s_block_at', $sActionAttempted ) );
|
207 |
$this->setIpTransgressed(); // We now black mark this IP
|
208 |
-
|
209 |
-
$this->loadWp()
|
210 |
-
->wpDie( $sDieMessage );
|
211 |
-
return false;
|
212 |
}
|
213 |
|
214 |
-
return
|
215 |
}
|
216 |
|
217 |
/**
|
4 |
return;
|
5 |
}
|
6 |
|
7 |
+
require_once( dirname( __FILE__ ).'/loginprotect_base.php' );
|
8 |
|
9 |
+
class ICWP_WPSF_Processor_LoginProtect_Gasp extends ICWP_WPSF_Processor_LoginProtect_Base {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
/**
|
12 |
* @return string
|
13 |
*/
|
14 |
+
protected function buildLoginFormItems() {
|
15 |
return $this->getGaspLoginHtml();
|
16 |
}
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
/**
|
19 |
* @return string
|
20 |
*/
|
21 |
+
private function getGaspLoginHtml() {
|
22 |
|
23 |
$sLabel = $this->getTextImAHuman();
|
24 |
$sAlert = $this->getTextPleaseCheckBox();
|
86 |
}
|
87 |
|
88 |
/**
|
89 |
+
* @throws Exception
|
90 |
+
*/
|
91 |
+
protected function performCheckWithException() {
|
92 |
+
$oDp = $this->loadDP();
|
93 |
+
$sGaspCheckBox = $oDp->post( $this->getGaspCheckboxName() );
|
94 |
+
$sHoney = $oDp->post( 'icwp_wpsf_login_email' );
|
95 |
+
|
96 |
+
$sUsername = $this->getUserToAudit();
|
97 |
+
$sActionAttempted = $this->getActionToAudit();
|
98 |
+
|
99 |
+
$bValid = false;
|
100 |
+
$sError = '';
|
101 |
+
if ( empty( $sGaspCheckBox ) ) {
|
102 |
+
$sAuditMessage = sprintf(
|
103 |
+
_wpsf__( 'User "%s" attempted to %s but GASP checkbox was not present.' ),
|
104 |
+
$sUsername, $sActionAttempted
|
105 |
+
).' '._wpsf__( 'Probably a BOT.' );
|
106 |
+
$this->addToAuditEntry( $sAuditMessage, 3, $sActionAttempted.'_protect_block_gasp_checkbox' );
|
107 |
+
$this->setLoginAsFailed( $sActionAttempted.'.gasp.checkbox.fail' );
|
108 |
+
$sError = _wpsf__( "You must check that box to say you're not a bot." );
|
109 |
+
}
|
110 |
+
else if ( !empty( $sHoney ) ) {
|
111 |
+
$sAuditMessage = sprintf(
|
112 |
+
_wpsf__( 'User "%s" attempted to %s but they were caught by the GASP honeypot.' ),
|
113 |
+
$sUsername, $sActionAttempted
|
114 |
+
).' '._wpsf__( 'Probably a BOT.' );
|
115 |
+
$this->addToAuditEntry( $sAuditMessage, 3, $sActionAttempted.'_protect_block_gasp_honeypot' );
|
116 |
+
$this->setLoginAsFailed( $sActionAttempted.'.gasp.honeypot.fail' );
|
117 |
+
$sError = sprintf( _wpsf__( 'You appear to be a bot - terminating %s attempt.' ), $sActionAttempted );
|
118 |
+
}
|
119 |
+
else {
|
120 |
+
$bValid = true;
|
121 |
+
}
|
122 |
+
|
123 |
+
if ( !$bValid ) {
|
124 |
+
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
125 |
+
$oFO = $this->getFeature();
|
126 |
+
$oFO->setOptInsightsAt( sprintf( 'last_%s_block_at', $sActionAttempted ) );
|
127 |
+
$this->setIpTransgressed(); // We now black mark this IP
|
128 |
+
throw new Exception( $sError );
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
* @param string $sUsername
|
134 |
* @param string $sActionAttempted - one of 'login', 'register', 'reset-password'
|
135 |
+
* @return bool - true if validation successful
|
136 |
+
* @throws Exception
|
137 |
*/
|
138 |
protected function doGaspChecks( $sUsername, $sActionAttempted = 'login' ) {
|
139 |
+
$oDp = $this->loadDP();
|
140 |
+
$sGaspCheckBox = $oDp->post( $this->getGaspCheckboxName() );
|
141 |
+
$sHoney = $oDp->post( 'icwp_wpsf_login_email' );
|
142 |
|
143 |
+
$bValid = false;
|
144 |
$sDieMessage = '';
|
145 |
if ( empty( $sGaspCheckBox ) ) {
|
146 |
+
$sAuditMessage = sprintf(
|
147 |
+
_wpsf__( 'User "%s" attempted to %s but GASP checkbox was not present.' ),
|
148 |
+
empty( $sUsername ) ? 'unknown' : $sUsername, $sActionAttempted
|
149 |
+
).' '._wpsf__( 'Probably a BOT.' );
|
150 |
$this->addToAuditEntry( $sAuditMessage, 3, $sActionAttempted.'_protect_block_gasp_checkbox' );
|
151 |
$this->doStatIncrement( $sActionAttempted.'.gasp.checkbox.fail' );
|
|
|
152 |
$sDieMessage = _wpsf__( "You must check that box to say you're not a bot." );
|
|
|
153 |
}
|
154 |
else if ( !empty( $sHoney ) ) {
|
155 |
+
$sAuditMessage = sprintf(
|
156 |
+
_wpsf__( 'User "%s" attempted to %s but they were caught by the GASP honeypot.' ),
|
157 |
+
empty( $sUsername ) ? 'unknown' : $sUsername, $sActionAttempted
|
158 |
+
).' '._wpsf__( 'Probably a BOT.' );
|
159 |
$this->addToAuditEntry( $sAuditMessage, 3, $sActionAttempted.'_protect_block_gasp_honeypot' );
|
160 |
$this->doStatIncrement( $sActionAttempted.'.gasp.honeypot.fail' );
|
|
|
161 |
$sDieMessage = sprintf( _wpsf__( 'You appear to be a bot - terminating %s attempt.' ), $sActionAttempted );
|
162 |
+
}
|
163 |
+
else {
|
164 |
+
$bValid = true;
|
165 |
}
|
166 |
|
167 |
+
if ( !$bValid ) {
|
168 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
169 |
$oFO = $this->getFeature();
|
170 |
$oFO->setOptInsightsAt( sprintf( 'last_%s_block_at', $sActionAttempted ) );
|
171 |
$this->setIpTransgressed(); // We now black mark this IP
|
172 |
+
throw new Exception( $sDieMessage );
|
|
|
|
|
|
|
173 |
}
|
174 |
|
175 |
+
return $bValid;
|
176 |
}
|
177 |
|
178 |
/**
|
src/processors/loginprotect_googleauthenticator.php
CHANGED
@@ -85,7 +85,7 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
|
|
85 |
* @param int $nSavingUserId
|
86 |
*/
|
87 |
public function handleEditOtherUserProfileSubmit( $nSavingUserId ) {
|
88 |
-
$oDp = $this->
|
89 |
|
90 |
// Can only edit other users if you're admin/security-admin
|
91 |
if ( $this->getController()->getHasPermissionToManage() ) {
|
@@ -212,16 +212,15 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
|
|
212 |
$oLoginTrack = $this->getLoginTrack();
|
213 |
|
214 |
// Mulifactor or not
|
215 |
-
$bNeedToCheckThisFactor = $oFO->isChainedAuth() || !$this->getLoginTrack()->
|
216 |
$bErrorOnFailure = $bNeedToCheckThisFactor && $oLoginTrack->isFinalFactorRemainingToTrack();
|
217 |
$oLoginTrack->addUnSuccessfulFactor( $this->getStub() );
|
218 |
|
219 |
-
if ( !$bNeedToCheckThisFactor ||
|
220 |
return $oUser;
|
221 |
}
|
222 |
|
223 |
-
|
224 |
-
if ( $bIsUser && $this->hasValidatedProfile( $oUser ) ) {
|
225 |
|
226 |
$oError = new WP_Error();
|
227 |
|
@@ -267,7 +266,7 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
|
|
267 |
'value' => '',
|
268 |
'placeholder' => _wpsf__( 'Please use your Google Authenticator App to retrieve your code.' ),
|
269 |
'text' => _wpsf__( 'Google Authenticator Code' ),
|
270 |
-
'help_link' => '
|
271 |
'extras' => array(
|
272 |
'onkeyup' => "this.value=this.value.replace(/[^\d]/g,'')"
|
273 |
)
|
@@ -289,10 +288,10 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
|
|
289 |
$aEmailContent[] = $this->generateGaRemovalConfirmationLink();
|
290 |
|
291 |
$sRecipient = $oUser->get( 'user_email' );
|
292 |
-
if ( $this->
|
293 |
$sEmailSubject = _wpsf__( 'Google Authenticator Removal Confirmation' );
|
294 |
$bSendSuccess = $this->getEmailProcessor()
|
295 |
-
->
|
296 |
}
|
297 |
return $bSendSuccess;
|
298 |
}
|
@@ -342,16 +341,15 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
|
|
342 |
}
|
343 |
|
344 |
/**
|
345 |
-
* @param
|
|
|
346 |
*/
|
347 |
-
protected function auditLogin( $bIsSuccess ) {
|
348 |
if ( $bIsSuccess ) {
|
349 |
$this->addToAuditEntry(
|
350 |
sprintf(
|
351 |
_wpsf__( 'User "%s" verified their identity using Google Authenticator Two-Factor Authentication.' ),
|
352 |
-
$
|
353 |
-
),
|
354 |
-
2, 'login_protect_ga_verified'
|
355 |
);
|
356 |
$this->doStatIncrement( 'login.googleauthenticator.verified' );
|
357 |
}
|
@@ -359,9 +357,7 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
|
|
359 |
$this->addToAuditEntry(
|
360 |
sprintf(
|
361 |
_wpsf__( 'User "%s" failed to verify their identity using Google Authenticator Two-Factor Authentication.' ),
|
362 |
-
$
|
363 |
-
),
|
364 |
-
2, 'login_protect_ga_failed'
|
365 |
);
|
366 |
$this->doStatIncrement( 'login.googleauthenticator.fail' );
|
367 |
}
|
85 |
* @param int $nSavingUserId
|
86 |
*/
|
87 |
public function handleEditOtherUserProfileSubmit( $nSavingUserId ) {
|
88 |
+
$oDp = $this->loadDP();
|
89 |
|
90 |
// Can only edit other users if you're admin/security-admin
|
91 |
if ( $this->getController()->getHasPermissionToManage() ) {
|
212 |
$oLoginTrack = $this->getLoginTrack();
|
213 |
|
214 |
// Mulifactor or not
|
215 |
+
$bNeedToCheckThisFactor = $oFO->isChainedAuth() || !$this->getLoginTrack()->hasSuccessfulFactor();
|
216 |
$bErrorOnFailure = $bNeedToCheckThisFactor && $oLoginTrack->isFinalFactorRemainingToTrack();
|
217 |
$oLoginTrack->addUnSuccessfulFactor( $this->getStub() );
|
218 |
|
219 |
+
if ( !$bNeedToCheckThisFactor || !( $oUser instanceof WP_User ) || is_wp_error( $oUser ) ) {
|
220 |
return $oUser;
|
221 |
}
|
222 |
|
223 |
+
if ( $this->hasValidatedProfile( $oUser ) ) {
|
|
|
224 |
|
225 |
$oError = new WP_Error();
|
226 |
|
266 |
'value' => '',
|
267 |
'placeholder' => _wpsf__( 'Please use your Google Authenticator App to retrieve your code.' ),
|
268 |
'text' => _wpsf__( 'Google Authenticator Code' ),
|
269 |
+
'help_link' => 'https://icwp.io/wpsf42',
|
270 |
'extras' => array(
|
271 |
'onkeyup' => "this.value=this.value.replace(/[^\d]/g,'')"
|
272 |
)
|
288 |
$aEmailContent[] = $this->generateGaRemovalConfirmationLink();
|
289 |
|
290 |
$sRecipient = $oUser->get( 'user_email' );
|
291 |
+
if ( $this->loadDP()->validEmail( $sRecipient ) ) {
|
292 |
$sEmailSubject = _wpsf__( 'Google Authenticator Removal Confirmation' );
|
293 |
$bSendSuccess = $this->getEmailProcessor()
|
294 |
+
->sendEmailWithWrap( $sRecipient, $sEmailSubject, $aEmailContent );
|
295 |
}
|
296 |
return $bSendSuccess;
|
297 |
}
|
341 |
}
|
342 |
|
343 |
/**
|
344 |
+
* @param WP_User $oUser
|
345 |
+
* @param bool $bIsSuccess
|
346 |
*/
|
347 |
+
protected function auditLogin( $oUser, $bIsSuccess ) {
|
348 |
if ( $bIsSuccess ) {
|
349 |
$this->addToAuditEntry(
|
350 |
sprintf(
|
351 |
_wpsf__( 'User "%s" verified their identity using Google Authenticator Two-Factor Authentication.' ),
|
352 |
+
$oUser->user_login ), 2, 'login_protect_ga_verified'
|
|
|
|
|
353 |
);
|
354 |
$this->doStatIncrement( 'login.googleauthenticator.verified' );
|
355 |
}
|
357 |
$this->addToAuditEntry(
|
358 |
sprintf(
|
359 |
_wpsf__( 'User "%s" failed to verify their identity using Google Authenticator Two-Factor Authentication.' ),
|
360 |
+
$oUser->user_login ), 2, 'login_protect_ga_failed'
|
|
|
|
|
361 |
);
|
362 |
$this->doStatIncrement( 'login.googleauthenticator.fail' );
|
363 |
}
|
src/processors/loginprotect_googlerecaptcha.php
CHANGED
@@ -9,92 +9,56 @@ require_once( dirname( __FILE__ ).'/loginprotect_base.php' );
|
|
9 |
class ICWP_WPSF_Processor_LoginProtect_GoogleRecaptcha extends ICWP_WPSF_Processor_LoginProtect_Base {
|
10 |
|
11 |
/**
|
|
|
12 |
*/
|
13 |
public function run() {
|
14 |
-
|
15 |
-
$oFO = $this->getFeature();
|
16 |
-
if ( !$oFO->getIsGoogleRecaptchaReady() ) {
|
17 |
-
return;
|
18 |
-
}
|
19 |
-
|
20 |
add_action( 'wp_enqueue_scripts', array( $this, 'registerGoogleRecaptchaJs' ), 99 );
|
21 |
add_action( 'login_enqueue_scripts', array( $this, 'registerGoogleRecaptchaJs' ), 99 );
|
|
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
|
|
30 |
}
|
31 |
-
|
32 |
-
// before username/password check (20)
|
33 |
-
add_filter( 'authenticate', array( $this, 'checkLoginForGoogleRecaptcha_Filter' ), 15, 3 );
|
34 |
}
|
35 |
|
36 |
/**
|
37 |
* @return string
|
38 |
*/
|
39 |
-
public function
|
40 |
$this->setRecaptchaToEnqueue();
|
41 |
-
return
|
42 |
}
|
43 |
|
44 |
/**
|
|
|
45 |
*/
|
46 |
-
public function
|
47 |
$this->setRecaptchaToEnqueue();
|
48 |
-
|
49 |
}
|
50 |
|
51 |
/**
|
52 |
* @return string
|
53 |
*/
|
54 |
-
protected function
|
55 |
-
$
|
56 |
-
return sprintf( '%s<div class="icwpg-recaptcha"></div>', $this->isRecaptchaInvisible() ? '' : $sNonInvisStyle );
|
57 |
-
}
|
58 |
-
|
59 |
-
public function checkGoogleRecaptcha_Action() {
|
60 |
-
try {
|
61 |
-
$this->checkRequestRecaptcha();
|
62 |
-
}
|
63 |
-
catch ( Exception $oE ) {
|
64 |
-
$this->loadWp()
|
65 |
-
->wpDie( 'Google reCAPTCHA checking failed.' );
|
66 |
-
}
|
67 |
}
|
68 |
|
69 |
/**
|
70 |
-
*
|
71 |
-
* block testing of username and password
|
72 |
-
* @param WP_User|WP_Error $oUser
|
73 |
-
* @return WP_Error
|
74 |
*/
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
}
|
79 |
-
|
80 |
-
// we haven't already failed before now
|
81 |
-
if ( !is_wp_error( $oUser ) ) {
|
82 |
-
|
83 |
-
try {
|
84 |
-
$this->checkRequestRecaptcha();
|
85 |
-
}
|
86 |
-
catch ( Exception $oE ) {
|
87 |
-
$sCode = ( $oE->getCode() == 1 ) ? 'shield_google_recaptcha_empty' : 'shield_google_recaptcha_failed';
|
88 |
-
$oUser = new WP_Error( $sCode, $oE->getMessage() );
|
89 |
-
}
|
90 |
-
|
91 |
-
if ( is_wp_error( $oUser ) ) {
|
92 |
-
$this->setLoginAsFailed( 'login.recaptcha.fail' );
|
93 |
-
}
|
94 |
-
else {
|
95 |
-
$this->doStatIncrement( 'login.recaptcha.verified' );
|
96 |
-
}
|
97 |
-
}
|
98 |
-
return $oUser;
|
99 |
}
|
100 |
}
|
9 |
class ICWP_WPSF_Processor_LoginProtect_GoogleRecaptcha extends ICWP_WPSF_Processor_LoginProtect_Base {
|
10 |
|
11 |
/**
|
12 |
+
* We no longer check if recaptcha is ready, we just use run(). So check beforehand.
|
13 |
*/
|
14 |
public function run() {
|
15 |
+
parent::run();
|
|
|
|
|
|
|
|
|
|
|
16 |
add_action( 'wp_enqueue_scripts', array( $this, 'registerGoogleRecaptchaJs' ), 99 );
|
17 |
add_action( 'login_enqueue_scripts', array( $this, 'registerGoogleRecaptchaJs' ), 99 );
|
18 |
+
}
|
19 |
|
20 |
+
/**
|
21 |
+
* @throws Exception
|
22 |
+
*/
|
23 |
+
protected function performCheckWithException() {
|
24 |
+
try {
|
25 |
+
$this->checkRequestRecaptcha();
|
26 |
+
$this->doStatIncrement( 'login.recaptcha.verified' );
|
27 |
+
}
|
28 |
+
catch ( Exception $oE ) {
|
29 |
+
$this->setLoginAsFailed( 'login.recaptcha.fail' );
|
30 |
+
throw $oE;
|
31 |
}
|
|
|
|
|
|
|
32 |
}
|
33 |
|
34 |
/**
|
35 |
* @return string
|
36 |
*/
|
37 |
+
public function provideLoginFormItems() {
|
38 |
$this->setRecaptchaToEnqueue();
|
39 |
+
return parent::provideLoginFormItems();
|
40 |
}
|
41 |
|
42 |
/**
|
43 |
+
* @return void
|
44 |
*/
|
45 |
+
public function printLoginFormItems() {
|
46 |
$this->setRecaptchaToEnqueue();
|
47 |
+
parent::printLoginFormItems();
|
48 |
}
|
49 |
|
50 |
/**
|
51 |
* @return string
|
52 |
*/
|
53 |
+
protected function buildLoginFormItems() {
|
54 |
+
return $this->getGoogleRecaptchaHtml();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
}
|
56 |
|
57 |
/**
|
58 |
+
* @return string
|
|
|
|
|
|
|
59 |
*/
|
60 |
+
private function getGoogleRecaptchaHtml() {
|
61 |
+
$sNonInvisStyle = '<style>@media screen {#rc-imageselect, .icwpg-recaptcha iframe {transform:scale(0.90);-webkit-transform:scale(0.90);transform-origin:0 0;-webkit-transform-origin:0 0;}</style>';
|
62 |
+
return sprintf( '%s<div class="icwpg-recaptcha"></div>', $this->isRecaptchaInvisible() ? '' : $sNonInvisStyle );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
}
|
64 |
}
|
src/processors/loginprotect_intent.php
CHANGED
@@ -13,6 +13,11 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
13 |
*/
|
14 |
private $oLoginTrack;
|
15 |
|
|
|
|
|
|
|
|
|
|
|
16 |
/**
|
17 |
*/
|
18 |
public function run() {
|
@@ -21,6 +26,9 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
21 |
add_action( 'init', array( $this, 'onWpInit' ), 0 );
|
22 |
add_action( 'wp_logout', array( $this, 'onWpLogout' ) );
|
23 |
|
|
|
|
|
|
|
24 |
if ( $oFO->getIfSupport3rdParty() ) {
|
25 |
add_action( 'wc_social_login_before_user_login', array( $this, 'onWcSocialLogin' ) );
|
26 |
}
|
@@ -74,8 +82,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
74 |
|
75 |
// process the current login intent
|
76 |
if ( $oWpUsers->isUserLoggedIn() ) {
|
77 |
-
|
78 |
-
if ( $this->isCurrentUserSubjectToLoginIntent() ) {
|
79 |
$this->processLoginIntent();
|
80 |
}
|
81 |
else if ( $this->hasLoginIntent() ) {
|
@@ -90,11 +97,8 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
90 |
/**
|
91 |
* hooked to 'init' and only run if a user is logged in
|
92 |
*/
|
93 |
-
|
94 |
$oWpUsers = $this->loadWpUsers();
|
95 |
-
if ( !$oWpUsers->isUserLoggedIn() ) {
|
96 |
-
return;
|
97 |
-
}
|
98 |
|
99 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
100 |
$oFO = $this->getFeature();
|
@@ -111,16 +115,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
111 |
return;
|
112 |
}
|
113 |
|
114 |
-
|
115 |
-
do_action( $oFO->prefix( 'login-intent-validation' ) );
|
116 |
-
if ( $oFO->isChainedAuth() ) {
|
117 |
-
$bLoginIntentValidated = !$oLoginTracker->hasUnSuccessfulFactorAuth();
|
118 |
-
}
|
119 |
-
else {
|
120 |
-
$bLoginIntentValidated = $oLoginTracker->hasSuccessfulFactorAuth();
|
121 |
-
}
|
122 |
-
|
123 |
-
if ( $bLoginIntentValidated ) {
|
124 |
|
125 |
if ( $oDp->post( 'skip_mfa' ) === 'Y' ) { // store the browser hash
|
126 |
$oFO->addMfaLoginHash( $oWpUsers->getCurrentWpUser() );
|
@@ -130,7 +125,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
130 |
$this->loadAdminNoticesProcessor()->addFlashMessage(
|
131 |
_wpsf__( 'Success' ).'! '._wpsf__( 'Thank you for authenticating your login.' ) );
|
132 |
|
133 |
-
$oFO->setOptInsightsAt( '
|
134 |
}
|
135 |
else {
|
136 |
$this->loadAdminNoticesProcessor()->addFlashMessage(
|
@@ -159,7 +154,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
159 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
160 |
$oFO = $this->getFeature();
|
161 |
|
162 |
-
$this->
|
163 |
|
164 |
// support for WooCommerce Social Login
|
165 |
if ( $oFO->getIfSupport3rdParty() ) {
|
@@ -175,10 +170,9 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
175 |
public function initLoginIntent( $oUser ) {
|
176 |
if ( $oUser instanceof WP_User ) {
|
177 |
|
178 |
-
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $
|
179 |
-
$
|
180 |
-
if ( !$
|
181 |
-
$oF = $this->getFeature();
|
182 |
$nTimeout = (int)apply_filters(
|
183 |
$oF->prefix( 'login_intent_timeout' ),
|
184 |
$oF->getDef( 'login_intent_timeout' )
|
@@ -222,13 +216,15 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
222 |
}
|
223 |
|
224 |
/**
|
|
|
|
|
|
|
225 |
* @return bool
|
226 |
*/
|
227 |
-
|
228 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
229 |
$oFO = $this->getFeature();
|
230 |
-
return !$oFO->canUserMfaSkip( $
|
231 |
-
&& apply_filters( $this->prefix( 'user_subject_to_login_intent' ), false );
|
232 |
}
|
233 |
|
234 |
/**
|
@@ -305,7 +301,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
305 |
'login_intent_flag' => $oFO->getLoginIntentRequestFlag()
|
306 |
),
|
307 |
'hrefs' => array(
|
308 |
-
'form_action' => $this->
|
309 |
'css_bootstrap' => $oCon->getPluginUrl_Css( 'bootstrap4.min.css' ),
|
310 |
'js_bootstrap' => $oCon->getPluginUrl_Js( 'bootstrap4.min.js' ),
|
311 |
'shield_logo' => 'https://ps.w.org/wp-simple-firewall/assets/banner-772x250.png',
|
@@ -314,7 +310,8 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
314 |
'favicon' => $oCon->getPluginUrl_Image( 'pluginlogo_24x24.png' ),
|
315 |
),
|
316 |
'flags' => array(
|
317 |
-
'can_skip_mfa'
|
|
|
318 |
)
|
319 |
);
|
320 |
|
@@ -366,6 +363,37 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
|
|
366 |
return $this->oLoginTrack;
|
367 |
}
|
368 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
369 |
/**
|
370 |
* @param ICWP_WPSF_Processor_LoginProtect_Track $oLoginTrack
|
371 |
* @return $this
|
13 |
*/
|
14 |
private $oLoginTrack;
|
15 |
|
16 |
+
/**
|
17 |
+
* @var bool
|
18 |
+
*/
|
19 |
+
private $bLoginIntentProcessed;
|
20 |
+
|
21 |
/**
|
22 |
*/
|
23 |
public function run() {
|
26 |
add_action( 'init', array( $this, 'onWpInit' ), 0 );
|
27 |
add_action( 'wp_logout', array( $this, 'onWpLogout' ) );
|
28 |
|
29 |
+
// 100 priority is important as this takes priority
|
30 |
+
add_filter( $oFO->prefix( 'user_subject_to_login_intent' ), array( $this, 'applyUserCanMfaSkip' ), 100, 2 );
|
31 |
+
|
32 |
if ( $oFO->getIfSupport3rdParty() ) {
|
33 |
add_action( 'wc_social_login_before_user_login', array( $this, 'onWcSocialLogin' ) );
|
34 |
}
|
82 |
|
83 |
// process the current login intent
|
84 |
if ( $oWpUsers->isUserLoggedIn() ) {
|
85 |
+
if ( $this->isUserSubjectToLoginIntent() ) {
|
|
|
86 |
$this->processLoginIntent();
|
87 |
}
|
88 |
else if ( $this->hasLoginIntent() ) {
|
97 |
/**
|
98 |
* hooked to 'init' and only run if a user is logged in
|
99 |
*/
|
100 |
+
private function processLoginIntent() {
|
101 |
$oWpUsers = $this->loadWpUsers();
|
|
|
|
|
|
|
102 |
|
103 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
104 |
$oFO = $this->getFeature();
|
115 |
return;
|
116 |
}
|
117 |
|
118 |
+
if ( $this->getIsLoginIntentValid() ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
|
120 |
if ( $oDp->post( 'skip_mfa' ) === 'Y' ) { // store the browser hash
|
121 |
$oFO->addMfaLoginHash( $oWpUsers->getCurrentWpUser() );
|
125 |
$this->loadAdminNoticesProcessor()->addFlashMessage(
|
126 |
_wpsf__( 'Success' ).'! '._wpsf__( 'Thank you for authenticating your login.' ) );
|
127 |
|
128 |
+
$oFO->setOptInsightsAt( 'last_2fa_login_at' );
|
129 |
}
|
130 |
else {
|
131 |
$this->loadAdminNoticesProcessor()->addFlashMessage(
|
154 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
155 |
$oFO = $this->getFeature();
|
156 |
|
157 |
+
$this->removeLoginIntent();
|
158 |
|
159 |
// support for WooCommerce Social Login
|
160 |
if ( $oFO->getIfSupport3rdParty() ) {
|
170 |
public function initLoginIntent( $oUser ) {
|
171 |
if ( $oUser instanceof WP_User ) {
|
172 |
|
173 |
+
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oF */
|
174 |
+
$oF = $this->getFeature();
|
175 |
+
if ( !$oF->canUserMfaSkip( $oUser ) ) {
|
|
|
176 |
$nTimeout = (int)apply_filters(
|
177 |
$oF->prefix( 'login_intent_timeout' ),
|
178 |
$oF->getDef( 'login_intent_timeout' )
|
216 |
}
|
217 |
|
218 |
/**
|
219 |
+
* Must be set with a higher priority than other filters as it will override them
|
220 |
+
* @param bool $bIsSubjectTo
|
221 |
+
* @param WP_User $oUser
|
222 |
* @return bool
|
223 |
*/
|
224 |
+
public function applyUserCanMfaSkip( $bIsSubjectTo, $oUser ) {
|
225 |
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
226 |
$oFO = $this->getFeature();
|
227 |
+
return $bIsSubjectTo && !$oFO->canUserMfaSkip( $oUser );
|
|
|
228 |
}
|
229 |
|
230 |
/**
|
301 |
'login_intent_flag' => $oFO->getLoginIntentRequestFlag()
|
302 |
),
|
303 |
'hrefs' => array(
|
304 |
+
'form_action' => $this->loadDP()->getRequestUri(),
|
305 |
'css_bootstrap' => $oCon->getPluginUrl_Css( 'bootstrap4.min.css' ),
|
306 |
'js_bootstrap' => $oCon->getPluginUrl_Js( 'bootstrap4.min.js' ),
|
307 |
'shield_logo' => 'https://ps.w.org/wp-simple-firewall/assets/banner-772x250.png',
|
310 |
'favicon' => $oCon->getPluginUrl_Image( 'pluginlogo_24x24.png' ),
|
311 |
),
|
312 |
'flags' => array(
|
313 |
+
'can_skip_mfa' => $oFO->getMfaSkipEnabled(),
|
314 |
+
'show_what_is_this' => !$oFO->isPremium(), // white label mitigation
|
315 |
)
|
316 |
);
|
317 |
|
363 |
return $this->oLoginTrack;
|
364 |
}
|
365 |
|
366 |
+
/**
|
367 |
+
* assume that a user is logged in.
|
368 |
+
* @return bool
|
369 |
+
*/
|
370 |
+
private function getIsLoginIntentValid() {
|
371 |
+
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
372 |
+
$oFO = $this->getFeature();
|
373 |
+
if ( !$this->isLoginIntentProcessed() ) {
|
374 |
+
// This action sets up the necessary login tracker info
|
375 |
+
do_action( $oFO->prefix( 'login-intent-validation' ), $this->loadWpUsers()->getCurrentWpUser() );
|
376 |
+
$this->setLoginIntentProcessed();
|
377 |
+
}
|
378 |
+
$oTrk = $this->getLoginTrack();
|
379 |
+
return $oFO->isChainedAuth() ? $oTrk->hasUnSuccessfulFactor() : $oTrk->hasSuccessfulFactor();
|
380 |
+
}
|
381 |
+
|
382 |
+
/**
|
383 |
+
* @return bool
|
384 |
+
*/
|
385 |
+
public function isLoginIntentProcessed() {
|
386 |
+
return (bool)$this->bLoginIntentProcessed;
|
387 |
+
}
|
388 |
+
|
389 |
+
/**
|
390 |
+
* @return $this
|
391 |
+
*/
|
392 |
+
public function setLoginIntentProcessed() {
|
393 |
+
$this->bLoginIntentProcessed = true;
|
394 |
+
return $this;
|
395 |
+
}
|
396 |
+
|
397 |
/**
|
398 |
* @param ICWP_WPSF_Processor_LoginProtect_Track $oLoginTrack
|
399 |
* @return $this
|
src/processors/loginprotect_intentprovider_base.php
CHANGED
@@ -29,7 +29,7 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
|
|
29 |
}
|
30 |
|
31 |
// Necessary so we don't show user intent to people without it
|
32 |
-
add_filter( $oFO->prefix( 'user_subject_to_login_intent' ), array( $this, '
|
33 |
|
34 |
add_action( 'show_user_profile', array( $this, 'addOptionsToUserProfile' ) );
|
35 |
add_action( 'personal_options_update', array( $this, 'handleUserProfileSubmit' ) );
|
@@ -41,10 +41,10 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
|
|
41 |
}
|
42 |
|
43 |
/**
|
|
|
44 |
*/
|
45 |
-
public function validateLoginIntent() {
|
46 |
$oLoginTrack = $this->getLoginTrack();
|
47 |
-
$oUser = $this->loadWpUsers()->getCurrentWpUser();
|
48 |
|
49 |
$sFactor = $this->getStub();
|
50 |
if ( !$this->isProfileReady( $oUser ) ) {
|
@@ -53,11 +53,11 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
|
|
53 |
else {
|
54 |
if ( $this->processOtp( $oUser, $this->fetchCodeFromRequest() ) ) {
|
55 |
$oLoginTrack->addSuccessfulFactor( $sFactor );
|
56 |
-
$this->auditLogin( true );
|
57 |
}
|
58 |
else {
|
59 |
$oLoginTrack->addUnSuccessfulFactor( $sFactor );
|
60 |
-
$this->auditLogin( false );
|
61 |
}
|
62 |
}
|
63 |
}
|
@@ -74,6 +74,10 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
|
|
74 |
* @return bool
|
75 |
*/
|
76 |
protected function hasValidatedProfile( $oUser ) {
|
|
|
|
|
|
|
|
|
77 |
$oWpUsers = $this->loadWpUsers();
|
78 |
|
79 |
$sKey = $this->getStub().'_validated';
|
@@ -251,9 +255,10 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
|
|
251 |
abstract public function addLoginIntentField( $aFields );
|
252 |
|
253 |
/**
|
254 |
-
* @param
|
|
|
255 |
*/
|
256 |
-
abstract protected function auditLogin( $bIsSuccess );
|
257 |
|
258 |
/**
|
259 |
* @return string
|
@@ -270,11 +275,12 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
|
|
270 |
}
|
271 |
|
272 |
/**
|
273 |
-
* @param bool
|
|
|
274 |
* @return bool
|
275 |
*/
|
276 |
-
public function
|
277 |
-
return ( $bIsSubjectTo || $this->
|
278 |
}
|
279 |
|
280 |
/**
|
29 |
}
|
30 |
|
31 |
// Necessary so we don't show user intent to people without it
|
32 |
+
add_filter( $oFO->prefix( 'user_subject_to_login_intent' ), array( $this, 'filterUserSubjectToIntent' ), 10, 2 );
|
33 |
|
34 |
add_action( 'show_user_profile', array( $this, 'addOptionsToUserProfile' ) );
|
35 |
add_action( 'personal_options_update', array( $this, 'handleUserProfileSubmit' ) );
|
41 |
}
|
42 |
|
43 |
/**
|
44 |
+
* @param WP_User $oUser
|
45 |
*/
|
46 |
+
public function validateLoginIntent( $oUser ) {
|
47 |
$oLoginTrack = $this->getLoginTrack();
|
|
|
48 |
|
49 |
$sFactor = $this->getStub();
|
50 |
if ( !$this->isProfileReady( $oUser ) ) {
|
53 |
else {
|
54 |
if ( $this->processOtp( $oUser, $this->fetchCodeFromRequest() ) ) {
|
55 |
$oLoginTrack->addSuccessfulFactor( $sFactor );
|
56 |
+
$this->auditLogin( $oUser, true );
|
57 |
}
|
58 |
else {
|
59 |
$oLoginTrack->addUnSuccessfulFactor( $sFactor );
|
60 |
+
$this->auditLogin( $oUser, false );
|
61 |
}
|
62 |
}
|
63 |
}
|
74 |
* @return bool
|
75 |
*/
|
76 |
protected function hasValidatedProfile( $oUser ) {
|
77 |
+
if ( !( $oUser instanceof WP_User ) ) {
|
78 |
+
return false;
|
79 |
+
}
|
80 |
+
|
81 |
$oWpUsers = $this->loadWpUsers();
|
82 |
|
83 |
$sKey = $this->getStub().'_validated';
|
255 |
abstract public function addLoginIntentField( $aFields );
|
256 |
|
257 |
/**
|
258 |
+
* @param WP_User $oUser
|
259 |
+
* @param bool $bIsSuccess
|
260 |
*/
|
261 |
+
abstract protected function auditLogin( $oUser, $bIsSuccess );
|
262 |
|
263 |
/**
|
264 |
* @return string
|
275 |
}
|
276 |
|
277 |
/**
|
278 |
+
* @param bool $bIsSubjectTo
|
279 |
+
* @param WP_User $oUser
|
280 |
* @return bool
|
281 |
*/
|
282 |
+
public function filterUserSubjectToIntent( $bIsSubjectTo, $oUser ) {
|
283 |
+
return ( $bIsSubjectTo || $this->hasValidatedProfile( $oUser ) );
|
284 |
}
|
285 |
|
286 |
/**
|
src/processors/loginprotect_track.php
CHANGED
@@ -108,14 +108,14 @@ class ICWP_WPSF_Processor_LoginProtect_Track {
|
|
108 |
/**
|
109 |
* @return bool
|
110 |
*/
|
111 |
-
public function
|
112 |
return ( $this->getCountFactorsSuccessful() > 0 );
|
113 |
}
|
114 |
|
115 |
/**
|
116 |
* @return bool
|
117 |
*/
|
118 |
-
public function
|
119 |
return ( $this->getCountFactorsUnsuccessful() > 0 );
|
120 |
}
|
121 |
|
108 |
/**
|
109 |
* @return bool
|
110 |
*/
|
111 |
+
public function hasSuccessfulFactor() {
|
112 |
return ( $this->getCountFactorsSuccessful() > 0 );
|
113 |
}
|
114 |
|
115 |
/**
|
116 |
* @return bool
|
117 |
*/
|
118 |
+
public function hasUnSuccessfulFactor() {
|
119 |
return ( $this->getCountFactorsUnsuccessful() > 0 );
|
120 |
}
|
121 |
|
src/processors/loginprotect_twofactorauth.php
CHANGED
@@ -36,16 +36,15 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
|
|
36 |
}
|
37 |
|
38 |
/**
|
39 |
-
* @param
|
|
|
40 |
*/
|
41 |
-
protected function auditLogin( $bIsSuccess ) {
|
42 |
if ( $bIsSuccess ) {
|
43 |
$this->addToAuditEntry(
|
44 |
sprintf(
|
45 |
_wpsf__( 'User "%s" verified their identity using Email Two-Factor Authentication.' ),
|
46 |
-
$
|
47 |
-
),
|
48 |
-
2, 'login_protect_two_factor_verified'
|
49 |
);
|
50 |
$this->doStatIncrement( 'login.twofactor.verified' );
|
51 |
}
|
@@ -53,9 +52,7 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
|
|
53 |
$this->addToAuditEntry(
|
54 |
sprintf(
|
55 |
_wpsf__( 'User "%s" failed to verify their identity using Email Two-Factor Authentication.' ),
|
56 |
-
$
|
57 |
-
),
|
58 |
-
2, 'login_protect_two_factor_failed'
|
59 |
);
|
60 |
$this->doStatIncrement( 'login.twofactor.failed' );
|
61 |
}
|
@@ -86,7 +83,7 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
|
|
86 |
'value' => $this->fetchCodeFromRequest(),
|
87 |
'placeholder' => _wpsf__( 'This code was just sent to your registered Email address.' ),
|
88 |
'text' => _wpsf__( 'Email OTP' ),
|
89 |
-
'help_link' => '
|
90 |
);
|
91 |
}
|
92 |
return $aFields;
|
@@ -108,13 +105,11 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
|
|
108 |
* @param WP_User $oUser
|
109 |
* @return bool
|
110 |
*/
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
$
|
115 |
-
|
116 |
-
$aSubjectedUserLevels = array( 1, 2, 3, 8 ); // by default all roles except subscribers!
|
117 |
-
}
|
118 |
|
119 |
// see: https://codex.wordpress.org/Roles_and_Capabilities#User_Level_to_Role_Conversion
|
120 |
|
@@ -188,13 +183,17 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
|
|
188 |
sprintf( _wpsf__( 'Username: %s' ), $oUser->get( 'user_login' ) ),
|
189 |
sprintf( _wpsf__( 'IP Address: %s' ), $sIpAddress ),
|
190 |
'',
|
191 |
-
sprintf( '- <a href="%s" target="_blank">%s</a>', 'http://icwp.io/96', _wpsf__( 'Why no login link?' ) ),
|
192 |
-
''
|
193 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
$sEmailSubject = _wpsf__( 'Two-Factor Login Verification' );
|
195 |
|
196 |
$bResult = $this->getEmailProcessor()
|
197 |
-
->
|
198 |
if ( $bResult ) {
|
199 |
$sAuditMessage = sprintf( _wpsf__( 'User "%s" was sent an email to verify their Identity using Two-Factor Login Auth for IP address "%s".' ), $oUser->get( 'user_login' ), $sIpAddress );
|
200 |
$this->addToAuditEntry( $sAuditMessage, 2, 'login_protect_two_factor_email_send' );
|
36 |
}
|
37 |
|
38 |
/**
|
39 |
+
* @param WP_User $oUser
|
40 |
+
* @param bool $bIsSuccess
|
41 |
*/
|
42 |
+
protected function auditLogin( $oUser, $bIsSuccess ) {
|
43 |
if ( $bIsSuccess ) {
|
44 |
$this->addToAuditEntry(
|
45 |
sprintf(
|
46 |
_wpsf__( 'User "%s" verified their identity using Email Two-Factor Authentication.' ),
|
47 |
+
$oUser->user_login ), 2, 'login_protect_two_factor_verified'
|
|
|
|
|
48 |
);
|
49 |
$this->doStatIncrement( 'login.twofactor.verified' );
|
50 |
}
|
52 |
$this->addToAuditEntry(
|
53 |
sprintf(
|
54 |
_wpsf__( 'User "%s" failed to verify their identity using Email Two-Factor Authentication.' ),
|
55 |
+
$oUser->user_login ), 2, 'login_protect_two_factor_failed'
|
|
|
|
|
56 |
);
|
57 |
$this->doStatIncrement( 'login.twofactor.failed' );
|
58 |
}
|
83 |
'value' => $this->fetchCodeFromRequest(),
|
84 |
'placeholder' => _wpsf__( 'This code was just sent to your registered Email address.' ),
|
85 |
'text' => _wpsf__( 'Email OTP' ),
|
86 |
+
'help_link' => 'https://icwp.io/3t'
|
87 |
);
|
88 |
}
|
89 |
return $aFields;
|
105 |
* @param WP_User $oUser
|
106 |
* @return bool
|
107 |
*/
|
108 |
+
private function getIsUserSubjectToEmailAuthentication( $oUser ) {
|
109 |
+
/** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
|
110 |
+
$oFO = $this->getFeature();
|
111 |
+
$nUserLevel = $oUser->user_level;
|
112 |
+
$aSubjectedUserLevels = $oFO->getEmail2FaRoles();
|
|
|
|
|
113 |
|
114 |
// see: https://codex.wordpress.org/Roles_and_Capabilities#User_Level_to_Role_Conversion
|
115 |
|
183 |
sprintf( _wpsf__( 'Username: %s' ), $oUser->get( 'user_login' ) ),
|
184 |
sprintf( _wpsf__( 'IP Address: %s' ), $sIpAddress ),
|
185 |
'',
|
|
|
|
|
186 |
);
|
187 |
+
|
188 |
+
if ( !$this->getController()->isRelabelled() ) {
|
189 |
+
$aMessage[] = sprintf( '- <a href="%s" target="_blank">%s</a>', 'https://icwp.io/96', _wpsf__( 'Why no login link?' ) );
|
190 |
+
$aContent[] = '';
|
191 |
+
}
|
192 |
+
|
193 |
$sEmailSubject = _wpsf__( 'Two-Factor Login Verification' );
|
194 |
|
195 |
$bResult = $this->getEmailProcessor()
|
196 |
+
->sendEmailWithWrap( $sEmail, $sEmailSubject, $aMessage );
|
197 |
if ( $bResult ) {
|
198 |
$sAuditMessage = sprintf( _wpsf__( 'User "%s" was sent an email to verify their Identity using Two-Factor Login Auth for IP address "%s".' ), $oUser->get( 'user_login' ), $sIpAddress );
|
199 |
$this->addToAuditEntry( $sAuditMessage, 2, 'login_protect_two_factor_email_send' );
|
src/processors/loginprotect_wplogin.php
CHANGED
@@ -84,7 +84,7 @@ class ICWP_WPSF_Processor_LoginProtect_WpLogin extends ICWP_WPSF_Processor_BaseW
|
|
84 |
* @return bool
|
85 |
*/
|
86 |
protected function checkForUnsupportedConfiguration() {
|
87 |
-
$oDp = $this->
|
88 |
$aRequestParts = $oDp->getRequestUriParts();
|
89 |
if ( $aRequestParts === false || empty( $aRequestParts['path'] ) ) {
|
90 |
|
@@ -108,7 +108,7 @@ class ICWP_WPSF_Processor_LoginProtect_WpLogin extends ICWP_WPSF_Processor_BaseW
|
|
108 |
|
109 |
// Next block option is where it's a direct attempt to access the old login URL
|
110 |
if ( !$bDoBlock ) {
|
111 |
-
$sPath = trim( $this->
|
112 |
$aPossiblePaths = array(
|
113 |
trim( home_url( 'wp-login.php', 'relative' ), '/' ),
|
114 |
trim( home_url( 'wp-signup.php', 'relative' ), '/' ),
|
@@ -181,7 +181,7 @@ class ICWP_WPSF_Processor_LoginProtect_WpLogin extends ICWP_WPSF_Processor_BaseW
|
|
181 |
* @return string
|
182 |
*/
|
183 |
public function blockRegisterUrlRedirect( $sUrl ) {
|
184 |
-
$aParts = $this->
|
185 |
if ( is_array( $aParts ) && !empty( $aParts[ 'path' ] ) && strpos( $aParts[ 'path' ], 'wp-register.php' ) ) {
|
186 |
$this->doWpLoginFailedRedirect404();
|
187 |
die();
|
84 |
* @return bool
|
85 |
*/
|
86 |
protected function checkForUnsupportedConfiguration() {
|
87 |
+
$oDp = $this->loadDP();
|
88 |
$aRequestParts = $oDp->getRequestUriParts();
|
89 |
if ( $aRequestParts === false || empty( $aRequestParts['path'] ) ) {
|
90 |
|
108 |
|
109 |
// Next block option is where it's a direct attempt to access the old login URL
|
110 |
if ( !$bDoBlock ) {
|
111 |
+
$sPath = trim( $this->loadDP()->getRequestPath(), '/' );
|
112 |
$aPossiblePaths = array(
|
113 |
trim( home_url( 'wp-login.php', 'relative' ), '/' ),
|
114 |
trim( home_url( 'wp-signup.php', 'relative' ), '/' ),
|
181 |
* @return string
|
182 |
*/
|
183 |
public function blockRegisterUrlRedirect( $sUrl ) {
|
184 |
+
$aParts = $this->loadDP()->getRequestUriParts();
|
185 |
if ( is_array( $aParts ) && !empty( $aParts[ 'path' ] ) && strpos( $aParts[ 'path' ], 'wp-register.php' ) ) {
|
186 |
$this->doWpLoginFailedRedirect404();
|
187 |
die();
|
src/processors/loginprotect_yubikey.php
CHANGED
@@ -29,13 +29,14 @@ class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_Login
|
|
29 |
*/
|
30 |
public function addOptionsToUserProfile( $oUser ) {
|
31 |
$oCon = $this->getController();
|
|
|
32 |
|
33 |
$bValidatedProfile = $this->hasValidatedProfile( $oUser );
|
34 |
$aData = array(
|
35 |
'has_validated_profile' => $bValidatedProfile,
|
36 |
-
'is_my_user_profile' => ( $oUser->ID == $
|
37 |
'i_am_valid_admin' => $oCon->getHasPermissionToManage(),
|
38 |
-
'user_to_edit_is_admin' => $
|
39 |
'strings' => array(
|
40 |
'description_otp_code' => _wpsf__( 'This is your unique Yubikey Device ID.' ),
|
41 |
'description_otp' => _wpsf__( 'Provide a One Time Password from your Yubikey.' ),
|
@@ -116,7 +117,7 @@ class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_Login
|
|
116 |
$oFO = $this->getFeature();
|
117 |
$oLoginTrack = $this->getLoginTrack();
|
118 |
|
119 |
-
$bNeedToCheckThisFactor = $oFO->isChainedAuth() || !$oLoginTrack->
|
120 |
$bErrorOnFailure = $bNeedToCheckThisFactor && $oLoginTrack->isFinalFactorRemainingToTrack();
|
121 |
$oLoginTrack->addUnSuccessfulFactor( ICWP_WPSF_Processor_LoginProtect_Track::Factor_Yubikey );
|
122 |
|
@@ -208,24 +209,21 @@ class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_Login
|
|
208 |
}
|
209 |
|
210 |
/**
|
211 |
-
* @param
|
|
|
212 |
*/
|
213 |
-
protected function auditLogin( $bIsSuccess ) {
|
214 |
if ( $bIsSuccess ) {
|
215 |
$this->addToAuditEntry(
|
216 |
-
sprintf( _wpsf__( 'User "%s" successfully logged in using a validated Yubikey One Time Password.' ),
|
217 |
-
|
218 |
-
->get( 'user_login' ) ),
|
219 |
-
2, 'login_protect_yubikey_login_success'
|
220 |
);
|
221 |
$this->doStatIncrement( 'login.yubikey.verified' );
|
222 |
}
|
223 |
else {
|
224 |
$this->addToAuditEntry(
|
225 |
-
sprintf( _wpsf__( 'User "%s" failed to verify their identity using Yubikey One Time Password.' ),
|
226 |
-
|
227 |
-
->get( 'user_login' ) ),
|
228 |
-
2, 'login_protect_yubikey_failed'
|
229 |
);
|
230 |
$this->doStatIncrement( 'login.yubikey.failed' );
|
231 |
}
|
@@ -243,7 +241,7 @@ class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_Login
|
|
243 |
'placeholder' => _wpsf__( 'Use your Yubikey to generate a new code.' ),
|
244 |
'value' => '',
|
245 |
'text' => _wpsf__( 'Yubikey OTP' ),
|
246 |
-
'help_link' => '
|
247 |
);
|
248 |
}
|
249 |
return $aFields;
|
29 |
*/
|
30 |
public function addOptionsToUserProfile( $oUser ) {
|
31 |
$oCon = $this->getController();
|
32 |
+
$oWpUsers = $this->loadWpUsers();
|
33 |
|
34 |
$bValidatedProfile = $this->hasValidatedProfile( $oUser );
|
35 |
$aData = array(
|
36 |
'has_validated_profile' => $bValidatedProfile,
|
37 |
+
'is_my_user_profile' => ( $oUser->ID == $oWpUsers->getCurrentWpUserId() ),
|
38 |
'i_am_valid_admin' => $oCon->getHasPermissionToManage(),
|
39 |
+
'user_to_edit_is_admin' => $oWpUsers->isUserAdmin( $oUser ),
|
40 |
'strings' => array(
|
41 |
'description_otp_code' => _wpsf__( 'This is your unique Yubikey Device ID.' ),
|
42 |
'description_otp' => _wpsf__( 'Provide a One Time Password from your Yubikey.' ),
|
117 |
$oFO = $this->getFeature();
|
118 |
$oLoginTrack = $this->getLoginTrack();
|
119 |
|
120 |
+
$bNeedToCheckThisFactor = $oFO->isChainedAuth() || !$oLoginTrack->hasSuccessfulFactor();
|
121 |
$bErrorOnFailure = $bNeedToCheckThisFactor && $oLoginTrack->isFinalFactorRemainingToTrack();
|
122 |
$oLoginTrack->addUnSuccessfulFactor( ICWP_WPSF_Processor_LoginProtect_Track::Factor_Yubikey );
|
123 |
|
209 |
}
|
210 |
|
211 |
/**
|
212 |
+
* @param WP_User $oUser
|
213 |
+
* @param bool $bIsSuccess
|
214 |
*/
|
215 |
+
protected function auditLogin( $oUser, $bIsSuccess ) {
|
216 |
if ( $bIsSuccess ) {
|
217 |
$this->addToAuditEntry(
|
218 |
+
sprintf( _wpsf__( 'User "%s" successfully logged in using a validated Yubikey One Time Password.' ),
|
219 |
+
$oUser->user_login ), 2, 'login_protect_yubikey_login_success'
|
|
|
|
|
220 |
);
|
221 |
$this->doStatIncrement( 'login.yubikey.verified' );
|
222 |
}
|
223 |
else {
|
224 |
$this->addToAuditEntry(
|
225 |
+
sprintf( _wpsf__( 'User "%s" failed to verify their identity using Yubikey One Time Password.' ),
|
226 |
+
$oUser->user_login ), 2, 'login_protect_yubikey_failed'
|
|
|
|
|
227 |
);
|
228 |
$this->doStatIncrement( 'login.yubikey.failed' );
|
229 |
}
|
241 |
'placeholder' => _wpsf__( 'Use your Yubikey to generate a new code.' ),
|
242 |
'value' => '',
|
243 |
'text' => _wpsf__( 'Yubikey OTP' ),
|
244 |
+
'help_link' => 'https://icwp.io/4i'
|
245 |
);
|
246 |
}
|
247 |
return $aFields;
|
src/processors/plugin.php
CHANGED
@@ -34,6 +34,10 @@ class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
|
|
34 |
$this->getTrackingProcessor()->run();
|
35 |
}
|
36 |
|
|
|
|
|
|
|
|
|
37 |
add_action( 'wp_loaded', array( $this, 'onWpLoaded' ) );
|
38 |
add_action( 'in_admin_footer', array( $this, 'printVisitorIpFooter' ) );
|
39 |
|
@@ -44,7 +48,7 @@ class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
|
|
44 |
|
45 |
case 'importexport_export':
|
46 |
case 'importexport_handshake':
|
47 |
-
case '
|
48 |
if ( $oFO->isImportExportPermitted() ) {
|
49 |
$this->getSubProcessorImportExport()->runAction();
|
50 |
}
|
34 |
$this->getTrackingProcessor()->run();
|
35 |
}
|
36 |
|
37 |
+
if ( $oFO->isImportExportPermitted() ) {
|
38 |
+
$this->getSubProcessorImportExport()->run();
|
39 |
+
}
|
40 |
+
|
41 |
add_action( 'wp_loaded', array( $this, 'onWpLoaded' ) );
|
42 |
add_action( 'in_admin_footer', array( $this, 'printVisitorIpFooter' ) );
|
43 |
|
48 |
|
49 |
case 'importexport_export':
|
50 |
case 'importexport_handshake':
|
51 |
+
case 'importexport_updatenotified':
|
52 |
if ( $oFO->isImportExportPermitted() ) {
|
53 |
$this->getSubProcessorImportExport()->runAction();
|
54 |
}
|
src/processors/plugin_badge.php
CHANGED
@@ -24,7 +24,7 @@ class ICWP_WPSF_Processor_Plugin_Badge extends ICWP_WPSF_Processor_BaseWpsf {
|
|
24 |
}
|
25 |
|
26 |
public function includeJquery() {
|
27 |
-
wp_enqueue_script( 'jquery', null, array(), false, true
|
28 |
}
|
29 |
|
30 |
/**
|
@@ -32,11 +32,15 @@ class ICWP_WPSF_Processor_Plugin_Badge extends ICWP_WPSF_Processor_BaseWpsf {
|
|
32 |
* @return array
|
33 |
*/
|
34 |
public function gatherPluginWidgetContent( $aContent ) {
|
|
|
|
|
|
|
35 |
|
36 |
-
$
|
37 |
-
|
38 |
-
sprintf( '<a href="%s"
|
39 |
);
|
|
|
40 |
$aDisplayData = array(
|
41 |
'sInstallationDays' => sprintf( _wpsf__( 'Days Installed: %s' ), $this->getInstallationDays() ),
|
42 |
'sFooter' => $sFooter,
|
@@ -46,8 +50,7 @@ class ICWP_WPSF_Processor_Plugin_Badge extends ICWP_WPSF_Processor_BaseWpsf {
|
|
46 |
if ( !is_array( $aContent ) ) {
|
47 |
$aContent = array();
|
48 |
}
|
49 |
-
$aContent[] = $
|
50 |
-
->renderTemplate( 'snippets/widget_dashboard_plugin.php', $aDisplayData );
|
51 |
return $aContent;
|
52 |
}
|
53 |
|
24 |
}
|
25 |
|
26 |
public function includeJquery() {
|
27 |
+
wp_enqueue_script( 'jquery', null, array(), false, true );
|
28 |
}
|
29 |
|
30 |
/**
|
32 |
* @return array
|
33 |
*/
|
34 |
public function gatherPluginWidgetContent( $aContent ) {
|
35 |
+
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
36 |
+
$oFO = $this->getFeature();
|
37 |
+
$oCon = $this->getController();
|
38 |
|
39 |
+
$aLabels = $oCon->getPluginLabels();
|
40 |
+
$sFooter = sprintf( _wpsf__( '%s is provided by %s' ), $oCon->getHumanName(),
|
41 |
+
sprintf( '<a href="%s">%s</a>', $aLabels[ 'AuthorURI' ], $aLabels[ 'Author' ] )
|
42 |
);
|
43 |
+
|
44 |
$aDisplayData = array(
|
45 |
'sInstallationDays' => sprintf( _wpsf__( 'Days Installed: %s' ), $this->getInstallationDays() ),
|
46 |
'sFooter' => $sFooter,
|
50 |
if ( !is_array( $aContent ) ) {
|
51 |
$aContent = array();
|
52 |
}
|
53 |
+
$aContent[] = $oFO->renderTemplate( 'snippets/widget_dashboard_plugin.php', $aDisplayData );
|
|
|
54 |
return $aContent;
|
55 |
}
|
56 |
|
src/processors/plugin_importexport.php
CHANGED
@@ -12,6 +12,8 @@ class ICWP_WPSF_Processor_Plugin_ImportExport extends ICWP_WPSF_Processor_BaseWp
|
|
12 |
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
13 |
$oFO = $this->getFeature();
|
14 |
|
|
|
|
|
15 |
if ( $oFO->hasImportExportMasterImportUrl() ) {
|
16 |
try {
|
17 |
$this->setupCronImport();
|
@@ -22,6 +24,31 @@ class ICWP_WPSF_Processor_Plugin_ImportExport extends ICWP_WPSF_Processor_BaseWp
|
|
22 |
}
|
23 |
}
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
public function runAction() {
|
26 |
$oDP = $this->loadDP();
|
27 |
switch ( $oDP->query( 'shield_action' ) ) {
|
@@ -34,8 +61,8 @@ class ICWP_WPSF_Processor_Plugin_ImportExport extends ICWP_WPSF_Processor_BaseWp
|
|
34 |
add_action( 'init', array( $this, 'runOptionsExportHandshake' ) );
|
35 |
break;
|
36 |
|
37 |
-
case '
|
38 |
-
add_action( 'init', array( $this, '
|
39 |
break;
|
40 |
|
41 |
default:
|
@@ -62,11 +89,40 @@ class ICWP_WPSF_Processor_Plugin_ImportExport extends ICWP_WPSF_Processor_BaseWp
|
|
62 |
}
|
63 |
|
64 |
/**
|
65 |
-
*
|
66 |
*/
|
67 |
-
public function
|
68 |
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
69 |
$oFO = $this->getFeature();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
}
|
71 |
|
72 |
/**
|
@@ -163,9 +219,13 @@ class ICWP_WPSF_Processor_Plugin_ImportExport extends ICWP_WPSF_Processor_BaseWp
|
|
163 |
* @throws Exception
|
164 |
*/
|
165 |
protected function setupCronImport() {
|
|
|
|
|
166 |
$this->loadWpCronProcessor()
|
167 |
->setNextRun( strtotime( 'tomorrow 1am' ) - get_option( 'gmt_offset' )*HOUR_IN_SECONDS + rand( 0, 1800 ) )
|
168 |
->createCronJob( $this->getCronName(), array( $this, 'cron_autoImport' ) );
|
|
|
|
|
169 |
add_action( $this->getFeature()->prefix( 'delete_plugin' ), array( $this, 'deleteCron' ) );
|
170 |
}
|
171 |
|
@@ -256,6 +316,11 @@ class ICWP_WPSF_Processor_Plugin_ImportExport extends ICWP_WPSF_Processor_BaseWp
|
|
256 |
'options_imported'
|
257 |
);
|
258 |
$oFO->setImportExportLastImportHash( md5( serialize( $aParts[ 'data' ] ) ) );
|
|
|
|
|
|
|
|
|
|
|
259 |
}
|
260 |
|
261 |
// if it's network enabled, we save the new master URL.
|
12 |
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
13 |
$oFO = $this->getFeature();
|
14 |
|
15 |
+
add_action( $this->prefix( 'importexport_notify' ), array( $this, 'runWhitelistNotify' ) );
|
16 |
+
|
17 |
if ( $oFO->hasImportExportMasterImportUrl() ) {
|
18 |
try {
|
19 |
$this->setupCronImport();
|
24 |
}
|
25 |
}
|
26 |
|
27 |
+
public function runWhitelistNotify() {
|
28 |
+
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
29 |
+
$oFO = $this->getFeature();
|
30 |
+
|
31 |
+
if ( $oFO->hasImportExportWhitelistSites() ) {
|
32 |
+
|
33 |
+
$oFs = $this->loadFS();
|
34 |
+
foreach ( $oFO->getImportExportWhitelist() as $sUrl ) {
|
35 |
+
$oFs->getUrl(
|
36 |
+
$sUrl,
|
37 |
+
array(
|
38 |
+
'blocking' => false,
|
39 |
+
'body' => array( 'shield_action' => 'importexport_updatenotified' )
|
40 |
+
)
|
41 |
+
);
|
42 |
+
}
|
43 |
+
|
44 |
+
$this->addToAuditEntry(
|
45 |
+
_wpsf__( 'Sent notifications to whitelisted sites for required options import.' ),
|
46 |
+
1,
|
47 |
+
'options_import_notify'
|
48 |
+
);
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
public function runAction() {
|
53 |
$oDP = $this->loadDP();
|
54 |
switch ( $oDP->query( 'shield_action' ) ) {
|
61 |
add_action( 'init', array( $this, 'runOptionsExportHandshake' ) );
|
62 |
break;
|
63 |
|
64 |
+
case 'importexport_updatenotified':
|
65 |
+
add_action( 'init', array( $this, 'runOptionsUpdateNotified' ) );
|
66 |
break;
|
67 |
|
68 |
default:
|
89 |
}
|
90 |
|
91 |
/**
|
92 |
+
* We've been notified that there's an update to pull in from the master site so we set a cron to do this.
|
93 |
*/
|
94 |
+
public function runOptionsUpdateNotified() {
|
95 |
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
96 |
$oFO = $this->getFeature();
|
97 |
+
|
98 |
+
$sCronHook = $oFO->prefix( 'importexport_updatenotified' );
|
99 |
+
if ( wp_next_scheduled( $sCronHook ) ) {
|
100 |
+
wp_clear_scheduled_hook( $sCronHook );
|
101 |
+
}
|
102 |
+
|
103 |
+
if ( !wp_next_scheduled( $sCronHook ) ) {
|
104 |
+
|
105 |
+
wp_schedule_single_event( $this->loadDP()->time() + 12, $sCronHook );
|
106 |
+
|
107 |
+
preg_match( '#.*WordPress/.*\s+(.*)\s?#', $this->loadDP()->server( 'HTTP_USER_AGENT' ), $aMatches );
|
108 |
+
if ( !empty( $aMatches[ 1 ] ) && filter_var( $aMatches[ 1 ], FILTER_VALIDATE_URL ) ) {
|
109 |
+
$sUrl = parse_url( $aMatches[ 1 ], PHP_URL_HOST );
|
110 |
+
if ( !empty( $sUrl ) ) {
|
111 |
+
$sUrl = 'Site: '.$sUrl;
|
112 |
+
}
|
113 |
+
}
|
114 |
+
else {
|
115 |
+
$sUrl = '';
|
116 |
+
}
|
117 |
+
|
118 |
+
$this->addToAuditEntry(
|
119 |
+
_wpsf__( 'Received notification that options import required.' )
|
120 |
+
.' '.sprintf( _wpsf__( 'Current master site: %s' ), $oFO->getImportExportMasterImportUrl() ),
|
121 |
+
1,
|
122 |
+
'options_import_notified',
|
123 |
+
$sUrl
|
124 |
+
);
|
125 |
+
}
|
126 |
}
|
127 |
|
128 |
/**
|
219 |
* @throws Exception
|
220 |
*/
|
221 |
protected function setupCronImport() {
|
222 |
+
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
223 |
+
$oFO = $this->getFeature();
|
224 |
$this->loadWpCronProcessor()
|
225 |
->setNextRun( strtotime( 'tomorrow 1am' ) - get_option( 'gmt_offset' )*HOUR_IN_SECONDS + rand( 0, 1800 ) )
|
226 |
->createCronJob( $this->getCronName(), array( $this, 'cron_autoImport' ) );
|
227 |
+
// For auto update whitelist notifications:
|
228 |
+
add_action( $oFO->prefix( 'importexport_updatenotified' ), array( $this, 'cron_autoImport' ) );
|
229 |
add_action( $this->getFeature()->prefix( 'delete_plugin' ), array( $this, 'deleteCron' ) );
|
230 |
}
|
231 |
|
316 |
'options_imported'
|
317 |
);
|
318 |
$oFO->setImportExportLastImportHash( md5( serialize( $aParts[ 'data' ] ) ) );
|
319 |
+
|
320 |
+
// Fix for the overwriting of the Master Site URL with an empty string.
|
321 |
+
if ( !$oFO->hasImportExportMasterImportUrl() ) {
|
322 |
+
$oFO->setImportExportMasterImportUrl( $sMasterSiteUrl );
|
323 |
+
}
|
324 |
}
|
325 |
|
326 |
// if it's network enabled, we save the new master URL.
|
src/processors/plugin_notes.php
CHANGED
@@ -9,11 +9,11 @@ require_once( dirname( __FILE__ ).'/basedb.php' );
|
|
9 |
class ICWP_WPSF_Processor_Plugin_Notes extends ICWP_WPSF_BaseDbProcessor {
|
10 |
|
11 |
/**
|
12 |
-
* @param ICWP_WPSF_FeatureHandler_Plugin $
|
13 |
* @throws Exception
|
14 |
*/
|
15 |
-
public function __construct( ICWP_WPSF_FeatureHandler_Plugin $
|
16 |
-
parent::__construct( $
|
17 |
}
|
18 |
|
19 |
public function run() {
|
9 |
class ICWP_WPSF_Processor_Plugin_Notes extends ICWP_WPSF_BaseDbProcessor {
|
10 |
|
11 |
/**
|
12 |
+
* @param ICWP_WPSF_FeatureHandler_Plugin $oModCon
|
13 |
* @throws Exception
|
14 |
*/
|
15 |
+
public function __construct( ICWP_WPSF_FeatureHandler_Plugin $oModCon ) {
|
16 |
+
parent::__construct( $oModCon, $oModCon->getDbNameNotes() );
|
17 |
}
|
18 |
|
19 |
public function run() {
|
src/processors/plugin_tracking.php
CHANGED
@@ -44,7 +44,7 @@ class ICWP_WPSF_Processor_Plugin_Tracking extends ICWP_WPSF_Processor_BasePlugin
|
|
44 |
'hrefs' => array(
|
45 |
'learn_more' => 'http://translate.icontrolwp.com',
|
46 |
'link_to_see' => $oFO->getLinkToTrackingDataDump(),
|
47 |
-
'link_to_moreinfo' => '
|
48 |
|
49 |
)
|
50 |
);
|
@@ -98,7 +98,7 @@ class ICWP_WPSF_Processor_Plugin_Tracking extends ICWP_WPSF_Processor_BasePlugin
|
|
98 |
* @return array
|
99 |
*/
|
100 |
protected function getBaseTrackingData() {
|
101 |
-
$oDP = $this->
|
102 |
$oWP = $this->loadWp();
|
103 |
$oWpPlugins = $this->loadWpPlugins();
|
104 |
return array(
|
44 |
'hrefs' => array(
|
45 |
'learn_more' => 'http://translate.icontrolwp.com',
|
46 |
'link_to_see' => $oFO->getLinkToTrackingDataDump(),
|
47 |
+
'link_to_moreinfo' => 'https://icwp.io/shieldtrackinginfo',
|
48 |
|
49 |
)
|
50 |
);
|
98 |
* @return array
|
99 |
*/
|
100 |
protected function getBaseTrackingData() {
|
101 |
+
$oDP = $this->loadDP();
|
102 |
$oWP = $this->loadWp();
|
103 |
$oWpPlugins = $this->loadWpPlugins();
|
104 |
return array(
|
src/processors/sessions.php
CHANGED
@@ -19,35 +19,58 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
|
|
19 |
private $oCurrent;
|
20 |
|
21 |
/**
|
22 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
23 |
*/
|
24 |
-
public function __construct( ICWP_WPSF_FeatureHandler_Sessions $
|
25 |
-
parent::__construct( $
|
26 |
}
|
27 |
|
28 |
public function run() {
|
29 |
-
if ( $this->
|
30 |
-
add_action( '
|
31 |
-
add_action( '
|
32 |
add_action( 'wp_loaded', array( $this, 'onWpLoaded' ), 0 );
|
33 |
add_filter( 'login_message', array( $this, 'printLinkToAdmin' ) );
|
34 |
}
|
35 |
}
|
36 |
|
37 |
/**
|
38 |
-
* @param string
|
39 |
-
* @param
|
|
|
|
|
40 |
*/
|
41 |
-
public function
|
42 |
-
$this->
|
|
|
|
|
|
|
|
|
43 |
}
|
44 |
|
45 |
/**
|
|
|
|
|
|
|
|
|
46 |
*/
|
47 |
-
public function
|
48 |
$this->terminateCurrentSession();
|
49 |
}
|
50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
/**
|
52 |
*/
|
53 |
public function onWpLoaded() {
|
@@ -68,6 +91,14 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
|
|
68 |
}
|
69 |
}
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
/**
|
72 |
* Only show Go To Admin link for Authors and above.
|
73 |
* @param string $sMessage
|
@@ -105,12 +136,17 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
|
|
105 |
return false;
|
106 |
}
|
107 |
|
|
|
|
|
|
|
|
|
108 |
// If they have a currently active session, terminate it (i.e. we replace it)
|
109 |
$oSession = $this->queryGetSession( $sUsername, $this->getSessionId() );
|
110 |
if ( !empty( $oSession ) ) {
|
111 |
$this->queryTerminateSession( $oSession );
|
112 |
}
|
113 |
$this->queryCreateSession( $sUsername, $this->getSessionId() );
|
|
|
114 |
return true;
|
115 |
}
|
116 |
|
@@ -242,10 +278,9 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
|
|
242 |
}
|
243 |
$this->doStatIncrement( 'user.session.terminate' );
|
244 |
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
->forUserSession( $oSession );
|
249 |
}
|
250 |
|
251 |
/**
|
@@ -267,6 +302,15 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
|
|
267 |
return $oRetrieve->setTable( $this->getTableName() );
|
268 |
}
|
269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
270 |
/**
|
271 |
* @return ICWP_WPSF_Query_Sessions_Update
|
272 |
*/
|
19 |
private $oCurrent;
|
20 |
|
21 |
/**
|
22 |
+
* @var int
|
23 |
+
*/
|
24 |
+
private $nSessionAlreadyCreatedUserId = 0;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @param ICWP_WPSF_Processor_Sessions $oModCon
|
28 |
*/
|
29 |
+
public function __construct( ICWP_WPSF_FeatureHandler_Sessions $oModCon ) {
|
30 |
+
parent::__construct( $oModCon, $oModCon->getSessionsTableName() );
|
31 |
}
|
32 |
|
33 |
public function run() {
|
34 |
+
if ( $this->isReadyToRun() ) {
|
35 |
+
add_action( 'set_logged_in_cookie', array( $this, 'onWpSetLoggedInCookie' ), 5, 4 ); //login
|
36 |
+
add_action( 'clear_auth_cookie', array( $this, 'onWpClearAuthCookie' ), 0 ); //logout
|
37 |
add_action( 'wp_loaded', array( $this, 'onWpLoaded' ), 0 );
|
38 |
add_filter( 'login_message', array( $this, 'printLinkToAdmin' ) );
|
39 |
}
|
40 |
}
|
41 |
|
42 |
/**
|
43 |
+
* @param string $sCookie
|
44 |
+
* @param int $nExpire
|
45 |
+
* @param int $nExpiration
|
46 |
+
* @param int $nUserId
|
47 |
*/
|
48 |
+
public function onWpSetLoggedInCookie( $sCookie, $nExpire, $nExpiration, $nUserId ) {
|
49 |
+
$oUser = $this->loadWpUsers()
|
50 |
+
->getUserById( $nUserId );
|
51 |
+
if ( $oUser instanceof WP_User && !$this->isSessionAlreadyCreatedForUser( $oUser ) ) {
|
52 |
+
$this->activateUserSession( $oUser->user_login, $oUser );
|
53 |
+
}
|
54 |
}
|
55 |
|
56 |
/**
|
57 |
+
* @param string $sCookie
|
58 |
+
* @param int $nExpire
|
59 |
+
* @param int $nExpiration
|
60 |
+
* @param int $nUserId
|
61 |
*/
|
62 |
+
public function onWpClearAuthCookie() {
|
63 |
$this->terminateCurrentSession();
|
64 |
}
|
65 |
|
66 |
+
/**
|
67 |
+
* @param string $sUsername
|
68 |
+
* @param WP_User $oUser
|
69 |
+
*/
|
70 |
+
public function onWpLogin( $sUsername, $oUser ) {
|
71 |
+
$this->activateUserSession( $sUsername, $oUser );
|
72 |
+
}
|
73 |
+
|
74 |
/**
|
75 |
*/
|
76 |
public function onWpLoaded() {
|
91 |
}
|
92 |
}
|
93 |
|
94 |
+
/**
|
95 |
+
* @param WP_User $oUser
|
96 |
+
* @return bool
|
97 |
+
*/
|
98 |
+
private function isSessionAlreadyCreatedForUser( $oUser ) {
|
99 |
+
return $this->nSessionAlreadyCreatedUserId > 0 && $this->nSessionAlreadyCreatedUserId == $oUser->ID;
|
100 |
+
}
|
101 |
+
|
102 |
/**
|
103 |
* Only show Go To Admin link for Authors and above.
|
104 |
* @param string $sMessage
|
136 |
return false;
|
137 |
}
|
138 |
|
139 |
+
if ( $this->isSessionAlreadyCreatedForUser( $oUser ) ) {
|
140 |
+
return true;
|
141 |
+
}
|
142 |
+
|
143 |
// If they have a currently active session, terminate it (i.e. we replace it)
|
144 |
$oSession = $this->queryGetSession( $sUsername, $this->getSessionId() );
|
145 |
if ( !empty( $oSession ) ) {
|
146 |
$this->queryTerminateSession( $oSession );
|
147 |
}
|
148 |
$this->queryCreateSession( $sUsername, $this->getSessionId() );
|
149 |
+
$this->nSessionAlreadyCreatedUserId = $oUser->ID;
|
150 |
return true;
|
151 |
}
|
152 |
|
278 |
}
|
279 |
$this->doStatIncrement( 'user.session.terminate' );
|
280 |
|
281 |
+
return $this->getSessionTerminator()
|
282 |
+
->setTable( $this->getTableName() )
|
283 |
+
->forUserSession( $oSession );
|
|
|
284 |
}
|
285 |
|
286 |
/**
|
302 |
return $oRetrieve->setTable( $this->getTableName() );
|
303 |
}
|
304 |
|
305 |
+
/**
|
306 |
+
* @return ICWP_WPSF_Query_Sessions_Terminate
|
307 |
+
*/
|
308 |
+
public function getSessionTerminator() {
|
309 |
+
require_once( $this->getQueryDir().'sessions_terminate.php' );
|
310 |
+
$oRetrieve = new ICWP_WPSF_Query_Sessions_Terminate();
|
311 |
+
return $oRetrieve->setTable( $this->getTableName() );
|
312 |
+
}
|
313 |
+
|
314 |
/**
|
315 |
* @return ICWP_WPSF_Query_Sessions_Update
|
316 |
*/
|
src/processors/statistics.php
CHANGED
@@ -14,21 +14,21 @@ class ICWP_WPSF_Processor_Statistics extends ICWP_WPSF_BaseDbProcessor {
|
|
14 |
private $oReportingProcessor;
|
15 |
|
16 |
/**
|
17 |
-
* @param ICWP_WPSF_FeatureHandler_Statistics $
|
18 |
*/
|
19 |
-
public function __construct( ICWP_WPSF_FeatureHandler_Statistics $
|
20 |
-
parent::__construct( $
|
21 |
}
|
22 |
|
23 |
public function run() {
|
24 |
/** @var ICWP_WPSF_FeatureHandler_Statistics $oFO */
|
25 |
$oFO = $this->getFeature();
|
26 |
-
if ( $this->
|
27 |
add_filter( $oFO->prefix( 'dashboard_widget_content' ), array( $this, 'gatherStatsSummaryWidgetContent' ), 10 );
|
28 |
}
|
29 |
|
30 |
// Reporting stats run or destroy
|
31 |
-
if ( $this->
|
32 |
$this->getReportingProcessor()
|
33 |
->run();
|
34 |
}
|
@@ -220,7 +220,7 @@ class ICWP_WPSF_Processor_Statistics extends ICWP_WPSF_BaseDbProcessor {
|
|
220 |
);
|
221 |
|
222 |
$aDisplayData = array(
|
223 |
-
'sHeading' => _wpsf__( '
|
224 |
'aAllStats' => $aAllStats,
|
225 |
'aKeyStats' => $aKeyStats,
|
226 |
);
|
@@ -325,8 +325,8 @@ class ICWP_WPSF_Processor_Statistics extends ICWP_WPSF_BaseDbProcessor {
|
|
325 |
return $this->query_selectAll( array( 'stat_key', 'tally' ) );
|
326 |
}
|
327 |
|
328 |
-
public function
|
329 |
-
parent::
|
330 |
if ( !$this->getFeature()->isPluginDeleting() ) {
|
331 |
$this->commit();
|
332 |
}
|
@@ -336,7 +336,7 @@ class ICWP_WPSF_Processor_Statistics extends ICWP_WPSF_BaseDbProcessor {
|
|
336 |
* @return array
|
337 |
*/
|
338 |
protected function getTableColumnsByDefinition() {
|
339 |
-
$aDef = $this->getFeature()->
|
340 |
return ( is_array( $aDef ) ? $aDef : array() );
|
341 |
}
|
342 |
|
14 |
private $oReportingProcessor;
|
15 |
|
16 |
/**
|
17 |
+
* @param ICWP_WPSF_FeatureHandler_Statistics $oModCon
|
18 |
*/
|
19 |
+
public function __construct( ICWP_WPSF_FeatureHandler_Statistics $oModCon ) {
|
20 |
+
parent::__construct( $oModCon, $oModCon->getStatisticsTableName() );
|
21 |
}
|
22 |
|
23 |
public function run() {
|
24 |
/** @var ICWP_WPSF_FeatureHandler_Statistics $oFO */
|
25 |
$oFO = $this->getFeature();
|
26 |
+
if ( $this->isReadyToRun() ) {
|
27 |
add_filter( $oFO->prefix( 'dashboard_widget_content' ), array( $this, 'gatherStatsSummaryWidgetContent' ), 10 );
|
28 |
}
|
29 |
|
30 |
// Reporting stats run or destroy
|
31 |
+
if ( $this->loadDP()->getPhpVersionIsAtLeast( '5.3.0' ) ) {
|
32 |
$this->getReportingProcessor()
|
33 |
->run();
|
34 |
}
|
220 |
);
|
221 |
|
222 |
$aDisplayData = array(
|
223 |
+
'sHeading' => sprintf( _wpsf__( '%s Statistics' ), $this->getController()->getHumanName() ),
|
224 |
'aAllStats' => $aAllStats,
|
225 |
'aKeyStats' => $aKeyStats,
|
226 |
);
|
325 |
return $this->query_selectAll( array( 'stat_key', 'tally' ) );
|
326 |
}
|
327 |
|
328 |
+
public function onModuleShutdown() {
|
329 |
+
parent::onModuleShutdown();
|
330 |
if ( !$this->getFeature()->isPluginDeleting() ) {
|
331 |
$this->commit();
|
332 |
}
|
336 |
* @return array
|
337 |
*/
|
338 |
protected function getTableColumnsByDefinition() {
|
339 |
+
$aDef = $this->getFeature()->getDef( 'statistics_table_columns' );
|
340 |
return ( is_array( $aDef ) ? $aDef : array() );
|
341 |
}
|
342 |
|
src/processors/statistics_reporting.php
CHANGED
@@ -14,10 +14,10 @@ class ICWP_WPSF_Processor_Statistics_Reporting extends ICWP_WPSF_BaseDbProcessor
|
|
14 |
private $oConsolidation;
|
15 |
|
16 |
/**
|
17 |
-
* @param ICWP_WPSF_FeatureHandler_Statistics $
|
18 |
*/
|
19 |
-
public function __construct( ICWP_WPSF_FeatureHandler_Statistics $
|
20 |
-
parent::__construct( $
|
21 |
}
|
22 |
|
23 |
public function run() {
|
@@ -71,8 +71,8 @@ class ICWP_WPSF_Processor_Statistics_Reporting extends ICWP_WPSF_BaseDbProcessor
|
|
71 |
return (bool)$mResult;
|
72 |
}
|
73 |
|
74 |
-
public function
|
75 |
-
parent::
|
76 |
if ( !$this->getFeature()->isPluginDeleting() ) {
|
77 |
$this->commit();
|
78 |
}
|
14 |
private $oConsolidation;
|
15 |
|
16 |
/**
|
17 |
+
* @param ICWP_WPSF_FeatureHandler_Statistics $oModCon
|
18 |
*/
|
19 |
+
public function __construct( ICWP_WPSF_FeatureHandler_Statistics $oModCon ) {
|
20 |
+
parent::__construct( $oModCon, $oModCon->getReportingTableName() );
|
21 |
}
|
22 |
|
23 |
public function run() {
|
71 |
return (bool)$mResult;
|
72 |
}
|
73 |
|
74 |
+
public function onModuleShutdown() {
|
75 |
+
parent::onModuleShutdown();
|
76 |
if ( !$this->getFeature()->isPluginDeleting() ) {
|
77 |
$this->commit();
|
78 |
}
|
src/processors/user_management.php
CHANGED
@@ -61,15 +61,35 @@ class ICWP_WPSF_Processor_UserManagement extends ICWP_WPSF_Processor_BaseWpsf {
|
|
61 |
$oUser = $this->loadWpUsers()->getUserByUsername( $sUsername );
|
62 |
if ( $oUser instanceof WP_User ) {
|
63 |
|
64 |
-
$this->setPasswordStartedAt( $oUser )
|
|
|
|
|
|
|
|
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
}
|
|
|
|
|
|
|
|
|
73 |
}
|
74 |
|
75 |
/**
|
@@ -139,10 +159,12 @@ class ICWP_WPSF_Processor_UserManagement extends ICWP_WPSF_Processor_BaseWpsf {
|
|
139 |
* @param WP_User $oUser
|
140 |
* @return bool
|
141 |
*/
|
142 |
-
|
143 |
if ( !( $oUser instanceof WP_User ) ) {
|
144 |
return false;
|
145 |
}
|
|
|
|
|
146 |
|
147 |
$aUserCapToRolesMap = array(
|
148 |
'network_admin' => 'manage_network',
|
@@ -195,13 +217,43 @@ class ICWP_WPSF_Processor_UserManagement extends ICWP_WPSF_Processor_BaseWpsf {
|
|
195 |
return $this
|
196 |
->getFeature()
|
197 |
->getEmailProcessor()
|
198 |
-
->
|
199 |
-
$
|
200 |
sprintf( _wpsf__( 'Notice - %s' ), sprintf( _wpsf__( '%s Just Logged Into %s' ), $sHumanName, $sHomeUrl ) ),
|
201 |
$aMessage
|
202 |
);
|
203 |
}
|
204 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
/**
|
206 |
* @return ICWP_WPSF_Processor_UserManagement_Passwords
|
207 |
*/
|
@@ -218,7 +270,7 @@ class ICWP_WPSF_Processor_UserManagement extends ICWP_WPSF_Processor_BaseWpsf {
|
|
218 |
/**
|
219 |
* @return ICWP_WPSF_Processor_UserManagement_Sessions
|
220 |
*/
|
221 |
-
|
222 |
if ( !isset( $this->oProcessorSessions ) ) {
|
223 |
require_once( dirname( __FILE__ ).'/usermanagement_sessions.php' );
|
224 |
/** @var ICWP_WPSF_FeatureHandler_UserManagement $oFO */
|
@@ -228,14 +280,6 @@ class ICWP_WPSF_Processor_UserManagement extends ICWP_WPSF_Processor_BaseWpsf {
|
|
228 |
return $this->oProcessorSessions;
|
229 |
}
|
230 |
|
231 |
-
/**
|
232 |
-
* @param string $sWpUsername
|
233 |
-
* @return array|bool
|
234 |
-
*/
|
235 |
-
public function getActiveUserSessionRecords( $sWpUsername = '' ) {
|
236 |
-
return $this->getProcessorSessions()->getActiveSessionRecordsForUsername( $sWpUsername );
|
237 |
-
}
|
238 |
-
|
239 |
/**
|
240 |
* @return string
|
241 |
*/
|
61 |
$oUser = $this->loadWpUsers()->getUserByUsername( $sUsername );
|
62 |
if ( $oUser instanceof WP_User ) {
|
63 |
|
64 |
+
$this->setPasswordStartedAt( $oUser )// used by Password Policies
|
65 |
+
->setUserLastLoginTime( $oUser )
|
66 |
+
->sendLoginNotifications( $oUser );
|
67 |
+
}
|
68 |
+
}
|
69 |
|
70 |
+
/**
|
71 |
+
* @param WP_User $oUser - not checking that user is valid
|
72 |
+
* @return $this
|
73 |
+
*/
|
74 |
+
private function sendLoginNotifications( $oUser ) {
|
75 |
+
/** @var ICWP_WPSF_FeatureHandler_UserManagement $oFO */
|
76 |
+
$oFO = $this->getFeature();
|
77 |
+
$bAdmin = $oFO->isSendAdminEmailLoginNotification();
|
78 |
+
$bUser = $oFO->isSendUserEmailLoginNotification();
|
79 |
+
|
80 |
+
// do some magic logic so we don't send both to the same person (the assumption being that the admin
|
81 |
+
// email recipient is actually an admin (or they'll maybe not get any).
|
82 |
+
if ( $bAdmin && $bUser && ( $oFO->getAdminLoginNotificationEmail() === $oUser->user_email ) ) {
|
83 |
+
$bUser = false;
|
84 |
+
}
|
85 |
+
|
86 |
+
if ( $bAdmin ) {
|
87 |
+
$this->sendAdminLoginEmailNotification( $oUser );
|
88 |
}
|
89 |
+
if ( $bUser && !$this->isUserSubjectToLoginIntent( $oUser ) ) {
|
90 |
+
$this->sendUserLoginEmailNotification( $oUser );
|
91 |
+
}
|
92 |
+
return $this;
|
93 |
}
|
94 |
|
95 |
/**
|
159 |
* @param WP_User $oUser
|
160 |
* @return bool
|
161 |
*/
|
162 |
+
private function sendAdminLoginEmailNotification( $oUser ) {
|
163 |
if ( !( $oUser instanceof WP_User ) ) {
|
164 |
return false;
|
165 |
}
|
166 |
+
/** @var ICWP_WPSF_FeatureHandler_UserManagement $oFO */
|
167 |
+
$oFO = $this->getFeature();
|
168 |
|
169 |
$aUserCapToRolesMap = array(
|
170 |
'network_admin' => 'manage_network',
|
217 |
return $this
|
218 |
->getFeature()
|
219 |
->getEmailProcessor()
|
220 |
+
->sendEmailWithWrap(
|
221 |
+
$oFO->getAdminLoginNotificationEmail(),
|
222 |
sprintf( _wpsf__( 'Notice - %s' ), sprintf( _wpsf__( '%s Just Logged Into %s' ), $sHumanName, $sHomeUrl ) ),
|
223 |
$aMessage
|
224 |
);
|
225 |
}
|
226 |
|
227 |
+
/**
|
228 |
+
* @param WP_User $oUser
|
229 |
+
* @return bool
|
230 |
+
*/
|
231 |
+
private function sendUserLoginEmailNotification( $oUser ) {
|
232 |
+
$aMessage = array(
|
233 |
+
sprintf( _wpsf__( '%s is notifying you of a successful login to your WordPress account.' ), $this->getController()
|
234 |
+
->getHumanName() ),
|
235 |
+
'',
|
236 |
+
_wpsf__( 'Details for this login are below:' ),
|
237 |
+
'- '.sprintf( _wpsf__( 'Site URL: %s' ), $this->loadWp()->getHomeUrl() ),
|
238 |
+
'- '.sprintf( _wpsf__( 'Username: %s' ), $oUser->get( 'user_login' ) ),
|
239 |
+
'- '.sprintf( _wpsf__( 'IP Address: %s' ), $this->ip() ),
|
240 |
+
'- '.sprintf( _wpsf__( 'Login Time: %s' ), $this->loadWp()->getTimeStampForDisplay() ),
|
241 |
+
'',
|
242 |
+
_wpsf__( 'If this is unexpected or suspicious, please contact your site administrator immediately.' ),
|
243 |
+
'',
|
244 |
+
_wpsf__( 'Thanks.' )
|
245 |
+
);
|
246 |
+
|
247 |
+
return $this
|
248 |
+
->getFeature()
|
249 |
+
->getEmailProcessor()
|
250 |
+
->sendEmailWithWrap(
|
251 |
+
$oUser->user_email,
|
252 |
+
sprintf( _wpsf__( 'Notice - %s' ), _wpsf__( 'A login to your WordPress account just occurred' ) ),
|
253 |
+
$aMessage
|
254 |
+
);
|
255 |
+
}
|
256 |
+
|
257 |
/**
|
258 |
* @return ICWP_WPSF_Processor_UserManagement_Passwords
|
259 |
*/
|
270 |
/**
|
271 |
* @return ICWP_WPSF_Processor_UserManagement_Sessions
|
272 |
*/
|
273 |
+
public function getProcessorSessions() {
|
274 |
if ( !isset( $this->oProcessorSessions ) ) {
|
275 |
require_once( dirname( __FILE__ ).'/usermanagement_sessions.php' );
|
276 |
/** @var ICWP_WPSF_FeatureHandler_UserManagement $oFO */
|
280 |
return $this->oProcessorSessions;
|
281 |
}
|
282 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
283 |
/**
|
284 |
* @return string
|
285 |
*/
|
src/processors/usermanagement_sessions.php
CHANGED
@@ -4,15 +4,43 @@ if ( class_exists( 'ICWP_WPSF_Processor_UserManagement_Sessions', false ) ) {
|
|
4 |
return;
|
5 |
}
|
6 |
|
7 |
-
require_once( dirname( __FILE__ ).'/
|
8 |
|
9 |
-
class ICWP_WPSF_Processor_UserManagement_Sessions extends
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
public function run() {
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
}
|
17 |
|
18 |
/**
|
@@ -85,6 +113,30 @@ class ICWP_WPSF_Processor_UserManagement_Sessions extends ICWP_WPSF_Processor_Ba
|
|
85 |
}
|
86 |
}
|
87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
/**
|
89 |
* @return int
|
90 |
*/
|
@@ -98,16 +150,14 @@ class ICWP_WPSF_Processor_UserManagement_Sessions extends ICWP_WPSF_Processor_Ba
|
|
98 |
else {
|
99 |
$oSess = $oFO->getSession();
|
100 |
$nTime = $this->time();
|
101 |
-
$nTimeout = $this->getSessionTimeoutInterval();
|
102 |
-
$nIdleTimeout = $this->getSessionIdleTimeoutInterval();
|
103 |
|
104 |
$nForceLogOutCode = 0; // when it's == 0 it's a valid session
|
105 |
|
106 |
// timeout interval
|
107 |
-
if ( $
|
108 |
$nForceLogOutCode = 1;
|
109 |
} // idle timeout interval
|
110 |
-
else if ( $
|
111 |
$oFO->setOptInsightsAt( 'last_idle_logout_at' );
|
112 |
$nForceLogOutCode = 2;
|
113 |
} // login ip address lock
|
@@ -124,22 +174,9 @@ class ICWP_WPSF_Processor_UserManagement_Sessions extends ICWP_WPSF_Processor_Ba
|
|
124 |
* @return integer
|
125 |
*/
|
126 |
public function setTimeoutCookieExpiration_Filter( $nTimeout ) {
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
/**
|
132 |
-
* @return integer
|
133 |
-
*/
|
134 |
-
protected function getSessionTimeoutInterval() {
|
135 |
-
return $this->getOption( 'session_timeout_interval' )*DAY_IN_SECONDS;
|
136 |
-
}
|
137 |
-
|
138 |
-
/**
|
139 |
-
* @return integer
|
140 |
-
*/
|
141 |
-
protected function getSessionIdleTimeoutInterval() {
|
142 |
-
return $this->getOption( 'session_idle_timeout_interval' )*HOUR_IN_SECONDS;
|
143 |
}
|
144 |
|
145 |
/**
|
4 |
return;
|
5 |
}
|
6 |
|
7 |
+
require_once( dirname( __FILE__ ).'/cronbase.php' );
|
8 |
|
9 |
+
class ICWP_WPSF_Processor_UserManagement_Sessions extends ICWP_WPSF_Processor_CronBase {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @return callable
|
13 |
+
*/
|
14 |
+
protected function getCronCallback() {
|
15 |
+
return array( $this, 'cron_runSessionsCleanup' );
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @return string
|
20 |
+
*/
|
21 |
+
protected function getCronName() {
|
22 |
+
/** @var ICWP_WPSF_FeatureHandler_UserManagement $oFO */
|
23 |
+
$oFO = $this->getFeature();
|
24 |
+
return $oFO->prefix( $oFO->getDef( 'cron_name_sessionscleanup' ) );
|
25 |
+
}
|
26 |
|
27 |
public function run() {
|
28 |
+
if ( $this->isReadyToRun() ) {
|
29 |
+
parent::run();
|
30 |
+
add_filter( 'wp_login_errors', array( $this, 'addLoginMessage' ) );
|
31 |
+
add_filter( 'auth_cookie_expiration', array( $this, 'setTimeoutCookieExpiration_Filter' ), 100, 1 );
|
32 |
+
add_action( 'wp_loaded', array( $this, 'onWpLoaded' ), 1 ); // Check the current every page load.
|
33 |
+
add_action( 'wp_login', array( $this, 'onWpLogin' ), 10, 1 );
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @return bool
|
39 |
+
*/
|
40 |
+
public function isReadyToRun() {
|
41 |
+
/** @var ICWP_WPSF_FeatureHandler_UserManagement $oFO */
|
42 |
+
$oFO = $this->getFeature();
|
43 |
+
return ( parent::isReadyToRun() && $oFO->getSessionsProcessor()->isReadyToRun() );
|
44 |
}
|
45 |
|
46 |
/**
|
113 |
}
|
114 |
}
|
115 |
|
116 |
+
public function cleanExpiredSessions() {
|
117 |
+
/** @var ICWP_WPSF_FeatureHandler_UserManagement $oFO */
|
118 |
+
$oFO = $this->getFeature();
|
119 |
+
$oTerminator = $oFO->getSessionsProcessor()
|
120 |
+
->getSessionTerminator();
|
121 |
+
|
122 |
+
$nNow = $this->time();
|
123 |
+
// We use 14 as an outside case. If it's 2 days, WP cookie will expire anyway.
|
124 |
+
// And if User Management is active, then it'll draw in that value.
|
125 |
+
$oTerminator->forExpiredLoginAt( $nNow - apply_filters( 'auth_cookie_expiration', 14*DAY_IN_SECONDS ) );
|
126 |
+
|
127 |
+
// Default is ZERO, so we don't want to terminate all sessions if it's never set.
|
128 |
+
if ( $oFO->hasSessionIdleTimeout() ) {
|
129 |
+
$oTerminator->forExpiredLoginIdle( $nNow - $oFO->getSessionIdleTimeoutInterval() );
|
130 |
+
}
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* A cron that will automatically cleanout expired/idle sessions.
|
135 |
+
*/
|
136 |
+
public function cron_runSessionsCleanup() {
|
137 |
+
$this->cleanExpiredSessions();
|
138 |
+
}
|
139 |
+
|
140 |
/**
|
141 |
* @return int
|
142 |
*/
|
150 |
else {
|
151 |
$oSess = $oFO->getSession();
|
152 |
$nTime = $this->time();
|
|
|
|
|
153 |
|
154 |
$nForceLogOutCode = 0; // when it's == 0 it's a valid session
|
155 |
|
156 |
// timeout interval
|
157 |
+
if ( $oFO->hasSessionTimeoutInterval() && ( $nTime - $oSess->getLoggedInAt() > $oFO->getSessionTimeoutInterval() ) ) {
|
158 |
$nForceLogOutCode = 1;
|
159 |
} // idle timeout interval
|
160 |
+
else if ( $oFO->hasSessionIdleTimeout() && ( $nTime - $oSess->getLastActivityAt() > $oFO->getSessionIdleTimeoutInterval() ) ) {
|
161 |
$oFO->setOptInsightsAt( 'last_idle_logout_at' );
|
162 |
$nForceLogOutCode = 2;
|
163 |
} // login ip address lock
|
174 |
* @return integer
|
175 |
*/
|
176 |
public function setTimeoutCookieExpiration_Filter( $nTimeout ) {
|
177 |
+
/** @var ICWP_WPSF_FeatureHandler_UserManagement $oFO */
|
178 |
+
$oFO = $this->getFeature();
|
179 |
+
return $oFO->hasSessionTimeoutInterval() ? $oFO->getSessionTimeoutInterval() : $nTimeout;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
}
|
181 |
|
182 |
/**
|
src/query/sessions_terminate.php
CHANGED
@@ -24,6 +24,46 @@ class ICWP_WPSF_Query_Sessions_Terminate extends ICWP_WPSF_Query_Base {
|
|
24 |
return $this->query_terminateForUser( $oSession->getUsername(), $oSession->getId() );
|
25 |
}
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
/**
|
28 |
* @param string $sWpUsername
|
29 |
* @param string $sSessionId
|
24 |
return $this->query_terminateForUser( $oSession->getUsername(), $oSession->getId() );
|
25 |
}
|
26 |
|
27 |
+
/**
|
28 |
+
* @param int $bOlderThan
|
29 |
+
* @return bool
|
30 |
+
*/
|
31 |
+
public function forExpiredLoginAt( $bOlderThan ) {
|
32 |
+
return $this->query_terminateExpired( $bOlderThan, 'logged_in_at' );
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @param int $bOlderThan
|
37 |
+
* @return bool
|
38 |
+
*/
|
39 |
+
public function forExpiredLoginIdle( $bOlderThan ) {
|
40 |
+
return $this->query_terminateExpired( $bOlderThan, 'last_activity_at' );
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @param int $nOlderThan
|
45 |
+
* @param string $sColumn
|
46 |
+
* @return bool
|
47 |
+
*/
|
48 |
+
protected function query_terminateExpired( $nOlderThan, $sColumn = 'logged_in_at' ) {
|
49 |
+
|
50 |
+
$sQuery = "
|
51 |
+
DELETE FROM `%s`
|
52 |
+
WHERE `%s` < %s
|
53 |
+
";
|
54 |
+
$sQuery = sprintf(
|
55 |
+
$sQuery,
|
56 |
+
$this->getTable(),
|
57 |
+
esc_sql( $sColumn ),
|
58 |
+
(int)$nOlderThan
|
59 |
+
);
|
60 |
+
|
61 |
+
$nCount = $this->loadDbProcessor()
|
62 |
+
->doSql( $sQuery );
|
63 |
+
|
64 |
+
return is_numeric( $nCount );
|
65 |
+
}
|
66 |
+
|
67 |
/**
|
68 |
* @param string $sWpUsername
|
69 |
* @param string $sSessionId
|
src/query/statistics_base.php
CHANGED
@@ -143,7 +143,7 @@ class ICWP_WPSF_Query_Statistics_Base extends ICWP_WPSF_Query_Base {
|
|
143 |
* @return int
|
144 |
*/
|
145 |
public function getDateTo() {
|
146 |
-
return isset( $this->nDateTo ) ? (int)$this->nDateTo : $this->
|
147 |
}
|
148 |
|
149 |
/**
|
143 |
* @return int
|
144 |
*/
|
145 |
public function getDateTo() {
|
146 |
+
return isset( $this->nDateTo ) ? (int)$this->nDateTo : $this->loadDP()->time();
|
147 |
}
|
148 |
|
149 |
/**
|
src/wizards/base.php
CHANGED
@@ -288,7 +288,7 @@ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
|
|
288 |
),
|
289 |
'hrefs' => array(
|
290 |
'dashboard' => $oFO->getUrl_AdminPage(),
|
291 |
-
'goprofooter' => '
|
292 |
),
|
293 |
'ajax' => array(
|
294 |
'content' => $oFO->getAjaxActionData( 'wiz_process_step' ),
|
@@ -307,7 +307,8 @@ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
|
|
307 |
$oCon = $this->getModCon()->getConn();
|
308 |
return array(
|
309 |
'strings' => array(
|
310 |
-
'page_title'
|
|
|
311 |
),
|
312 |
'data' => array(),
|
313 |
'hrefs' => array(
|
@@ -338,13 +339,15 @@ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
|
|
338 |
* @return array
|
339 |
*/
|
340 |
protected function getRenderData_PageWizard() {
|
|
|
341 |
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
342 |
$oFO = $this->getModCon();
|
343 |
return $this->loadDP()->mergeArraysRecursive(
|
344 |
$this->getRenderData_TwigPageBase(),
|
345 |
array(
|
346 |
'strings' => array(
|
347 |
-
'page_title'
|
|
|
348 |
),
|
349 |
'data' => array(
|
350 |
'wizard_slug' => $this->getWizardSlug(),
|
@@ -353,7 +356,7 @@ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
|
|
353 |
),
|
354 |
'hrefs' => array(
|
355 |
'dashboard' => $oFO->getUrl_AdminPage(),
|
356 |
-
'goprofooter' => '
|
357 |
),
|
358 |
'ajax' => array(
|
359 |
'content' => $oFO->getAjaxActionData( 'wiz_process_step' ),
|
@@ -440,18 +443,22 @@ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
|
|
440 |
*/
|
441 |
protected function getRenderData_SlideBase() {
|
442 |
$oFO = $this->getModCon();
|
|
|
443 |
$aWizards = $this->getModuleWizardsForRender();
|
444 |
return array(
|
445 |
-
'
|
|
|
|
|
|
|
446 |
'is_premium' => $oFO->isPremium(),
|
447 |
'has_other_wizards' => false
|
448 |
),
|
449 |
-
'hrefs'
|
450 |
'dashboard' => $oFO->getUrl_AdminPage(),
|
451 |
-
'gopro' => '
|
452 |
),
|
453 |
-
'imgs'
|
454 |
-
'data'
|
455 |
'mod_wizards_count' => count( $aWizards ),
|
456 |
'mod_wizards' => $aWizards
|
457 |
),
|
288 |
),
|
289 |
'hrefs' => array(
|
290 |
'dashboard' => $oFO->getUrl_AdminPage(),
|
291 |
+
'goprofooter' => 'https://icwp.io/goprofooter',
|
292 |
),
|
293 |
'ajax' => array(
|
294 |
'content' => $oFO->getAjaxActionData( 'wiz_process_step' ),
|
307 |
$oCon = $this->getModCon()->getConn();
|
308 |
return array(
|
309 |
'strings' => array(
|
310 |
+
'page_title' => 'Twig Page',
|
311 |
+
'plugin_name' => $oCon->getHumanName()
|
312 |
),
|
313 |
'data' => array(),
|
314 |
'hrefs' => array(
|
339 |
* @return array
|
340 |
*/
|
341 |
protected function getRenderData_PageWizard() {
|
342 |
+
$oCon = $this->getModCon()->getConn();
|
343 |
/** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
|
344 |
$oFO = $this->getModCon();
|
345 |
return $this->loadDP()->mergeArraysRecursive(
|
346 |
$this->getRenderData_TwigPageBase(),
|
347 |
array(
|
348 |
'strings' => array(
|
349 |
+
'page_title' => $this->getPageTitle(),
|
350 |
+
'plugin_name' => $oCon->getHumanName()
|
351 |
),
|
352 |
'data' => array(
|
353 |
'wizard_slug' => $this->getWizardSlug(),
|
356 |
),
|
357 |
'hrefs' => array(
|
358 |
'dashboard' => $oFO->getUrl_AdminPage(),
|
359 |
+
'goprofooter' => 'https://icwp.io/goprofooter',
|
360 |
),
|
361 |
'ajax' => array(
|
362 |
'content' => $oFO->getAjaxActionData( 'wiz_process_step' ),
|
443 |
*/
|
444 |
protected function getRenderData_SlideBase() {
|
445 |
$oFO = $this->getModCon();
|
446 |
+
$oCon = $this->getModCon()->getConn();
|
447 |
$aWizards = $this->getModuleWizardsForRender();
|
448 |
return array(
|
449 |
+
'strings' => array(
|
450 |
+
'plugin_name' => $oCon->getHumanName()
|
451 |
+
),
|
452 |
+
'flags' => array(
|
453 |
'is_premium' => $oFO->isPremium(),
|
454 |
'has_other_wizards' => false
|
455 |
),
|
456 |
+
'hrefs' => array(
|
457 |
'dashboard' => $oFO->getUrl_AdminPage(),
|
458 |
+
'gopro' => 'https://icwp.io/ap',
|
459 |
),
|
460 |
+
'imgs' => array(),
|
461 |
+
'data' => array(
|
462 |
'mod_wizards_count' => count( $aWizards ),
|
463 |
'mod_wizards' => $aWizards
|
464 |
),
|
src/wizards/plugin.php
CHANGED
@@ -197,7 +197,7 @@ class ICWP_WPSF_Wizard_Plugin extends ICWP_WPSF_Wizard_BaseWpsf {
|
|
197 |
case 'ip_detect':
|
198 |
$aAdditional = array(
|
199 |
'hrefs' => array(
|
200 |
-
'visitor_ip' => '
|
201 |
)
|
202 |
);
|
203 |
break;
|
@@ -206,7 +206,7 @@ class ICWP_WPSF_Wizard_Plugin extends ICWP_WPSF_Wizard_BaseWpsf {
|
|
206 |
case 'import':
|
207 |
$aAdditional = array(
|
208 |
'hrefs' => array(
|
209 |
-
'blog_importexport' => '
|
210 |
),
|
211 |
'imgs' => array(
|
212 |
'shieldnetworkmini' => $oConn->getPluginUrl_Image( 'shield/shieldnetworkmini.png' ),
|
@@ -281,7 +281,7 @@ class ICWP_WPSF_Wizard_Plugin extends ICWP_WPSF_Wizard_BaseWpsf {
|
|
281 |
case 'import':
|
282 |
$aAdditional = array(
|
283 |
'hrefs' => array(
|
284 |
-
'blog_importexport' => '
|
285 |
),
|
286 |
'imgs' => array(
|
287 |
'shieldnetworkmini' => $oConn->getPluginUrl_Image( 'shield/shieldnetworkmini.png' ),
|
197 |
case 'ip_detect':
|
198 |
$aAdditional = array(
|
199 |
'hrefs' => array(
|
200 |
+
'visitor_ip' => 'https://icwp.io/visitorip',
|
201 |
)
|
202 |
);
|
203 |
break;
|
206 |
case 'import':
|
207 |
$aAdditional = array(
|
208 |
'hrefs' => array(
|
209 |
+
'blog_importexport' => 'https://icwp.io/av'
|
210 |
),
|
211 |
'imgs' => array(
|
212 |
'shieldnetworkmini' => $oConn->getPluginUrl_Image( 'shield/shieldnetworkmini.png' ),
|
281 |
case 'import':
|
282 |
$aAdditional = array(
|
283 |
'hrefs' => array(
|
284 |
+
'blog_importexport' => 'https://icwp.io/av'
|
285 |
),
|
286 |
'imgs' => array(
|
287 |
'shieldnetworkmini' => $oConn->getPluginUrl_Image( 'shield/shieldnetworkmini.png' ),
|
templates/html/plugin_badge.html
CHANGED
@@ -82,7 +82,7 @@
|
|
82 |
</style>
|
83 |
<div id="icwpWpsfSiteBadge">
|
84 |
<a id="icwpWpsfCloseButton" onclick="getElementById('icwpWpsfSiteBadge').remove();">x</a>
|
85 |
-
<a href="
|
86 |
<img src="%s" alt="%s Logo" />
|
87 |
<div class="badge-text">%s</div>
|
88 |
</a>
|
82 |
</style>
|
83 |
<div id="icwpWpsfSiteBadge">
|
84 |
<a id="icwpWpsfCloseButton" onclick="getElementById('icwpWpsfSiteBadge').remove();">x</a>
|
85 |
+
<a href="https://icwp.io/wpsecurityfirewall" target="_blank" title="This site is protected by the Shield Security plugin.">
|
86 |
<img src="%s" alt="%s Logo" />
|
87 |
<div class="badge-text">%s</div>
|
88 |
</a>
|
templates/php/index.php
CHANGED
@@ -2,10 +2,10 @@
|
|
2 |
$sBaseDirName = dirname( __FILE__ ).DIRECTORY_SEPARATOR;
|
3 |
|
4 |
if ( $flags[ 'wrap_page_content' ] ) : ?>
|
5 |
-
<div class="wrap">
|
6 |
<div class="bootstrap-wpadmin1 icwp-options-page <?php echo $data[ 'mod_slug' ]; ?>">
|
7 |
<h1 style="height: 0; display: none"></h1>
|
8 |
-
<?php endif
|
9 |
|
10 |
<?php if ( $flags[ 'access_restricted' ] ) : ?>
|
11 |
<?php include( $sBaseDirName.'access_restricted.php' ); ?>
|
@@ -16,7 +16,7 @@ if ( $flags[ 'wrap_page_content' ] ) : ?>
|
|
16 |
<?php if ( $flags[ 'wrap_page_content' ] ) : ?>
|
17 |
</div><!-- / bootstrap-wpadmin -->
|
18 |
</div><!-- / wrap -->
|
19 |
-
<?php endif
|
20 |
|
21 |
<?php include_once( $sBaseDirName.'index_footer.php' ); ?>
|
22 |
|
@@ -24,3 +24,13 @@ if ( $flags[ 'wrap_page_content' ] ) : ?>
|
|
24 |
if ( $help_video[ 'show' ] ) {
|
25 |
include_once( $sBaseDirName.'snippets/help_video_player.php' );
|
26 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
$sBaseDirName = dirname( __FILE__ ).DIRECTORY_SEPARATOR;
|
3 |
|
4 |
if ( $flags[ 'wrap_page_content' ] ) : ?>
|
5 |
+
<div class="wrap">
|
6 |
<div class="bootstrap-wpadmin1 icwp-options-page <?php echo $data[ 'mod_slug' ]; ?>">
|
7 |
<h1 style="height: 0; display: none"></h1>
|
8 |
+
<?php endif; ?>
|
9 |
|
10 |
<?php if ( $flags[ 'access_restricted' ] ) : ?>
|
11 |
<?php include( $sBaseDirName.'access_restricted.php' ); ?>
|
16 |
<?php if ( $flags[ 'wrap_page_content' ] ) : ?>
|
17 |
</div><!-- / bootstrap-wpadmin -->
|
18 |
</div><!-- / wrap -->
|
19 |
+
<?php endif; ?>
|
20 |
|
21 |
<?php include_once( $sBaseDirName.'index_footer.php' ); ?>
|
22 |
|
24 |
if ( $help_video[ 'show' ] ) {
|
25 |
include_once( $sBaseDirName.'snippets/help_video_player.php' );
|
26 |
}
|
27 |
+
?>
|
28 |
+
|
29 |
+
<?php if ( !empty( $aPluginLabels[ 'icon_url_128x128' ] ) ) : ?>
|
30 |
+
<style>
|
31 |
+
#TopPluginIcon {
|
32 |
+
background-image: url( "<?php echo $aPluginLabels[ 'icon_url_128x128' ]; ?>" ) !important;
|
33 |
+
}
|
34 |
+
</style>
|
35 |
+
<?php endif;
|
36 |
+
|
templates/php/notices/rate-plugin.php
CHANGED
@@ -5,6 +5,6 @@
|
|
5 |
WordPress community.
|
6 |
<br/><span style="text-decoration: underline">We simply need your help help to reach others</span>...</p>
|
7 |
<p>
|
8 |
-
<a href="
|
9 |
Please, could you leave us a review on WordPress.org?</a>
|
10 |
</p>
|
5 |
WordPress community.
|
6 |
<br/><span style="text-decoration: underline">We simply need your help help to reach others</span>...</p>
|
7 |
<p>
|
8 |
+
<a href="https://icwp.io/wpsfreview" class="button button-primary" target="_blank">
|
9 |
Please, could you leave us a review on WordPress.org?</a>
|
10 |
</p>
|
templates/php/page/login_intent.php
CHANGED
@@ -157,14 +157,16 @@
|
|
157 |
</p>
|
158 |
</div>
|
159 |
</div>
|
160 |
-
|
161 |
-
<div class="
|
162 |
-
<
|
163 |
-
<
|
164 |
-
|
165 |
-
|
|
|
|
|
166 |
</div>
|
167 |
-
|
168 |
</div>
|
169 |
</div>
|
170 |
</div>
|
157 |
</p>
|
158 |
</div>
|
159 |
</div>
|
160 |
+
<?php if ( $flags['show_what_is_this'] ) : ?>
|
161 |
+
<div class="row">
|
162 |
+
<div class="col">
|
163 |
+
<p id="WhatIsThis" class="text-center">
|
164 |
+
<a href="<?php echo $hrefs[ 'what_is_this' ]; ?>" class="btn btn-link"
|
165 |
+
target="_blank"><?php echo $strings[ 'what_is_this' ]; ?></a>
|
166 |
+
</p>
|
167 |
+
</div>
|
168 |
</div>
|
169 |
+
<?php endif; ?>
|
170 |
</div>
|
171 |
</div>
|
172 |
</div>
|
templates/php/snippets/module-help-admin_access_restriction.php
CHANGED
@@ -32,11 +32,11 @@
|
|
32 |
do the 1st option - which is the recommended.
|
33 |
</p>
|
34 |
<ol>
|
35 |
-
<li>Follow the guide <a href="
|
36 |
turned off the Shield plugin you can go in and set the access key to whatever you like,
|
37 |
and then remove the 'forceoff' file.
|
38 |
</li>
|
39 |
-
<li>Follow the guide <a href="
|
40 |
your plugin to default settings.
|
41 |
</li>
|
42 |
</ol>
|
32 |
do the 1st option - which is the recommended.
|
33 |
</p>
|
34 |
<ol>
|
35 |
+
<li>Follow the guide <a href="https://icwp.io/am" target="_blank">set out here</a>. Once you've
|
36 |
turned off the Shield plugin you can go in and set the access key to whatever you like,
|
37 |
and then remove the 'forceoff' file.
|
38 |
</li>
|
39 |
+
<li>Follow the guide <a href="https://icwp.io/al" target="_blank">set out here</a> to reset
|
40 |
your plugin to default settings.
|
41 |
</li>
|
42 |
</ol>
|
templates/php/snippets/module-help-firewall.php
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<h5>What is the Firewall?</h5>
|
2 |
<p>This is a big topic and is best covered in-detail in our helpdesk section.</p>
|
3 |
-
<p><a href="
|
4 |
https://icontrolwp.freshdesk.com/support/solutions/folders/3000000263</a> .
|
5 |
</p>
|
1 |
<h5>What is the Firewall?</h5>
|
2 |
<p>This is a big topic and is best covered in-detail in our helpdesk section.</p>
|
3 |
+
<p><a href="https://icwp.io/ak" target="_blank">
|
4 |
https://icontrolwp.freshdesk.com/support/solutions/folders/3000000263</a> .
|
5 |
</p>
|
templates/php/snippets/module-help-headers.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
<h5>What are HTTP Headers?</h5>
|
2 |
<p>This can be a complex topic, but it's worth taking some time to read about it.</p>
|
3 |
-
<p>We've provided some further <a href="
|
4 |
on the topic to help you get your... "head" around it. ;)</p>
|
1 |
<h5>What are HTTP Headers?</h5>
|
2 |
<p>This can be a complex topic, but it's worth taking some time to read about it.</p>
|
3 |
+
<p>We've provided some further <a href="https://icwp.io/aj" target="_blank">in-depth articles</a>
|
4 |
on the topic to help you get your... "head" around it. ;)</p>
|
templates/php/snippets/module-help-login_protect.php
CHANGED
@@ -6,7 +6,7 @@
|
|
6 |
<dt>What is multi-factor authentication (MFA)?</dt>
|
7 |
<dd>
|
8 |
<p>See the link below for a complete explanation of MFA.</p>
|
9 |
-
<p><a href="
|
10 |
https://www.icontrolwp.com/blog/security-multi-two-factor-authentication-wordpress/</a> .
|
11 |
</p>
|
12 |
<p>Please read this. It really helps.</p>
|
6 |
<dt>What is multi-factor authentication (MFA)?</dt>
|
7 |
<dd>
|
8 |
<p>See the link below for a complete explanation of MFA.</p>
|
9 |
+
<p><a href="https://icwp.io/ai" target="_blank">
|
10 |
https://www.icontrolwp.com/blog/security-multi-two-factor-authentication-wordpress/</a> .
|
11 |
</p>
|
12 |
<p>Please read this. It really helps.</p>
|
templates/php/snippets/module-help-plugin.php
CHANGED
@@ -16,7 +16,7 @@
|
|
16 |
public IP address.
|
17 |
</p>
|
18 |
<p>Don't know your IP address? Go here:
|
19 |
-
(<a href="
|
20 |
</p>
|
21 |
<p>With this result, you should be able to select the correct item from the list. The higher up the
|
22 |
list the better, with <code>REMOTE_ADDR</code> being the #1 preferred, if possible.</p>
|
16 |
public IP address.
|
17 |
</p>
|
18 |
<p>Don't know your IP address? Go here:
|
19 |
+
(<a href="https://icwp.io/an" target="_blank">We've done it for you</a> ;)
|
20 |
</p>
|
21 |
<p>With this result, you should be able to select the correct item from the list. The higher up the
|
22 |
list the better, with <code>REMOTE_ADDR</code> being the #1 preferred, if possible.</p>
|
templates/php/snippets/plugin_badge.php
CHANGED
@@ -82,7 +82,7 @@
|
|
82 |
</style>
|
83 |
<div id="icwpWpsfSiteBadge">
|
84 |
<a id="icwpWpsfCloseButton">x</a>
|
85 |
-
<a href="
|
86 |
title="This site is protected by the Shield Security plugin."
|
87 |
%s>
|
88 |
<img src="%s" alt="%s Logo" />
|
82 |
</style>
|
83 |
<div id="icwpWpsfSiteBadge">
|
84 |
<a id="icwpWpsfCloseButton">x</a>
|
85 |
+
<a href="https://icwp.io/wpsecurityfirewall" target="_blank"
|
86 |
title="This site is protected by the Shield Security plugin."
|
87 |
%s>
|
88 |
<img src="%s" alt="%s Logo" />
|
templates/php/snippets/plugin_badge_widget.php
CHANGED
@@ -28,7 +28,7 @@
|
|
28 |
}
|
29 |
</style>
|
30 |
<div id="icwpWpsfSiteBadge" class="icwp_wpsf_site_badge">
|
31 |
-
<a href="
|
32 |
<img src="<?php echo $hrefs['img_src']; ?>" alt="<?php echo $strings['plugin_name']; ?> Logo" />
|
33 |
<div class="badge-text">
|
34 |
This Site Is Protected By <span style="font-style: italic;">The</span><br/><?php echo $strings['plugin_name']; ?> →
|
28 |
}
|
29 |
</style>
|
30 |
<div id="icwpWpsfSiteBadge" class="icwp_wpsf_site_badge">
|
31 |
+
<a href="https://icwp.io/wpsecurityfirewall" target="_blank" title="<?php echo $strings['plugin_name']; ?>">
|
32 |
<img src="<?php echo $hrefs['img_src']; ?>" alt="<?php echo $strings['plugin_name']; ?> Logo" />
|
33 |
<div class="badge-text">
|
34 |
This Site Is Protected By <span style="font-style: italic;">The</span><br/><?php echo $strings['plugin_name']; ?> →
|
templates/php/snippets/pro.php
CHANGED
@@ -71,17 +71,19 @@ $aLicKeyInput = $inputs[ 'license_key' ];
|
|
71 |
<?php echo $flags[ 'button_enabled_check' ] ? '' : 'disabled="disabled"'; ?> >
|
72 |
Check License
|
73 |
</button>
|
74 |
-
|
|
|
|
|
|
|
|
|
75 |
<ul>
|
76 |
<li>URL To Activate: <?php echo $vars[ 'activation_url' ]; ?></li>
|
77 |
<li>Licenses may only be checked once in 20 seconds. Checks more frequent than this will
|
78 |
automatically be skipped</li>
|
79 |
</ul>
|
80 |
-
</
|
81 |
</div>
|
82 |
</form>
|
83 |
-
<p class="font-weight-bold">Be sure to have first activated your URL in your
|
84 |
-
<a target="_blank" href="<?php echo $aHrefs[ 'keyless_cp' ]; ?>">Keyless Activation control panel</a>.</p>
|
85 |
|
86 |
<form method="post" id="ConnectionDebug">
|
87 |
<?php foreach ( $ajax[ 'connection_debug' ] as $sAjKey => $sAjVal ) : ?>
|
@@ -218,12 +220,12 @@ $aLicKeyInput = $inputs[ 'license_key' ];
|
|
218 |
$1/month per site ($12/year)</p>
|
219 |
<ol>
|
220 |
<li>Just grab a new license from the
|
221 |
-
<a href="
|
222 |
<li>Activate your license on your sites using the 'Activate Key' button.</li>
|
223 |
</ol>
|
224 |
|
225 |
<p class="text-center">
|
226 |
-
<a href="
|
227 |
class="btn btn-large btn-success">
|
228 |
Upgrade To Shield Pro Now →</a>
|
229 |
</p>
|
71 |
<?php echo $flags[ 'button_enabled_check' ] ? '' : 'disabled="disabled"'; ?> >
|
72 |
Check License
|
73 |
</button>
|
74 |
+
|
75 |
+
|
76 |
+
<div class="form-text text-muted">
|
77 |
+
<p class="font-weight-bold"><br/>Be sure to have first activated your URL in your
|
78 |
+
<a target="_blank" href="<?php echo $aHrefs[ 'keyless_cp' ]; ?>">Keyless Activation control panel</a>.</p>
|
79 |
<ul>
|
80 |
<li>URL To Activate: <?php echo $vars[ 'activation_url' ]; ?></li>
|
81 |
<li>Licenses may only be checked once in 20 seconds. Checks more frequent than this will
|
82 |
automatically be skipped</li>
|
83 |
</ul>
|
84 |
+
</div>
|
85 |
</div>
|
86 |
</form>
|
|
|
|
|
87 |
|
88 |
<form method="post" id="ConnectionDebug">
|
89 |
<?php foreach ( $ajax[ 'connection_debug' ] as $sAjKey => $sAjVal ) : ?>
|
220 |
$1/month per site ($12/year)</p>
|
221 |
<ol>
|
222 |
<li>Just grab a new license from the
|
223 |
+
<a href="https://icwp.io/buyshieldpro" target="_blank">One Dollar Plugin here</a>.</li>
|
224 |
<li>Activate your license on your sites using the 'Activate Key' button.</li>
|
225 |
</ol>
|
226 |
|
227 |
<p class="text-center">
|
228 |
+
<a href="https://icwp.io/buyshieldpro" target="_blank" id="ButtonBuyNow"
|
229 |
class="btn btn-large btn-success">
|
230 |
Upgrade To Shield Pro Now →</a>
|
231 |
</p>
|
templates/php/snippets/widget_dashboard_plugin.php
CHANGED
@@ -1,4 +1,8 @@
|
|
1 |
-
<p><?echo $sInstallationDays; ?></p>
|
2 |
<hr />
|
3 |
-
<p
|
4 |
-
|
|
|
|
|
|
|
|
1 |
+
<p><?php echo $sInstallationDays; ?></p>
|
2 |
<hr />
|
3 |
+
<p>
|
4 |
+
<?php if ( !empty( $sFooter ) ) : ?>
|
5 |
+
<?php echo $sFooter; ?><br />
|
6 |
+
<?php endif; ?>
|
7 |
+
<span style="font-size: x-small;"><?php echo $sIpAddress; ?></span>
|
8 |
+
</p>
|
templates/php/widgets/icwp_common_widgets.php
CHANGED
@@ -13,13 +13,13 @@
|
|
13 |
<div class="row">
|
14 |
<div class="span6">
|
15 |
<ul>
|
16 |
-
<li><a href="
|
17 |
-
<li><a href="
|
18 |
</ul>
|
19 |
</div>
|
20 |
<div class="span5">
|
21 |
<ul>
|
22 |
-
<li><a href="
|
23 |
<li><a href="http://wordpress.org/extend/plugins/wp-simple-firewall/" target="_blank">Show some love, and give this a 5 star rating on WordPress.org.</a></li>
|
24 |
</ul>
|
25 |
</div>
|
13 |
<div class="row">
|
14 |
<div class="span6">
|
15 |
<ul>
|
16 |
+
<li><a href="https://icwp.io/2b" target="_blank"><strong>Manage <u>All</u> Your WordPress Sites In 1 Place!</strong></a></li>
|
17 |
+
<li><a href="https://icwp.io/2c" target="_blank">Check out all our other WordPress Plugins</a></li>
|
18 |
</ul>
|
19 |
</div>
|
20 |
<div class="span5">
|
21 |
<ul>
|
22 |
+
<li><a href="https://icwp.io/2d" target="_blank"><strong>Visit the plugin Help & Support page</strong></a>.</li>
|
23 |
<li><a href="http://wordpress.org/extend/plugins/wp-simple-firewall/" target="_blank">Show some love, and give this a 5 star rating on WordPress.org.</a></li>
|
24 |
</ul>
|
25 |
</div>
|
templates/twig/emails/user_management/user_login_notification.twig
ADDED
File without changes
|
templates/twig/features/feature-base.twig
CHANGED
@@ -10,7 +10,7 @@
|
|
10 |
</div>
|
11 |
<div class="page-header">
|
12 |
<h2>
|
13 |
-
<a id="pluginlogo_32" class="header-icon32" href="
|
14 |
{{ sPageTitle|raw }}
|
15 |
</h2>
|
16 |
</div>
|
10 |
</div>
|
11 |
<div class="page-header">
|
12 |
<h2>
|
13 |
+
<a id="pluginlogo_32" class="header-icon32" href="https://icwp.io/2k" target="_blank"></a>
|
14 |
{{ sPageTitle|raw }}
|
15 |
</h2>
|
16 |
</div>
|
templates/twig/snippets/widget_common.twig
CHANGED
@@ -13,13 +13,13 @@
|
|
13 |
<div class="row">
|
14 |
<div class="span6">
|
15 |
<ul>
|
16 |
-
<li><a href="
|
17 |
-
<li><a href="
|
18 |
</ul>
|
19 |
</div>
|
20 |
<div class="span5">
|
21 |
<ul>
|
22 |
-
<li><a href="
|
23 |
<li><a href="http://wordpress.org/extend/plugins/wp-simple-firewall/" target="_blank">Show some love, and give this a 5 star rating on WordPress.org.</a></li>
|
24 |
</ul>
|
25 |
</div>
|
13 |
<div class="row">
|
14 |
<div class="span6">
|
15 |
<ul>
|
16 |
+
<li><a href="https://icwp.io/2b" target="_blank"><strong>Manage <u>All</u> Your WordPress Sites In 1 Place!</strong></a></li>
|
17 |
+
<li><a href="https://icwp.io/2c" target="_blank">Check out all our other WordPress Plugins</a></li>
|
18 |
</ul>
|
19 |
</div>
|
20 |
<div class="span5">
|
21 |
<ul>
|
22 |
+
<li><a href="https://icwp.io/2d" target="_blank"><strong>Visit the plugin Help & Support page</strong></a>.</li>
|
23 |
<li><a href="http://wordpress.org/extend/plugins/wp-simple-firewall/" target="_blank">Show some love, and give this a 5 star rating on WordPress.org.</a></li>
|
24 |
</ul>
|
25 |
</div>
|
templates/twig/wizard/pages/base.twig
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
<div id="FooterWizardBanner" class="container-fluid">
|
6 |
<div id="WizardBanner" class="row">
|
7 |
<div class="col-lg-5 offset-lg-3 col-md-5 offset-md-3 col-sm-8 col-8">
|
8 |
-
<p>Support future development and get exclusive
|
9 |
<br />Vulnerability Scanner; Options Import; Email Support+more.</p>
|
10 |
</div>
|
11 |
<div class="col-lg-1 col-md-2 col-sm-2 col-4">
|
5 |
<div id="FooterWizardBanner" class="container-fluid">
|
6 |
<div id="WizardBanner" class="row">
|
7 |
<div class="col-lg-5 offset-lg-3 col-md-5 offset-md-3 col-sm-8 col-8">
|
8 |
+
<p>Support future development and get exclusive {{ strings.plugin_name }} features:
|
9 |
<br />Vulnerability Scanner; Options Import; Email Support+more.</p>
|
10 |
</div>
|
11 |
<div class="col-lg-1 col-md-2 col-sm-2 col-4">
|
templates/twig/wizard/slides/common/base.twig
CHANGED
@@ -6,12 +6,12 @@
|
|
6 |
<div class="container-fluid">
|
7 |
<div class="row">
|
8 |
<div class="col-6">
|
9 |
-
{% block
|
10 |
<button class="btn btn-outline-secondary btn-block ButtonPreviousSlide">← Previous Step </button>
|
11 |
{% endblock %}
|
12 |
</div>
|
13 |
<div class="col-6">
|
14 |
-
{% block
|
15 |
<button class="btn btn-info btn-block ButtonNextSlide">Next Step →</button>
|
16 |
{% endblock %}
|
17 |
</div>
|
@@ -31,9 +31,25 @@
|
|
31 |
<div class="slide-footer">
|
32 |
{% block slide_footer %}
|
33 |
<hr />
|
34 |
-
<
|
35 |
-
|
36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
{% endblock %}
|
38 |
</div>
|
39 |
</div>
|
6 |
<div class="container-fluid">
|
7 |
<div class="row">
|
8 |
<div class="col-6">
|
9 |
+
{% block slide_header_previous_top %}
|
10 |
<button class="btn btn-outline-secondary btn-block ButtonPreviousSlide">← Previous Step </button>
|
11 |
{% endblock %}
|
12 |
</div>
|
13 |
<div class="col-6">
|
14 |
+
{% block slide_header_next_top %}
|
15 |
<button class="btn btn-info btn-block ButtonNextSlide">Next Step →</button>
|
16 |
{% endblock %}
|
17 |
</div>
|
31 |
<div class="slide-footer">
|
32 |
{% block slide_footer %}
|
33 |
<hr />
|
34 |
+
<div class="row">
|
35 |
+
<div class="col">
|
36 |
+
<p>Click 'Next Step' at the top to continue.
|
37 |
+
Or <a href="{{ hrefs.dashboard }}" style="color: inherit; text-decoration: underline;">go back</a>
|
38 |
+
to {{ strings.plugin_name }} Dashboard</p>
|
39 |
+
</div>
|
40 |
+
</div>
|
41 |
+
<div class="row">
|
42 |
+
<div class="col-6">
|
43 |
+
{% block slide_header_previous_bottom %}
|
44 |
+
<button class="btn btn-outline-secondary btn-block ButtonPreviousSlide">← Previous Step </button>
|
45 |
+
{% endblock %}
|
46 |
+
</div>
|
47 |
+
<div class="col-6">
|
48 |
+
{% block slide_header_next_top_bottom %}
|
49 |
+
<button class="btn btn-info btn-block ButtonNextSlide">Next Step →</button>
|
50 |
+
{% endblock %}
|
51 |
+
</div>
|
52 |
+
</div>
|
53 |
{% endblock %}
|
54 |
</div>
|
55 |
</div>
|
templates/twig/wizard/slides/common/base_finish.twig
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
{% extends 'wizard/slides/common/base.twig' %}
|
2 |
|
3 |
-
{% block
|
4 |
|
5 |
{% block slide_body_middle %}
|
6 |
|
@@ -47,5 +47,7 @@
|
|
47 |
{% block slide_footer %}
|
48 |
<hr />
|
49 |
<a href="{{ hrefs.dashboard }}" class="btn btn-outline-secondary">
|
50 |
-
⇐ Return To The
|
51 |
-
{% endblock %}
|
|
|
|
1 |
{% extends 'wizard/slides/common/base.twig' %}
|
2 |
|
3 |
+
{% block slide_header_next_top %}{% endblock %}
|
4 |
|
5 |
{% block slide_body_middle %}
|
6 |
|
47 |
{% block slide_footer %}
|
48 |
<hr />
|
49 |
<a href="{{ hrefs.dashboard }}" class="btn btn-outline-secondary">
|
50 |
+
⇐ Return To The {{ strings.plugin_name }} WordPress Dashboard</a>
|
51 |
+
{% endblock %}
|
52 |
+
|
53 |
+
{% block slide_header_next_bottom %}{% endblock %}
|
templates/twig/wizard/slides/common/base_start.twig
CHANGED
@@ -1,3 +1,4 @@
|
|
1 |
{% extends 'wizard/slides/common/base.twig' %}
|
2 |
|
3 |
-
{% block
|
|
1 |
{% extends 'wizard/slides/common/base.twig' %}
|
2 |
|
3 |
+
{% block slide_header_previous_top %}{% endblock %}
|
4 |
+
{% block slide_header_previous_bottom %}{% endblock %}
|
templates/twig/wizard/slides/common/no_access.twig
CHANGED
@@ -8,7 +8,7 @@
|
|
8 |
<p>To run this wizard you need to have certain privileges that are not met by your current account level.</p>
|
9 |
<p>If this doesn't seem right, please contact your site administrator.</p>
|
10 |
|
11 |
-
<a href="{{ hrefs.dashboard }}" class="btn btn-outline-secondary">Go Back To
|
12 |
|
13 |
{% endblock %}
|
14 |
|
8 |
<p>To run this wizard you need to have certain privileges that are not met by your current account level.</p>
|
9 |
<p>If this doesn't seem right, please contact your site administrator.</p>
|
10 |
|
11 |
+
<a href="{{ hrefs.dashboard }}" class="btn btn-outline-secondary">Go Back To {{ strings.plugin_name }} Dashboard</a>
|
12 |
|
13 |
{% endblock %}
|
14 |
|
templates/twig/wizard/slides/welcome/optin.twig
CHANGED
@@ -42,7 +42,7 @@
|
|
42 |
<hr />
|
43 |
|
44 |
<h6>Bonus: Join our new Facebook group</h6>
|
45 |
-
<p><a href="
|
46 |
Click here to request access to our new Facebook group</a> where you can ask questions
|
47 |
and help others with WordPress security and in particular, the Shield Security plugin.</p>
|
48 |
|
42 |
<hr />
|
43 |
|
44 |
<h6>Bonus: Join our new Facebook group</h6>
|
45 |
+
<p><a href="https://icwp.io/cu" target="_blank">
|
46 |
Click here to request access to our new Facebook group</a> where you can ask questions
|
47 |
and help others with WordPress security and in particular, the Shield Security plugin.</p>
|
48 |
|
templates/twig/wpadmin_pages/insights/index.twig
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
{% extends '/wpadmin_pages/base.twig' %}
|
2 |
|
3 |
-
{% block h1heading %}<h1>
|
4 |
|
5 |
{% block body_head %}
|
6 |
{% endblock %}
|
1 |
{% extends '/wpadmin_pages/base.twig' %}
|
2 |
|
3 |
+
{% block h1heading %}<h1>{{ strings.page_title }}</h1>{% endblock %}
|
4 |
|
5 |
{% block body_head %}
|
6 |
{% endblock %}
|
templates/twig/wpadmin_pages/insights/recent_events.twig
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<div id="SectionRecentEvents" class="insights_widget card w-100">
|
2 |
<div class="card-header">
|
3 |
<h5 class="card-title">Recent Events</h5>
|
4 |
-
<h6 class="card-subtitle mb-2 text-muted">
|
5 |
</div>
|
6 |
<div class="card-body overflow_container">
|
7 |
<div class="overflow_inner">
|
1 |
<div id="SectionRecentEvents" class="insights_widget card w-100">
|
2 |
<div class="card-header">
|
3 |
<h5 class="card-title">Recent Events</h5>
|
4 |
+
<h6 class="card-subtitle mb-2 text-muted">{{ strings.box_receve_subtitle }}</h6>
|
5 |
</div>
|
6 |
<div class="card-body overflow_container">
|
7 |
<div class="overflow_inner">
|
templates/twig/wpadmin_pages/insights/title.twig
CHANGED
@@ -1,20 +1,20 @@
|
|
1 |
<div id="SectionTitle" class="insights_widget card w-100">
|
2 |
<div class="card-header">
|
3 |
-
<h5 class="card-title mb-0">
|
4 |
</div>
|
5 |
<div class="card-body overflow_container">
|
6 |
<div class="overflow_inner">
|
7 |
-
<p>This <span class="font-weight-bold">Insights Dashboard</span> is new with
|
8 |
<br />It's a 1st version, designed
|
9 |
to provide a high-level summary of your WordPress site security, and Shield activity.</p>
|
10 |
<p>If you have suggestions or feedback, please let us know
|
11 |
-
<a href="
|
12 |
in our <span class="badge badge-info">new</span> Facebook group</a>.</p>
|
13 |
{% if flags.is_pro %}
|
14 |
<p>Thank you for your support with your Shield Pro purchase. :)</p>
|
15 |
{% else %}
|
16 |
<p>For just $1/month, get all the extra features and 1-on-1 technical support -
|
17 |
-
<a href="
|
18 |
{% endif %}
|
19 |
</div>
|
20 |
{#<a href="#" class="card-link">Card link</a>#}
|
1 |
<div id="SectionTitle" class="insights_widget card w-100">
|
2 |
<div class="card-header">
|
3 |
+
<h5 class="card-title mb-0">{{ strings.box_welcome_title }}</h5>
|
4 |
</div>
|
5 |
<div class="card-body overflow_container">
|
6 |
<div class="overflow_inner">
|
7 |
+
<p>This <span class="font-weight-bold">Insights Dashboard</span> is new with v6.7.0
|
8 |
<br />It's a 1st version, designed
|
9 |
to provide a high-level summary of your WordPress site security, and Shield activity.</p>
|
10 |
<p>If you have suggestions or feedback, please let us know
|
11 |
+
<a href="https://icwp.io/shieldsecuritygroupfb" target="_blank">
|
12 |
in our <span class="badge badge-info">new</span> Facebook group</a>.</p>
|
13 |
{% if flags.is_pro %}
|
14 |
<p>Thank you for your support with your Shield Pro purchase. :)</p>
|
15 |
{% else %}
|
16 |
<p>For just $1/month, get all the extra features and 1-on-1 technical support -
|
17 |
+
<a href="https://icwp.io/cw" class="btn btn-outline-success">Go Pro Today!</a></p>
|
18 |
{% endif %}
|
19 |
</div>
|
20 |
{#<a href="#" class="card-link">Card link</a>#}
|