You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中验证网络地址与Netmask(CIDR)的匹配性?

Laravel IP地址与子网掩码匹配验证方案

1. 从CIDR字符串提取IP和子网掩码

如果用户输入的是CIDR格式(如192.168.1.100/25),直接分割字符串即可分离IP地址和CIDR前缀;若输入的是点分格式子网掩码(如255.255.255.128),可以转成对应的CIDR前缀:

// 分割CIDR字符串
$cidr = '192.168.1.100/25';
list($ip, $cidrPrefix) = explode('/', $cidr, 2);

// 点分掩码转CIDR前缀
function maskToCidr(string $mask): int
{
    $binaryMask = implode('', array_map(function($octet) {
        return str_pad(decbin((int)$octet), 8, '0', STR_PAD_LEFT);
    }, explode('.', $mask)));
    return strlen(rtrim($binaryMask, '0'));
}

// 示例:将255.255.255.128转为25
$cidrPrefix = maskToCidr('255.255.255.128');

2. 计算有效网络范围

通过IP地址和CIDR前缀,计算网段的起始(网络地址)和结束(广播地址),两者之间的IP即为有效范围:

function getNetworkRange(string $ip, int $cidrPrefix): array
{
    $ipLong = ip2long($ip);
    $maskLong = ~((1 << (32 - $cidrPrefix)) - 1) & 0xFFFFFFFF;
    
    $networkLong = $ipLong & $maskLong;
    $broadcastLong = $networkLong | (~$maskLong & 0xFFFFFFFF);
    
    return [
        'network' => long2ip($networkLong),
        'broadcast' => long2ip($broadcastLong),
        'network_long' => $networkLong,
        'broadcast_long' => $broadcastLong
    ];
}

// 示例:计算192.168.1.100/25的范围
$range = getNetworkRange('192.168.1.100', 25);
// 返回:network=192.168.1.0, broadcast=192.168.1.127

3. Laravel中实现验证逻辑

方法一:自定义可复用验证规则

  1. 生成规则文件:
php artisan make:rule ValidIpForNetmask
  1. 编辑app/Rules/ValidIpForNetmask.php:
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class ValidIpForNetmask implements Rule
{
    protected int $cidrPrefix;

    public function __construct(string $netmask)
    {
        // 自动转换子网掩码格式为CIDR前缀
        if (strpos($netmask, '.') !== false) {
            $this->cidrPrefix = $this->maskToCidr($netmask);
        } else {
            $this->cidrPrefix = (int)ltrim($netmask, '/');
        }
    }

    public function passes($attribute, $value): bool
    {
        $ipLong = ip2long($value);
        if (!$ipLong) return false;

        $maskLong = ~((1 << (32 - $this->cidrPrefix)) - 1) & 0xFFFFFFFF;
        $networkLong = $ipLong & $maskLong;

        // 验证IP与掩码运算后是否等于网段起始地址
        return $ipLong === ($networkLong & $maskLong);
    }

    public function message(): string
    {
        return 'Invalid network address for that netmask';
    }

    private function maskToCidr(string $mask): int
    {
        $binaryMask = implode('', array_map(function($octet) {
            return str_pad(decbin((int)$octet), 8, '0', STR_PAD_LEFT);
        }, explode('.', $mask)));
        return strlen(rtrim($binaryMask, '0'));
    }
}
  1. 在控制器中调用:
public function store(Request $request)
{
    $validated = $request->validate([
        'ip_address' => ['required', 'ip', new ValidIpForNetmask($request->netmask)],
        'netmask' => ['required', 'regex:/^(\/[0-9]{1,2}|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$/'],
    ]);

    // 验证通过后的业务逻辑
}

方法二:在FormRequest中直接处理

如果不需要复用规则,可直接在请求类中添加验证逻辑:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class NetworkRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'ip_address' => 'required|ip',
            'netmask' => ['required', 'regex:/^(\/[0-9]{1,2}|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$/'],
        ];
    }

    public function withValidator($validator)
    {
        $validator->after(function ($validator) {
            $ip = $this->ip_address;
            $netmask = $this->netmask;

            // 转换子网掩码为CIDR前缀
            $cidr = strpos($netmask, '.') !== false 
                ? strlen(rtrim(implode('', array_map(fn($oct) => str_pad(decbin((int)$oct), 8, '0', STR_PAD_LEFT), explode('.', $netmask))), '0'))
                : (int)ltrim($netmask, '/');

            $ipLong = ip2long($ip);
            $maskLong = ~((1 << (32 - $cidr)) - 1) & 0xFFFFFFFF;
            $networkLong = $ipLong & $maskLong;

            if ($ipLong !== ($networkLong & $maskLong)) {
                $validator->errors()->add('ip_address', 'Invalid network address for that netmask');
            }
        });
    }
}

控制器中使用该请求类:

public function store(NetworkRequest $request)
{
    // 验证通过,执行业务逻辑
}

内容的提问来源于stack exchange,提问作者Abid Raheem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 09:40:59