PHPのお勉強!

PHP TOP

iconv

(PHP 4 >= 4.0.5, PHP 5, PHP 7, PHP 8)

iconvある文字エンコーディングの文字列を、別の文字エンコーディングに変換する

説明

iconv(string $from_encoding, string $to_encoding, string $string): string|false

文字列 string の文字セットを from_encoding から to_encoding に変換します。

パラメータ

from_encoding

string の解釈に使われる文字セット。

to_encoding

変換したいエンコーディング。

文字列 //TRANSLITto_encoding に追加すると、翻字機能が有効になります。これは、指定された文字集合で 表せない文字を、見た目の似ている別の文字に置き換える機能です。 文字列 //IGNORE を追加すると、指定された文字集合で 表せない文字は黙って切り捨てられます。 それ以外の場合は E_NOTICE が発生し、この関数は false を返します。

警告

//TRANSLIT が機能したとしたら、 どう動くかはシステムの iconv() の実装 (ICONV_IMPL を参照) に依存します。 実装によっては、//TRANSLIT を無視することが知られています。 よって、to_encoding において無効な文字に対しては、 変換処理は失敗するかもしれません。

string

変換する文字列。

戻り値

変換された文字列を返します。 失敗した場合に false を返します。

例1 iconv() の例

<?php
$text
= "This is the Euro symbol '?'.";

echo
'Original : ', $text, PHP_EOL;
echo
'TRANSLIT : ', iconv("UTF-8", "ISO-8859-1//TRANSLIT", $text), PHP_EOL;
echo
'IGNORE : ', iconv("UTF-8", "ISO-8859-1//IGNORE", $text), PHP_EOL;
echo
'Plain : ', iconv("UTF-8", "ISO-8859-1", $text), PHP_EOL;

?>

上の例の出力は、 たとえば以下のようになります。

Original : This is the Euro symbol '?'.
TRANSLIT : This is the Euro symbol 'EUR'.
IGNORE   : This is the Euro symbol ''.
Plain    :
Notice: iconv(): Detected an illegal character in input string in .\iconv-example.php on line 7

注意

注意:

文字エンコーディングと、指定できるオプションは、 インストールされている iconv の実装に依存します。 from_encodingto_encoding が現在のシステムでサポートされていない場合は、 false を返します。

参考

  • mb_convert_encoding() - ある文字エンコーディングの文字列を、別の文字エンコーディングに変換する
  • UConverter::transcode() - ある文字エンコーディングから別の文字エンコーディングに文字列を変換する

add a note

User Contributed Notes 39 notes

up
84
Ritchie
17 years ago
Please note that iconv('UTF-8', 'ASCII//TRANSLIT', ...) doesn't work properly when locale category LC_CTYPE is set to C or POSIX. You must choose another locale otherwise all non-ASCII characters will be replaced with question marks. This is at least true with glibc 2.5.

Example:
<?php
setlocale
(LC_CTYPE, 'POSIX');
echo
iconv('UTF-8', 'ASCII//TRANSLIT', "Žluťoučký kůň\n");
// ?lu?ou?k? k??

setlocale(LC_CTYPE, 'cs_CZ');
echo
iconv('UTF-8', 'ASCII//TRANSLIT', "Žluťoučký kůň\n");
// Zlutoucky kun
?>
up
77
orrd101 at gmail dot com
12 years ago
The "//ignore" option doesn't work with recent versions of the iconv library. So if you're having trouble with that option, you aren't alone.

That means you can't currently use this function to filter invalid characters. Instead it silently fails and returns an empty string (or you'll get a notice but only if you have E_NOTICE enabled).

This has been a known bug with a known solution for at least since 2009 years but no one seems to be willing to fix it (PHP must pass the -c option to iconv). It's still broken as of the latest release 5.4.3.

https://bugs.php.net/bug.php?id=48147
https://bugs.php.net/bug.php?id=52211
https://bugs.php.net/bug.php?id=61484

[UPDATE 15-JUN-2012]
Here's a workaround...

ini_set('mbstring.substitute_character', "none");
$text= mb_convert_encoding($text, 'UTF-8', 'UTF-8');

That will strip invalid characters from UTF-8 strings (so that you can insert it into a database, etc.). Instead of "none" you can also use the value 32 if you want it to insert spaces in place of the invalid characters.
up
57
daniel dot rhodes at warpasylum dot co dot uk
13 years ago
Interestingly, setting different target locales results in different, yet appropriate, transliterations. For example:

<?php
//some German
$utf8_sentence = 'Weiß, Goldmann, Göbel, Weiss, Göthe, Goethe und Götz';

//UK
setlocale(LC_ALL, 'en_GB');

//transliterate
$trans_sentence = iconv('UTF-8', 'ASCII//TRANSLIT', $utf8_sentence);

//gives [Weiss, Goldmann, Gobel, Weiss, Gothe, Goethe und Gotz]
//which is our original string flattened into 7-bit ASCII as
//an English speaker would do it (ie. simply remove the umlauts)
echo $trans_sentence . PHP_EOL;

//Germany
setlocale(LC_ALL, 'de_DE');

$trans_sentence = iconv('UTF-8', 'ASCII//TRANSLIT', $utf8_sentence);

//gives [Weiss, Goldmann, Goebel, Weiss, Goethe, Goethe und Goetz]
//which is exactly how a German would transliterate those
//umlauted characters if forced to use 7-bit ASCII!
//(because really ä = ae, ö = oe and ü = ue)
echo $trans_sentence . PHP_EOL;

?>
up
51
annuaireehtp at gmail dot com
15 years ago
to test different combinations of convertions between charsets (when we don't know the source charset and what is the convenient destination charset) this is an example :

<?php
$tab
= array("UTF-8", "ASCII", "Windows-1252", "ISO-8859-15", "ISO-8859-1", "ISO-8859-6", "CP1256");
$chain = "";
foreach (
$tab as $i)
{
foreach (
$tab as $j)
{
$chain .= " $i$j ".iconv($i, $j, "$my_string");
}
}

echo
$chain;
?>

then after displaying, you use the $i$j that shows good displaying.
NB: you can add other charsets to $tab to test other cases.
up
6
Daniel Klein
5 years ago
If you want to convert to a Unicode encoding without the byte order mark (BOM), add the endianness to the encoding, e.g. instead of "UTF-16" which will add a BOM to the start of the string, use "UTF-16BE" which will convert the string without adding a BOM.

i.e.

<?php
iconv
('CP1252', 'UTF-16', $text); // with BOM
iconv('CP1252', 'UTF-16BE', $text); // without BOM
up
9
zhawari at hotmail dot com
19 years ago
Here is how to convert UCS-2 numbers to UTF-8 numbers in hex:

<?php
function ucs2toutf8($str)
{
for (
$i=0;$i<strlen($str);$i+=4)
{
$substring1 = $str[$i].$str[$i+1];
$substring2 = $str[$i+2].$str[$i+3];

if (
$substring1 == "00")
{
$byte1 = "";
$byte2 = $substring2;
}
else
{
$substring = $substring1.$substring2;
$byte1 = dechex(192+(hexdec($substring)/64));
$byte2 = dechex(128+(hexdec($substring)%64));
}
$utf8 .= $byte1.$byte2;
}
return
$utf8;
}

echo
strtoupper(ucs2toutf8("06450631062D0020"));

?>

Input:
06450631062D
Output:
D985D8B1D8AD

regards,
Ziyad
up
8
jessiedeer at hotmail dot com
11 years ago
iconv with //IGNORE works as expected: it will skip the character if this one does not exist in the $out_charset encoding.

If a character is missing from the $in_charset encoding (eg byte \x81 from CP1252 encoding), then iconv will return an error, whether with //IGNORE or not.
up
19
manuel at kiessling dot net
15 years ago
Like many other people, I have encountered massive problems when using iconv() to convert between encodings (from UTF-8 to ISO-8859-15 in my case), especially on large strings.

The main problem here is that when your string contains illegal UTF-8 characters, there is no really straight forward way to handle those. iconv() simply (and silently!) terminates the string when encountering the problematic characters (also if using //IGNORE), returning a clipped string. The

<?php

$newstring
= html_entity_decode(htmlentities($oldstring, ENT_QUOTES, 'UTF-8'), ENT_QUOTES , 'ISO-8859-15');

?>

workaround suggested here and elsewhere will also break when encountering illegal characters, at least dropping a useful note ("htmlentities(): Invalid multibyte sequence in argument in...")

I have found a lot of hints, suggestions and alternative methods (it's scary and in my opinion no good sign how many ways PHP natively provides to convert the encoding of strings), but none of them really worked, except for this one:

<?php

$newstring
= mb_convert_encoding($oldstring, 'ISO-8859-15', 'UTF-8');

?>
up
6
jorortega at gmail dot com
11 years ago
Be aware that iconv in PHP uses system implementations of locales and languages, what works under linux, normally doesn't in windows.

Also, you may notice that recent versions of linux (debian, ubuntu, centos, etc) the //TRANSLIT option doesn't work. since most distros doesn't include the intl packages (example: php5-intl and icuxx (where xx is a number) in debian) by default. And this because the intl package conflicts with another package needed for international DNS resolution.

Problem is that configuration is dependent of the sysadmin of the machine where you're hosted, so iconv is pretty much useless by default, depending on what configuration is used by your distro or the machine's admin.
up
14
Leigh Morresi
16 years ago
If you are getting question-marks in your iconv output when transliterating, be sure to 'setlocale' to something your system supports.

Some PHP CMS's will default setlocale to 'C', this can be a problem.

use the "locale" command to find out a list..

$ locale -a
C
en_AU.utf8
POSIX

<?php
setlocale
(LC_CTYPE, 'en_AU.utf8');
$str = iconv('UTF-8', 'ASCII//TRANSLIT', "Côte d'Ivoire");
?>
up
7
nikolai-dot-zujev-at-gmail-dot-com
20 years ago
Here is an example how to convert windows-1251 (windows) or cp1251(Linux/Unix) encoded string to UTF-8 encoding.

<?php
function cp1251_utf8( $sInput )
{
$sOutput = "";

for (
$i = 0; $i < strlen( $sInput ); $i++ )
{
$iAscii = ord( $sInput[$i] );

if (
$iAscii >= 192 && $iAscii <= 255 )
$sOutput .= "&#".( 1040 + ( $iAscii - 192 ) ).";";
else if (
$iAscii == 168 )
$sOutput .= "&#".( 1025 ).";";
else if (
$iAscii == 184 )
$sOutput .= "&#".( 1105 ).";";
else
$sOutput .= $sInput[$i];
}

return
$sOutput;
}
?>
up
9
gree:.. (gree 4T grees D0T net)
17 years ago
In my case, I had to change:
<?php
setlocale
(LC_CTYPE, 'cs_CZ');
?>
to
<?php
setlocale
(LC_CTYPE, 'cs_CZ.UTF-8');
?>
Otherwise it returns question marks.

When I asked my linux for locale (by locale command) it returns "cs_CZ.UTF-8", so there is maybe correlation between it.

iconv (GNU libc) 2.6.1
glibc 2.3.6
up
10
atelier at degoy dot com
10 years ago
There may be situations when a new version of a web site, all in UTF-8, has to display some old data remaining in the database with ISO-8859-1 accents. The problem is iconv("ISO-8859-1", "UTF-8", $string) should not be applied if $string is already UTF-8 encoded.

I use this function that does'nt need any extension :

function convert_utf8( $string ) {
if ( strlen(utf8_decode($string)) == strlen($string) ) {
// $string is not UTF-8
return iconv("ISO-8859-1", "UTF-8", $string);
} else {
// already UTF-8
return $string;
}
}

I have not tested it extensively, hope it may help.
up
5
anton dot vakulchik at gmail dot com
16 years ago
function detectUTF8($string)
{
return preg_match('%(?:
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)+%xs', $string);
}

function cp1251_utf8( $sInput )
{
$sOutput = "";

for ( $i = 0; $i < strlen( $sInput ); $i++ )
{
$iAscii = ord( $sInput[$i] );

if ( $iAscii >= 192 && $iAscii <= 255 )
$sOutput .= "&#".( 1040 + ( $iAscii - 192 ) ).";";
else if ( $iAscii == 168 )
$sOutput .= "&#".( 1025 ).";";
else if ( $iAscii == 184 )
$sOutput .= "&#".( 1105 ).";";
else
$sOutput .= $sInput[$i];
}

return $sOutput;
}

function encoding($string){
if (function_exists('iconv')) {
if (@!iconv('utf-8', 'cp1251', $string)) {
$string = iconv('cp1251', 'utf-8', $string);
}
return $string;
} else {
if (detectUTF8($string)) {
return $string;
} else {
return cp1251_utf8($string);
}
}
}
echo encoding($string);
up
4
phpnet at dariosulser dot ch
5 years ago
ANSI = Windows-1252 = CP1252
So UTF-8 -> ANSI:

<?php
$string
= "Winkel γ=200 für 1€"; //"γ"=HTML:&gamma;
$result = iconv('UTF-8', 'CP1252//IGNORE', $string);
echo
$result;
?>

Note1
<?php
$string
= "Winkel γ=200 für 1€";
$result = iconv('UTF-8', 'CP1252', $string);
echo
$result; //"conv(): Detected an illegal character in input string"
?>

Note2 (ANSI is better than decode in ISO 8859-1 (ISO-8859-1==Latin-1)
<?php
$string
= "Winkel γ=200 für 1€";
$result = utf8_decode($string);
echo
$result; //"Winkel ?=200 für 1?"
?>

Note3 of used languages on Websites:
93.0% = UTF-8;
3.5% = Latin-1;
0.6% = ANSI <----- you shoud use (or utf-8 if your page is in Chinese or has Maths)
up
14
ameten
13 years ago
I have used iconv to convert from cp1251 into UTF-8. I spent a day to investigate why a string with Russian capital 'Р' (sounds similar to 'r') at the end cannot be inserted into a database.

The problem is not in iconv. But 'Р' in cp1251 is chr(208) and 'Р' in UTF-8 is chr(208).chr(106). chr(106) is one of the space symbol which match '\s' in regex. So, it can be taken by a greedy '+' or '*' operator. In that case, you loose 'Р' in your string.

For example, 'ГР ' (Russian, UTF-8). Function preg_match. Regex is '(.+?)[\s]*'. Then '(.+?)' matches 'Г'.chr(208) and '[\s]*' matches chr(106).' '.

Although, it is not a bug of iconv, but it looks like it very much. That's why I put this comment here.
up
7
nilcolor at gmail dot coom
19 years ago
Didn't know its a feature or not but its works for me (PHP 5.0.4)

iconv('', 'UTF-8', $str)

test it to convert from windows-1251 (stored in DB) to UTF-8 (which i use for web pages).
BTW i convert each array i fetch from DB with array_walk_recursive...
up