commit vendor
This commit is contained in:
75
vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/BackendInterface.php
vendored
Normal file
75
vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/BackendInterface.php
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\DAV\PropertyStorage\Backend;
|
||||
|
||||
use Sabre\DAV\PropFind;
|
||||
use Sabre\DAV\PropPatch;
|
||||
|
||||
/**
|
||||
* Propertystorage backend interface.
|
||||
*
|
||||
* Propertystorage backends must implement this interface to be used by the
|
||||
* propertystorage plugin.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
interface BackendInterface
|
||||
{
|
||||
/**
|
||||
* Fetches properties for a path.
|
||||
*
|
||||
* This method received a PropFind object, which contains all the
|
||||
* information about the properties that need to be fetched.
|
||||
*
|
||||
* Usually you would just want to call 'get404Properties' on this object,
|
||||
* as this will give you the _exact_ list of properties that need to be
|
||||
* fetched, and haven't yet.
|
||||
*
|
||||
* However, you can also support the 'allprops' property here. In that
|
||||
* case, you should check for $propFind->isAllProps().
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function propFind($path, PropFind $propFind);
|
||||
|
||||
/**
|
||||
* Updates properties for a path.
|
||||
*
|
||||
* This method received a PropPatch object, which contains all the
|
||||
* information about the update.
|
||||
*
|
||||
* Usually you would want to call 'handleRemaining' on this object, to get;
|
||||
* a list of all properties that need to be stored.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function propPatch($path, PropPatch $propPatch);
|
||||
|
||||
/**
|
||||
* This method is called after a node is deleted.
|
||||
*
|
||||
* This allows a backend to clean up all associated properties.
|
||||
*
|
||||
* The delete method will get called once for the deletion of an entire
|
||||
* tree.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function delete($path);
|
||||
|
||||
/**
|
||||
* This method is called after a successful MOVE.
|
||||
*
|
||||
* This should be used to migrate all properties from one path to another.
|
||||
* Note that entire collections may be moved, so ensure that all properties
|
||||
* for children are also moved along.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
*/
|
||||
public function move($source, $destination);
|
||||
}
|
||||
224
vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/PDO.php
vendored
Normal file
224
vendor/sabre/dav/lib/DAV/PropertyStorage/Backend/PDO.php
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\DAV\PropertyStorage\Backend;
|
||||
|
||||
use Sabre\DAV\PropFind;
|
||||
use Sabre\DAV\PropPatch;
|
||||
use Sabre\DAV\Xml\Property\Complex;
|
||||
|
||||
/**
|
||||
* PropertyStorage PDO backend.
|
||||
*
|
||||
* This backend class uses a PDO-enabled database to store webdav properties.
|
||||
* Both sqlite and mysql have been tested.
|
||||
*
|
||||
* The database structure can be found in the examples/sql/ directory.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class PDO implements BackendInterface
|
||||
{
|
||||
/**
|
||||
* Value is stored as string.
|
||||
*/
|
||||
const VT_STRING = 1;
|
||||
|
||||
/**
|
||||
* Value is stored as XML fragment.
|
||||
*/
|
||||
const VT_XML = 2;
|
||||
|
||||
/**
|
||||
* Value is stored as a property object.
|
||||
*/
|
||||
const VT_OBJECT = 3;
|
||||
|
||||
/**
|
||||
* PDO.
|
||||
*
|
||||
* @var \PDO
|
||||
*/
|
||||
protected $pdo;
|
||||
|
||||
/**
|
||||
* PDO table name we'll be using.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $tableName = 'propertystorage';
|
||||
|
||||
/**
|
||||
* Creates the PDO property storage engine.
|
||||
*/
|
||||
public function __construct(\PDO $pdo)
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches properties for a path.
|
||||
*
|
||||
* This method received a PropFind object, which contains all the
|
||||
* information about the properties that need to be fetched.
|
||||
*
|
||||
* Usually you would just want to call 'get404Properties' on this object,
|
||||
* as this will give you the _exact_ list of properties that need to be
|
||||
* fetched, and haven't yet.
|
||||
*
|
||||
* However, you can also support the 'allprops' property here. In that
|
||||
* case, you should check for $propFind->isAllProps().
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function propFind($path, PropFind $propFind)
|
||||
{
|
||||
if (!$propFind->isAllProps() && 0 === count($propFind->get404Properties())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query = 'SELECT name, value, valuetype FROM '.$this->tableName.' WHERE path = ?';
|
||||
$stmt = $this->pdo->prepare($query);
|
||||
$stmt->execute([$path]);
|
||||
|
||||
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||
if ('resource' === gettype($row['value'])) {
|
||||
$row['value'] = stream_get_contents($row['value']);
|
||||
}
|
||||
switch ($row['valuetype']) {
|
||||
case null:
|
||||
case self::VT_STRING:
|
||||
$propFind->set($row['name'], $row['value']);
|
||||
break;
|
||||
case self::VT_XML:
|
||||
$propFind->set($row['name'], new Complex($row['value']));
|
||||
break;
|
||||
case self::VT_OBJECT:
|
||||
$propFind->set($row['name'], unserialize($row['value']));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties for a path.
|
||||
*
|
||||
* This method received a PropPatch object, which contains all the
|
||||
* information about the update.
|
||||
*
|
||||
* Usually you would want to call 'handleRemaining' on this object, to get;
|
||||
* a list of all properties that need to be stored.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function propPatch($path, PropPatch $propPatch)
|
||||
{
|
||||
$propPatch->handleRemaining(function ($properties) use ($path) {
|
||||
if ('pgsql' === $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
|
||||
$updateSql = <<<SQL
|
||||
INSERT INTO {$this->tableName} (path, name, valuetype, value)
|
||||
VALUES (:path, :name, :valuetype, :value)
|
||||
ON CONFLICT (path, name)
|
||||
DO UPDATE SET valuetype = :valuetype, value = :value
|
||||
SQL;
|
||||
} else {
|
||||
$updateSql = <<<SQL
|
||||
REPLACE INTO {$this->tableName} (path, name, valuetype, value)
|
||||
VALUES (:path, :name, :valuetype, :value)
|
||||
SQL;
|
||||
}
|
||||
|
||||
$updateStmt = $this->pdo->prepare($updateSql);
|
||||
$deleteStmt = $this->pdo->prepare('DELETE FROM '.$this->tableName.' WHERE path = ? AND name = ?');
|
||||
|
||||
foreach ($properties as $name => $value) {
|
||||
if (!is_null($value)) {
|
||||
if (is_scalar($value)) {
|
||||
$valueType = self::VT_STRING;
|
||||
} elseif ($value instanceof Complex) {
|
||||
$valueType = self::VT_XML;
|
||||
$value = $value->getXml();
|
||||
} else {
|
||||
$valueType = self::VT_OBJECT;
|
||||
$value = serialize($value);
|
||||
}
|
||||
|
||||
$updateStmt->bindParam('path', $path, \PDO::PARAM_STR);
|
||||
$updateStmt->bindParam('name', $name, \PDO::PARAM_STR);
|
||||
$updateStmt->bindParam('valuetype', $valueType, \PDO::PARAM_INT);
|
||||
$updateStmt->bindParam('value', $value, \PDO::PARAM_LOB);
|
||||
|
||||
$updateStmt->execute();
|
||||
} else {
|
||||
$deleteStmt->execute([$path, $name]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after a node is deleted.
|
||||
*
|
||||
* This allows a backend to clean up all associated properties.
|
||||
*
|
||||
* The delete method will get called once for the deletion of an entire
|
||||
* tree.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function delete($path)
|
||||
{
|
||||
$stmt = $this->pdo->prepare('DELETE FROM '.$this->tableName." WHERE path = ? OR path LIKE ? ESCAPE '='");
|
||||
$childPath = strtr(
|
||||
$path,
|
||||
[
|
||||
'=' => '==',
|
||||
'%' => '=%',
|
||||
'_' => '=_',
|
||||
]
|
||||
).'/%';
|
||||
|
||||
$stmt->execute([$path, $childPath]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after a successful MOVE.
|
||||
*
|
||||
* This should be used to migrate all properties from one path to another.
|
||||
* Note that entire collections may be moved, so ensure that all properties
|
||||
* for children are also moved along.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
*/
|
||||
public function move($source, $destination)
|
||||
{
|
||||
// I don't know a way to write this all in a single sql query that's
|
||||
// also compatible across db engines, so we're letting PHP do all the
|
||||
// updates. Much slower, but it should still be pretty fast in most
|
||||
// cases.
|
||||
$select = $this->pdo->prepare('SELECT id, path FROM '.$this->tableName.' WHERE path = ? OR path LIKE ?');
|
||||
$select->execute([$source, $source.'/%']);
|
||||
|
||||
$update = $this->pdo->prepare('UPDATE '.$this->tableName.' SET path = ? WHERE id = ?');
|
||||
while ($row = $select->fetch(\PDO::FETCH_ASSOC)) {
|
||||
// Sanity check. SQL may select too many records, such as records
|
||||
// with different cases.
|
||||
if ($row['path'] !== $source && 0 !== strpos($row['path'], $source.'/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$trailingPart = substr($row['path'], strlen($source) + 1);
|
||||
$newPath = $destination;
|
||||
if ($trailingPart) {
|
||||
$newPath .= '/'.$trailingPart;
|
||||
}
|
||||
$update->execute([$newPath, $row['id']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
176
vendor/sabre/dav/lib/DAV/PropertyStorage/Plugin.php
vendored
Normal file
176
vendor/sabre/dav/lib/DAV/PropertyStorage/Plugin.php
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\DAV\PropertyStorage;
|
||||
|
||||
use Sabre\DAV\INode;
|
||||
use Sabre\DAV\PropFind;
|
||||
use Sabre\DAV\PropPatch;
|
||||
use Sabre\DAV\Server;
|
||||
use Sabre\DAV\ServerPlugin;
|
||||
|
||||
/**
|
||||
* PropertyStorage Plugin.
|
||||
*
|
||||
* Adding this plugin to your server allows clients to store any arbitrary
|
||||
* WebDAV property.
|
||||
*
|
||||
* See:
|
||||
* http://sabre.io/dav/property-storage/
|
||||
*
|
||||
* for more information.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Plugin extends ServerPlugin
|
||||
{
|
||||
/**
|
||||
* If you only want this plugin to store properties for a limited set of
|
||||
* paths, you can use a pathFilter to do this.
|
||||
*
|
||||
* The pathFilter should be a callable. The callable retrieves a path as
|
||||
* its argument, and should return true or false whether it allows
|
||||
* properties to be stored.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
public $pathFilter;
|
||||
|
||||
/**
|
||||
* @var Backend\BackendInterface
|
||||
*/
|
||||
public $backend;
|
||||
|
||||
/**
|
||||
* Creates the plugin.
|
||||
*/
|
||||
public function __construct(Backend\BackendInterface $backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
}
|
||||
|
||||
/**
|
||||
* This initializes the plugin.
|
||||
*
|
||||
* This function is called by Sabre\DAV\Server, after
|
||||
* addPlugin is called.
|
||||
*
|
||||
* This method should set up the required event subscriptions.
|
||||
*/
|
||||
public function initialize(Server $server)
|
||||
{
|
||||
$server->on('propFind', [$this, 'propFind'], 130);
|
||||
$server->on('propPatch', [$this, 'propPatch'], 300);
|
||||
$server->on('afterMove', [$this, 'afterMove']);
|
||||
$server->on('afterUnbind', [$this, 'afterUnbind']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during PROPFIND operations.
|
||||
*
|
||||
* If there's any requested properties that don't have a value yet, this
|
||||
* plugin will look in the property storage backend to find them.
|
||||
*/
|
||||
public function propFind(PropFind $propFind, INode $node)
|
||||
{
|
||||
$path = $propFind->getPath();
|
||||
$pathFilter = $this->pathFilter;
|
||||
if ($pathFilter && !$pathFilter($path)) {
|
||||
return;
|
||||
}
|
||||
$this->backend->propFind($propFind->getPath(), $propFind);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during PROPPATCH operations.
|
||||
*
|
||||
* If there's any updated properties that haven't been stored, the
|
||||
* propertystorage backend can handle it.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function propPatch($path, PropPatch $propPatch)
|
||||
{
|
||||
$pathFilter = $this->pathFilter;
|
||||
if ($pathFilter && !$pathFilter($path)) {
|
||||
return;
|
||||
}
|
||||
$this->backend->propPatch($path, $propPatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after a node is deleted.
|
||||
*
|
||||
* This allows the backend to clean up any properties still in the
|
||||
* database.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function afterUnbind($path)
|
||||
{
|
||||
$pathFilter = $this->pathFilter;
|
||||
if ($pathFilter && !$pathFilter($path)) {
|
||||
return;
|
||||
}
|
||||
$this->backend->delete($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after a node is moved.
|
||||
*
|
||||
* This allows the backend to move all the associated properties.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
*/
|
||||
public function afterMove($source, $destination)
|
||||
{
|
||||
$pathFilter = $this->pathFilter;
|
||||
if ($pathFilter && !$pathFilter($source)) {
|
||||
return;
|
||||
}
|
||||
// If the destination is filtered, afterUnbind will handle cleaning up
|
||||
// the properties.
|
||||
if ($pathFilter && !$pathFilter($destination)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->backend->move($source, $destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a plugin name.
|
||||
*
|
||||
* Using this name other plugins will be able to access other plugins
|
||||
* using \Sabre\DAV\Server::getPlugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginName()
|
||||
{
|
||||
return 'property-storage';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bunch of meta-data about the plugin.
|
||||
*
|
||||
* Providing this information is optional, and is mainly displayed by the
|
||||
* Browser plugin.
|
||||
*
|
||||
* The description key in the returned array may contain html and will not
|
||||
* be sanitized.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPluginInfo()
|
||||
{
|
||||
return [
|
||||
'name' => $this->getPluginName(),
|
||||
'description' => 'This plugin allows any arbitrary WebDAV property to be set on any resource.',
|
||||
'link' => 'http://sabre.io/dav/property-storage/',
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user