From 1594ec07882c2edc41274f1cc80b95147cf41709 Mon Sep 17 00:00:00 2001 From: Michael Grossklos Date: Sat, 16 Oct 2021 19:22:50 +0200 Subject: [PATCH] Adding addSource feature --- src/VCard.php | 997 ++++++++++++++++++++++++++------------------------ 1 file changed, 519 insertions(+), 478 deletions(-) diff --git a/src/VCard.php b/src/VCard.php index 29008ae..b38588f 100644 --- a/src/VCard.php +++ b/src/VCard.php @@ -16,27 +16,30 @@ */ class VCard { + /** + * Default Charset + * + * @var string + */ + public $charset = 'utf-8'; /** * definedElements * * @var array */ private $definedElements; - /** * Filename * * @var string */ private $filename; - /** * Save Path * * @var string */ private $savePath = null; - /** * Multiple properties for element allowed * @@ -47,23 +50,58 @@ class VCard 'address', 'phoneNumber', 'url', - 'label' + 'label', ]; - /** * Properties * * @var array */ private $properties; - + /** - * Default Charset + * Sets the source for fetching a new version of the vCard * - * @var string + * @param string $url + * + * @throws VCardException */ - public $charset = 'utf-8'; - + public function addSource($url = '') + { + $this->setProperty( + null, + 'SOURCE', + $url + ); + } + + /** + * Set property + * + * @param string $element The element name you want to set, f.e.: name, email, phoneNumber, ... + * @param string $key + * @param string $value + * + * @throws VCardException + */ + private function setProperty($element, $key, $value) + { + if (!in_array($element, $this->multiplePropertiesForElementAllowed) + && isset($this->definedElements[$element]) + ) { + throw VCardException::elementAlreadyExists($element); + } + + // we define that we set this element + $this->definedElements[$element] = true; + + // adding property + $this->properties[] = [ + 'key' => $key, + 'value' => $value, + ]; + } + /** * Add address * @@ -77,6 +115,7 @@ class VCard * @param string [optional] $type * $type may be DOM | INTL | POSTAL | PARCEL | HOME | WORK * or any combination of these: e.g. "WORK;PARCEL;POSTAL" + * * @return $this */ public function addAddress( @@ -91,21 +130,32 @@ public function addAddress( ) { // init value $value = $name . ';' . $extended . ';' . $street . ';' . $city . ';' . $region . ';' . $zip . ';' . $country; - + // set property $this->setProperty( 'address', 'ADR' . (($type != '') ? ';' . $type : '') . $this->getCharsetString(), $value ); - + return $this; } - + + /** + * Get charset string + * + * @return string + */ + public function getCharsetString() + { + return ';CHARSET=' . $this->charset; + } + /** * Add birthday * - * @param string $date Format is YYYY-MM-DD + * @param string $date Format is YYYY-MM-DD + * * @return $this */ public function addBirthday($date) @@ -115,15 +165,16 @@ public function addBirthday($date) 'BDAY', $date ); - + return $this; } - + /** * Add company * - * @param string $company - * @param string $department + * @param string $company + * @param string $department + * * @return $this */ public function addCompany($company, $department = '') @@ -134,22 +185,23 @@ public function addCompany($company, $department = '') $company . ($department != '' ? ';' . $department : '') ); - + // if filename is empty, add to filename if ($this->filename === null) { $this->setFilename($company); } - + return $this; } - + /** * Add email * - * @param string $address The e-mail address + * @param string $address The e-mail address * @param string [optional] $type The type of the email address * $type may be PREF | WORK | HOME * or any combination of these: e.g. "PREF;WORK" + * * @return $this */ public function addEmail($address, $type = '') @@ -159,14 +211,15 @@ public function addEmail($address, $type = '') 'EMAIL;INTERNET' . (($type != '') ? ';' . $type : ''), $address ); - + return $this; } - + /** * Add jobtitle * - * @param string $jobtitle The jobtitle for the person. + * @param string $jobtitle The jobtitle for the person. + * * @return $this */ public function addJobtitle($jobtitle) @@ -176,15 +229,15 @@ public function addJobtitle($jobtitle) 'TITLE' . $this->getCharsetString(), $jobtitle ); - + return $this; } - + /** * Add a label * - * @param string $label - * @param string $type + * @param string $label + * @param string $type * * @return $this */ @@ -195,14 +248,15 @@ public function addLabel($label, $type = '') 'LABEL' . ($type !== '' ? ';' . $type : ''), $label ); - + return $this; } - + /** * Add role * - * @param string $role The role for the person. + * @param string $role The role for the person. + * * @return $this */ public function addRole($role) @@ -212,111 +266,10 @@ public function addRole($role) 'ROLE' . $this->getCharsetString(), $role ); - + return $this; } - - /** - * Add a photo or logo (depending on property name) - * - * @param string $property LOGO|PHOTO - * @param string $url image url or filename - * @param bool $include Do we include the image in our vcard or not? - * @param string $element The name of the element to set - * @throws VCardException - */ - private function addMedia($property, $url, $include = true, $element) - { - $mimeType = null; - - //Is this URL for a remote resource? - if (filter_var($url, FILTER_VALIDATE_URL) !== false) { - $headers = get_headers($url, 1); - - if (array_key_exists('Content-Type', $headers)) { - $mimeType = $headers['Content-Type']; - if (is_array($mimeType)) { - $mimeType = end($mimeType); - } - } - } else { - //Local file, so inspect it directly - $mimeType = mime_content_type($url); - } - if (strpos($mimeType, ';') !== false) { - $mimeType = strstr($mimeType, ';', true); - } - if (!is_string($mimeType) || substr($mimeType, 0, 6) !== 'image/') { - throw VCardException::invalidImage(); - } - $fileType = strtoupper(substr($mimeType, 6)); - - if ($include) { - if ((bool) ini_get('allow_url_fopen') === true) { - $value = file_get_contents($url); - } else { - $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, $url); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); - $value = curl_exec($curl); - curl_close($curl); - } - - if (!$value) { - throw VCardException::emptyURL(); - } - - $value = base64_encode($value); - $property .= ";ENCODING=b;TYPE=" . $fileType; - } else { - if (filter_var($url, FILTER_VALIDATE_URL) !== false) { - $propertySuffix = ';VALUE=URL'; - $propertySuffix .= ';TYPE=' . strtoupper($fileType); - - $property = $property . $propertySuffix; - $value = $url; - } else { - $value = $url; - } - } - - $this->setProperty( - $element, - $property, - $value - ); - } - - /** - * Add a photo or logo (depending on property name) - * - * @param string $property LOGO|PHOTO - * @param string $content image content - * @param string $element The name of the element to set - */ - private function addMediaContent($property, $content, $element) - { - $finfo = new \finfo(); - $mimeType = $finfo->buffer($content, FILEINFO_MIME_TYPE); - - if (strpos($mimeType, ';') !== false) { - $mimeType = strstr($mimeType, ';', true); - } - if (!is_string($mimeType) || substr($mimeType, 0, 6) !== 'image/') { - throw VCardException::invalidImage(); - } - $fileType = strtoupper(substr($mimeType, 6)); - - $content = base64_encode($content); - $property .= ";ENCODING=b;TYPE=" . $fileType; - - $this->setProperty( - $element, - $property, - $content - ); - } - + /** * Add name * @@ -325,6 +278,7 @@ private function addMediaContent($property, $content, $element) * @param string [optional] $additional * @param string [optional] $prefix * @param string [optional] $suffix + * * @return $this */ public function addName( @@ -342,10 +296,10 @@ public function addName( $lastName, $suffix, ]); - + // define filename $this->setFilename($values); - + // set property $property = $lastName . ';' . $firstName . ';' . $additional . ';' . $prefix . ';' . $suffix; $this->setProperty( @@ -353,7 +307,7 @@ public function addName( 'N' . $this->getCharsetString(), $property ); - + // is property FN set? if (!$this->hasProperty('FN')) { // set property @@ -363,14 +317,45 @@ public function addName( trim(implode(' ', $values)) ); } - + return $this; } - + + /** + * Has property + * + * @param string $key + * + * @return bool + */ + public function hasProperty($key) + { + $properties = $this->getProperties(); + + foreach ($properties as $property) { + if ($property['key'] === $key && $property['value'] !== '') { + return true; + } + } + + return false; + } + + /** + * Get properties + * + * @return array + */ + public function getProperties() + { + return $this->properties; + } + /** * Add note * - * @param string $note + * @param string $note + * * @return $this */ public function addNote($note) @@ -380,14 +365,15 @@ public function addNote($note) 'NOTE' . $this->getCharsetString(), $note ); - + return $this; } - + /** * Add categories * - * @param array $categories + * @param array $categories + * * @return $this */ public function addCategories($categories) @@ -397,18 +383,19 @@ public function addCategories($categories) 'CATEGORIES' . $this->getCharsetString(), trim(implode(',', $categories)) ); - + return $this; } - + /** * Add phone number * - * @param string $number + * @param string $number * @param string [optional] $type * Type may be PREF | WORK | HOME | VOICE | FAX | MSG | * CELL | PAGER | BBS | CAR | MODEM | ISDN | VIDEO * or any senseful combination, e.g. "PREF;WORK;VOICE" + * * @return $this */ public function addPhoneNumber($number, $type = '') @@ -418,15 +405,16 @@ public function addPhoneNumber($number, $type = '') 'TEL' . (($type != '') ? ';' . $type : ''), $number ); - + return $this; } - + /** * Add Logo * - * @param string $url image url or filename - * @param bool $include Include the image in our vcard? + * @param string $url image url or filename + * @param bool $include Include the image in our vcard? + * * @return $this */ public function addLogo($url, $include = true) @@ -437,68 +425,174 @@ public function addLogo($url, $include = true) $include, 'logo' ); - - return $this; - } - - /** - * Add Logo content - * - * @param string $content image content - * @return $this - */ - public function addLogoContent($content) - { - $this->addMediaContent( - 'LOGO', - $content, - 'logo' - ); - + return $this; } - + /** - * Add Photo + * Add a photo or logo (depending on property name) * - * @param string $url image url or filename - * @param bool $include Include the image in our vcard? - * @return $this - */ - public function addPhoto($url, $include = true) - { - $this->addMedia( - 'PHOTO', - $url, - $include, - 'photo' - ); - - return $this; - } - - /** - * Add Photo content + * @param string $property LOGO|PHOTO + * @param string $url image url or filename + * @param bool $include Do we include the image in our vcard or not? + * @param string $element The name of the element to set * - * @param string $content image content - * @return $this + * @throws VCardException */ - public function addPhotoContent($content) + private function addMedia($property, $url, $include = true, $element) { - $this->addMediaContent( - 'PHOTO', - $content, - 'photo' - ); - - return $this; - } - + $mimeType = null; + + //Is this URL for a remote resource? + if (filter_var($url, FILTER_VALIDATE_URL) !== false) { + $headers = get_headers($url, 1); + + if (array_key_exists('Content-Type', $headers)) { + $mimeType = $headers['Content-Type']; + if (is_array($mimeType)) { + $mimeType = end($mimeType); + } + } + } else { + //Local file, so inspect it directly + $mimeType = mime_content_type($url); + } + if (strpos($mimeType, ';') !== false) { + $mimeType = strstr($mimeType, ';', true); + } + if (!is_string($mimeType) || substr($mimeType, 0, 6) !== 'image/') { + throw VCardException::invalidImage(); + } + $fileType = strtoupper(substr($mimeType, 6)); + + if ($include) { + if ((bool) ini_get('allow_url_fopen') === true) { + $value = file_get_contents($url); + } else { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + $value = curl_exec($curl); + curl_close($curl); + } + + if (!$value) { + throw VCardException::emptyURL(); + } + + $value = base64_encode($value); + $property .= ";ENCODING=b;TYPE=" . $fileType; + } else { + if (filter_var($url, FILTER_VALIDATE_URL) !== false) { + $propertySuffix = ';VALUE=URL'; + $propertySuffix .= ';TYPE=' . strtoupper($fileType); + + $property = $property . $propertySuffix; + $value = $url; + } else { + $value = $url; + } + } + + $this->setProperty( + $element, + $property, + $value + ); + } + + /** + * Add Logo content + * + * @param string $content image content + * + * @return $this + */ + public function addLogoContent($content) + { + $this->addMediaContent( + 'LOGO', + $content, + 'logo' + ); + + return $this; + } + + /** + * Add a photo or logo (depending on property name) + * + * @param string $property LOGO|PHOTO + * @param string $content image content + * @param string $element The name of the element to set + */ + private function addMediaContent($property, $content, $element) + { + $finfo = new \finfo(); + $mimeType = $finfo->buffer($content, FILEINFO_MIME_TYPE); + + if (strpos($mimeType, ';') !== false) { + $mimeType = strstr($mimeType, ';', true); + } + if (!is_string($mimeType) || substr($mimeType, 0, 6) !== 'image/') { + throw VCardException::invalidImage(); + } + $fileType = strtoupper(substr($mimeType, 6)); + + $content = base64_encode($content); + $property .= ";ENCODING=b;TYPE=" . $fileType; + + $this->setProperty( + $element, + $property, + $content + ); + } + + /** + * Add Photo + * + * @param string $url image url or filename + * @param bool $include Include the image in our vcard? + * + * @return $this + */ + public function addPhoto($url, $include = true) + { + $this->addMedia( + 'PHOTO', + $url, + $include, + 'photo' + ); + + return $this; + } + + /** + * Add Photo content + * + * @param string $content image content + * + * @return $this + */ + public function addPhotoContent($content) + { + $this->addMediaContent( + 'PHOTO', + $content, + 'photo' + ); + + return $this; + } + /** * Add URL * - * @param string $url + * @param string $url * @param string [optional] $type Type may be WORK | HOME + * * @return $this */ public function addURL($url, $type = '') @@ -508,36 +602,96 @@ public function addURL($url, $type = '') 'URL' . (($type != '') ? ';' . $type : ''), $url ); - + return $this; } - + /** - * Build VCard (.vcf) + * Download a vcard or vcal file to the browser. + */ + public function download() + { + // define output + $output = $this->getOutput(); + + foreach ($this->getHeaders(false) as $header) { + header($header); + } + + // echo the output and it will be a download + echo $output; + } + + /** + * Get output as string + * iOS devices (and safari < iOS 8 in particular) can not read .vcf (= vcard) files. + * So I build a workaround to build a .ics (= vcalender) file. * * @return string */ - public function buildVCard() + public function getOutput() { - // init string - $string = "BEGIN:VCARD\r\n"; - $string .= "VERSION:3.0\r\n"; - $string .= "REV:" . date("Y-m-d") . "T" . date("H:i:s") . "Z\r\n"; - - // loop all properties - $properties = $this->getProperties(); - foreach ($properties as $property) { - // add to string - $string .= $this->fold($property['key'] . ':' . $this->escape($property['value']) . "\r\n"); + $output = ($this->isIOS7()) ? + $this->buildVCalendar() : $this->buildVCard(); + + return $output; + } + + /** + * Is iOS less than 7 (should cal wrapper be returned) + * + * @return bool + */ + public function isIOS7() + { + return ($this->isIOS() && $this->shouldAttachmentBeCal()); + } + + /** + * Is iOS - Check if the user is using an iOS-device + * + * @return bool + */ + public function isIOS() + { + // get user agent + $browser = $this->getUserAgent(); + + return (strpos($browser, 'iphone') || strpos($browser, 'ipod') || strpos($browser, 'ipad')); + } + + /** + * Returns the browser user agent string. + * + * @return string + */ + protected function getUserAgent() + { + if (array_key_exists('HTTP_USER_AGENT', $_SERVER)) { + $browser = strtolower($_SERVER['HTTP_USER_AGENT']); + } else { + $browser = 'unknown'; } - - // add to string - $string .= "END:VCARD\r\n"; - - // return - return $string; + + return $browser; } - + + /** + * Checks if we should return vcard in cal wrapper + * + * @return bool + */ + protected function shouldAttachmentBeCal() + { + $browser = $this->getUserAgent(); + + $matches = []; + preg_match('/os (\d+)_(\d+)\s+/', $browser, $matches); + $version = isset($matches[1]) ? ((int) $matches[1]) : 999; + + return ($version < 8); + } + /** * Build VCalender (.ics) - Safari (< iOS 8) can not open .vcf files, so we have build a workaround. * @@ -548,7 +702,7 @@ public function buildVCalendar() // init dates $dtstart = date("Ymd") . "T" . date("Hi") . "00"; $dtend = date("Ymd") . "T" . date("Hi") . "01"; - + // init string $string = "BEGIN:VCALENDAR\n"; $string .= "VERSION:2.0\n"; @@ -559,75 +713,122 @@ public function buildVCalendar() $string .= "DTSTAMP:" . $dtstart . "Z\n"; $string .= "ATTACH;VALUE=BINARY;ENCODING=BASE64;FMTTYPE=text/directory;\n"; $string .= " X-APPLE-FILENAME=" . $this->getFilename() . "." . $this->getFileExtension() . ":\n"; - + // base64 encode it so that it can be used as an attachemnt to the "dummy" calendar appointment $b64vcard = base64_encode($this->buildVCard()); - + // chunk the single long line of b64 text in accordance with RFC2045 // (and the exact line length determined from the original .ics file exported from Apple calendar $b64mline = chunk_split($b64vcard, 74, "\n"); - + // need to indent all the lines by 1 space for the iphone (yes really?!!) $b64final = preg_replace('/(.+)/', ' $1', $b64mline); $string .= $b64final; - + // output the correctly formatted encoded text $string .= "END:VEVENT\n"; $string .= "END:VCALENDAR\n"; - + // return return $string; } - + /** - * Returns the browser user agent string. + * Get filename * * @return string */ - protected function getUserAgent() + public function getFilename() { - if (array_key_exists('HTTP_USER_AGENT', $_SERVER)) { - $browser = strtolower($_SERVER['HTTP_USER_AGENT']); - } else { - $browser = 'unknown'; + if (!$this->filename) { + return 'unknown'; } - - return $browser; + + return $this->filename; } - + /** - * Decode + * Set filename * - * @param string $value The value to decode - * @return string decoded + * @param mixed $value + * @param bool $overwrite [optional] Default overwrite is true + * @param string $separator [optional] Default separator is an underscore '_' + * + * @return void */ - private function decode($value) + public function setFilename($value, $overwrite = true, $separator = '_') { - // convert cyrlic, greek or other caracters to ASCII characters - return Transliterator::transliterate($value); + // recast to string if $value is array + if (is_array($value)) { + $value = implode($separator, $value); + } + + // trim unneeded values + $value = trim($value, $separator); + + // remove all spaces + $value = preg_replace('/\s+/', $separator, $value); + + // if value is empty, stop here + if (empty($value)) { + return; + } + + // decode value + lowercase the string + $value = strtolower($this->decode($value)); + + // urlize this part + $value = Transliterator::urlize($value); + + // overwrite filename or add to filename using a prefix in between + $this->filename = ($overwrite) ? + $value : $this->filename . $separator . $value; } - + /** - * Download a vcard or vcal file to the browser. + * Get file extension + * + * @return string + */ + public function getFileExtension() + { + return ($this->isIOS7()) ? + 'ics' : 'vcf'; + } + + /** + * Build VCard (.vcf) + * + * @return string */ - public function download() + public function buildVCard() { - // define output - $output = $this->getOutput(); - - foreach ($this->getHeaders(false) as $header) { - header($header); + // init string + $string = "BEGIN:VCARD\r\n"; + $string .= "VERSION:3.0\r\n"; + $string .= "REV:" . date("Y-m-d") . "T" . date("H:i:s") . "Z\r\n"; + + // loop all properties + $properties = $this->getProperties(); + foreach ($properties as $property) { + // add to string + $string .= $this->fold($property['key'] . ':' . $this->escape($property['value']) . "\r\n"); } - - // echo the output and it will be a download - echo $output; + + // add to string + $string .= "END:VCARD\r\n"; + + // return + return $string; } - + /** * Fold a line according to RFC2425 section 5.8.1. * * @link http://tools.ietf.org/html/rfc2425#section-5.8.1 - * @param string $text + * + * @param string $text + * * @return mixed */ protected function fold($text) @@ -635,18 +836,20 @@ protected function fold($text) if (strlen($text) <= 75) { return $text; } - + // split, wrap and trim trailing separator return substr($this->chunk_split_unicode($text, 75, "\r\n "), 0, -3); } - + /** * multibyte word chunk split + * * @link http://php.net/manual/en/function.chunk-split.php#107711 - * - * @param string $body The string to be chunked. - * @param integer $chunklen The chunk length. - * @param string $end The line ending sequence. + * + * @param string $body The string to be chunked. + * @param integer $chunklen The chunk length. + * @param string $end The line ending sequence. + * * @return string Chunked string */ protected function chunk_split_unicode($body, $chunklen = 76, $end = "\r\n") @@ -659,93 +862,29 @@ protected function chunk_split_unicode($body, $chunklen = 76, $end = "\r\n") } return $body; } - + /** * Escape newline characters according to RFC2425 section 5.8.4. * * @link http://tools.ietf.org/html/rfc2425#section-5.8.4 - * @param string $text + * + * @param string $text + * * @return string */ protected function escape($text) { $text = str_replace("\r\n", "\\n", $text); $text = str_replace("\n", "\\n", $text); - + return $text; } - - /** - * Get output as string - * @deprecated in the future - * - * @return string - */ - public function get() - { - return $this->getOutput(); - } - - /** - * Get charset - * - * @return string - */ - public function getCharset() - { - return $this->charset; - } - - /** - * Get charset string - * - * @return string - */ - public function getCharsetString() - { - return ';CHARSET=' . $this->charset; - } - - /** - * Get content type - * - * @return string - */ - public function getContentType() - { - return ($this->isIOS7()) ? - 'text/x-vcalendar' : 'text/x-vcard'; - } - - /** - * Get filename - * - * @return string - */ - public function getFilename() - { - if (!$this->filename) { - return 'unknown'; - } - - return $this->filename; - } - - /** - * Get file extension - * - * @return string - */ - public function getFileExtension() - { - return ($this->isIOS7()) ? - 'ics' : 'vcf'; - } - + /** * Get headers * - * @param bool $asAssociative + * @param bool $asAssociative + * * @return array */ public function getHeaders($asAssociative) @@ -754,16 +893,16 @@ public function getHeaders($asAssociative) $contentDisposition = 'attachment; filename=' . $this->getFilename() . '.' . $this->getFileExtension(); $contentLength = mb_strlen($this->getOutput(), '8bit'); $connection = 'close'; - - if ((bool)$asAssociative) { + + if ((bool) $asAssociative) { return [ - 'Content-type' => $contentType, + 'Content-type' => $contentType, 'Content-Disposition' => $contentDisposition, - 'Content-Length' => $contentLength, - 'Connection' => $connection, + 'Content-Length' => $contentLength, + 'Connection' => $connection, ]; } - + return [ 'Content-type: ' . $contentType, 'Content-Disposition: ' . $contentDisposition, @@ -771,74 +910,52 @@ public function getHeaders($asAssociative) 'Connection: ' . $connection, ]; } - + /** - * Get output as string - * iOS devices (and safari < iOS 8 in particular) can not read .vcf (= vcard) files. - * So I build a workaround to build a .ics (= vcalender) file. + * Get content type * * @return string */ - public function getOutput() + public function getContentType() { - $output = ($this->isIOS7()) ? - $this->buildVCalendar() : $this->buildVCard(); - - return $output; + return ($this->isIOS7()) ? + 'text/x-vcalendar' : 'text/x-vcard'; } - + /** - * Get properties + * Get charset * - * @return array + * @return string */ - public function getProperties() + public function getCharset() { - return $this->properties; + return $this->charset; } - + /** - * Has property + * Set charset * - * @param string $key - * @return bool - */ - public function hasProperty($key) - { - $properties = $this->getProperties(); - - foreach ($properties as $property) { - if ($property['key'] === $key && $property['value'] !== '') { - return true; - } - } - - return false; - } - - /** - * Is iOS - Check if the user is using an iOS-device + * @param mixed $charset * - * @return bool + * @return void */ - public function isIOS() + public function setCharset($charset) { - // get user agent - $browser = $this->getUserAgent(); - - return (strpos($browser, 'iphone') || strpos($browser, 'ipod') || strpos($browser, 'ipad')); + $this->charset = $charset; } - + /** - * Is iOS less than 7 (should cal wrapper be returned) + * Get output as string + * + * @return string + * @deprecated in the future * - * @return bool */ - public function isIOS7() + public function get() { - return ($this->isIOS() && $this->shouldAttachmentBeCal()); + return $this->getOutput(); } - + /** * Save to a file * @@ -847,70 +964,23 @@ public function isIOS7() public function save() { $file = $this->getFilename() . '.' . $this->getFileExtension(); - + // Add save path if given if (null !== $this->savePath) { $file = $this->savePath . $file; } - + file_put_contents( $file, $this->getOutput() ); } - - /** - * Set charset - * - * @param mixed $charset - * @return void - */ - public function setCharset($charset) - { - $this->charset = $charset; - } - - /** - * Set filename - * - * @param mixed $value - * @param bool $overwrite [optional] Default overwrite is true - * @param string $separator [optional] Default separator is an underscore '_' - * @return void - */ - public function setFilename($value, $overwrite = true, $separator = '_') - { - // recast to string if $value is array - if (is_array($value)) { - $value = implode($separator, $value); - } - - // trim unneeded values - $value = trim($value, $separator); - - // remove all spaces - $value = preg_replace('/\s+/', $separator, $value); - - // if value is empty, stop here - if (empty($value)) { - return; - } - - // decode value + lowercase the string - $value = strtolower($this->decode($value)); - - // urlize this part - $value = Transliterator::urlize($value); - - // overwrite filename or add to filename using a prefix in between - $this->filename = ($overwrite) ? - $value : $this->filename . $separator . $value; - } - + /** * Set the save path directory * - * @param string $savePath Save Path + * @param string $savePath Save Path + * * @throws VCardException */ public function setSavePath($savePath) @@ -918,54 +988,25 @@ public function setSavePath($savePath) if (!is_dir($savePath)) { throw VCardException::outputDirectoryNotExists(); } - + // Add trailing directory separator the save path if (substr($savePath, -1) != DIRECTORY_SEPARATOR) { $savePath .= DIRECTORY_SEPARATOR; } - + $this->savePath = $savePath; } - + /** - * Set property + * Decode * - * @param string $element The element name you want to set, f.e.: name, email, phoneNumber, ... - * @param string $key - * @param string $value - * @throws VCardException - */ - private function setProperty($element, $key, $value) - { - if (!in_array($element, $this->multiplePropertiesForElementAllowed) - && isset($this->definedElements[$element]) - ) { - throw VCardException::elementAlreadyExists($element); - } - - // we define that we set this element - $this->definedElements[$element] = true; - - // adding property - $this->properties[] = [ - 'key' => $key, - 'value' => $value - ]; - } - - /** - * Checks if we should return vcard in cal wrapper + * @param string $value The value to decode * - * @return bool + * @return string decoded */ - protected function shouldAttachmentBeCal() + private function decode($value) { - $browser = $this->getUserAgent(); - - $matches = []; - preg_match('/os (\d+)_(\d+)\s+/', $browser, $matches); - $version = isset($matches[1]) ? ((int)$matches[1]) : 999; - - return ($version < 8); + // convert cyrlic, greek or other caracters to ASCII characters + return Transliterator::transliterate($value); } }