UTF-8 baştan sona
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
Veri Depolama :
utf8mb4
Veritabanı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.utf8mb4
Birutf8mb4_*
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
utf8
Unicode 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
charset
iç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
/utf8
geç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-Type
MIME 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()
ekleyinJSON_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-charset
tü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.
- 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
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
mbstring
iş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 .
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.
default_charset
Php.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.
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.
Benim durumumda, mb_split
normal 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");
.
Ö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.
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.
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.
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
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.)
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)
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-handshake
your my.cnf
, under [mysqld]
ve yeniden başlatmayı deneyin mysql
.
UTF8 dışında bir şey kullanmanız durumunda bu sorunlara neden olabilir.
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 !
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!
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.
connection.php içinde: mysqli_set_charset ($ con, “utf8”); ve sql harmanlamasında utf = 8