Diff
14 years ago
.htaccess
14 years ago
Diff.php
14 years ago
GeoIP.dat
13 years ago
IPTraf.php
13 years ago
diffResult.php
14 years ago
email_genericAlert.php
14 years ago
email_newIssues.php
14 years ago
email_unlockRequest.php
14 years ago
menu_activity.php
13 years ago
menu_blockedIPs.php
13 years ago
menu_countryBlocking.php
13 years ago
menu_options.php
13 years ago
menu_scan.php
13 years ago
menu_scanSchedule.php
13 years ago
schedWeekEntry.php
13 years ago
sysinfo.php
14 years ago
unknownFiles.php
13 years ago
viewFullActivityLog.php
13 years ago
wf503.php
13 years ago
wfAPI.php
13 years ago
wfAction.php
14 years ago
wfArray.php
13 years ago
wfBrowscap.php
14 years ago
wfBrowscapCache.php
14 years ago
wfBulkCountries.php
13 years ago
wfConfig.php
13 years ago
wfCountryMap.php
13 years ago
wfCrawl.php
13 years ago
wfDB.php
13 years ago
wfDict.php
14 years ago
wfGeoIP.php
13 years ago
wfIssues.php
13 years ago
wfLockedOut.php
14 years ago
wfLog.php
13 years ago
wfModTracker.php
14 years ago
wfRate.php
14 years ago
wfScanEngine.php
13 years ago
wfSchema.php
13 years ago
wfUnlockMsg.php
14 years ago
wfUtils.php
13 years ago
wfViewResult.php
14 years ago
wordfenceClass.php
13 years ago
wordfenceConstants.php
13 years ago
wordfenceHash.php
13 years ago
wordfenceScanner.php
13 years ago
wordfenceURLHoover.php
13 years ago
wfUtils.php
460 lines
| 1 | <?php |
| 2 | require_once('wfConfig.php'); |
| 3 | require_once('wfCountryMap.php'); |
| 4 | class wfUtils { |
| 5 | private static $isWindows = false; |
| 6 | public static $scanLockFH = false; |
| 7 | private static $lastErrorReporting = false; |
| 8 | private static $lastDisplayErrors = false; |
| 9 | public static function makeTimeAgo($secs, $noSeconds = false) { |
| 10 | if($secs < 1){ |
| 11 | return "a moment"; |
| 12 | } |
| 13 | $months = floor($secs / (86400 * 30)); |
| 14 | $days = floor($secs / 86400); |
| 15 | $hours = floor($secs / 3600); |
| 16 | $minutes = floor($secs / 60); |
| 17 | if($months) { |
| 18 | $days -= $months * 30; |
| 19 | return self::pluralize($months, 'month', $days, 'day'); |
| 20 | } else if($days) { |
| 21 | $hours -= $days * 24; |
| 22 | return self::pluralize($days, 'day', $hours, 'hour'); |
| 23 | } else if($hours) { |
| 24 | $minutes -= $hours * 60; |
| 25 | return self::pluralize($hours, 'hour', $minutes, 'min'); |
| 26 | } else if($minutes) { |
| 27 | $secs -= $minutes * 60; |
| 28 | return self::pluralize($minutes, 'min'); |
| 29 | } else { |
| 30 | if($noSeconds){ |
| 31 | return "less than a minute"; |
| 32 | } else { |
| 33 | return floor($secs) . " secs"; |
| 34 | } |
| 35 | } |
| 36 | } |
| 37 | public static function pluralize($m1, $t1, $m2 = false, $t2 = false) { |
| 38 | if($m1 != 1) { |
| 39 | $t1 = $t1 . 's'; |
| 40 | } |
| 41 | if($m2 != 1) { |
| 42 | $t2 = $t2 . 's'; |
| 43 | } |
| 44 | if($m1 && $m2){ |
| 45 | return "$m1 $t1 $m2 $t2"; |
| 46 | } else { |
| 47 | return "$m1 $t1"; |
| 48 | } |
| 49 | } |
| 50 | public static function formatBytes($bytes, $precision = 2) { |
| 51 | $units = array('B', 'KB', 'MB', 'GB', 'TB'); |
| 52 | |
| 53 | $bytes = max($bytes, 0); |
| 54 | $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); |
| 55 | $pow = min($pow, count($units) - 1); |
| 56 | |
| 57 | // Uncomment one of the following alternatives |
| 58 | $bytes /= pow(1024, $pow); |
| 59 | // $bytes /= (1 << (10 * $pow)); |
| 60 | |
| 61 | return round($bytes, $precision) . ' ' . $units[$pow]; |
| 62 | } |
| 63 | public static function inet_ntoa($ip){ |
| 64 | $long = 4294967295 - ($ip - 1); |
| 65 | return long2ip(-$long); |
| 66 | } |
| 67 | public static function inet_aton($ip){ |
| 68 | return sprintf("%u", ip2long($ip)); |
| 69 | } |
| 70 | public static function getBaseURL(){ |
| 71 | return plugins_url() . '/wordfence/'; |
| 72 | } |
| 73 | public static function getPluginBaseDir(){ |
| 74 | return WP_CONTENT_DIR . '/plugins/'; |
| 75 | //return ABSPATH . 'wp-content/plugins/'; |
| 76 | } |
| 77 | public static function getIP(){ |
| 78 | $IP = 0; |
| 79 | if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ |
| 80 | $IP = $_SERVER['HTTP_X_FORWARDED_FOR']; |
| 81 | if(is_array($IP) && isset($IP[0])){ $IP = $IP[0]; } //It seems that some hosts may modify _SERVER vars into arrays. |
| 82 | } |
| 83 | if((! preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $IP)) && isset($_SERVER['HTTP_X_REAL_IP'])){ |
| 84 | $IP = $_SERVER['HTTP_X_REAL_IP']; |
| 85 | if(is_array($IP) && isset($IP[0])){ $IP = $IP[0]; } //It seems that some hosts may modify _SERVER vars into arrays. |
| 86 | } |
| 87 | if((! preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $IP)) && isset($_SERVER['REMOTE_ADDR'])){ |
| 88 | $IP = $_SERVER['REMOTE_ADDR']; |
| 89 | if(is_array($IP) && isset($IP[0])){ $IP = $IP[0]; } //It seems that some hosts may modify _SERVER vars into arrays. |
| 90 | } |
| 91 | if(preg_match('/,/', $IP)){ |
| 92 | $parts = explode(',', $IP); //Some users have "unknown,100.100.100.100" for example so we take the first thing that looks like an IP. |
| 93 | foreach($parts as $part){ |
| 94 | if(preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $part)){ |
| 95 | $IP = trim($part); |
| 96 | break; |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | if(preg_match('/:\d+$/', $IP)){ |
| 101 | $IP = preg_replace('/:\d+$/', '', $IP); |
| 102 | } |
| 103 | if(self::isValidIP($IP)){ |
| 104 | return $IP; |
| 105 | } else { |
| 106 | $msg = "Wordfence can't get the IP of clients and therefore can't operate. We received IP: $IP. X-Forwarded-For was: " . $_SERVER['HTTP_X_FORWARDED_FOR'] . " REMOTE_ADDR was: " . $_SERVER['REMOTE_ADDR']; |
| 107 | $possible = array(); |
| 108 | foreach($_SERVER as $key => $val){ |
| 109 | if(preg_match('/^\d+\.\d+\.\d+\.\d+/', $val) && strlen($val) < 255){ |
| 110 | if($val != '127.0.0.1'){ |
| 111 | $possible[$key] = $val; |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | if(sizeof($possible) > 0){ |
| 116 | $msg .= " Report the following on the Wordfence forums and they may be able to help. Headers that may contain the client IP: "; |
| 117 | foreach($possible as $key => $val){ |
| 118 | $msg .= "$key => $val "; |
| 119 | } |
| 120 | } |
| 121 | wordfence::status(1, 'error', $msg); |
| 122 | error_log($msg); |
| 123 | return false; |
| 124 | } |
| 125 | } |
| 126 | public static function isValidIP($IP){ |
| 127 | if(preg_match('/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/', $IP, $m)){ |
| 128 | if( |
| 129 | $m[0] >= 0 && $m[0] <= 255 && |
| 130 | $m[1] >= 0 && $m[1] <= 255 && |
| 131 | $m[2] >= 0 && $m[2] <= 255 && |
| 132 | $m[3] >= 0 && $m[3] <= 255 |
| 133 | ){ |
| 134 | return true; |
| 135 | } |
| 136 | } |
| 137 | return false; |
| 138 | } |
| 139 | public static function getRequestedURL(){ |
| 140 | return (@$_SERVER['HTTPS'] ? 'https' : 'http') . '://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; |
| 141 | } |
| 142 | |
| 143 | public static function editUserLink($userID){ |
| 144 | return get_admin_url() . 'user-edit.php?user_id=' . $userID; |
| 145 | } |
| 146 | public static function tmpl($file, $data){ |
| 147 | extract($data); |
| 148 | ob_start(); |
| 149 | include $file; |
| 150 | return ob_get_contents() . (ob_end_clean() ? "" : ""); |
| 151 | } |
| 152 | public static function bigRandomHex(){ |
| 153 | return dechex(rand(0, 2147483647)) . dechex(rand(0, 2147483647)) . dechex(rand(0, 2147483647)); |
| 154 | } |
| 155 | public static function encrypt($str){ |
| 156 | $key = wfConfig::get('encKey'); |
| 157 | if(! $key){ |
| 158 | wordfence::status(1, 'error', "Wordfence error: No encryption key found!"); |
| 159 | return false; |
| 160 | } |
| 161 | $db = new wfDB(); |
| 162 | return $db->querySingle("select HEX(AES_ENCRYPT('%s', '%s')) as val", $str, $key); |
| 163 | } |
| 164 | public static function decrypt($str){ |
| 165 | $key = wfConfig::get('encKey'); |
| 166 | if(! $key){ |
| 167 | wordfence::status(1, 'error', "Wordfence error: No encryption key found!"); |
| 168 | return false; |
| 169 | } |
| 170 | $db = new wfDB(); |
| 171 | return $db->querySingle("select AES_DECRYPT(UNHEX('%s'), '%s') as val", $str, $key); |
| 172 | } |
| 173 | public static function lcmem(){ |
| 174 | $trace=debug_backtrace(); |
| 175 | $caller=array_shift($trace); |
| 176 | $c2 = array_shift($trace); |
| 177 | $mem = memory_get_usage(true); |
| 178 | error_log("$mem at " . $caller['file'] . " line " . $caller['line']); |
| 179 | } |
| 180 | public static function logCaller(){ |
| 181 | $trace=debug_backtrace(); |
| 182 | $caller=array_shift($trace); |
| 183 | $c2 = array_shift($trace); |
| 184 | error_log("Caller for " . $caller['file'] . " line " . $caller['line'] . " is " . $c2['file'] . ' line ' . $c2['line']); |
| 185 | } |
| 186 | public static function getWPVersion(){ |
| 187 | global $wp_version; |
| 188 | global $wordfence_wp_version; |
| 189 | if(isset($wordfence_wp_version)){ |
| 190 | return $wordfence_wp_version; |
| 191 | } else { |
| 192 | return $wp_version; |
| 193 | } |
| 194 | } |
| 195 | public static function isAdminPageMU(){ |
| 196 | if(preg_match('/^[\/a-zA-Z0-9\-\_\s\+\~\!\^\.]*\/wp-admin\/network\//', $_SERVER['REQUEST_URI'])){ |
| 197 | return true; |
| 198 | } |
| 199 | return false; |
| 200 | } |
| 201 | public static function getSiteBaseURL(){ |
| 202 | return rtrim(site_url(), '/') . '/'; |
| 203 | } |
| 204 | public static function longestLine($data){ |
| 205 | $lines = preg_split('/[\r\n]+/', $data); |
| 206 | $max = 0; |
| 207 | foreach($lines as $line){ |
| 208 | $len = strlen($line); |
| 209 | if($len > $max){ |
| 210 | $max = $len; |
| 211 | } |
| 212 | } |
| 213 | return $max; |
| 214 | } |
| 215 | public static function longestNospace($data){ |
| 216 | $lines = preg_split('/[\r\n\s\t]+/', $data); |
| 217 | $max = 0; |
| 218 | foreach($lines as $line){ |
| 219 | $len = strlen($line); |
| 220 | if($len > $max){ |
| 221 | $max = $len; |
| 222 | } |
| 223 | } |
| 224 | return $max; |
| 225 | } |
| 226 | public static function requestMaxMemory(){ |
| 227 | if(wfConfig::get('maxMem', false) && (int) wfConfig::get('maxMem') > 0){ |
| 228 | $maxMem = (int) wfConfig::get('maxMem'); |
| 229 | } else { |
| 230 | $maxMem = 256; |
| 231 | } |
| 232 | if( function_exists('memory_get_usage') && ( (int) @ini_get('memory_limit') < $maxMem ) ){ |
| 233 | @ini_set('memory_limit', $maxMem . 'M'); |
| 234 | } |
| 235 | } |
| 236 | public static function isAdmin(){ |
| 237 | if(is_multisite()){ |
| 238 | if(current_user_can('manage_network')){ |
| 239 | return true; |
| 240 | } |
| 241 | } else { |
| 242 | if(current_user_can('manage_options')){ |
| 243 | return true; |
| 244 | } |
| 245 | } |
| 246 | return false; |
| 247 | } |
| 248 | public static function isWindows(){ |
| 249 | if(! self::$isWindows){ |
| 250 | if(preg_match('/^win/i', PHP_OS)){ |
| 251 | self::$isWindows = 'yes'; |
| 252 | } else { |
| 253 | self::$isWindows = 'no'; |
| 254 | } |
| 255 | } |
| 256 | return self::$isWindows == 'yes' ? true : false; |
| 257 | } |
| 258 | public static function getScanLock(){ |
| 259 | //Windows does not support non-blocking flock, so we use time. |
| 260 | $scanRunning = wfConfig::get('wf_scanRunning'); |
| 261 | if($scanRunning && time() - $scanRunning < WORDFENCE_MAX_SCAN_TIME){ |
| 262 | return false; |
| 263 | } |
| 264 | wfConfig::set('wf_scanRunning', time()); |
| 265 | return true; |
| 266 | } |
| 267 | public static function clearScanLock(){ |
| 268 | wfConfig::set('wf_scanRunning', ''); |
| 269 | } |
| 270 | public static function isScanRunning(){ |
| 271 | $scanRunning = wfConfig::get('wf_scanRunning'); |
| 272 | if($scanRunning && time() - $scanRunning < WORDFENCE_MAX_SCAN_TIME){ |
| 273 | return true; |
| 274 | } else { |
| 275 | return false; |
| 276 | } |
| 277 | } |
| 278 | public static function getIPGeo($IP){ //Works with int or dotted |
| 279 | |
| 280 | $locs = self::getIPsGeo(array($IP)); |
| 281 | if(isset($locs[$IP])){ |
| 282 | return $locs[$IP]; |
| 283 | } else { |
| 284 | return false; |
| 285 | } |
| 286 | } |
| 287 | public static function getIPsGeo($IPs){ //works with int or dotted. Outputs same format it receives. |
| 288 | $IPs = array_unique($IPs); |
| 289 | $isInt = false; |
| 290 | if(strpos($IPs[0], '.') === false){ |
| 291 | $isInt = true; |
| 292 | } |
| 293 | $toResolve = array(); |
| 294 | $db = new wfDB(); |
| 295 | global $wp_version; |
| 296 | global $wpdb; |
| 297 | $locsTable = $wpdb->base_prefix . 'wfLocs'; |
| 298 | $IPLocs = array(); |
| 299 | foreach($IPs as $IP){ |
| 300 | $r1 = $db->query("select IP, ctime, failed, city, region, countryName, countryCode, lat, lon, unix_timestamp() - ctime as age from " . $locsTable . " where IP=%s", ($isInt ? $IP : self::inet_aton($IP)) ); |
| 301 | if($r1){ |
| 302 | if($row = mysql_fetch_assoc($r1)){ |
| 303 | if($row['age'] > WORDFENCE_MAX_IPLOC_AGE){ |
| 304 | $db->query("delete from " . $locsTable . " where IP=%s", $row['IP']); |
| 305 | } else { |
| 306 | if($row['failed'] == 1){ |
| 307 | $IPLocs[$IP] = false; |
| 308 | } else { |
| 309 | if(! $isInt){ |
| 310 | $row['IP'] = self::inet_ntoa($row['IP']); |
| 311 | } |
| 312 | $IPLocs[$IP] = $row; |
| 313 | } |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | if(! isset($IPLocs[$IP])){ |
| 318 | $toResolve[] = $IP; |
| 319 | } |
| 320 | } |
| 321 | if(sizeof($toResolve) > 0){ |
| 322 | $api = new wfAPI(wfConfig::get('apiKey'), $wp_version); |
| 323 | try { |
| 324 | $freshIPs = $api->call('resolve_ips', array(), array( |
| 325 | 'ips' => implode(',', $toResolve) |
| 326 | )); |
| 327 | if(is_array($freshIPs)){ |
| 328 | foreach($freshIPs as $IP => $value){ |
| 329 | if($value == 'failed'){ |
| 330 | $db->query("insert IGNORE into " . $locsTable . " (IP, ctime, failed) values (%s, unix_timestamp(), 1)", ($isInt ? $IP : self::inet_aton($IP)) ); |
| 331 | $IPLocs[$IP] = false; |
| 332 | } else { |
| 333 | $db->query("insert IGNORE into " . $locsTable . " (IP, ctime, failed, city, region, countryName, countryCode, lat, lon) values (%s, unix_timestamp(), 0, '%s', '%s', '%s', '%s', %s, %s)", |
| 334 | ($isInt ? $IP : self::inet_aton($IP)), |
| 335 | $value[3], //city |
| 336 | $value[2], //region |
| 337 | $value[1], //countryName |
| 338 | $value[0],//countryCode |
| 339 | $value[4],//lat |
| 340 | $value[5]//lon |
| 341 | ); |
| 342 | $IPLocs[$IP] = array( |
| 343 | 'IP' => $IP, |
| 344 | 'city' => $value[3], |
| 345 | 'region' => $value[2], |
| 346 | 'countryName' => $value[1], |
| 347 | 'countryCode' => $value[0], |
| 348 | 'lat' => $value[4], |
| 349 | 'lon' => $value[5] |
| 350 | ); |
| 351 | } |
| 352 | } |
| 353 | } |
| 354 | } catch(Exception $e){ |
| 355 | wordfence::status(2, 'error', "Call to Wordfence API to resolve IPs failed: " . $e->getMessage()); |
| 356 | return array(); |
| 357 | } |
| 358 | } |
| 359 | return $IPLocs; |
| 360 | } |
| 361 | public function reverseLookup($IP){ |
| 362 | $db = new wfDB(); |
| 363 | global $wpdb; |
| 364 | $reverseTable = $wpdb->base_prefix . 'wfReverseCache'; |
| 365 | $IPn = wfUtils::inet_aton($IP); |
| 366 | $host = $db->querySingle("select host from " . $reverseTable . " where IP=%s and unix_timestamp() - lastUpdate < %d", $IPn, WORDFENCE_REVERSE_LOOKUP_CACHE_TIME); |
| 367 | if(! $host){ |
| 368 | $ptr = implode(".", array_reverse(explode(".",$IP))) . ".in-addr.arpa"; |
| 369 | $host = @dns_get_record($ptr, DNS_PTR); |
| 370 | if($host == null){ |
| 371 | $host = 'NONE'; |
| 372 | } else { |
| 373 | $host = $host[0]['target']; |
| 374 | } |
| 375 | $db->query("insert into " . $reverseTable . " (IP, host, lastUpdate) values (%s, '%s', unix_timestamp()) ON DUPLICATE KEY UPDATE host='%s', lastUpdate=unix_timestamp()", $IPn, $host, $host); |
| 376 | } |
| 377 | if($host == 'NONE'){ |
| 378 | return ''; |
| 379 | } else { |
| 380 | return $host; |
| 381 | } |
| 382 | } |
| 383 | public static function errorsOff(){ |
| 384 | self::$lastErrorReporting = @ini_get('error_reporting'); |
| 385 | @error_reporting(0); |
| 386 | self::$lastDisplayErrors = @ini_get('display_errors'); |
| 387 | @ini_set('display_errors', 0); |
| 388 | if(class_exists('wfScan')){ wfScan::$errorHandlingOn = false; } |
| 389 | } |
| 390 | public static function errorsOn(){ |
| 391 | @error_reporting(self::$lastErrorReporting); |
| 392 | @ini_set('display_errors', self::$lastDisplayErrors); |
| 393 | if(class_exists('wfScan')){ wfScan::$errorHandlingOn = true; } |
| 394 | } |
| 395 | public static function fileTooBig($file){ //Deals with files > 2 gigs on 32 bit systems which are reported with the wrong size due to integer overflow |
| 396 | wfUtils::errorsOff(); |
| 397 | $fh = @fopen($file, 'r'); |
| 398 | wfUtils::errorsOn(); |
| 399 | if(! $fh){ return false; } |
| 400 | $offset = WORDFENCE_MAX_FILE_SIZE_TO_PROCESS + 1; |
| 401 | $tooBig = false; |
| 402 | if(fseek($fh, $offset, SEEK_SET) === 0){ |
| 403 | if(strlen(fread($fh, 1)) === 1){ |
| 404 | $tooBig = true; |
| 405 | } |
| 406 | } //Otherwise we couldn't seek there so it must be smaller |
| 407 | fclose($fh); |
| 408 | return $tooBig; |
| 409 | } |
| 410 | public static function fileOver2Gigs($file){ |
| 411 | $fh = @fopen($file, 'r'); |
| 412 | if(! $fh){ return false; } |
| 413 | $offset = 2147483647; |
| 414 | $tooBig = false; |
| 415 | if(fseek($fh, $offset, SEEK_SET) === 0){ |
| 416 | if(strlen(fread($fh, 1)) === 1){ |
| 417 | $tooBig = true; |
| 418 | } |
| 419 | } //Otherwise we couldn't seek there so it must be smaller |
| 420 | fclose($fh); |
| 421 | return $tooBig; |
| 422 | } |
| 423 | public static function countryCode2Name($code){ |
| 424 | if(isset(wfCountryMap::$map[$code])){ |
| 425 | return wfCountryMap::$map[$code]; |
| 426 | } else { |
| 427 | return ''; |
| 428 | } |
| 429 | } |
| 430 | public static function extractBareURI($URL){ |
| 431 | $URL = preg_replace('/^https?:\/\/[^\/]+/i', '', $URL); //strip of method and host |
| 432 | $URL = preg_replace('/\#.*$/', '', $URL); //strip off fragment |
| 433 | $URL = preg_replace('/\?.*$/', '', $URL); //strip off query string |
| 434 | return $URL; |
| 435 | } |
| 436 | public static function IP2Country($IP){ |
| 437 | if(! (function_exists('geoip_open') && function_exists('geoip_country_code_by_addr'))){ |
| 438 | require_once('wfGeoIP.php'); |
| 439 | } |
| 440 | $gi = geoip_open(dirname(__FILE__) . "/GeoIP.dat",GEOIP_STANDARD); |
| 441 | $country = geoip_country_code_by_addr($gi, $IP); |
| 442 | geoip_close($gi); |
| 443 | return $country ? $country : ''; |
| 444 | } |
| 445 | public static function siteURLRelative(){ |
| 446 | if(is_multisite()){ |
| 447 | $URL = network_site_url(); |
| 448 | } else { |
| 449 | $URL = site_url(); |
| 450 | } |
| 451 | $URL = preg_replace('/^https?:\/\/[^\/]+/i', '', $URL); |
| 452 | $URL = rtrim($URL, '/') . '/'; |
| 453 | return $URL; |
| 454 | } |
| 455 | |
| 456 | } |
| 457 | |
| 458 | |
| 459 | ?> |
| 460 |