(PHP 4 >= 4.0.5, PHP 5, PHP 7, PHP
iconv — Преобразует строку из одной кодировки символов в другую
Описание
iconv(string $from_encoding
, string $to_encoding
, string $string
): string|false
Список параметров
-
from_encoding
-
Текущая кодировка, используемая для интерпретации параметра
string
. -
to_encoding
-
Требуемая на выходе кодировка.
Если к параметру
to_encoding
добавлена строка
//TRANSLIT
, включается режим транслитерации.
Это значит, что в случае, если символ не может быть представлен в требуемой кодировке,
он может быть заменён одним или несколькими похожими символами.
Если добавлена строка//IGNORE
, то символы,
которые не могут быть представлены в требуемой кодировке, будут
удалены.
В случае отсутствия вышеуказанных параметров
будет сгенерирована ошибка уровняE_NOTICE
,
а функция вернётfalse
.Предостережение
Как будет работать
//TRANSLIT
и будет ли вообще, зависит от
системной реализации iconv() (ICONV_IMPL
).
Известны некоторые реализации, которые просто игнорируют
//TRANSLIT
, так что конвертация для символов некорректных
дляto_encoding
скорее всего закончится ошибкой. -
string
-
Строка (string) для преобразования.
Возвращаемые значения
Возвращает преобразованную строку или false
в случае возникновения ошибки.
Примеры
Пример #1 Пример использования iconv()
<?php
$text = "Это символ евро - '€'.";
echo
'Исходная строка : ', $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 'Обычное преобразование : ', iconv("UTF-8", "ISO-8859-1", $text), PHP_EOL;?>
Результатом выполнения данного примера
будет что-то подобное:
Исходная строка : Это символ евро - '€'. С добавлением TRANSLIT : Это символ евро - 'EUR'. С добавлением IGNORE :Это символ евро - ''. Обычное преобразование : Notice: iconv(): Detected an illegal character in input string in .iconv-example.php on line 7
Примечания
Замечание:
Доступные кодировки и опции зависят от установленной реализации iconv.
Если параметрfrom_encoding
илиfrom_encoding
не поддерживается в текущей системе, будет возвращено значениеfalse
.
Смотрите также
- mb_convert_encoding() — Преобразует строку из одной кодировки символов в другую
- UConverter::transcode() — Преобразует строку из одной кодировки символов в другую
orrd101 at gmail dot com ¶
10 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.
Ritchie ¶
15 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
?>
daniel dot rhodes at warpasylum dot co dot uk ¶
11 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;?>
annuaireehtp at gmail dot com ¶
13 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.
manuel at kiessling dot net ¶
13 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');?>
Leigh Morresi ¶
14 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");
?>
zhawari at hotmail dot com ¶
18 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
Nopius ¶
7 years ago
As orrd101 said, there is a bug with //IGNORE in recent PHP versions (we use 5.6.5) where we couldn't convert some strings (i.e. "∙" from UTF8 to CP1251 with //IGNORE).
But we have found a workaround and now we use both //TRANSLIT and //IGNORE flags:
$text="∙";
iconv("UTF8", "CP1251//TRANSLIT//IGNORE", $text);
Daniel Klein ¶
6 years ago
I just found out today that the Windows and *NIX versions of PHP use different iconv libraries and are not very consistent with each other.
Here is a repost of my earlier code that now works on more systems. It converts as much as possible and replaces the rest with question marks:
<?php
if (!function_exists('utf8_to_ascii')) {
setlocale(LC_CTYPE, 'en_AU.utf8');
if (@iconv("UTF-8", "ASCII//IGNORE//TRANSLIT", 'é') === false) {
// PHP is probably using the glibc library (*NIX)
function utf8_to_ascii($text) {
return iconv("UTF-8", "ASCII//TRANSLIT", $text);
}
}
else {
// PHP is probably using the libiconv library (Windows)
function utf8_to_ascii($text) {
if (is_string($text)) {
// Includes combinations of characters that present as a single glyph
$text = preg_replace_callback('/X/u', __FUNCTION__, $text);
}
elseif (is_array($text) && count($text) == 1 && is_string($text[0])) {
// IGNORE characters that can't be TRANSLITerated to ASCII
$text = iconv("UTF-8", "ASCII//IGNORE//TRANSLIT", $text[0]);
// The documentation says that iconv() returns false on failure but it returns ''
if ($text === '' || !is_string($text)) {
$text = '?';
}
elseif (preg_match('/w/', $text)) { // If the text contains any letters...
$text = preg_replace('/W+/', '', $text); // ...then remove all non-letters
}
}
else { // $text was not a string
$text = '';
}
return $text;
}
}
}
jessiedeer at hotmail dot com ¶
9 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.
atelier at degoy dot com ¶
8 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.
Daniel Klein ¶
3 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
nikolai-dot-zujev-at-gmail-dot-com ¶
18 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;
}
?>
vitek at 4rome dot ru ¶
18 years ago
On some systems there may be no such function as iconv(); this is due to the following reason: a constant is defined named `iconv` with the value `libiconv`. So, the string PHP_FUNCTION(iconv) transforms to PHP_FUNCTION(libiconv), and you have to call libiconv() function instead of iconv().
I had seen this on FreeBSD, but I am sure that was a rather special build.
If you'd want not to be dependent on this behaviour, add the following to your script:
<?php
if (!function_exists('iconv') && function_exists('libiconv')) {
function iconv($input_encoding, $output_encoding, $string) {
return libiconv($input_encoding, $output_encoding, $string);
}
}
?>
Thanks to tony2001 at phpclub.net for explaining this behaviour.
gree:.. (gree 4T grees D0T net) ¶
15 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
nilcolor at gmail dot coom ¶
17 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...
jorortega at gmail dot com ¶
9 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.
ameten ¶
12 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.
zhawari at hotmail dot com ¶
18 years ago
Here is how to convert UTF-8 numbers to UCS-2 numbers in hex:
<?phpfunction utf8toucs2($str)
{
for ($i=0;$i<strlen($str);$i+=2)
{
$substring1 = $str[$i].$str[$i+1];
$substring2 = $str[$i+2].$str[$i+3];
if (
hexdec($substring1) < 127)
$results = "00".$str[$i].$str[$i+1];
else
{
$results = dechex((hexdec($substring1)-192)*64 + (hexdec($substring2)-128));
if ($results < 1000) $results = "0".$results;
$i+=2;
}
$ucs2 .= $results;
}
return $ucs2;
}
echo
strtoupper(utf8toucs2("D985D8B1D8AD"))."n";
echo strtoupper(utf8toucs2("456725"))."n";?>
Input:
D985D8B1D8AD
Output:
06450631062D
Input:
456725
Output:
004500670025
ng4rrjanbiah at rediffmail dot com ¶
18 years ago
Here is a code to convert ISO 8859-1 to UTF-8 and vice versa without using iconv.
<?php
//Logic from http://twiki.org/cgi-bin/view/Codev/InternationalisationUTF8
$str_iso8859_1 = 'foo in ISO 8859-1';
//ISO 8859-1 to UTF-8
$str_utf8 = preg_replace("/([x80-xFF])/e",
"chr(0xC0|ord('\1')>>6).chr(0x80|ord('\1')&0x3F)",
$str_iso8859_1);
//UTF-8 to ISO 8859-1
$str_iso8859_1 = preg_replace("/([xC2xC3])([x80-xBF])/e",
"chr(ord('\1')<<6&0xC0|ord('\2')&0x3F)",
$str_utf8);
?>
HTH,
R. Rajesh Jeba Anbiah
anyean at gmail dot com ¶
17 years ago
<?php
//script from http://zizi.kxup.com/
//javascript unesape
function unescape($str) {
$str = rawurldecode($str);
preg_match_all("/(?:%u.{4})|&#x.{4};|&#d+;|.+/U",$str,$r);
$ar = $r[0];
print_r($ar);
foreach($ar as $k=>$v) {
if(substr($v,0,2) == "%u")
$ar[$k] = iconv("UCS-2","UTF-8",pack("H4",substr($v,-4)));
elseif(substr($v,0,3) == "&#x")
$ar[$k] = iconv("UCS-2","UTF-8",pack("H4",substr($v,3,-1)));
elseif(substr($v,0,2) == "&#") {
echo substr($v,2,-1)."<br>";
$ar[$k] = iconv("UCS-2","UTF-8",pack("n",substr($v,2,-1)));
}
}
return join("",$ar);
}
?>
kikke ¶
13 years ago
You can use native iconv in Linux via passthru if all else failed.
Use the -c parameter to suppress error messages.
Daniel Klein ¶
9 years ago
You can use 'CP1252' instead of 'Windows-1252':
<?php
// These two lines are equivalent
$result = iconv('Windows-1252', 'UTF-8', $string);
$result = iconv('CP1252', 'UTF-8', $string);
?>
Note: The following code points are not valid in CP1252 and will cause errors.
129 (0x81)
141 (0x8D)
143 (0x8F)
144 (0x90)
157 (0x9D)
Use the following instead:
<?php
// Remove invalid code points, convert everything else
$result = iconv('CP1252', 'UTF-8//IGNORE', $string);
?>
berserk220 at mail dot ru ¶
14 years ago
So, as iconv() does not always work correctly, in most cases, much easier to use htmlentities().
Example: <?php $content=htmlentities(file_get_contents("incoming.txt"), ENT_QUOTES, "Windows-1252"); file_put_contents("outbound.txt", html_entity_decode($content, ENT_QUOTES , "utf-8")); ?>
anton dot vakulchik at gmail dot com ¶
15 years ago
function detectUTF8($string)
{
return preg_match('%(?:
[xC2-xDF][x80-xBF] # non-overlong 2-byte
|xE0[xA0-xBF][x80-xBF] # excluding overlongs
|[xE1-xECxEExEF][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);
phpmanualspam at netebb dot com ¶
13 years ago
mirek code, dated 16-May-2008 10:17, added the characters `^~'" to the output.
This function will strip out these extra characters:
<?php
setlocale(LC_ALL, 'en_US.UTF8');
function clearUTF($s)
{
$r = '';
$s1 = @iconv('UTF-8', 'ASCII//TRANSLIT', $s);
$j = 0;
for ($i = 0; $i < strlen($s1); $i++) {
$ch1 = $s1[$i];
$ch2 = @mb_substr($s, $j++, 1, 'UTF-8');
if (strstr('`^~'"', $ch1) !== false) {
if ($ch1 <> $ch2) {
--$j;
continue;
}
}
$r .= ($ch1=='?') ? $ch2 : $ch1;
}
return $r;
}
?>
mightye at gmail dot com ¶
15 years ago
To strip bogus characters from your input (such as data from an unsanitized or other source which you can't trust to necessarily give you strings encoded according to their advertised encoding set), use the same character set as both the input and the output, with //IGNORE on the output charcter set.
<?php
// assuming '†' is actually UTF8, htmlentities will assume it's iso-8859
// since we did not specify in the 3rd argument of htmlentities.
// This generates "â[bad utf-8 character]"
// If passed to any libxml, it will generate a fatal error.
$badUTF8 = htmlentities('†');// iconv() can ignore characters which cannot be encoded in the target character set
$goodUTF8 = iconv("utf-8", "utf-8//IGNORE", $badUTF8);
?>
The result of the example does not give you back the dagger character which was the original input (it got lost when htmlentities was misused to encode it incorrectly, though this is common from people not accustomed to dealing with extended character sets), but it does at least give you data which is sane in your target character set.
phpnet at dariosulser dot ch ¶
3 years ago
ANSI = Windows-1252 = CP1252
So UTF-8 -> ANSI:
<?php
$string = "Winkel γ=200 für 1€"; //"γ"=HTML:γ
$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)
rasmus at mindplay dot dk ¶
8 years ago
Note an important difference between iconv() and mb_convert_encoding() - if you're working with strings, as opposed to files, you most likely want mb_convert_encoding() and not iconv(), because iconv() will add a byte-order marker to the beginning of (for example) a UTF-32 string when converting from e.g. ISO-8859-1, which can throw off all your subsequent calculations and operations on the resulting string.
In other words, iconv() appears to be intended for use when converting the contents of files - whereas mb_convert_encoding() is intended for use when juggling strings internally, e.g. strings that aren't being read/written to/from files, but exchanged with some other media.
martin at front of mind dot co dot uk ¶
13 years ago
For transcoding values in an Excel generated CSV the following seems to work:
<?php
$value = iconv('Windows-1252', 'UTF-8//TRANSLIT', $value);
?>
Locoluis ¶
16 years ago
The following are Microsoft encodings that are based on ISO-8859 but with the addition of those stupid control characters.
CP1250 is Eastern European (not ISO-8859-2)
CP1251 is Cyrillic (not ISO-8859-5)
CP1252 is Western European (not ISO-8859-1)
CP1253 is Greek (not ISO-8859-7)
CP1254 is Turkish (not ISO-8859-9)
CP1255 is Hebrew (not ISO-8859-8)
CP1256 is Arabic (not ISO-8859-6)
CP1257 is Baltic (not ISO-8859-4)
If you know you're getting input from a Windows machine with those encodings, use one of these as a parameter to iconv.
chicopeste at gmail dot com ¶
9 years ago
iconv also support CP850.
I used iconv("CP850", "UTF-8//TRANSLIT", $var);
to convert from SQL_Latin1_General_CP850_CI_AI to UTF-8.
jessie at hotmail dot com ¶
9 years ago
Provided that there is no invalid code point in the character chain for the input encoding, the //IGNORE option works as expected. No bug here.
vb (at) bertola.eu ¶
12 years ago
On my system, according to tests, and also as reported by other people elsewhere, you can combine TRANSLIT and IGNORE only by appending
//IGNORE//TRANSLIT
strictly in that order, but NOT by appending //TRANSLIT//IGNORE, which would lead to //IGNORE being ignored ( :) ).
Anyway, it's hard to understand how one could devise a system of passing options that does not allow to couple both options in a neat manner, and also to understand why the default behaviour should be the less useful and most dangerous one (throwing away most of your data at the first unexpected character). Software design FAIL :-/
admin at iecw dot net ¶
9 years ago
aissam at yahoo dot com ¶
18 years ago
For those who have troubles in displaying UCS-2 data on browser, here's a simple function that convert ucs2 to html unicode entities :
<?phpfunction ucs2html($str) {
$str=trim($str); // if you are reading from file
$len=strlen($str);
$html='';
for($i=0;$i<$len;$i+=2)
$html.='&#'.hexdec(dechex(ord($str[$i+1])).
sprintf("%02s",dechex(ord($str[$i])))).';';
return($html);
}
?>
Anonymous ¶
13 years ago
For text with special characters such as (é) é which appears at 0xE9 in the ISO-8859-1 and at 0x82 in IBM-850. The correct output character set is 'IBM850' as:
('ISO-8859-1', 'IBM850', 'Québec')
Andries Seutens ¶
13 years ago
When doing transliteration, you have to make sure that your LC_COLLATE is properly set, otherwise the default POSIX will be used.
To transform "rené" into "rene" we could use the following code snippet:
<?php
setlocale
(LC_CTYPE, 'nl_BE.utf8');$string = 'rené';
$string = iconv('UTF-8', 'ASCII//TRANSLIT', $string);
echo
$string; // outputs rene?>
mirek at burkon dot org ¶
14 years ago
If you need to strip as many national characters from UTF-8 as possible and keep the rest of input unchanged (i.e. convert whatever can be converted to ASCII and leave the rest), you can do it like this:
<?php
setlocale(LC_ALL, 'en_US.UTF8');
function
clearUTF($s)
{
$r = '';
$s1 = iconv('UTF-8', 'ASCII//TRANSLIT', $s);
for ($i = 0; $i < strlen($s1); $i++)
{
$ch1 = $s1[$i];
$ch2 = mb_substr($s, $i, 1);$r .= $ch1=='?'?$ch2:$ch1;
}
return $r;
}
echo
clearUTF('Šíleně žluťoučký Vašek úpěl olol! This will remain untranslated: ᾡᾧῘઍિ૮');
//outputs Silene zlutoucky Vasek upel olol! This will remain untranslated: ᾡᾧῘઍિ૮
?>
Just remember you HAVE TO set locale to some unicode encoding to make iconv handle //TRANSLIT correctly!
Проблема кодировок часто возникает при написании парсеров, чтении данных из xml и CSV файлов. Ниже представлены способы эту проблему решить.
1
windows-1251 в UTF-8
$text = iconv('windows-1251//IGNORE', 'UTF-8//IGNORE', $text);
echo $text;
PHP
$text = mb_convert_encoding($text, 'UTF-8', 'windows-1251');
echo $text;
PHP
2
UTF-8 в windows-1251
$text = iconv('utf-8//IGNORE', 'windows-1251//IGNORE', $text);
echo $text;
PHP
$text = mb_convert_encoding($text, 'windows-1251', 'utf-8');
echo $text;
PHP
3
Когда ни что не помогает
$text = iconv('utf-8//IGNORE', 'cp1252//IGNORE', $text);
$text = iconv('cp1251//IGNORE', 'utf-8//IGNORE', $text);
echo $text;
PHP
Иногда доходит до бреда, но работает:
$text = iconv('utf-8//IGNORE', 'windows-1251//IGNORE', $text);
$text = iconv('windows-1251//IGNORE', 'utf-8//IGNORE', $text);
echo $text;
PHP
4
File_get_contents / CURL
Бывают случаи когда file_get_contents()
или CURL возвращают иероглифы (ÐлмазнÑе боÑÑ) – причина тут не в кодировке, а в отсутствии BOM-метки.
$text = file_get_contents('https://example.com');
$text = "xEFxBBxBF" . $text;
echo $text;
PHP
Ещё бывают случаи, когда file_get_contents() возвращает текст в виде:
�mw�Ƒ0�����&IkAI��f��j4/{�</�&�h�� ��({�o�����:/��<g���g��(�=�9�Paɭ
Это сжатый текст в GZIP, т.к. функция не отправляет правильные заголовки. Решение проблемы через CURL:
function getcontents($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
echo getcontents('https://example.com');
PHP
12.01.2017, обновлено 02.11.2021
Другие публикации
Отправка e-mail в кодировке UTF-8 с вложенными файлами и возможные проблемы.
JSON (JavaScript Object Notation) – текстовый формат обмена данными, основанный на JavaScript, который представляет собой набор пар {ключ: значение}. Значение может быть массивом, числом, строкой и…
Описание значений глобального массива $_SERVER с примерами.
Так как Instagram и Fasebook ограничили доступ к API, а фото с открытого аккаунта всё же нужно периодически получать и…
В статье представлены различные PHP-расширения для чтения файлов XLS, XLSX, описаны их плюсы и минусы, а также примеры…
Примеры как зарегистрировать бота в Телеграм, описание и взаимодействие с основными методами API.
Иногда требуется сменить полностью кодировку файла, например с utf-8 в windows-1251. Зачастую это делается с помощью редактора кода. Но что если это необходимо сделать программно, в этом поможет функции php — iconv().
Для того чтобы не перекодировать каждую строку файла с помощью iconv(string $input_charset, string $output_charset, string $string) — мы можем преобразовать лишь одну строку. Этой строкой будет наш файл, полностью, полученный с помощью функции file_get_contents($path).
Для примера полностью перекодируем файл из UTF-8 в WINDOWS-1251.
В итоге это будет выглядеть вот так:
$file_string = file_get_contents ("tmp/test_file.csv"); $file_string = iconv("UTF-8", "WINDOWS-1251", $file_string); file_put_contents ("tmp/test_file.csv", $file_string);
Также, если вы хотите сменить окончания строк, например с Mac ( r ) формата на Windows ( rn ) / Unix ( n ) формат:
// Windows CRLF $string = preg_replace('~(*BSR_ANYCRLF)R~', "rn", $string); // Unix CR $string = preg_replace('~(*BSR_ANYCRLF)R~', "n", $string); // Mac LF $string = preg_replace('~(*BSR_ANYCRLF)R~', "r", $string);
- Главная
- Новости
- Web
- PHP
- JavaScript
- HTML и CSS
- MySQL
- Apache
- Домены
- Заработок
- SEO
- Разное
- ОС
- FreeBSD
- RouterOS
- Windows
- Linux
- Утилиты
- Git
- Редакторы
- Hardware
- Микроконтроллеры Arduino
- Справочники
- Стандарты и справочники
- Счета оплаты ЕСВ
- Здоровье
- Строительство и ремонт
- Авто
- Налогообложение
- Разное
- Веселые картинки
- Whois доменов
- Обратная связь
Главная / Web / PHP / Конвертация сайта из win-1251 …
Конвертация сайта из Windows-1251 в UTF-8
Забегая на перед можно с уверенностью сказать, что на сегодняшний день следует использовать исключительно кодировку UTF-8. Это, конечно, не означает, что нужно конвертировать из win-1251 в UTF-8 все, особенно не поддерживаемые более сайты, но задуматься о переводе активно развиваемых проектов нужно было еще, как говорят, вчера. Потребность в конвертации сайта из win-1251 в UTF-8 возникает по многим причинам, но для начала следует разобраться, в чем же принципиальная разница этих кодировок? Самое главное отличие — количество символов, которые могут содержаться в каждой из них.
Кодировка Windows-1251 может содержать не более 255 символов, так как все символы этой кодировки кодируются одним байтом. Из-за этой особенности, такие кодировки, как win-1251 еще называют «однобайтными». В состав Windows-1251 входят символы кириллического, латинского алфавитов, знаки препинания и некоторые другие символы. Из-за столь ограниченного набора символов, вывести в Windows 1251 символы китайского иероглифа (供) или, например, немецкого умляута (ö) невозможно.
Можно предположить, как делают множество создателей кириллических сайтов, что для проектов, на которых будут использоваться только кириллица или латинские символы кодировка utf-8 ни к чему. Еще больше, в приоритете использования Windows-1251 может убедить тот факт, что символы этой кодировки занимают меньше места, и в следствие чего немного быстрее обрабатываются строковыми функциями PHP.
Кодировка UTF-8 имеет настолько больше преимуществ, что увеличенный размер её символов перестает играть значимую роль и превращается в одни плюсы. В utf-8 хранится огромный набор знаков, иероглифов и букв различных алфавитов, включая и кириллические, в связи с чем русскоязычный сайт в кодировке utf-8 корректно отобразиться на компьютерах в Японии, арабских и других стран, которые даже не подозревают о существовании кодировки win-1251 и других однобайтных кодировок (KOI8-R, CP866, ISO 8859-5 и др.) с поддержкой кириллических символов.
Подробнее про кодировку UTF-8 можно узнать из материалов Википедии.
Перекодирование сайта в UTF-8
Перекодирование скриптов сайта из win-1251 в UTF-8 — это далеко не простое занятие, как может показаться на первый взгляд. Необходимо проделать большой объем работы, вкратце рассмотренный ниже:
- Конвертировать данные MySQL.
- Конвертировать файлы скриптов и некоторые другие.
- Заменить строковые функции на их мультибайтные аналоги.
- Изменить паттерны во многих функциях регулярных выражений.
- Заменить функции отправки почты.
- Исправить все внутренние перекодировки iconv() и др.
- Протестировать.
Большинство сложностей с конвертацией сайта из win-1251 (или любой другой однобайтовой кодировки) в UTF-8, в первую очередь вызваны тем, что PHP, даже самая новая версия (на момент написания статьи 5.4), не полностью поддерживает кодировку UTF-8. Поскольку большинство символов в UTF-8 закодированы двумя (до четырех) байт — обычные строковые функции не правильно работают с такими символами. Пример ниже следует набирать в UTF-8:
header(‘Content-type: text/html; charset=utf-8’);
$str = ‘Проверка кодировки’;
echo substr($str, 0, 7);
Вместо ожидаемого вывода «Проверк» получаем «Про» и «крокозябл» в конце — «�». Обычные строковые функции PHP предназначены для работы с однобайтными кодировками, символы которых состоят из одного байта, вот функция substr() и вырезает первые семь байт соответствующие симовлам «П,р,о» (кириллические буквы в UTF-8 кодируются 2-мя байтами) и первому байту буквы «в», вследствие чего «в» и превращается в «крокозябл �».
Далее будут рассмотрены способы, как подружить строковые функции PHP с кодировкой UTF-8.
Редактирование скриптов в кодировке UTF-8
Для редактирования скриптов в кодировке UTF-8 необходим редактор, который не только понимает эту кодировку, но и не добавляет специальный символ BOM, из за наличия которого скрипты могут вести себя неожиданным образом.
В качестве редактора PHP-кода можно посоветовать бесплатный NetBeans или платные редакторы PhpStorm (99$), Zend Studio (299$). Поскольку это не обычные редакторы, а так называемые IDE (интегрированная среда разработки) — дополнительный функционал этих программ будет весьма кстати при рефакторинге кода для UTF-8.
Конвертация данных в MySQL
Перед конвертацией данных в базе MySQL из Windows-1251 в UTF-8 необходимо обязательно выполнить резервное копирование конвертируемой БД, в противном случае можно безвозвратно потерять все или часть данных! Следует обратить внимание, что в MySQL кодировка Windows-1251 называется cp1251, а UTF-8 — utf8.
Первым шагом необходимо обязательно проверить — соответствует ли кодировка БД, таблиц и всех её колонок соединению по умолчанию, во избежание необратимого перекодирования неизвестных новой кодировке символов в вопросительные знаки. Точнее, следует проверить, правильно ли «общался» скрипт с БД и нет ли во всех таблицах самой БД колонок с разными кодировками. Соединение с MySQL по умолчанию для всех запросов должно быть установлено в cp1251 — этот параметр задается либо в настройках MySQL в главном конфигурационном файле (MySQL — установка и настройка default-character-set=cp1251), либо в скриптах сайта сразу после подключения к БД: mysql_query(‘SET NAMES cp1251’). Для самой БД, таблиц и её колонок кодировка также, должна быть cp1251. Выполнить проверку поможет скрипт, код которого опубликован ниже (если таблиц не много можно посмотреть данные о кодировках при помощи PHPMyAdmin):
<?php
$mysqlhost = »;
$mysqlusers = »;
$mysqlpass = »;
$dbname = »;
$db = @mysql_connect($mysqlhost, $mysqlusers, $mysqlpass);
mysql_select_db($dbname);
//mysql_query(‘SET NAMES cp1251’);
// Скрипт проверки кодировок
// http://petrenco.com/php.php?txt=142
// Кодировка соединения
$result = mysql_query(‘show variables like «character_set_connection»;’);
$row = mysql_fetch_assoc($result);
$mysql_charset_conn = $row[‘Value’];
// Кодировка БД
$result = mysql_query(‘SHOW VARIABLES LIKE «character_set_database»;’);
$row = mysql_fetch_assoc($result);
$mysql_charset_db = $row[‘Value’];
$result = mysql_query(‘SHOW TABLES’);
while ($row = mysql_fetch_row($result))
$tables_arr[] = $row[0];
$counter_tables = 0;
foreach ($tables_arr AS $table_name)
{
$result = mysql_query(‘SHOW CREATE TABLE `’.$table_name.‘`’);
while ($row = mysql_fetch_assoc($result))
{
preg_match_all(‘~`(.*?)` ([a-z]{1,10}).*?(?:character set|collate) ([a-z0-9-_]+) ~i’, $row[‘Create Table’], $matches);
preg_match(‘~DEFAULT CHARSET=([a-z0-9-_]+) {0,1}~i’, $row[‘Create Table’], $match);
if (is_array($matches[1]))
{
foreach ($matches[0] as $key => $found_cols)
{
$res_arr[$table_name][‘columns’][$matches[1][$key]][‘type’] = $matches[2][$key];
$res_arr[$table_name][‘columns’][$matches[1][$key]][‘charset’] = $matches[3][$key];
}
}
if ($match[1] !== $mysql_charset_conn)
{
$res_arr[$table_name][‘default_charset’] = $match[1];
}
$counter_tables++;
}
}
//print_r($res_arr);
$table_txt = »;
foreach ($res_arr AS $table => $vals_arr)
{
if (is_array($vals_arr[‘columns’]))
{
foreach ($vals_arr[‘columns’] AS $column => $column_val)
{
$columns .= ‘<div style=»color: red; font-weight: bold;»>Колонка: ‘.$column.‘; тип: ‘.$column_val[‘type’].‘; кодировка: ‘.$column_val[‘charset’].‘</div>’;
}
}
else
{
$columns = ‘<span style=»color: green;»>Кодировка столбцов равна кодировке таблицы</span>’;
}
if (!empty($vals_arr[‘default_charset’]))
$default_charset_txt = ‘<span style=»color: red; font-weight: bold;»>’.$vals_arr[‘default_charset’].‘</span>’;
else
$default_charset_txt = ‘<span style=»color: green;»>’.$mysql_charset_conn.‘</span>’;
$table_txt .= ‘
<tr style=»background: #fff;»>
<td>’.$table.‘</td>
<td>’.$default_charset_txt.‘</td>
<td>’.$columns.‘</td>
</tr>’;
}
if ($mysql_charset_db !== $mysql_charset_conn)
$db_charset = ‘<h2 style=»color: red;»>В БД ‘.$dbname.‘ установлена кодировка по умолчанию: ‘.$mysql_charset_db.‘</h2>’;
else
$db_charset = ‘<h2 style=»color: green;»>В БД ‘.$dbname.‘ установлена кодировка по умолчанию: ‘.$mysql_charset_db.‘</h2>’;
$counter_tables;
if (empty($table_txt))
$table_found = ‘<h2 style=»color: green;»>Найдено таблиц ‘.$counter_tables.‘ шт., кодировка соединения соответствует табличным кодировкам по умолчанию</h2>’;
else
{
$table_found = ‘
<h2 style=»color: red;»>Таблицы не соответствующие кодировке соединения</h2>
<table cellpadding=»5″ cellspacing=»1″ style=»background: grey;»>
<tr style=»background: red;»>
<th>Название таблицы</th>
<th>Кодировка таблицы<br>
(DEFAULT CHARSET)
</th>
<th>Кодировка колонок</th>
</tr>
‘.$table_txt.‘
</table>’;
}
echo ‘<h1>Кодировка соединения с БД: <span style=»color: orange; font-size: 70px;»>’.$mysql_charset_conn.‘</span></h1>
‘.$db_charset.‘
‘.$table_found.»;
?>
Скрипт находит все несоответствующие соединению кодировки в БД. О наличии таких кодировок можно узнать из сообщений красного цвета. Как подготовить такие данные к конвертации можно прочитать тут: «Проблемы с кодировкой в MySQL версий 4.1+», «Исправление и преобразование кодировок таблиц MySQL». Если на странице только черный, зеленый и оранжевый (кодировка соединения) цвета — с кодировками в БД все впорядке и можно приступать к конвертированию данных: «Конвертация БД из Win-1251 в UTF8».
После преобразования данных в таблицах MySQL из cp1251 в utf8 необходимо изменить кодировку по умолчанию для скриптов (изменение настройки в my.ini / my.conf или SQL запросом SET NAMES utf8 каждый раз после подключения к БД). Также следует заменить заголовок с указанием кодировки, отправляемый сервером браузеру клиента. Это можно сделать изменив в HTML-коде строку, расположенную между дескрипторами <head>…</head>
…
<meta http-equiv=«Content-Type» content=«text/html; charset=UTF-8»>
…
или выведя заголовок непосредственно средствами PHP:
header(‘Content-type: text/html; charset=utf-8’);
Эти два способа указания кодировки браузеру можно совместить.
Теперь, вся информация из БД будет выводиться на страницах сайта как положено, а вот все тексты не латинскими буквами, расположенные в скриптах, отобразятся «кракозяблами». Для превращения «кракозяблов» в нормальный текст необходимо перекодировать уже сами скрипты, о чем речь пойдет в следующем разделе.
Перекодировка скриптов из Windows-1251 в UTF-8
Поскольку латинские буквы и знаки препинания имеют одинаковые коды символов как в кодировке Windows-1251 и так и в UTF-8 — проблем с их отображением не возникнет. В связи с этим ни код PHP, ни HTML-разметка, заданная латинскими буквами и знаками препинания практически не пострадают. Другое дело — кириллический алфавит.
Чтобы кириллические символы отображались как положено в кодировке UTF-8 необходимо их перекодировать. Один из простейших способов организовать этот процесс — использование мощностей библиотеки ICONV (PHP-функция iconv()). Конвертировать все подряд не нужно — необходимо исключить бинарные файлы (файлы изображений, pdf, архивов и др.) — если случайно конвертировать и их — данные этих файлов будут потеряны.
Скрипт, представленный ниже, помогает автоматизировать процесс конвертирования скриптов в UTF-8 из Windows 1251. Функция win1251_to_utf8() обрабатывает все вложенные директории и файлы, позволяя задать исключения — файлы и директории, данные в которых конвертировать в UTF-8 не нужно. Также необходимо задать расширения файлов — только файлы с заданными расширениями будут конвертированы. Перед запуском скрипта — обязательно сделайте резервную копию конвертируемых файлов! Ведь, например, если случайно запустить этот скрипт повторно, и конвертировать файлы, которые уже находятся в кодировке UTF-8 из Win1251 снова в UTF-8 — возможны проблемы с данными.
Перед запуском функции win1251_to_utf8(), следует ОБЯЗАТЕЛЬНО убедиться, что все файлы, подлежащие конвертации доступны на запись, в противном случае может получиться «каша» из файлов с кодировкой Windows-1251 и UTF-8, разобраться в которой будет уже совсем не легко. Для этих целей следует изначально задать переменной $convert значение 0. Если ошибок не найдено, то тогда нужно присвоить $convert значение 1.
<?php
ini_set(‘display_errors’, 1);
// Конвертер модуля ссылок
// Входные данные
// $source ……. — путь к директории, например my_script_w1251/scripts (в конце слеш не нужен)
// $ext_convert … — массив с разрешенными расширениями файлов — только файлы с указанными разрешениями будут конвертироваться. Например: array(‘php’, ‘inc’);
// $exclude …… — массив с файлами и директориями, данные которых конвертировать запрещено. Например: array(‘dir’ => array(‘mod’, ‘lib/scripts’), ‘file’ => array(‘lib/index.php’))
// $convert …… — флаг (1 перезаписывать файлы, 0 — только прочитать/проверить доступ на запись)
// $result ……. — стоит оставить пустым, используется для передачи данных при рекурсивном проходе директорий
// Результат выполнения — $result = win1251_to_utf8()
// $result[‘output_txt’] … — текстовый вывод в HTML результатов выполнения функции: черный цвет — найденный файл подлежит конвертации (расширение есть в массиве), серый цвет — не подлежит
function win1251_to_utf8($source, $ext_convert = array(), $exclude = array(‘file’ => array(), ‘dir’ => array()), $convert = 0, $result = array())
{
// http://petrenco.com/php.php?txt=142
if (!isset($result[‘source’][‘dir’]))
{
$result[‘source’][‘dir’] = $source;
$result[‘source’][‘strlen’] = mb_strlen($source);
}
if ($paths = array_diff(scandir($source), array(‘..’, ‘.’)))
{
foreach($paths as $path)
{
if (is_dir($source.‘/’.$path))
{
// Обработка исключений
if (!in_array($source.‘/’.$path, $exclude[‘dir’]))
{
$result = win1251_to_utf8($source.‘/’.$path, $ext_convert, $exclude, $convert, $result);
}
}
else
{
if (!in_array($source.‘/’.$path, $exclude[‘file’]))
{
// Только файлы с определенными расширениями
foreach ($ext_convert AS $key => $ext)
$tmp .= ‘(?:.’.$ext.‘)|’;
$tmp = substr($tmp, 0, —1);
$pattern = ‘~’.$tmp.‘$~i’;
$result[‘counter_files’]++;
if (preg_match($pattern, $source.‘/’.$path))
{
$file_content = file_get_contents($source.‘/’.$path);
// Перекодировка
$fs1 = filesize($source.‘/’.$path);
if ($convert == 1)
{
// Проверка на доступность файла для записи
if (!is_writable($source.‘/’.$path))
{
$result[‘output_txt’] .= ‘<div style=»color: red;»>’.$result[‘counter_files’].‘. Ошибка: ‘.$source.‘/’.$path.‘ не доступен для записи, конвертация остановлена.</div>’;
return $result;
}
$file_content = iconv(‘windows-1251’, ‘utf-8’, $file_content);
file_put_contents($source.‘/’.$path, $file_content);
$fs2 = filesize($source.‘/’.$path);
if ($fs1 != $fs2)
$result[‘output_txt’] .= ‘<div style=»color: red;»>’.$result[‘counter_files’].‘. Ошибка: ‘.$source.‘/’.$path.‘ (‘.$fs1.‘ != ‘.$fs2.‘)</div>’;
else
$result[‘output_txt’] .= ‘<div style=»color: green;»>’.$result[‘counter_files’].‘. ‘.$source.‘/’.$path.‘</div>’;
}
else
{
if (!is_writable($source.‘/’.$path))
$result[‘output_txt’] .= ‘<div style=»color: red;»>’.$result[‘counter_files’].‘. Ошибка: ‘.$source.‘/’.$path.‘ не доступен для записи.</div>’;
else
$result[‘output_txt’] .= ‘<div style=»»>’.$result[‘counter_files’].‘. ‘.$source.‘/’.$path.‘</div>’;
}
$result[‘path’][‘conv_file_path’][] = $source.‘/’.$path;
}
else
{
$result[‘output_txt’] .= ‘<div style=»color: #a0a0a0;»>’.$result[‘counter_files’].‘. ‘.$source.‘/’.$path.‘</div>’;
}
}
}
}
}
return $result;
}
$source = ‘my_project/lib’; // Начинать с той же директории, из которой запущен файл с функцией
$convert = 0;
$ext_convert = array(‘php’, ‘inc’, ‘html’, ‘htm’);
$exclude_dir = array($source.‘/img’, $source.‘/scripts’); // Директории, файлы в которых конвертировать не нужно
$exclude_file = array($source.‘/!capcha.php’); // файлы, которые конвертировать не нужно
$exclude = array(‘file’ => $exclude_file, ‘dir’ => $exclude_dir);
$result_func = win1251_to_utf8($source, $ext_convert, $exclude, $convert);
echo ‘<html>
<head>
<title>Конвертация файлов</title>
<meta http-equiv=»Content-Type» content=»text/html; charset=utf-8″>
</head>
<body>
‘
.$result_func[‘output_txt’].‘
</body>
</html>’;
?>
После изменения кодировки файлов необходимо прописать или изменить локаль (предварительно, стоит ознакомиться с документацией по функции setlocale(), чтобы избежать проблем из-за отличий в операционных системах):
setlocale (LC_ALL, «ru_RU.UTF-8»);
Эта строчка должна присутствовать вначале каждого скрипта.
После этих действий, весь сайт, скорее всего, отобразится как положено. «Скорее всего» потому, что еще необходимо внести изменения в коде скриптов, т.е. произвести рефакторинг кода — решить проблему со строковыми и некоторыми другими функциями PHP при работе с кодировкой UTF-8.
Строковые функции PHP и UTF-8
Как было написано ранее, обычные строковые функции PHP (strlen(), substr(), strtolower() и др.) корректно работают только с однобайтными кодировками. Для мультибайтных кодировок, одной из которых и является UTF-8, необходимо применять специальные функции, например, из расширения PHP Mbstring.
Исключением является функция strlen(). В однобайтной кодировке, функция, возвращая количество символов, возвращает и размер строки в байтах, поскольку, как уже говорилось ранее, каждый символ в таких кодировках равен одному байту, и, соответственно, количество символов строки равно размеру в байтах. Заменять такую функцию, например на mb_strlen() нужно только тогда, когда задача strlen() была в подсчете количества символов. Если же strlen() использовалась для подсчета размера строки в байтах с последующей передачей этих данных, например в заголовок HTTP отправляемый клиенту для указания размера передаваемых данных — её следует оставить без изменений. Например, необходимо узнать размер и кол-во символов строки «строка, передаваемая клиенту»:
<?php
mb_internal_encoding(‘UTF-8’);
setlocale (LC_ALL, «ru_RU.UTF-8»);
header(‘Content-type: text/html; charset=utf-8’);
$str = ‘строка, передаваемая клиенту’;
$strlen = strlen($str);
$mb_strlen = mb_strlen($str);
echo ‘Строка состоит из: ‘.$strlen.‘ байт и ‘.$mb_strlen.‘ символов.’;
// 53 байта, 28 символов
?>
(В кодировке UTF-8 кириллические символы занимают 2 байта, пробел и запятая — 1 байт)
Есть несколько решений этой проблемы: перезагрузка функций, замена обычных строковых функций в коде на функции с приставкой «mb_» и использование функций написанных сторонними разработчиками или самостоятельно.
Перезагрузка функций
Перезагрузка функций — это указание интерпретатору PHP воспринимать часть обычных функций, работающих с однобайтовыми кодировками как функции MBString — со списком перегружаемых функций можно ознакомиться в официальной документации PHP). Чтобы выполнить перезагрузку функций необходимо в главном конфигурационном файле PHP (php.ini) установить параметр:
Ранее, до версии PHP 5.2.7, изменение настроек перезагрузки функций можно было осуществить в файле .htaccess (php_value mbstring.func_overload 2), но в более поздних версиях эта возможность, к сожалению, не доступна.
Если необходимо установить/отключить перезагрузку функций только для одного/нескольких сайтов следует воспользоваться директивой php_admin_value mbstring.func_overload 2 в конфигурации сервера Apache для виртуальных хостов.
Перезагрузку функций стоит применять лишь для быстрого изменения поведения скриптов. Мало того, что перезагрузка изменяет поведение далеко не всех необходимых функций, так еще она не решает проблему с определением, в каком контексте используется функция strlen().
Замена строковых функций
Замена строковых функций, другими словами рефакторинг кода PHP, более трудоёмкое, но и более правильное решение. Заменять обычные строковые функции можно на функции из библиотеки MBString или другие функции. Лучший вариант — заменить все однобайтовые функции аналогами с приставкой «mb_», а вот функции, которые аналогов не имеют (str_split(), wordwrap(), ucfirst(), lcfirst(), ucwords() и др.) — создавать самостоятельно или искать готовые решения в сети, например в комментариях к каждой из функций в официальной документации PHP.
Для замены функций на MB-аналоги как раз и пригодится один из редакторов, о которых говорилось выше. Предлагаемый способ замены тестировался в NetBeans, но скорее всего он будет аналогичен и в других IDE.
Перед использованием функций из MBString необходимо установить внутреннюю кодировку скрипта в UTF-8 при помощи функции mb_internal_encoding(), которая должна выполнятся перед использованием всех функций MBString в скриптах
mb_internal_encoding(‘UTF-8’)
Также, задать внутреннюю кодировку скрипта можно в конфигурационном файле PHP — тогда этот параметр распространится на все скрипты.
Для начала следует создать проект в NetBeans, в который должны быть включены все скрипты, обслуживающие сайт. Далее, для замены, например функции substr(), необходимо создать собственную функцию substr() в новом файле подключенном к проекту, иначе рефакторинг произвести не удастся:
<?php
function substr() {};
?>
Потом на функции subst() нужно нажать правой кнопкой мыши и из меню выбрать: Refactor -> Rename, в поле New Name изменить subst на mb_substr и нажать кнопку «Preview»:
Теперь можно заменить все функции сразу во всех файлах проекта, либо предварительно просмотреть в каком контексте используется substr() в коде каждого файла скрипта — байты или символы.
На что еще следует обратить внимание
Регулярные выражения и UTF-8
Чтобы регулярные выражения в функциях preg_…() работали корректно, необходимо добавить модификатор шаблона u. Также, следует забыть о шаблоне w, и заменить его на pL, хотя лучше всего использовать такую конструкцию [а-я].
Функция iconv()
Необходимо найти все вызовы функций iconv() в коде скриптов сайта, и заменить кодировки, либо вообще убрать эту функцию там, где из UTF-8 символы перекодировались в Windows1251.
Sape
Если сайт работает с ситемой Сапе (на сайте размещаются ссылки), необходимо изменить код подключения Сапе и вместо $sape = new SAPE_client() нужно написать:
$o[‘charset’] = ‘UTF-8’;
$sape = new SAPE_client($o);
unset($o);
Подробнее тут.
Опубликовано: 2012/06/10
HTML-код ссылки на эту страницу:
<a href=»https://petrenco.com/php.php?txt=142″ target=»_blank»>Конвертация сайта из win-1251 в UTF-8</a>
51459