Signature
str_rot13(string $string): stringPurpose
str_rot13() applies the ROT13 transform to a string. Every ASCII letter moves 13 places forward in the alphabet, wrapping from z back to a. Everything else, including digits, spaces, punctuation and bytes outside the ASCII letter range, stays exactly as it was.
The English alphabet has 26 letters, so shifting by 13 twice lands you back where you started. This means one function does both jobs: encoding and decoding. Passing an already transformed string to str_rot13() returns the original text.
Signature
Parameters and defaults
$string: the input text. It is the only parameter and it has no default, so you must always supply it.
There is no option for choosing a different shift amount. If you need a shift other than 13, you have to write your own mapping, for example with strtr().
Return value and failure cases
The function always returns a string. It does not return false and it does not signal failure through a return value. An empty string produces an empty string.
The returned string has the same length in bytes as the input, because each letter is replaced by exactly one other letter and nothing else changes.
With declare(strict_types=1), passing a non-string value such as an integer raises a TypeError. Without strict types, scalar values follow PHP's usual parameter coercion rules. Passing an array is always a TypeError.
Example 1: encode and decode
The simplest use is a round trip. The same call produces the encoded text and restores the original.
$original = 'Hello, World!';
$encoded = str_rot13($original);
echo $encoded, "\n";
echo str_rot13($encoded), "\n";Uryyb, Jbeyq! Hello, World!
The comma, space and exclamation mark are untouched, while the letters change and keep their case.
Example 2: what changes and what does not
Only the letters A–Z and a–z are rewritten. Digits, dots, the at sign and the byte sequence for an accented character are left alone.
$values = ['PHP 4.3.0', 'abcxyz ABCXYZ', 'user@example.com', 'café'];
$result = [];
foreach ($values as $value) {
$result[] = str_rot13($value);
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";["CUC 4.3.0","nopklm NOPKLM","hfre@rknzcyr.pbz","pnsé"]
Notice how x, y and z wrap around to k, l and m. In café, the three ASCII letters change but é stays the same, because it is stored as non-ASCII bytes and the function does not touch those.
Example 3: hiding spoilers in a list
Because str_rot13() takes a single string and returns a string, it works well as a callback for array_map().
$spoilers = ['The butler did it', 'Rosebud is a sled'];
$hidden = array_map('str_rot13', $spoilers);
$revealed = array_map('str_rot13', $hidden);
echo json_encode(['hidden' => $hidden, 'revealed' => $revealed], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"hidden":["Gur ohgyre qvq vg","Ebfrohq vf n fyrq"],"revealed":["The butler did it","Rosebud is a sled"]}
This style of light obfuscation is the classic use of ROT13: text that a reader can decode on purpose but will not read by accident.
Edge cases
- Case is preserved. Uppercase letters map to uppercase letters and lowercase to lowercase.
- Non-ASCII text is not rotated. Letters such as
é,ßor Cyrillic and Greek characters are passed through byte for byte. The function does not understand multibyte alphabets. - Digits are not shifted.
4.3.0stays4.3.0. - Applying it an even number of times is a no-op. Two calls restore the input, four calls do too.
- Binary data survives unchanged outside letters. Only bytes that are ASCII letters are replaced, but you should still treat the function as text oriented.
Common mistakes
- Treating ROT13 as encryption. There is no key and anyone can reverse it instantly. Never use it for passwords, tokens or personal data. For passwords use
password_hash(), and for secrecy use a real encryption library. - Expecting a different shift. The shift is fixed at 13. Searching for a parameter to change it will not help.
- Expecting Unicode support. Rotating
éor non-Latin letters does not happen. If you need that, build a character map yourself. - Forgetting the function is its own inverse. Writing a separate decode function is unnecessary; reuse
str_rot13(). - Passing arrays. Use
array_map('str_rot13', $array)to transform each element instead.
Related functions
strtr()for custom character mappings, including other shift amounts.str_replace()for substituting whole substrings.base64_encode()andbin2hex()for representing bytes as text, which is a different goal from obfuscation.password_hash()for storing passwords safely.
Recap
str_rot13() shifts ASCII letters by 13 places, keeps case, and leaves all other characters alone. It takes one string, returns one string, and reverses itself when applied twice. It is handy for casual obfuscation and for simple demonstrations, but it offers no security whatsoever.
Tested examples
$original = 'Hello, World!';
$encoded = str_rot13($original);
echo $encoded, "\n";
echo str_rot13($encoded), "\n";
Uryyb, Jbeyq! Hello, World!
$values = ['PHP 4.3.0', 'abcxyz ABCXYZ', 'user@example.com', 'café'];
$result = [];
foreach ($values as $value) {
$result[] = str_rot13($value);
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
["CUC 4.3.0","nopklm NOPKLM","hfre@rknzcyr.pbz","pnsé"]
$spoilers = ['The butler did it', 'Rosebud is a sled'];
$hidden = array_map('str_rot13', $spoilers);
$revealed = array_map('str_rot13', $hidden);
echo json_encode(['hidden' => $hidden, 'revealed' => $revealed], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"hidden":["Gur ohgyre qvq vg","Ebfrohq vf n fyrq"],"revealed":["The butler did it","Rosebud is a sled"]}