Làm cách nào để đặt tiêu đề HTTP thành UTF-8 bằng PHP có giá trị trong trình xác thực W3C?


319

Tôi có một số trang PHP lặp lại nhiều thứ khác nhau thành các trang HTML với mã sau đây.

<meta http-equiv="Content-type" content="text/html; charset=utf-8" />

Tuy nhiên, khi tôi xác thực bằng trình xác nhận W3C, nó xuất hiện:

Mã hóa ký tự được chỉ định trong tiêu đề HTTP (iso-8859-1) khác với giá trị trong phần tử (utf-8).

Tôi còn khá mới với PHP và tôi đã tự hỏi liệu tôi có thể và nên thay đổi tiêu đề cho các tệp PHP để khớp với các tệp HTML hay không.

Câu trả lời:


897

Sử dụng headerđể sửa đổi tiêu đề HTTP:

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

Lưu ý để gọi chức năng này trước khi bất kỳ đầu ra nào được gửi đến máy khách. Nếu không, tiêu đề cũng đã được gửi và rõ ràng bạn không thể thay đổi nó nữa. Bạn có thể kiểm tra với headers_sent. Xem trang hướng dẫnheader để biết thêm thông tin.


4
Tôi chỉ nói thêm rằng khi bạn đặt tiêu đề HTTP chính xác như thế này, bạn không cần <meta>thẻ nữa.
Jon

3
@Jon: Tôi sẽ sử dụng cả hai. Tương đương HTTP METAđược sử dụng khi tài liệu HTML không được tải qua HTTP (ví dụ: từ đĩa).
Gumbo

6
Điều này sẽ chỉ hoạt động nếu thực thi php của bạn, để làm điều đó cho các trang tĩnh, bạn nên lưu tệp html của mình NHƯ utf-8. Làm như vậy sẽ thêm ký tự BOM utf-8 được mã hóa vào đầu tệp. byte 0xEF, 0xBB, 0xBF được thêm vào phần đầu của tệp. Hầu hết các máy chủ web sẽ nhận thấy điều này và áp dụng tiêu đề thích hợp. Trong thực tế, lưu tệp php của bạn dưới dạng utf-8, sẽ thực hiện được điều tương tự.
Rạng rỡ

1
@Jeremy Walton: Rằng UTF-8 được thêm vào không nhất thiết phải xảy ra. Trên thực tế, nó thậm chí không cần thiết cho UTF-8 vì nó chỉ có một thứ tự byte (nhưng nó có thể được sử dụng để xác định UTF-8).
Gumbo

1
@Gumbo: chắc chắn, tôi đang đơn giản hóa ở đây và nhắm mục tiêu theo kịch bản web phổ biến nhất (câu hỏi dường như nói về kịch bản này). Có tính đến mức độ rõ ràng của câu hỏi, tại sao bạn phải làm gì đó khi bạn thậm chí không hiểu những lợi thế mà một ngày nào đó có thể cung cấp là gì?
Jon


15

Đây là một vấn đề với máy chủ web của bạn gửi ra một tiêu đề HTTP không khớp với tiêu đề bạn xác định. Để biết hướng dẫn về cách làm cho máy chủ gửi tiêu đề chính xác, xem trang này .

Mặt khác, bạn cũng có thể sử dụng PHP để sửa đổi các tiêu đề, nhưng điều này phải được thực hiện trước khi xuất bất kỳ văn bản nào sử dụng mã này:

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

Thông tin thêm về cách gửi tiêu đề bằng PHP có thể được tìm thấy trong tài liệu cho chức năng tiêu đề .


12

Bạn cũng có thể sử dụng một cách ngắn hơn:

<?php header('Content-Type: charset=utf-8'); ?>

Xem RFC 2616 . Nó chỉ hợp lệ để chỉ định bộ ký tự.


Tôi thích tùy chọn này, vì (tôi giả sử) nó sẽ cho phép bạn đặt riêng phần khác của loại nội dung (ví dụ: bạn có một số trang văn bản / trang đơn giản và một số trang văn bản / html, nhưng tất cả chúng đều là UTF8.) Tôi hiểu có đúng không?
Eric Seastrand

1
Tôi không thể tìm thấy phần của RFC 2616 nói rằng nó hợp lệ để chỉ định theo cách đó. Content-Type = "Content-Type" ":" media-typemedia-type = type "/" subtype *( ";" parameter )
AI0867

1
Nó không hợp lệ để chỉ xác định bộ ký tự. Nó không hợp lệ theo RFC 2616 (dù sao cũng đã lỗi thời) cũng như trên RFC 7231 (không lỗi thời) cũng như bất kỳ RFC nào khác. Xem stackoverflow.com/questions/41994062/ từ
sIDIAbarker

10

Để thực hiện đúng, bạn cần thay đổi một loạt điều.

Cơ sở dữ liệu (ngay sau khi kết nối):

mysql_query("SET NAMES utf8");

// Meta tag HTML (probably it's already set): 
meta charset="utf-8"
header php (before any output of the HTML):
header('Content-Type: text/html; charset=utf-8')
table-rows-charset (for each row):
utf8_unicode_ci

4
Liên minh của cơ sở dữ liệu không ảnh hưởng đến đầu ra do PHP tạo ra vì dữ liệu được mã hóa theo định dạng gốc được định cấu hình để sử dụng với PHP trước khi nó được trả về cho người dùng. Thứ hai, OP đã không đề cập đến việc anh ấy đang sử dụng MySQL. Thứ ba MyISAM đã lỗi thời và không nên được đề xuất trừ khi bạn biết bạn đang làm gì Có một lý do khiến InnoDB trở thành mặc định mới.
EWit

cuối cùng là một danh sách đầy đủ tất cả các vị trí để thiết lập mã hóa ký tự.
Filip OvertoneSinger Rydlo

mysql_query ("THIẾT LẬP TÊN utf8"); trước khi truy vấn chọn của tôi đã khắc phục sự cố cho tôi. cảm ơn :)
Deepak Goswami

7

PHP sẽ tự động gửi các tiêu đề nếu được thiết lập để sử dụng mã hóa nội bộ:

ini_set('default_charset', 'utf-8');
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.