aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre/dav/lib/DAV/Client.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sabre/dav/lib/DAV/Client.php')
-rw-r--r--vendor/sabre/dav/lib/DAV/Client.php448
1 files changed, 448 insertions, 0 deletions
diff --git a/vendor/sabre/dav/lib/DAV/Client.php b/vendor/sabre/dav/lib/DAV/Client.php
new file mode 100644
index 000000000..d46b397b6
--- /dev/null
+++ b/vendor/sabre/dav/lib/DAV/Client.php
@@ -0,0 +1,448 @@
+<?php
+
+namespace Sabre\DAV;
+
+use Sabre\HTTP;
+
+/**
+ * SabreDAV DAV client
+ *
+ * This client wraps around Curl to provide a convenient API to a WebDAV
+ * server.
+ *
+ * NOTE: This class is experimental, it's api will likely change in the future.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Client extends HTTP\Client {
+
+ /**
+ * The xml service.
+ *
+ * Uset this service to configure the property and namespace maps.
+ *
+ * @var mixed
+ */
+ public $xml;
+
+ /**
+ * The elementMap
+ *
+ * This property is linked via reference to $this->xml->elementMap.
+ * It's deprecated as of version 3.0.0, and should no longer be used.
+ *
+ * @deprecated
+ * @var array
+ */
+ public $propertyMap = [];
+
+ /**
+ * Base URI
+ *
+ * This URI will be used to resolve relative urls.
+ *
+ * @var string
+ */
+ protected $baseUri;
+
+ /**
+ * Basic authentication
+ */
+ const AUTH_BASIC = 1;
+
+ /**
+ * Digest authentication
+ */
+ const AUTH_DIGEST = 2;
+
+ /**
+ * NTLM authentication
+ */
+ const AUTH_NTLM = 4;
+
+ /**
+ * Identity encoding, which basically does not nothing.
+ */
+ const ENCODING_IDENTITY = 1;
+
+ /**
+ * Deflate encoding
+ */
+ const ENCODING_DEFLATE = 2;
+
+ /**
+ * Gzip encoding
+ */
+ const ENCODING_GZIP = 4;
+
+ /**
+ * Sends all encoding headers.
+ */
+ const ENCODING_ALL = 7;
+
+ /**
+ * Content-encoding
+ *
+ * @var int
+ */
+ protected $encoding = self::ENCODING_IDENTITY;
+
+ /**
+ * Constructor
+ *
+ * Settings are provided through the 'settings' argument. The following
+ * settings are supported:
+ *
+ * * baseUri
+ * * userName (optional)
+ * * password (optional)
+ * * proxy (optional)
+ * * authType (optional)
+ * * encoding (optional)
+ *
+ * authType must be a bitmap, using self::AUTH_BASIC, self::AUTH_DIGEST
+ * and self::AUTH_NTLM. If you know which authentication method will be
+ * used, it's recommended to set it, as it will save a great deal of
+ * requests to 'discover' this information.
+ *
+ * Encoding is a bitmap with one of the ENCODING constants.
+ *
+ * @param array $settings
+ */
+ function __construct(array $settings) {
+
+ if (!isset($settings['baseUri'])) {
+ throw new \InvalidArgumentException('A baseUri must be provided');
+ }
+
+ parent::__construct();
+
+ $this->baseUri = $settings['baseUri'];
+
+ if (isset($settings['proxy'])) {
+ $this->addCurlSetting(CURLOPT_PROXY, $settings['proxy']);
+ }
+
+ if (isset($settings['userName'])) {
+ $userName = $settings['userName'];
+ $password = isset($settings['password']) ? $settings['password'] : '';
+
+ if (isset($settings['authType'])) {
+ $curlType = 0;
+ if ($settings['authType'] & self::AUTH_BASIC) {
+ $curlType |= CURLAUTH_BASIC;
+ }
+ if ($settings['authType'] & self::AUTH_DIGEST) {
+ $curlType |= CURLAUTH_DIGEST;
+ }
+ if ($settings['authType'] & self::AUTH_NTLM) {
+ $curlType |= CURLAUTH_NTLM;
+ }
+ } else {
+ $curlType = CURLAUTH_BASIC | CURLAUTH_DIGEST;
+ }
+
+ $this->addCurlSetting(CURLOPT_HTTPAUTH, $curlType);
+ $this->addCurlSetting(CURLOPT_USERPWD, $userName . ':' . $password);
+
+ }
+
+ if (isset($settings['encoding'])) {
+ $encoding = $settings['encoding'];
+
+ $encodings = [];
+ if ($encoding & self::ENCODING_IDENTITY) {
+ $encodings[] = 'identity';
+ }
+ if ($encoding & self::ENCODING_DEFLATE) {
+ $encodings[] = 'deflate';
+ }
+ if ($encoding & self::ENCODING_GZIP) {
+ $encodings[] = 'gzip';
+ }
+ $this->addCurlSetting(CURLOPT_ENCODING, implode(',', $encodings));
+ }
+
+ $this->addCurlSetting(CURLOPT_USERAGENT, 'sabre-dav/' . Version::VERSION . ' (http://sabre.io/)');
+
+ $this->xml = new Xml\Service();
+ // BC
+ $this->propertyMap = & $this->xml->elementMap;
+
+ }
+
+ /**
+ * Does a PROPFIND request
+ *
+ * The list of requested properties must be specified as an array, in clark
+ * notation.
+ *
+ * The returned array will contain a list of filenames as keys, and
+ * properties as values.
+ *
+ * The properties array will contain the list of properties. Only properties
+ * that are actually returned from the server (without error) will be
+ * returned, anything else is discarded.
+ *
+ * Depth should be either 0 or 1. A depth of 1 will cause a request to be
+ * made to the server to also return all child resources.
+ *
+ * @param string $url
+ * @param array $properties
+ * @param int $depth
+ * @return array
+ */
+ function propFind($url, array $properties, $depth = 0) {
+
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->formatOutput = true;
+ $root = $dom->createElementNS('DAV:', 'd:propfind');
+ $prop = $dom->createElement('d:prop');
+
+ foreach ($properties as $property) {
+
+ list(
+ $namespace,
+ $elementName
+ ) = \Sabre\Xml\Service::parseClarkNotation($property);
+
+ if ($namespace === 'DAV:') {
+ $element = $dom->createElement('d:' . $elementName);
+ } else {
+ $element = $dom->createElementNS($namespace, 'x:' . $elementName);
+ }
+
+ $prop->appendChild($element);
+ }
+
+ $dom->appendChild($root)->appendChild($prop);
+ $body = $dom->saveXML();
+
+ $url = $this->getAbsoluteUrl($url);
+
+ $request = new HTTP\Request('PROPFIND', $url, [
+ 'Depth' => $depth,
+ 'Content-Type' => 'application/xml'
+ ], $body);
+
+ $response = $this->send($request);
+
+ if ((int)$response->getStatus() >= 400) {
+ throw new \Sabre\HTTP\ClientHttpException($response);
+ }
+
+ $result = $this->parseMultiStatus($response->getBodyAsString());
+
+ // If depth was 0, we only return the top item
+ if ($depth === 0) {
+ reset($result);
+ $result = current($result);
+ return isset($result[200]) ? $result[200] : [];
+ }
+
+ $newResult = [];
+ foreach ($result as $href => $statusList) {
+
+ $newResult[$href] = isset($statusList[200]) ? $statusList[200] : [];
+
+ }
+
+ return $newResult;
+
+ }
+
+ /**
+ * Updates a list of properties on the server
+ *
+ * The list of properties must have clark-notation properties for the keys,
+ * and the actual (string) value for the value. If the value is null, an
+ * attempt is made to delete the property.
+ *
+ * @param string $url
+ * @param array $properties
+ * @return bool
+ */
+ function propPatch($url, array $properties) {
+
+ $propPatch = new Xml\Request\PropPatch();
+ $propPatch->properties = $properties;
+ $xml = $this->xml->write(
+ '{DAV:}propertyupdate',
+ $propPatch
+ );
+
+ $url = $this->getAbsoluteUrl($url);
+ $request = new HTTP\Request('PROPPATCH', $url, [
+ 'Content-Type' => 'application/xml',
+ ], $xml);
+ $response = $this->send($request);
+
+ if ($response->getStatus() >= 400) {
+ throw new \Sabre\HTTP\ClientHttpException($response);
+ }
+
+ if ($response->getStatus() === 207) {
+ // If it's a 207, the request could still have failed, but the
+ // information is hidden in the response body.
+ $result = $this->parseMultiStatus($response->getBodyAsString());
+
+ $errorProperties = [];
+ foreach ($result as $href => $statusList) {
+ foreach ($statusList as $status => $properties) {
+
+ if ($status >= 400) {
+ foreach ($properties as $propName => $propValue) {
+ $errorProperties[] = $propName . ' (' . $status . ')';
+ }
+ }
+
+ }
+ }
+ if ($errorProperties) {
+
+ throw new \Sabre\HTTP\ClientException('PROPPATCH failed. The following properties errored: ' . implode(', ', $errorProperties));
+ }
+ }
+ return true;
+
+ }
+
+ /**
+ * Performs an HTTP options request
+ *
+ * This method returns all the features from the 'DAV:' header as an array.
+ * If there was no DAV header, or no contents this method will return an
+ * empty array.
+ *
+ * @return array
+ */
+ function options() {
+
+ $request = new HTTP\Request('OPTIONS', $this->getAbsoluteUrl(''));
+ $response = $this->send($request);
+
+ $dav = $response->getHeader('Dav');
+ if (!$dav) {
+ return [];
+ }
+
+ $features = explode(',', $dav);
+ foreach ($features as &$v) {
+ $v = trim($v);
+ }
+ return $features;
+
+ }
+
+ /**
+ * Performs an actual HTTP request, and returns the result.
+ *
+ * If the specified url is relative, it will be expanded based on the base
+ * url.
+ *
+ * The returned array contains 3 keys:
+ * * body - the response body
+ * * httpCode - a HTTP code (200, 404, etc)
+ * * headers - a list of response http headers. The header names have
+ * been lowercased.
+ *
+ * For large uploads, it's highly recommended to specify body as a stream
+ * resource. You can easily do this by simply passing the result of
+ * fopen(..., 'r').
+ *
+ * This method will throw an exception if an HTTP error was received. Any
+ * HTTP status code above 399 is considered an error.
+ *
+ * Note that it is no longer recommended to use this method, use the send()
+ * method instead.
+ *
+ * @param string $method
+ * @param string $url
+ * @param string|resource|null $body
+ * @param array $headers
+ * @throws ClientException, in case a curl error occurred.
+ * @return array
+ */
+ function request($method, $url = '', $body = null, array $headers = []) {
+
+ $url = $this->getAbsoluteUrl($url);
+
+ $response = $this->send(new HTTP\Request($method, $url, $headers, $body));
+ return [
+ 'body' => $response->getBodyAsString(),
+ 'statusCode' => (int)$response->getStatus(),
+ 'headers' => array_change_key_case($response->getHeaders()),
+ ];
+
+ }
+
+ /**
+ * Returns the full url based on the given url (which may be relative). All
+ * urls are expanded based on the base url as given by the server.
+ *
+ * @param string $url
+ * @return string
+ */
+ function getAbsoluteUrl($url) {
+
+ // If the url starts with http:// or https://, the url is already absolute.
+ if (preg_match('/^http(s?):\/\//', $url)) {
+ return $url;
+ }
+
+ // If the url starts with a slash, we must calculate the url based off
+ // the root of the base url.
+ if (strpos($url, '/') === 0) {
+ $parts = parse_url($this->baseUri);
+ return $parts['scheme'] . '://' . $parts['host'] . (isset($parts['port']) ? ':' . $parts['port'] : '') . $url;
+ }
+
+ // Otherwise...
+ return $this->baseUri . $url;
+
+ }
+
+ /**
+ * Parses a WebDAV multistatus response body
+ *
+ * This method returns an array with the following structure
+ *
+ * [
+ * 'url/to/resource' => [
+ * '200' => [
+ * '{DAV:}property1' => 'value1',
+ * '{DAV:}property2' => 'value2',
+ * ],
+ * '404' => [
+ * '{DAV:}property1' => null,
+ * '{DAV:}property2' => null,
+ * ],
+ * ],
+ * 'url/to/resource2' => [
+ * .. etc ..
+ * ]
+ * ]
+ *
+ *
+ * @param string $body xml body
+ * @return array
+ */
+ function parseMultiStatus($body) {
+
+ $multistatus = $this->xml->expect('{DAV:}multistatus', $body);
+
+ $result = [];
+
+ foreach ($multistatus->getResponses() as $response) {
+
+ $result[$response->getHref()] = $response->getResponseProperties();
+
+ }
+
+ return $result;
+
+ }
+
+}