如何正确解析我的 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)
我正在使用来自 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)