PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 3.1.14
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v3.1.14
3.1.14 3.1.13 3.1.12 3.1.11 3.1.10 3.1.9 3.1.8 3.1.7 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 All 123 releases
← All changes | Inc/Framework/Inc/Base/User.php +99 -16 3.1.8 → 3.1.14 View file →
@@ -1,8 +1,8 @@
1 1 <?php
2 2 /**
3 3 * @package FirePlugins Framework
4 - * @version 1.1.146
4 + * @version 1.2.6
5 5 *
6 6 * @author FirePlugins <[email protected]>
7 7 * @link https://www.fireplugins.com
8 8 * @copyright Copyright © 2026 FirePlugins All Rights Reserved
@@ -18,8 +18,17 @@
18 18
19 19 class User
20 20 {
21 21 /**
22 + * Per-request memoized result of get() for the current active user (no field/value given),
23 + * keyed by the logged-in user ID (0 for guests) so it stays correct if the current user
24 + * changes within the same PHP process (e.g. wp_set_current_user() in tests/WP-CLI/cron).
25 + *
26 + * @var array
27 + */
28 + private static $currentUserCache = [];
29 +
30 + /**
22 31 * Return the user object
23 32 *
24 33 * @param mixed $value The user identifier
25 34 * @param mixed $field The field to search for (id | ID | slug | email | login)
@@ -30,15 +39,29 @@
30 39 {
31 40 // Return current active user
32 41 if (empty($field) || empty($value))
33 42 {
43 + $current_user_id = get_current_user_id();
44 +
45 + if (array_key_exists($current_user_id, self::$currentUserCache))
46 + {
47 + return self::$currentUserCache[$current_user_id];
48 + }
49 +
34 50 if (!is_user_logged_in())
35 51 {
36 - return new \WP_User;
52 + return (self::$currentUserCache[$current_user_id] = new \WP_User);
37 53 }
38 54
39 55 $field = 'ID';
40 - $value = get_current_user_id();
56 + $value = $current_user_id;
57 +
58 + if (!self::exists($value))
59 + {
60 + return (self::$currentUserCache[$current_user_id] = null);
61 + }
62 +
63 + return (self::$currentUserCache[$current_user_id] = get_user_by($field, $value));
41 64 }
42 65
43 66 if (!self::exists($value))
44 67 {
@@ -43,9 +66,9 @@
43 66 if (!self::exists($value))
44 67 {
45 68 return;
46 69 }
47 -
70 +
48 71 return get_user_by($field, $value);
49 72 }
50 73
51 74 /**
@@ -73,25 +96,85 @@
73 96 return $user;
74 97 }
75 98
76 99 /**
77 - * Get the IP address of the user
100 + * Get the IP address of the user.
78 101 *
102 + * Forwarded headers (X-Forwarded-For, Client-IP) are visitor-controlled, so they are
103 + * only honoured when REMOTE_ADDR is a proxy the site has declared trusted through the
104 + * `fpframework/trusted_proxies` filter. Otherwise REMOTE_ADDR is the answer.
105 + *
79 106 * @return string
80 107 */
81 108 public static function getIP()
82 109 {
83 - // Whether ip is from the share internet
84 - if (!empty($_SERVER['HTTP_CLIENT_IP']))
85 - {
86 - return sanitize_text_field(wp_unslash($_SERVER['HTTP_CLIENT_IP']));
87 - }
110 + $remote_addr = isset($_SERVER['REMOTE_ADDR']) ? self::validIP(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';
88 111
89 - //whether ip is from the proxy
90 - if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
91 - {
92 - return sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR']));
93 - }
112 + $trusted_proxies = apply_filters('fpframework/trusted_proxies', []);
113 + $trusted_proxies = is_array($trusted_proxies) ? $trusted_proxies : [];
94 114
95 - return sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR']));
115 + /**
116 + * A private or loopback connection address can only be a proxy on the site's own
117 + * network (nginx in front of Apache, Docker, an internal load balancer), so its
118 + * forwarded headers are honoured without configuration. Public addresses are only
119 + * trusted when the site lists them.
120 + */
121 + $behind_proxy = $remote_addr !== '' && (!self::isRoutable($remote_addr) || in_array($remote_addr, $trusted_proxies, true));
122 +
123 + if (!$behind_proxy)
124 + {
125 + return $remote_addr;
126 + }
127 +
128 + foreach (['HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP'] as $header)
129 + {
130 + if (empty($_SERVER[$header]))
131 + {
132 + continue;
133 + }
134 +
135 + // The proxy appends the address it saw last; earlier entries are whatever the client sent.
136 + $hops = array_reverse(array_map('trim', explode(',', wp_unslash($_SERVER[$header]))));
137 +
138 + foreach ($hops as $hop)
139 + {
140 + if (in_array($hop, $trusted_proxies, true) || ($hop !== '' && !self::isRoutable($hop)))
141 + {
142 + continue;
143 + }
144 +
145 + if ($ip = self::validIP($hop))
146 + {
147 + return $ip;
148 + }
149 + }
150 + }
151 +
152 + return $remote_addr;
153 + }
154 +
155 + /**
156 + * Returns the value when it is a syntactically valid IPv4/IPv6 address, otherwise ''.
157 + *
158 + * @param string $value
159 + *
160 + * @return string
161 + */
162 + /**
163 + * Whether the address is public (not private, loopback or otherwise reserved).
164 + *
165 + * @param string $ip
166 + *
167 + * @return bool
168 + */
169 + private static function isRoutable($ip)
170 + {
171 + return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
172 + }
173 +
174 + private static function validIP($value)
175 + {
176 + $value = is_string($value) ? trim($value) : '';
177 +
178 + return filter_var($value, FILTER_VALIDATE_IP) ? $value : '';
96 179 }
97 180 }