Changeset 6db528a
- Timestamp:
- 06/21/10 16:10:06 (2 years ago)
- Branches:
- ('master', '8434b8322dd6f8ff37c17bd45b94e7a826f86b53')('vitrine', 'afe109c61a407808bd54d88bcccb1cde726a010a')
- Children:
- f7fcb8f42bc54078fe4c73eb63af5fcf75f308cd
- Parents:
- 681f10fb3c57d071a4c02e5371cbc6136f4be4a4
- git-author:
- maparent <maparent@9a151f2f-a8df-0310-a5c5-9fb547312938>2010-06-21 20:10:06+00:00
- git-committer:
- maparent <maparent@9a151f2f-a8df-0310-a5c5-9fb547312938>2010-06-21 20:10:06+00:00
- Location:
- trunk/html
- Files:
-
- 2 edited
-
classes/VCard.php (modified) (3 diffs)
-
tests/vcardTest.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/html/classes/VCard.php
r32dece9 r6db528a 29 29 error_reporting(E_ALL); 30 30 31 /** Représente une ligne d'une VCard. 32 */ 33 34 class VCardLineInfo { 35 const line_r = '/^(\s*)(?:(?P<grp>[A-Za-z][-0-9A-Za-z]*)\.)?(?P<nm>[A-Za-z][-0-9A-Za-z]*)(?P<pa>(?:;(?:AIFF|AOL|APPLELINK|ATTMAIL|AVI|BBS|BMP|CAR|CELL|CGM|CIS|DIB|DOM|EWORLD|FAX|GIF|HOME|IBMMAIL|INTERNET|INTL|ISDN|JPEG|MCIMAIL|MET|MODEM|MPEG|MPEG2|MSG|PAGER|PARCEL|PCM|PDF|PGP|PICT|PMB|POSTAL|POWERSHARE|PREF|PRODIGY|PS|QTIME|TIFF|TLX|VIDEO|VOICE|WAVE|WMF|WORK|X400|X509|(?:[A-Za-z][-0-9A-Za-z]*=(?:"[ \t!#-\x7e\x80-\xff]*"|[ \t!#-+\.-9<-~\x80-\xff]*)(?:,(?:"[ \t!#-\x7e\x80-\xff]*"|[ \t!#-+\.-9<-~\x80-\xff]*))*)))*):(?P<va>[ \t!-~\x80-\xff]*)$/'; 36 const line_start_r = '/(\s*)(?:(?P<grp>[A-Za-z][-0-9A-Za-z]*)\.)?(?P<nm>[A-Za-z][-0-9A-Za-z]*)[:;]/'; 37 const base64_r = '|^\s*([0-9A-Za-z\+\\/\\\\]+)(={0,2})\s*$|'; 38 private static $encodings = array('B' => true, '7BIT' => true, '8BIT' => true, 39 'QUOTED-PRINTABLE' => true, 'BASE64' => true); 40 private static $name_allows_x = array('MAILER' => true, 'ADR' => true, 'TITLE' => true, 41 'SORT-STRING' => true, 'LABEL' => true, 'NOTE' => true, 42 'SOURCE' => true, 'ROLE' => true, 'FN' => true, 'ORG' => true, 43 'N' => true, 'NICKNAME' => true, 'CATEGORIES' => true); 44 private static $legal_params=array( 45 'ADR' => array('TYPE' => true,'VALUE' => true,'LANGUAGE' => true), 46 'AGENT' => array('VALUE' => true), 47 'BEGIN' => array(), 48 'BDAY' => array('VALUE' => true), 49 'CATEGORIES' => array('VALUE' => true,'LANGUAGE' => true), 50 'CLASS' => array(), 51 'EMAIL' => array('TYPE' => true), 52 'END' => array(), 53 'FN' => array('VALUE' => true,'LANGUAGE' => true), 54 'GEO' => array(), 55 'KEY' => array('TYPE' => true,'ENCODING' => true), 56 'LABEL' => array('TYPE' => true,'VALUE' => true,'LANGUAGE' => true), 57 'LOGO' => array('VALUE' => true,'ENCODING' => true,'TYPE' => true), 58 'MAILER' => array('VALUE' => true,'LANGUAGE' => true), 59 'N' => array('VALUE' => true,'LANGUAGE' => true), 60 'NAME' => array(), 61 'NICKNAME' => array('VALUE' => true,'LANGUAGE' => true), 62 'NOTE' => array('VALUE' => true,'LANGUAGE' => true), 63 'ORG' => array('VALUE' => true,'LANGUAGE' => true), 64 'PHOTO' => array('VALUE' => true,'ENCODING' => true,'TYPE' => true), 65 'PRODID' => array(), 66 'PROFILE' => array(), 67 'REV' => array('VALUE' => true), 68 'ROLE' => array('VALUE' => true,'LANGUAGE' => true), 69 'SORT-STRING' => array('VALUE' => true,'LANGUAGE' => true), 70 'SOUND' => array('VALUE' => true,'ENCODING' => true,'TYPE' => true), 71 'SOURCE' => array('VALUE' => true,'CONTEXT' => true), 72 'TEL' => array('TYPE' => true), 73 'TITLE' => array('VALUE' => true,'LANGUAGE' => true), 74 'TZ' => array(), 75 'UID' => array(), 76 'URL' => array(), 77 'VERSION' => array()); 78 private static $param_values = array( 79 'VALUE' => '/BINARY|CID|CONTENT\-ID|DATE|DATE\-TIME|INLINE|PTEXT|URI|URL|X\-[!-\+\-\/-9;<\?-Z\\^-~]+/', 80 'TYPE' => '/BBS|CAR|CELL|DOM|FAX|HOME|INTERNET|INTL|ISDN|MODEM|MSG|PAGER|PARCEL|PCS|PGP|POSTAL|PREF|VIDEO|VOICE|WORK|X509|X\-[!-\+\-\/-9;<\?-Z\\^-~]+/', 81 'ENCODING' => '/7BIT|8BIT|B|BASE64|QUOTED\-PRINTABLE|X\-[!-\+\-\/-9;<\?-Z\\^-~]+/', 82 'LANGUAGE' => '/[a-z]{2-3}(\-[A-Z]+)/', 83 'CHARSET' => '/\w+/' 84 ); 85 private static $props_structured = array( 86 'N' => array('family_name', 'first_name', 'additional_name', 'hon_prefixes', 'hon_suffixes'), 87 'ADR' => array('adr_pob', 'adr_ext', 'adr_stradr', 'adr_loc', 'adr_reg', 'adr_pc', 'adr_ctry'), 88 'GEO' => array('latitude', 'longitude'), 89 'ORG' => array() 90 ); 91 92 private $_is_valid_start = false; 93 private $_bad_end = true; 94 private $name = ''; 95 private $group = ''; 96 private $value = ''; 97 private $params = array(); 98 private $errors = array(); 99 public $rawline; 100 101 function __construct($line) { 102 $this->rawline = $line; 103 $match = array(); 104 if (0 != preg_match(self::line_start_r, $line, $match)) { 105 $name = strtoupper($match['nm']); 106 $this->_is_valid_start = array_key_exists($name, self::$legal_params) or $this->is_xname($name); 107 $this->name = $name; 108 $this->group = $match['grp']; 109 $this->tryLine(); 110 } 111 } 112 113 function splitEscapedStructure($s, $c=';') { 114 $parts = explode($c, $s); 115 $new_parts = array(); 116 $acc = ''; 117 foreach ($parts as $part) { 118 if (strlen($part) != 0 and substr($part, strlen($part)-1,1) == '\\') { 119 $acc .= $part.$c; 120 } else { 121 $new_parts[] = $acc.$part; 122 $acc = ''; 123 } 124 } 125 return $new_parts; 126 } 127 128 function is_xname($s) { 129 return strncmp(strtoupper($s), 'X-', 2) == 0; 130 } 131 132 function getEncoding() { 133 if (array_key_exists('ENCODING', $this->params)) { 134 $encoding = $this->params['ENCODING']; 135 $encoding = strtoupper($encoding[0]); 136 if ($encoding == 'BASE64') { 137 return 'B'; 138 } elseif (array_key_exists($encoding, self::$encodings)) { 139 return $encoding; 140 } 141 } 142 return null; 143 } 144 145 function checkParams($paramList) { 146 $params = array(); 147 if ('' != $paramList) { 148 $paramList = $this->splitEscapedStructure($paramList); 149 foreach ($paramList as $param) { 150 if ('' == $param) { 151 continue; 152 } 153 if (strpos($param, '=') !== false) { 154 list($key,$vals) = explode('=',$param, 2); 155 } else { # From known_types 156 $key = 'TYPE'; 157 $vals = $param; 158 } 159 $vals = $this->splitEscapedStructure($vals,','); 160 $key = strtoupper($key); 161 if (array_key_exists($key, $params)) { 162 $params[$key] = array_merge($params[$key], $vals); 163 } else { 164 $params[$key] = $vals; 165 } 166 $valid_params = array(); 167 if (array_key_exists($this->name, self::$legal_params)) { 168 $valid_params = self::$legal_params[$this->name]; 169 } 170 if (!array_key_exists($key, $valid_params)) { 171 if (!($this->is_xname($key) and ($this->is_xname($this->name) or array_key_exists($this->name, self::$name_allows_x)))) { 172 $this->errors[] = sprintf("ERROR Illegal param: %s for %s", $key, $this->name); 173 } 174 if (array_key_exists($key, self::$param_values)) { 175 foreach ($vals as $v) { 176 if (0 == preg_match(self::$param_values[$key], $v)) { 177 $this->errors[] = sprintf("ERROR Ilegal param value: %s for %s", $v, $key); 178 } 179 } 180 } 181 } 182 } 183 } 184 return $params; 185 } 186 187 function tryLine() { 188 $match = array(); 189 if (0 != preg_match(self::line_r,$this->rawline, $match)) { 190 $this->_bad_end = false; 191 $this->value = $match['va']; 192 $this->params = $this->checkParams($match['pa']); 193 } else { 194 $this->_bad_end = true; 195 # possibly: the params go beyond a simple line 196 $this->value = ''; 197 $this->params = array(); 198 } 199 } 200 201 function canAppend($line, $indented=false) { 202 if ($this->getEncoding() == 'B' and 0 != preg_match(self::base64_r, $line)) { 203 return true; 204 } 205 return $indented; 206 } 207 function append($line) { 208 if ($this->_bad_end) { 209 $this->rawline .= $line; 210 $this->tryLine(); 211 } else { 212 $this->value .= $line; 213 } 214 return true; # TODO: Do I need this? 215 } 216 function getResults(&$results, &$errors) { 217 if ($this->_bad_end or !$this->_is_valid_start) { 218 $errors[] = "ERROR Invalid line: ".$this->rawline; 219 return; 220 } 221 if ($this->getEncoding() == 'B') { 222 $value = base64_decode($this->value); 223 if ($value === FALSE) { 224 $errors[] = "ERROR Base64 error"; 225 } else { 226 $results[] = array($this->name.'_data', $this->group, $this->params, $value); 227 if ($this->name == 'logo' or $this->name == 'photo') { 228 $type = 'jpeg'; 229 if (array_key_exists('TYPE',$this->params)) { 230 $type = $this->params['TYPE']; 231 } 232 $results[] = array($this->name.'_type', $this->group, $this->params, 'image/'.$type); 233 } 234 } 235 } 236 else { 237 if ($this->getEncoding() == 'QUOTED-PRINTABLE') { 238 $this->value = quoted_printable_decode($this->value); 239 } 240 if (array_key_exists($this->name, self::$props_structured)) { 241 $parts = $this->splitEscapedStructure($this->value, ';'); 242 for ($i = 0; $i<count($parts);$i++) { 243 $parts[$i] = VCard::vcardUnescape($parts[$i]); 244 } 245 $part_names = self::$props_structured[$this->name]; 246 if (0 != count($part_names)) { 247 if (count($parts) > count($part_names)) { 248 $this->errors[] = sprintf("ERROR Too many parts in %s:%s", 249 $this->name, $this->value); 250 } 251 $num = 0; 252 $avalue = array(); 253 foreach ($part_names as $part_name) { 254 if ($num < count($parts)) { 255 $v = $parts[$num++]; 256 } else { 257 $v = ''; 258 } 259 if ($v != '') { 260 $avalue[$part_name] = $v; 261 } 262 } 263 $this->value = $avalue; 264 } else { 265 $this->value = $parts; 266 } 267 } else { 268 $this->value = VCard::vcardUnescape($this->value); 269 } 270 } 271 if ($this->name == 'VERSION' and trim($this->value) != '3.0') { 272 $errors[] = 'ERROR wrong Vcard version: '.$this->value; 273 } 274 $errors = array_merge($errors, $this->errors); 275 $results[] = array($this->name, $this->group, $this->params, $this->value); 276 } 277 function hasErrors() { 278 return $this->_bad_end or count($this->errors) > 0 or !$this->_is_valid_start; 279 } 280 function isValidStart() { 281 return $this->_is_valid_start; 282 } 283 function isBegin() { 284 return $this->name == 'BEGIN' and $this->group == null and $this->value == 'VCARD' and !$this->params; 285 } 286 function isEnd() { 287 return $this->name == 'END' and $this->group == null and $this->value == 'VCARD' and !$this->params; 288 } 289 290 function isDummy() { 291 return false; 292 } 293 } 294 295 /** Représente la ligne initiale, vide. 296 */ 297 class VCardDummyLineInfo { 298 public $rawline = ''; 299 function hasErrors() { 300 return False; 301 } 302 function getResults(&$results, &$errors) { 303 } 304 function canAppend($line, $indented=False) { 305 return False; 306 } 307 function isEnd() { 308 return False; 309 } 310 function isDummy() { 311 return True; 312 } 313 } 314 31 315 /** Représente une VCard en particulier. 32 316 */ … … 34 318 define('VCARD_NUM_PICTURE', 2); //Define the type of my picture 35 319 class VCard extends GenericDataObject { 320 private static $legal_fields = array('FN' => true, 'ORG' => true, 'TITLE' => true, 321 'ROLE' => true, 'EMAIL' => true, 'TEL' => true, 'FAX' => true, 'ADR_POB' => true, 322 'ADR_EXT' => true, 'ADR_STRADR' => true, 'ADR_LOC' => true, 'ADR_REG' => true, 323 'ADR_PC' => true, 'ADR_CTRY' => true, 'PHOTO_URL' => true, 'PHOTO_TYPE' => true, 324 'PHOTO_data' => true, 'N' => true); 36 325 private $mRow; 37 326 /** Get an instance of the object … … 1422 1711 * @param $str string containing a SINGLE vCard in vCard 3.0 format. 1423 1712 * If it contains more than one, only the first one will be imported 1713 * @return An array with two elements. First is an array of error strings. 1714 * Second is an array of supported vCard elements, each of the following form: 1715 * ($name, $group, $params, $value) 1716 * Params are an array Name=>array of values 1717 * $value may be an array in some cases (ORG, ADR, N, GEO) 1718 */ 1719 public static function full_parse($vcard) { 1720 $errors = array(); 1721 $minSpaces = 30000; 1722 $results = array(); 1723 $oldInfo = new VCardDummyLineInfo(); 1724 if (strpos($vcard, "\r") !== false) { 1725 $vcard = str_replace("\r\n" , "\n" , $vcard); 1726 $vcard = str_replace("\r" , "\n" , $vcard); 1727 } 1728 $lineNum = 0; 1729 foreach (explode("\n",$vcard) as $l) { 1730 $info = new VCardLineInfo($l); 1731 $numSpaces = strlen($l) - strlen(ltrim($l)); 1732 if ($lineNum > 0) { 1733 $minSpaces = min($minSpaces, $numSpaces); 1734 } 1735 if (!$info->hasErrors()) { 1736 if ($lineNum == 0 and !$info->isBegin()) { 1737 $errors[] = "ERROR Does not start with begin: ".$l; 1738 } 1739 $oldInfo->getResults($results, $errors); 1740 $oldInfo = $info; 1741 } elseif ($oldInfo->canAppend($l, $numSpaces > $minSpaces)) { 1742 $oldInfo->append(substr($l,$minSpaces+1)); 1743 } elseif ($info->isValidStart()) { 1744 $oldInfo->getResults($results, $errors); 1745 $oldInfo = $info; 1746 } elseif ($oldInfo->canAppend($l, True)) { 1747 if (strlen($l) > 0) { 1748 $errors[]="WARNING Not indented: ".$l; 1749 if ($minSpaces < strlen($l) and false === strpos(" \t", substr($l,$minSpaces,1))) { 1750 $l = ' '.$l; 1751 } 1752 $oldInfo->append(substr($l, $minSpaces)); 1753 } 1754 } else { 1755 $oldInfo->getResults($results, $errors); 1756 $oldInfo = $info; 1757 } 1758 $lineNum++; 1759 } 1760 $oldInfo->getResults($results, $errors); 1761 if (count($results) == 0) { 1762 $errors[] = "ERROR Empty VCARD"; 1763 } 1764 elseif (!$oldInfo->isEnd()) { 1765 $errors[]="ERROR Does not end with END: ".$oldInfo->rawline; 1766 } 1767 return array($errors, $results); 1768 } 1769 1770 /** Parses a vCard into a tokenised array 1771 * @param $str string containing a SINGLE vCard in vCard 3.0 format. 1772 * If it contains more than one, only the first one will be imported 1424 1773 * @return An array of supported vCard elements, or an empty array if something 1425 1774 * went wrong 1426 1775 */ 1427 public static function parse($str) { 1776 public static function parse($vcard) { 1777 list($errors, $full_results) = self::full_parse($vcard); 1778 // errors are discarded. 1779 $results = array(); 1780 foreach ($full_results as $r) { 1781 list($name, $group, $params, $value) = $r; 1782 if (!array_key_exists($name, self::$legal_fields)) { 1783 continue; 1784 } 1785 if ($name == 'TEL') { 1786 if (array_search('WORK',$params['TYPE']) != FALSE) { 1787 if (array_search('FAX',$params['TYPE']) != FALSE) { 1788 $results['fax'] = $value; 1789 } elseif (array_search('VOICE',$this->params['TYPE']) != FALSE) { 1790 $results['tel'] = $value; 1791 } 1792 } 1793 // suppress non-work phone? Seems so. 1794 continue; 1795 } elseif ($name == 'ORG') { 1796 $value = implode(';',$value); 1797 } elseif (is_array($value)) { 1798 foreach ($value as $k=>$v) { 1799 $results[strtolower($k)] = $v; 1800 } 1801 } 1802 if ($group != '') { 1803 $name = $group . '.' . $name; 1804 } 1805 $results[strtolower($name)] = $value; 1806 } 1807 return $results; 1808 } 1809 1810 /** Parses a vCard into a tokenised array 1811 * @param $str string containing a SINGLE vCard in vCard 3.0 format. 1812 * If it contains more than one, only the first one will be imported 1813 * @return An array of supported vCard elements, or an empty array if something 1814 * went wrong 1815 */ 1816 public static function old_parse($str) { 1428 1817 $vcard_elements = array (); 1429 1818 //echo "VCard::parse(): vCard raw data:<br><pre>"; print_r($str); echo "</pre>"; -
trunk/html/tests/vcardTest.php
rf90da8f r6db528a 38 38 } 39 39 40 private static function extractField($vcard, $name, $group=null) { 41 foreach ($vcard as $line) { 42 list($lname, $lgroup, $param, $value) = $line; 43 if ($name == $lname and $group == $lgroup) { 44 return array($param, $value); 45 } 46 } 47 return null; 48 } 49 50 const simple_card = 'BEGIN:VCARD 51 VERSION:3.0 52 FN:Marc-Antoine Parent 53 N:PARENT;Marc-Antoine 54 TEL;TYPE=WORK,PREF:(123) 456-7890 55 ADR;TYPE=WORK:;;1234 rue Marue;Maville;Maprovince;;Lhiver 56 EMAIL;TYPE=INTERNET:maparent@exemple.com 57 END:VCARD'; 58 59 public function testFindFN() { 60 list($errors, $res) = VCard::full_parse(self::simple_card); 61 $this->assertEquals(count($errors),0); 62 $field = self::extractField($res, 'FN'); 63 $this->assertEquals($field[1], 'Marc-Antoine Parent'); 64 } 65 66 const comma_param_card = 'BEGIN:VCARD 67 VERSION:3.0 68 FN:Marc-Antoine Parent 69 N:PARENT;Marc-Antoine 70 TEL;TYPE=WORK,PREF:(123) 456-7890 71 ADR;TYPE=WORK:;;1234 rue Marue;Maville;Maprovince;;Lhiver 72 EMAIL;TYPE=INTERNET,pref:maparent@exemple.com 73 END:VCARD'; 74 75 public function testCommaParam() { 76 list($errors, $res) = VCard::full_parse(self::comma_param_card); 77 $this->assertEquals(count($errors),0); 78 $field = self::extractField($res, 'EMAIL'); 79 $this->assertEquals($field[0]['TYPE'], array('INTERNET', 'pref')); 80 } 81 82 const repeat_param_card = 'BEGIN:VCARD 83 VERSION:3.0 84 FN:Marc-Antoine Parent 85 N:PARENT;Marc-Antoine 86 TEL;TYPE=WORK,PREF:(123) 456-7890 87 ADR;TYPE=WORK:;;1234 rue Marue;Maville;Maprovince;;Lhiver 88 EMAIL;TYPE=INTERNET;TYPE=pref:maparent@exemple.com 89 END:VCARD'; 90 91 public function testRepeatParam() { 92 list($errors, $res) = VCard::full_parse(self::repeat_param_card); 93 $this->assertEquals(count($errors),0); 94 $field = self::extractField($res, 'EMAIL'); 95 $this->assertEquals($field[0]['TYPE'], array('INTERNET', 'pref')); 96 } 97 98 const continuation_card = 'BEGIN:VCARD 99 VERSION:3.0 100 FN:Marc-Antoine Parent 101 N:PARENT;Marc-Antoine 102 TEL;TYPE=WORK,PREF:(123) 456-7890 103 ADR;TYPE=WORK:;;1234 rue Marue; 104 Maville;Maprovince;;Lhiver 105 EMAIL;TYPE=INTERNET:maparent@exemple.com 106 END:VCARD'; 107 108 public function testContinuation() { 109 list($errors, $res) = VCard::full_parse(self::continuation_card); 110 $this->assertEquals(count($errors),0); 111 $field = self::extractField($res, 'ADR'); 112 $this->assertEquals($field[1]['adr_stradr'], '1234 rue Marue'); 113 } 114 115 const unindented_continuation_card = 'BEGIN:VCARD 116 VERSION:3.0 117 FN:Marc-Antoine Parent 118 N:PARENT;Marc-Antoine 119 TEL;TYPE=WORK,PREF:(123) 456-7890 120 ADR;TYPE=WORK:;;1234 rue Marue; 121 Maville;Maprovince;;Lhiver 122 EMAIL;TYPE=INTERNET:maparent@exemple.com 123 END:VCARD'; 124 125 const globally_indented_card = 'BEGIN:VCARD 126 VERSION:3.0 127 FN:Marc-Antoine Parent 128 N:PARENT;Marc-Antoine 129 TEL;TYPE=WORK,PREF:(123) 456-7890 130 ADR;TYPE=WORK:;;1234 rue Marue; 131 Maville;Maprovince;;Lhiver 132 EMAIL;TYPE=INTERNET:maparent@exemple.com 133 END:VCARD'; 134 135 const globally_indented_with_reindented_continuation_card = 'BEGIN:VCARD 136 VERSION:3.0 137 FN:Marc-Antoine Parent 138 N:PARENT;Marc-Antoine 139 TEL;TYPE=WORK,PREF:(123) 456-7890 140 ADR;TYPE=WORK:;;1234 rue Marue; 141 Maville;Maprovince;;Lhiver 142 EMAIL;TYPE=INTERNET:maparent@exemple.com 143 END:VCARD'; 144 145 146 public function testUnindentedContinuation() { 147 list($errors, $res) = VCard::full_parse(self::unindented_continuation_card); 148 # there should be a WARNING 149 $this->assertEquals(count($errors), 1); 150 $this->assertSame(strpos($errors[0],'WARNING'), 0); 151 $field = self::extractField($res, 'ADR'); 152 $this->assertEquals($field[1]['adr_stradr'], '1234 rue Marue'); 153 } 154 155 public function testGloballyIndented() { 156 list($errors, $res) = VCard::full_parse(self::globally_indented_card); 157 $this->assertEquals(count($errors), 1); 158 $this->assertSame(strpos($errors[0],'WARNING'), 0); 159 $field = self::extractField($res, 'ADR'); 160 $this->assertEquals($field[1]['adr_stradr'], '1234 rue Marue'); 161 } 162 163 public function testGloballyIndentedWithReindentedContinuation() { 164 list($errors, $res) = VCard::full_parse(self::globally_indented_with_reindented_continuation_card); 165 $this->assertEquals(count($errors),0); 166 $field = self::extractField($res, 'ADR'); 167 $this->assertEquals($field[1]['adr_stradr'], '1234 rue Marue'); 168 } 169 170 const invalid_line_card = 'BEGIN:VCARD 171 VERSION:3.0 172 FN:Marc-Antoine Parent 173 N:PARENT;Marc-Antoine 174 TEL;TYPE=WORK,PREF:(123) 456-7890 175 ADR;TYPE=WORK:;;1234 rue Marue;Maville;Maprovince;;Lhiver 176 PHOTO;VALUE= 177 EMAIL;TYPE=INTERNET:maparent@exemple.com 178 END:VCARD'; 179 180 public function testInvalidLine() { 181 list($errors, $res) = VCard::full_parse(self::invalid_line_card); 182 # there should be a WARNING 183 $this->assertEquals(count($errors), 1); 184 $this->assertSame(strpos($errors[0],'ERROR Invalid line'), 0); 185 $field = self::extractField($res, 'ADR'); 186 $this->assertEquals($field[1]['adr_stradr'], '1234 rue Marue'); 187 } 188 189 const rapport_nc_1_card = 'BEGIN:VCARD 190 VERSION:3.0 191 FN:Bruno BASTARD 192 N:BASTARD;Bruno 193 PHOTO;VALUE= 194 TEL;TYPE=WORK,PREF:NR 195 ADR;TYPE=WORK:;Université de Toulouse-Le Mirail 196 Centre Audiovisuel et multimédia 197 5 allées Antonio Machado 198 31058 Toulouse Cedex 01;toulouse;;31000;FR 199 EMAIL;TYPE=INTERNET:NR 200 ROLE:content provider 201 ORG:NR; 202 URL:NR 203 END:VCARD'; 204 205 public function testRapportNC1() { 206 list($errors, $res) = VCard::full_parse(self::rapport_nc_1_card); 207 $field = self::extractField($res, 'ADR'); 208 $indent_warning = 0; 209 $invalid_error = 0; 210 $other = 0; 211 foreach ($errors as $error) { 212 if (strpos($error,'ERROR Invalid line') === 0) { 213 $invalid_error++; 214 } elseif (strpos($error,'WARNING Not indented') === 0) { 215 $indent_warning++; 216 } else { 217 $other++; 218 } 219 } 220 $this->assertEquals($invalid_error, 1); 221 $this->assertEquals($indent_warning, 3); 222 $this->assertEquals($other, 0); 223 $this->assertEquals($field[1]['adr_ext'], 'Université de Toulouse-Le Mirail Centre Audiovisuel et multimédia 5 allées Antonio Machado 31058 Toulouse Cedex 01'); 224 } 225 226 const rapport_nc_2_card = 'BEGIN:VCARD 227 VERSION:3.0 228 ORG:MinistÚre de l\'Ãducation nationale, de l\'Enseignement 229 supérieur et de la Recherche 230 END:VCARD'; 231 232 public function testRapportNC2() { 233 list($errors, $res) = VCard::full_parse(self::rapport_nc_2_card); 234 $field = self::extractField($res, 'ORG'); 235 $this->assertEquals($field[1], array('MinistÚre de l\'Ãducation nationale, de l\'Enseignement supérieur et de la Recherche')); 236 $this->assertEquals(count($errors),1); 237 $this->assertSame(strpos($errors[0],'WARNING'), 0); 238 } 239 240 public function testUnnamedParam() { 241 list($errors, $res) = VCard::full_parse('BEGIN:VCARD 242 FN:Susan Thomas 243 TEL:+1-919-555-1234 244 EMAIL;INTERNET:sthomas@host.com 245 END:VCARD'); 246 $this->assertEquals(count($errors),0); 40 247 } 248 249 const agent_card = 'BEGIN:VCARD 250 VERSION:3.0 251 FN:Bruno BASTARD 252 N:BASTARD;Bruno 253 AGENT:BEGIN:VCARD\\nFN:Susan Thomas\\nTEL:+1-919-555- 254 1234\\nEMAIL\\;TYPE=INTERNET:sthomas@host.com\\nEND:VCARD\\n 255 END:VCARD'; 256 257 public function testAgent() { 258 list($errors, $res) = VCard::full_parse(self::agent_card); 259 $this->assertEquals(count($errors),0); 260 $agent = self::extractField($res, 'AGENT'); 261 $agent = $agent[1]; 262 $this->assertEquals($agent, 263 "BEGIN:VCARD\nFN:Susan Thomas\nTEL:+1-919-555-1234\nEMAIL;TYPE=INTERNET:sthomas@host.com\nEND:VCARD\n"); 264 265 $agent = str_replace(array('\\;','\\n'),array(';',"\n"),$agent); 266 list($errors, $res) = VCard::full_parse($agent); 267 $field = self::extractField($res, 'TEL'); 268 $this->assertEquals($field[1],'+1-919-555-1234'); 269 $this->assertEquals(count($errors),0); 270 } 271 272 273 ##Cas horrible: Les paramÚtres débordent sur la ligne suivante 274 275 const param_continuation_card = 'BEGIN:VCARD 276 VERSION:3.0 277 FN:Marc-Antoine Parent 278 N:PARENT;Marc-Antoine 279 TEL;TYPE=HOME,WORK,PREF,VOICE,FAX,MSG,CELL,PAGER,BBS,MODEM, 280 CAR,ISDN,VIDEO,PCS:(123) 456-7890 281 END:VCARD'; 282 283 public function testParamContinuation() { 284 list($errors, $res) = VCard::full_parse(self::param_continuation_card); 285 $this->assertEquals(count($errors),0); 286 $field = self::extractField($res, 'TEL'); 287 $this->assertEquals(count($field[0]['TYPE']), 14); 288 } 289 290 # Autre cas: paramÚtres ou autres contenant des séparateurs escapés 291 const escaped_comma_card = 'BEGIN:VCARD 292 VERSION:3.0 293 FN:Marc-Antoine Parent 294 N:PARENT;Marc-Antoine 295 TEL;TYPE=HOME,X-COMMA\,VALUE:(123) 456-7890 296 END:VCARD'; 297 # Echec pcq les paramÚtres n'ont pas droit aux séparateurs 298 299 const escaped_structured_value_card = 'BEGIN:VCARD 300 VERSION:3.0 301 FN:Marc-Antoine Parent 302 N:PARENT;Marc-Antoine 303 ADR;TYPE=WORK:;;1234 rue Marue\\;bureau 100;Maville;Maprovince;;Lhiver 304 END:VCARD'; 305 public function testEscapedStructured() { 306 list($errors, $res) = VCard::full_parse(self::escaped_structured_value_card); 307 $this->assertEquals(count($errors),0); 308 $field = self::extractField($res, 'ADR'); 309 $this->assertEquals($field[1]['adr_stradr'], '1234 rue Marue;bureau 100'); 310 } 311 }
Note: See TracChangeset
for help on using the changeset viewer.
