Kirill
Kirill

Reputation: 406

Can anyone explain this PHP code to me? Unexpected result from a single line of code

Can someone explain what is PHP doing here and if it is possible to get predictable result?

Could this be used for hiding messages?

echo '1' | 'z';

Upvotes: 0

Views: 232

Answers (4)

hakre
hakre

Reputation: 197554

If you do a bitwise operation between two strings, each character within a string represents an octet of 8 bits. The bitwise operation is then done character per character. That is converting a character into an integer first like with the ord function and then turning the result as a string (comparable to chr).

 echo '1' | 'z';

Is the same as

 echo chr(ord('1') | ord('z'));

Taken from the PHP manual:

Example #2 Bitwise XOR operations on strings

<?php
echo 12 ^ 9; // Outputs '5'

echo "12" ^ "9"; // Outputs the Backspace character (ascii 8)
                 // ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8

echo "hallo" ^ "hello"; // Outputs the ascii values #0 #4 #0 #0 #0
                        // 'a' ^ 'e' = #4

echo 2 ^ "3"; // Outputs 1
              // 2 ^ ((int)"3") == 1

echo "2" ^ 3; // Outputs 1
              // ((int)"2") ^ 3 == 1
?>

The same conversion logic applies to the OR | operator:

<?php
echo 12 | 9; // Outputs '13'

echo "12" | "9"; // Outputs the 9 character (ascii 57)
                 // ('1' (ascii 49)) | ('9' (ascii 57)) = #57

echo "hallo" | "hello"; // Outputs the ascii values #104 #101 #108 #108 #111
                        // 'a' | 'e' = #101

echo 2 | "3"; // Outputs 3
              // 2 | ((int)"3") == 3

echo "2" | 3; // Outputs 3
              // ((int)"2") | 3 == 3
?>

If you do a bitwise operation between a string and an integer, strings are converted to integer first.

Upvotes: 2

Mark Baker
Mark Baker

Reputation: 212402

It's using a bitwise OR operator

'1' = ASCII 0x31 = Binary 00110001
'z' = ASCII 0x7A = Binary 01111010

ORing the two gives

  00110001  1
| 01111010  z
= 01111011  {

which is 0x7B which is ASCII character {

And as has been pointed out, to make this reversible, XOR should be used rather than OR

XORing the two gives

  00110001  1
^ 01111010  z
= 01001011  K

which is 0x4B which is ASCII character K

Reversing:

  01001011  K
^ 01111010  z
= 00110001  1

EDIT

It's not a particularly strong code, but:

$plainTextMessage = "My secret message";
$secretCharacter = 'z';

$codedMessage = '';
for($i = 0; $i < strlen($plainTextMessage); $i++) {
    $codedMessage .= $plainTextMessage[$i] ^ $secretCharacter;
}
echo 'Coded Message is: '.$codedMessage.PHP_EOL;

$decodedMessage = '';
for($i = 0; $i < strlen($codedMessage); $i++) {
    $decodedMessage .= $codedMessage[$i] ^ $secretCharacter;
}

echo 'Decoded Message is: '.$decodedMessage.PHP_EOL;

Upvotes: 2

Tadeck
Tadeck

Reputation: 137290

This is bit-wise "or" operator. It returns a result made of bits that were set to 1 in at least one of the elements ('1' or 'z').

All of the following give the same results:

$r1 = '1' | 'z';
$r2 = chr(49) | chr(122); // chr(49) is '1', chr(122) is 'z'
$r3 = chr(49 | 122); // result is chr(123), which is '{'

and all of them are equal to '{'. See proof here: http://ideone.com/YC048

Upvotes: 0

Rich Bradshaw
Rich Bradshaw

Reputation: 72975

| is a bitwise operator - instead of operating on a string, or object, it operates on the bits (i.e. the 0s and 1s). In this case, | is OR. That is, bits that are in the first or second argument are set.

When you represent both as bits, take the bits that are in common, then echo it as a string, it happens to be '{' in this case.

Yes, you could use this to encode things - a similar but better way to do this is using XOR instead of OR. Have a look at http://en.wikipedia.org/wiki/XOR_cipher.

Upvotes: 1

Related Questions