mb_strlen()&strlen()不会从对Ajax的Ajax调用中返回正确的值

Per*_*yCS 4 javascript php ajax encoding utf-8

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

我尝试过但没有用的东西:

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

更多信息

我的Ajax向我的PHP发送一个用户名,用于检查SQL DB并返回可用或不返回.我决定在检查数据库之前尝试在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);
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

测试结果

这是我在PHP中进行DIE时返回的内容,如下所示回显(在下面的Ajax更改之前和之后[在UTF-8中添加请求] ...

PHP SNIPPIT

die ('!1!' .  $username . '!2!' . mb_strlen($username) . '!3!' . strlen($username) . '!4!');
Run Code Online (Sandbox Code Playgroud)

测试数据

用户名: David Perry

!1!David Perry!2!11!3!11!4!

用户名: Ü|"〜÷Û♦

!1!ܦ\"〜%u2666!2!9!3!13!4!

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

第二个可见的7个字符.mb_strlen显示9,strlen显示13.

在阅读了Joeri Sebrechts解决方案和链接后,他们给了我查找Ajax请求参数,有人有以下内容......

AJAX SNIPPIT(从原始代码更改)

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

(我在charset=UTF-8一篇文章中看到的一个例子中添加了).

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

好的,经过多次阅读后,我相信我编写的JS错误.我正在使用逃生......如下......

var requestData = "username=" + escape(sNameToCheck);
Run Code Online (Sandbox Code Playgroud)

看完这个网站后......

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

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

var requestData = "username=" + encodeURIComponent(sNameToCheck);
Run Code Online (Sandbox Code Playgroud)

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

$username = rawurldecode($_POST['username']);
Run Code Online (Sandbox Code Playgroud)

这样做仍然为我上面的奇怪例子而不是7提供了8个字符.它很接近,但我做错了什么?如果我浏览屏幕上的文字,则为7个字符.有什么想法可以让我更好地理解这个吗?

固定/解决!

好的,谢谢你的提示,引导我朝着正确的方向努力.我的更改如下.

在AJAX中 - 我曾经有过逃生(sNameToCheck); -

var requestData = "username=" + encodeURIComponent(sNameToCheck);
Run Code Online (Sandbox Code Playgroud)

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

$username = rawurldecode($_POST['username']);
if (get_magic_quotes_gpc()) $username = stripslashes($username);
Run Code Online (Sandbox Code Playgroud)

我真的很讨厌magic_quotes ...这让我对表格数据感到非常沮丧,因为我忘了它.只要它有效.我很高兴!

所以,现在mb_strlen工作了,我可以轻松地将其添加回...

if (mb_strlen($username) < MIN_USERNAME_SIZE) { echo 'invalid_too_short'; exit; }
Run Code Online (Sandbox Code Playgroud)

效果很好!

Joe*_*hts 6

PHP是一个字节处理器,它不是charset-aware.这有很多棘手的后果.

Strlen()以字节为单位返回长度,而不是以字符为单位的长度.这是因为php的"字符串"类型实际上是一个字节数组.Utf8为每个字符使用多个字节作为"特殊字符".因此strlen()只会为一个狭窄的文本子集(=纯英文文本)提供正确的答案.

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

Mysql将从php接收一个字节流,并将根据您通过SET NAMES指令设置的数据库会话的字符集来解析它.每次连接到数据库时,都必须告知它php字符串的编码.

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

总结一下,您可以在下一页上找到有关如何确保将所有数据视为utf8的建议.遵循它,您的问题应该自行解决. http://malevolent.com/weblog/archive/2007/03/12/unicode-utf8-php-mysql/