UTF-8 sepenuhnya

Nov 11 2008

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

1044 chazomaticus Nov 11 2008 at 04:43

Penyimpanan Data :

  • Tentukan utf8mb4kumpulan 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 menggunakan utf8mb4pengkodean jika utf8mb4_*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 charsetdi 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/ utf8berlaku 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-Typeheader MIME sendiri secara manual , yang lebih berfungsi tetapi memiliki efek yang sama.

  • Saat mengenkode keluaran menggunakan json_encode(), tambahkan JSON_UNESCAPED_UNICODEsebagai 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-charsetatribut 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.

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 mbstringfungsi 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.

157 mercator Nov 13 2008 at 02:27

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).

66 chroder Nov 11 2008 at 04:30

Selain pengaturan default_charsetdi 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.

37 JimW. Sep 11 2012 at 22:40

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.

25 JDelage Feb 24 2012 at 05:20

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");.

23 JimmyKane Jan 27 2014 at 16:16

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.

15 PuertoAGP Sep 10 2014 at 10:39

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.

14 MiguelStevens Jan 13 2014 at 16:37

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.

10 AbdulSadikYalcin May 06 2015 at 04:36

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

9 JW. Nov 11 2008 at 04:29

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.)

7 jalf Nov 11 2008 at 04:48

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)

7 BudimirGrom Feb 12 2015 at 06:52

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-handshakeke Anda my.cnf, di bawah [mysqld], dan mulai ulang mysql.

Ini dapat menyebabkan masalah jika Anda menggunakan apa pun selain UTF8.

6 commonpike Jan 14 2011 at 23:13

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 !

2 castro_pereira Mar 25 2019 at 02:27

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!

Accountantم Aug 24 2019 at 02:10

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.

IjazAhmedBhatti Sep 27 2020 at 13:24

di connection.php: mysqli_set_charset ($ con, “utf8”); dan di sql collation utf = 8