PHP, MySQL и XML = искаженный вывод HTML - PullRequest
6 голосов
/ 13 января 2011

У меня есть поле в MySQL типа text с использованием следующего сопоставления: utf8_general_ci.

Это поле XML заполняется с помощью переменной, построенной с использованием DOMDocument:

function ed_audit_node($dom, $field, $new, $old){

    //create audit_detail node
    $ad = $dom->createElement('audit_detail');

    $fn = $dom->createElement('fieldname');
    $fn->appendChild($dom->createTextNode($field));
    $ad->appendChild($fn);

    $ov = $dom->createElement('old_value');
    $ov->appendChild($dom->createTextNode($old));
    $ad->appendChild($ov);

    $nv = $dom->createElement('new_value');
    $nv->appendChild($dom->createTextNode($new));
    $ad->appendChild($nv);

    //append to document
    return $ad;
}

Воткак я сохраняю в БД ($ xml происходит от $ dom-> saveXML ()):

function ed_audit_insert($ed, $xml){
    global $visitor;

    $sql = <<<EOF
    INSERT INTO ed.audit
    (employee_id, audit_date, audit_action, audit_data, user_id) 
    VALUES (
        {$ed[emp][employee_id]}, 
        now(), 
        '{$ed[audit_action]}', 
        '{$xml}', 
        {$visitor[user_id]}
    );      
EOF;
    $req = mysql_query($sql,$ed['db']) or die(db_query_error($sql,mysql_error(),__FUNCTION__));
//snip  
}

Смотрите более старую, параллельную, слегка связанную тему о том, как я создаю этот XML: Другая ошибка синтаксического анализа PHP XML: «Неправильный ввод UTF-8, укажите кодировку!»

Что работает : - запрос к базе данных, выбор поля и его вывод с использованием jQuery(.ajax ()) и заполнение текстовой области.Firebug и textarea соответствуют содержимому базы данных (подтверждено с помощью Toad).

Что не работает : - вывод текста из базы данных на HTML-страницу.Эта HTML-страница имеет тип контента ISO-8859-1, который я не могу изменить.

Вот код, который выводит это на экран:

$xmlData = simplexml_load_string($d['audit_data']);

foreach ($xmlData->audit_detail as $a){
    echo "<p> straight from db = ".$a->new_value."</p>";
    echo "<p> utf8_decode() = ".utf8_decode($a->new_value)."</p>";
} 

Я также использовалРасширение charset для Firefox: безуспешно пробовал ISO-8859-1, UTF-8 и 1252.

Если это был UTF-8, разве я не должен видеть алмазы с вопросительными знаками внутри (так как это контент?тип = ISO-8859-1)Если это не UTF-8, что это?

Edit # 1

Вот снимок других моих тестов:

<code>$xmlData = simplexml_load_string($d['audit_data']);
foreach ($xmlData->audit_detail as $a){
    echo "<p>encoding is, straight from db, using mb_detect_encoding: ".mb_detect_encoding($a->new_value)."</p>";
    echo "<p>encoding is, with utf8_decode, using mb_detect_encoding: ".mb_detect_encoding(utf8_decode($a->new_value))."</p>";
    echo "<hr/>";
    echo "<p> straight from db = <pre>".$a->new_value."
"; echo"

utf8_decode () =

".utf8_decode($a->new_value)."
"; echo""; $ iso88591_2 = iconv ('UTF-8', 'ISO-8859-1', $ a-> new_value); $ iso88591_3 = mb_convert_encoding ($ a-> new_value, 'ISO-8859-1', 'UTF-8 '); echo "

iconv () =". $ Iso88591_2. "

"; echo "

mb_convert_encoding () =". $ Iso88591_3. "

";}

Редактировать # 2

Я добавил фирменный тег FF, xmp.

Код:

<code>$xmlData = simplexml_load_string($d['audit_data']);

foreach ($xmlData->audit_detail as $a){
    echo "<p>encoding is, straight from db, using mb_detect_encoding: ".mb_detect_encoding($a->new_value)."</p>";
    echo "<p>encoding is, with utf8_decode, using mb_detect_encoding: ".mb_detect_encoding(utf8_decode($a->new_value))."</p>";
    echo "<hr/>";
    echo "<p> straight from db = <pre>".$a->new_value."
";echo "

utf8_decode () =

".utf8_decode($a->new_value)."
";эхо ""; $ iso88591_2 = iconv ('UTF-8', 'ISO-8859-1', $ a-> new_value); $ iso88591_3 = mb_convert_encoding ($ a-> new_value, 'ISO-8859-1', 'UTF-8 '); echo "

iconv () =". $ Iso88591_2. "

"; echo "

mb_convert_encoding () =". $ Iso88591_3. "

"; echo ""; echo"

прямо из базы данных, используя = ". $ a-> new_value."

"; echo"

utf8_decode (), используя = ". Utf8_decode ($ a-> new_value)."

";}

Вот некоторые метатеги со страницы:

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="dc.language" scheme="ISO639-2/T" content="eng" />

IMO, последний метатег не имеет отношения.

Редактировать # 3

Исходный код:

<code><p>encoding is, straight from db, using mb_detect_encoding: UTF-8</p><p>encoding is, with utf8_decode, using mb_detect_encoding: ASCII</p><hr/><p> straight from db = <pre>Ro马eç ³é ¥n franê¡©s

utf8_decode ()=

Ro?e??n fran?s

iconv () = Ro

mb_convert_encoding () = Ro? E ?? n fran? S

прямо из базы данных, используя = Roé © ¬eç ³é ¥ n franê¡ © s

utf8_decode (), используя = Ro? E?? n fran? s

Edit # 4

Вот оператор SQL, поступающий в базу данных:

INSERT INTO ed.audit
    (employee_id, audit_date, audit_action, audit_data, user_id) 
    VALUES (
        75, 
        now(), 
        'u', 
        '<?xml version="1.0"?>
<audit><audit_detail><fieldname>role_fra</fieldname><old_value>aRo&#x9A6C;e&#x7833;&#x9825;n fran&#xA869;s</old_value><new_value>bRo&#x9A6C;e&#x7833;&#x9825;n fran&#xA869;s</new_value></audit_detail></audit>
', 
        333
    );

!Обратите внимание, что текст этого XML не обязательно соответствует приведенным выше снимкам экрана.

Edit # 5

Вот моя новая функция, которая оборачивает тег CDATA вокруг моих значенийдля узлов old_value и new_value:

function ed_audit_node($dom, $field, $new, $old){

    //create audit_detail node
    $ad = $dom->createElement('audit_detail');

    $fn = $dom->createElement('fieldname');
    $fn->appendChild($dom->createTextNode($field));
    $ad->appendChild($fn);

    $ov = $dom->createElement('old_value');

    $ov->appendChild($dom->createCDATASection($old));
    $ad->appendChild($ov);

    $nv = $dom->createElement('new_value');
    $nv->appendChild($dom->createCDATASection($new));
    $ad->appendChild($nv);

    //append to document
    return $ad;
}

Я также добавил кодировку в документ XML:

$dom = new DomDocument('1.0', 'UTF-8');

Вот мой новый вызов simpleXML:

$xmlData = simplexml_load_string($d['audit_data'], "SimpleXMLElement", LIBXML_NOENT | LIBXML_NOCDATA);

Я также вижу теги CDATA в Toad.Тем не менее, я все еще получаю сообщение об ошибке:

Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 2: parser error : Input is not proper UTF-8, indicate encoding ! Bytes: 0xE9 0xE9 0x6C 0x65 in <snip>

Edit # 6

Я только что заметил, что вызов jQuery возвращает правильные акцентированные символы в CDATA.

1 Ответ

1 голос
/ 13 января 2011

Технически ваша строка находится в UTF8, но символы в кодировке HTML (при визуализации браузером) не в UTF8.Таким образом, &#xa869; является допустимой строкой UTF8, но символ, отображаемый на экране из веб-браузера, не является допустимым UTF8.

Я бы также перенес ваше эхо на экран (последние 2 строки в вашем примере) вот так:

echo "<p>straight from db = <xmp>".$a->new_value."</xmp></p>";
echo "<p>utf8_decode() = <xmp>".utf8_decode($a->new_value)."</xmp></p>";

Это будет ясно отображать точку, которую я делаю выше.

Редактировать:

Проблема на самом деле неуправляемаянедокументированная «особенность» в simplexml_load_string () для PHP.Он автоматически преобразует все символы из их прямой формы XML в их действительную форму символа.Единственный способ обойти это - использовать simplexml_load_string () следующим образом:

 $data = simplexml_load_string(
      '<?xml version="1.0" encoding="utf-8"?> 
           <audit>
                <audit_detail>
                     <fieldname>role_fra</fieldname>
                     <old_value><![CDATA[aRo&#x9A6C;e&#x7833;&#x9825;n fran&#xA869;s]]></old_value>
                     <new_value><![CDATA[bRo&#x9A6C;e&#x7833;&#x9825;n fran&#xA869;s]]></new_value>
                </audit_detail>
           </audit>', 
      "SimpleXMLElement", 
      LIBXML_NOENT | LIBXML_NOCDATA
 );
 print "<PRE>";
 print_r($data);
 exit;

Вы должны обернуть свои элементы в теги <![CDATA[]]> и затем передать параметр LIBXML_NOCDATA в анализатор xml.Это приведет к тому, что элементы в тегах <![CDATA[]]> будут преобразованы в строковый тип, и PHP сможет правильно обработать это за пределами SimpleXMLObject.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...