vcf importer pre alpha. Import working but contact pictures are not saved.
This commit is contained in:
44
php/download.php
Normal file
44
php/download.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* download.php, zarafa contact to vcf im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
$basedir = $_GET["basedir"];
|
||||
$secid = $_GET["secid"];
|
||||
$fileid = $_GET["fileid"];
|
||||
$realname = $_GET["realname"];
|
||||
|
||||
$secfile = $basedir . "/secid." . $secid;
|
||||
$vcffile = $basedir . "/" . $fileid . "." . $secid;
|
||||
|
||||
// if the secid file exists -> download!
|
||||
if(file_exists($secfile)) {
|
||||
@header("Last-Modified: " . @gmdate("D, d M Y H:i:s",time()) . " GMT");
|
||||
@header("Content-type: text/vcard");
|
||||
header("Content-Length: " . filesize($vcffile));
|
||||
header("Content-Disposition: attachment; filename=" . $realname . ".vcf");
|
||||
|
||||
//write vcf
|
||||
readfile($vcffile);
|
||||
unlink($secfile);
|
||||
unlink($vcffile);
|
||||
}
|
||||
|
||||
?>
|
594
php/module.contact.php
Normal file
594
php/module.contact.php
Normal file
@@ -0,0 +1,594 @@
|
||||
<?php
|
||||
/**
|
||||
* class.calendar.php, zarafa contact to vcf im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
include_once('vcf/class.vCard.php');
|
||||
|
||||
class ContactModule extends Module {
|
||||
|
||||
private $DEBUG = true; // enable error_log debugging
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param $id
|
||||
* @param $data
|
||||
*/
|
||||
public function __construct($id, $data) {
|
||||
parent::Module($id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all the actions in the $data variable.
|
||||
* Exception part is used for authentication errors also
|
||||
* @return boolean true on success or false on failure.
|
||||
*/
|
||||
public function execute() {
|
||||
$result = false;
|
||||
|
||||
if(!$this->DEBUG) {
|
||||
/* disable error printing - otherwise json communication might break... */
|
||||
ini_set('display_errors', '0');
|
||||
}
|
||||
|
||||
foreach($this->data as $actionType => $actionData) {
|
||||
if(isset($actionType)) {
|
||||
try {
|
||||
if($this->DEBUG) {
|
||||
error_log("exec: " . $actionType);
|
||||
}
|
||||
switch($actionType) {
|
||||
case "export":
|
||||
$result = $this->exportCalendar($actionType, $actionData);
|
||||
break;
|
||||
case "import":
|
||||
$result = $this->importContacts($actionType, $actionData);
|
||||
break;
|
||||
case "addattachment":
|
||||
$result = $this->addAttachment($actionType, $actionData);
|
||||
break;
|
||||
case "attachmentpath":
|
||||
$result = $this->getAttachmentPath($actionType, $actionData);
|
||||
break;
|
||||
default:
|
||||
$this->handleUnknownActionType($actionType);
|
||||
}
|
||||
|
||||
} catch (MAPIException $e) {
|
||||
if($this->DEBUG) {
|
||||
error_log("mapi exception: " . $e->getMessage());
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
if($this->DEBUG) {
|
||||
error_log("exception: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random string with variable length.
|
||||
* @param $length the lenght of the generated string
|
||||
* @return string a random string
|
||||
*/
|
||||
private function randomstring($length = 6) {
|
||||
// $chars - all allowed charakters
|
||||
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
|
||||
srand((double)microtime()*1000000);
|
||||
$i = 0;
|
||||
$pass = "";
|
||||
while ($i < $length) {
|
||||
$num = rand() % strlen($chars);
|
||||
$tmp = substr($chars, $num, 1);
|
||||
$pass = $pass . $tmp;
|
||||
$i++;
|
||||
}
|
||||
return $pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the secid file (used to verify the download path)
|
||||
* @param $secid the secid, a random security token
|
||||
*/
|
||||
private function createSecIDFile($secid) {
|
||||
$lockFile = TMP_PATH . "/secid." . $secid;
|
||||
$fh = fopen($lockFile, 'w') or die("can't open secid file");
|
||||
$stringData = date(DATE_RFC822);
|
||||
fwrite($fh, $stringData);
|
||||
fclose($fh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the secid file (used to verify the download path)
|
||||
* @param $time a timestamp
|
||||
* @param $incl_time true if date should include time
|
||||
* @ return date object
|
||||
*/
|
||||
private function getIcalDate($time, $incl_time = true) {
|
||||
return $incl_time ? date('Ymd\THis', $time) : date('Ymd', $time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an attachment to the give contact
|
||||
* @param $actionType
|
||||
* @param $actionData
|
||||
*/
|
||||
private function addAttachment($actionType, $actionData) {
|
||||
// Get Attachment data from state
|
||||
$attachment_state = new AttachmentState();
|
||||
$attachment_state->open();
|
||||
|
||||
$filename = "ContactPicture.jpg";
|
||||
$tmppath = $actionData["tmpfile"];
|
||||
$filesize = filesize($tmppath);
|
||||
$f = getimagesize($tmppath);
|
||||
$filetype = $f["mime"];
|
||||
|
||||
// Move the uploaded file into the attachment state
|
||||
$attachid = $attachment_state->addProvidedAttachmentFile($actionData["storeid"], $filename, $tmppath, array(
|
||||
"name" => $filename,
|
||||
"size" => $filesize,
|
||||
"type" => $filetype,
|
||||
"sourcetype" => 'default'
|
||||
));
|
||||
|
||||
$attachment_state->close();
|
||||
|
||||
$response['status'] = true;
|
||||
$response['storeid'] = $actionData["storeid"];
|
||||
$response['tmpname'] = $attachid;
|
||||
$response['name'] = $filename;
|
||||
$response['size'] = $filesize;
|
||||
$response['type'] = $filetype;
|
||||
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
}
|
||||
|
||||
/**
|
||||
* The main export function, creates the ics file for download
|
||||
* @param $actionType
|
||||
* @param $actionData
|
||||
*/
|
||||
private function exportContacts($actionType, $actionData) {
|
||||
$secid = $this->randomstring();
|
||||
$this->createSecIDFile($secid);
|
||||
$tmpname = stripslashes($actionData["calendar"] . ".ics." . $this->randomstring(8));
|
||||
$filename = TMP_PATH . "/" . $tmpname . "." . $secid;
|
||||
|
||||
if(!is_writable(TMP_PATH . "/")) {
|
||||
error_log("could not write to export tmp directory!");
|
||||
}
|
||||
|
||||
$tz = date("e"); // use php timezone (maybe set up in php.ini, date.timezone)
|
||||
|
||||
if($this->DEBUG) {
|
||||
error_log("PHP Timezone: " . $tz);
|
||||
}
|
||||
|
||||
$config = array(
|
||||
"language" => substr($GLOBALS["settings"]->get("zarafa/v1/main/language"),0,2),
|
||||
"directory" => TMP_PATH . "/",
|
||||
"filename" => $tmpname . "." . $secid,
|
||||
"unique_id" => "zarafa-export-plugin",
|
||||
"TZID" => $tz
|
||||
);
|
||||
|
||||
$v = new vcalendar($config);
|
||||
$v->setProperty("method", "PUBLISH"); // required of some calendar software
|
||||
$v->setProperty("x-wr-calname", $actionData["calendar"]); // required of some calendar software
|
||||
$v->setProperty("X-WR-CALDESC", "Exported Zarafa Calendar"); // required of some calendar software
|
||||
$v->setProperty("X-WR-TIMEZONE", $tz);
|
||||
|
||||
$xprops = array("X-LIC-LOCATION" => $tz); // required of some calendar software
|
||||
iCalUtilityFunctions::createTimezone($v, $tz, $xprops); // create timezone object in calendar
|
||||
|
||||
|
||||
foreach($actionData["data"] as $event) {
|
||||
$event["props"]["description"] = $this->loadEventDescription($event);
|
||||
$event["props"]["attendees"] = $this->loadAttendees($event);
|
||||
|
||||
$vevent = & $v->newComponent("vevent"); // create a new event object
|
||||
$this->addEvent($vevent, $event["props"]);
|
||||
}
|
||||
|
||||
$v->saveCalendar();
|
||||
|
||||
$response['status'] = true;
|
||||
$response['fileid'] = $tmpname; // number of entries that will be exported
|
||||
$response['basedir'] = TMP_PATH;
|
||||
$response['secid'] = $secid;
|
||||
$response['realname'] = $actionData["calendar"];
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
|
||||
if($this->DEBUG) {
|
||||
error_log("export done, bus data written!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main import function, parses the uploaded vcf file
|
||||
* @param $actionType
|
||||
* @param $actionData
|
||||
*/
|
||||
private function importContacts($actionType, $actionData) {
|
||||
if($this->DEBUG) {
|
||||
error_log("PHP Timezone: " . $tz);
|
||||
}
|
||||
|
||||
if(is_readable ($actionData["vcf_filepath"])) {
|
||||
$vcard = new vCard($actionData["vcf_filepath"], false, array('Collapse' => false)); // Parse it!
|
||||
error_log(print_r($vcard, true));
|
||||
if(count($vcard) == 0) {
|
||||
$response['status'] = false;
|
||||
$response['message']= "No contacts in vcf file";
|
||||
} else {
|
||||
$vCard = $vcard;
|
||||
if (count($vCard) == 1) {
|
||||
$vCard = array($vcard);
|
||||
}
|
||||
|
||||
$response['status'] = true;
|
||||
$response['parsed_file']= $actionData["vcf_filepath"];
|
||||
$response['parsed'] = array (
|
||||
'contacts' => $this->parseContactsToArray($vCard)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$response['status'] = false;
|
||||
$response['message']= "File could not be read by server";
|
||||
}
|
||||
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
|
||||
if($this->DEBUG) {
|
||||
error_log("parsing done, bus data written!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a array with contacts
|
||||
*
|
||||
* @param contacts vcard or csv contacts
|
||||
* @param csv optional, true if contacts are csv contacts
|
||||
* @return array parsed contacts
|
||||
* @private
|
||||
*/
|
||||
private function parseContactsToArray($contacts, $csv = false) {
|
||||
$carr = array();
|
||||
if(!$csv) {
|
||||
foreach ($contacts as $Index => $vCard) {
|
||||
$properties = array();
|
||||
$properties["display_name"] = $vCard -> FN[0];
|
||||
$properties["fileas"] = $vCard -> FN[0];
|
||||
|
||||
foreach ($vCard -> N as $Name) {
|
||||
$properties["given_name"] = $Name['FirstName'];
|
||||
$properties["middle_name"] = $Name['AdditionalNames'];
|
||||
$properties["surname"] = $Name['LastName'];
|
||||
$properties["display_name_prefix"] = $Name['Prefixes'];
|
||||
}
|
||||
if ($vCard -> TEL) {
|
||||
foreach ($vCard -> TEL as $Tel) {
|
||||
if(!is_scalar($Tel)) {
|
||||
if(in_array("home", $Tel['Type'])) {
|
||||
$properties["home_telephone_number"] = $Tel['Value'];
|
||||
} else if(in_array("cell", $Tel['Type'])) {
|
||||
$properties["cellular_telephone_number"] = $Tel['Value'];
|
||||
} else if(in_array("work", $Tel['Type'])) {
|
||||
$properties["business_telephone_number"] = $Tel['Value'];
|
||||
} else if(in_array("fax", $Tel['Type'])) {
|
||||
$properties["business_fax_number"] = $Tel['Value'];
|
||||
} else if(in_array("pager", $Tel['Type'])) {
|
||||
$properties["pager_telephone_number"] = $Tel['Value'];
|
||||
} else if(in_array("isdn", $Tel['Type'])) {
|
||||
$properties["isdn_number"] = $Tel['Value'];
|
||||
} else if(in_array("car", $Tel['Type'])) {
|
||||
$properties["car_telephone_number"] = $Tel['Value'];
|
||||
} else if(in_array("modem", $Tel['Type'])) {
|
||||
$properties["ttytdd_telephone_number"] = $Tel['Value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($vCard -> EMAIL) {
|
||||
$e=0;
|
||||
foreach ($vCard -> EMAIL as $Email) {
|
||||
$fileas = $Email['Value'];
|
||||
if(isset($properties["fileas"]) && !empty($properties["fileas"])) {
|
||||
$fileas = $properties["fileas"];
|
||||
}
|
||||
|
||||
if(!is_scalar($Email)) {
|
||||
switch($e) {
|
||||
case 0:
|
||||
$properties["email_address_1"] = $Email['Value'];
|
||||
$properties["email_address_display_name_1"] = $fileas . " (" . $Email['Value'] . ")";
|
||||
break;
|
||||
case 1:
|
||||
$properties["email_address_2"] = $Email['Value'];
|
||||
$properties["email_address_display_name_2"] = $fileas . " (" . $Email['Value'] . ")";
|
||||
break;
|
||||
case 2:
|
||||
$properties["email_address_3"] = $Email['Value'];
|
||||
$properties["email_address_display_name_3"] = $fileas . " (" . $Email['Value'] . ")";
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
$e++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($vCard -> ORG) {
|
||||
foreach ($vCard -> ORG as $Organization) {
|
||||
$properties["company_name"] = $Organization['Name'];
|
||||
if(empty($properties["display_name"])) {
|
||||
$properties["display_name"] = $Organization['Name']; // if we have no displayname - use the company name as displayname
|
||||
$properties["fileas"] = $Organization['Name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($vCard -> TITLE) {
|
||||
$properties["title"] = $vCard -> TITLE[0];
|
||||
}
|
||||
if ($vCard -> URL) {
|
||||
$properties["webpage"] = $vCard -> URL[0];
|
||||
}
|
||||
if ($vCard -> IMPP) {
|
||||
foreach ($vCard -> IMPP as $IMPP) {
|
||||
if (!is_scalar($IMPP)) {
|
||||
$properties["im"] = $IMPP['Value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($vCard -> ADR) {
|
||||
foreach ($vCard -> ADR as $Address) {
|
||||
if(in_array("work", $Address['Type'])) {
|
||||
$properties["business_address_street"] = $Address['StreetAddress'];
|
||||
$properties["business_address_city"] = $Address['Locality'];
|
||||
$properties["business_address_state"] = $Address['Region'];
|
||||
$properties["business_address_postal_code"] = $Address['PostalCode'];
|
||||
$properties["business_address_country"] = $Address['Country'];
|
||||
$properties["business_address"] = $this->buildAddressString($Address['StreetAddress'], $Address['PostalCode'], $Address['Locality'], $Address['Region'], $Address['Country']);
|
||||
} else if(in_array("home", $Address['Type'])) {
|
||||
$properties["home_address_street"] = $Address['StreetAddress'];
|
||||
$properties["home_address_city"] = $Address['Locality'];
|
||||
$properties["home_address_state"] = $Address['Region'];
|
||||
$properties["home_address_postal_code"] = $Address['PostalCode'];
|
||||
$properties["home_address_country"] = $Address['Country'];
|
||||
$properties["home_address"] = $this->buildAddressString($Address['StreetAddress'], $Address['PostalCode'], $Address['Locality'], $Address['Region'], $Address['Country']);
|
||||
} else if(in_array("postal", $Address['Type'])||in_array("parcel", $Address['Type'])||in_array("intl", $Address['Type'])||in_array("dom", $Address['Type'])) {
|
||||
$properties["other_address_street"] = $Address['StreetAddress'];
|
||||
$properties["other_address_city"] = $Address['Locality'];
|
||||
$properties["other_address_state"] = $Address['Region'];
|
||||
$properties["other_address_postal_code"] = $Address['PostalCode'];
|
||||
$properties["other_address_country"] = $Address['Country'];
|
||||
$properties["other_address"] = $this->buildAddressString($Address['StreetAddress'], $Address['PostalCode'], $Address['Locality'], $Address['Region'], $Address['Country']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($vCard -> BDAY) {
|
||||
$properties["birthday"] = strtotime($vCard -> BDAY[0]);
|
||||
}
|
||||
if ($vCard -> NOTE) {
|
||||
$properties["body"] = $vCard -> NOTE[0];
|
||||
}
|
||||
if ($vCard -> PHOTO) {
|
||||
if(!is_writable(TMP_PATH . "/")) {
|
||||
error_log("could not write to export tmp directory!: " . $E);
|
||||
} else {
|
||||
$tmppath = TMP_PATH . "/" . $this->randomstring(15);
|
||||
try {
|
||||
if($vCard -> SaveFile('photo', 0, $tmppath)) {
|
||||
$properties["x_photo_path"] = $tmppath;
|
||||
} else {
|
||||
if($this->DEBUG) {
|
||||
error_log("remote imagefetching not implemented");
|
||||
}
|
||||
}
|
||||
} catch (Exception $E) {
|
||||
error_log("Image exception: " . $E);
|
||||
}
|
||||
}
|
||||
}
|
||||
array_push($carr, $properties);
|
||||
}
|
||||
} else {
|
||||
error_log("csv parsing not implemented");
|
||||
}
|
||||
|
||||
return $carr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the whole addressstring
|
||||
*
|
||||
* @param street
|
||||
* @param zip
|
||||
* @param city
|
||||
* @param state
|
||||
* @param country
|
||||
* @return string the concatinated address string
|
||||
* @private
|
||||
*/
|
||||
private function buildAddressString($street, $zip, $city, $state, $country) {
|
||||
$out = "";
|
||||
|
||||
if (isset($country) && $street != "") $out = $country;
|
||||
|
||||
$zcs = "";
|
||||
if (isset($zip) && $zip != "") $zcs = $zip;
|
||||
if (isset($city) && $city != "") $zcs .= (($zcs)?" ":"") . $city;
|
||||
if (isset($state) && $state != "") $zcs .= (($zcs)?" ":"") . $state;
|
||||
if ($zcs) $out = $zcs . "\r\n" . $out;
|
||||
|
||||
if (isset($street) && $street != "") $out = $street . (($out)?"\r\n". $out: "") ;
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the file to a temporary directory, prepare it for oc upload
|
||||
* @param $actionType
|
||||
* @param $actionData
|
||||
* @private
|
||||
*/
|
||||
private function getAttachmentPath($actionType, $actionData) {
|
||||
// Get store id
|
||||
$storeid = false;
|
||||
if(isset($actionData["store"])) {
|
||||
$storeid = $actionData["store"];
|
||||
}
|
||||
|
||||
// Get message entryid
|
||||
$entryid = false;
|
||||
if(isset($actionData["entryid"])) {
|
||||
$entryid = $actionData["entryid"];
|
||||
}
|
||||
|
||||
// Check which type isset
|
||||
$openType = "attachment";
|
||||
|
||||
// Get number of attachment which should be opened.
|
||||
$attachNum = false;
|
||||
if(isset($actionData["attachNum"])) {
|
||||
$attachNum = $actionData["attachNum"];
|
||||
}
|
||||
|
||||
// Check if storeid and entryid isset
|
||||
if($storeid && $entryid) {
|
||||
// Open the store
|
||||
$store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
|
||||
|
||||
if($store) {
|
||||
// Open the message
|
||||
$message = mapi_msgstore_openentry($store, hex2bin($entryid));
|
||||
|
||||
if($message) {
|
||||
$attachment = false;
|
||||
|
||||
// Check if attachNum isset
|
||||
if($attachNum) {
|
||||
// Loop through the attachNums, message in message in message ...
|
||||
for($i = 0; $i < (count($attachNum) - 1); $i++)
|
||||
{
|
||||
// Open the attachment
|
||||
$tempattach = mapi_message_openattach($message, (int) $attachNum[$i]);
|
||||
if($tempattach) {
|
||||
// Open the object in the attachment
|
||||
$message = mapi_attach_openobj($tempattach);
|
||||
}
|
||||
}
|
||||
|
||||
// Open the attachment
|
||||
$attachment = mapi_message_openattach($message, (int) $attachNum[(count($attachNum) - 1)]);
|
||||
}
|
||||
|
||||
// Check if the attachment is opened
|
||||
if($attachment) {
|
||||
|
||||
// Get the props of the attachment
|
||||
$props = mapi_attach_getprops($attachment, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_MIME_TAG, PR_DISPLAY_NAME, PR_ATTACH_METHOD));
|
||||
// Content Type
|
||||
$contentType = "application/octet-stream";
|
||||
// Filename
|
||||
$filename = "ERROR";
|
||||
|
||||
// Set filename
|
||||
if(isset($props[PR_ATTACH_LONG_FILENAME])) {
|
||||
$filename = $props[PR_ATTACH_LONG_FILENAME];
|
||||
} else if(isset($props[PR_ATTACH_FILENAME])) {
|
||||
$filename = $props[PR_ATTACH_FILENAME];
|
||||
} else if(isset($props[PR_DISPLAY_NAME])) {
|
||||
$filename = $props[PR_DISPLAY_NAME];
|
||||
}
|
||||
|
||||
// Set content type
|
||||
if(isset($props[PR_ATTACH_MIME_TAG])) {
|
||||
$contentType = $props[PR_ATTACH_MIME_TAG];
|
||||
} else {
|
||||
// Parse the extension of the filename to get the content type
|
||||
if(strrpos($filename, ".") !== false) {
|
||||
$extension = strtolower(substr($filename, strrpos($filename, ".")));
|
||||
$contentType = "application/octet-stream";
|
||||
if (is_readable("mimetypes.dat")){
|
||||
$fh = fopen("mimetypes.dat","r");
|
||||
$ext_found = false;
|
||||
while (!feof($fh) && !$ext_found){
|
||||
$line = fgets($fh);
|
||||
preg_match("/(\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i", $line, $result);
|
||||
if ($extension == $result[1]){
|
||||
$ext_found = true;
|
||||
$contentType = $result[2];
|
||||
}
|
||||
}
|
||||
fclose($fh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$tmpname = tempnam(TMP_PATH, stripslashes($filename));
|
||||
|
||||
// Open a stream to get the attachment data
|
||||
$stream = mapi_openpropertytostream($attachment, PR_ATTACH_DATA_BIN);
|
||||
$stat = mapi_stream_stat($stream);
|
||||
// File length = $stat["cb"]
|
||||
|
||||
$fhandle = fopen($tmpname,'w');
|
||||
$buffer = null;
|
||||
for($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) {
|
||||
// Write stream
|
||||
$buffer = mapi_stream_read($stream, BLOCK_SIZE);
|
||||
fwrite($fhandle,$buffer,strlen($buffer));
|
||||
}
|
||||
fclose($fhandle);
|
||||
|
||||
$response = array();
|
||||
$response['tmpname'] = $tmpname;
|
||||
$response['filename'] = $filename;
|
||||
$response['status'] = true;
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$response['status'] = false;
|
||||
$response['message'] = "Store could not be opened!";
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
}
|
||||
} else {
|
||||
$response['status'] = false;
|
||||
$response['message'] = "Wrong call, store and entryid have to be set!";
|
||||
$this->addActionData($actionType, $response);
|
||||
$GLOBALS["bus"]->addData($this->getResponseData());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
81
php/plugin.contactimporter.php
Normal file
81
php/plugin.contactimporter.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* plugin.contactimporter.php, zarafa contact to vcf im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* contactimporter Plugin
|
||||
*
|
||||
* With this plugin you can import a vcf file to your zarafa addressbook
|
||||
*
|
||||
*/
|
||||
class Plugincontactimporter extends Plugin {
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function Plugincontactimporter() {}
|
||||
|
||||
/**
|
||||
* Function initializes the Plugin and registers all hooks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function init() {
|
||||
$this->registerHook('server.core.settings.init.before');
|
||||
}
|
||||
|
||||
/**
|
||||
* Function is executed when a hook is triggered by the PluginManager
|
||||
*
|
||||
* @param string $eventID the id of the triggered hook
|
||||
* @param mixed $data object(s) related to the hook
|
||||
* @return void
|
||||
*/
|
||||
function execute($eventID, &$data) {
|
||||
switch($eventID) {
|
||||
case 'server.core.settings.init.before' :
|
||||
$this->injectPluginSettings($data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the core Settings class is initialized and ready to accept sysadmin default
|
||||
* settings.
|
||||
* @param Array $data Reference to the data of the triggered hook
|
||||
*/
|
||||
function injectPluginSettings(&$data) {
|
||||
$data['settingsObj']->addSysAdminDefaults(Array(
|
||||
'zarafa' => Array(
|
||||
'v1' => Array(
|
||||
'plugins' => Array(
|
||||
'contactimporter' => Array(
|
||||
'enable' => PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE,
|
||||
'enable_export' => PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE_EXPORT,
|
||||
'default_addressbook' => PLUGIN_CONTACTIMPORTER_DEFAULT
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
?>
|
72
php/upload.php
Normal file
72
php/upload.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* upload.php, zarafa contact to vcf im/exporter
|
||||
*
|
||||
* Author: Christoph Haas <christoph.h@sprinternet.at>
|
||||
* Copyright (C) 2012-2013 Christoph Haas
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
require_once("../config.php");
|
||||
|
||||
/* disable error printing - otherwise json communication might break... */
|
||||
ini_set('display_errors', '0');
|
||||
|
||||
/**
|
||||
* respond/echo JSON
|
||||
* @param $arr
|
||||
*/
|
||||
function respondJSON($arr) {
|
||||
echo json_encode($arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random string with variable length.
|
||||
* @param $length the lenght of the generated string
|
||||
* @return string a random string
|
||||
*/
|
||||
function randomstring($length = 6) {
|
||||
// $chars - all allowed charakters
|
||||
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
|
||||
srand((double)microtime()*1000000);
|
||||
$i = 0;
|
||||
$pass = "";
|
||||
while ($i < $length) {
|
||||
$num = rand() % strlen($chars);
|
||||
$tmp = substr($chars, $num, 1);
|
||||
$pass = $pass . $tmp;
|
||||
$i++;
|
||||
}
|
||||
return $pass;
|
||||
}
|
||||
|
||||
$destpath = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD;
|
||||
$destpath .= $_FILES['vcfdata']['name'] . randomstring();
|
||||
|
||||
if(is_readable ($_FILES['vcfdata']['tmp_name'])) {
|
||||
$result = move_uploaded_file($_FILES['vcfdata']['tmp_name'],$destpath);
|
||||
|
||||
if($result) {
|
||||
respondJSON(array ('success'=>true, 'vcf_file'=>$destpath));
|
||||
} else {
|
||||
respondJSON(array ('success'=>false,'error'=>"File could not be moved to TMP path! Check plugin config and folder permissions!"));
|
||||
}
|
||||
} else {
|
||||
respondJSON(array ('success'=>false,'error'=>"File could not be read by server, upload error!"));
|
||||
}
|
||||
?>
|
410
php/vcf/Herr test of master jun .vcf
Normal file
410
php/vcf/Herr test of master jun .vcf
Normal file
@@ -0,0 +1,410 @@
|
||||
BEGIN:VCARD
|
||||
VERSION:2.1
|
||||
N;LANGUAGE=de:master;test;of;Herr;jun.
|
||||
FN:Herr test of master jun.
|
||||
ORG:testcomp;Abteilung X
|
||||
TITLE:chef
|
||||
TEL;WORK;VOICE:123456
|
||||
TEL;HOME;VOICE:234567
|
||||
TEL;CELL;VOICE:456789
|
||||
ADR;WORK:;;test 1;entenh;tirol;789;Albanien
|
||||
LABEL;WORK;ENCODING=QUOTED-PRINTABLE:test 1=0D=0A=
|
||||
789 entenh tirol=0D=0A=
|
||||
Albanien
|
||||
ADR;HOME;PREF:;;priv 2;sepplh;vorarlberg;213;Anguilla
|
||||
LABEL;HOME;PREF;ENCODING=QUOTED-PRINTABLE:priv 2=0D=0A=
|
||||
213 sepplh vorarlberg=0D=0A=
|
||||
Anguilla
|
||||
ADR;POSTAL:;;other 4;saadsf;addsag;5649;Brasilien
|
||||
LABEL;POSTAL;ENCODING=QUOTED-PRINTABLE:other 4=0D=0A=
|
||||
saadsf - addsag=0D=0A=
|
||||
Brasilien=0D=0A=
|
||||
5649
|
||||
X-MS-OL-DEFAULT-POSTAL-ADDRESS:1
|
||||
URL;WORK:www.google.at
|
||||
EMAIL;PREF;INTERNET:email1@at.e
|
||||
EMAIL;INTERNET:email2@at.e
|
||||
EMAIL;INTERNET:email3@at.e
|
||||
PHOTO;TYPE=JPEG;ENCODING=BASE64:
|
||||
/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgK
|
||||
CgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkL
|
||||
EBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAAR
|
||||
CAE6AToDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAA
|
||||
AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK
|
||||
FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG
|
||||
h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl
|
||||
5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREA
|
||||
AgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYk
|
||||
NOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE
|
||||
hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk
|
||||
5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5+m0rBwBg5qhNp8yngj8K799K3jOBz2xV
|
||||
ebQXc5VP0r4eNdLc/G5Ybm1Rwf2aVRhlPFKIWxgiu0bw+2eV5+lVrjQnTlV/KtFWTOaWHlA5
|
||||
B4yjHAqPOOtdFNosgPKVRudMZAcjH4Vqqi2OZp31Mrfk4FOVsMM1K8BVsY/CnR2rEZOarmQJ
|
||||
DlQhQ2epweKejBRjNPCAIBxSbCQcHPNDYcutkTW7ljsJrTgwQD6Gs22jKt05rYs7dnAIH4VE
|
||||
pFKnIfGApyo61ZRnByD+VTR2DZyVxmriWJYYIrmlNdTojSdhdPZtwLN7DntXfaDMgRZHbqAO
|
||||
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
|
||||
XX3YBDZA71mlVz90flVRbQToxZ//2Q==
|
||||
|
||||
X-MS-OL-DESIGN;CHARSET=utf-8:<card xmlns="http://schemas.microsoft.com/office/outlook/12/electronicbusinesscards" ver="1.0" layout="left" bgcolor="ffffff"><img xmlns="" align="tleft" area="32" use="photo"/><fld xmlns="" prop="name" align="left" dir="ltr" style="b" color="000000" size="10"/><fld xmlns="" prop="org" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="title" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="dept" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="telwork" align="left" dir="ltr" color="000000" size="8"><label align="right" color="626262">Geschäftlich</label></fld><fld xmlns="" prop="telcell" align="left" dir="ltr" color="000000" size="8"><label align="right" color="626262">Mobiltelefon</label></fld><fld xmlns="" prop="telhome" align="left" dir="ltr" color="000000" size="8"><label align="right" color="626262">Privat</label></fld><fld xmlns="" prop="email" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="email2" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="email3" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="addrhome" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="addrwork" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="addrother" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="webwork" align="left" dir="ltr" color="000000" size="8"/><fld xmlns="" prop="blank" size="8"/><fld xmlns="" prop="blank" size="8"/></card>
|
||||
REV:20130520T141721Z
|
||||
END:VCARD
|
690
php/vcf/class.vCard.php
Normal file
690
php/vcf/class.vCard.php
Normal file
@@ -0,0 +1,690 @@
|
||||
<?php
|
||||
/**
|
||||
* vCard class for parsing a vCard and/or creating one
|
||||
*
|
||||
* @link https://github.com/nuovo/vCard-parser
|
||||
* @author Martins Pilsetnieks, Roberts Bruveris
|
||||
* @see RFC 2426, RFC 2425
|
||||
* @version 0.4.8
|
||||
*/
|
||||
|
||||
class vCard implements Countable, Iterator
|
||||
{
|
||||
const MODE_ERROR = 'error';
|
||||
const MODE_SINGLE = 'single';
|
||||
const MODE_MULTIPLE = 'multiple';
|
||||
|
||||
const endl = "\n";
|
||||
|
||||
/**
|
||||
* @var string Current object mode - error, single or multiple (for a single vCard within a file and multiple combined vCards)
|
||||
*/
|
||||
private $Mode; //single, multiple, error
|
||||
|
||||
private $Path = '';
|
||||
private $RawData = '';
|
||||
|
||||
/**
|
||||
* @var array Internal options container. Options:
|
||||
* bool Collapse: If true, elements that can have multiple values but have only a single value are returned as that value instead of an array
|
||||
* If false, an array is returned even if it has only one value.
|
||||
*/
|
||||
private $Options = array(
|
||||
'Collapse' => false
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array Internal data container. Contains vCard objects for multiple vCards and just the data for single vCards.
|
||||
*/
|
||||
private $Data = array();
|
||||
|
||||
/**
|
||||
* @static Parts of structured elements according to the spec.
|
||||
*/
|
||||
private static $Spec_StructuredElements = array(
|
||||
'n' => array('LastName', 'FirstName', 'AdditionalNames', 'Prefixes', 'Suffixes'),
|
||||
'adr' => array('POBox', 'ExtendedAddress', 'StreetAddress', 'Locality', 'Region', 'PostalCode', 'Country'),
|
||||
'geo' => array('Latitude', 'Longitude'),
|
||||
'org' => array('Name', 'Unit1', 'Unit2')
|
||||
);
|
||||
private static $Spec_MultipleValueElements = array('nickname', 'categories');
|
||||
|
||||
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'),
|
||||
'impp' => array('personal', 'business', 'home', 'work', 'mobile', 'pref')
|
||||
);
|
||||
|
||||
private static $Spec_FileElements = array('photo', 'logo', 'sound');
|
||||
|
||||
/**
|
||||
* vCard constructor
|
||||
*
|
||||
* @param string Path to file, optional.
|
||||
* @param string Raw data, optional.
|
||||
* @param array Additional options, optional. Currently supported options:
|
||||
* bool Collapse: If true, elements that can have multiple values but have only a single value are returned as that value instead of an array
|
||||
* If false, an array is returned even if it has only one value.
|
||||
*
|
||||
* One of these parameters must be provided, otherwise an exception is thrown.
|
||||
*/
|
||||
public function __construct($Path = false, $RawData = false, array $Options = null)
|
||||
{
|
||||
// Checking preconditions for the parser.
|
||||
// If path is given, the file should be accessible.
|
||||
// If raw data is given, it is taken as it is.
|
||||
// In both cases the real content is put in $this -> RawData
|
||||
if ($Path)
|
||||
{
|
||||
if (!is_readable($Path))
|
||||
{
|
||||
throw new Exception('vCard: Path not accessible ('.$Path.')');
|
||||
}
|
||||
|
||||
$this -> Path = $Path;
|
||||
$this -> RawData = file_get_contents($this -> Path);
|
||||
}
|
||||
elseif ($RawData)
|
||||
{
|
||||
$this -> RawData = $RawData;
|
||||
}
|
||||
else
|
||||
{
|
||||
//throw new Exception('vCard: No content provided');
|
||||
// Not necessary anymore as possibility to create vCards is added
|
||||
}
|
||||
|
||||
if (!$this -> Path && !$this -> RawData)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($Options)
|
||||
{
|
||||
$this -> Options = array_merge($this -> Options, $Options);
|
||||
}
|
||||
|
||||
// Counting the begin/end separators. If there aren't any or the count doesn't match, there is a problem with the file.
|
||||
// If there is only one, this is a single vCard, if more, multiple vCards are combined.
|
||||
$Matches = array();
|
||||
$vCardBeginCount = preg_match_all('{^BEGIN\:VCARD}miS', $this -> RawData, $Matches);
|
||||
$vCardEndCount = preg_match_all('{^END\:VCARD}miS', $this -> RawData, $Matches);
|
||||
|
||||
if (($vCardBeginCount != $vCardEndCount) || !$vCardBeginCount)
|
||||
{
|
||||
$this -> Mode = vCard::MODE_ERROR;
|
||||
throw new Exception('vCard: invalid vCard');
|
||||
}
|
||||
|
||||
$this -> Mode = $vCardBeginCount == 1 ? vCard::MODE_SINGLE : vCard::MODE_MULTIPLE;
|
||||
|
||||
// Removing/changing inappropriate newlines, i.e., all CRs or multiple newlines are changed to a single newline
|
||||
$this -> RawData = str_replace("\r", "\n", $this -> RawData);
|
||||
$this -> RawData = preg_replace('{(\n+)}', "\n", $this -> RawData);
|
||||
|
||||
// In multiple card mode the raw text is split at card beginning markers and each
|
||||
// fragment is parsed in a separate vCard object.
|
||||
if ($this -> Mode == self::MODE_MULTIPLE)
|
||||
{
|
||||
$this -> RawData = explode('BEGIN:VCARD', $this -> RawData);
|
||||
$this -> RawData = array_filter($this -> RawData);
|
||||
|
||||
foreach ($this -> RawData as $SinglevCardRawData)
|
||||
{
|
||||
// Prepending "BEGIN:VCARD" to the raw string because we exploded on that one.
|
||||
// If there won't be the BEGIN marker in the new object, it will fail.
|
||||
$SinglevCardRawData = 'BEGIN:VCARD'."\n".$SinglevCardRawData;
|
||||
|
||||
$ClassName = get_class($this);
|
||||
$this -> Data[] = new $ClassName(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
|
||||
// (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);
|
||||
|
||||
// Restoring the BASE64 final equals sign (see a few lines above)
|
||||
$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.
|
||||
if (strpos($Line, ':') === false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Each line is split into two parts. The key contains the element name and additional parameters, if present,
|
||||
// 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')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((strpos($Key, 'agent') === 0) && (stripos($Value, 'begin:vcard') !== false))
|
||||
{
|
||||
$ClassName = get_class($this);
|
||||
$Value = new $ClassName(false, str_replace('-wrap-', "\n", $Value));
|
||||
if (!isset($this -> Data[$Key]))
|
||||
{
|
||||
$this -> Data[$Key] = array();
|
||||
}
|
||||
$this -> Data[$Key][] = $Value;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$Value = str_replace('-wrap-', '', $Value);
|
||||
}
|
||||
|
||||
$Value = trim(self::Unescape($Value));
|
||||
$Type = array();
|
||||
|
||||
// Here additional parameters are parsed
|
||||
$KeyParts = explode(';', $Key);
|
||||
$Key = $KeyParts[0];
|
||||
$Encoding = false;
|
||||
|
||||
if (strpos($Key, 'item') === 0)
|
||||
{
|
||||
$TmpKey = explode('.', $Key, 2);
|
||||
$Key = $TmpKey[1];
|
||||
$ItemIndex = (int)str_ireplace('item', '', $TmpKey[0]);
|
||||
}
|
||||
|
||||
if (count($KeyParts) > 1)
|
||||
{
|
||||
$Parameters = self::ParseParameters($Key, array_slice($KeyParts, 1));
|
||||
|
||||
foreach ($Parameters as $ParamKey => $ParamValue)
|
||||
{
|
||||
switch ($ParamKey)
|
||||
{
|
||||
case 'encoding':
|
||||
$Encoding = $ParamValue;
|
||||
if (in_array($ParamValue, array('b', 'base64')))
|
||||
{
|
||||
//$Value = base64_decode($Value);
|
||||
}
|
||||
elseif ($ParamValue == 'quoted-printable') // v2.1
|
||||
{
|
||||
$Value = quoted_printable_decode($Value);
|
||||
}
|
||||
break;
|
||||
case 'charset': // v2.1
|
||||
if ($ParamValue != 'utf-8' && $ParamValue != 'utf8')
|
||||
{
|
||||
$Value = mb_convert_encoding($Value, 'UTF-8', $ParamValue);
|
||||
}
|
||||
break;
|
||||
case 'type':
|
||||
$Type = $ParamValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checking files for colon-separated additional parameters (Apple's Address Book does this), for example, "X-ABCROP-RECTANGLE" for photos
|
||||
if (in_array($Key, self::$Spec_FileElements) && isset($Parameters['encoding']) && in_array($Parameters['encoding'], array('b', 'base64')))
|
||||
{
|
||||
// If colon is present in the value, it must contain Address Book parameters
|
||||
// (colon is an invalid character for base64 so it shouldn't appear in valid files)
|
||||
if (strpos($Value, ':') !== false)
|
||||
{
|
||||
$Value = explode(':', $Value);
|
||||
$Value = array_pop($Value);
|
||||
}
|
||||
}
|
||||
|
||||
// Values are parsed according to their type
|
||||
if (isset(self::$Spec_StructuredElements[$Key]))
|
||||
{
|
||||
$Value = self::ParseStructuredValue($Value, $Key);
|
||||
if ($Type)
|
||||
{
|
||||
$Value['Type'] = $Type;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (in_array($Key, self::$Spec_MultipleValueElements))
|
||||
{
|
||||
$Value = self::ParseMultipleTextValue($Value, $Key);
|
||||
}
|
||||
|
||||
if ($Type)
|
||||
{
|
||||
$Value = array(
|
||||
'Value' => $Value,
|
||||
'Type' => $Type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($Value) && $Encoding)
|
||||
{
|
||||
$Value['Encoding'] = $Encoding;
|
||||
}
|
||||
|
||||
if (!isset($this -> Data[$Key]))
|
||||
{
|
||||
$this -> Data[$Key] = array();
|
||||
}
|
||||
|
||||
$this -> Data[$Key][] = $Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to get the various vCard values as object members, e.g.
|
||||
* a call to $vCard -> N gets the "N" value
|
||||
*
|
||||
* @param string Key
|
||||
*
|
||||
* @return mixed Value
|
||||
*/
|
||||
public function __get($Key)
|
||||
{
|
||||
$Key = strtolower($Key);
|
||||
if (isset($this -> Data[$Key]))
|
||||
{
|
||||
if ($Key == 'agent')
|
||||
{
|
||||
return $this -> Data[$Key];
|
||||
}
|
||||
elseif (in_array($Key, self::$Spec_FileElements))
|
||||
{
|
||||
$Value = $this -> Data[$Key];
|
||||
foreach ($Value as $K => $V)
|
||||
{
|
||||
if (stripos($V['Value'], 'uri:') === 0)
|
||||
{
|
||||
$Value[$K]['Value'] = substr($V, 4);
|
||||
$Value[$K]['Encoding'] = 'uri';
|
||||
}
|
||||
}
|
||||
return $Value;
|
||||
}
|
||||
|
||||
if ($this -> Options['Collapse'] && is_array($this -> Data[$Key]) && (count($this -> Data[$Key]) == 1))
|
||||
{
|
||||
return $this -> Data[$Key][0];
|
||||
}
|
||||
return $this -> Data[$Key];
|
||||
}
|
||||
elseif ($Key == 'Mode')
|
||||
{
|
||||
return $this -> Mode;
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an embedded file
|
||||
*
|
||||
* @param string Key
|
||||
* @param int Index of the file, defaults to 0
|
||||
* @param string Target path where the file should be saved, including the filename
|
||||
*
|
||||
* @return bool Operation status
|
||||
*/
|
||||
public function SaveFile($Key, $Index = 0, $TargetPath = '')
|
||||
{
|
||||
if (!isset($this -> Data[$Key]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!isset($this -> Data[$Key][$Index]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returing false if it is an image URL
|
||||
if (stripos($this -> Data[$Key][$Index]['Value'], 'uri:') === 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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')
|
||||
{
|
||||
$RawContent = base64_decode($RawContent);
|
||||
}
|
||||
$Status = file_put_contents($TargetPath, $RawContent);
|
||||
return (bool)$Status;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('vCard: Cannot save file ('.$Key.'), target path not writable ('.$TargetPath.')');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method for adding data to the vCard
|
||||
*
|
||||
* @param string Key
|
||||
* @param string Method call arguments. First element is value.
|
||||
*
|
||||
* @return vCard Current object for method chaining
|
||||
*/
|
||||
public function __call($Key, $Arguments)
|
||||
{
|
||||
$Key = strtolower($Key);
|
||||
|
||||
if (!isset($this -> Data[$Key]))
|
||||
{
|
||||
$this -> Data[$Key] = array();
|
||||
}
|
||||
|
||||
$Value = isset($Arguments[0]) ? $Arguments[0] : false;
|
||||
|
||||
if (count($Arguments) > 1)
|
||||
{
|
||||
$Types = array_values(array_slice($Arguments, 1));
|
||||
|
||||
if (isset(self::$Spec_StructuredElements[$Key]) &&
|
||||
in_array($Arguments[1], self::$Spec_StructuredElements[$Key])
|
||||
)
|
||||
{
|
||||
$LastElementIndex = 0;
|
||||
|
||||
if (count($this -> Data[$Key]))
|
||||
{
|
||||
$LastElementIndex = count($this -> Data[$Key]) - 1;
|
||||
}
|
||||
|
||||
if (isset($this -> Data[$Key][$LastElementIndex]))
|
||||
{
|
||||
if (empty($this -> Data[$Key][$LastElementIndex][$Types[0]]))
|
||||
{
|
||||
$this -> Data[$Key][$LastElementIndex][$Types[0]] = $Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$LastElementIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($this -> Data[$Key][$LastElementIndex]))
|
||||
{
|
||||
$this -> Data[$Key][$LastElementIndex] = array(
|
||||
$Types[0] => $Value
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif (isset(self::$Spec_ElementTypes[$Key]))
|
||||
{
|
||||
$this -> Data[$Key][] = array(
|
||||
'Value' => $Value,
|
||||
'Type' => $Types
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif ($Value)
|
||||
{
|
||||
$this -> Data[$Key][] = $Value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method for getting vCard content out
|
||||
*
|
||||
* @return string Raw vCard content
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$Text = 'BEGIN:VCARD'.self::endl;
|
||||
$Text .= 'VERSION:3.0'.self::endl;
|
||||
|
||||
foreach ($this -> Data as $Key => $Values)
|
||||
{
|
||||
$KeyUC = strtoupper($Key);
|
||||
$Key = strtolower($Key);
|
||||
|
||||
if (in_array($KeyUC, array('PHOTO', 'VERSION')))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($Values as $Index => $Value)
|
||||
{
|
||||
$Text .= $KeyUC;
|
||||
if (is_array($Value) && isset($Value['Type']))
|
||||
{
|
||||
$Text .= ';TYPE='.self::PrepareTypeStrForOutput($Value['Type']);
|
||||
}
|
||||
$Text .= ':';
|
||||
|
||||
if (isset(self::$Spec_StructuredElements[$Key]))
|
||||
{
|
||||
$PartArray = array();
|
||||
foreach (self::$Spec_StructuredElements[$Key] as $Part)
|
||||
{
|
||||
$PartArray[] = isset($Value[$Part]) ? $Value[$Part] : '';
|
||||
}
|
||||
$Text .= implode(';', $PartArray);
|
||||
}
|
||||
elseif (is_array($Value) && isset(self::$Spec_ElementTypes[$Key]))
|
||||
{
|
||||
$Text .= $Value['Value'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$Text .= $Value;
|
||||
}
|
||||
|
||||
$Text .= self::endl;
|
||||
}
|
||||
}
|
||||
|
||||
$Text .= 'END:VCARD'.self::endl;
|
||||
return $Text;
|
||||
}
|
||||
|
||||
// !Helper methods
|
||||
|
||||
private static function PrepareTypeStrForOutput($Type)
|
||||
{
|
||||
return implode(',', array_map('strtoupper', $Type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the escaping slashes from the text.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string Text to prepare.
|
||||
*
|
||||
* @return string Resulting text.
|
||||
*/
|
||||
private static function Unescape($Text)
|
||||
{
|
||||
return str_replace(array('\:', '\;', '\,', "\n"), array(':', ';', ',', ''), $Text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Separates the various parts of a structured value according to the spec.
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param string Raw text string
|
||||
* @param string Key (e.g., N, ADR, ORG, etc.)
|
||||
*
|
||||
* @return array Parts in an associative array.
|
||||
*/
|
||||
private static function ParseStructuredValue($Text, $Key)
|
||||
{
|
||||
$Text = array_map('trim', explode(';', $Text));
|
||||
|
||||
$Result = array();
|
||||
$Ctr = 0;
|
||||
|
||||
foreach (self::$Spec_StructuredElements[$Key] as $Index => $StructurePart)
|
||||
{
|
||||
$Result[$StructurePart] = isset($Text[$Index]) ? $Text[$Index] : null;
|
||||
}
|
||||
return $Result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
private static function ParseMultipleTextValue($Text)
|
||||
{
|
||||
return explode(',', $Text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
private static function ParseParameters($Key, array $RawParams = null)
|
||||
{
|
||||
if (!$RawParams)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
// Parameters are split into (key, value) pairs
|
||||
$Parameters = array();
|
||||
foreach ($RawParams as $Item)
|
||||
{
|
||||
$Parameters[] = explode('=', strtolower($Item));
|
||||
}
|
||||
|
||||
$Type = array();
|
||||
$Result = array();
|
||||
|
||||
// And each parameter is checked whether anything can/should be done because of it
|
||||
foreach ($Parameters as $Index => $Parameter)
|
||||
{
|
||||
// Skipping empty elements
|
||||
if (!$Parameter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handling type parameters without the explicit TYPE parameter name (2.1 valid)
|
||||
if (count($Parameter) == 1)
|
||||
{
|
||||
// Checks if the type value is allowed for the specific element
|
||||
// The second part of the "if" statement means that email elements can have non-standard types (see the spec)
|
||||
if (
|
||||
(isset(self::$Spec_ElementTypes[$Key]) && in_array($Parameter[0], self::$Spec_ElementTypes[$Key])) ||
|
||||
($Key == 'email' && is_scalar($Parameter[0]))
|
||||
)
|
||||
{
|
||||
$Type[] = $Parameter[0];
|
||||
}
|
||||
}
|
||||
elseif (count($Parameter) > 2)
|
||||
{
|
||||
$TempTypeParams = self::ParseParameters($Key, explode(',', $RawParams[$Index]));
|
||||
if ($TempTypeParams['type'])
|
||||
{
|
||||
$Type = array_merge($Type, $TempTypeParams['type']);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ($Parameter[0])
|
||||
{
|
||||
case 'encoding':
|
||||
if (in_array($Parameter[1], array('quoted-printable', 'b', 'base64')))
|
||||
{
|
||||
$Result['encoding'] = $Parameter[1] == 'base64' ? 'b' : $Parameter[1];
|
||||
}
|
||||
break;
|
||||
case 'charset':
|
||||
$Result['charset'] = $Parameter[1];
|
||||
break;
|
||||
case 'type':
|
||||
$Type = array_merge($Type, explode(',', $Parameter[1]));
|
||||
break;
|
||||
case 'value':
|
||||
if (strtolower($Parameter[1]) == 'url')
|
||||
{
|
||||
$Result['encoding'] = 'uri';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$Result['type'] = $Type;
|
||||
|
||||
return $Result;
|
||||
}
|
||||
|
||||
// !Interface methods
|
||||
|
||||
// Countable interface
|
||||
public function count()
|
||||
{
|
||||
switch ($this -> Mode)
|
||||
{
|
||||
case self::MODE_ERROR:
|
||||
return 0;
|
||||
break;
|
||||
case self::MODE_SINGLE:
|
||||
return 1;
|
||||
break;
|
||||
case self::MODE_MULTIPLE:
|
||||
return count($this -> Data);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Iterator interface
|
||||
public function rewind()
|
||||
{
|
||||
reset($this -> Data);
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
return current($this -> Data);
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
return next($this -> Data);
|
||||
}
|
||||
|
||||
public function valid()
|
||||
{
|
||||
return ($this -> current() !== false);
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
return key($this -> Data);
|
||||
}
|
||||
}
|
||||
?>
|
216
php/vcf/test.php
Normal file
216
php/vcf/test.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<style type="text/css">
|
||||
body
|
||||
{
|
||||
font-family: Corbel, Arial, sans-serif;
|
||||
padding: 20px 50px;
|
||||
}
|
||||
div.Agent
|
||||
{
|
||||
padding: 20px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
img
|
||||
{
|
||||
float: right;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
require_once('class.vCard.php');
|
||||
|
||||
/**
|
||||
* Test function for vCard content output
|
||||
* @param vCard vCard object
|
||||
*/
|
||||
function OutputvCard(vCard $vCard)
|
||||
{
|
||||
echo '<h2>'.$vCard -> FN[0].'</h2>';
|
||||
|
||||
if ($vCard -> PHOTO)
|
||||
{
|
||||
foreach ($vCard -> PHOTO as $Photo)
|
||||
{
|
||||
if ($Photo['Encoding'] == 'b')
|
||||
{
|
||||
echo '<img src="data:image/'.$Photo['Type'][0].';base64,'.$Photo['Value'].'" /><br />';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<img src="'.$Photo['Value'].'" /><br />';
|
||||
}
|
||||
|
||||
/*
|
||||
// It can also be saved to a file
|
||||
try
|
||||
{
|
||||
$vCard -> SaveFile('photo', 0, 'test_image.jpg');
|
||||
// The parameters are:
|
||||
// - name of the file we want to save (photo, logo or sound)
|
||||
// - index of the file in case of multiple files (defaults to 0)
|
||||
// - target path to save to, including the filenam
|
||||
}
|
||||
catch (Exception $E)
|
||||
{
|
||||
// Target path not writable
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($vCard -> N as $Name)
|
||||
{
|
||||
echo '<h3>Name: '.$Name['FirstName'].' '.$Name['LastName'].'</h3>';
|
||||
}
|
||||
|
||||
foreach ($vCard -> ORG as $Organization)
|
||||
{
|
||||
echo '<h3>Organization: '.$Organization['Name'].
|
||||
($Organization['Unit1'] || $Organization['Unit2'] ?
|
||||
' ('.implode(', ', array($Organization['Unit1'], $Organization['Unit2'])).')' :
|
||||
''
|
||||
).'</h3>';
|
||||
}
|
||||
|
||||
if ($vCard -> TEL)
|
||||
{
|
||||
echo '<p><h4>Phone</h4>';
|
||||
foreach ($vCard -> TEL as $Tel)
|
||||
{
|
||||
if (is_scalar($Tel))
|
||||
{
|
||||
echo $Tel.'<br />';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $Tel['Value'].' ('.implode(', ', $Tel['Type']).')<br />';
|
||||
}
|
||||
}
|
||||
echo '</p>';
|
||||
}
|
||||
|
||||
if ($vCard -> EMAIL)
|
||||
{
|
||||
echo '<p><h4>Email</h4>';
|
||||
foreach ($vCard -> EMAIL as $Email)
|
||||
{
|
||||
if (is_scalar($Email))
|
||||
{
|
||||
echo $Email;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $Email['Value'].' ('.implode(', ', $Email['Type']).')<br />';
|
||||
}
|
||||
}
|
||||
echo '</p>';
|
||||
}
|
||||
|
||||
if ($vCard -> URL)
|
||||
{
|
||||
echo '<p><h4>URL</h4>';
|
||||
foreach ($vCard -> URL as $URL)
|
||||
{
|
||||
if (is_scalar($URL))
|
||||
{
|
||||
echo $URL.'<br />';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $URL['Value'].'<br />';
|
||||
}
|
||||
}
|
||||
echo '</p>';
|
||||
}
|
||||
|
||||
if ($vCard -> IMPP)
|
||||
{
|
||||
echo '<p><h4>Instant messaging</h4>';
|
||||
foreach ($vCard -> IMPP as $IMPP)
|
||||
{
|
||||
if (is_scalar($IMPP))
|
||||
{
|
||||
echo $IMPP.'<br />';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $IMPP['Value'].'<br/ >';
|
||||
}
|
||||
}
|
||||
echo '</p>';
|
||||
}
|
||||
|
||||
if ($vCard -> ADR)
|
||||
{
|
||||
foreach ($vCard -> ADR as $Address)
|
||||
{
|
||||
echo '<p><h4>Address ('.implode(', ', $Address['Type']).')</h4>';
|
||||
echo 'Street address: <strong>'.($Address['StreetAddress'] ? $Address['StreetAddress'] : '-').'</strong><br />'.
|
||||
'PO Box: <strong>'.($Address['POBox'] ? $Address['POBox'] : '-').'</strong><br />'.
|
||||
'Extended address: <strong>'.($Address['ExtendedAddress'] ? $Address['ExtendedAddress'] : '-').'</strong><br />'.
|
||||
'Locality: <strong>'.($Address['Locality'] ? $Address['Locality'] : '-').'</strong><br />'.
|
||||
'Region: <strong>'.($Address['Region'] ? $Address['Region'] : '-').'</strong><br />'.
|
||||
'ZIP/Post code: <strong>'.($Address['PostalCode'] ? $Address['PostalCode'] : '-').'</strong><br />'.
|
||||
'Country: <strong>'.($Address['Country'] ? $Address['Country'] : '-').'</strong>';
|
||||
}
|
||||
echo '</p>';
|
||||
}
|
||||
|
||||
if ($vCard -> AGENT)
|
||||
{
|
||||
echo '<h4>Agents</h4>';
|
||||
foreach ($vCard -> AGENT as $Agent)
|
||||
{
|
||||
if (is_scalar($Agent))
|
||||
{
|
||||
echo '<div class="Agent">'.$Agent.'</div>';
|
||||
}
|
||||
elseif (is_a($Agent, 'vCard'))
|
||||
{
|
||||
echo '<div class="Agent">';
|
||||
OutputvCard($Agent);
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$vCard = new vCard(
|
||||
'test.vcf', // Path to vCard file
|
||||
false, // Raw vCard text, can be used instead of a file
|
||||
array( // Option array
|
||||
// This lets you get single values for elements that could contain multiple values but have only one value.
|
||||
// This defaults to false so every value that could have multiple values is returned as array.
|
||||
'Collapse' => false
|
||||
)
|
||||
);
|
||||
|
||||
if (count($vCard) == 0)
|
||||
{
|
||||
throw new Exception('vCard test: empty vCard!');
|
||||
}
|
||||
// if the file contains a single vCard, it is accessible directly.
|
||||
elseif (count($vCard) == 1)
|
||||
{
|
||||
OutputvCard($vCard);
|
||||
}
|
||||
// if the file contains multiple vCards, they are accessible as elements of an array
|
||||
else
|
||||
{
|
||||
foreach ($vCard as $Index => $vCardPart)
|
||||
{
|
||||
OutputvCard($vCardPart);
|
||||
}
|
||||
}
|
||||
?>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user