如何正确解析我的 Apple Mac 联系人 vCard?

How can I parse my Apple Mac contacts vCard correctly?

我正在使用来自 Sourceforge 的 vCard Parser https://sourceforge.net/projects/vcardphp/files/vcardphp/vcardphp-1.1.2/

我只是post这里摘录:

vcard.php

function parse(&$lines)
{
    $this->_map = null;
    $property = new VCardProperty();
    while ($property->parse($lines)) {
        if (is_null($this->_map)) {
            if ($property->name == 'BEGIN') {
                $this->_map = array();
            }
        } else {
            if ($property->name == 'END') {
                break;
            } else {
                $this->_map[$property->name][] = $property;
            }
        }
        // MDH: Create new property to prevent overwriting previous one
        // (PHP5)
        $property = new VCardProperty();
    }
    return $this->_map != null;
}



function parse(&$lines)
{
    while (list(, $line) = each($lines)) {
        $line = rtrim($line);
        $tmp = split_quoted_string(":", $line, 2);
        if (count($tmp) == 2) {
            $this->value = $tmp[1];
            $tmp = strtoupper($tmp[0]);
            $tmp = split_quoted_string(";", $tmp);
            $this->name = $tmp[0];
            $this->params = array();
            for ($i = 1; $i < count($tmp); $i++) {
                $this->_parseParam($tmp[$i]);
            }
            if ($this->params['ENCODING'][0] == 'QUOTED-PRINTABLE') {
                $this->_decodeQuotedPrintable($lines);
            }
            if ($this->params['CHARSET'][0] == 'UTF-8') {
                $this->value = utf8_decode($this->value);
            }
            return true;
        }
    }
    return false;
}

vbook.php

function parse_vcards(&$lines)
{
    $cards = array();
    $card = new VCard();
    while ($card->parse($lines)) {
        $property = $card->getProperty('N');
        if (!$property) {
            return "";
        }
        $n = $property->getComponents();
        $tmp = array();
        if ($n[3]) $tmp[] = $n[3];      // Mr.
        if ($n[1]) $tmp[] = $n[1];      // John
        if ($n[2]) $tmp[] = $n[2];      // Quinlan
        if ($n[4]) $tmp[] = $n[4];      // Esq.
        $ret = array();
        if ($n[0]) $ret[] = $n[0];
        $tmp = join(" ", $tmp);
        if ($tmp) $ret[] = $tmp;
        $key = join(", ", $ret);
        $cards[$key] = $card;
        // MDH: Create new VCard to prevent overwriting previous one (PHP5)
        $card = new VCard();
    }
    ksort($cards);
    return $cards;
}

function print_vcard($card, $hide)
{
    $names = array('N', 'FN', 'TITLE', 'TEL', 'EMAIL', 'URL', 'ADR', 'NOTE');

    $row = 0;

    foreach ($names as $name) {
        if (in_array_case($name, $hide)) {
            continue;
        }
        $properties = $card->getProperties($name);
        if ($properties) {
            foreach ($properties as $property) {
                $show = true;
                $types = $property->params['TYPE'];
                if ($types) {
                    foreach ($types as $type) {
                        if (in_array_case($type, $hide)) {
                            $show = false;
                            break;
                        }
                    }
                }
                if ($show) {
                    $class = ($row++ % 2 == 0) ? "property-even" : "property-odd";
                    print_vcard_property($property, $class, $hide);
                }
            }
        }
    }
}


function print_vcard_property($property, $class, $hide)
{
    $name = $property->name;
    $value = $property->value;

    $types = $property->params['TYPE'];
    if ($types) {
            print_r(array_filter($types));
            }
    switch ($name) {
        case 'N':
            $name = $property->getComponents();
            print_r(array_filter($name));
        break;
            case 'TEL':
            $tel = $property->getComponents();
            print_r(array_filter($tel));
        break;
        case 'FN':
            $company = $property->getComponents();
            print_r(array_filter($company));
        break;    
        case 'ADR':
            $adr = $property->getComponents();
            print_r(array_filter($adr));
            break;
        case 'EMAIL':
            $email = $property->getComponents();
            print_r(array_filter($email));
            break;
        case 'URL':
            $url = $property->getComponents();
            print_r(array_filter($url));
            break;
        default:
            $components = $property->getComponents();
            $lines = array();
            foreach ($components as $component) {
                if ($component) {
                    $lines[] = $component;
                }
            }
            $html = join("\n", $lines);
            break;
    }
    echo "<br>";
    echo "<br><br>";

}

当我使用示例 vcard 文件时效果很好,如下所示:

BEGIN:VCARD
N:Smith;Jim;Alvin;Mr.
FN:Jim A. Smith
CATEGORIES:Family
BDAY:1977-01-27
ADR;WORK:;Suite 900;11 5th Street;Coco Beach;FL;32082
ADR;HOME:;;198 Elm Street;Coco Beach;FL;32082
TEL;WORK:904-555-9384;
TEL;HOME:904-873-0394
TEL;CELL:904-934-3429
END:VCARD

但是我的 Apple Contacts vcard 看起来有点不同:

BEGIN:VCARD
N:Underwood;Frank;;;
FN:Frank Underwood
item1.EMAIL;type=INTERNET;type=pref:frank.underwood@hoc.com
item2.TEL;type=pref:+01 321 323123123
item2.X-ABLabel:Mobil
item3.ADR;type=pref:;;Richmondstreet 21;Washington D.C;;12312;
item4.URL;type=pref:http://www.frankunderwood.com/
item4.X-ABLabel:_$!<HomePage>!$_
CATEGORIES:Friends
END:VCARD

所以在我的示例中只打印了人名,而不是电子邮件、phone、地址或 url。所以在解析中我需要删除 item1、item2 等等。但是我不知道该怎么做。

以下是如何将 Apple 联系人导出到正确的 vCard 文件的解决方案,可以正确解析:

转到 Contacts/Settings/vCard 并将格式更改为 2.1 和 Unicode (UTF-8)