无需提交两次表单即可重用代码

4
这是关于在我的网站上实现“删除账户”功能的内容。
如果用户请求删除他的账户(需要3天时间删除完整数据)并在这3天内尝试登录,我们需要询问确认,如果您已经登录,则账户将被启用。
为此,我使用以下代码。
 $('#loginform').on('submit',function(e) {
   var t = $(this);

   $.post('/login.php', t.serialize(), function(data) {
     if(data.error.length) {
       $('.login_result', t).html(data.result).slideDown();

     } else if(data.result == 'waiting_for_deletion') {
       jconfirm('Account will be enabled if you login',
          function(is_confirmed) {
            if(is_confirmed) {                            
               $('input:hidden[name="loginform"]').val('confirm_reactivation');
               ('#loginform').submit();
             }
          } ,
          'Yes', 'Cancel');
         } else {
            location.href = '/accounts';
         }
  }, 'json')
});

如果用户输入了正确的详细信息(电子邮件和密码),将要求确认,如果确认后,我将使用新的输入字段值重新提交表单。

我想知道如何在不重复提交表单的情况下重用我的PHP代码?

或者我可以在第一个ajax调用中再使用一个ajax调用吗?(我认为不可能)。

同时,它不应该影响正常登录

// 编辑过的

这是我的PHP代码

login.php

if(isset($_POST['loginform'])) {

    $email = trim(mb_strtolower($_POST['email']));
    $password = $_POST['upw'];


    if (empty($email)) {
        $error['#email'] = 'Wrong mail';
    }
    validate('password', $password, $error['#password']);

    // check for correct password now
    if(!$error) {

        $data = query_execute("SELECT * FROM users WHERE email='".sqlescape($email)."' LIMIT 1");

        if(!$data) {
            $error['#email'] = 'Account not exists';

        } elseif(!$data['active'] && !(int)$data['validated']) {
            $error['error'] = 'Account not validated';

        } elseif(!$data['password'] || !check_password($password, $data['password'], $data['userid'])) {
            $error['#password'] = 'Wrong password';

        // ----------------------------------------------
        // OK, ALL FINE! USER COULD LOGIN
        // ----------------------------------------------
        } else {

           $confirmation = $_POST['loginform'] == 'confirm_reactivation' ? true : false;

            $Delete_Accounts = query_execute("SELECT * FROM deleteacoount WHERE email='".sqlescape($email)."' LIMIT 1");

            // Waiting for Deletion accounts
            if ($Delete_Accounts[$data['userid']] == 2 && !$confirmation) {
                $result = 'waiting_for_deletion';
            } else {
                if($confirmation) {
                    query_execute("DELETE FROM deleteacoount WHERE email='".sqlescape($email)."'");
                }

         DB_query("UPDATE users SET last_login=NOW(),
                               last_ip='".$_POST['ip']."'                                  
                           WHERE userid=".$userid."",'#');

                $result = 'OK';
            }
        }
        // ----------------------------------------------
    }

    if($error) {

        $result = '<div class="alert alert-block alert-error mb5"><h4>'.$error.'</div>';

    }

    jsonReturn($result, $error);
}

@Armin:请检查我编辑过的代码。 - Sree KS
2
这只是我的个人意见 - 这是我如何设计此用例的方式:(1)用户提交“账户删除”表单。这将向其帐户添加一个标志(account_delete_requested)以及日期/时间。(2)每天/每小时运行CRON作业,检查这些标志/日期/时间并删除超过3天的任何人。(3)完全分开,每次用户登录时,检查“account_delete_requested”标志/日期/时间,并在3天内重新激活。 - waterloomatt
@waterloomatt:你说得对,我正在以同样的方式进行。但是当用户尝试登录时,我只想要求确认一下。 - Sree KS
1
你能否让 PHP 返回代表三种不同状态的 JSON:1. 错误(用户名/密码无效),2. 正确(有效的用户名/密码 && 帐户没有设置"account_delete_requested"标志),3. 激活(有效的用户名/密码 && 帐户已经设置了"account_delete_requested"标志)。然后,JS会查看该状态并且执行以下动作:显示错误消息、重定向到一个着陆页面、显示确认对话框;如果确认对话框等于Y,则重定向到着陆页面,因为您知道用户名/密码是正确的。这样,您就不需要再次提交表单;确认对话框将自行驱动。 - waterloomatt
@waterloomatt:你很聪明,这是个好方法。但如果结果没问题,我还想更新“最后登录”并从“已删除帐户”表中删除用户。同时,它不应影响正常登录。 - Sree KS
好的,这里有两种情况:(1)“普通账户”,用户名/密码正确-更新last_login,返回JSON OK。(2)如果该账户正在等待删除,只需从PHP返回JSON ACTIVATE。然后,在JS中,如果确认对话框为Y,则触发一个AJAX请求以重新激活帐户,该请求将更新last_login并删除记录,最后重定向到着陆页面。类似于$.post('/activate.php')...; location.href...; **但是有一个主要问题。PHP将在登录期间设置会话标志。如果用户在对话框上选择“N”,则可能不希望这样做。 - waterloomatt
3个回答

4
你需要编写ajax函数,修改对象后再次提交。
function submitForm(form) {
    $.post('/ajax.php', form.serialize(), function (data) {
        if (data.error.length) {
            $('.login_result', form).html(data.result).slideDown();

        } else if (data.result === 'waiting_for_deletion') {

            jconfirm('Account will be enabled if you login',
                function (is_confirmed) {
                    if (is_confirmed) {
                        form.find('input:hidden[name="loginform"]').val('confirm_reactivation');
                        submitForm(form);
                        return;
                    }
                },
                'Yes', 'Cancel');
        } else {
            location.href = '/me';
        }
    });
}

$('#loginform').on('submit', function (e) {
    e.preventDefault();

    submitForm($(this));
});

这样我们分割了函数。但是会提交表单两次,对吗? - Sree KS
@Sree 第一次我们调用 request = submitForm(_this); 并通过 request.done 捕获响应,但第二次我们只需修改后调用 submitForm(_this) - Vasyl Zhuryk
我们该如何捕获响应,因为每次响应都不同? - Sree KS
提交表单(submitForm(form));相同的函数被调用两次(表单被提交两次)。我不希望那样。请阅读我的问题。 - Sree KS
如果账户处于活跃状态,则首次调用将重定向到“/me”,但如果账户正在等待删除,则需要显示确认弹出窗口。确认后,发送带有confirm_reactivation的请求。或者另一种选择是使用套接字。 - Vasyl Zhuryk

4
在这里,我使用了一个额外的ajax调用并重用现有代码来创建另一个PHP文件,以解决这个问题而不需要提交表单两次。
$(".password").on('focus', function () {
        var email=$('input[name="email"]').val();
        confirm_reactivation(email);
});

function confirm_reactivation(email)
{

var api="email="+ email;
         $.ajax({
        method : 'POST',
        url : confirm_reactivation.php,
        data : api
      }).done(function(data){
        var out = $.parseJSON(JSON.stringify(data));
        if(out.message == 'success'){
             $('input:hidden[name="loginform"]').val('confirm_reactivation');
        }else{
               $('input:hidden[name="loginform"]').val('');
        }
      });
}

$('#loginform').on('submit',function(e) {

  var check_value=$('input:hidden[name="loginform"]').val();
if(check_value !='' || check_value == null)
{
var t = $(this);

   $.post('/login.php', t.serialize(), function(data) {
     if(data.error.length) {
       $('.login_result', t).html(data.result).slideDown();

     } else {
            location.href = '/accounts';
         }
  }, 'json')
}
else{
       jconfirm('Account will be enabled if you login',
          function(is_confirmed) {
            if(is_confirmed) {                            

$('input:hidden[name="loginform"]').val('confirm_reactivation');
               //('#loginform').submit();
var t = $(this);


   $.post('/login.php', t.serialize(), function(data) {
     if(data.error.length) {
       $('.login_result', t).html(data.result).slideDown();

     } else {
            location.href = '/accounts';
         }
  }, 'json')
             }
          } ,
          'Yes', 'Cancel');

}


});

以下是您的新PHP文件,我已重用了您的代码并添加了一些内容。

//confirm_reactivation.php

<?php

 $email = trim(mb_strtolower($_POST['email']));

  $Delete_Accounts = query_execute("SELECT * FROM deleteacoount WHERE email='".sqlescape($email)."' LIMIT 1");

            // Waiting for Deletion accounts
            if ($Delete_Accounts[$data['userid']] == 2) {
                $message = array("message" =>'success',"status" =>200);
 echo json_encode($message);exit;
            }
            else{
             $message = array("message" =>'failed',"status" =>200);
 echo json_encode($message);exit;
            }



?>

That's it. Thank you!


@ZakariaAcharki 不,如果你仔细阅读我的代码,你就会知道这一点。他的问题是同时他不想提交两次表单,在我的程序中,如果你是普通用户,你只能提交一次表单,或者如果你是已删除的用户并且再次回来,此时你也只能提交一次表单。谢谢! - Mohamed Azharuddin
1
@ZakariaAcharki,我找到了我的逻辑错误并进行了修复,请现在检查一下。谢谢! - Mohamed Azharuddin

3

我不太清楚为什么您不想提交表单两次。

无论如何,有两个目标必须实现:

  1. 用户必须知道他/她的帐户正在等待删除并确认登录。
  2. 服务器必须知道用户已确认。

这里有一个解决方案:在加载登录页面时加载所有“waiting_for_deletion”电子邮件(您可以为安全原因进行哈希处理)。用户输入电子邮件后,您可以比较输入的电子邮件和“waiting_for_deletion”列表。如果列表中存在该电子邮件,则显示确认弹出窗口。

这种解决方案在性能方面不太好(您必须在呈现登录页面时随时加载电子邮件列表),安全性也不好(您在客户端加载电子邮件列表并进行检查,即使对列表中的电子邮件进行了哈希处理,它也是一个弱点)。但是,它可以实现您的目标。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接