UTF-8 sepenuhnya
Saya sedang menyiapkan server baru dan ingin mendukung UTF-8 sepenuhnya di aplikasi web saya. Saya telah mencoba ini di masa lalu pada server yang ada dan sepertinya selalu harus kembali ke ISO-8859-1.
Di mana tepatnya saya perlu menyetel encoding / charsets? Saya sadar bahwa saya perlu mengonfigurasi Apache, MySQL, dan PHP untuk melakukan ini - apakah ada daftar periksa standar yang dapat saya ikuti, atau mungkin memecahkan masalah di mana ketidaksesuaian terjadi?
Ini untuk server Linux baru, menjalankan MySQL 5, PHP, 5, dan Apache 2.
Jawaban
Penyimpanan Data :
Tentukan
utf8mb4
kumpulan karakter pada semua tabel dan kolom teks di database Anda. Ini membuat MySQL secara fisik menyimpan dan mengambil nilai yang dikodekan secara native dalam UTF-8. Perhatikan bahwa MySQL secara implisit akan menggunakanutf8mb4
pengkodean jikautf8mb4_*
pemeriksaan ditentukan (tanpa rangkaian karakter eksplisit).Dalam versi MySQL yang lebih lama (<5.5.3), sayangnya Anda akan dipaksa untuk menggunakan hanya
utf8
, yang hanya mendukung sebagian karakter Unicode. Saya berharap saya bercanda.
Akses Data :
Dalam kode aplikasi Anda (misalnya PHP), dalam metode akses DB apa pun yang Anda gunakan, Anda harus menyetel rangkaian karakter koneksi ke
utf8mb4
. Dengan cara ini, MySQL tidak melakukan konversi dari UTF-8 aslinya saat menyerahkan data ke aplikasi Anda dan sebaliknya.Beberapa driver menyediakan mekanismenya sendiri untuk mengonfigurasi himpunan karakter koneksi, yang memperbarui status internalnya sendiri dan memberi tahu MySQL tentang pengkodean yang akan digunakan pada koneksi — ini biasanya merupakan pendekatan yang lebih disukai. Dalam PHP:
Jika Anda menggunakan lapisan abstraksi PDO dengan PHP ≥ 5.3.6, Anda dapat menentukan
charset
di DSN :$dbh = new PDO('mysql:charset=utf8mb4');
Jika Anda menggunakan mysqli , Anda dapat menghubungi set_charset():
$mysqli->set_charset('utf8mb4'); // object oriented style mysqli_set_charset($link, 'utf8mb4'); // procedural style
Jika Anda terjebak dengan mysql biasa tetapi kebetulan menjalankan PHP ≥ 5.2.3, Anda dapat memanggil mysql_set_charset.
Jika pengemudi tidak menyediakan mekanisme sendiri untuk menetapkan karakter koneksi set, Anda mungkin harus mengeluarkan permintaan untuk memberitahu MySQL bagaimana aplikasi Anda mengharapkan data pada koneksi yang akan dikodekan: SET NAMES 'utf8mb4'.
Pertimbangan yang sama tentang
utf8mb4
/utf8
berlaku seperti di atas.
Keluaran :
Jika aplikasi Anda mengirimkan teks ke sistem lain, mereka juga perlu diberi tahu tentang pengkodean karakter. Dengan aplikasi web, browser harus diberi tahu tentang pengkodean tempat data dikirim (melalui header respons HTTP atau metadata HTML ).
Di PHP, Anda dapat menggunakan default_charsetopsi php.ini, atau menerbitkan
Content-Type
header MIME sendiri secara manual , yang lebih berfungsi tetapi memiliki efek yang sama.Saat mengenkode keluaran menggunakan
json_encode()
, tambahkanJSON_UNESCAPED_UNICODE
sebagai parameter kedua.
Masukan :
Sayangnya, Anda harus memverifikasi setiap string yang diterima sebagai UTF-8 yang valid sebelum Anda mencoba menyimpannya atau menggunakannya di mana saja. PHP mb_check_encoding()melakukan triknya, tetapi Anda harus menggunakannya secara religius. Benar-benar tidak ada jalan lain, karena klien jahat dapat mengirimkan data dalam pengkodean apa pun yang mereka inginkan, dan saya belum menemukan trik untuk membuat PHP melakukan ini untuk Anda dengan andal.
Dari pembacaan saya tentang spesifikasi HTML saat ini , sub-peluru berikut tidak diperlukan atau bahkan berlaku lagi untuk HTML modern. Pemahaman saya adalah bahwa browser akan bekerja dengan dan mengirimkan data dalam kumpulan karakter yang ditentukan untuk dokumen tersebut. Namun, jika Anda menargetkan HTML versi lama (XHTML, HTML4, dll.), Poin berikut mungkin masih berguna:
- Hanya untuk HTML sebelum HTML5 : Anda ingin semua data yang dikirimkan kepada Anda oleh browser dalam UTF-8. Sayangnya, jika Anda pergi dengan satu-satunya cara untuk andal melakukan hal ini adalah menambahkan
accept-charset
atribut untuk semua Anda<form>
tag:<form ... accept-charset="UTF-8">
. - Hanya untuk HTML sebelum HTML5 : perhatikan bahwa spesifikasi HTML W3C mengatakan bahwa klien "harus" secara default mengirim formulir kembali ke server dalam rangkaian karakter apa pun yang disajikan server, tetapi ini tampaknya hanya rekomendasi, oleh karena itu kebutuhan untuk eksplisit pada setiap
<form>
menandai.
- Hanya untuk HTML sebelum HTML5 : Anda ingin semua data yang dikirimkan kepada Anda oleh browser dalam UTF-8. Sayangnya, jika Anda pergi dengan satu-satunya cara untuk andal melakukan hal ini adalah menambahkan
Pertimbangan Kode Lainnya :
Cukup jelas, semua file yang akan Anda sajikan (PHP, HTML, JavaScript, dll.) Harus dienkode dalam UTF-8 yang valid.
Anda perlu memastikan bahwa setiap kali Anda memproses string UTF-8, Anda melakukannya dengan aman. Sayangnya, ini adalah bagian yang sulit. Anda mungkin ingin memanfaatkan ekstensi PHP secara mbstringekstensif.
Operasi string bawaan PHP tidak secara default aman UTF-8. Ada beberapa hal yang dapat Anda lakukan dengan aman dengan operasi string PHP normal (seperti penggabungan), tetapi untuk kebanyakan hal Anda harus menggunakan
mbstring
fungsi yang setara .Untuk mengetahui apa yang Anda lakukan (baca: jangan mengacaukannya), Anda benar-benar perlu mengetahui UTF-8 dan cara kerjanya pada level serendah mungkin. Lihat salah satu tautan dari utf8.com untuk mendapatkan sumber daya yang bagus untuk mempelajari semua yang perlu Anda ketahui.
Saya ingin menambahkan satu hal ke jawaban terbaik chazomaticus :
Jangan lupa tag META juga (seperti ini, atau versi HTML4 atau XHTML-nya ):
<meta charset="utf-8">
Itu tampak sepele, tetapi IE7 telah memberi saya masalah dengan itu sebelumnya.
Saya melakukan segalanya dengan benar; database, koneksi database, dan header HTTP Jenis Konten semuanya disetel ke UTF-8, dan berfungsi dengan baik di semua browser lain, tetapi Internet Explorer masih bersikeras menggunakan pengkodean "Eropa Barat".
Ternyata halaman tersebut tidak memiliki tag META. Menambahkan itu memecahkan masalah.
Edit:
W3C sebenarnya memiliki bagian yang agak besar yang didedikasikan untuk I18N . Mereka memiliki sejumlah artikel yang terkait dengan masalah ini - menjelaskan sisi HTTP, (X) HTML dan CSS:
- FAQ: Mengubah encoding (X) halaman HTML ke UTF-8
- Mendeklarasikan pengkodean karakter dalam HTML
- Tutorial: Kumpulan karakter & pengkodean dalam XHTML, HTML dan CSS
- Mengatur parameter charset HTTP
Mereka merekomendasikan penggunaan header HTTP dan tag meta HTML (atau deklarasi XML jika XHTML disajikan sebagai XML).
Selain pengaturan default_charset
di php.ini, Anda dapat mengirim rangkaian karakter yang benar menggunakan header()
dari dalam kode Anda, sebelum keluaran apa pun:
header('Content-Type: text/html; charset=utf-8');
Bekerja dengan Unicode di PHP itu mudah selama Anda menyadari bahwa sebagian besar fungsi string tidak berfungsi dengan Unicode, dan beberapa mungkin mengacaukan string sepenuhnya . PHP menganggap "karakter" menjadi 1 byte. Terkadang ini tidak masalah (misalnya, explode()
hanya mencari urutan byte dan menggunakannya sebagai pemisah - jadi tidak masalah karakter apa yang sebenarnya Anda cari). Tetapi di lain waktu, ketika fungsi sebenarnya dirancang untuk bekerja pada karakter , PHP tidak tahu bahwa teks Anda memiliki karakter multi-byte yang ditemukan dengan Unicode.
Perpustakaan yang bagus untuk diperiksa adalah phputf8 . Ini akan menulis ulang semua fungsi "buruk" sehingga Anda dapat bekerja dengan aman pada string UTF8. Ada ekstensi seperti ekstensi mbstring yang mencoba melakukan ini untuk Anda juga, tetapi saya lebih suka menggunakan perpustakaan karena lebih portabel (tetapi saya menulis produk pasar massal, jadi itu penting bagi saya). Tapi phputf8 dapat menggunakan mbstring di belakang layar, untuk meningkatkan performa.
Saya menemukan masalah dengan seseorang yang menggunakan PDO dan jawabannya adalah menggunakan ini untuk string koneksi PDO:
$pdo = new PDO(
'mysql:host=mysql.example.com;dbname=example_db',
"username",
"password",
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
Situs tempat saya mengambil ini sedang tidak aktif, tetapi saya bisa mendapatkannya menggunakan cache Google, untungnya.
Dalam kasus saya, saya menggunakan mb_split
, yang menggunakan regex. Oleh karena itu saya juga harus secara manual memastikan pengkodean regex adalah utf-8 dengan melakukanmb_regex_encoding('UTF-8');
Sebagai catatan tambahan, saya juga menemukan dengan menjalankan mb_internal_encoding()
bahwa pengkodean internal bukanlah utf-8, dan saya mengubahnya dengan menjalankan mb_internal_encoding("UTF-8");
.
Pertama-tama jika Anda berada di <5.3PHP maka tidak. Ada banyak masalah yang harus Anda atasi.
Saya terkejut bahwa tidak ada yang menyebutkan pustaka intl , yang memiliki dukungan yang baik untuk unicode , graphemes , operasi string , lokalisasi , dan banyak lagi, lihat di bawah.
Saya akan mengutip beberapa informasi tentang dukungan unicode di PHP oleh slide Elizabeth Smith di PHPBenelux'14
INTL
Baik:
- Bungkus di sekitar perpustakaan ICU
- Lokal standar, setel lokal per skrip
- Pemformatan angka
- Pemformatan mata uang
- Pemformatan pesan (menggantikan gettext)
- Kalender, tanggal, zona waktu dan waktu
- Transliterator
- Spoofchecker
- Paket sumber daya
- Konverter
- Dukungan IDN
- Grafem
- Pemeriksaan
- Iterator
Buruk:
- Tidak mendukung zend_multibite
- Tidak mendukung konversi output input HTTP
- Tidak mendukung kelebihan beban fungsi
mb_string
- Mengaktifkan dukungan zend_multibyte
- Mendukung pengodean masuk / keluar HTTP transparan
- Menyediakan beberapa pembungkus untuk funtionallity seperti strtoupper
ICONV
- Utama untuk konversi rangkaian karakter
- Penangan buffer keluaran
- fungsi pengkodean pantomim
- konversi
- beberapa pembantu string (len, substr, strpos, strrpos)
- Filter Aliran
stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')
DATABASES
- mysql: Charset dan collation pada tabel dan koneksi (bukan collation). Juga jangan gunakan mysql - msqli atau PDO
- postgresql: pg_set_client_encoding
- sqlite (3): Pastikan itu dikompilasi dengan dukungan unicode dan intl
Beberapa Gotcha lainnya
- Anda tidak dapat menggunakan nama file unicode dengan PHP dan windows kecuali Anda menggunakan ekstensi bagian ke-3.
- Kirim semuanya dalam ASCII jika Anda menggunakan exec, proc_open, dan panggilan baris perintah lainnya
- Teks biasa bukan teks biasa, file memiliki pengkodean
- Anda dapat mengonversi file dengan cepat menggunakan filter iconv
Saya akan memperbarui jawaban ini jika ada yang mengubah fitur yang ditambahkan dan sebagainya.
Satu-satunya hal yang akan saya tambahkan ke jawaban luar biasa ini adalah menekankan pada penyimpanan file Anda dalam pengkodean utf8, saya telah memperhatikan bahwa browser menerima properti ini daripada menyetel utf8 sebagai pengkodean kode Anda. Setiap editor teks yang layak akan menunjukkan ini kepada Anda, misalnya Notepad ++ memiliki opsi menu untuk pengkondisian file, ini menunjukkan kepada Anda pengkodean saat ini dan memungkinkan Anda untuk mengubahnya. Untuk semua file php saya, saya menggunakan utf8 tanpa BOM.
Beberapa waktu yang lalu saya memiliki seseorang meminta saya untuk menambahkan dukungan utf8 untuk aplikasi php / mysql yang dirancang oleh orang lain, saya perhatikan bahwa semua file dikodekan dalam ANSI, jadi saya harus menggunakan ICONV untuk mengonversi semua file, mengubah tabel database untuk menggunakan utf8 charset dan utf8_general_ci collate, tambahkan 'SET NAMES utf8' ke lapisan abstraksi database setelah koneksi (jika menggunakan 5.3.6 atau sebelumnya, Anda harus menggunakan charset = utf8 dalam string koneksi) dan mengubah fungsi string untuk menggunakan multibyte php fungsi string setara.
Saya baru-baru ini menemukan bahwa penggunaan strtolower()
dapat menyebabkan masalah di mana data terpotong setelah karakter khusus.
Solusinya adalah menggunakan
mb_strtolower($string, 'UTF-8');
mb_ menggunakan MultiByte. Ini mendukung lebih banyak karakter tetapi secara umum sedikit lebih lambat.
Saya baru saja mengalami masalah yang sama dan menemukan solusi yang baik di manual PHP.
Saya mengubah semua pengkodean file saya ke UTF8 kemudian pengkodean default pada koneksi saya. Ini menyelesaikan semua masalah.
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());
}
Lihat sumber
Di PHP, Anda harus menggunakan fungsi multibyte , atau mengaktifkan mbstring.func_overload . Dengan begitu, hal-hal seperti strlen akan berfungsi jika Anda memiliki karakter yang membutuhkan lebih dari satu byte.
Anda juga perlu mengidentifikasi kumpulan karakter tanggapan Anda. Anda dapat menggunakan AddDefaultCharset, seperti di atas, atau menulis kode PHP yang mengembalikan header. (Atau Anda dapat menambahkan tag META ke dokumen HTML Anda.)
Dukungan Unicode di PHP masih sangat berantakan. Meskipun mampu mengubah string ISO8859 (yang digunakan secara internal) ke utf8, ia tidak memiliki kemampuan untuk bekerja dengan string unicode secara native, yang berarti semua fungsi pemrosesan string akan mengacaukan dan merusak string Anda. Jadi, Anda harus menggunakan pustaka terpisah untuk mendapatkan dukungan utf8 yang benar, atau menulis ulang semua fungsi penanganan string sendiri.
Bagian yang mudah hanya menentukan charset di header HTTP dan dalam database dan semacamnya, tetapi tidak ada yang penting jika kode PHP Anda tidak menampilkan UTF8 yang valid. Itulah bagian yang sulit, dan PHP hampir tidak memberi Anda bantuan di sana. (Saya pikir PHP6 seharusnya memperbaiki yang terburuk dari ini, tapi itu masih lama)
Jika Anda ingin server MySQL memutuskan kumpulan karakter, dan bukan PHP sebagai klien (perilaku lama; lebih disukai, menurut pendapat saya), coba tambahkan skip-character-set-client-handshake
ke Anda my.cnf
, di bawah [mysqld]
, dan mulai ulang mysql
.
Ini dapat menyebabkan masalah jika Anda menggunakan apa pun selain UTF8.
Jawaban teratas sangat bagus. Inilah yang harus saya lakukan pada pengaturan debian / php / mysql biasa:
// 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
itu saja !
jika Anda menginginkan solusi mysql, saya mengalami masalah serupa dengan 2 proyek saya, setelah migrasi server. Setelah mencari dan mencoba banyak solusi, saya menemukan yang ini / tidak ada sebelum yang ini berhasil):
mysqli_set_charset($con,"utf8");
Setelah menambahkan baris ini ke file konfigurasi saya, semuanya berfungsi dengan baik!
Saya menemukan solusi ini https://www.w3schools.com/PHP/func_mysqli_set_charset.asp ketika saya sedang mencari untuk memecahkan penyisipan dari kueri html
semoga berhasil!
Sekadar catatan:
Anda menghadapi masalah karakter non-latin Anda menunjukkan sebagai ?????????
, Anda mengajukan pertanyaan, dan itu bisa ditutup dengan referensi untuk pertanyaan kanonik ini, Anda mencoba segalanya dan tidak peduli apa yang Anda lakukan Anda masih mendapatkan ??????????
dari MySQL
.
Itu sebagian besar karena Anda menguji data lama Anda yang telah dimasukkan ke database menggunakan charset yang salah dan diubah dan disimpan menjadi karakter tanda tanya sebenarnya ?
. Yang berarti Anda kehilangan teks asli Anda selamanya dan apa pun yang Anda coba, Anda akan mendapatkannya ???????
.
Menerapkan kembali apa yang telah Anda pelajari dari jawaban pertanyaan ini pada data baru dapat menyelesaikan masalah Anda.
di connection.php: mysqli_set_charset ($ con, “utf8”); dan di sql collation utf = 8