1<?php 2 3namespace Sabre\CardDAV; 4 5use Sabre\DAV; 6use Sabre\VObject; 7use Sabre\HTTP\RequestInterface; 8use Sabre\HTTP\ResponseInterface; 9 10/** 11 * VCF Exporter 12 * 13 * This plugin adds the ability to export entire address books as .vcf files. 14 * This is useful for clients that don't support CardDAV yet. They often do 15 * support vcf files. 16 * 17 * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 18 * @author Evert Pot (http://evertpot.com/) 19 * @author Thomas Tanghus (http://tanghus.net/) 20 * @license http://sabre.io/license/ Modified BSD License 21 */ 22class VCFExportPlugin extends DAV\ServerPlugin { 23 24 /** 25 * Reference to Server class 26 * 27 * @var Sabre\DAV\Server 28 */ 29 protected $server; 30 31 /** 32 * Initializes the plugin and registers event handlers 33 * 34 * @param DAV\Server $server 35 * @return void 36 */ 37 function initialize(DAV\Server $server) { 38 39 $this->server = $server; 40 $this->server->on('method:GET', [$this, 'httpGet'], 90); 41 $server->on('browserButtonActions', function($path, $node, &$actions) { 42 if ($node instanceof IAddressBook) { 43 $actions .= '<a href="' . htmlspecialchars($path, ENT_QUOTES, 'UTF-8') . '?export"><span class="oi" data-glyph="book"></span></a>'; 44 } 45 }); 46 } 47 48 /** 49 * Intercepts GET requests on addressbook urls ending with ?export. 50 * 51 * @param RequestInterface $request 52 * @param ResponseInterface $response 53 * @return bool 54 */ 55 function httpGet(RequestInterface $request, ResponseInterface $response) { 56 57 $queryParams = $request->getQueryParameters(); 58 if (!array_key_exists('export', $queryParams)) return; 59 60 $path = $request->getPath(); 61 62 $node = $this->server->tree->getNodeForPath($path); 63 64 if (!($node instanceof IAddressBook)) return; 65 66 $this->server->transactionType = 'get-addressbook-export'; 67 68 // Checking ACL, if available. 69 if ($aclPlugin = $this->server->getPlugin('acl')) { 70 $aclPlugin->checkPrivileges($path, '{DAV:}read'); 71 } 72 73 $response->setHeader('Content-Type', 'text/directory'); 74 $response->setStatus(200); 75 76 $nodes = $this->server->getPropertiesForPath($path, [ 77 '{' . Plugin::NS_CARDDAV . '}address-data', 78 ], 1); 79 80 $response->setBody($this->generateVCF($nodes)); 81 82 // Returning false to break the event chain 83 return false; 84 85 } 86 87 /** 88 * Merges all vcard objects, and builds one big vcf export 89 * 90 * @param array $nodes 91 * @return string 92 */ 93 function generateVCF(array $nodes) { 94 95 $output = ""; 96 97 foreach ($nodes as $node) { 98 99 if (!isset($node[200]['{' . Plugin::NS_CARDDAV . '}address-data'])) { 100 continue; 101 } 102 $nodeData = $node[200]['{' . Plugin::NS_CARDDAV . '}address-data']; 103 104 // Parsing this node so VObject can clean up the output. 105 $output .= 106 VObject\Reader::read($nodeData)->serialize(); 107 108 } 109 110 return $output; 111 112 } 113 114 /** 115 * Returns a plugin name. 116 * 117 * Using this name other plugins will be able to access other plugins 118 * using \Sabre\DAV\Server::getPlugin 119 * 120 * @return string 121 */ 122 function getPluginName() { 123 124 return 'vcf-export'; 125 126 } 127 128 /** 129 * Returns a bunch of meta-data about the plugin. 130 * 131 * Providing this information is optional, and is mainly displayed by the 132 * Browser plugin. 133 * 134 * The description key in the returned array may contain html and will not 135 * be sanitized. 136 * 137 * @return array 138 */ 139 function getPluginInfo() { 140 141 return [ 142 'name' => $this->getPluginName(), 143 'description' => 'Adds the ability to export CardDAV addressbooks as a single vCard file.', 144 'link' => 'http://sabre.io/dav/vcf-export-plugin/', 145 ]; 146 147 } 148 149} 150