Gform_validation with preg_match for IP addresses Not Working. Help! :) [RESOLVED]

Hi there,

I’m using gform_validation to make sure a user is entering the following range of IP Addresses:

127.  0.0.0 – 127.255.255.255     127.0.0.0 /8
10.  0.0.0 –  10.255.255.255      10.0.0.0 /8
172. 16.0.0 – 172. 31.255.255    172.16.0.0 /12
192.168.0.0 – 192.168.255.255   192.168.0.0 /16

My script seems to work fine if I use the patterns individually (see below), but not if they are combined. I used https://www.regextester.com and https://www.functions-online.com/preg_match.html and it appears that the preg_match patterns are correct in either case.

I also tried including each pattern in an elseif conditional. But nothing I tried works reliably (unless I just use a single pattern).

I would appreciate any help…

function validate_private_ip($private_ip) {
  $private_ip = trim($private_ip);

  // The four patterns I'm trying to combine, which work fine individually...
  
  // $pattern = "(^10\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)";
  // $pattern = "(^127\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)";
  // $pattern = "(^172\.16\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)";
  // $pattern = "(^192\.168\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)";

  // All 4 patterns...
  $pattern = "(^10\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])|^127\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])|^172\.16\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])|^192\.168\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)";

  if ( ! preg_match( $pattern, $private_ip ) ) {
      return false;
  }
  return true;
}

function trgr_order_private_ip_validation( $validation_result ) {
  $form = $validation_result['form'];

    foreach( $form['fields'] as &$field ) {
      // check for fields with this class (added via GravityForms)
      if ( strpos( $field->cssClass, 'order-private-ip-validate' ) === false ) {
        continue;
      }
      $field_value = rgpost( "input_{$field['id']}" );
      $is_valid = validate_private_ip( $field_value );
      if ( $is_valid ) {
        continue;
      }
      $validation_result['is_valid'] = false;
      $field->failed_validation = true;
      $field->validation_message = 'Invalid entry. Must be:<br>10.0.0.0 thru 10.255.255.255;<br>127.0.0.0 thru 127.255.255.255;<br>172.16.0.0 thru 172.31.255.255; or<br>192.168.0.0 thru 192.168.255.255. ';
    }

  $validation_result['form'] = $form;
  return $validation_result;

}
add_filter( 'gform_validation_5', 'trgr_order_private_ip_validation' );

Can you share the version with the if/else statements? I think that would be easiest to troubleshoot. Or you could simplify it with a switch/case statement as well.

Yes indeed! In this case, I’m just trying to get 2 of the patterns to work together. Thank you!

function validate_ip($ip) {
$ip = trim($ip);
$pattern_1 = "(^10\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)";
$pattern_2 = "(^127\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)";

if ( ! preg_match( $pattern_1, $ip ) ) {
  return false;
} elseif ( ! preg_match( $pattern_2, $ip ) ) {
  return false;
}
return true;
}

function trgr_order_ip_validation( $validation_result ) {
  $form = $validation_result['form'];

foreach( $form['fields'] as &$field ) {
  // check for fields with this class (added via GravityForms)
  if ( strpos( $field->cssClass, 'trgr-order-private-ip-validate' ) === false ) {
    continue;
  }
  $field_value = rgpost( "input_{$field['id']}" );
  $is_valid = validate_ip( $field_value );
  if ( $is_valid ) {
    continue;
  }
  $validation_result['is_valid'] = false;
  $field->failed_validation = true;
  $field->validation_message = 'Invalid entry. Must be:<br>10.0.0.0 thru 10.255.255.255;<br>127.0.0.0 thru 127.255.255.255;<br>172.16.0.0 thru 172.31.255.255; or<br>192.168.0.0 thru 192.168.255.255. ';
}

  $validation_result['form'] = $form;
  return $validation_result;

}

add_filter( 'gform_validation_7', 'trgr_order_ip_validation' );

Summarizing: you want to ensure the IP address is from a private range. So you need to ensure the address IS in one of the ranges in order to pass validation. But you are testing with the first range and returning false is it’s not in the 24-bit block (10.0.0.0 – 10.255.255.255). But that would be inaccurate, since it might be a different private IP address range (i.e. the 20 or 16 bit block.) I think you have to test them all, and if the submitted IP does not match anything, THEN return false; not return false when the first pattern fails to match. Something like this:

if ( !preg_match($p1, $private_ip) && !preg_match($p2, $private_ip) && !preg_match($p3, $private_ip) && !preg_match($p1, $private_ip) ){
	return false;
}

If I have that right, that says:

IF not a match with pattern one 
    AND not a match with pattern two 
    AND not a match with pattern three 
    AND not a match with pattern four 
THEN return false

See if we are on the right track.

Yup-- that seems to have done the trick. Thanks again Chris!

1 Like

Awesome - thank you for the update.