Ind F. Ashiku
Ind F. Ashiku

Reputation: 169

PHP utf8 encoding and decoding

I have the following code in php

$test = "\151\163\142\156";
echo utf8_decode($test);
var_dump($test);

and i get the following result:

isbn
string(4) "isbn"

I get some text from a txt file that has the \151\163\142\156 text

$all_text = file_get_contents('test.txt');
var_dump($all_text);

result:

string(16) "\151\163\142\156"

I have the following questions:

  1. how can i utf8 decode the second text so i get the isbn result?

  2. how can i encode the isbn to get \151\163\142\156 ?

EDIT

(from comments)

I tried everything with iconv and encode but nothing worked. The text from the .txt file is string(16) and not string(4) so i can encode it. The txt file is saved from sublime with Western (ISO 8859-1) encoding

Upvotes: 1

Views: 2982

Answers (2)

deceze
deceze

Reputation: 522626

This has absolutely nothing to do with UTF-8 encoding. Forget about that part entirely. utf8_decode doesn't do anything in your code. iconv is entirely unrelated.

It has to do with PHP string literal interpretation. The \... in "\151\163\142\156" is a special PHP string literal escape sequence:

\[0-7]{1,3}
the sequence of characters matching the regular expression is a character in octal notation, which silently overflows to fit in a byte (e.g. "\400" === "\000")

http://php.net/manual/en/language.types.string.php#language.types.string.syntax.double

Which very easily explains why it works when written in a PHP string literal, and doesn't work when reading from an outside source (because the external text read through file_get_contents is not being interpreted as PHP code). Simply do echo "\151\163\142\156" and you'll see "isbn" without any other conversions necessary.

To manually convert the individual escape sequences in the string \151\163\142\156 to their character equivalents (really: their byte equivalents):

$string = '\151\163\142\156';  // note: single quotes cause no iterpretation
echo preg_replace_callback('/\\\\([0-7]{1,3})/', function ($m) {
    return chr(octdec($m[1]));
}, $string)
// isbn

stripcslashes happens to include this functionality, but it also does a whole lot of other things which may be undesired.

The other way around:

$string = 'isbn';
preg_replace_callback('/./', function ($m) {
    return '\\' . decoct(ord($m[0]));
}, $string)
// \151\163\142\156

Upvotes: 1

Try using stripcslashes :

<?php

$test = "\151\163\142\156";
echo utf8_decode( $test );                         // "isbn"
var_dump( $test );

echo "<br/><br/><br/>";

$all_text = file_get_contents( "test.txt" );
echo utf8_decode( $all_text ) .                    // "\151\163\142\156"
     "<br/>" .
     utf8_decode( stripcslashes( $all_text ) );    // "isbn"
var_dump( stripcslashes( $all_text ) );

?>

Tested with this file :

This is some text :

\151\163\142\156

And this is more text!!!

Next is how to convert chars to codes :

<?php
$test = "isbn";
$coded = "";
for ( $i = 0; $i < strlen( $test ); $i++ ) // PROCESS EACH CHAR IN STRING.
  $coded .= "\\" . decoct( ord( $test[ $i ] ) ); // CHAR CODE TO OCTAL.

echo $coded .                           // "\151\163\142\156"
     "<br/>" .
     stripcslashes( $coded );           // "isbn".
?>

Let's make it more general with a function that we can call anywhere :

<?php
function code_string ( $s )
{ $coded = "";
  for ( $i = 0; $i < strlen( $s ); $i++ )
    $coded .= "\\" . decoct( ord( $s[ $i ] ) );
  return $coded;
}

$x = code_string( "isbn" );
echo $x .                           // "\151\163\142\156"
     "<br/>" .
     stripcslashes( $x );           // "isbn".
?>

Upvotes: 1

Related Questions