Search code examples
phpstringspecial-charactersshuffle

Why do some characters lose when I use str_shuffle() in PHP?


This is the code in lib.php:

<?php

class table {

    function __construct($string, $time) {

        $out = '<table cellpadding="5">';
        $out .= $this->getRow('th', 'Nom., Shuffled String, Lenght');

        for ($x = 1; $x <= $time; $x++) {

            $shuffledStr = str_shuffle($string); //Maybe this causes the problem
            $shuffledStr_len = strlen($shuffledStr);
            $out .= $this->getRow('td', $x . ', ' . $shuffledStr . ', ' . $shuffledStr_len);
        }

        $out .= '</table>';

        echo $out;
    }

    public function getRow($tagName, $contents_list) {

        //Variables:
        $out = '';
        $contents_array = explode(', ', $contents_list);
        $contents_number = count($contents_array);
        $start_tag = '<' .  $tagName . '>';
        $end_tag = '</' .   $tagName . '>';

        // Build
        $out .= '<tr>';

        for ($i = 0; $i < $contents_number; $i++) {
            $out .= $start_tag . $contents_array[$i] . $end_tag;
        }

        $out .= '</tr>';

        return $out;
    }

}
?>

And here is index.php:

    <?php
require_once 'lib.php';
$string = ''; //My string
$shuffleTimes = 100;
$table = new table($string, $shuffleTimes);
?>

This program gets the a string and the number that you wanna shuffle, then create a table and returns the number, shuffled string and the length of the shuffle string in each row.

If I set the variable $string to 'Stack Overflow' for instance it'll work correctly (It shuffles this word 100 times randomly, returns all lengths 14 and the length of the ALL shuffled strings are really 14.)

But...

If I add some special character to the variable $string (for example Stack Overflow+_)(*&^%$#{}[]<>@!~./=-) it won't work correctly. That means it returns the lengths 37 But they doesn't have 37 characters!(For example it printed nothing and printed it's lenght 38. I think it's a bit strange. :(

Why is that?! Which character causes that and how to fix it?


Solution

  • There are multiple issues with your code.

    1. getRow() issue :

    The problem is in getRow(), where you concat parameters into one string with ,, and then explode by ,. If your string has , inside it, then you will have problems, example: Stack ,test.

    2. multibyte issue :

    This code doesn't work for multibyte characters. To accomplish that you will need to change function str_shuffle() with function bellow mb_str_shuffle(), and strlen() with mb_strlen().

    function mb_str_shuffle($str) {
        $tmp = preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
        shuffle($tmp);
        return join("", $tmp);
    }
    

    Or some other unicode function that you find in comments on http://php.net/manual/en/function.str-shuffle.php

    3. length is ok, but string is missing issue :

    This is because you have HTML special chars in your string, like < and >. If string Stack Overflow+_)(*&^%$#{}[]<>@!~./=- is shuffled, and you get something like a#^&/c-_O. instead of a#^&/c-_O.< ~*>)$wevS+{(%}klr[]f=to!@. You should escape special chars with htmlspecialchars() when you output the string.