[英]List of known troublesome characters that causes PHP to fail to detect the proper character encoding before converting to UTF-8 resulting in lost data
PHP 並不總是正確的,我寫的內容必須始終正確。 在這種情況下,帶有主題的 email 包含短划線字符。 該線程是關於檢測 PHP 錯誤地檢測到單獨的奇怪字符(比如說,在其他純 ASCII 文本中)。 我已經確定了一個 static 示例,盡管我的目標是創建一個明確的線程,其中包含盡可能接近我們可以創建的插入代碼版本。
這是我從 email 的主題 header 開始的字符串:
<?php
//This is AFTER exploding the : of the header and using trim on $p[1]:
$s = '=?ISO-8859-1?Q?orkut=20=96=20convite=20enviado=20por=20Lais=20Piccirillo?=';
//orkut – convite enviado por Lais Piccirillo
?>
通常,下一步是執行以下操作:
$s = imap_mime_header_decode($s);//orkut � convite enviado por Lais Piccirillo
通常超過這一點,我會做以下事情:
$s = mb_convert_encoding($subject, 'UTF-8', mb_detect_encoding($s));//en dash missing!
現在,我收到了 static 對較早 static 問題的回答。 最終,我能夠將這組工作代碼放在一起:
<?php
$s1 = '=?ISO-8859-1?Q?orkut=20=96=20convite=20enviado=20por=20Lais=20Piccirillo?=';
//Attempt to determine the character set:
$en = mb_detect_encoding($s1);//ASCII; wrong!!!
$p = explode('?', $s1, 3)[1];//ISO-8859-1; wrong!!!
//Necessary to decode the q-encoded header text any way FIRST:
$s2 = imap_mime_header_decode($s1);
//Now scan for character exceptions in the original text to compensate for PHP:
if (strpos($s1, '=96') !== false) {$s2 = mb_convert_encoding($s2[0]->text, 'UTF-8', 'CP1252');}
else {$s2 = mb_convert_encoding($s2[0]->text, 'UTF-8');}
//String is finally ready for client output:
echo '<pre>'.print_r($s2,1).'</pre>';//orkut – convite enviado por Lais Piccirillo
?>
現在要么我仍然編程不正確,並且在 PHP 中有一些東西我丟失了(嘗試了html_entity_decode
、 iconv
、 mb_convert_encoding
和utf8_encode
的許多組合),或者,至少在 PHP 的那一刻,我們將被強制檢測特定字符並手動覆蓋編碼,就像我在第 12 行所做的那樣。在后一種情況下,需要創建錯誤報告,或者如果已經存在特定於該問題的錯誤報告,則可能更新錯誤報告。
所以從技術上講,問題是:
我們如何正確檢測所有字符編碼以防止在將字符串轉換為 UTF-8 的過程中丟失任何字符?
如果不存在這樣的正確答案,則有效答案包括在其他情況下純 ASCII 文本導致 PHP 未能正確檢測到正確的字符編碼從而導致不正確的 UTF-8 編碼字符串的字符。 假設這個問題在未來得到解決,並且可以針對所有其他相關答案中列出的所有奇數字符進行驗證,那么可以接受正確的答案。
您將 PHP 無法解決的問題歸咎於 PHP:
您的實際問題是您發送的信息是錯誤的 - 發送給您的系統犯了一個常見錯誤,即錯誤地將 Windows-1252 標記為 ISO-8859-1。
兩種編碼之間的區別在於,從 0x80 到 0x9F 的字節是 ISO 8859 中的控制字符,並且(大部分)分配給 Windows-1252 中的可打印字符。 請注意,任何系統都無法自動告訴您打算使用哪種解釋 - 無論哪種方式,memory 中都只有一個包含 0x96 的字節。 然而,任何此類字節更有可能是 Windows- 1252字符,而不是 ISO 8859 中很少使用的額外控制字符,因此一個常見的解決方案是簡單地假設任何標記為 ISO-8859-1 的數據是實際上是 Windows-1252 。
這使得解決方案非常簡單:
// $input is the ASCII string you've received
$input = '=?ISO-8859-1?Q?orkut=20=96=20convite=20enviado=20por=20Lais=20Piccirillo?=';
// Decode the string into its labelled encoding, and string of bytes
$mime_decoded = imap_mime_header_decode($input);
$input_encoding = $mime_decode[0]->charset;
$raw_bytes = $mime_decode[0]->text;
// If it claims to be ISO-8859-1, assume it's lying
if ( $input_encoding === 'ISO-8859-1' ) {
$input_encoding = 'Windows-1252';
}
// Now convert from a known encoding to UTF-8 for the use of your application
$utf8_string = mb_convert_encoding($raw_bytes, 'UTF-8', $input_encoding);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.