@@ -30,15 +30,36 @@ private static function fingerprint() {
3030 // Get and validate IP address (support IPv4 and IPv6)
3131 $ ip_raw = $ _SERVER ['HTTP_X_FORWARDED_FOR ' ] ?? $ _SERVER ['REMOTE_ADDR ' ] ?? '' ;
3232 // Handle multiple IPs in X-Forwarded-For
33- $ ip_raw = trim (explode (', ' , $ ip_raw )[0 ]); // Trim after selecting first IP
34- $ ip = filter_var ($ ip_raw , FILTER_VALIDATE_IP ) ? $ ip_raw : '' ;
33+ $ ip_raw = sanitize_text_field ( trim ( explode ( ', ' , $ ip_raw )[0 ] ) ); // Trim after selecting first IP
34+
35+ // Default if we can’t extract a stable prefix
36+ $ ip_prefix = '' ;
37+
38+ // IPv4: grab the first two octets
39+ if ( filter_var ( $ ip_raw , FILTER_VALIDATE_IP , FILTER_FLAG_IPV4 ) ) {
40+ $ octets = explode ( '. ' , $ ip_raw );
41+ if ( count ( $ octets ) >= 2 ) {
42+ $ ip_prefix = $ octets [0 ] . '. ' . $ octets [1 ];
43+ }
44+
45+ // IPv6: first two hextets
46+ } elseif ( filter_var ( $ ip_raw , FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 ) ) {
47+ // Normalize IP to its full canonical form (optional)
48+ // https://www.php.net/manual/en/function.inet-ntop.php
49+ // Inet_pton converts IPv6 to binary, inet_ntop converts it back to string
50+ $ normalized_ip = inet_ntop ( inet_pton ( $ ip_raw ) );
51+ $ hextets = explode ( ': ' , $ normalized_ip );
52+ if ( count ( $ hextets ) >= 2 ) {
53+ $ ip_prefix = strtolower ( $ hextets [0 ] . ': ' . $ hextets [1 ] );
54+ }
55+ }
3556
3657 // Get and sanitize Accept-Language
3758 $ lang_raw = $ _SERVER ['HTTP_ACCEPT_LANGUAGE ' ] ?? '' ;
3859 $ lang_clean = sanitize_text_field (wp_unslash ($ lang_raw ));
3960 $ lang = preg_match ('/^[a-zA-Z]{1,3}(?:-[a-zA-Z]{1,3})?(?:,[a-zA-Z]{1,3}(?:-[a-zA-Z]{1,3})?)*$/i ' , $ lang_clean ) ? $ lang_clean : '' ;
4061
41- return "{$ ua }| {$ ip }| {$ lang }" ;
62+ return "{$ ua }| {$ ip_prefix }| {$ lang }" ;
4263 }
4364
4465 /**
0 commit comments