1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\VObject; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse 6*a1a3b679SAndreas Boehler ArrayObject; 7*a1a3b679SAndreas Boehler 8*a1a3b679SAndreas Boehler/** 9*a1a3b679SAndreas Boehler * VObject Parameter 10*a1a3b679SAndreas Boehler * 11*a1a3b679SAndreas Boehler * This class represents a parameter. A parameter is always tied to a property. 12*a1a3b679SAndreas Boehler * In the case of: 13*a1a3b679SAndreas Boehler * DTSTART;VALUE=DATE:20101108 14*a1a3b679SAndreas Boehler * VALUE=DATE would be the parameter name and value. 15*a1a3b679SAndreas Boehler * 16*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/). 17*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 18*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 19*a1a3b679SAndreas Boehler */ 20*a1a3b679SAndreas Boehlerclass Parameter extends Node { 21*a1a3b679SAndreas Boehler 22*a1a3b679SAndreas Boehler /** 23*a1a3b679SAndreas Boehler * Parameter name 24*a1a3b679SAndreas Boehler * 25*a1a3b679SAndreas Boehler * @var string 26*a1a3b679SAndreas Boehler */ 27*a1a3b679SAndreas Boehler public $name; 28*a1a3b679SAndreas Boehler 29*a1a3b679SAndreas Boehler /** 30*a1a3b679SAndreas Boehler * vCard 2.1 allows parameters to be encoded without a name. 31*a1a3b679SAndreas Boehler * 32*a1a3b679SAndreas Boehler * We can deduce the parameter name based on it's value. 33*a1a3b679SAndreas Boehler * 34*a1a3b679SAndreas Boehler * @var bool 35*a1a3b679SAndreas Boehler */ 36*a1a3b679SAndreas Boehler public $noName = false; 37*a1a3b679SAndreas Boehler 38*a1a3b679SAndreas Boehler /** 39*a1a3b679SAndreas Boehler * Parameter value 40*a1a3b679SAndreas Boehler * 41*a1a3b679SAndreas Boehler * @var string 42*a1a3b679SAndreas Boehler */ 43*a1a3b679SAndreas Boehler protected $value; 44*a1a3b679SAndreas Boehler 45*a1a3b679SAndreas Boehler /** 46*a1a3b679SAndreas Boehler * Sets up the object. 47*a1a3b679SAndreas Boehler * 48*a1a3b679SAndreas Boehler * It's recommended to use the create:: factory method instead. 49*a1a3b679SAndreas Boehler * 50*a1a3b679SAndreas Boehler * @param string $name 51*a1a3b679SAndreas Boehler * @param string $value 52*a1a3b679SAndreas Boehler */ 53*a1a3b679SAndreas Boehler public function __construct(Document $root, $name, $value = null) { 54*a1a3b679SAndreas Boehler 55*a1a3b679SAndreas Boehler $this->name = strtoupper($name); 56*a1a3b679SAndreas Boehler $this->root = $root; 57*a1a3b679SAndreas Boehler if (is_null($name)) { 58*a1a3b679SAndreas Boehler $this->noName = true; 59*a1a3b679SAndreas Boehler $this->name = static::guessParameterNameByValue($value); 60*a1a3b679SAndreas Boehler } 61*a1a3b679SAndreas Boehler 62*a1a3b679SAndreas Boehler // If guessParameterNameByValue() returns an empty string 63*a1a3b679SAndreas Boehler // above, we're actually dealing with a parameter that has no value. 64*a1a3b679SAndreas Boehler // In that case we have to move the value to the name. 65*a1a3b679SAndreas Boehler if ($this->name === '') { 66*a1a3b679SAndreas Boehler $this->noName = false; 67*a1a3b679SAndreas Boehler $this->name = strtoupper($value); 68*a1a3b679SAndreas Boehler } else { 69*a1a3b679SAndreas Boehler $this->setValue($value); 70*a1a3b679SAndreas Boehler } 71*a1a3b679SAndreas Boehler 72*a1a3b679SAndreas Boehler } 73*a1a3b679SAndreas Boehler 74*a1a3b679SAndreas Boehler /** 75*a1a3b679SAndreas Boehler * Try to guess property name by value, can be used for vCard 2.1 nameless parameters. 76*a1a3b679SAndreas Boehler * 77*a1a3b679SAndreas Boehler * Figuring out what the name should have been. Note that a ton of 78*a1a3b679SAndreas Boehler * these are rather silly in 2014 and would probably rarely be 79*a1a3b679SAndreas Boehler * used, but we like to be complete. 80*a1a3b679SAndreas Boehler * 81*a1a3b679SAndreas Boehler * @param string $value 82*a1a3b679SAndreas Boehler * @return string 83*a1a3b679SAndreas Boehler */ 84*a1a3b679SAndreas Boehler public static function guessParameterNameByValue($value) { 85*a1a3b679SAndreas Boehler switch(strtoupper($value)) { 86*a1a3b679SAndreas Boehler 87*a1a3b679SAndreas Boehler // Encodings 88*a1a3b679SAndreas Boehler case '7-BIT' : 89*a1a3b679SAndreas Boehler case 'QUOTED-PRINTABLE' : 90*a1a3b679SAndreas Boehler case 'BASE64' : 91*a1a3b679SAndreas Boehler $name = 'ENCODING'; 92*a1a3b679SAndreas Boehler break; 93*a1a3b679SAndreas Boehler 94*a1a3b679SAndreas Boehler // Common types 95*a1a3b679SAndreas Boehler case 'WORK' : 96*a1a3b679SAndreas Boehler case 'HOME' : 97*a1a3b679SAndreas Boehler case 'PREF' : 98*a1a3b679SAndreas Boehler 99*a1a3b679SAndreas Boehler // Delivery Label Type 100*a1a3b679SAndreas Boehler case 'DOM' : 101*a1a3b679SAndreas Boehler case 'INTL' : 102*a1a3b679SAndreas Boehler case 'POSTAL' : 103*a1a3b679SAndreas Boehler case 'PARCEL' : 104*a1a3b679SAndreas Boehler 105*a1a3b679SAndreas Boehler // Telephone types 106*a1a3b679SAndreas Boehler case 'VOICE' : 107*a1a3b679SAndreas Boehler case 'FAX' : 108*a1a3b679SAndreas Boehler case 'MSG' : 109*a1a3b679SAndreas Boehler case 'CELL' : 110*a1a3b679SAndreas Boehler case 'PAGER' : 111*a1a3b679SAndreas Boehler case 'BBS' : 112*a1a3b679SAndreas Boehler case 'MODEM' : 113*a1a3b679SAndreas Boehler case 'CAR' : 114*a1a3b679SAndreas Boehler case 'ISDN' : 115*a1a3b679SAndreas Boehler case 'VIDEO' : 116*a1a3b679SAndreas Boehler 117*a1a3b679SAndreas Boehler // EMAIL types (lol) 118*a1a3b679SAndreas Boehler case 'AOL' : 119*a1a3b679SAndreas Boehler case 'APPLELINK' : 120*a1a3b679SAndreas Boehler case 'ATTMAIL' : 121*a1a3b679SAndreas Boehler case 'CIS' : 122*a1a3b679SAndreas Boehler case 'EWORLD' : 123*a1a3b679SAndreas Boehler case 'INTERNET' : 124*a1a3b679SAndreas Boehler case 'IBMMAIL' : 125*a1a3b679SAndreas Boehler case 'MCIMAIL' : 126*a1a3b679SAndreas Boehler case 'POWERSHARE' : 127*a1a3b679SAndreas Boehler case 'PRODIGY' : 128*a1a3b679SAndreas Boehler case 'TLX' : 129*a1a3b679SAndreas Boehler case 'X400' : 130*a1a3b679SAndreas Boehler 131*a1a3b679SAndreas Boehler // Photo / Logo format types 132*a1a3b679SAndreas Boehler case 'GIF' : 133*a1a3b679SAndreas Boehler case 'CGM' : 134*a1a3b679SAndreas Boehler case 'WMF' : 135*a1a3b679SAndreas Boehler case 'BMP' : 136*a1a3b679SAndreas Boehler case 'DIB' : 137*a1a3b679SAndreas Boehler case 'PICT' : 138*a1a3b679SAndreas Boehler case 'TIFF' : 139*a1a3b679SAndreas Boehler case 'PDF ': 140*a1a3b679SAndreas Boehler case 'PS' : 141*a1a3b679SAndreas Boehler case 'JPEG' : 142*a1a3b679SAndreas Boehler case 'MPEG' : 143*a1a3b679SAndreas Boehler case 'MPEG2' : 144*a1a3b679SAndreas Boehler case 'AVI' : 145*a1a3b679SAndreas Boehler case 'QTIME' : 146*a1a3b679SAndreas Boehler 147*a1a3b679SAndreas Boehler // Sound Digital Audio Type 148*a1a3b679SAndreas Boehler case 'WAVE' : 149*a1a3b679SAndreas Boehler case 'PCM' : 150*a1a3b679SAndreas Boehler case 'AIFF' : 151*a1a3b679SAndreas Boehler 152*a1a3b679SAndreas Boehler // Key types 153*a1a3b679SAndreas Boehler case 'X509' : 154*a1a3b679SAndreas Boehler case 'PGP' : 155*a1a3b679SAndreas Boehler $name = 'TYPE'; 156*a1a3b679SAndreas Boehler break; 157*a1a3b679SAndreas Boehler 158*a1a3b679SAndreas Boehler // Value types 159*a1a3b679SAndreas Boehler case 'INLINE' : 160*a1a3b679SAndreas Boehler case 'URL' : 161*a1a3b679SAndreas Boehler case 'CONTENT-ID' : 162*a1a3b679SAndreas Boehler case 'CID' : 163*a1a3b679SAndreas Boehler $name = 'VALUE'; 164*a1a3b679SAndreas Boehler break; 165*a1a3b679SAndreas Boehler 166*a1a3b679SAndreas Boehler default: 167*a1a3b679SAndreas Boehler $name = ''; 168*a1a3b679SAndreas Boehler } 169*a1a3b679SAndreas Boehler 170*a1a3b679SAndreas Boehler return $name; 171*a1a3b679SAndreas Boehler } 172*a1a3b679SAndreas Boehler 173*a1a3b679SAndreas Boehler /** 174*a1a3b679SAndreas Boehler * Updates the current value. 175*a1a3b679SAndreas Boehler * 176*a1a3b679SAndreas Boehler * This may be either a single, or multiple strings in an array. 177*a1a3b679SAndreas Boehler * 178*a1a3b679SAndreas Boehler * @param string|array $value 179*a1a3b679SAndreas Boehler * @return void 180*a1a3b679SAndreas Boehler */ 181*a1a3b679SAndreas Boehler public function setValue($value) { 182*a1a3b679SAndreas Boehler 183*a1a3b679SAndreas Boehler $this->value = $value; 184*a1a3b679SAndreas Boehler 185*a1a3b679SAndreas Boehler } 186*a1a3b679SAndreas Boehler 187*a1a3b679SAndreas Boehler /** 188*a1a3b679SAndreas Boehler * Returns the current value 189*a1a3b679SAndreas Boehler * 190*a1a3b679SAndreas Boehler * This method will always return a string, or null. If there were multiple 191*a1a3b679SAndreas Boehler * values, it will automatically concatinate them (separated by comma). 192*a1a3b679SAndreas Boehler * 193*a1a3b679SAndreas Boehler * @return string|null 194*a1a3b679SAndreas Boehler */ 195*a1a3b679SAndreas Boehler public function getValue() { 196*a1a3b679SAndreas Boehler 197*a1a3b679SAndreas Boehler if (is_array($this->value)) { 198*a1a3b679SAndreas Boehler return implode(',' , $this->value); 199*a1a3b679SAndreas Boehler } else { 200*a1a3b679SAndreas Boehler return $this->value; 201*a1a3b679SAndreas Boehler } 202*a1a3b679SAndreas Boehler 203*a1a3b679SAndreas Boehler } 204*a1a3b679SAndreas Boehler 205*a1a3b679SAndreas Boehler /** 206*a1a3b679SAndreas Boehler * Sets multiple values for this parameter. 207*a1a3b679SAndreas Boehler * 208*a1a3b679SAndreas Boehler * @param array $value 209*a1a3b679SAndreas Boehler * @return void 210*a1a3b679SAndreas Boehler */ 211*a1a3b679SAndreas Boehler public function setParts(array $value) { 212*a1a3b679SAndreas Boehler 213*a1a3b679SAndreas Boehler $this->value = $value; 214*a1a3b679SAndreas Boehler 215*a1a3b679SAndreas Boehler } 216*a1a3b679SAndreas Boehler 217*a1a3b679SAndreas Boehler /** 218*a1a3b679SAndreas Boehler * Returns all values for this parameter. 219*a1a3b679SAndreas Boehler * 220*a1a3b679SAndreas Boehler * If there were no values, an empty array will be returned. 221*a1a3b679SAndreas Boehler * 222*a1a3b679SAndreas Boehler * @return array 223*a1a3b679SAndreas Boehler */ 224*a1a3b679SAndreas Boehler public function getParts() { 225*a1a3b679SAndreas Boehler 226*a1a3b679SAndreas Boehler if (is_array($this->value)) { 227*a1a3b679SAndreas Boehler return $this->value; 228*a1a3b679SAndreas Boehler } elseif (is_null($this->value)) { 229*a1a3b679SAndreas Boehler return array(); 230*a1a3b679SAndreas Boehler } else { 231*a1a3b679SAndreas Boehler return array($this->value); 232*a1a3b679SAndreas Boehler } 233*a1a3b679SAndreas Boehler 234*a1a3b679SAndreas Boehler } 235*a1a3b679SAndreas Boehler 236*a1a3b679SAndreas Boehler /** 237*a1a3b679SAndreas Boehler * Adds a value to this parameter 238*a1a3b679SAndreas Boehler * 239*a1a3b679SAndreas Boehler * If the argument is specified as an array, all items will be added to the 240*a1a3b679SAndreas Boehler * parameter value list. 241*a1a3b679SAndreas Boehler * 242*a1a3b679SAndreas Boehler * @param string|array $part 243*a1a3b679SAndreas Boehler * @return void 244*a1a3b679SAndreas Boehler */ 245*a1a3b679SAndreas Boehler public function addValue($part) { 246*a1a3b679SAndreas Boehler 247*a1a3b679SAndreas Boehler if (is_null($this->value)) { 248*a1a3b679SAndreas Boehler $this->value = $part; 249*a1a3b679SAndreas Boehler } else { 250*a1a3b679SAndreas Boehler $this->value = array_merge((array)$this->value, (array)$part); 251*a1a3b679SAndreas Boehler } 252*a1a3b679SAndreas Boehler 253*a1a3b679SAndreas Boehler } 254*a1a3b679SAndreas Boehler 255*a1a3b679SAndreas Boehler /** 256*a1a3b679SAndreas Boehler * Checks if this parameter contains the specified value. 257*a1a3b679SAndreas Boehler * 258*a1a3b679SAndreas Boehler * This is a case-insensitive match. It makes sense to call this for for 259*a1a3b679SAndreas Boehler * instance the TYPE parameter, to see if it contains a keyword such as 260*a1a3b679SAndreas Boehler * 'WORK' or 'FAX'. 261*a1a3b679SAndreas Boehler * 262*a1a3b679SAndreas Boehler * @param string $value 263*a1a3b679SAndreas Boehler * @return bool 264*a1a3b679SAndreas Boehler */ 265*a1a3b679SAndreas Boehler public function has($value) { 266*a1a3b679SAndreas Boehler 267*a1a3b679SAndreas Boehler return in_array( 268*a1a3b679SAndreas Boehler strtolower($value), 269*a1a3b679SAndreas Boehler array_map('strtolower', (array)$this->value) 270*a1a3b679SAndreas Boehler ); 271*a1a3b679SAndreas Boehler 272*a1a3b679SAndreas Boehler } 273*a1a3b679SAndreas Boehler 274*a1a3b679SAndreas Boehler /** 275*a1a3b679SAndreas Boehler * Turns the object back into a serialized blob. 276*a1a3b679SAndreas Boehler * 277*a1a3b679SAndreas Boehler * @return string 278*a1a3b679SAndreas Boehler */ 279*a1a3b679SAndreas Boehler public function serialize() { 280*a1a3b679SAndreas Boehler 281*a1a3b679SAndreas Boehler $value = $this->getParts(); 282*a1a3b679SAndreas Boehler 283*a1a3b679SAndreas Boehler if (count($value)===0) { 284*a1a3b679SAndreas Boehler return $this->name . '='; 285*a1a3b679SAndreas Boehler } 286*a1a3b679SAndreas Boehler 287*a1a3b679SAndreas Boehler if ($this->root->getDocumentType() === Document::VCARD21 && $this->noName) { 288*a1a3b679SAndreas Boehler 289*a1a3b679SAndreas Boehler return implode(';', $value); 290*a1a3b679SAndreas Boehler 291*a1a3b679SAndreas Boehler } 292*a1a3b679SAndreas Boehler 293*a1a3b679SAndreas Boehler return $this->name . '=' . array_reduce( 294*a1a3b679SAndreas Boehler $value, 295*a1a3b679SAndreas Boehler function($out, $item) { 296*a1a3b679SAndreas Boehler 297*a1a3b679SAndreas Boehler if (!is_null($out)) $out.=','; 298*a1a3b679SAndreas Boehler 299*a1a3b679SAndreas Boehler // If there's no special characters in the string, we'll use the simple 300*a1a3b679SAndreas Boehler // format. 301*a1a3b679SAndreas Boehler // 302*a1a3b679SAndreas Boehler // The list of special characters is defined as: 303*a1a3b679SAndreas Boehler // 304*a1a3b679SAndreas Boehler // Any character except CONTROL, DQUOTE, ";", ":", "," 305*a1a3b679SAndreas Boehler // 306*a1a3b679SAndreas Boehler // by the iCalendar spec: 307*a1a3b679SAndreas Boehler // https://tools.ietf.org/html/rfc5545#section-3.1 308*a1a3b679SAndreas Boehler // 309*a1a3b679SAndreas Boehler // And we add ^ to that because of: 310*a1a3b679SAndreas Boehler // https://tools.ietf.org/html/rfc6868 311*a1a3b679SAndreas Boehler // 312*a1a3b679SAndreas Boehler // But we've found that iCal (7.0, shipped with OSX 10.9) 313*a1a3b679SAndreas Boehler // severaly trips on + characters not being quoted, so we 314*a1a3b679SAndreas Boehler // added + as well. 315*a1a3b679SAndreas Boehler if (!preg_match('#(?: [\n":;\^,\+] )#x', $item)) { 316*a1a3b679SAndreas Boehler return $out.$item; 317*a1a3b679SAndreas Boehler } else { 318*a1a3b679SAndreas Boehler // Enclosing in double-quotes, and using RFC6868 for encoding any 319*a1a3b679SAndreas Boehler // special characters 320*a1a3b679SAndreas Boehler $out.='"' . strtr( 321*a1a3b679SAndreas Boehler $item, 322*a1a3b679SAndreas Boehler array( 323*a1a3b679SAndreas Boehler '^' => '^^', 324*a1a3b679SAndreas Boehler "\n" => '^n', 325*a1a3b679SAndreas Boehler '"' => '^\'', 326*a1a3b679SAndreas Boehler ) 327*a1a3b679SAndreas Boehler ) . '"'; 328*a1a3b679SAndreas Boehler return $out; 329*a1a3b679SAndreas Boehler } 330*a1a3b679SAndreas Boehler 331*a1a3b679SAndreas Boehler } 332*a1a3b679SAndreas Boehler ); 333*a1a3b679SAndreas Boehler 334*a1a3b679SAndreas Boehler } 335*a1a3b679SAndreas Boehler 336*a1a3b679SAndreas Boehler /** 337*a1a3b679SAndreas Boehler * This method returns an array, with the representation as it should be 338*a1a3b679SAndreas Boehler * encoded in json. This is used to create jCard or jCal documents. 339*a1a3b679SAndreas Boehler * 340*a1a3b679SAndreas Boehler * @return array 341*a1a3b679SAndreas Boehler */ 342*a1a3b679SAndreas Boehler public function jsonSerialize() { 343*a1a3b679SAndreas Boehler 344*a1a3b679SAndreas Boehler return $this->value; 345*a1a3b679SAndreas Boehler 346*a1a3b679SAndreas Boehler } 347*a1a3b679SAndreas Boehler 348*a1a3b679SAndreas Boehler /** 349*a1a3b679SAndreas Boehler * Called when this object is being cast to a string 350*a1a3b679SAndreas Boehler * 351*a1a3b679SAndreas Boehler * @return string 352*a1a3b679SAndreas Boehler */ 353*a1a3b679SAndreas Boehler public function __toString() { 354*a1a3b679SAndreas Boehler 355*a1a3b679SAndreas Boehler return (string)$this->getValue(); 356*a1a3b679SAndreas Boehler 357*a1a3b679SAndreas Boehler } 358*a1a3b679SAndreas Boehler 359*a1a3b679SAndreas Boehler /** 360*a1a3b679SAndreas Boehler * Returns the iterator for this object 361*a1a3b679SAndreas Boehler * 362*a1a3b679SAndreas Boehler * @return ElementList 363*a1a3b679SAndreas Boehler */ 364*a1a3b679SAndreas Boehler public function getIterator() { 365*a1a3b679SAndreas Boehler 366*a1a3b679SAndreas Boehler if (!is_null($this->iterator)) 367*a1a3b679SAndreas Boehler return $this->iterator; 368*a1a3b679SAndreas Boehler 369*a1a3b679SAndreas Boehler return $this->iterator = new ArrayObject((array)$this->value); 370*a1a3b679SAndreas Boehler 371*a1a3b679SAndreas Boehler } 372*a1a3b679SAndreas Boehler 373*a1a3b679SAndreas Boehler} 374