POST locks the script and does not execute the code after submitting the form

0

I have a problem at hand. I have a credit card form, where the customer will fill out the data and be submitted to the bank's evaluation. However, it should run some operations before from reaching the function that will send its data to the payment gateway. I will illustrate a step by step of what should be happening:

  • User fills in card details;
  • Send the form;
  • Get the answer "Please wait, analyzing data";
  • User receives "Approved Payment" or "Payment Denied";
  • But step 3 is not running at all. Here's my code:

    $('#credit_card_form').submit(function() {
        $.post($("#credit_card_form").attr('action'), $("#credit_card_form").serialize(), function(data){
            $("#retorno_form").html(data);
        }); 
        return false;
    });
    

    POST is treated here:

    if ($_POST['f'] == 'pay_credit_card') {
        $bandeira_cartao = $_POST['card_brand'];
        $numero_cartao = $_POST['card_number'];
        $vecto_mes = $_POST['card_valid_month'];
        $vecto_ano = $_POST['card_valid_year'];
        $cod_seguranca = $_POST['card_security'];
        $nome_cartao = $_POST['card_name'];
    
        if ($_POST['card_number'] == '') {
            echo "Preencha o campo X"
            return false;
        }
    
        // d_none = display: none;
        echo "<script>$('#aviso_carregando_cartao').removeClass('d_none'); $('#div_formulario_cartao').addClass('d_none');</script>";
        $retorno_pagamento = CS_MundiPagg($bandeira_cartao, $numero_cartao, $vecto_mes, $vecto_ano, $cod_seguranca, $nome_cartao);
        if ($retorno_pagamento == 'Captured') {     
            echo "<script>$('#sucesso_cartao').removeClass('d_none'); $('#modal-close').addClass('d_none');</script>";
        }
    }
    

    It happens that it already passes the "echo" above CS_MundiPagg () and goes straight to the answer, at the end of the script. As if it "locked" the script after the user submitted the form and brought only the final answer (payment approved or not).

    I've tried almost everything, I'm not finding a solution. Is there hope at the end of the tunnel?

        
    asked by anonymous 15.05.2017 / 16:26

    2 answers

    1

    If you pass right through it is because the conditional does not return true.

    In addition, it is a very weak, inconsistent, and redundant conditional.

    It is inconsistent because it does not validate the input. It just checks if it is equal to empty and then stops. This means that if the user types an empty space or anything invalid, the validation will pass.

    You are also just making a cursory check of the card number and leaving other parameters untreated. At a minimum you should also check the month, year and code.

    Redundancy is in the misuse of variables. Declare and assign variables that are not even used.

    $bandeira_cartao = $_POST['card_brand'];
    $numero_cartao = $_POST['card_number'];
    $vecto_mes = $_POST['card_valid_month'];
    $vecto_ano = $_POST['card_valid_year'];
    $cod_seguranca = $_POST['card_security'];
    $nome_cartao = $_POST['card_name'];
    

    Then it does:

    if ($_POST['card_number'] == '') {
    

    And at no time did you use any of the above variables.

    Check with isset() if each parameter exists.

    After this, make the appropriate validations for each one.

    Below is an example for the credit card number:

    function numbers_only($str, $exception = '')
    {
        return preg_replace('#[^0-9'.$exception.']#', '', mb_convert_kana($str, 'n'));
    }
    
    $c = 'card_number';
    if (isset($_POST[$c])) {
        $numero_cartao = trim($_POST[$c]);
    
        // Verifica se não está vazio
        if (empty($numero_cartao)) {
            echo 'Número do cartão não pode ser vazio';
            exit;
        }
    
        // Sanitiza removendo tudo que não for numérico
        // Sanitizar é opcional. Depende da política da sua empresa.
        $s = numbers_only($s);
    
        // Verifica a qunatidade de caracteres. A anatomia de um cartão é mínimo 12 e máximo 19. Note que esse padrão varia de acordo com a operadora e pode surgir uma nova operadora com padrão que modifique essa regra.
        $s = strlen($numero_cartao);
        if ($s < 12 || $s > 19) {
            echo 'Número do cartão é inválido';
            exit;
        }
    }
    

    It's a pretty simple example, but it's the least you can do.

    For the other fields, follow the same logic. The month and year fields check the entry if it is not empty and whether it is numeric. After that verify that the date is valid.

    A minimum check also in the name field is always good to do.

    And to save a request to the gateway, you can also detect by the number which the card operator is and thus create a validation rule for the security code since each carrier has a format. This item is not required. It would only be to refine the system and avoid unnecessary requests to the gateway.

    You can actually send the data without any processing, because the gateway API will do the validations anyway. This is acting in bad faith and in a sense it's stupid.

    The validations are to avoid unnecessary requests, as commented above and also important for UX (user experience). The user gets annoyed when he waits for a request and receives an error. Depending on the case, you even give up the purchase.
    It is smarter to handle common and predictable errors, avoiding requests that cost time and processing. The ideal is to already treat this data with JavaScript and for precaution, ALWAYS must treat in the backend (PHP).

        
    15.05.2017 / 16:45
    0

    I recommend you pass this part of the code to javascript / jquery, using $.ajax() instead of $.post() :

    $.ajax({
        type: "POST",
        url: $("#credit_card_form").attr('action'),
        data: $("#credit_card_form").serialize(),
        dataType: 'json',
        beforeSend: function(){
            $('#aviso_carregando_cartao').removeClass('d_none');
            $('#formulario_cartao').addClass('d_none');
        },
        complete: function(){
            $('#aviso_carregando_cartao').addClass('d_none');
            $('#formulario_cartao').removeClass('d_none');
        },
        success: function(html){
           if(html.success)
           {
             $('#sucesso_cartao').removeClass('d_none');
             $('#modal-close').addClass('d_none');
           }
           else
           {
             $("#retorno_form").html(html.errormsg);
           }
        }
    });
    

    and your PHP would look something like this:

    if ($_POST['f'] == 'pay_credit_card') {
        $bandeira_cartao = $_POST['card_brand'];
        $numero_cartao = $_POST['card_number'];
        $vecto_mes = $_POST['card_valid_month'];
        $vecto_ano = $_POST['card_valid_year'];
        $cod_seguranca = $_POST['card_security'];
        $nome_cartao = $_POST['card_name'];
        $status = ['success' => false, 'errormsg' => ''];
    
        if ($_POST['card_number'] == '') {
            $status['success'] = false;
            $status['errormsg'] = "Preencha o campo X";
            echo json_encode($status);
            return false;
        }
    
        $retorno_pagamento = CS_MundiPagg($bandeira_cartao, $numero_cartao, $vecto_mes, $vecto_ano, $cod_seguranca, $nome_cartao);
        if ($retorno_pagamento == 'Captured') {
            $status['success'] = true;
            echo json_encode($status);
        }
    }
    

    I did not test the code, but see if it works.

        
    15.05.2017 / 16:54