私はさまざまなRSSフィードからたくさんのテキストを読み、それらを私のデータベースに挿入しています。
もちろん、フィードにはいくつかの異なる文字エンコーディングが使用されています。 UTF-8およびISO-8859-1.
残念ながら、テキストのエンコーディングに問題がある場合があります。例:
"Fußball"の "ß"は私のデータベースでは "Â"のように見えるはずです。 「Â」の場合は正しく表示されます。
私のデータベースでは "Fußball"の "ß"が "ß"のように見えることがあります。それからもちろんそれは間違って表示されます。
それ以外の場合、 "ß"は "ß"として保存されます - 変更はありません。それからそれはまた間違って表示されます。
ケース2と3を回避するために私は何ができますか?
どのようにしてすべてを同じエンコーディング、できればUTF-8にすることができますか?いつutf8_encode()
を使用しなければならないのか、utf8_decode()
を使用しなければならない場合(効果は明確ですが、関数を使用しなければならない場合はいつですか)、そしていつ入力を何もしなければなりませんか?
あなたは私を助けて、すべてを同じエンコーディングにする方法を教えてもらえますか?おそらくmb_detect_encoding()
関数がありますか?このための関数を書くことができますか?だから私の問題は次のとおりです。
このような機能は動作しますか?
function correct_encoding($text) {
$current_encoding = mb_detect_encoding($text, 'auto');
$text = iconv($current_encoding, 'UTF-8', $text);
return $text;
}
私はそれをテストしましたが、うまくいきません。どうしたんだ?
utf8_encode()
をすでにUTF8の文字列に適用すると、文字化けしたUTF8出力が返されます。
これらすべての問題に対処する機能を作りました。それはEncoding::toUTF8()
と呼ばれます。
あなたはあなたの文字列のエンコーディングが何であるかを知る必要はありません。 Latin1(iso 8859-1)、Windows-1252、UTF8のいずれか、または文字列にそれらを混在させることができます。 Encoding::toUTF8()
はすべてをUTF8に変換します。
これは、UTF-8とLatin1を同じ文字列に混在させて、サービスがすべてのデータをめちゃくちゃにしているためです。
使用法:
require_once('Encoding.php');
use \ForceUTF8\Encoding; // It's namespaced now.
$utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string);
$latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string);
ダウンロード:
https://github.com/neitanod/forceutf8
更新:
文字化けしているように見えるすべてのUTF8文字列を修正する別の関数Encoding::fixUFT8()
を含めました。
使用法:
require_once('Encoding.php');
use \ForceUTF8\Encoding; // It's namespaced now.
$utf8_string = Encoding::fixUTF8($garbled_utf8_string);
例:
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
出力されます:
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
更新:関数(forceUTF8
)をEncoding
というクラスの静的関数のファミリーに変換しました。新しい関数はEncoding::toUTF8()
です。
最初にどのエンコーディングが使用されているのかを検出する必要があります。 RSSフィードを(おそらくHTTP経由で)解析しているので、 Content-Type
HTTPヘッダフィールド のcharset
パラメータからエンコーディングを読むべきです。存在しない場合は、 XML処理命令 のencoding
属性からエンコードを読み取ります。それも欠けている場合、 仕様で定義されているように UTF-8を使用してください。
編集これは私がおそらくすることです:
応答を送信して取得するには、 cURL を使用します。これにより、特定のヘッダフィールドを設定したり、レスポンスヘッダを取得したりすることができます。レスポンスを取得した後、HTTPレスポンスを解析してそれをヘッダーとボディに分割する必要があります。ヘッダはMIMEタイプを含むContent-Type
ヘッダフィールドと(うまくいけば)encoding/charsetを持つcharset
パラメータを含むべきです。そうでない場合は、encoding
属性が存在するかどうかXML PIを分析し、そこからエンコーディングを取得します。それも欠けている場合、XML仕様はエンコーディングとしてUTF-8を使用するように定義します。
$url = 'http://www.lr-online.de/storage/rss/rss/sport.xml';
$accept = array(
'type' => array('application/rss+xml', 'application/xml', 'application/rdf+xml', 'text/xml'),
'charset' => array_diff(mb_list_encodings(), array('pass', 'auto', 'wchar', 'byte2be', 'byte2le', 'byte4be', 'byte4le', 'BASE64', 'UUENCODE', 'HTML-ENTITIES', 'Quoted-Printable', '7bit', '8bit'))
);
$header = array(
'Accept: '.implode(', ', $accept['type']),
'Accept-Charset: '.implode(', ', $accept['charset']),
);
$encoding = null;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
$response = curl_exec($curl);
if (!$response) {
// error fetching the response
} else {
$offset = strpos($response, "\r\n\r\n");
$header = substr($response, 0, $offset);
if (!$header || !preg_match('/^Content-Type:\s+([^;]+)(?:;\s*charset=(.*))?/im', $header, $match)) {
// error parsing the response
} else {
if (!in_array(strtolower($match[1]), array_map('strtolower', $accept['type']))) {
// type not accepted
}
$encoding = trim($match[2], '"\'');
}
if (!$encoding) {
$body = substr($response, $offset + 4);
if (preg_match('/^<\?xml\s+version=(?:"[^"]*"|\'[^\']*\')\s+encoding=("[^"]*"|\'[^\']*\')/s', $body, $match)) {
$encoding = trim($match[1], '"\'');
}
}
if (!$encoding) {
$encoding = 'utf-8';
} else {
if (!in_array($encoding, array_map('strtolower', $accept['charset']))) {
// encoding not accepted
}
if ($encoding != 'utf-8') {
$body = mb_convert_encoding($body, 'utf-8', $encoding);
}
}
$simpleXML = simplexml_load_string($body, null, LIBXML_NOERROR);
if (!$simpleXML) {
// parse error
} else {
echo $simpleXML->asXML();
}
}
エンコードを検出するのは難しいです。
mb_detect_encoding
は、合格した候補者の数に基づいて推測して機能します。一部のエンコーディングでは、特定のバイトシーケンスが無効であるため、さまざまな候補を区別できます。残念ながら、同じバイトが有効である(しかし異なる)エンコーディングがたくさんあります。このような場合、エンコーディングを決定する方法はありません。これらの場合に推測するためにあなた自身のロジックを実装することができます。たとえば、日本のサイトからのデータは日本語のエンコーディングを持つ可能性が高くなります。
西ヨーロッパ言語のみを扱う限り、考慮すべき3つの主要なエンコーディングはutf-8
、iso-8859-1
およびcp-1252
です。これらは多くのプラットフォームでデフォルトになっているので、間違って報告される可能性が最も高いです。例えば。人々が異なるエンコーディングを使用する場合、彼らはそれについて率直である可能性があります。したがって、エンコーディングがこれら3つのうちの1つとして報告されていない限り、良い戦略はプロバイダを信頼することです。 mb_check_encoding
を使用して、実際に有効であることを再度確認する必要があります(validはbeingと同じではありません)。 - 同じ入力が多くのエンコーディングに対して有効かもしれません)。それらのうちの1つであれば、mb_detect_encoding
を使ってそれらを区別することができます。幸いなことに、それはかなり決定的です。あなたはUTF-8,ISO-8859-1,WINDOWS-1252
という適切なdetect-sequenceを使う必要があります。
エンコーディングを検出したら、それを内部表現に変換する必要があります(UTF-8
が唯一の正しい選択です)。関数utf8_encode
は、ISO-8859-1
をUTF-8
に変換するので、その特定の入力タイプに対してのみ使用できます。他のエンコーディングの場合はmb_convert_encoding
を使います。
A本当にisUTF8
-関数を実装するための良い方法は php.net にあります。
function isUTF8($string) {
return (utf8_encode(utf8_decode($string)) == $string);
}
このチートシートには、PHPでのUTF-8処理に関する一般的な注意事項がいくつか記載されています。 http://developer.loftdigital。 com/blog/php-utf-8チートシート
文字列内のマルチバイト文字を検出するこの関数は、( source )も役立つことがあります。
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);
}
少し頭を上げて、あなたはあなたのデータベースで "ß"が "Â"として表示されるべきであると言いました。
これは、おそらくlatin1文字エンコーディングのデータベースを使用しているか、おそらくphp-mysql接続が正しく設定されていないためです。つまり、phpはmysqlがutf-8を使用するように設定していると考えますbelives phpはiso-8859-1としてエンコードされたデータを送信しているので、送信されたデータをもう一度utf-8としてエンコードしようとすると、このような問題が発生する可能性があります。
これを見てください、あなたを助けるかもしれません: http://php.net/manual/en/function.mysql-set-charset.php
応答はさまざまなエンコーディングでコーディングされる可能性があるため、入力時に文字セットをテストする必要があります。
次の関数を使って検出と翻訳を行うことで、すべてのコンテンツをUTF-8に送信します。
function fixRequestCharset()
{
$ref = array( &$_GET, &$_POST, &$_REQUEST );
foreach ( $ref as &$var )
{
foreach ( $var as $key => $val )
{
$encoding = mb_detect_encoding( $var[ $key ], mb_detect_order(), true );
if ( !$encoding ) continue;
if ( strcasecmp( $encoding, 'UTF-8' ) != 0 )
{
$encoding = iconv( $encoding, 'UTF-8', $var[ $key ] );
if ( $encoding === false ) continue;
$var[ $key ] = $encoding;
}
}
}
}
そのルーチンはリモートホストから来るすべてのPHP変数をUTF-8に変換します。
または、エンコードを検出または変換できなかった場合は値を無視します。
あなたは自分のニーズに合わせてカスタマイズできます。
変数を使う前にそれを呼び出すだけです。
mb_detect_encoding
とmb_convert_encoding
に関して興味深いことは、あなたが提案するエンコーディングの順番が重要であるということです。
// $input is actually UTF-8
mb_detect_encoding($input, "UTF-8", "ISO-8859-9, UTF-8");
// ISO-8859-9 (WRONG!)
mb_detect_encoding($input, "UTF-8", "UTF-8, ISO-8859-9");
// UTF-8 (OK)
そのため、予想されるエンコーディングを指定するときには特定の順序を使用することをお勧めします。それでも、これは絶対確実というわけではないことに留意してください。
エンコーディングは、UTF-8に2回エンコードしたように見えます。つまり、他のエンコーディングからUTF-8へ、そしてまたUTF-8へ。あなたがiso-8859-1を持っているかのように、iso-8859-1からutf-8に変換し、そしてUTF-8への別の変換のために新しい文字列をiso-8859-1として扱いました。
これが、あなたがしたことの疑似コードです。
$inputstring = getFromUser();
$utf8string = iconv($current_encoding, 'utf-8', $inputstring);
$flawedstring = iconv($current_encoding, 'utf-8', $utf8string);
試してみてください:
mb_detect_encoding()
を使ってエンコーディングを検出します。それは、「ミドル」変換ではiso-8859-1を使ったと仮定しています。 windows-1252を使っていたら、windows-1252(latin1)に変換してください。オリジナルのソースエンコーディングは重要ではありません。あなたが使用していたものに欠陥がありましたが、2回目の変換です。
これは何が起こったのか私の推測です。 1つの拡張ASCIIバイトの代わりに4バイトを取得するためにできることは他にほとんどありません。
ドイツ語もiso-8859-2とwindows-1250(latin2)を使います。
RSSフィードの文字エンコーディングの作成は 複雑なようです 。通常のWebページでさえ、それらのエンコーディングを省略したり、嘘をついたりすることがよくあります。
そのため、正しい方法でエンコーディングを検出してから何らかの形の自動検出(推測)にフォールバックすることができます。
私はこれがより古い質問であることを知っています、しかし私は決して傷つけない有用な答えを考えます。デスクトップアプリケーション、SQLite、およびGET/POST変数間のエンコーディングに問題がありました。あるものはUTF-8であり、あるものはASCIIであり、そして基本的にすべてのものは外国の文字が関与したときにめちゃくちゃになるでしょう。
これが私の解決策です。処理の前に各ページロードであなたのGET/POST/REQUEST(私はクッキーを省略しましたが、あなたは望むならそれらを追加することができます)をスクラブします。ヘッダーでうまくいきます。ソースのエンコーディングを自動的に検出できない場合、PHPは警告をスローします。したがって、これらの警告は@で抑制されます。
//Convert everything in our vars to UTF-8 for playing Nice with the database...
//Use some auto detection here to help us not double-encode...
//Suppress possible warnings with @'s for when encoding cannot be detected
try
{
$process = array(&$_GET, &$_POST, &$_REQUEST);
while (list($key, $val) = each($process)) {
foreach ($val as $k => $v) {
unset($process[$key][$k]);
if (is_array($v)) {
$process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = $v;
$process[] = &$process[$key][@mb_convert_encoding($k,'UTF-8','auto')];
} else {
$process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = @mb_convert_encoding($v,'UTF-8','auto');
}
}
}
unset($process);
}
catch(Exception $ex){}
AGES以来、エンコードの解決方法を調べていましたが、このページはおそらく何年にもわたる検索の結論です。私はあなたが述べた提案のいくつかをテストしました、そしてここに私のノートがあります:
これは私のテスト文字列です:
これは「書いて書いた」文字列で、私はそれらを見るためにp''Sòme '特別な文字を使っています、fùnctìonによって変換されました! & それでおしまい!
この文字列をutf8_general_ci
として設定されているフィールドのDBに保存するためにINSERTを行います。
私のページの文字セットはUTF-8です
そのようにINSERTを実行した場合、私のDBにはおそらく火星から来た文字がいくつかあります。そのため、それらを何らかの "安全な" UTF-8に変換する必要があります。 utf8_encode()
を試しましたが、それでもエイリアンの文字が私のデータベースに侵入していました...
それで私は番号8で投稿されたforceUTF8
関数を使用しようとしました、しかしDBで保存されたストリングはそのように見えます:
これは、 "wröngngwrötten"文字列です。私は、p'''me '特別な文字を見て、それをfüctonで変換します。 & それでおしまい!
そこで、このページでさらにいくつかの情報を収集し、それらを他のページの他の情報とマージすることで、私はこの解決策に関する問題を解決しました。
$finallyIDidIt = mb_convert_encoding(
$string,
mysql_client_encoding($resourceID),
mb_detect_encoding($string)
);
今私のデータベースで私は正しいエンコーディングの私の文字列を持っています。
注:mysql_client_encoding
関数には注意してください。この関数はリソースIDをパラメータとして使用するため、DBに接続する必要があります。
しかし、そうですね、私はINSERTの前にその再エンコードをしているだけなので、私にとっては問題にはなりません。
私はこれがこのページのような人が私を助けてくれるのを助けることを願っています!
みんなありがとう!
マウロ
それは簡単です:あなたがUTF-8ではない何かを手に入れるとき、あなたはそのINTO utf8にENCODEしなければなりません。
そのため、ISO-8859-1の特定のフィードを取得するときは、utf8_encodeを介して解析してください。
ただし、UTF8フィードを取得している場合は、何もする必要はありません。
php.net/ mb_detect_encoding
echo mb_detect_encoding($str, "auto");
または
echo mb_detect_encoding($str, "UTF-8, ASCII, ISO-8859-1");
結果がどうなっているのか本当にわかりませんが、フィードの一部をさまざまなエンコードで取り、mb_detect_encoding
が機能するかどうか試してみることをお勧めします。
更新
autoは "ASCII、JIS、UTF-8、EUC-JP、SJIS"の略です。検出された文字セットを返します。 iconv を使用して、文字列をutf-8に変換できます。
<?php
function convertToUTF8($str) {
$enc = mb_detect_encoding($str);
if ($enc && $enc != 'UTF-8') {
return iconv($enc, 'UTF-8', $str);
} else {
return $str;
}
}
?>
私はそれをテストしていないので、保証はありません。そしてもっと簡単な方法があるかもしれません。
私のために働いた@harpax。私の場合、これで十分です。
if (isUTF8($str)) {
echo $str;
}
else
{
echo iconv("ISO-8859-1", "UTF-8//TRANSLIT", $str);
}
Ÿ
はß
のためのMojibakeです。データベースには、16進数があります。
DF if the column is "latin1",
C39F if the column is utf8 -- OR -- it is latin1, but "double-encoded"
C383C5B8 if double-encoded into a utf8 column
あなたはPHPのエンコーディング/デコーディング関数を使用しないでください。代わりに、データベースとデータベースへの接続を正しく設定する必要があります。
MySQLが関係している場合は、以下を参照してください。 utf8文字に関する問題。私が見るものは私が保存したものではありません
あなたのphpスクリプトを整理した後、mysqlにあなたがどんな文字セットを渡しているのか、そして受け取りたいのかを忘れないでください。
例:文字セットutf8を設定します。
Latin1 I/Oセッションでutf8データをlatin1テーブルに渡すと、これらの厄介な鳥の餌が得られます。私はoscommerce店で一日おきにこれを見ます。前後にそれが正しいように見えるかもしれません。しかし、phpmyadminは真実を示します。 mysqlに渡す文字セットを指定することで、mysqlデータの変換が自動的に処理されます。
既存のスクランブルされたmysqlデータを回復する方法は議論するもう一つのスレッドです。 :)
ヘッダからエンコーディングを取得し、それをutf-8に変換します。
$post_url='http://website.domain';
/// Get headers ////////////////////////////////////////////////////////////
function get_headers_curl($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
$r = curl_exec($ch);
return $r;
}
$the_header = get_headers_curl($post_url);
/// check for redirect /////////////////////////////////////////////////
if (preg_match("/Location:/i", $the_header)) {
$arr = explode('Location:', $the_header);
$location = $arr[1];
$location=explode(chr(10), $location);
$location = $location[0];
$the_header = get_headers_curl(trim($location));
}
/// Get charset /////////////////////////////////////////////////////////////////////
if (preg_match("/charset=/i", $the_header)) {
$arr = explode('charset=', $the_header);
$charset = $arr[1];
$charset=explode(chr(10), $charset);
$charset = $charset[0];
}
///////////////////////////////////////////////////////////////////////////////
// echo $charset;
if($charset && $charset!='UTF-8') { $html = iconv($charset, "UTF-8", $html); }
最も投票された答えはうまくいきません。ここに私のものがあり、それが役立つことを願っています。
function toUTF8($raw) {
try{
return mb_convert_encoding($raw, "UTF-8", "auto");
}catch(\Exception $e){
return mb_convert_encoding($raw, "UTF-8", "GBK");
}
}
このバージョンはドイツ語用ですが、$ CHARSETSと$ TESTCHARSを変更できます
class CharsetDetector
{
private static $CHARSETS = array(
"ISO_8859-1",
"ISO_8859-15",
"CP850"
);
private static $TESTCHARS = array(
"€",
"ä",
"Ä",
"ö",
"Ö",
"ü",
"Ü",
"ß"
);
public static function convert($string)
{
return self::__iconv($string, self::getCharset($string));
}
public static function getCharset($string)
{
$normalized = self::__normalize($string);
if(!strlen($normalized))return "UTF-8";
$best = "UTF-8";
$charcountbest = 0;
foreach (self::$CHARSETS as $charset) {
$str = self::__iconv($normalized, $charset);
$charcount = 0;
$stop = mb_strlen( $str, "UTF-8");
for( $idx = 0; $idx < $stop; $idx++)
{
$char = mb_substr( $str, $idx, 1, "UTF-8");
foreach (self::$TESTCHARS as $testchar) {
if($char == $testchar)
{
$charcount++;
break;
}
}
}
if($charcount>$charcountbest)
{
$charcountbest=$charcount;
$best=$charset;
}
//echo $text."<br />";
}
return $best;
}
private static function __normalize($str)
{
$len = strlen($str);
$ret = "";
for($i = 0; $i < $len; $i++){
$c = ord($str[$i]);
if ($c > 128) {
if (($c > 247)) $ret .=$str[$i];
elseif ($c > 239) $bytes = 4;
elseif ($c > 223) $bytes = 3;
elseif ($c > 191) $bytes = 2;
else $ret .=$str[$i];
if (($i + $bytes) > $len) $ret .=$str[$i];
$ret2=$str[$i];
while ($bytes > 1) {
$i++;
$b = ord($str[$i]);
if ($b < 128 || $b > 191) {$ret .=$ret2; $ret2=""; $i+=$bytes-1;$bytes=1; break;}
else $ret2.=$str[$i];
$bytes--;
}
}
}
return $ret;
}
private static function __iconv($string, $charset)
{
return iconv ( $charset, "UTF-8" , $string );
}
}
私はここで解決策を見つけます http://deer.org.ua/2009/10/06/1/
class Encoding
{
/**
* http://deer.org.ua/2009/10/06/1/
* @param $string
* @return null
*/
public static function detect_encoding($string)
{
static $list = ['utf-8', 'windows-1251'];
foreach ($list as $item) {
try {
$sample = iconv($item, $item, $string);
} catch (\Exception $e) {
continue;
}
if (md5($sample) == md5($string)) {
return $item;
}
}
return null;
}
}
$content = file_get_contents($file['tmp_name']);
$encoding = Encoding::detect_encoding($content);
if ($encoding != 'utf-8') {
$result = iconv($encoding, 'utf-8', $content);
} else {
$result = $content;
}
私は@は悪い決断だと思います、そしてdeer.org.uaからの解決にいくつかの変更を加えます。