¥
立即购买

PHP表单字段验证生成器

0 浏览
0 试用
0 购买
Dec 10, 2025更新

本提示词专为PHP开发者设计,能够根据指定的表单字段类型生成专业、准确且安全的验证代码。它覆盖了常见的表单验证场景,如邮箱、密码、电话号码等,确保生成的代码符合最佳安全实践和性能标准。通过结构化的输出格式和详细的代码注释,帮助开发者快速集成验证功能,提升开发效率和代码质量。

验证函数定义

<?php
declare(strict_types=1);

/**
 * 严格密码校验(strict)
 *
 * 规则(默认,可通过$options微调):
 * - 长度:12–64
 * - 必须包含:至少1个大写字母、1个小写字母、1个数字、1个符号
 * - 不允许空白字符(空格、制表符、换行等)
 * - 仅允许可打印ASCII字符(0x21–0x7E),避免不可见或易混淆字符
 * - 禁止连续3个及以上相同字符(如:aaa、111)
 * - 禁止常见顺序序列(长度≥4),如:abcd、1234、qwer(含反向序列)
 * - 可选黑名单匹配
 *
 * @param string $password 待验证的密码(不要在入参前对密码进行trim/normalize)
 * @param array{
 *   min_length?: int,
 *   max_length?: int,
 *   require_upper?: bool,
 *   require_lower?: bool,
 *   require_digit?: bool,
 *   require_symbol?: bool,
 *   disallow_whitespace?: bool,
 *   ascii_only?: bool,
 *   max_repeating_run?: int,          // 允许的最大连续重复次数(默认2,表示3连及以上视为违规)
 *   min_sequence_len?: int,           // 序列最小长度(默认4)
 *   blacklist?: string[]              // 直接匹配的黑名单(小写比对)
 * } $options
 *
 * @return array{
 *   valid: bool,
 *   errors: string[],                 // 错误码列表
 *   messages: string[]                // 可直接显示的错误信息(中文)
 * }
 *
 * @throws InvalidArgumentException    // 当$options配置非法时
 */
function validatePasswordStrict(string $password, array $options = []): array
{
    // 1) 读取并规范化校验参数
    $minLen           = $options['min_length']          ?? 12;
    $maxLen           = $options['max_length']          ?? 64;
    $requireUpper     = $options['require_upper']       ?? true;
    $requireLower     = $options['require_lower']       ?? true;
    $requireDigit     = $options['require_digit']       ?? true;
    $requireSymbol    = $options['require_symbol']      ?? true;
    $disallowWS       = $options['disallow_whitespace'] ?? true;
    $asciiOnly        = $options['ascii_only']          ?? true;
    $maxRepeatRun     = $options['max_repeating_run']   ?? 2;
    $minSeqLen        = $options['min_sequence_len']    ?? 4;
    $blacklist        = $options['blacklist']           ?? [];

    // 2) 参数合法性检查(避免错误配置导致绕过)
    if ($minLen < 8 || $maxLen < $minLen || $maxLen > 256) {
        throw new InvalidArgumentException('Invalid length constraints.');
    }
    if ($maxRepeatRun < 1 || $minSeqLen < 3) {
        throw new InvalidArgumentException('Invalid repetition/sequence constraints.');
    }
    if (!is_array($blacklist)) {
        throw new InvalidArgumentException('Blacklist must be an array of strings.');
    }

    // 3) 准备结果容器
    $errors   = [];
    $messages = [];

    // 4) 长度检查(不对密码做trim,避免误改用户输入)
    $len = strlen($password);
    if ($len < $minLen) {
        $errors[]   = 'length_short';
        $messages[] = "密码长度不能少于{$minLen}个字符。";
    }
    if ($len > $maxLen) {
        $errors[]   = 'length_long';
        $messages[] = "密码长度不能超过{$maxLen}个字符。";
    }

    // 5) 空白字符检查
    if ($disallowWS && preg_match('/\s/', $password) === 1) {
        $errors[]   = 'whitespace_found';
        $messages[] = '密码不能包含空白字符(空格、制表符、换行等)。';
    }

    // 6) ASCII可打印字符限制(0x21-0x7E,排除空格)
    if ($asciiOnly && preg_match('/^[\x21-\x7E]+$/', $password) !== 1) {
        $errors[]   = 'not_ascii_printable';
        $messages[] = '密码仅允许使用可打印ASCII字符(不含空格)。';
    }

    // 7) 复杂度类别检查
    if ($requireUpper && preg_match('/[A-Z]/', $password) !== 1) {
        $errors[]   = 'missing_upper';
        $messages[] = '至少包含1个大写字母。';
    }
    if ($requireLower && preg_match('/[a-z]/', $password) !== 1) {
        $errors[]   = 'missing_lower';
        $messages[] = '至少包含1个小写字母。';
    }
    if ($requireDigit && preg_match('/\d/', $password) !== 1) {
        $errors[]   = 'missing_digit';
        $messages[] = '至少包含1个数字。';
    }
    // 针对ASCII符号更精确的范围:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
    if ($requireSymbol && preg_match('/[!"#$%&\'()*+,\-\.\/:;<=>?@\[\\\\]^_`{|}~]/', $password) !== 1) {
        $errors[]   = 'missing_symbol';
        $messages[] = '至少包含1个符号字符(如 !@#\$%^&* 等)。';
    }

    // 8) 连续重复字符检查(如:aaa、111)
    if ($maxRepeatRun >= 1) {
        $pattern = '/(.)\1{' . $maxRepeatRun . ',}/'; // 连续>= maxRepeatRun+1
        if (preg_match($pattern, $password) === 1) {
            $errors[]   = 'repeated_chars';
            $messages[] = "不允许出现连续超过" . $maxRepeatRun . "个相同字符的片段。";
        }
    }

    // 9) 序列检查(字母、数字、键盘序列,含反向;长度>= $minSeqLen)
    if (containsForbiddenSequence($password, $minSeqLen)) {
        $errors[]   = 'sequential_chars';
        $messages[] = "不允许出现长度≥{$minSeqLen}的顺序或键盘序列(例如 abcd、1234、qwer)。";
    }

    // 10) 黑名单直匹配(使用小写比对)
    if (!empty($blacklist)) {
        $passLower = strtolower($password);
        foreach ($blacklist as $bad) {
            if (!is_string($bad)) continue;
            if ($passLower === strtolower($bad)) {
                $errors[]   = 'blacklisted';
                $messages[] = '密码过于常见或存在泄露风险,请更换。';
                break;
            }
        }
    }

    return [
        'valid'    => count($errors) === 0,
        'errors'   => $errors,
        'messages' => $messages,
    ];
}

/**
 * 检测是否包含常见顺序序列或键盘序列的子串。
 * - 字母:abcdefghijklmnopqrstuvwxyz(及反向)
 * - 数字:0123456789(及反向)
 * - 键盘行:qwertyuiopasdfghjklzxcvbnm(及反向)
 */
function containsForbiddenSequence(string $password, int $minSeqLen = 4): bool
{
    if ($minSeqLen < 3) {
        $minSeqLen = 3; // 安全下限
    }
    $p = strtolower($password);

    // 序列基准
    $sequences = [
        'abcdefghijklmnopqrstuvwxyz',
        '0123456789',
        'qwertyuiopasdfghjklzxcvbnm',
    ];

    foreach ($sequences as $seq) {
        if (hasSubsequence($p, $seq, $minSeqLen)) {
            return true;
        }
        $rev = strrev($seq);
        if (hasSubsequence($p, $rev, $minSeqLen)) {
            return true;
        }
    }
    return false;
}

/**
 * 判断字符串$p中是否包含序列$seq的任意长度>=minLen的连续片段。
 */
function hasSubsequence(string $p, string $seq, int $minLen): bool
{
    $seqLen = strlen($seq);
    for ($l = $minLen; $l <= $seqLen; $l++) {
        for ($i = 0; $i <= $seqLen - $l; $i++) {
            $sub = substr($seq, $i, $l);
            if ($sub !== '' && strpos($p, $sub) !== false) {
                return true;
            }
        }
    }
    return false;
}

核心验证逻辑

  • 长度验证:拒绝小于最小长度或超过最大长度的密码。
  • 字符集验证:
    • 可选限制为可打印ASCII(0x21–0x7E),避免空格及不可见字符引发存储/显示问题。
    • 可选禁用所有空白字符。
  • 复杂度检查:分别确保至少包含1个大写、1个小写、1个数字、1个符号。
  • 重复字符检查:拒绝连续超过指定次数(默认>2)的相同字符片段。
  • 序列检查:拒绝常见顺序(字母、数字)与键盘序列(qwerty…)及其反向,长度≥4即视为违规。
  • 黑名单检查:支持对已知常见或泄露密码进行直接匹配拦截(区分大小写前先统一为小写进行比较)。

返回值说明

  • valid: 布尔值。true 表示通过所有校验;false 表示至少存在一项违规。
  • errors: 错误码数组,用于程序内分支处理(例如 i18n)。
    • 可能的错误码:length_short, length_long, whitespace_found, not_ascii_printable, missing_upper, missing_lower, missing_digit, missing_symbol, repeated_chars, sequential_chars, blacklisted
  • messages: 面向用户的中文提示数组,可直接展示或拼接后展示。

使用示例(后端集成)

<?php
declare(strict_types=1);

// 示例黑名单(可替换为更完整的列表或来源于配置/数据库)
$commonPasswords = [
    'password', '123456', '123456789', 'qwerty', '111111', '123123', 'abc123', 'password1'
];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 服务器端不要trim密码,原样读取
    $password = $_POST['password'] ?? '';

    $result = validatePasswordStrict($password, [
        'min_length'          => 12,
        'max_length'          => 64,
        'require_upper'       => true,
        'require_lower'       => true,
        'require_digit'       => true,
        'require_symbol'      => true,
        'disallow_whitespace' => true,
        'ascii_only'          => true,
        'max_repeating_run'   => 2,
        'min_sequence_len'    => 4,
        'blacklist'           => $commonPasswords,
    ]);

    if (!$result['valid']) {
        // 返回422并输出错误信息(JSON示例)
        http_response_code(422);
        header('Content-Type: application/json; charset=UTF-8');
        echo json_encode([
            'ok'       => false,
            'errors'   => $result['errors'],
            'messages' => $result['messages'],
        ], JSON_UNESCAPED_UNICODE);
        exit;
    }

    // 通过校验,安全哈希存储(不要明文存储)
    // PASSWORD_DEFAULT 在当前PHP版本会选择安全算法(如 Argon2id 或 Bcrypt)
    $hash = password_hash($password, PASSWORD_DEFAULT);

    // 持久化$hash到数据库...
    // 示例响应:
    header('Content-Type: application/json; charset=UTF-8');
    echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
    exit;
}

使用示例(前端校验:HTML + JS)

说明:

  • 前端仅用于提升用户体验,后端校验必须保留且为最终裁决。
  • pattern 与 JS 实时校验与后端规则尽量一致,但正则能力有限,仍以后端为准。
<form id="signup" method="post" action="/register">
  <label for="password">密码(12–64位,含大小写、数字、符号)</label>
  <input
    type="password"
    id="password"
    name="password"
    inputmode="text"
    minlength="12"
    maxlength="64"
    autocomplete="new-password"
    required
    pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!&quot;#$%&'()*+,\-\.\/:;<=>?@\[\\\]\^_`{|}~])(?!.*\s)[\x21-\x7E]{12,64}$"
    aria-describedby="pwd-help"
  />
  <div id="pwd-help">
    <ul id="pwd-rules">
      <li data-rule="len">长度 12–64</li>
      <li data-rule="lower">至少1个小写字母</li>
      <li data-rule="upper">至少1个大写字母</li>
      <li data-rule="digit">至少1个数字</li>
      <li data-rule="symbol">至少1个符号</li>
      <li data-rule="space">不包含空白字符</li>
      <li data-rule="repeat">不出现≥3个连续相同字符</li>
      <li data-rule="sequence">不包含 abcd/1234/qwer 等序列</li>
    </ul>
  </div>
  <button type="submit">提交</button>
</form>

<script>
(function () {
  const input = document.getElementById('password');
  const rules = {
    len:      v => v.length >= 12 && v.length <= 64,
    lower:    v => /[a-z]/.test(v),
    upper:    v => /[A-Z]/.test(v),
    digit:    v => /\d/.test(v),
    symbol:   v => /[!"#$%&'()*+,\-\.\/:;<=>?@\[\\\]\^_`{|}~]/.test(v),
    space:    v => !/\s/.test(v),
    ascii:    v => /^[\x21-\x7E]*$/.test(v),
    repeat:   v => !/(.)\1{2,}/.test(v),
    sequence: v => containsSequence(v.toLowerCase(), 4) === false
  };

  const li = Object.fromEntries(
    Array.from(document.querySelectorAll('#pwd-rules li'))
      .map(el => [el.getAttribute('data-rule'), el])
  );

  function containsSequence(p, minLen) {
    const seqs = [
      'abcdefghijklmnopqrstuvwxyz',
      '0123456789',
      'qwertyuiopasdfghjklzxcvbnm'
    ];
    const hasSub = (s, seq, l) => {
      for (let len = l; len <= seq.length; len++) {
        for (let i = 0; i <= seq.length - len; i++) {
          const sub = seq.slice(i, i + len);
          if (sub && s.includes(sub)) return true;
        }
      }
      return false;
    };
    for (const seq of seqs) {
      if (hasSub(p, seq, minLen)) return true;
      const rev = seq.split('').reverse().join('');
      if (hasSub(p, rev, minLen)) return true;
    }
    return false;
  }

  function updateUI() {
    const v = input.value;
    for (const [k, fn] of Object.entries(rules)) {
      const ok = fn(v);
      const el = li[k];
      if (!el) continue;
      el.style.color = ok ? '#2e7d32' : '#c62828';
      el.style.textDecoration = ok ? 'none' : 'none';
      el.textContent = el.textContent.replace(/^✅|^❌/,'').trim();
      el.textContent = (ok ? '✅ ' : '❌ ') + el.textContent;
    }
    // 将ASCII限制也纳入评估,但不在列表单独展示
    input.setCustomValidity(
      rules.len(v) && rules.lower(v) && rules.upper(v) &&
      rules.digit(v) && rules.symbol(v) && rules.space(v) &&
      rules.repeat(v) && rules.sequence(v) && rules.ascii(v)
        ? ''
        : '密码不符合复杂度要求'
    );
  }

  input.addEventListener('input', updateUI);
  updateUI();
})();
</script>

说明:

  • pattern 使用了前瞻实现基本复杂度校验,但不同浏览器对正则特性的支持可能略有差异,因此用 JS 辅助实时校验,并始终以服务端校验为准。
  • 为与后端一致,JS 同步检查了 ASCII、空白、重复、序列等规则。

注意事项

  • 不要在后端对密码进行 trim 或大小写转换;保持用户原始输入进行校验与哈希。
  • 仅依赖前端校验不安全。必须保留服务端校验作为最终判定。
  • 存储密码应使用 password_hash(PASSWORD_DEFAULT),验证用 password_verify;不要自行设计哈希算法或存储明文。
  • 若业务允许非ASCII密码(提升可记忆度与熵),可将 ascii_only 设为 false,但需确保数据库/显示层完整支持UTF-8并避免归一化问题。
  • 建议引入服务端的“已泄露密码”检查(例如采用 k-匿名 HIBP API 的前缀查询方式),但请注意网络超时与隐私保护;本示例未直接调用外部服务。
  • 错误提示建议与速率限制(rate limit)结合,防止枚举与暴力尝试。
  • 提交表单时,确保全程HTTPS,防止传输中被窃听或篡改。
  • 如加入“确认密码”字段,比较时直接使用严格相等(===),无需做时序防护,但仍需后端校验一致性。

1) 验证函数定义

<?php
declare(strict_types=1);

/**
 * 标准强度的邮箱验证(后端)
 *
 * 功能概要:
 * - 去除首尾空白,拒绝控制字符(防邮件头注入)
 * - 拆分本地部分(local)与域名(domain)
 * - 可选:将国际化域名(IDN)转换为ASCII(Punycode)
 * - 基础长度检查(总长/本地部分/域名/域名标签)
 * - 基础格式检查(点号位置、域名标签字符、必须含点)
 * - 使用 filter_var 进行RFC兼容的邮箱格式校验
 * - 可选:MX记录检查(需网络与DNS)
 *
 * @param string $rawEmail 表单原始输入的邮箱
 * @param array{
 *   allowIDN?: bool,          // 是否允许并转换国际化域名,默认 true
 *   requireMX?: bool,         // 是否要求域名存在MX记录,默认 false
 *   maxLength?: int,          // 邮箱总长度上限,默认 254
 *   lowercaseDomain?: bool    // 域名是否统一转小写,默认 true
 * } $options
 *
 * @return array{
 *   valid: bool,              // 验证是否通过
 *   value: ?string,           // 规范化后的邮箱(通过时返回)
 *   error: ?string,           // 错误信息(失败时返回)
 *   code: string              // 错误/成功代码,便于程序分支处理
 * }
 */
function validateEmail(string $rawEmail, array $options = []): array
{
    $opts = array_merge([
        'allowIDN' => true,
        'requireMX' => false,
        'maxLength' => 254,
        'lowercaseDomain' => true,
    ], $options);

    // 1) 规范化输入:去除首尾空白
    $email = trim($rawEmail);

    // 2) 非空检查
    if ($email === '') {
        return ['valid' => false, 'value' => null, 'error' => '邮箱不能为空', 'code' => 'EMPTY'];
    }

    // 3) 拒绝控制字符(包含 \r \n 等,防止邮件头注入)
    if (preg_match('/[\x00-\x1F\x7F]/', $email)) {
        return ['valid' => false, 'value' => null, 'error' => '包含非法控制字符', 'code' => 'CONTROL_CHAR'];
    }

    // 4) 必须恰好一个 @
    if (substr_count($email, '@') !== 1) {
        return ['valid' => false, 'value' => null, 'error' => '邮箱格式不正确', 'code' => 'FORMAT_AT'];
    }

    [$local, $domain] = explode('@', $email, 2);

    // 5) 本地部分/域名非空
    if ($local === '' || $domain === '') {
        return ['valid' => false, 'value' => null, 'error' => '本地部分或域名缺失', 'code' => 'FORMAT_PARTS'];
    }

    // 6) 本地部分长度限制
    if (strlen($local) > 64) {
        return ['valid' => false, 'value' => null, 'error' => '本地部分长度超限', 'code' => 'LENGTH_LOCAL'];
    }

    // 7) 本地部分点号规则:不得首尾为点且不得出现连续点
    if ($local[0] === '.' || substr($local, -1) === '.' || strpos($local, '..') !== false) {
        return ['valid' => false, 'value' => null, 'error' => '本地部分点号位置不合法', 'code' => 'LOCAL_DOT'];
    }

    // 8) 可选:将国际化域名转ASCII(Punycode)
    $asciiDomain = $domain;
    if ($opts['allowIDN'] && function_exists('idn_to_ascii')) {
        $flags = defined('IDNA_DEFAULT') ? IDNA_DEFAULT : 0;
        if (defined('INTL_IDNA_VARIANT_UTS46')) {
            // 兼容旧版PHP:存在变体常量时传入第三参数
            $asciiDomain = idn_to_ascii($domain, $flags, INTL_IDNA_VARIANT_UTS46);
        } else {
            // PHP 8+:使用两参版本
            $asciiDomain = idn_to_ascii($domain, $flags);
        }
        if ($asciiDomain === false) {
            return ['valid' => false, 'value' => null, 'error' => '域名国际化转换失败', 'code' => 'IDN_ERROR'];
        }
    }

    // 9) 域名统一转小写(推荐)
    if ($opts['lowercaseDomain']) {
        $asciiDomain = strtolower($asciiDomain);
    }

    // 10) 域名长度限制
    if (strlen($asciiDomain) > 253) {
        return ['valid' => false, 'value' => null, 'error' => '域名长度超限', 'code' => 'LENGTH_DOMAIN'];
    }

    // 11) 域名标签检查:至少一个点;每个标签1-63字符;仅字母数字和连字符,且不得以连字符开头/结尾
    $labels = explode('.', $asciiDomain);
    if (count($labels) < 2) {
        return ['valid' => false, 'value' => null, 'error' => '域名缺少顶级域', 'code' => 'DOMAIN_DOT'];
    }
    foreach ($labels as $lab) {
        if ($lab === '' || strlen($lab) > 63) {
            return ['valid' => false, 'value' => null, 'error' => '域名标签长度不合法', 'code' => 'DOMAIN_LABEL_LENGTH'];
        }
        if (!preg_match('/^[A-Za-z0-9-]+$/', $lab) || $lab[0] === '-' || substr($lab, -1) === '-') {
            return ['valid' => false, 'value' => null, 'error' => '域名标签格式不合法', 'code' => 'DOMAIN_LABEL_FORMAT'];
        }
    }

    // 12) 组合候选邮箱并进行总长度限制
    $candidate = $local . '@' . $asciiDomain;
    if (strlen($candidate) > $opts['maxLength']) {
        return ['valid' => false, 'value' => null, 'error' => '邮箱总长度超限', 'code' => 'LENGTH_TOTAL'];
    }

    // 13) 使用 filter_var 进行最终格式校验(标准ASCII邮箱)
    if (filter_var($candidate, FILTER_VALIDATE_EMAIL) === false) {
        return ['valid' => false, 'value' => null, 'error' => '邮箱格式不合法', 'code' => 'FORMAT_FILTER'];
    }

    // 14) 可选:MX记录检查(可能耗时,默认关闭)
    if (!empty($opts['requireMX'])) {
        $mxRecords = dns_get_record($asciiDomain, DNS_MX);
        if ($mxRecords === false || $mxRecords === []) {
            return ['valid' => false, 'value' => null, 'error' => '域名无MX记录', 'code' => 'DNS_MX'];
        }
    }

    // 全部通过
    return ['valid' => true, 'value' => $candidate, 'error' => null, 'code' => 'OK'];
}

参数说明:

  • allowIDN:是否将国际化域名转换为Punycode后验证,默认 true
  • requireMX:是否强制检查域名MX记录,默认 false(出于性能与可用性考虑不默认启用)
  • maxLength:邮箱总长度上限,默认 254(常见最大长度)
  • lowercaseDomain:是否将域名部分统一小写(不影响投递),默认 true

2) 核心验证逻辑

  • 输入预处理:trim 去除空白,拒绝任意控制字符(含 CR/LF),防止邮件头注入
  • 结构检查:必须恰好一个 @,且本地部分与域名均非空
  • 本地部分规则:长度≤64,不得首尾为点,且不得连续两个点
  • 域名处理:
    • 可选将IDN转换为ASCII(Punycode),失败即判无效
    • 统一小写(推荐)
    • 总长度≤253,至少包含一个点
    • 每个标签1-63字符,仅字母数字连字符,且不得首尾为连字符
  • 总长度限制:邮箱总长度≤配置的 maxLength(默认254)
  • RFC格式校验:filter_var($email, FILTER_VALIDATE_EMAIL)
  • 可选DNS校验:requireMX 启用时检查 MX 记录

3) 返回值说明

  • 成功:

    • valid = true
    • value = 规范化后的邮箱(域名可能为小写、IDN域名为Punycode)
    • error = null
    • code = "OK"
  • 失败:

    • valid = false
    • value = null
    • error = 明确的错误描述(如“邮箱格式不正确”)
    • code = 机器可读的错误码(如 EMPTY、CONTROL_CHAR、FORMAT_AT、LENGTH_LOCAL、DOMAIN_LABEL_FORMAT、DNS_MX 等)

4) 使用示例

后端(PHP)整合示例:

<?php
require __DIR__ . '/validateEmail.php'; // 如果你将函数单独保存

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $emailInput = $_POST['email'] ?? '';

    $result = validateEmail($emailInput, [
        'allowIDN' => true,
        'requireMX' => false,   // 如需验证MX记录,则设为 true
        'maxLength' => 254,
        'lowercaseDomain' => true,
    ]);

    if ($result['valid']) {
        // 通过验证,使用 $result['value']
        // 注意输出时进行HTML转义
        echo '验证通过:' . htmlspecialchars($result['value'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
        // 后续业务:入库、发送验证邮件等
    } else {
        // 验证失败,返回错误信息
        http_response_code(422); // 语义化状态码(可选)
        echo '验证失败(' . $result['code'] . '):' . htmlspecialchars((string)$result['error'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }
}

前端(HTML + JS)基础校验示例:

<form id="emailForm" method="post" action="">
  <label for="email">邮箱</label>
  <input
    type="email"
    id="email"
    name="email"
    required
    inputmode="email"
    autocomplete="email"
    maxlength="254"
  />
  <button type="submit">提交</button>
</form>

<script>
  (function () {
    const form = document.getElementById('emailForm');
    const email = document.getElementById('email');

    // 实时提示(保持与后端长度限制一致)
    email.addEventListener('input', function () {
      email.setCustomValidity('');
      if (email.value.length > 254) {
        email.setCustomValidity('邮箱长度不能超过254个字符');
      } else if (email.validity.typeMismatch) {
        email.setCustomValidity('请输入有效的邮箱地址');
      }
    });

    form.addEventListener('submit', function (e) {
      if (!email.checkValidity()) {
        e.preventDefault();
        email.reportValidity();
      }
    });
  })();
</script>

说明:

  • 使用 HTML5 原生 type="email" + required + maxlength 进行基础前端校验
  • 通过 JS 的 Constraint Validation API 提供更友好的错误提示
  • 最终数据安全以服务器端验证为准(前端校验可被绕过)

5) 注意事项

  • 前端校验仅作为用户体验优化,必须保留后端验证
  • 严禁直接将用户输入用于邮件头(如“From”)等敏感位置;本函数已阻止控制字符以降低头注入风险
  • 若启用 MX 验证,需考虑网络延迟与可用性(DNS 解析失败并不总代表邮箱不可用)
  • 对于需要支持国际化邮箱本地部分(非ASCII)的场景,应扩展策略(如使用 FILTER_FLAG_EMAIL_UNICODE),但“standard”强度通常保持ASCII本地部分即可
  • 输出到HTML时使用 htmlspecialchars 进行转义
  • 存储前建议统一域名小写,便于比较与查重
  • 如在高并发场景进行MX检查,建议加入缓存或异步处理,避免阻塞请求

以上方案遵循PHP最佳实践,避免使用废弃或不安全函数,验证逻辑清晰、可维护,并包含必要的错误处理与前后端一体化示例。

验证函数定义

<?php
declare(strict_types=1);

/**
 * 基础级别的电话/手机号验证器(后端校验)
 *
 * 规则(basic):
 * - 允许的字符:数字、空格、连字符(-)、点(.)、括号(),以及可选的起始加号(+)
 * - 数字总数需在指定范围内(默认 7 到 15 位)
 * - 加号最多出现一次且只能出现在开头
 * - 括号必须成对出现且不能先出现右括号
 * - 可配置是否必填
 *
 * 返回:
 * [
 *   'valid'  => bool,          // 是否通过验证
 *   'value'  => ?string,       // 归一化后的值(仅包含“+”与数字),未通过或未填写时为 null
 *   'errors' => string[],      // 错误信息列表(便于展示给用户或记录日志)
 * ]
 *
 * @param string $phone 原始输入
 * @param array  $options 可选项:
 *   - required   bool 是否必填,默认 true
 *   - min_digits int  最少数字个数,默认 7
 *   - max_digits int  最多数字个数,默认 15
 *
 * @return array{valid:bool,value:?string,errors:array<int,string>}
 */
function validatePhoneBasic(string $phone, array $options = []): array
{
    $defaults = [
        'required'   => true,
        'min_digits' => 7,
        'max_digits' => 15,
    ];
    $opts = array_merge($defaults, $options);

    $errors = [];

    // 1) 去除首尾空白
    $raw = trim($phone);

    // 2) 必填校验
    if ($raw === '') {
        if ($opts['required'] === false) {
            return [
                'valid'  => true,
                'value'  => null, // 表示“未提供”
                'errors' => [],
            ];
        }
        return [
            'valid'  => false,
            'value'  => null,
            'errors' => ['电话/手机号为必填项。'],
        ];
    }

    // 3) 字符集校验(仅允许:数字、空格、连字符、点、括号、加号)
    if (!preg_match('/^[0-9\+\-\s\(\)\.]+$/', $raw)) {
        $errors[] = '仅允许数字、空格、连字符(-)、点(.)、括号(),以及前导加号(+)。';
    }

    // 4) 加号规则:最多一次且必须在开头
    $plusCount = substr_count($raw, '+');
    if ($plusCount > 1) {
        $errors[] = '加号(+)最多只能出现一次。';
    } elseif ($plusCount === 1 && $raw[0] !== '+') {
        $errors[] = '加号(+)只能出现在号码开头。';
    }

    // 5) 括号基础配对与顺序校验
    $openCount  = substr_count($raw, '(');
    $closeCount = substr_count($raw, ')');
    if ($openCount !== $closeCount) {
        $errors[] = '括号()必须成对出现。';
    } else {
        $firstOpen  = strpos($raw, '(');
        $firstClose = strpos($raw, ')');
        if ($firstClose !== false && ($firstOpen === false || $firstOpen > $firstClose)) {
            $errors[] = '右括号不能在左括号之前出现。';
        }
    }

    // 6) 数字个数范围校验(忽略所有分隔符,仅统计数字)
    $digitsOnly = preg_replace('/\D+/', '', $raw);
    $digitLen   = strlen($digitsOnly);
    if ($digitLen < (int)$opts['min_digits'] || $digitLen > (int)$opts['max_digits']) {
        $errors[] = '号码中的数字个数需在 ' . (int)$opts['min_digits'] . ' 到 ' . (int)$opts['max_digits'] . ' 位之间.';
    }

    // 7) 汇总结果
    if (!empty($errors)) {
        return [
            'valid'  => false,
            'value'  => null,
            'errors' => $errors,
        ];
    }

    // 8) 归一化输出:仅保留起始加号与数字(便于后续存储/比对)
    $normalized = ($raw[0] === '+') ? ('+' . $digitsOnly) : $digitsOnly;

    return [
        'valid'  => true,
        'value'  => $normalized,
        'errors' => [],
    ];
}

核心验证逻辑

  • 去空白:trim 去除首尾空白,防止输入噪声影响判断。
  • 必填控制:可通过 options.required 配置是否必填;为空且非必填则直接通过并返回 null。
  • 字符白名单:仅允许数字、空格、-、.、()、以及前导 +,阻断异常字符注入。
  • 加号规则:+ 最多 1 个且必须出现在开头,避免中间位置的非法格式。
  • 括号检查:左右数量一致且不能先出现右括号,避免明显的格式错误。
  • 数字数量范围:去除分隔符后统计纯数字长度,默认要求 7–15 位。
  • 归一化输出:将所有分隔符移除,仅保留起始 + 与数字,便于后续存储和一致性处理。

返回值说明

  • valid: 布尔值。true 表示验证通过;false 表示验证失败。
  • value: 字符串或 null。通过时为归一化后的电话号码(只包含起始 + 与数字);未提供(且非必填)或失败时为 null。
  • errors: 字符串数组。包含所有未通过原因,便于前端逐条提示或记录日志。

使用示例

<?php
declare(strict_types=1);

// 假设来自 POST 表单
$phoneInput = $_POST['phone'] ?? '';

$result = validatePhoneBasic($phoneInput, [
    'required'   => true, // 该字段必填
    'min_digits' => 7,
    'max_digits' => 15,
]);

if ($result['valid']) {
    // 归一化后的号码,可直接用于持久化存储
    $normalizedPhone = $result['value']; // 如:+8613800138000 或 02188881234

    // 示例:使用参数化语句写入数据库(以 PDO 为例)
    /*
    $stmt = $pdo->prepare('INSERT INTO users (phone) VALUES (:phone)');
    $stmt->execute([':phone' => $normalizedPhone]);
    */

    echo '提交成功,已保存号码:' . htmlspecialchars((string)$normalizedPhone, ENT_QUOTES, 'UTF-8');
} else {
    // 展示第一条错误(或遍历全部错误)
    foreach ($result['errors'] as $msg) {
        echo '<p class="error">' . htmlspecialchars($msg, ENT_QUOTES, 'UTF-8') . '</p>';
    }
}

注意事项

  • 本验证为“基础级别”,旨在拦截明显无效或不安全的输入;不校验具体国家/地区号段、运营商等规则。对强校验需求,可在此基础上引入更严格的号码库或专业库进行二次校验。
  • 建议存储归一化后的号码(仅 “+” 与数字),避免分隔符差异导致重复值难以比对。
  • 后端校验不可替代;即使未来添加前端校验,也应始终保留后端校验逻辑。
  • 输出到页面或日志时,请进行适当的转义(如 htmlspecialchars),防止 XSS。
  • 与数据库交互时使用参数化查询或预处理语句,避免 SQL 注入。
  • 若需要支持分机号、SIP/URI 或特定国家格式,可在当前函数外层增加业务规则或扩展可选项。

示例详情

解决的问题

将表单校验从“重复造轮子、容易出错”的低效工作,升级为“标准化、可复制、可审计”的高质量模块生产。面向PHP开发者与技术团队,通过一次性给出字段类型、验证强度、是否需要前端校验等信息,自动生成严谨、安全、可直接落地的验证代码,并附带清晰注释、调用示例与集成指引。核心目标:显著缩短开发与代码评审时间,降低安全与合规风险,统一团队风格与规范,支持快速复用与扩展,帮助产品更快更稳地上线与迭代。

适用用户

PHP后端开发工程师

一键按字段类型生成验证代码,快速覆盖邮箱、密码、手机号等表单;通过强度选项匹配项目要求,减少手写与低级错误,加速提测与上线。

全栈开发者与个人站长

不必深挖安全细节即可生成可靠校验;几分钟集成到既有项目,显著降低维护成本,减少无效提交,提升站点转化率。

技术负责人/架构师

以统一模板与注释规范输出验证逻辑,推动团队编码一致性;减少安全漏洞与返工,缩短评审时间,便于跨项目复用。

特征总结

按字段类型一键生成验证代码,涵盖邮箱、密码、手机号等常见场景。
内置强度选项自动匹配校验规则,轻松切换基础、严格或企业级安全。
生成易读注释与使用说明,新成员也能即插即用,缩短对接与交付周期。
自动处理格式、长度与特殊字符,减少边界漏测,提升输入数据可靠性。
自带错误提示与返回约定,前后端统一口径,用户体验与排错效率两不误。
可按项目需求定制模板与参数,一键复用到注册、登录、订单等表单。
遵循安全最佳实践,默认规避常见漏洞,减少安全审计与返工风险与成本。
提供可复制示例与集成指引,新老框架均可快速接入,降低学习门槛。
支持可选前端校验,表单提交前即时拦截错误,减少无效请求与服务器压力。
输出结构清晰可维护,方便代码评审与团队协作,长期维护更轻松更稳定。

如何使用购买的提示词模板

1. 直接在外部 Chat 应用中使用

将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。

2. 发布为 API 接口调用

把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。

3. 在 MCP Client 中配置使用

在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。

AI 提示词价格
¥20.00元
先用后买,用好了再付款,超安全!

您购买后可以获得什么

获得完整提示词模板
- 共 535 tokens
- 3 个可调节参数
{ 表单字段类型 } { 验证强度 } { 包含前端验证 }
获得社区贡献内容的使用权
- 精选社区优质案例,助您快速上手提示词
使用提示词兑换券,低至 ¥ 9.9
了解兑换券 →
限时半价

不要错过!

半价获取高级提示词-优惠即将到期

17
:
23
小时
:
59
分钟
:
59