UTF-8을 올바르게 인코딩하지 않는 PHP DOMDocument loadHTML


195

DOMDocument를 사용하여 일부 HTML을 구문 분석하려고하지만 그렇게하면 갑자기 인코딩이 손실됩니다 (적어도 그것이 나에게 나타나는 방식입니다).

$profile = "<div><p>various japanese characters</p></div>";
$dom = new DOMDocument();
$dom->loadHTML($profile); 

$divs = $dom->getElementsByTagName('div');

foreach ($divs as $div) {
    echo $dom->saveHTML($div);
}

이 코드의 결과는 일본어가 아닌 많은 문자를 얻는 것입니다. 그러나 내가 할 경우 :

echo $profile;

올바르게 표시됩니다. saveHTML과 saveXML을 시도했지만 올바르게 표시되지 않았습니다. PHP 5.3을 사용하고 있습니다.

내가 보는 것 :

ã¤ãªãã¤å·ã·ã«ã´ã«ã¦ãã¢ã¤ã«ã©ã³ãç³»ã®å®¶åº­ã«ã9人åå¼ã®5çªç®ã¨ãã¦çã¾ãããå½¼ãå«ãã¦4人ã俳åªã«ãªã£ããç¶è¦ªã¯æ¨æã®ã»ã¼ã«ã¹ãã³ã§ãæ¯è¦ªã¯éµä¾¿å±ã®å®¢å®¤ä¿ã ã£ããé«æ ¡æ代ã¯ã­ã£ãã£ã®ã¢ã«ãã¤ãã«å¤ãã¿ãæè²è³éãåããªããã«ããªãã¯ç³»ã®é«æ ¡ã¸é²å­¦ã

보여야 할 것 :

イリノイ州シカゴにて、アイルランド系の家庭に、9人兄弟の5番目として生まれる。彼を含めて4人が俳優になった。父親は木材のセールスマンで、母親は郵便局の客室係だった。高校時代はキャディのアルバイトに勤しみ、教育資金を受けながらカトリック系の高校へ進学

편집 : 코드를 5 줄로 단순화하여 직접 테스트 할 수 있습니다.

$profile = "<div lang=ja><p>イリノイ州シカゴにて、アイルランド系の家庭に、</p></div>";
$dom = new DOMDocument();
$dom->loadHTML($profile);
echo $dom->saveHTML();
echo $profile;

반환되는 HTML은 다음과 같습니다.

<div lang="ja"><p>イリノイ州シカゴã«ã¦ã€ã‚¢ã‚¤ãƒ«ãƒ©ãƒ³ãƒ‰ç³»ã®å®¶åº­ã«ã€</p></div>
<div lang="ja"><p>イリノイ州シカゴにて、アイルランド系の家庭に、</p></div>


감사. 나는 모든 것을 점검했지만 아무런 도움이되지 않았습니다. 나는 ????를 얻지 못하지만 다른 이상한 텍스트가 있습니다. 여기에 붙여 넣으려고하지만 사이트에서 어떻게 표시 될지 모르겠습니다.
약간 A.


성공하지 못했습니다. 이전과 같은 문자를 반환했습니다.
약간 A.

답변:


514

DOMDocument::loadHTML달리 명시하지 않는 한 문자열을 ISO-8859-1에있는 것으로 간주합니다. 이로 인해 UTF-8 문자열이 잘못 해석됩니다.

문자열에 XML 인코딩 선언이 포함되어 있지 않은 경우 문자열 앞에 UTF-8로 처리되도록 할 수 있습니다.

$profile = '<p>イリノイ州シカゴにて、アイルランド系の家庭に、9</p>';
$dom = new DOMDocument();
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $profile);
echo $dom->saveHTML();

문자열에 이러한 선언이 이미 포함되어 있는지 알 수없는 경우 SmartDOMDocument에 다음 과 같은 해결 방법이 있습니다.

$profile = '<p>イリノイ州シカゴにて、アイルランド系の家庭に、9</p>';
$dom = new DOMDocument();
$dom->loadHTML(mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8'));
echo $dom->saveHTML();

이것은 훌륭한 해결 방법은 아니지만 모든 문자를 ISO-8859-1 (이 katana와 같이)로 표현할 수있는 것은 아니므로 가장 안전한 대안입니다.


1
그렇습니다. 도와 주셔서 감사합니다. saveXML, saveXML을 시도했지만로드 중에 문제가 발생했을 것이라고 생각하지 않았습니다.
약간 A.

4
mb_convert_encoding 호출은 나를 위해 일했지만 인코딩 선언 앞에 붙지 않았습니다. 문서에 이미 선언이 충돌했기 때문일 수 있습니다. 많은 감사-이것을 쫓는 데 많은 시간을 절약했습니다.
Peter Bagnall

1
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $content);PHP7에서 나를 위해 고쳤습니다 (그래도 여전히 문제입니다)-HTML 문서에서 utf8을 정의했기 때문에 이것은 실제로 성가신 문제 <meta charset="UTF-8" />입니다. 완전히 직관적이지 않습니다.
iquito

11
여전히 2017 년 에이 답변은 관련이 있으며 저에게도 도움이되었습니다. 내 데이터베이스, 멀티 바이트, HTML 메타 태그 및 DOM 인코딩이 모두 utf8로 설정되었지만 노드를 하나의 DOC에서 다른 노드로 가져올 때 여전히 인코딩이 잘못되었습니다. php.net/manual/en/function.mb-convert-encoding.php 가 수정되었습니다.
Louis Loudog Trottier

6
$dom->loadHTML(mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8'));잘 작동합니다! 감사합니다
vee

67

문제는 saveHTML()및에 saveXML()있으며 둘 다 Unix에서 올바르게 작동하지 않습니다. Unix에서 사용될 때 UTF-8 문자를 올바르게 저장하지 않지만 Windows에서는 작동합니다.

해결 방법은 매우 간단합니다.

기본값을 사용하면 설명 된 오류가 발생합니다.

$str = $dom->saveHTML(); // saves incorrectly

다음과 같이 저장하면됩니다.

$str = $dom->saveHTML($dom->documentElement); // saves correctly

이 코드 줄은 UTF-8 문자가 올바르게 저장되도록합니다. 를 사용하는 경우 동일한 해결 방법을 사용하십시오 saveXML().


최신 정보

아래의 댓글 섹션에서 " Jack M "이 제안하고 " Pamela "및 " Marco Aurélio Deleu "가 확인한 경우 다음과 같은 변형이 작동 할 수 있습니다.

$str = utf8_decode($dom->saveHTML($dom->documentElement));

노트

  1. 영어 문자는 saveHTML()매개 변수없이 사용할 때 아무런 문제를 일으키지 않습니다 (영어 문자는 UTF-8에서 단일 바이트 문자로 저장되므로)

  2. 멀티 바이트 문자 (예 : 중국어, 러시아어, 아랍어, 히브리어 등)가있는 경우 문제가 발생합니다.

이 기사를 읽는 것이 좋습니다 : http://coding.smashingmagazine.com/2012/06/06/all-about-unicode-utf8-character-sets/ . UTF-8의 작동 방식과이 문제점이있는 이유를 이해합니다. 약 30 분이 소요되지만 시간이 많이 소요됩니다.


5
이 솔루션을 사용하는 동안 utf8_decode해야했습니다. 감사!
Jack M.

9
내 특수 문자를 유지하려면 utf8_decode ($ dom-> saveHTML (dom-> documentElement))가되어야했습니다. 그렇지 않으면, 그들은 단지 다른 것이되었습니다. 다른 사람에게 도움이 될 경우를 대비하여 언급하십시오.
Jack M.

4
감사합니다 @MrJack. 또한 이상한 문자없이 표시되도록 동일한 작업을 수행해야했습니다$str = utf8_decode($dom->saveHTML($dom->documentElement));
Pamela

1
utf8_decode($dom->saveHTML($dom->documentElement));나를 위해 완벽하게 했어.
Marco Aurélio Deleu

2
당신은 이것으로 내 생명을 구했습니다. 나는이 답을 어디에서나 찾았다! 감사합니다!
Paulo Hgo

15

실제 소스 파일이 UTF-8로 저장되어 있는지 확인하십시오 (권장하지 않는 BOM Chars를 UTF-8과 함께 사용해 볼 수도 있습니다).

또한 HTML의 경우 meta태그를 사용하여 올바른 인코딩을 선언했는지 확인하십시오 .

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

CMS 인 경우 (Jomla로 질문에 태그를 추가 한 것처럼) 인코딩에 적절한 설정을 구성해야 할 수 있습니다.


나는 당신이 말하는 것을 이해하지만 문자를 표시하는 데 아무런 문제가 없습니다. 내가 "echo $ profile;" 잘 작동합니다. DomDocument가 실패하기 시작했을 때입니다.
약간 A.

2
메타는 saveHTML이 ASCII 이상의 모든 항목을 엔티티로 인코딩하지 못하게합니다. 내가 찾고있는 해결책 :)
sod

2
참고로 최신 <meta charset="UTF-8">태그는 DOMDocument에서 작동하지 않습니다.
Taylan

10

다음 utf-8과 같이 인코딩을 적용하는 줄을 앞에 붙일 수 있습니다 .

@$doc->loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $profile);

그런 다음 다음과 같이 기존 코드를 계속 사용할 수 있습니다.

$doc->saveXML()

10

이것은 알아내는 데 시간이 걸렸지 만 여기에 내 대답이 있습니다.

DomDocument를 사용하기 전에 file_get_contents를 사용하여 URL을 검색 한 다음 문자열 함수로 처리합니다. 아마도 가장 좋은 방법은 아니지만 빠를 것입니다. Dom이 빠르다고 확신 한 후 처음으로 다음을 시도했습니다.

$dom = new DomDocument('1.0', 'UTF-8');
if ($dom->loadHTMLFile($url) == false) { // read the url
    // error message
}
else {
    // process
}

적절한 메타 태그, PHP 설정 및 여기 및 다른 곳에서 제공되는 모든 구제책에도 불구하고 UTF-8 인코딩을 보존하는 데 크게 실패했습니다. 작동하는 내용은 다음과 같습니다.

$dom = new DomDocument('1.0', 'UTF-8');
$str = file_get_contents($url);
if ($dom->loadHTML(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8')) == false) {
}

이제 모든 것이 세상에 맞습니다. 도움이 되었기를 바랍니다.


이 문제를 해결하는 또 다른 방법은 다른 곳에서도 제안 된 것입니다. if ($ dom-> loadHTML ( '<? xml encoding = "UTF-8">'. $ str) = = 거짓). 내 답변을 게시 한 후 첫 번째 제안은 실패했지만 두 번째 제안은 효과가있는 경우를 발견했습니다.
Sam

의 매개 변수 없이도 나를 위해 작동합니다 DomDocument('1.0', 'UTF-8'). 그러나 제 경우에는 부분 HTML 만로드됩니다.
JKB

5

이해하기 쉬운 헤더를 사용하여 DOMDocument에 HTML 버전을 제공해야합니다. HTML5처럼.

$profile ='<?xml version="1.0" encoding="'.$_encoding.'"?>'. $html;

어쩌면 당신이 문제에하지 않도록 당신이 주변에 ... 쿼리를 시작합니다 때, 당신이 할 수있는 유효로 HTML을 유지 :-)하고 멀리하는 좋은 아이디어입니다 htmlentities!!!! 그것은 앞뒤로 필요한 자원 낭비입니다. 당신의 코드를 미쳐 버리세요 !!!!


5

manjaro에서 PHP 7.3.8을 사용하고 있으며 페르시아어 콘텐츠로 작업하고있었습니다. 이것은 내 문제를 해결했다.

$html = 'hi</b><p>سلام<div>の家庭に、9 ☆';
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
print $doc->saveHTML($doc->documentElement) . PHP_EOL . PHP_EOL;

이 같은 페이지에서 Sam이 몇 년 전에 똑같은 조언을하였습니다. 중복 정보를 게시하지 마십시오.
mickmackusa

4

나를위한 작품 찾기 :

$dom = new \DOMDocument;
$dom->loadHTML(utf8_decode($html));
...
return  utf8_encode( $dom->saveHTML());

2
주의, 정보가 유실 될 수 있습니다 utf8_decode의 (a로 대체 ?)
jwal

2

올바른 결과를 위해 사용하십시오

$dom = new DOMDocument();
$dom->loadHTML('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . $profile);
echo $dom->saveHTML();
echo $profile;

이 작업

mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8');

& lt;와 같은 특수 기호는 잘못된 방법입니다. & gt; $ profile에있을 수 있으며 mb_convert_encoding 후 두 번 변환되지 않습니다. XSS 및 잘못된 HTML의 구멍입니다.


1

나를 위해 일한 유일한 것은 허용 된 답변이었습니다.

$profile = '<p>イリノイ州シカゴにて、アイルランド系の家庭に、9</p>';
$dom = new DOMDocument();
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $profile);
echo $dom->saveHTML();

하나

이로 인해 <?xml encoding="utf-8" ?>문서 출력 에 새로운 문제가 발생했습니다 .

그때 나를위한 해결책은

foreach ($doc->childNodes as $xx) {
    if ($xx instanceof \DOMProcessingInstruction) {
        $xx->parentNode->removeChild($xx);
    }
}

일부 솔루션은 xml헤더 를 제거하고 수행해야 한다고 말했습니다.

$dom->saveXML($dom->documentElement);

이것은 부분 문서 (예 : 두 개의 <p>태그가 있는 문서)와 같이 작동하지 않으며 <p>반환되는 태그 중 하나만 작동합니다 .


0

문제는 DOMDocument :: saveHTML () 함수에 매개 변수를 추가하면 인코딩이 손실된다는 것입니다. 어떤 경우에는 매개 변수 사용을 피하고 찾고자하는 것을 찾기 위해 이전 문자열 함수를 사용해야합니다.

이전 답변이 효과가 있다고 생각하지만이 해결 방법이 효과가 없기 때문에 내 경우에있을 수있는 ppl을 돕기 위해 해당 답변을 추가하고 있습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.