Mb_strlen () & strlen () do not return the correct values ​​from an Ajax call in PHP

How can I add validation in PHP for the length of the passed name $. The site is UTF-8, but I believe that Javascript uses a different encoding. You can see in the comments where I tried different things in PHP and they do not work.

What I tried and did not work:

  • Ajax change (javascript) for passing variables in UTF-8, not javascript encoding
  • strlen, mb_strlen in PHP - both return invalid values

ADDITIONAL INFORMATION

My Ajax sends the username to my PHP, which checks the SQL database and returns it or not. I decided to try and do additional testing in PHP before checking the DB (for example, mb_strlen($username ). mb_internal_encoding("UTF-8"); also set.

I was going to try and send an Ajax request to UTF-8, but did not see a way to do this.

is UPPER used correctly in MySQL? - for UTF-8?

PHP BELOW ***********

 // 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 CODE BELOW

 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 } 

TEST RESULTS

This is what I will return when I DIE in PHP and exit as in the following (before and after changing Ajax below [adding to UTF-8 to the request] ...

PHP SNIPPIT

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

DATA TEST

Username: David Perry

! 1! David Perry! 2! eleven! 3! eleven! 4!

Username: Ü | "~ Γ· Γ› ♦

! 1! ά¦ \ "~% u2666! 2! 9! 3! 13! 4!

The first one works. The second should work, but the coding seems strange (understandable).

7 visible characters for the second. mb_strlen shows 9, strlen shows 13.

After reading the solution and Joeri Sebrechts link that they gave me, I looked at the Ajax request parameters, and someone had the following ...

AJAX SNIPPIT (modified from source)

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

(I added to charset=UTF-8 from the example that I saw in the article).

UPDATE: November 27, 9:11 p.m. EST

Well, after long readings, I believe that I code my JS error. I used the escape ... as follows ...

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

Looking at this site ...

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

it helped me understand what happens with each function and how they are encoded and decoded. I should be able to do this ...

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

in JS and in PHP, I should be able to do this ...

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

Doing this still gives me 8 characters for my weird example above, not 7. Is it close, but am I doing something wrong? If I cursor through the text on the screen, these are 7 characters. Any ideas to help me better understand this?

FIXED / SOLVED !!!

Well, thanks for your advice that leads me in the right direction to do this job. My changes were as follows.

In AJAX - I used escape (sNameToCheck); -

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

In PHP * - I had $ username = $ _POST ['username']; - *

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

I really hate magic_quotes ... it caused me about 50 hours of frustration with the form data because I forgot about it. While this is working. I'm happy!

So, mb_strlen now works, and I can easily add it back to ...

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

It works great!

+4
source share
2 answers

PHP is a byte processor; it does not support encoding. This has a number of complex consequences.

Strlen () returns the length in bytes, not the length in characters. This is because the php type "string" is actually an array of bytes. Utf8 uses more than one byte per character for "special characters". Therefore strlen () will give you the correct answer for a narrow subset of text (= plain text in English).

Mb_strlen () treats the string as valid characters, but accepts it in the encoding specified through mbstring.internal_encoding, because the string itself is just an array of bytes and has no metadata indicating its character set. If you work with utf8 data and set internal_encoding to utf8, it will give you the correct answer. If your data is not utf8, this will give you the wrong answer.

Mysql will get the byte stream from php and analyze it based on the character set of the database session that you set using the SET NAMES directive. Each time you connect to the database, you must tell it what encoding your php lines are in.

The browser receives a stream of bytes from php and will analyze it based on the header of the http type of the charset of the content, which you control through php.ini default_charset. The Ajax call will be sent to the same encoding as the page from which it is being executed.

To summarize, you can find recommendations on the next page on how to ensure that all your data is processed as utf8. Follow her, and your problem should solve itself. http://malevolent.com/weblog/archive/2007/03/12/unicode-utf8-php-mysql/

+6
source

With a quick overview you can clear it:

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

in

 // 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'; } } 
+1
source

Source: https://habr.com/ru/post/1382795/


All Articles