使用json_encode将值从PHP传递到Ajax时出现意外结果

问题描述

目标:为网站开发注册表格

问题PHP使用json_encode函数将意外结果返回给Ajax(例如,它应返回DUPLICATE_USERNAME时返回DUPLICATE_EMAIL)。

代码说明/算法

  1. 用户注册表格中输入其详细信息(用户名,电子邮件等)
  2. 单击提交按钮后,PHP脚本(registrationProcess.PHP)通过POST获取输入
  3. 运行数据库检查,以便提供用户名和电子邮件(此处我们假设它们不可用)
  4. PHP通过Ajax将值返回到前端。它返回两个字符串,DUPLICATE_USERNAMEDUPLICATE_EMAIL;执行此操作的功能handleRegisterError($error_type)
  5. 根据返回的字符串,正确更改网页的用户界面

功能是脚本的一部分,单击提交按钮后将调用功能

<?PHP

/**
* This function gets called in the PHP script if a registration error has been found. It is passed either DUPLICATE_USERNAME or DUPLICATE_EMAIL.
*/
function handleRegisterError($error_type) {
  switch($error_type) {
    case "DUPLICATE_USERNAME":
      $data = array("error" => "DUPLICATE_USERNAME");
      echo json_encode($data);
      break;
    case "DUPLICATE_EMAIL":
      $data = array("error" => "DUPLICATE_EMAIL");
      echo json_encode($data);
      break;
    default:
      echo "Unexpected error in registrationProcess.PHP"
      break;
  }
}
/>

现在,前端HTML注册页面上的JavaScript代码接收到该代码

<script>
        $.ajax({
            dataType: 'json',url: "../PHP/registrationProcess.PHP",success: function(data) {
               console.log("SUCCESS: " + data.error);
               handleError(data.error);
            },error: function(jqXHR,textStatus,errorThrown) {
                console.log("ERROR CALLING AJAX! textStatus = " + textStatus + " | errorThrown = " + errorThrown);
            }
        });

        function handleError(errorType) {
            console.log("errorType = " + errorType);
            switch(errorType) {
                case "DUPLICATE_USERNAME":
                    // display duplicate username error
                    $("#username-error").attr("hidden",false);
                    $("#username-input-field").css("margin-bottom",8);
                    break;
                case "DUPLICATE_EMAIL":
                    // display duplicate email error
                    $("#email-error").attr("hidden",false);
                    $("#email-input-field").css("margin-bottom",8);
                    break;
            }
        }
    </script>

接收代码由基本的Ajax表单组成,用于从PHP接收结果。它将接收到的变量(data.error)传递到handleError函数,该函数又包含一个switch语句,该语句更改UI来解决重复的用户名/电子邮件错误

调试

PHP从json_encode发送值时,它回显正在传输到网站的JSON代码,因此我可以轻松地看到PHP作为JSON传输的内容。对于JavaScript调试,我使用console.log函数打印"SUCCESS",然后打印data.error(应该类似于PHP传输的值)。为了安全起见,然后从handleError函数将JavaScript中使用的错误反复打印到控制台。

您可以看到我用来分析这两个图像中的错误的两种调试源的示例,其中从PHP传输的JSON在图像的左上方,控制台在图像的右侧。 :

Image 1

问题分析

我已将以下用户放入数据库

为了测试代码,然后运行了两个单独的测试:在 一个测试 中,我尝试创建另一个名为Mike and a different email用户名(预计将返回DUPLICATE_USERNAME错误)。在 第二次测试 中,我尝试使用name Jenna and the email mikey@gmail.com创建另一个用户名,该用户名可能会导致DUPLICATE_EMAIL错误

用户名重复时,我的代码成功处理了第一种情况:

Enter image description here

但是,在第二种情况下,PHP可以正确识别DUPLICATE_EMAIL错误,但是JavaScript / Ajax在发送时会以某种方式将其解释为DUPLICATE_USERNAME。

Enter image description here

导致该错误代码在做错什么?网页上的某些状态可能是以前的数据传输中保存的状态?

感谢您花费时间来解决此问题!

registrationProcess.PHP的脚本:

<?PHP
include 'secureFunctions.PHP';

$username = "";
$birthday = "";
$gender = "";
$email = "";
$password = "";

$username = getvariable('username');
$birthday = getvariable('birthday');
$gender = getvariable('gender');
$email = getvariable('email');
$password = getvariable('password');

$db_host = "sql7.freesqldatabase.com";
$db_username = "sql7369409";
$db_password = "*******";
$db_name = "sql7369409";

$conn = new MysqLi($db_host,$db_username,$db_password,$db_name);

if(MysqLi_connect_error()) {
    die("Database connection Failed: " . MysqLi_connect_error);
}

if($gender != "") {
    // Edit gender for the database
    switch ("gender") {
        case "male":
            $gender = "m";
            break;
        case "female":
            $gender = "f";
            break;
        case "other":
            $gender = "o";
            break;
    }
}

if($birthday != "") {
    // Edit birthday for the database
    $arr = explode('/',$birthday);
    $birthday = $arr[2] . '-' . $arr[1] . '-' . $arr[0];
}

$sql = "INSERT INTO users (id,username,birthday,gender,email,password)
VALUES (NULL,'$username','$birthday','$gender','$email','$password')";

if (MysqLi_query($conn,$sql)) {
    echo "New record created successfully!";
    header("Location: ../pages/index.html");
    exit();
}
else {
    handleRegisterError(registrationGetErrorType(MysqLi_error($conn)),"TRUE");
}

function handleRegisterError($error_type,$devValue) {
    //echo "errorType = $error_type ";
    if($devValue == "TRUE") {
        /*
        switch ($error_type) {
            case "DUPLICATE_USERNAME":
                //echo "test2";
                $data = array("error" => "DUPLICATE_USERNAME");
                echo json_encode($data);
                break;
            case "DUPLICATE_EMAIL":
                //echo "test1";
                $data = array("error" => "DUPLICATE_EMAIL");
                echo json_encode($data);
                break;
            case "UNKNowN":
                $data = array("error" => "UNKNowN");
                echo json_encode($data);
                break;
        }
        */

        //$data;
        if($error_type == "DUPLICATE_USERNAME") {
            //echo " t1 ";
            $data = array("error" => "DUPLICATE_USERNAME");
            //echo json_encode($data);
        } elseif($error_type == "DUPLICATE_EMAIL") {
            //echo " t2 ";
            $data = array("error" => "DUPLICATE_EMAIL");
            //echo json_encode($data);
        } else {
            $data = array("error" => "UNKNowN");
            //echo json_encode($data);
        }
        echo json_encode($data);
    }

}

?>

上面的脚本还使用了secureFunctions.PHP中的一些方法

<?PHP
/**
 * Retrieves a variable from HTML using the null coalesce operator (for security reasons)
 * @param mixed $variableName
 * @return void
 */
function getvariable($variableName) {
    $result = $_POST[$variableName] ?? '';
    return $result;
}

/**
 * There are two types of registration errors: (1) username already in use (2) email already in use or (3) UnkNown error
 * First two errors look like this:
 *   (1): Duplicate entry 'skorjanc.survey@gmail.com' for key 'email'
 *   (2): Duplicate entry 'King_Fish' for key 'name'
 *
 * @param mixed $sqlDbText The error text from the server
 * @return (1) DUPLICATE_USERNAME (2) DUPLICATE_EMAIL (3) UNKNowN
 */
function registrationGetErrorType($sqlDbText) {
    $filtered = str_replace("'","",$sqlDbText); // Replace single quotes with air
    $array = explode(" ",$filtered);
    $key = $array[count($array)-1];

    if($key == "email") {
        return "DUPLICATE_EMAIL";
    } elseif($key == "name") {
        return "DUPLICATE_USERNAME";
    }

    return "UNKNowN";
}
?>

ArJay suggested一样,在两种情况下(用户名重复和密码重复),我还在$array方法中附加了$keyregistrationGetErrorType的值:

(1)DUPLICATE_USERNAME

array = Array ( [0] => Duplicate [1] => entry [2] => King_Fish [3] => for [4] => key [5] => name )
key = name

(2)重复电子邮件

array = Array ( [0] => Duplicate [1] => entry [2] => skor@gmail.com [3] => for [4] => key [5] => email )
key = email

解决方法

我已经找到了问题的原因。

单击“提交”按钮时,所有值实际上都已从表单发送到正确的PHP脚本。处理了这些值,并返回了具有正确错误的正确JSON对象。

但是,由于提交按钮功能,页面刷新了。现在,所有表单变量都被重新设置为空,例如username = ""email = ""等。这些变量再次被同一脚本使用并针对现有数据库记录进行了测试,从而导致错误的第二个错误(DUPLICATE_USERNAME而不是DUPLICATE_EMAIL)。

似乎我遇到了算法错误,因为我以导致错误的方式设计了代码流。但是,我找到了关于创建注册/登录页面的很棒的教程,我已经对其代码进行了测试(并且可以运行!)-follow this link

感谢大家,特别是彼得·莫滕森(Peter Mortensen)对这个错误的耐心!