0

The following replaces any IP address with <ip>.

$match = '/[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/';
$replace = '<ip>';
$CurrentText = preg_replace($match, $replace, $CurrentText);

How can I only replace IP addresses that do not start with 192 or 10.

ie. 10.0.0.1 should not be matched, but 11.0.0.1 should.

Joncom
  • 1,985
  • 1
  • 18
  • 29

4 Answers4

4

Try this:

$match = '/(?<!\d)(?!10\.|192\.)\d{1,3}(?>\.\d{1,3}){3}/';
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • Add added a correction to your post and marked it the correct answer. Please accept the edit. EDIT: Disregard, my fix was bad, and your suggestion still does not work. – Joncom Feb 27 '14 at 23:43
  • I have added a lookbehind to ensure we don't start matching in the middle of a number. – Niet the Dark Absol Feb 27 '14 at 23:52
1

Private IP addresses do not work like this, particularly the Class-C private nets 192.168.0.0/16. Perfectly valid public IP addresses can start with 192.

Use something like this:

function ip_is_private ($ip) {
    $pri_addrs = array (
                      '10.0.0.0|10.255.255.255', // single class A network
                      '172.16.0.0|172.31.255.255', // 16 contiguous class B network
                      '192.168.0.0|192.168.255.255', // 256 contiguous class C network
                      '169.254.0.0|169.254.255.255', // Link-local address also refered to as Automatic Private IP Addressing
                      '127.0.0.0|127.255.255.255' // localhost
                     );

    $long_ip = ip2long ($ip);
    if ($long_ip != -1) {

        foreach ($pri_addrs AS $pri_addr) {
            list ($start, $end) = explode('|', $pri_addr);

             // IF IS PRIVATE
             if ($long_ip >= ip2long ($start) && $long_ip <= ip2long ($end)) {
                 return true;
             }
        }
    }

    return false;
}

From: https://stackoverflow.com/a/13818126/1064767

Community
  • 1
  • 1
Sammitch
  • 30,782
  • 7
  • 50
  • 77
1
// test string
$string = '192.168.1.1,10.0.0.1,1.2.3.4,BAD:256.257.258.259';
// first must be between 1-255
$npf = '([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])';
// next must be between 0-255
$npn = '([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])';
// ip has to be bordered by \b regex to be valid
$pattern = "~\\b{$npf}\\.{$npn}\\.{$npn}\\.{$npn}\\b~s";
// replace with a callback
$string = preg_replace_callback($pattern, function($match){
    // play with them as you wish
    $ip = $match[0];
    $match1 = intval($match[1]);
    if(in_array($match1, array(10, 192))){
        return $ip;
    }
    return '<ip>';
}, $string);
// clean up
unset($npf, $npn);
// output string
var_dump($string);

Code is commented, should make sense.

BONUS:

These are the private IP ranges.

$private_ranges = array(
    // 10.0.0.1 to 10.255.255.254
    ip2long('10.0.0.0') => ip2long('10.255.255.255'),
    // 172.16.0.1 to 172.31.255.254
    ip2long('172.16.0.0') => ip2long('172.31.255.255'),
    // 192.168.0.1 to 192.168.255.254
    ip2long('192.168.0.0') => ip2long('192.168.255.255'),
     // 127.0.0.0 to 127.255.255.255
    ip2long('127.0.0.0') => ip2long('127.255.255.255'),
);

Use them in an array with ip2long() against $match[0] for better hit testing.

CodeAngry
  • 12,760
  • 3
  • 50
  • 57
0

With some fancy preg_replace_callback() to make it more understandable:

$ip = "192.168.1.1";
$match = '/[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/';
$replace = '<ip>';

$ip = preg_replace_callback($match, function($matches) use ($replace) { //Run this function every time there's a match. Bring $replace from the outside.
    $first = array_shift(explode(".", $matches[0])); //Get first segment of the IP
    if (!in_array($first, ["192", "10"])) { //If the segment isn't 192 or 10
        return $replace; //Return the replacement (<ip>)
    }
    return $matches[0]; //Else, return the IP unchanged.
}, $ip);

echo $ip;
Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308