-
-
Save miken32/f402317ce71bf7156e4a4a645e6a500b to your computer and use it in GitHub Desktop.
<?php | |
namespace App\Rules; | |
use Closure; | |
use Illuminate\Contracts\Validation\ValidationRule; | |
use const FILTER_FLAG_IPV4; | |
use const FILTER_FLAG_IPV6; | |
use const FILTER_VALIDATE_INT; | |
use const FILTER_VALIDATE_IP; | |
class Cidr implements ValidationRule | |
{ | |
/** @var bool whether or not the rule has been called with network constraints */ | |
private bool $has_bits; | |
/** | |
* @param int|null $ipv4minbits The minimum number of bits allowed in an IPv4 network | |
* @param int|null $ipv4maxbits The maximum number of bits allowed in an IPv4 network | |
* @param int|null $ipv6minbits The minimum number of bits allowed in an IPv6 network | |
* @param int|null $ipv6maxbits The maximum number of bits allowed in an IPv6 network | |
*/ | |
public function __construct( | |
public ?int $ipv4minbits = null, | |
public ?int $ipv4maxbits = null, | |
public ?int $ipv6minbits = null, | |
public ?int $ipv6maxbits = null, | |
) | |
{ | |
$this->has_bits = func_num_args() > 0; | |
} | |
/** | |
* @param string $attribute The attribute being validated | |
* @param mixed $value The current value of the attribute | |
* @param Closure $fail Closure to be run in case of failure | |
* @return void | |
*/ | |
public function validate(string $attribute, mixed $value, Closure $fail): void | |
{ | |
$mask = null; | |
$valid_mask = true; | |
if (str_contains($value, "/")) { | |
[$value, $mask] = explode("/", $value); | |
} elseif ($this->has_bits) { | |
// if we specify a bit constraint, assume the bits are required | |
$fail($this->message()); | |
} | |
if (str_contains($value, ":")) { | |
// ipv6 | |
if ($mask !== null) { | |
$valid_mask = filter_var( | |
$mask, | |
FILTER_VALIDATE_INT, | |
["options" => ["min_range" => $this->ipv6minbits ?? 0, "max_range" => $this->ipv6maxbits ?? 128]] | |
); | |
} | |
$valid_address = filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); | |
} else { | |
// ipv4 | |
if ($mask !== null) { | |
$valid_mask = filter_var( | |
$mask, | |
FILTER_VALIDATE_INT, | |
["options" => ["min_range" => $this->ipv4minbits ?? 0, "max_range" => $this->ipv4maxbits ?? 32]] | |
); | |
if ($valid_mask) { | |
$long = ip2long($value); | |
$mask = -1 << (32 - $mask); | |
$valid_mask = long2ip($long & $mask) === $value; | |
} | |
} | |
$valid_address = filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); | |
} | |
if (!$valid_address || !$valid_mask) { | |
$fail($this->message()); | |
} | |
} | |
public function message(): string | |
{ | |
return !$this->has_bits | |
? __("The :attribute must be a valid IP address or CIDR subnet.") | |
: sprintf( | |
__("The :attribute must be a valid CIDR subnet with a mask of %d-%d (IPv4) or %d-%d (IPv6) bits."), | |
$this->ipv4minbits ?? 0, | |
$this->ipv4maxbits ?? 32, | |
$this->ipv6minbits ?? 0, | |
$this->ipv6maxbits ?? 128 | |
); | |
} | |
} |
@miken32 I've updated this class for Laravel 10.x (new ValidationRule contract) and PHP 8.1 (str_contains()) .. are you interested in having this to update?
@jonnott nah, I've updated months ago in our project, just didn't remember I'd posted this here.
@jonnott nah, I've updated months ago in our project, just didn't remember I'd posted this here.
Sweet, I've grabbed your new version. Thnx!
Appreciate this, I've used the basis but have a version/rule to check if an IP is in one or more CIDR subnets, not sure if it'd be useful to chuck a link on here or if you'd find that useful.
I think this could be cool as a little package like https://github.com/Propaganistas/Laravel-Phone
@miken32 would you be up for collab on this? i.e. if I turned it into a similar package + co-maintain .. ?
how is it going to put it into a repo guys?
how is it going to put it into a repo guys?
Are you keen for a package then?
how is it going to put it into a repo guys?
Are you keen for a package then?
sure
wait did we move anywhere with a repo? @miken32 since you are the author that would makes sense for you to do it...
Yeah I can do that @justasSendrauskas give me a couple of days
@justasSendrauskas @jonnott @lrljoe I put up a package miken32/network-rules
if you want to have a look. Consolidated a bunch of one-off code I was using internally and added a bunch of new validations as well. Still marked as pre-release for now.
@miken32 brilliant! thank you very much
Very excited for this!
Thanks! you saved me a lot of time. 🚀