UTF-8 baştan sona

Nov 11 2008

Yeni bir sunucu kuruyorum ve web uygulamamda UTF-8'i tam olarak desteklemek istiyorum. Bunu geçmişte mevcut sunucularda denedim ve her zaman ISO-8859-1'e geri dönmek zorunda kalıyorum.

Kodlamayı / karakter kümelerini tam olarak nerede ayarlamam gerekir? Bunu yapmak için Apache, MySQL ve PHP'yi yapılandırmam gerektiğinin farkındayım - takip edebileceğim standart bir kontrol listesi var mı veya uyuşmazlıkların meydana geldiği yerlerde belki de sorun giderme var mı?

Bu, MySQL 5, PHP, 5 ve Apache 2 çalıştıran yeni bir Linux sunucusu içindir.

Yanıtlar

1044 chazomaticus Nov 11 2008 at 04:43

Veri Depolama :

  • utf8mb4Veritabanınızdaki tüm tablolarda ve metin sütunlarında karakter kümesini belirtin . Bu, MySQL'in UTF-8'de yerel olarak kodlanmış değerleri fiziksel olarak depolamasını ve almasını sağlar. utf8mb4Bir utf8mb4_*harmanlama belirtilirse (herhangi bir açık karakter seti olmadan) MySQL'in dolaylı olarak kodlamayı kullanacağını unutmayın .

  • MySQL'in eski sürümlerinde (<5.5.3), maalesef sadece utf8Unicode karakterlerinin bir alt kümesini destekleyen basitçe kullanmak zorunda kalacaksınız . Keşke şaka yapıyor olsaydım.

Veri Erişimi :

  • Uygulama kodunuzda (ör. PHP), hangi DB erişim yöntemini kullanırsanız kullanın, bağlantı karakter kümesini olarak ayarlamanız gerekir utf8mb4. Bu şekilde MySQL, verileri uygulamanıza aktarırken yerel UTF-8'den dönüştürme yapmaz ve bunun tersi de geçerlidir.

  • Bazı sürücüler, hem kendi dahili durumunu güncelleyen hem de MySQL'e bağlantıda kullanılacak kodlama hakkında bilgi veren bağlantı karakter kümesini yapılandırmak için kendi mekanizmalarını sağlar - bu genellikle tercih edilen yaklaşımdır. PHP'de:

    • Eğer kullanıyorsanız PDO PHP ≥ 5.3.6 ile soyutlama katmanı şunları belirtebilirsiniz charsetiçinde DSN :

       $dbh = new PDO('mysql:charset=utf8mb4');
      
    • Mysqli kullanıyorsanız şu numarayı arayabilirsiniz set_charset():

        $mysqli->set_charset('utf8mb4');       // object oriented style
        mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • Düz mysql ile takıldıysanız, ancak PHP ≥ 5.2.3 çalıştırıyorsanız, arayabilirsiniz mysql_set_charset.

  • Sürücü bağlantısı karakter kümesini ayarlamak için kendi mekanizmasını sağlamıyorsa, başvurunuz bağlantısında veri kodlanmış olmasını bekler nasıl MySQL anlatmak için bir sorgu vermek gerekebilir: SET NAMES 'utf8mb4'.

  • Yukarıdaki ile ilgili aynı düşünce utf8mb4/ utf8geçerlidir.

Çıktı :

  • Uygulamanız başka sistemlere metin iletiyorsa, karakter kodlamasından da haberdar olmaları gerekecektir. Web uygulamalarında, tarayıcıya verinin gönderildiği kodlama konusunda bilgi verilmelidir (HTTP yanıt başlıkları veya HTML meta verileri aracılığıyla ).

  • PHP'de default_charsetphp.ini seçeneğini kullanabilir veya Content-TypeMIME başlığını kendiniz elle yayınlayabilirsiniz , bu sadece daha fazla iş ama aynı etkiye sahiptir.

  • Çıkışı kullanarak kodlarken, ikinci bir parametre olarak json_encode()ekleyin JSON_UNESCAPED_UNICODE.

Girdi :

  • Ne yazık ki, saklamaya veya herhangi bir yerde kullanmaya çalışmadan önce alınan her dizenin geçerli UTF-8 olduğunu doğrulamalısınız. PHP mb_check_encoding()işi yapar, ancak onu dini olarak kullanmak zorundasınız. Kötü niyetli istemciler istedikleri kodlamayla veri gönderebildiklerinden ve PHP'nin bunu sizin için güvenilir bir şekilde yapmasını sağlayacak bir numara bulamadım.

  • Mevcut HTML spesifikasyonunu okumamdan , aşağıdaki alt madde işaretleri modern HTML için artık gerekli ve hatta geçerli değil. Anladığım kadarıyla tarayıcılar, belge için belirtilen karakter kümesindeki verilerle çalışacak ve veriler gönderecek. Ancak, eski HTML sürümlerini (XHTML, HTML4 vb.) Hedefliyorsanız, bu noktalar yine de yararlı olabilir:

    • Yalnızca HTML5'ten önceki HTML için : size tarayıcılar tarafından gönderilen tüm verilerin UTF-8 biçiminde olmasını istersiniz. Eğer güvenilir Bunu yapmanın tek yolu ile giderseniz Maalesef eklemektir accept-charsettüm özniteligini <form>etiketleri: <form ... accept-charset="UTF-8">.
    • Yalnızca HTML5'ten önceki HTML için : W3C HTML spesifikasyonunun, istemcilerin, sunucunun sunduğu karakter kümesindeki formları sunucuya geri göndermeyi varsayılan olarak "yapması gerektiğini" söylediğine dikkat edin, ancak bu sadece bir öneri, dolayısıyla her bir tek tek <form>etiket.

Diğer Kod Hususları :

  • Açıktır ki, sunacağınız tüm dosyalar (PHP, HTML, JavaScript, vb.) Geçerli UTF-8 ile kodlanmış olmalıdır.

  • Bir UTF-8 dizesini her işlediğinizde, bunu güvenli bir şekilde yaptığınızdan emin olmanız gerekir. Maalesef işin zor kısmı bu. Muhtemelen PHP'nin mbstringuzantısını kapsamlı bir şekilde kullanmak isteyeceksiniz .

  • PHP dize operasyonları yerleşik olan değil varsayılan UTF-8 kasa ile. Normal PHP dizge işlemleriyle (birleştirme gibi) güvenle yapabileceğiniz bazı şeyler vardır, ancak çoğu şey için eşdeğer mbstringişlevi kullanmalısınız .

  • Ne yaptığınızı bilmek için (okuyun: karıştırmayın), gerçekten UTF-8'i ve mümkün olan en düşük seviyede nasıl çalıştığını bilmeniz gerekir. Bilmeniz gereken her şeyi öğrenmek için iyi kaynaklar için utf8.com'daki bağlantılardan herhangi birine göz atın .

157 mercator Nov 13 2008 at 02:27

Chazomaticus'un mükemmel cevabına bir şey eklemek istiyorum :

META etiketini de unutmayın (bunun gibi veya HTML4 veya XHTML sürümü ):

<meta charset="utf-8">

Bu önemsiz görünüyor, ancak IE7 daha önce bana sorun yaşattı.

Her şeyi doğru yapıyordum; veritabanı, veritabanı bağlantısı ve Content-Type HTTP başlığının tümü UTF-8 olarak ayarlandı ve diğer tüm tarayıcılarda iyi çalıştı, ancak Internet Explorer hala "Batı Avrupa" kodlamasını kullanmakta ısrar etti.

Sayfanın META etiketinin olmadığı ortaya çıktı. Bunu eklemek sorunu çözdü.

Düzenle:

W3C aslında I18N'ye ayrılmış oldukça büyük bir bölüme sahiptir . Bu sorunla ilgili çok sayıda makaleleri var - şeylerin HTTP, (X) HTML ve CSS taraflarını açıklıyor:

  • SSS: (X) HTML sayfa kodlamasını UTF-8 olarak değiştirme
  • HTML'de karakter kodlamalarını bildirme
  • Eğitim: XHTML, HTML ve CSS'de karakter kümeleri ve kodlamalar
  • HTTP karakter kümesi parametresini ayarlama

Hem HTTP başlığını hem de HTML meta etiketini (veya XHTML'nin XML olarak sunulması durumunda XML bildirimi) kullanmanızı önerirler.

66 chroder Nov 11 2008 at 04:30

default_charsetPhp.ini'de ayarlamaya ek olarak header(), herhangi bir çıktıdan önce kodunuzun içinden kullanarak doğru karakter kümesini gönderebilirsiniz :

header('Content-Type: text/html; charset=utf-8');

PHP'de Unicode ile çalışmak, dizge işlevlerinin çoğunun Unicode ile çalışmadığını ve bazılarının dizeleri tamamen karıştırabileceğini anladığınız sürece kolaydır . PHP, "karakterleri" 1 bayt uzunluğunda kabul eder. Bazen bu sorun olmaz (örneğin, explode()yalnızca bir bayt dizisi arar ve onu ayırıcı olarak kullanır - bu nedenle hangi karakterleri aradığınız önemli değildir). Ancak diğer zamanlarda, işlev gerçekten karakterler üzerinde çalışmak üzere tasarlandığında , PHP'nin metninizin Unicode ile bulunan çok baytlı karakterlere sahip olduğu konusunda hiçbir fikri yoktur.

Kontrol etmek için iyi bir kütüphane phputf8'dir . Bu, tüm "kötü" işlevleri yeniden yazar, böylece UTF8 dizeleri üzerinde güvenle çalışabilirsiniz. Bunu sizin için de yapmaya çalışan mbstring uzantısı gibi uzantılar var, ancak daha taşınabilir olduğu için kütüphaneyi kullanmayı tercih ediyorum (ama kitle pazar ürünleri yazıyorum, bu yüzden bu benim için önemli). Ancak phputf8, performansı artırmak için yine de perde arkasında mbstring kullanabilir.

37 JimW. Sep 11 2012 at 22:40

PDO kullanan biriyle ilgili bir sorun buldum ve yanıt, bunu PDO bağlantı dizesi için kullanmaktı:

$pdo = new PDO(
    'mysql:host=mysql.example.com;dbname=example_db',
    "username",
    "password",
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

Bunu aldığım site kapalı, ancak neyse ki Google önbelleğini kullanarak onu alabildim.

25 JDelage Feb 24 2012 at 05:20

Benim durumumda, mb_splitnormal ifade kullanan kullanıyordum. Bu nedenle, düzenli ifade kodlamasının utf-8 olduğundan emin olmak zorunda kaldım.mb_regex_encoding('UTF-8');

Bir yan not olarak, mb_internal_encoding()dahili kodlamanın utf-8 olmadığını çalıştırarak da keşfettim ve bunu çalıştırarak değiştirdim mb_internal_encoding("UTF-8");.

23 JimmyKane Jan 27 2014 at 16:16

Öncelikle <5.3PHP içindeyseniz, hayır. Çözmen gereken bir sürü sorunun var.

Unicode , graphemes , string işlemleri , yerelleştirme ve daha pek çok şey için iyi bir desteğe sahip olan intl kitaplığından hiç kimsenin bahsetmediğine şaşırdım , aşağıya bakın.

Ben PHP 'unicode desteği hakkında bazı bilgiler teklif edecek Elizabeth Smith'in slaytlar de PHPBenelux'14

INTL

İyi:

  • Yoğun bakım kütüphanesi etrafına sarıcı
  • Standart yerel ayarlar, betiğe göre yerel ayarlar
  • Sayı biçimlendirme
  • Para birimi biçimlendirme
  • Mesaj biçimlendirme (gettext'in yerini alır)
  • Takvimler, tarihler, saat dilimi ve saat
  • Transliteratör
  • Sahte denetleyici
  • Kaynak paketleri
  • Dönüştürücüler
  • IDN desteği
  • Graphemes
  • Harmanlama
  • Yineleyiciler

Kötü:

  • Zend_multibite'ı desteklemiyor
  • HTTP girdi çıktı dönüşümünü desteklemiyor
  • Fonksiyon aşırı yüklemesini desteklemiyor

mb_string

  • Zend_multibyte desteğini etkinleştirir
  • Şeffaf HTTP giriş / çıkış kodlamasını destekler
  • Strtoupper gibi işlevsellik için bazı sarmalayıcılar sağlar

ICONV

  • Karakter kümesi dönüştürme için birincil
  • Çıktı arabellek işleyicisi
  • mime kodlama işlevi
  • dönüştürmek
  • bazı dize yardımcıları (len, substr, strpos, strrpos)
  • Akış Filtresi stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

VERİTABANLARI

  • mysql: Tablolarda ve bağlantıda karakter kümesi ve harmanlama (harmanlama değil). Ayrıca mysql - msqli veya PDO kullanmayın
  • postgresql: pg_set_client_encoding
  • sqlite (3): Unicode ve intl desteği ile derlendiğinden emin olun

Bazı başka Gotchas

  • 3. parça uzantısı kullanmadığınız sürece PHP ve Windows ile unicode dosya adlarını kullanamazsınız.
  • Exec, proc_open ve diğer komut satırı çağrılarını kullanıyorsanız her şeyi ASCII'de gönderin
  • Düz metin düz metin değildir, dosyalarda kodlamalar vardır
  • Iconv filtresi ile dosyaları anında dönüştürebilirsiniz

Eklenen özelliklerin değişmesi durumunda bu yanıtı güncelleyeceğim.

15 PuertoAGP Sep 10 2014 at 10:39

Bu şaşırtıcı cevaplara ekleyeceğim tek şey, dosyalarınızı utf8 kodlamasında kaydetmeyi vurgulamaktır, tarayıcıların bu özelliği kod kodlamanız olarak utf8'i ayarlamak yerine kabul ettiğini fark ettim. Herhangi bir düzgün metin editörü size bunu gösterecektir, örneğin Notepad ++ dosya kodlama için bir menü seçeneğine sahiptir, size mevcut kodlamayı gösterir ve değiştirmenize olanak tanır. Tüm php dosyalarım için BOM olmadan utf8 kullanıyorum.

Bir süre önce birisi benden başkası tarafından tasarlanmış bir php / mysql uygulaması için utf8 desteği eklememi istemişti, tüm dosyaların ANSI'de kodlandığını fark ettim, bu yüzden tüm dosyaları dönüştürmek için ICONV kullanmak zorunda kaldım, veritabanı tablolarını utf8 charset ve utf8_general_ci harmanlayın, bağlantıdan sonra veritabanı soyutlama katmanına 'SET NAMES utf8' ekleyin (5.3.6 veya daha eski kullanıyorsanız bağlantı dizesinde charset = utf8 kullanmanız gerekir) ve php multibyte kullanmak için dize işlevlerini değiştirin dize işlevlerine eşdeğer.

14 MiguelStevens Jan 13 2014 at 16:37

Yakın zamanda kullanımın strtolower(), verilerin özel bir karakterden sonra kesildiği durumlarda sorunlara neden olabileceğini keşfettim .

Çözüm kullanmaktı

mb_strtolower($string, 'UTF-8');

mb_ MultiByte kullanır. Daha fazla karakteri destekler ancak genel olarak biraz daha yavaştır.

10 AbdulSadikYalcin May 06 2015 at 04:36

Az önce aynı sorunu yaşadım ve PHP kılavuzlarında iyi bir çözüm buldum.

Tüm dosya kodlamamı UTF8 ve ardından bağlantımdaki varsayılan kodlamayı değiştirdim. Bu, tüm sorunları çözdü.

if (!$mysqli->set_charset("utf8")) { printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
   printf("Current character set: %s\n", $mysqli->character_set_name());
}

Kaynağı Görüntüle

9 JW. Nov 11 2008 at 04:29

PHP'de, çok baytlı işlevleri kullanmanız veya mbstring.func_overload'u açmanız gerekir . Bu şekilde, birden fazla bayt alan karakterleriniz varsa, strlen gibi şeyler işe yarayacaktır.

Ayrıca yanıtlarınızın karakter kümesini de belirlemeniz gerekir. AddDefaultCharset'i yukarıdaki gibi kullanabilir veya başlığı döndüren PHP kodunu yazabilirsiniz. (Veya HTML belgelerinize bir META etiketi ekleyebilirsiniz.)

7 jalf Nov 11 2008 at 04:48

PHP'deki Unicode desteği hala büyük bir karmaşa. Bir ISO8859 dizesini (dahili olarak kullandığı) utf8'e dönüştürme yeteneğine sahip olsa da, unicode dizeleriyle yerel olarak çalışma yeteneğinden yoksundur, bu da tüm dize işleme işlevlerinin dizelerinizi karıştıracağı ve bozacağı anlamına gelir. Dolayısıyla, uygun utf8 desteği için ayrı bir kitaplık kullanmanız veya tüm dize işleme işlevlerini kendiniz yeniden yazmanız gerekir.

İşin kolay kısmı, karakter kümesini HTTP üstbilgilerinde ve veritabanında vb. Belirtmektir, ancak PHP kodunuz geçerli UTF8 vermezse bunların hiçbiri önemli değildir. İşin zor kısmı bu ve PHP size neredeyse hiç yardım etmiyor. (Bence PHP6'nın bunun en kötüsünü çözmesi gerekiyor, ancak bu hala biraz uzaktadır)

7 BudimirGrom Feb 12 2015 at 06:52

MySQL sunucusunun karakter setine karar vermesini istiyorsanız ve bir istemci olarak PHP'nin değil (eski davranış; bence tercih edilir), skip-character-set-client-handshakeyour my.cnf, under [mysqld]ve yeniden başlatmayı deneyin mysql.

UTF8 dışında bir şey kullanmanız durumunda bu sorunlara neden olabilir.

6 commonpike Jan 14 2011 at 23:13

En iyi cevap mükemmel. Normal bir debian / php / mysql kurulumunda yapmam gerekenler:

// storage
// debian. apparently already utf-8

// retrieval
// the mysql database was stored in utf-8, 
// but apparently php was requesting iso. this worked: 
// ***notice "utf8", without dash, this is a mysql encoding***
mysql_set_charset('utf8');

// delivery
// php.ini did not have a default charset, 
// (it was commented out, shared host) and
// no http encoding was specified in the apache headers.
// this made apache send out a utf-8 header
// (and perhaps made php actually send out utf-8)
// ***notice "utf-8", with dash, this is a php encoding***
ini_set('default_charset','utf-8');

// submission
// this worked in all major browsers once apache
// was sending out the utf-8 header. i didnt add
// the accept-charset attribute.

// processing
// changed a few commands in php, like substr,
// to mb_substr

hepsi buydu !

2 castro_pereira Mar 25 2019 at 02:27

Bir mysql çözümü istiyorsanız, sunucu geçişinden sonra 2 projemde benzer sorunlar yaşadım. Bir çok çözümü aradıktan ve denedikten sonra, bununla karşılaştım / bu işe yaramadan önce hiçbir şey):

mysqli_set_charset($con,"utf8");

Bu satırı yapılandırma dosyama ekledikten sonra her şey yolunda gidiyor!

Bu çözümü buldum https://www.w3schools.com/PHP/func_mysqli_set_charset.asp html sorgusundan bir eki çözmeye çalışırken

iyi şanslar!

Accountantم Aug 24 2019 at 02:10

Sadece bir not:

Eğer sigara latin karakterlerin sorunu olarak gösteren karşı karşıya ?????????, bir soru soruldu ve bu kanonik soruya atfen kapalı var, her şeyi denedik ve size ne hala olursa olsun almak ??????????den MySQL.

Bunun nedeni çoğunlukla , veritabanına yanlış karakter seti kullanılarak eklenen ve aslında soru işareti karakterlerine dönüştürülen ve saklanan eski verilerinizi test etmenizdir ?. Bu, orijinal metninizi sonsuza dek kaybettiniz ve ne denerseniz deneyin elde edeceğiniz anlamına gelir ???????.

Bu sorunun yanıtlarından öğrendiklerinizi yeni bir veriye yeniden uygulamak sorununuzu çözebilir.

IjazAhmedBhatti Sep 27 2020 at 13:24

connection.php içinde: mysqli_set_charset ($ con, “utf8”); ve sql harmanlamasında utf = 8