【问题标题】:mb_strlen() & strlen() don't return correct values from an Ajax call to PHPmb_strlen() & strlen() 不会从对 PHP 的 Ajax 调用返回正确的值
【发布时间】:2012-01-05 05:57:04
【问题描述】:

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

我尝试过但没有成功:

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

更多信息

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

我打算尝试用 UTF-8 发送 Ajax 请求,但没有找到方法。

在 MySQL 中是否正确使用了 UPPER? - 对于 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 SNIPPIT

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

测试数据

用户名:大卫佩里

!1!大卫佩里!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");

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

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

好的,经过大量阅读,我相信我的 JS 编码错误。我用的是escape...如下...

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);

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

所以,现在 mb_strlen 可以正常工作了,我可以轻松地将它重新添加...

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

效果很好!

【问题讨论】:

  • 那段...很痛。单一的,迂腐的,loong。请编辑(至少添加一些分段符)。
  • 好吧,你有 mb_strlen() 部分因任何原因被注释掉了。究竟是什么不工作?
  • 您好。 mb_strlen 和 strlen 都给出了错误的值,因为我相信它在 Ajax 调用中的编码方式不同。

标签: php javascript ajax encoding utf-8


【解决方案1】:

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

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

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

Mysql 将从 php 接收字节流,并根据数据库会话的字符集对其进行解析,该字符集是您通过 SET NAMES 指令设置的。每次连接到数据库时,您必须告知它您的 php 字符串的编码是什么。

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

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

【讨论】:

  • 我忘记了一些可能是问题的代码行......在最初的 Ajax 调用中 registerRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");当我打印 PHP 看到的内容时,它是一堆奇怪的 /u2323 东西。所以,我假设那是 Ajax 编码。有没有办法将我的 Ajax 作为 UTF-8 传递?
  • 我用更多代码重新编辑了我的帖子,这样你就可以准确地看到我在做什么。不检查长度它确实有效(也许它的工作是侥幸)。它插入数据库,告诉我它是否被占用。完美运行(或者看起来如此)。我也尝试了奇怪的字符。当我尝试将检查添加到长度时出现了问题。我还阅读了您链接的那篇文章-非常感谢。它有助于。除了我阅读的“uni”选项之外,我之前已经完成了所有操作。我得再看看那个。 (抱歉一直在更改我的帖子,不想在您试图提供帮助时打扰您)。
  • 哦...所以也许我通过添加... registerRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");如果 Ajax 以与页面相同的编码提交调用......嗯......
  • 好的,我在测试中添加了一些真实数据。你能帮我看看吗?非常感激。在上方您会看到测试数据...以粗体显示。
  • 好的,经过几个小时的阅读,我相信你让我走上了正确的道路来解决这个问题。我会在我原来的问题中添加更多信息来向你展示......它仍然不能 100% 工作,但也许你可以告诉我为什么......(请感谢你)。
【解决方案2】:

快速浏览一下,您可以清理它:

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';
        }
}

【讨论】:

  • 谢谢!你的方法更干净。我会整理我的代码!有什么办法可以帮助解决它的 strlen 部分?
  • 我阅读了您链接的文章。从来没有这样想过!谢谢你的提示!我尝试并练习良好的编程,但在学习时 - 哇......有很多东西可以吸收!大声笑我以前用过===,但我不知道那篇文章是什么。谢谢!!!
  • 没问题。很高兴我能帮忙:)
猜你喜欢
  • 1970-01-01
  • 2017-07-08
  • 1970-01-01
  • 2018-01-02
  • 2014-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多