0

Got a strange one here.

I'm using a function to generate a random string of chars for a token :

private static function generatePasswordResetCode()
{
   $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-';
   return substr(str_shuffle($chars), 0, RESET_TOKEN_LENGTH);
}

RESET_TOKEN_LENGTH is a constant :

define("RESET_TOKEN_LENGTH", 100);

The code is saved to the table like so :

$code = self::generatePasswordResetCode();

$expiry_timestamp = time() + RESET_CODE_EXPIRY_TIME;

$sql = "INSERT INTO reset_codes (code, user_id, expires_at)
        VALUES (:code, :user_id, :expires_at)";

$db = static::getDB();
$stmt = $db->prepare($sql);

$stmt->bindParam(':user_id', $id, PDO::PARAM_INT);
$stmt->bindParam(':code', $code, PDO::PARAM_STR);
$stmt->bindValue(':expires_at', date('Y-m-d H:i:s', $expiry_timestamp), PDO::PARAM_STR);
$stmt->execute();

In the database the code column is set to varchar(255). I've also tried text and I have the same problem either way.

Whatever I define RESET_TOKEN_LENGTH to be up to and including 63 chars everything works fine, but any number above that and the string is being truncated in the code column :

define("RESET_TOKEN_LENGTH", 63);

// results in
MFYflHL6bVwNEG1DpqRA0ry5TgC9KhmntPUao2x-ujvekX7sZcQizWSd43OBIJ8

Great, but...

define("RESET_TOKEN_LENGTH", 64);

// results in
7fITjSp32gmA0YJCwFhrWvPk4VDQMZonl19btBKs5Ri-zULeXO...

Any ideas what could be causing this?

**** UPDATE ****

So this doesn't appear to be MySQL related but PHP related instead.

It seems that the combination of substr & str_shuffle result in a limit of 63 chars no matter what number above 63 you define.

To test it I changed the function like so :

$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-';
$code = substr(str_shuffle($chars), 0, RESET_TOKEN_LENGTH);
$code2 = substr(str_shuffle($chars), 0, RESET_TOKEN_LENGTH);

$code = $code . $code2;
return $code;

Which results in the correct var_dump output :

define("RESET_TOKEN_LENGTH", 50);

//results in
string(100) "fk8DcbusUeVxWOdp1HwNLEy9gzYm6tq0o3PMaZAIh2Sn45F-K7GH9l18hZNk73j6cQpFDfPwxMCe4BTrqiIASdRs5WEnoKgmzyXY" 

Where as doing :

define("RESET_TOKEN_LENGTH", 64);

//results in
string(126) "Q14Hd0WJjVotYRfsaU5pAM7DeZSuvwnCmxqbPgh6839XrEIyBcKTONzG-kil2FL0LUgQG8452WqKEfdmuzHlr9PZevc7VhnNCSjbk-wTyMR1iOspxaXYJDoFtBIA36" 

Showing that $code and $code2 are being truncated to 63 chars.

How very strange!

** UPDATE 2 **

It seems my lack of understanding as to how str_shuffle works was at fault here and nothing else. See the accepted answer below.

spice
  • 1,442
  • 19
  • 35
  • set `blob` it will work –  Dec 21 '19 at 18:30
  • How it the token output as it looks like how it is displayed having a limit (hence the addition of the `...`) – Nigel Ren Dec 21 '19 at 18:31
  • 1
    @dean Why won't `varchar(255)` hold 64 characters? – user3783243 Dec 21 '19 at 18:31
  • What database collation do you use when create this database? It seems for me you use kind of `unicode` which take 4 bytes for character – Romeo Ninov Dec 21 '19 at 18:35
  • `var_dump` returns `string(63)` when 64 is defined. – spice Dec 21 '19 at 18:36
  • collation is `utf8_general_ci` – spice Dec 21 '19 at 18:37
  • I'm not using Drupal but this seems like it may be relevant - https://www.drupal.org/project/drupal/issues/998898 – spice Dec 21 '19 at 18:42
  • By definition UTF-8 take from 1 to 4 bytes. And maybe this is the reason. Try to redefine column as `varchar(1024)`. And check the actual length of this column in database – Romeo Ninov Dec 21 '19 at 18:44
  • The issue seems to be with PHP and not MySQL. As the `var_dump` shows. Anything above the defined length of 63 returns `string(63)`. Could this be something to do with `substr` or `str_shuffle`? Do they have limits? – spice Dec 21 '19 at 18:47

1 Answers1

2

This has nothing to do with the DB, nor PDO. Your $chars is 63 characters long and str_shuffle just shuffles the characters in the string around. You can't get larger than 63 characters with a 63 character string.

You might be better of looking at PHP random string generator to resolve your issue.

user3783243
  • 5,368
  • 5
  • 22
  • 41
  • Over the 20+ years of programming PHP I've never run into this before. Was never aware that `str_shuffle` was limited to the number of chars you feed into it. I think I always just assumed that it would shuffle whatever you threw at it. You live 'n' learn! Thanks mate ;) – spice Dec 21 '19 at 19:07