PHP DOMDocument loadHTML UTF-8 को सही ढंग से एन्कोडिंग नहीं करता है


194

मैं 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人が俳優になった。父親は木材のセールスマンで、母親は郵便局の客室係だった。高校時代はキャディのアルバイトに勤しみ、教育資金を受けながらカトリック系の高校へ進学

संपादित करें: मैंने कोड को पाँच पंक्तियों तक सरल कर दिया है ताकि आप स्वयं इसका परीक्षण कर सकें।

$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>

यह आपकी मदद कर सकता है। stackoverflow.com/questions/1580543/...
frustratedtech

धन्यवाद। मैंने उन सभी की जाँच की और कुछ भी मदद नहीं की। मुझे नहीं मिलता ????, लेकिन कुछ अन्य अजीब पाठ। मैं इसे यहाँ चिपकाने की कोशिश करूँगा, लेकिन यह नहीं जानता कि साइट इसे कैसे प्रदर्शित करेगी।
थोड़ा ए।

उपयोग करने का प्रयास utf8_encode
Webnet

कोई सफलता नहीं मिली। पहले जैसे ही किरदार लौटाए।
थोड़ा ए।

जवाबों:


513

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 (इन कटाना की तरह) में प्रतिनिधित्व नहीं किया जा सकता है, यह सबसे सुरक्षित विकल्प है।


1
हाँ, यह किया है। आपके सहयोग के लिए धन्यवाद। मैंने saveHTML, saveXML की कोशिश की, यह नहीं सोचा कि समस्या लोड के दौरान आ रही है।
थोड़ा ए।

4
Mb_convert_encoding कॉल ने मेरे लिए काम किया, जबकि एन्कोडिंग घोषणा को पूर्व निर्धारित नहीं किया। संभवतः इसलिए कि दस्तावेज़ में पहले से ही परस्पर विरोधी घोषणा थी। बहुत धन्यवाद - मुझे इस समय का पीछा करते हुए बहुत समय बचा लिया।
पीटर बैगनॉल

1
$dom->loadHTML('<?xml encoding="utf-8" ?>' . $content);यह मेरे लिए PHP7 में तय किया (ताकि यह अभी भी एक मुद्दा है) - यह वास्तव में कष्टप्रद समस्या है, क्योंकि मैंने utf8 को HTML दस्तावेज़ में (साथ <meta charset="UTF-8" />) परिभाषित किया है, लेकिन इसका कोई प्रभाव नहीं है, इसे <? xml हिस्सा चाहिए, जो लगता है पूरी तरह से अनपेक्षित है।
इक्विटो

11
अभी भी 2017 में यह उत्तर प्रासंगिक है और मेरे लिए भी काम किया है। मैं अपने डेटाबेस, multibyte, html मेटा टैग और डोम एन्कोडिंग सभी utf8 के लिए सेट था और अभी भी एक DOC से दूसरे में नोड आयात करने पर बुरा एन्कोडिंग था। php.net/manual/en/function.mb-convert-encoding.php फिक्स था।
लुई लाउडोग ट्रॉटियर

6
$dom->loadHTML(mb_convert_encoding($profile, 'HTML-ENTITIES', 'UTF-8'));बहुत अच्छा काम करता है!
साभार

66

समस्या के साथ है saveHTML()और saveXML(), उन दोनों को सही ढंग से यूनिक्स में काम नहीं करते। यूनिक्स में उपयोग किए जाने पर वे सही ढंग से यूटीएफ -8 वर्णों को नहीं बचाते हैं, लेकिन वे विंडोज में काम करते हैं।

वर्कअराउंड बहुत सरल है:

यदि आप डिफ़ॉल्ट का प्रयास करते हैं, तो आपको वर्णित त्रुटि मिलेगी

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

आपको बस इतना करना है:

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

कोड की यह लाइन आपके UTF-8 वर्णों को सही ढंग से सहेजने के लिए मिलेगी। यदि आप उपयोग कर रहे हैं तो उसी वर्कअराउंड का उपयोग करें saveXML()


अपडेट करें

जैसा कि नीचे टिप्पणी अनुभाग में " जैक एम " द्वारा सुझाया गया है , और " पामेला " और " मार्को औरेलियो डेलेयू " द्वारा सत्यापित किया गया है , आपके मामले में निम्नलिखित भिन्नता काम कर सकती है:

$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 करना पड़ा। धन्यवाद!
जैक एम।

9
यह मेरे विशेष पात्रों को संरक्षित करने के लिए utf8_decode ($ dom-> saveHTML (dom-> documentElement)) बनना था। अन्यथा, वे सिर्फ कुछ और बन गए। सिर्फ मामले में इसका जिक्र करने से किसी और को मदद मिलती है।
जैक एम।

4
साभार @MrJack मुझे भी अजीब पात्रों के बिना इसे प्रदर्शित करने के लिए ऐसा ही करना था$str = utf8_decode($dom->saveHTML($dom->documentElement));
पामेला

1
utf8_decode($dom->saveHTML($dom->documentElement));मेरे लिए यह पूरी तरह से किया।
मार्को औरेलियो डेलेउ

2
आपने इससे मेरी जान बचाई। मैं इस जवाब के लिए देखा! धन्यवाद!
पाउलो होगो

15

सुनिश्चित करें कि वास्तविक स्रोत फ़ाइल UTF-8 के रूप में सहेजी गई है (आप सुनिश्चित करने के लिए UTF-8 के साथ गैर-अनुशंसित BOM चार्ट आज़माना चाह सकते हैं)।

HTML के मामले में, सुनिश्चित करें कि आपने metaटैग का उपयोग करके सही एन्कोडिंग घोषित किया है :

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

यदि यह एक सीएमएस है (जैसा कि आपने जूमला के साथ अपने प्रश्न को टैग किया है) तो आपको एन्कोडिंग के लिए उपयुक्त सेटिंग्स कॉन्फ़िगर करने की आवश्यकता हो सकती है।


मैं समझता हूं कि आप क्या कह रहे हैं, लेकिन मुझे पात्रों को प्रदर्शित करने में कोई समस्या नहीं है। अगर मैं "ईको $ प्रोफ़ाइल;" यह बढ़िया काम करता है। यह तब होता है जब DOMDocument इसे प्राप्त करता है कि यह विफल होने लगता है।
थोड़ा ए।

2
आपका मेटा ASCII से ऊपर सब कुछ एन्कोडिंग में saveHTML को रोकता है। समाधान मैं देख रहा था :)
sod

2
एक साइड नोट के रूप में, नया <meta charset="UTF-8">टैग DOMDocument के साथ काम नहीं करता है।
तायलान

10

आप utf-8एन्कोडिंग को लागू करने वाली एक पंक्ति को इस तरह से उपसर्ग कर सकते हैं :

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

और फिर आपके पास पहले से मौजूद कोड के साथ जारी रह सकता है, जैसे:

$doc->saveXML()

10

मुझे यह पता लगाने में थोड़ा समय लगा लेकिन यहाँ मेरा जवाब है।

DOMDocument का उपयोग करने से पहले मैं url को पुनः प्राप्त करने के लिए file_get_contents का उपयोग करूँगा और फिर उन्हें स्ट्रिंग फ़ंक्शंस के साथ संसाधित करूँगा। शायद सबसे अच्छा तरीका नहीं है लेकिन जल्दी। डोम के रूप में आश्वस्त होने के बाद मैं जितनी जल्दी कोशिश कर रहा था, मैंने निम्नलिखित कोशिश की:

$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) {
}

आदि अब दुनिया के साथ सब कुछ सही है। उम्मीद है की यह मदद करेगा।


बस ऊपर मेरे जवाब में जोड़ना चाहता था कि इसे संबोधित करने का एक और तरीका निम्नलिखित है, साथ ही कहीं और सुझाव दिया गया है: यदि ($ डोम-> loadHTML ('<? Xml एन्कोडिंग = "UTF-8">' $ str) =। = असत्य)। अपना उत्तर पोस्ट करने के बाद मुझे एक ऐसा अवसर मिला जहां मेरा पहला सुझाव विफल रहा लेकिन दूसरे ने काम किया।
सैम

मेरे लिए यहां तक ​​कि पारमों के बिना काम करता है DomDocument('1.0', 'UTF-8')। लेकिन मेरे मामले में केवल आंशिक html लोड किया गया है।
JKB

5

आपको अपने HTML के एक वर्जन को DOMDocument को हेडर के साथ खिलाना चाहिए जो कि समझ में आता है। 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;

यह वही सलाह सैम ने इस पेज पर पहले ही दी थी। कृपया कोई अनावश्यक जानकारी पोस्ट न करें।
मिकमैकुसा

4

मेरे लिए काम करता है:

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

2
सावधान रहें, utf8_decode जानकारी खो सकता है (एक के साथ बदल दिया गया है ?)
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; $ प्रोफ़ाइल में हो सकता है, और 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 () फ़ंक्शन में पैरामीटर जोड़ते हैं, तो आप एन्कोडिंग खो देते हैं। कुछ मामलों में, आपको पैरामीटर के उपयोग से बचने और पुराने स्ट्रिंग फ़ंक्शन का उपयोग करने की आवश्यकता होगी, जो कि आप देख रहे हैं।

मुझे लगता है कि पिछला उत्तर आपके लिए काम करता है, लेकिन चूंकि यह समाधान मेरे लिए काम नहीं करता, इसलिए मैं उस उत्तर को पीपीएल में मदद करने के लिए जोड़ रहा हूं जो मेरे मामले में हो सकता है।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.