Pertanyaan UTF-8 sepenuhnya


Saya menyiapkan server baru, dan ingin mendukung UTF-8 sepenuhnya dalam aplikasi web saya. Saya telah mencoba di masa lalu pada server yang ada dan tampaknya selalu harus kembali ke ISO-8859-1.

Di mana tepatnya saya harus mengatur encoding / charsets? Saya sadar bahwa saya perlu mengkonfigurasi Apache, MySQL dan PHP untuk melakukan ini - apakah ada daftar standar yang bisa saya ikuti, atau mungkin memecahkan masalah ketidaksesuaian yang terjadi?

Ini untuk server Linux baru, menjalankan MySQL 5, PHP 5 dan Apache 2.


986
2017-11-10 21:04


asal


Jawaban:


Penyimpanan data:

  • Tentukan utf8mb4 set karakter di semua tabel dan kolom teks di database Anda. Ini membuat MySQL secara fisik menyimpan dan mengambil nilai yang dikodekan secara asli di UTF-8. Perhatikan bahwa MySQL secara implisit akan digunakan utf8mb4 encoding jika a utf8mb4_* pemeriksaan ditentukan (tanpa set karakter eksplisit).

  • Dalam versi MySQL yang lebih lama (<5.5.3), Anda sayangnya akan dipaksa untuk menggunakan secara sederhana 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 mengatur charset koneksi ke utf8mb4. Dengan cara ini, MySQL tidak melakukan konversi dari UTF-8 asalnya ketika ia menyerahkan data ke aplikasi Anda dan sebaliknya.

  • Beberapa driver menyediakan mekanisme mereka sendiri untuk mengkonfigurasi set karakter koneksi, yang keduanya memperbarui keadaan internal sendiri dan menginformasikan MySQL dari pengkodean yang akan digunakan pada koneksi-ini biasanya adalah pendekatan yang disukai. Di PHP:

    • Jika Anda menggunakan PDO lapisan abstraksi dengan PHP ≥ 5.3.6, Anda dapat menentukan charset dalam DSN:

      $dbh = new PDO('mysql:charset=utf8mb4');
      
    • Jika Anda menggunakan mysqli, Anda bisa menelepon set_charset():

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • Jika Anda terjebak dengan polos mysql tetapi kebetulan menjalankan PHP ≥ 5.2.3, Anda bisa menelepon mysql_set_charset.

  • Jika driver tidak menyediakan mekanisme sendiri untuk mengatur set karakter koneksi, Anda mungkin harus mengeluarkan query 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 mengirim teks ke sistem lain, mereka juga perlu diberitahu tentang pengkodean karakter. Dengan aplikasi web, browser harus diberitahu tentang pengkodean di mana data dikirim (melalui header tanggapan HTTP atau Metadata HTML).

  • Di PHP, Anda dapat menggunakan default_charset php.ini opsi, atau secara manual mengeluarkan Content-Type MIME menautkan diri Anda sendiri, yang lebih banyak bekerja tetapi memiliki efek yang sama.

Memasukkan:

  • 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 trik, tetapi Anda harus menggunakannya secara religius. Sebenarnya 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 bacaan saya tentang arus Spesifikasi HTML, sub-peluru berikut ini tidak diperlukan atau bahkan berlaku lagi untuk HTML modern. Pemahaman saya adalah bahwa browser akan bekerja dengan dan mengirimkan data dalam set karakter yang ditentukan untuk dokumen. Namun, jika Anda menargetkan versi lama HTML (XHTML, HTML4, dll.), Titik-titik ini mungkin masih berguna:

    • Untuk HTML sebelum HTML5 saja: Anda ingin semua data dikirim kepada Anda oleh browser untuk berada di UTF-8. Sayangnya, jika Anda pergi dengan satu-satunya cara untuk melakukan hal ini adalah dengan tepercaya accept-charset atribut untuk semua Anda <form> tag: <form ... accept-charset="UTF-8">.
    • Untuk HTML sebelum HTML5 saja: perhatikan bahwa spesifikasi HTML W3C mengatakan bahwa klien "harus" default untuk mengirim formulir kembali ke server dalam charset apa pun yang dilayani server, tetapi ini tampaknya hanya rekomendasi, maka kebutuhan untuk menjadi eksplisit pada setiap satu <form> menandai.

Pertimbangan Kode Lainnya:

  • Cukup jelas, semua file yang akan Anda layani (PHP, HTML, JavaScript, dll.) Harus dikodekan dalam UTF-8 yang valid.

  • Anda perlu memastikan bahwa setiap kali Anda memproses string UTF-8, Anda melakukannya dengan aman. Sayangnya ini bagian yang sulit. Anda mungkin ingin menggunakan PHP secara ekstensif mbstring perpanjangan.

  • Operasi string bawaan PHP adalah tidak secara default UTF-8 aman.  Ada beberapa hal yang dapat Anda lakukan dengan operasi string PHP normal (seperti penggabungan), tetapi untuk sebagian besar hal Anda harus menggunakan yang setara mbstring fungsi.

  • Untuk mengetahui apa yang Anda lakukan (baca: tidak mengacaukannya), Anda benar-benar perlu mengetahui UTF-8 dan bagaimana cara kerjanya pada tingkat serendah mungkin. Lihat tautan apa pun dari utf8.com untuk beberapa sumber yang baik untuk mempelajari semua yang perlu Anda ketahui.


861
2017-11-10 21:43



Saya ingin menambahkan satu hal jawaban luar biasa chazomaticus:

Jangan lupa tag META (seperti ini, atau versi HTML4 atau XHTML-nya):

<meta charset="utf-8">

Itu tampaknya sepele, tetapi IE7 telah memberi saya masalah dengan itu sebelumnya.

Saya melakukan segalanya dengan benar; database, koneksi database dan header HTTP Content-Type telah diatur ke UTF-8, dan itu berfungsi dengan baik di semua browser lain, tetapi Internet Explorer masih bersikeras menggunakan pengkodean "Eropa Barat".

Ternyata halaman itu kehilangan tag META. Menambah itu memecahkan masalah.

Edit:

W3C sebenarnya memiliki yang agak besar bagian yang didedikasikan untuk I18N. Mereka memiliki sejumlah artikel yang terkait dengan masalah ini - menggambarkan sisi HTTP, (X) HTML dan CSS:

Mereka merekomendasikan untuk menggunakan baik header HTTP dan meta tag HTML (atau deklarasi XML dalam hal XHTML disajikan sebagai XML).


134
2017-11-12 19:27



Selain pengaturan default_charset di php.ini, Anda dapat mengirim penggunaan charset yang benar header() dari dalam kode Anda, sebelum keluaran apa pun:

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

Bekerja dengan Unicode di PHP mudah selama Anda menyadari bahwa sebagian besar fungsi string tidak berfungsi dengan Unicode, dan beberapa mungkin meruntuhkan 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 sebenarnya apa yang Anda cari). Tetapi di lain waktu, ketika fungsi sebenarnya dirancang untuk dikerjakan karakter, PHP tidak tahu bahwa teks Anda memiliki karakter multi-byte yang ditemukan dengan Unicode.

Perpustakaan yang bagus untuk diperiksa phputf8. Ini 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 (tapi saya menulis produk pasar massal, jadi itu penting bagi saya). Tetapi phputf8 dapat menggunakan mbstring di belakang layar, bagaimanapun, untuk meningkatkan kinerja.


55
2017-11-10 21:30



Topik lama, saya tahu. Menemukan masalah dengan seseorang 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 saya mengambil ini dari bawah, bisa mendapatkannya menggunakan cache google untungnya.


26
2017-09-11 15:40



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 melakukan mb_regex_encoding('UTF-8');

Sebagai catatan tambahan, saya juga menemukan dengan berlari mb_internal_encoding() bahwa pengkodean internal tidak utf-8, dan saya mengubah itu dengan menjalankan mb_internal_encoding("UTF-8");.


20
2018-02-23 22:20



Pertama-tama jika Anda berada di <5.3PHP, maka tidak. Anda punya banyak masalah yang harus diatasi.

Saya terkejut bahwa tidak ada yang menyebutkan intl perpustakaan, yang memiliki dukungan baik untuk unicode, grafem, operasi string , lokalisasi dan banyak lagi, lihat di bawah.

Saya akan mengutip beberapa informasi tentang dukungan unicode di PHP oleh Elizabeth Smith  slide di PHPBenelux'14

INTL

Baik:

  • Wrapper di sekitar perpustakaan ICU
  • Lokal standar, atur lokal per skrip
  • Pemformatan angka
  • Pemformatan mata uang
  • Pemformatan pesan (menggantikan gettext)
  • Kalender, tanggal, zona waktu, dan waktu
  • Transliterator
  • Spoofchecker
  • Kumpulan sumber daya
  • Konverter
  • Dukungan IDN
  • Graphemes
  • Pemeriksaan
  • Iterator

Buruk:

  • Tidak mendukung zend_multibite
  • Tidak mendukung konversi output input HTTP
  • Tidak mendukung fungsi overloading

mb_string

  • Mengaktifkan dukungan zend_multibyte
  • Mendukung penyandian transparan in / out HTTP
  • Menyediakan beberapa pembungkus untuk funtionallity seperti strtoupper

ICONV

  • Utama untuk konversi charset
  • Penangan keluaran buffer
  • fungsionalitas pengkodean mime
  • 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 pemeriksaan pada tabel dan koneksi (bukan collation). Juga jangan gunakan mysql - msqli atau PDO
  • postgresql: pg_set_client_encoding
  • sqlite (3): Pastikan itu dikompilasi dengan unicode dan intl support

Beberapa Gotchas lainnya

  • Anda tidak dapat menggunakan nama file unicode dengan PHP dan windows kecuali Anda menggunakan ekstensi bagian ke-3.
  • Kirim semuanya di ASCII jika Anda menggunakan exec, proc_open, dan panggilan baris perintah lainnya
  • Teks biasa bukan teks biasa, file memiliki penyandian
  • Anda dapat mengonversi file dengan cepat menggunakan filter ikonv

Saya akan memperbarui jawaban ini jika ada hal-hal yang mengubah fitur yang ditambahkan dan sebagainya.


19
2018-01-27 09:16



Saya baru-baru ini menemukan bahwa menggunakan strtolower() dapat menyebabkan masalah ketika 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.


13
2018-01-13 09:37