代码之家  ›  专栏  ›  技术社区  ›  Community wiki

mb_strlen()和strlen()没有从Ajax调用PHP返回正确的值

  •  4
  • Community wiki  · 技术社区  · 3 年前

    我如何在PHP中添加检查传递的$username的长度。该网站是UTF-8,但我相信Javascript使用了不同的编码。你可以在评论中看到,我在PHP中尝试了不同的东西,但它们都不起作用。

    我尝试了但没有成功:

    • 更改Ajax(javascript)以通过UTF-8而不是javascript编码传递变量
    • PHP中的strlen、mb_strlen都返回了不正确的值

    更多信息

    我的Ajax向我的PHP发送一个用户名,PHP检查SQL数据库并返回可用与否。我决定在检查数据库之前尝试在PHP中做一些额外的检查(比如 mb_strlen($username )。 mb_internal_encoding("UTF-8"); 也已设置。

    我本来打算尝试用UTF-8发送Ajax请求,但没有办法做到这一点。

    UPPER在MySQL中使用正确吗?-UTF-8的东西?

    PHP下方 * ** * ** * ** * *

    // Only checks for the username being valid or not and returns 'taken' or 'available'
    require_once('../defines/mainDefines.php'); // Connection variables
    require_once('commonMethods.php');
    require_once('sessionInit.php');    // start session, check for HTTP redid to HHHTPs
    
    sleep(2);   // Looks cool watching the spinner
    
    $username = $_POST['username'];
    
    //if (mb_strlen($username) < MIN_USERNAME_SIZE) echo 'invalid_too_short';
    
    //if (mb_strlen($username, 'UTF-8') < 10) { echo ('invalid_too_short'); exit; }
    //die ('!1!' .  $username . '!2!' . mb_strlen($username) . '!3!' . strlen($username) . '!4!');
    
    $dbc = mysqli_connect(DB_HOST, DB_READER, DB_READER_PASSWORD, DB_NAME) or     die(DB_CONNECT_ERROR . DB_HOST .  '--QueryDB--checkName.php');
    $stmt = mysqli_stmt_init($dbc);
    
    $query = "SELECT username FROM pcsuser WHERE UPPER(username) = UPPER(?)";
    if (!mysqli_stmt_prepare($stmt, $query)) {
        die('SEL:mysqli_prepare failed somehow:' . $query . '--QueryDB--checkName.php');
    }
    
    if (!mysqli_stmt_bind_param($stmt, 's', $username)) {
        die('mysqli_stmt_bind_param failed somehow --checkName.php');
    }
    
    if (!mysqli_stmt_execute($stmt)) {
        die('mysqli_stmt_execute failed somehow' . '--checkName.php');
    }
    
    mysqli_stmt_store_result($stmt);
    $num_rows = mysqli_stmt_num_rows($stmt);
    mysqli_stmt_bind_result($stmt, $row);           
    echo ($num_rows >= 1) ? 'taken' : 'available';
    
    mysqli_stmt_close($stmt);
    mysqli_close($dbc);
    

    下面的AJAX代码

    function CheckUsername(sNameToCheck) {
    document.getElementById("field_username").className = "validated";
    registerRequest = CreateRequest();
    if (registerRequest === null)
        alert("Unable to create AJAX request");
    else {
      var url= "https://www.perrycs.com/php/checkName.php";
      var requestData = "username=" + escape(sNameToCheck); // data to send
      registerRequest.onreadystatechange = ShowUsernameStatus;
      registerRequest.open("POST", url, true);
      registerRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
      registerRequest.send(requestData);
    }
    }
    
    
    function ShowUsernameStatus() {
    var img_sad = "graphics/signup/smiley-sad006.gif";
    var img_smile = "graphics/signup/smiley-happy088.gif";
    var img_checking = "graphics/signup/bluespinner.gif";
    
    if (request.readyState === 4) {
        if (request.status === 200) {
            var txtUsername = document.getElementById('txt_username');
            var fieldUsername = document.getElementById('field_username');
            var imgUsername = document.getElementById('img_username');
            var error = true;
            var response = request.responseText;
    
            switch (response) {
                case "available":
                    txtUsername.innerHTML = "NAME AVAILABLE!";
                    error = false;                  
                    break;
                case "taken":
                    txtUsername.innerHTML = "NAME TAKEN!";
                    break;
                case "invalid_too_short": 
                    txtUsername.innerHTML = "TOO SHORT!";
                    break;
                default:
                    txtUsername.innerHTML = "AJAX ERROR!";
                    break;
            } // matches switch
    
            if (error) {
                imgUsername.src = img_sad;
                fieldUsername.className = 'error';
            } else {
                imgUsername.src = img_smile;
                fieldUsername.className = 'validated';
            }
        } // matches ===200
    } // matches ===4
    }
    

    测试结果

    这是我在PHP中死亡时得到的结果,并如下面所示(在进行下面的Ajax更改之前和之后[在请求中添加UTF-8]。。。

    PHP狙击坑

    die ('!1!' .  $username . '!2!' . mb_strlen($username) . '!3!' . strlen($username) . '!4!');
    

    试验数据

    用户名: 大卫佩里

    !1.大卫·佩里!2.11!3.11!4.

    用户名: ”~·

    !1\“~%u2266!2!9!3!13!4!”!

    第一个有效。第二个应该可以工作,但看起来编码很奇怪(可以理解)。

    第二个有7个可见字符。mb_strlen显示9,strlen显示13。

    在阅读了Joeri Sebrechts的解决方案和他们给我的链接后,我查找了Ajax请求参数,有人得到了以下信息。。。

    阿贾克斯狙击坑 (由原始代码更改)

    registerRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
    

    (我在 charset=UTF-8 来自我在一篇文章中看到的一个例子)。

    更新:美国东部时间11月27日晚上9:11

    好的,经过大量的阅读,我相信我的JS编码错误。我在用逃生。。。如下。。。

    var requestData = "username=" + escape(sNameToCheck);
    

    看了这个网站之后。。。

    http://www.the-art-of-web.com/javascript/escape/

    它帮助我更多地了解了每个函数的情况以及它们是如何编码和解码的。我应该能够做到这一点。。。

    var requestData = "username=" + encodeURIComponent(sNameToCheck);
    

    在JS和PHP中,我应该能够做到这一点。。。

    $username = rawurldecode($_POST['username']);
    

    这样做仍然给了我8个字符,而不是7个字符。很近,但我做错了什么吗?如果我用光标浏览屏幕上的文本,它是7个字符。有什么想法可以帮助我更好地理解这一点吗?

    已修复/已解决!!!

    好的,谢谢你的建议,让我朝着正确的方向努力。我的改变如下。

    在AJAX中 --我曾经有escape(sNameToCheck)--

    var requestData=“username=”+encodeURIComponent(sNameToCheck);
    

    在PHP中 *--我曾经有$username=$_POST['username']--*

    $username = rawurldecode($_POST['username']);
    if (get_magic_quotes_gpc()) $username = stripslashes($username);
    

    我真的很讨厌魔术语录。。。它总共让我对表单数据感到了50多个小时的沮丧,因为我忘记了它。只要它有效。我很高兴!

    所以,现在mb_strlen工作了,我可以很容易地将其添加回。。。

    if (mb_strlen($username) < MIN_USERNAME_SIZE) { echo 'invalid_too_short'; exit; }
    

    效果很好!

    2 回复  |  直到 14 年前
        1
  •  6
  •   Joeri Sebrechts    14 年前

    PHP是一个字节处理器,它不支持字符集。这有许多棘手的后果。

    Strlen()返回的长度以字节为单位,而不是以字符为单位的长度。这是因为php的“字符串”类型实际上是一个字节数组。Utf8为“特殊字符”每个字符使用一个以上的字节。因此,strlen()只会为一小部分文本(=纯英语文本)给出正确的答案。

    Mb_strlen()将字符串视为实际字符,但假设它处于通过mbstring.internal_encoding指定的编码中,因为字符串本身只是一个字节数组,没有指定其字符集的元数据。如果您使用的是utf8数据,并将internal_encoding设置为utf8,它将为您提供正确的答案。如果你的数据不是utf8,它会给你错误的答案。

    Mysql将从php接收一个字节流,并根据数据库会话的字符集对其进行解析,该字符集是通过SETNAMES指令设置的。每次连接到数据库时,都必须通知它php字符串的编码方式。

    浏览器从php接收一个字节流,并将根据您通过php.ini default_charset控制的内容类型charsethttp标头对其进行解析。ajax调用将以与其运行的页面相同的编码提交。

    总之,您可以在下面的页面上找到关于如何确保您的所有数据都被视为utf8的建议。遵循它,你的问题就会自行解决。 http://malevolent.com/weblog/archive/2007/03/12/unicode-utf8-php-mysql/

        2
  •  1
  •   lrusli    14 年前

    快速浏览一下,您可以清除以下内容:

    if (request.status == 200) {
        if (request.responseText == "available") {
            document.getElementById("txt_username").innerHTML = "NAME AVAILABLE!";
            document.images['img_username'].src=img_smile;
            document.getElementById("continue").disabled = false;
            document.getElementById("field_username").className = 'validated';
        } else if (request.responseText == "taken") {
            document.getElementById("txt_username").innerHTML = "NAME TAKEN!";
            document.images['img_username'].src=img_sad;
            document.getElementById("field_username").className = 'error';
        } else if (request.responseText == "invalid_too_short") {
            document.getElementById("txt_username").innerHTML = "TOO SHORT!";
            document.images['img_username'].src=img_sad;
            document.getElementById("field_username").className = 'error';
        } else {
            document.getElementById("txt_username").innerHTML = "AJAX ERROR!";
                    document.images['img_username'].src=img_sad;
            document.getElementById("field_username").className = 'error';
        }
      }
    

    收件人:

    // I prefer triple equals
    // Read more at http://javascript.crockford.com/style2.html
    if (request.status === 200) {
            // use variables!
            var txtUsername = document.getElementById('txt_username');
            var fieldUsername = document.getElementById('field_username');
            var imgUsername = document.getElementById('img_username');
    
            var response = request.responseText;
    
            var error = true;
    
            // you can do a switch statement here too, if you prefer
            if (response === "available") {
                txtUsername.innerHTML = "NAME AVAILABLE!";
    
                document.getElementById("continue").disabled = false;
    
                error = false;
    
            } else if (response === "taken") {
                txtUsername.innerHTML = "NAME TAKEN!";
    
            } else if (response === "invalid_too_short") {
                txtUsername.innerHTML = "TOO SHORT!";
    
            } else {
                txtUsername.innerHTML = "AJAX ERROR!";
            }
    
            // refactor error actions
            if (error) {
                imgUsername.src = img_sad;
                fieldUsername.className = 'error';
            } else {
                imgUsername.src = img_smile;
                fieldUsername.className = 'validated';
            }
    }
    
    推荐文章