mb_strlen () & strlen () не возвращают правильные значения из вызова Ajax в PHP - PullRequest
4 голосов
/ 24 ноября 2011

Как я могу добавить проверку в PHP для длины пройденного $ username. Сайт работает в формате UTF-8, но я считаю, что Javascript использует другую кодировку. Вы можете видеть в комментариях, где я пробовал разные вещи в PHP, и они не работают.

То, что я пробовал и не работало:

  • Изменение Ajax (javascript) для передачи переменных с помощью UTF-8, а не кодирования javascript
  • strlen, mb_strlen в PHP - оба возвращают неверные значения

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

Мой Ajax отправляет имя пользователя на мой PHP, который проверяет базу данных SQL и возвращает доступное или нет. Я решил попробовать сделать дополнительную проверку в PHP перед проверкой БД (например, mb_strlen($username). mb_internal_encoding("UTF-8"); также установлено.

Я собирался попытаться отправить запрос Ajax в UTF-8, но не нашел способа сделать это.

правильно ли используется 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 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.

Прочитав решение и ссылку Джори Себрехтса, которые мне дали, я посмотрел параметры запроса Ajax, и у кого-то было следующее ...

AJAX SNIPPIT (изменено с исходного кода)

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

(я добавил в charset=UTF-8 из примера, который я видел в статье).

ОБНОВЛЕНИЕ: 27 ноября, 21:11 EST

Хорошо, после долгих чтений я считаю, что неправильно кодирую свой JS. Я использовал escape ... следующим образом ...

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

Посмотрев на этот сайт ...

http://www.the -art-of-web.com / JavaScript / бежать /

это помогло мне лучше понять, что происходит с каждой функцией и как они кодируют и декодируют. Я должен быть в состоянии сделать это ...

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

в JS и в PHP я должен быть в состоянии сделать это ...

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

В этом странном примере, приведенном выше, я получаю 8 символов вместо 7. Это близко, но я что-то не так делаю? Если я наведу курсор на текст на экране, это будет 7 символов. Любые идеи, которые помогут мне лучше понять это?

FIXED / РЕШИТЬ !!!

Хорошо, спасибо за ваши советы, которые ведут меня в правильном направлении, чтобы сделать эту работу. Мои изменения были следующие.

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

Отлично работает!

Ответы [ 2 ]

6 голосов
/ 28 ноября 2011

PHP является байтовым процессором, он не поддерживает кодировки. Это имеет ряд хитрых последствий.

Strlen () возвращает длину в байтах, а не длину в символах. Это потому, что тип php "string" на самом деле является массивом байтов. Utf8 использует более одного байта на символ для «специальных символов». Поэтому strlen () даст вам правильный ответ только для узкого подмножества текста (= простой текст на английском языке).

Mb_strlen () обрабатывает строку как фактические символы, но предполагает, что она находится в кодировке, указанной в mbstring.internal_encoding, поскольку сама строка является просто массивом байтов и не имеет метаданных, определяющих ее набор символов. Если вы работаете с данными utf8 и для параметра internal_encoding установлено значение utf8, это даст вам правильный ответ. Если ваши данные не являются utf8, это даст вам неправильный ответ.

Mysql получит поток байтов от php и проанализирует его на основе набора символов сеанса базы данных, который вы устанавливаете с помощью директивы SET NAMES. Каждый раз, когда вы подключаетесь к базе данных, вы должны сообщить ей, в какой кодировке находятся ваши строки php.

Браузер получает поток байтов от php и анализирует его на основе http-заголовка charset типа содержимого, которым вы управляете через php.ini default_charset. Вызов ajax будет отправлен в той же кодировке, что и страница, с которой он запускается.

Подводя итог, вы можете найти совет на следующей странице о том, как обеспечить обработку всех ваших данных как utf8. Следуйте ему, и ваша проблема должна разрешиться сама собой. http://malevolent.com/weblog/archive/2007/03/12/unicode-utf8-php-mysql/

1 голос
/ 24 ноября 2011

С первого взгляда вы можете очистить это:

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';
        }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...