Git Product home page Git Product logo

vcard-parser's People

Contributors

pilsetnieks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vcard-parser's Issues

Case problem with begin and end tags

If the vcf file contains
begin:vcard
end:vcard

(e.g as exported by Thunderbird) instead of

BEGIN:VCARD
END:VCARD

it fails because it tries to split the file using:
$this -> RawData = explode( 'BEGIN:VCARD', $this -> RawData);

This can be fixed by changing line 132 of vcard.php to
$this -> RawData = preg_split('{^BEGIN:VCARD}miS', $this -> RawData);

Howto create new entry with type and sub element (eg: adr)

Hi,

I am able to create simple entry with type HOME for example:
$vCard -> tel('555-1111', 'Home');
$vCard -> tel('555-1234', 'Work');

But how to do the same for ADR. with type and subvalue like StreetAddress
I am unable to figure it out.
Shold not be like this:
$vCard -> adr('My Country', 'Work', 'StreetAddress');
$vCard -> adr('My Country', 'StreetAddress', 'Work' );

I try to pass it as an array but no luck
$vCard -> adr('My Country', array('StreetAddress', 'Work') );

Any ideas?

PHP Warning: preg_match_all()

Hi,

On lines 92 and 93 it generate PHP warning.
$vCardBeginCount = preg_match_all('{^BEGIN:VCARD}miS', $this -> RawData);
$vCardEndCount = preg_match_all('{^END:VCARD}miS', $this -> RawData);

PHP Warning: preg_match_all() expects at least 3 parameters, 2 given in vCard.php on line 92
PHP Warning: preg_match_all() expects at least 3 parameters, 2 given in vCard.php on line 93

Empty vcard show as valid

Empty vcard are count as valid even so there is no value.
Here are 2 samples:

BEGIN:VCARD
UID:4165-4FBBCC00-33-9470200.vcf
VERSION:3.0
CLASS:PUBLIC
PROFILE:VCARD
END:VCARD

Or

BEGIN:VCARD
VERSION:3.0
PRODID:-//Apple Inc.//Address Book 6.1.2//EN
UID:bb332361-6c7e-4782-babd-d7d5a5f158f4
END:VCARD

The count check should return something different than the NB card as there is no value.

Addresses from Apple Addressbook cannot be parsed

I try to parse vcards from Apple Addressbook, but

foreach ($vCard -> ADR as $Address) {
// do something
}

doesn't work, cause Apples vcards looks like:

item1.ADR;type=HOME:;;Street;Foo;;00000;Bar
item2.ADR;type=HOME:;;Street;Foo;;00000;Bar

Any suggestions? :)

Apple vCards provide no CATEGORIES

I've grouped my iCloud contacts into groups and would have expected them as CATEGORIES. A search has shown that Apple keeps the groups in

  • separate vCards (X-ADDRESSBOOKSERVER-KIND:group) with
  • keeping the group name: in 'N:' and
  • lists therein the assigned contacts (X-ADDRESSBOOKSERVER-MEMBER:).

See example:

BEGIN:VCARD
VERSION:3.0
X-ADDRESSBOOKSERVER-KIND:group
PRODID:-//Apple Inc.//iOS 9.3.5//EN
N:PERS
FN:PERS
UID:6284484E-A4E4-42EF-8CFB-301C0DE2B2D7
X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:8C5292AA-F2D8-41DB-A5B6-582C39AD9BF3
X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:35185E23-D65D-46CA-9638-8DB5117740B9

...

X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:EDA333D2-2300-43A5-AFE9-045A8A5D6FF1
X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:2A009E2D-5A49-4550-B64A-E4CE40611DEB
X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:44287153-AE5A-4131-BBFF-D20E8F3A0ECD
END:VCARD

It would be extremely helpful if these groups were assigned as CATEGORIES to the respective contacts.

Wrong parsing of "adr" field

TYPE=WORK:;extended;street 1;city;state;zip;country

is parsed to

Array (
[POBox] =>
[ExtendedAddress] => extended
[StreetAddress] => street
[Locality] => 1
[Region] => city
[PostalCode] => state
[Country] =>zip
[Type] => Array ( [0] => work )
)

If parsed without extended everything is in place.
But when extended is given the street is split and the house-number is set as locality.

problematic vcard from Apple Addressbook

When using the parser some field disapear more likely the 'itemX' and 'X-'.
Where the 'X-' does not have too much value the 'itemX' does have a usefull value.

BEGIN:VCARD
VERSION:3.0
PRODID:-//Apple Inc.//Address Book 6.1.2//EN
N:von Besser;Hans;;Dr.;
FN:Eppendorf Vertrieb Deutschland GmbH
ORG:Eppendorf Vertrieb Deutschland GmbH;Vertriebsspezialist Systeme
EMAIL;type=INTERNET;type=WORK;type=pref:[email protected]
TEL;type=WORK;type=VOICE;type=pref:+49 931 28 67 51
TEL;type=CELL;type=VOICE:+49 171 230 05 95
item1.ADR;type=WORK;type=pref:;;Büro Würzburg\nOberer Kühlenberg 14;Würzburg;;97078;Germany
item1.X-ABADR:de
item2.URL;type=pref:www.eppendorf.de
item2.X-ABLabel:$!!$
X-ABShowAs:COMPANY
CATEGORIES:Personal Address Book
UID:bb332361-6c7e-4782-babd-d7d5a5f158f4
X-ABUID:75F1F559-5C43-4763-8BDE-E02A9FB9F937:ABPerson
END:VCARD

Difference between 2.1 and 3.0 versions

Small bug:
While parsing

    $vcard -> url 

it returns an array like

Array(
 '0' => Array(
                '0' => URL  
          )
);

if it is vcard of 2.1 version

and if it is 3.0 it gives a different result, such as

 '0' => Array(
                'Value' => URL  
          )
);

vCard.php Parse Error

Parse error: syntax error, unexpected T_FUNCTION, expecting ')' in include/vCard.php on line 552
The line is missing the closing ')'

$Parameters = array_map(function($Item))

PHP Parse error

PHP Parse error: syntax error, unexpected T_VARIABLE in vCard.php on line 209

  •                                           $ItemIndex = (int)str_ireplace('item', '' $TmpKey[0]);
    
  •                                           $ItemIndex = (int)str_ireplace('item', '', $TmpKey[0]);
    

E-mail is not parsed from vCard

Original issue from CardDAV project, which used your parser.


VERSION:3.0
NICKNAME:alu
EMAIL;TYPE=INTERNET;TYPE=HOME;TYPE=PREF:[email protected]
X-AFTERLOGIC-USE-FRIENDLY-NAME:1
FN:abu
PRODID:-//Afterlogic//6.5.x//EN
UID:b6a17e3a-3b0a-4f8e-9c4d-cec6d570097f
N:apu;asu;;;;
END:VCARD
])
01/11/2012 15:26:20 [ 3524] [DEBUG] [[email protected]] [android1334515447810] BackendCardDAV->_ParseVCardToAS(vCard fileas [abu])
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O      <Add>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O       <ServerEntryId>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O       b6a17e3a-3b0a-4f8e-9c4d-cec6d570097f
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O       </ServerEntryId>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O       <Data>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        <POOMCONTACTS:FileAs>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        abu
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        </POOMCONTACTS:FileAs>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        <POOMCONTACTS:FirstName>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        asu
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        </POOMCONTACTS:FirstName>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        <POOMCONTACTS:LastName>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        apu
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        </POOMCONTACTS:LastName>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        <POOMCONTACTS2:NickName>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        alu
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O        </POOMCONTACTS2:NickName>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O       </Data>
01/11/2012 15:26:20 [ 3524] [WBXML] [[email protected]] [android1334515447810] O      </Add>

X-Attributes in Apple Addressbook photos

When you crop the photo of an entry in the Apple Addressbook,
it looks like
PHOTO;X-ABCROP-RECTANGLE=ABClipRect_1&-9&20&283&283&WGHe9zKmBvRvhyIyYvN/1g=
=;ENCODING=b;TYPE=JPEG:/9j/4AAQSkZJRgABAQAAAQABAAD/4gQUSUNDX1BST0ZJTEUAAQE
AAAQEYXBwbAIAAABtbnRyUkdCIFhZWiAH2QADAA0AFQAWACNhY3NwQVBQTAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGzV7zp1myHv5rYyPVUXGqoJAAAAAAAAAAAAAAA

which becomes:
array(4) {
[0]=>
string(5) "photo"
[1]=>
string(70) "x-abcrop-rectangle=abcliprect_1&-9&20&283&283&wghe9zkmbvrvhyiyyvn/1g ="
[2]=>
string(10) "encoding=b"
[3]=>
string(9) "type=jpeg"
}

This yields to an endless recursion of self::ParseParameters

Therefore I added this lines:
if ($Key=='photo'){
if ($RawParams!=null){
$RawParams = array_filter($RawParams,create_function('$k','return (substr(trim($k),0,3)=="enc" || substr(trim($k),0,4)=="type");'));
}
}

Now only encoding and type are permitted for photos.

Patch with comments and proposed changes

I have been testing this parser library, intending to use it in a project, and have noted some opportunities for changes. They take the following forms:

  1. Improvements to support for v2.1 format (while the library targets 3.0 some support exists for 2.1 so it makes sense to improve it)
  2. An addition to support non-standard parameters which may be found "in the wild"
  3. Comments on possible weaknesses in the current code

My changes are as follows, in patch form:

@@ -50,11 +50,13 @@

        private static $Spec_ElementTypes = array(
            'email' => array('internet', 'x400', 'pref'),
            'adr' => array('dom', 'intl', 'postal', 'parcel', 'home', 'work', 'pref'),
            'label' => array('dom', 'intl', 'postal', 'parcel', 'home', 'work', 'pref'),
-           'tel' => array('home', 'msg', 'work', 'pref', 'voice', 'fax', 'cell', 'video', 'pager', 'bbs', 'modem', 'car', 'isdn', 'pcs')
+           'tel' => array('home', 'msg', 'work', 'pref', 'voice', 'fax', 'cell', 'video', 'pager', 'bbs', 'modem', 'car', 'isdn', 'pcs'),
+           'url' => array('work', 'home'), // not per RFC but may be present in practice
+           'impp' => array('personal','business','home','work','mobile','pref') // http://tools.ietf.org/html/rfc4770
        );

        private static $Spec_FileElements = array('photo', 'logo', 'sound');

        /**
@@ -138,16 +140,23 @@
                    $this -> Data[] = new vCard(false, $SinglevCardRawData);
                }
            }
            else
            {
+               // Protect the BASE64 final = sign (detected by the line beginning with whitespace), otherwise the next replace will get rid of it
+               $this -> RawData = preg_replace('/(\n\s.+)=(\n)/', '$1-base64=-$2', $this -> RawData);
+
                // Joining multiple lines that are split with a hard wrap and indicated by an equals sign at the end of line
+               // i.e. quoted-printable-encoded values in v2.1 vCards
                $this -> RawData = str_replace("=\n", '', $this -> RawData);

                // Joining multiple lines that are split with a soft wrap (space or tab on the beginning of the next line
                $this -> RawData = str_replace(array("\n ", "\n\t"), '-wrap-', $this -> RawData);

+               // Restore the BASE64 =
+               $this -> RawData = str_replace("-base64=-\n", "=\n", $this -> RawData);
+
                $Lines = explode("\n", $this -> RawData);

                foreach ($Lines as $Line)
                {
                    // Lines without colons are skipped because, most likely, they contain no data.
@@ -160,10 +169,11 @@
                    //  value is just the value
                    list($Key, $Value) = explode(':', $Line, 2);

                    // Key is transformed to lowercase because, even though the element and parameter names are written in uppercase,
                    //  it is quite possible that they will be in lower- or mixed case.
+                   // The key is trimmed to allow for non-significant WSP characters as allowed by v2.1
                    $Key = strtolower(trim(self::Unescape($Key)));

                    // These two lines can be skipped as they aren't necessary at all.
                    if ($Key == 'begin' || $Key == 'end')
                    {
@@ -183,10 +193,13 @@
                    else
                    {
                        $Value = str_replace('-wrap-', '', $Value);
                    }

+                   // The value is trimmed to allow for non-significant WSP characters as allowed by v2.1
+                   // (This might remove white space which a v3.0 parser is meant to retain)
+                   // WARNING! unescaping ; characters at this point causes the ParseStructuredValue later to parse the values wrongly!
                    $Value = trim(self::Unescape($Value));
                    $Type = array();

                    // Here additional parameters are parsed
                    $KeyParts = explode(';', $Key);
@@ -201,20 +214,22 @@
                        {
                            switch ($ParamKey)
                            {
                                case 'encoding':
                                    $Encoding = $ParamValue;
-                                   if ($ParamValue == 'b')
+                                   // Allow for both v3.0 B and v2.1 BASE64 encoding parameter values
+                                   //if ($ParamValue == 'b')
+                                   if (in_array($ParamValue, array('b', 'base64')))
                                    {
                                        //$Value = base64_decode($Value);
                                    }
-                                   elseif ($ParamValue == 'quoted-printable')
+                                   elseif ($ParamValue == 'quoted-printable') // v2.1
                                    {
                                        $Value = quoted_printable_decode($Value);
                                    }
                                    break;
-                               case 'charset':
+                               case 'charset': // v2.1
                                    if ($ParamValue != 'utf-8' && $ParamValue != 'utf8')
                                    {
                                        $Value = mb_convert_encoding($Value, 'UTF-8', $ParamValue);
                                    }
                                    break;
@@ -336,11 +351,13 @@
            }

            if (is_writable($TargetPath) || (!file_exists($TargetPath) && is_writable(dirname($TargetPath))))
            {
                $RawContent = $this -> Data[$Key][$Index]['Value'];
-               if (isset($this -> Data[$Key][$Index]['Encoding']) && $this -> Data[$Key][$Index]['Encoding'] == 'b')
+               // Allow for both v3.0 B and v2.1 BASE64 encoding parameter values
+               //if (isset($this -> Data[$Key][$Index]['Encoding']) && $this -> Data[$Key][$Index]['Encoding'] == 'b')
+               if (isset($this -> Data[$Key][$Index]['Encoding']) && (in_array($this -> Data[$Key][$Index]['Encoding'], array('b', 'base64'))) )
                {
                    $RawContent = base64_decode($RawContent);
                }
                $Status = file_put_contents($TargetPath, $RawContent);
                return (bool)$Status;
@@ -493,10 +510,12 @@
         * @return string Resulting text.
         */
        private static function Unescape($Text)
        {
            return str_replace(array('\:', '\;', '\,', "\n"), array(':', ';', ',', ''), $Text);
+           // The line above removes encoded newlines ("\n") rather than converting them back to CRLF character sequences!
+           // "\N" should be treated in the same way as "\n"
        }

        /**
         * Separates the various parts of a structured value according to the spec.
         *
@@ -582,11 +601,13 @@
                else
                {
                    switch ($Parameter[0])
                    {
                        case 'encoding':
-                           if (in_array($Parameter[1], array('quoted-printable', 'b')))
+                           // Allow for both v3.0 B and v2.1 BASE64 encoding parameter values
+                           //if (in_array($Parameter[1], array('quoted-printable', 'b')))
+                           if (in_array($Parameter[1], array('quoted-printable', 'b', 'base64')))
                            {
                                $Result['encoding'] = $Parameter[1];
                            }
                            break;
                        case 'charset':

Does not parse Apples vCard very well

This is the output from Apples vCard, I believe it's because of using items.

Array
(
    [0] => Array
        (
            [LastName] => 
            [FirstName] => 
            [AdditionalNames] => 
            [Prefixes] => 
            [Suffixes] => 
        )

)
Array
(
    [0] => Array
        (
            [Value] => 1-800-MY-APPLE
            [Type] => Array
                (
                    [0] => main
                    [1] => pref
                )

        )

)

For example, it uses item1.ADR instead of just ADR

 item1.ADR;type=WORK;type=pref:;;1 Infinite Loop;Cupertino;CA;95014;United States
 item1.X-ABADR:us

However, we don't even get the address out of it.

This pastebin contains the contents of the card: http://pastebin.com/mdsHFVv6

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.