Search code examples
phpstr-replacecaesar-cipher

PHP caesar cipher function str_replace is changing characters wrong


I am trying to make a caesar cipher function with PHP but I have a problem with str_replace.

When I'm do this,

function evangel($data, $key) {
    $alphabet = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');

    $cryptoAlphabet = array();

    for($i=0;$i<26;$i++) {
        $index = $i+$key;
        if($i+$key > 25) $index = (($i+$key)%25)-1;

        $cryptoAlphabet[$i] = $alphabet[$index];
    }

    $cryptedData = str_replace($alphabet, $cryptoAlphabet, $data);

    return $cryptedData;
}

It gives me these arrays;

$alphabet = Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f [6] => g [7] => h [8] => i [9] => j [10] => k [11] => l [12] => m [13] => n [14] => o [15] => p [16] => q [17] => r [18] => s [19] => t [20] => u [21] => v [22] => w [23] => x [24] => y [25] => z )

$cryptoAlphabet  = Array ( [0] => b [1] => c [2] => d [3] => e [4] => f [5] => g [6] => h [7] => i [8] => j [9] => k [10] => l [11] => m [12] => n [13] => o [14] => p [15] => q [16] => r [17] => s [18] => t [19] => u [20] => v [21] => w [22] => x [23] => y [24] => z [25] => a ) 

And this output for my $data = "aacceett" and $key = 1;

aaaaaaaa

But when I'm do this;

function evangel($data, $key) {
    $alphabet = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');

    $cryptoAlphabet = array('z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y');

    $cryptedData = str_replace($alphabet, $cryptoAlphabet, $data);

    return $cryptedData;
}

The arrays are declared manually but this time, for example when my $data = "ffddss";

eeccrr

The output is correct. Why when I'm changing the alphabet array automatically the str_replace function is not working?


Solution

  • Your crytpo alphabet is different in each case. In the first case, the [0] element is b, and in the second, z. Your code produces the results it does because - for example - when it sees a, it replaces it with b, then it see that the replacement for b is c, so it does that, and so on until it runs through the entire array, eventually finishing with the replacement of z with a, so all characters in the output become a. In your second case, a is translated to z (which will then get translated to y) but all other characters are replaced with something that comes earlier in the array, so they are not replaced again.

    You can work around this issue by using strtr instead. The difference between strtr and str_replace is that strtr will only replace a given substring once.

    function evangel($data, $key) {
        $alphabet = range('a', 'z');
        $cryptoAlphabet = array();
        for($i=0;$i<26;$i++) {
            $index = $i+$key;
            if($i+$key > 25) $index = (($i+$key)%25)-1;
    
            $cryptoAlphabet[$i] = $alphabet[$index];
        }
        $cryptedData = strtr($data, array_combine($alphabet, $cryptoAlphabet));
        return $cryptedData;
    }
    
    echo evangel('aacceett', 7);
    

    Output

    hhjjllaa
    

    Demo on 3v4l.org

    Note you can simplify your definition of $alphabet using range.