1<?php 2 3namespace Sabre\CardDAV; 4 5use Sabre\DAVACL; 6use Sabre\DAV; 7 8/** 9 * The Card object represents a single Card from an addressbook 10 * 11 * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 12 * @author Evert Pot (http://evertpot.com/) 13 * @license http://sabre.io/license/ Modified BSD License 14 */ 15class Card extends DAV\File implements ICard, DAVACL\IACL { 16 17 /** 18 * CardDAV backend 19 * 20 * @var Backend\BackendInterface 21 */ 22 protected $carddavBackend; 23 24 /** 25 * Array with information about this Card 26 * 27 * @var array 28 */ 29 protected $cardData; 30 31 /** 32 * Array with information about the containing addressbook 33 * 34 * @var array 35 */ 36 protected $addressBookInfo; 37 38 /** 39 * Constructor 40 * 41 * @param Backend\BackendInterface $carddavBackend 42 * @param array $addressBookInfo 43 * @param array $cardData 44 */ 45 function __construct(Backend\BackendInterface $carddavBackend, array $addressBookInfo, array $cardData) { 46 47 $this->carddavBackend = $carddavBackend; 48 $this->addressBookInfo = $addressBookInfo; 49 $this->cardData = $cardData; 50 51 } 52 53 /** 54 * Returns the uri for this object 55 * 56 * @return string 57 */ 58 function getName() { 59 60 return $this->cardData['uri']; 61 62 } 63 64 /** 65 * Returns the VCard-formatted object 66 * 67 * @return string 68 */ 69 function get() { 70 71 // Pre-populating 'carddata' is optional. If we don't yet have it 72 // already, we fetch it from the backend. 73 if (!isset($this->cardData['carddata'])) { 74 $this->cardData = $this->carddavBackend->getCard($this->addressBookInfo['id'], $this->cardData['uri']); 75 } 76 return $this->cardData['carddata']; 77 78 } 79 80 /** 81 * Updates the VCard-formatted object 82 * 83 * @param string $cardData 84 * @return string|null 85 */ 86 function put($cardData) { 87 88 if (is_resource($cardData)) 89 $cardData = stream_get_contents($cardData); 90 91 // Converting to UTF-8, if needed 92 $cardData = DAV\StringUtil::ensureUTF8($cardData); 93 94 $etag = $this->carddavBackend->updateCard($this->addressBookInfo['id'], $this->cardData['uri'], $cardData); 95 $this->cardData['carddata'] = $cardData; 96 $this->cardData['etag'] = $etag; 97 98 return $etag; 99 100 } 101 102 /** 103 * Deletes the card 104 * 105 * @return void 106 */ 107 function delete() { 108 109 $this->carddavBackend->deleteCard($this->addressBookInfo['id'], $this->cardData['uri']); 110 111 } 112 113 /** 114 * Returns the mime content-type 115 * 116 * @return string 117 */ 118 function getContentType() { 119 120 return 'text/vcard; charset=utf-8'; 121 122 } 123 124 /** 125 * Returns an ETag for this object 126 * 127 * @return string 128 */ 129 function getETag() { 130 131 if (isset($this->cardData['etag'])) { 132 return $this->cardData['etag']; 133 } else { 134 $data = $this->get(); 135 if (is_string($data)) { 136 return '"' . md5($data) . '"'; 137 } else { 138 // We refuse to calculate the md5 if it's a stream. 139 return null; 140 } 141 } 142 143 } 144 145 /** 146 * Returns the last modification date as a unix timestamp 147 * 148 * @return int 149 */ 150 function getLastModified() { 151 152 return isset($this->cardData['lastmodified']) ? $this->cardData['lastmodified'] : null; 153 154 } 155 156 /** 157 * Returns the size of this object in bytes 158 * 159 * @return int 160 */ 161 function getSize() { 162 163 if (array_key_exists('size', $this->cardData)) { 164 return $this->cardData['size']; 165 } else { 166 return strlen($this->get()); 167 } 168 169 } 170 171 /** 172 * Returns the owner principal 173 * 174 * This must be a url to a principal, or null if there's no owner 175 * 176 * @return string|null 177 */ 178 function getOwner() { 179 180 return $this->addressBookInfo['principaluri']; 181 182 } 183 184 /** 185 * Returns a group principal 186 * 187 * This must be a url to a principal, or null if there's no owner 188 * 189 * @return string|null 190 */ 191 function getGroup() { 192 193 return null; 194 195 } 196 197 /** 198 * Returns a list of ACE's for this node. 199 * 200 * Each ACE has the following properties: 201 * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are 202 * currently the only supported privileges 203 * * 'principal', a url to the principal who owns the node 204 * * 'protected' (optional), indicating that this ACE is not allowed to 205 * be updated. 206 * 207 * @return array 208 */ 209 function getACL() { 210 211 // An alternative acl may be specified through the cardData array. 212 if (isset($this->cardData['acl'])) { 213 return $this->cardData['acl']; 214 } 215 216 return [ 217 [ 218 'privilege' => '{DAV:}read', 219 'principal' => $this->addressBookInfo['principaluri'], 220 'protected' => true, 221 ], 222 [ 223 'privilege' => '{DAV:}write', 224 'principal' => $this->addressBookInfo['principaluri'], 225 'protected' => true, 226 ], 227 ]; 228 229 } 230 231 /** 232 * Updates the ACL 233 * 234 * This method will receive a list of new ACE's. 235 * 236 * @param array $acl 237 * @return void 238 */ 239 function setACL(array $acl) { 240 241 throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); 242 243 } 244 245 /** 246 * Returns the list of supported privileges for this node. 247 * 248 * The returned data structure is a list of nested privileges. 249 * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple 250 * standard structure. 251 * 252 * If null is returned from this method, the default privilege set is used, 253 * which is fine for most common usecases. 254 * 255 * @return array|null 256 */ 257 function getSupportedPrivilegeSet() { 258 259 return null; 260 261 } 262 263} 264