PHP: UTF8 curl_exec çıktı dönüştürme

5 Cevap php

Ben sadece UTF8 ile çalışmak istiyorum. Sorun her web sayfasının charset bilmiyorum. Bunu nasıl algılamak ve UTF8 dönüştürebilirsiniz?

<?php
$url = "http://vkontakte.ru";
$ch = curl_init($url);
$options = array(
    CURLOPT_RETURNTRANSFER => true,
);
curl_setopt_array($ch, $options);
$data = curl_exec($ch);

// $data = magic($data);

print $data;

Bu bakınız: http://paulisageek.com/tmp/curl-utf8

Nedir magic()?

5 Cevap

Gumbo ve Pekka tavsiyesi ile gidiyor, ben yazdım curl_exec_utf8

/** The same as curl_exec except tries its best to convert the output to utf8 **/
function curl_exec_utf8($ch) {
    $data = curl_exec($ch);
    if (!is_string($data)) return $data;

    unset($charset);
    $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);

    /* 1: HTTP Content-Type: header */
    preg_match( '@([\w/+]+)(;\s*charset=(\S+))?@i', $content_type, $matches );
    if ( isset( $matches[3] ) )
        $charset = $matches[3];

    /* 2: <meta> element in the page */
    if (!isset($charset)) {
        preg_match( '@<meta\s+http-equiv="Content-Type"\s+content="([\w/]+)(;\s*charset=([^\s"]+))?@i', $data, $matches );
        if ( isset( $matches[3] ) )
            $charset = $matches[3];
    }

    /* 3: <xml> element in the page */
    if (!isset($charset)) {
        preg_match( '@<\?xml.+encoding="([^\s"]+)@si', $data, $matches );
        if ( isset( $matches[1] ) )
            $charset = $matches[1];
    }

    /* 4: PHP's heuristic detection */
    if (!isset($charset)) {
        $encoding = mb_detect_encoding($data);
        if ($encoding)
            $charset = $encoding;
    }

    /* 5: Default for HTML */
    if (!isset($charset)) {
        if (strstr($content_type, "text/html") === 0)
            $charset = "ISO 8859-1";
    }

    /* Convert it if it is anything but UTF-8 */
    /* You can change "UTF-8"  to "UTF-8//IGNORE" to 
       ignore conversion errors and still output something reasonable */
    if (isset($charset) && strtoupper($charset) != "UTF-8")
        $data = iconv($charset, 'UTF-8', $data);

    return $data;
}

Regexs http://nadeausoftware.com/articles/2007/06/php_tip_how_get_web_page_content_type den çoğunlukla

Dönüştürme kolaydır. Tespit zor bir parçasıdır. Sen mb_detect_encoding deneyebilirsiniz ama bu çok zayıf bir yöntem olduğunu, bu anlamıyla içerik türünü "tahmin" ediyor gibi @ en iyi "kaba" farklılıklar (tahmin edebilirsiniz açıklamalarda vurgular troelskn bir çoklu-bayt kodlama mı ?) ancak benzer karakter setleri nüansları tespit başarısız.

Doğru yolu IMO olacaktır:

  • Sayfanın herhangi bir content-type Meta etiketleri Yorumlama
  • Sunucu tarafından gönderilen herhangi bir content-type başlıklarını Yorumlama
  • Bu hiçbir şey verirse, kodlama mb_detect_encoding kullanarak "kokla" deneyin ()
  • Bu hiçbir şey verirse, geri tanımlanmış bir varsayılan (belki ISO-8859-1, belki de UTF-8) düşer.

@ Gumbo yanıtında kurallarda belirtilen daha farklı, ben şahsen bir meta tag varsa, daha sayfanın gerçek kodlama daha güvenilir bir gösterge olduğunu eminim çünkü Meta etiketleri sunucu başlıklarına göre önceliği olması gerektiğini düşünüyorum Bazı site operatörleri koyan bir sunucu bile değiştirmek için nasıl bilmiyorum. Doğru yol, ancak daha yüksek önceliğe sahip içerik-tipi başlıkları tedavi gibi görünüyor.

Eski için, sana get_meta_tags() kullanabilirsiniz düşünüyorum. Zaten kıvrılma alma olmalıdır İkincisi, sadece bunu ayrıştırmak gerekir. Here sistematik cURL tarafından sunulan yanıt başlıklarını işlemek için nasıl tam bir örnektir.

Dönüşüm sonra kullanarak iconv olacaktır:

$new_content = iconv("incoming-charset", "utf-8", $content);

Sen gibi bir şey denemek ve kullanabilirsiniz:

http://www.php.net/manual/en/function.mb-detect-encoding.php

http://www.php.net/manual/en/function.mb-convert-encoding.php

Bu aptal kanıt olmamasına rağmen.

Tanımlanmış bir düzen vardır how to specify the character encoding in HTML:

Bir belgenin karakter kodlamasını (en yüksek öncelik en düşüğe) belirlerken [...] kullanıcı maddeleri uygun aşağıdaki öncelikleri gözlemek gerekir:

  1. "Content-Type" alanında bir HTTP "charset" parametresi.
  2. "Http-eşdeğeri" A META beyan set "Content-Type" ve "charset" için ayarlanmış bir değeri.
  3. charset özellik, harici bir kaynak ataması bir öğe ayarlanır.

Hiçbir karakter kodlaması bildirimi varsa, HTTP defines ISO 8859-1 as default character encoding. HTML için varsayılan karakter kodlaması olarak çok ya da sadece yanıtı işlemek için çöp kullanabilir ya.

XHTML için size ayrıca var XML declaration as source for the encoding:

XML belgesinde, belgenin karakter kodlamasını XML beyannamesinde belirtilir (örneğin, <?xml version="1.0" encoding="EUC-JP"?>). Amacıyla belirli karakter kodlamaları ile taşınabilirlik, mevcut belgeler, en iyi yaklaşım, web sunucusu doğru başlıklarını sağlar sağlamaktır. Bu mümkün değilse, açıkça onun karakter kodlamasını belirlemek isteyen bir belge XML bildirimi bir kodlama bildirimi ve meta http-eşdeğerli tablosunu her içermelidir (örneğin, <meta http-equiv="Content-type" content="text/html; charset=EUC-JP" />). XHTML-uyumlu kullanıcı ajanlar, XML bildiriminin kodlama bildiriminin değer önceliklidir.

Eğer hiçbir karakter kodlaması bildirimi, XML defines UTF-8 and UTF-16 as default character encoding:

Bir kodlama üst düzey protokol tarafından belirlenir olmadıkça bir XML öğesi hiçbir kodlama bildirimi içermediği halde içeriği UTF-8 veya UTF-16 değilse, aynı zamanda ölümcül bir hatadır.

Yani, özetlemek için, sırası:

  1. "Content-Type" alanında bir HTTP "charset" parametresi.
  2. encoding niteliği ile XML bildirimi.
  3. "Http-eşdeğeri" A META beyan set "Content-Type" ve "charset" için ayarlanmış bir değeri.

Hiçbir karakter kodlaması bildirimi varsa, HTML için Varsayılan kodlama olarak ISO 8859-1 varsayabiliriz ve XHTML için Varsayılan kodlama olarak UTF-8 veya UTF-16 kabul gerekir.

Ben bu cevabı bulmak için son derece mutlu olduğunu, ancak <meta> etiketi tespiti bir kusur var fark ettim. Bu sadece herhangi bir içerik türü etiketleri maç değildi ve henüz yeni HTML5 stil etiketleri için donanımlı değil: <meta charset="UTF-8">. Yani bu, bu mükemmel bir çözüm için yine çocuklar olur, ve teşekkürler umut yazdı!

/* 2: <meta> element in the page */
if (!isset($charset)) {
    preg_match('/<[\s]*meta[^>]*charset="?([^\s"]+)\s?"/i', $data, $matches);

    if (isset($matches[1])) {
        $charset = $matches[1];
    }
}

(PS I Açıkçası tam bir cevap değil gibi bir yorum olarak bu yazı nasıl çözemedim.)