-
-
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 | |
| ); | |
| } | |
| } |
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!
Sweet, I've grabbed your new version. Thnx!