#!/usr/bin/env php 0, "No FN property" => 0, "Ignored duplicates" => 0, "Merged values" => 0, "Error" => 0, "Unique cards" => 0, "Total written" => 0, ]; function writeStats() { global $stats; foreach ($stats as $name => $value) { echo str_pad($name, 23, " ", STR_PAD_RIGHT), str_pad($value, 6, " ", STR_PAD_LEFT), "\n"; } // Moving cursor back a few lines. echo "\033[" . count($stats) . "A"; } function write($vcard) { global $stats, $output; $stats["Total written"]++; fwrite($output, $vcard->serialize() . "\n"); } while ($vcard = $splitter->getNext()) { $stats["Total vcards"]++; writeStats(); $fn = isset($vcard->FN) ? (string)$vcard->FN : null; if (empty($fn)) { // Immediately write this vcard, we don't compare it. $stats["No FN property"]++; $stats['Unique cards']++; write($vcard); $vcard->destroy(); continue; } if (!isset($collectedNames[$fn])) { $collectedNames[$fn] = $vcard; $stats['Unique cards']++; continue; } else { // Starting comparison for all properties. We only check if properties // in the current vcard exactly appear in the earlier vcard as well. foreach ($vcard->children() as $newProp) { if (in_array($newProp->name, $ignoredProperties)) { // We don't care about properties such as UID and REV. continue; } $ok = false; foreach ($collectedNames[$fn]->select($newProp->name) as $compareProp) { if ($compareProp->serialize() === $newProp->serialize()) { $ok = true; break; } } if (!$ok) { if ($newProp->name === 'EMAIL' || $newProp->name === 'TEL') { // We're going to make another attempt to find this // property, this time just by value. If we find it, we // consider it a success. foreach ($collectedNames[$fn]->select($newProp->name) as $compareProp) { if ($compareProp->getValue() === $newProp->getValue()) { $ok = true; break; } } if (!$ok) { // Merging the new value in the old vcard. $collectedNames[$fn]->add(clone $newProp); $ok = true; $stats['Merged values']++; } } } if (!$ok) { // echo $newProp->serialize() . " does not appear in earlier vcard!\n"; $stats['Error']++; if ($debug) fwrite($debug, "Missing '" . $newProp->name . "' property in duplicate. Earlier vcard:\n" . $collectedNames[$fn]->serialize() . "\n\nLater:\n" . $vcard->serialize() . "\n\n"); $vcard->destroy(); continue 2; } } } $vcard->destroy(); $stats['Ignored duplicates']++; } foreach ($collectedNames as $vcard) { // Overwriting any old PRODID $vcard->PRODID = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN'; write($vcard); writeStats(); } echo str_repeat("\n", count($stats)), "\nDone.\n";