302 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			302 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * @file include/reddav.php
 | |
|  * @brief some DAV related functions for Hubzilla.
 | |
|  *
 | |
|  * This file contains some functions which did not fit into one of the RedDAV
 | |
|  * classes.
 | |
|  *
 | |
|  * The extended SabreDAV classes you will find in the RedDAV namespace under
 | |
|  * @ref includes/RedDAV/.
 | |
|  * The original SabreDAV classes you can find under @ref vendor/sabre/dav/.
 | |
|  * We need to use SabreDAV 1.8.x for PHP5.3 compatibility. SabreDAV >= 2.0
 | |
|  * requires PHP >= 5.4.
 | |
|  *
 | |
|  * @todo split up the classes into own files.
 | |
|  *
 | |
|  * @link http://github.com/friendica/red
 | |
|  * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
 | |
|  */
 | |
| 
 | |
| use Sabre\DAV;
 | |
| use RedMatrix\RedDAV;
 | |
| 
 | |
| require_once('vendor/autoload.php');
 | |
| require_once('include/attach.php');
 | |
| require_once('include/RedDAV/RedFile.php');
 | |
| require_once('include/RedDAV/RedDirectory.php');
 | |
| require_once('include/RedDAV/RedBasicAuth.php');
 | |
| 
 | |
| /**
 | |
|  * @brief Returns an array with viewable channels.
 | |
|  *
 | |
|  * Get a list of RedDirectory objects with all the channels where the visitor
 | |
|  * has <b>view_storage</b> perms.
 | |
|  *
 | |
|  * @todo Is there any reason why this is not inside RedDirectory class?
 | |
|  * @fixme function name looks like a class name, should we rename it?
 | |
|  *
 | |
|  * @param RedBasicAuth &$auth
 | |
|  * @return array RedDirectory[]
 | |
|  */
 | |
| function RedChannelList(&$auth) {
 | |
| 	$ret = array();
 | |
| 
 | |
| 	$r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0 AND channel_system = 0 AND NOT (channel_pageflags & %d)>0",
 | |
| 		intval(PAGE_HIDDEN)
 | |
| 	);
 | |
| 
 | |
| 	if ($r) {
 | |
| 		foreach ($r as $rr) {
 | |
| 			if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) {
 | |
| 				logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
 | |
| 				// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
 | |
| 				$ret[] = new RedDAV\RedDirectory('/cloud/' . $rr['channel_address'], $auth);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return $ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * @brief TODO what exactly does this function?
 | |
|  *
 | |
|  * Array with all RedDirectory and RedFile DAV\Node items for the given path.
 | |
|  *
 | |
|  * @todo Is there any reason why this is not inside RedDirectory class? Seems
 | |
|  * only to be used there and we could simplify it a bit there.
 | |
|  * @fixme function name looks like a class name, should we rename it?
 | |
|  *
 | |
|  * @param string $file path to a directory
 | |
|  * @param RedBasicAuth &$auth
 | |
|  * @returns null|array \Sabre\DAV\INode[]
 | |
|  * @throw \Sabre\DAV\Exception\Forbidden
 | |
|  * @throw \Sabre\DAV\Exception\NotFound
 | |
|  */
 | |
| function RedCollectionData($file, &$auth) {
 | |
| 	$ret = array();
 | |
| 
 | |
| 	$x = strpos($file, '/cloud');
 | |
| 	if ($x === 0) {
 | |
| 		$file = substr($file, 6);
 | |
| 	}
 | |
| 
 | |
| 	// return a list of channel if we are not inside a channel
 | |
| 	if ((! $file) || ($file === '/')) {
 | |
| 		return RedChannelList($auth);
 | |
| 	}
 | |
| 
 | |
| 	$file = trim($file, '/');
 | |
| 	$path_arr = explode('/', $file);
 | |
| 
 | |
| 	if (! $path_arr)
 | |
| 		return null;
 | |
| 
 | |
| 	$channel_name = $path_arr[0];
 | |
| 
 | |
| 	$r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' LIMIT 1",
 | |
| 		dbesc($channel_name)
 | |
| 	);
 | |
| 
 | |
| 	if (! $r)
 | |
| 		return null;
 | |
| 
 | |
| 	$channel_id = $r[0]['channel_id'];
 | |
| 	$perms = permissions_sql($channel_id);
 | |
| 
 | |
| 	$auth->owner_id = $channel_id;
 | |
| 
 | |
| 	$path = '/' . $channel_name;
 | |
| 
 | |
| 	$folder = '';
 | |
| 	$errors = false;
 | |
| 	$permission_error = false;
 | |
| 
 | |
| 	for ($x = 1; $x < count($path_arr); $x++) {
 | |
| 		$r = q("SELECT id, hash, filename, flags, is_dir FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND is_dir != 0 $perms LIMIT 1",
 | |
| 			dbesc($folder),
 | |
| 			dbesc($path_arr[$x]),
 | |
| 			intval($channel_id)
 | |
| 		);
 | |
| 		if (! $r) {
 | |
| 			// path wasn't found. Try without permissions to see if it was the result of permissions.
 | |
| 			$errors = true;
 | |
| 			$r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 limit 1",
 | |
| 				dbesc($folder),
 | |
| 				basename($path_arr[$x]),
 | |
| 				intval($channel_id)
 | |
| 			);
 | |
| 			if ($r) {
 | |
| 				$permission_error = true;
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		if ($r && intval($r[0]['is_dir'])) {
 | |
| 			$folder = $r[0]['hash'];
 | |
| 			$path = $path . '/' . $r[0]['filename'];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if ($errors) {
 | |
| 		if ($permission_error) {
 | |
| 			throw new DAV\Exception\Forbidden('Permission denied.');
 | |
| 		} else {
 | |
| 			throw new DAV\Exception\NotFound('A component of the request file path could not be found.');
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// This should no longer be needed since we just returned errors for paths not found
 | |
| 	if ($path !== '/' . $file) {
 | |
| 		logger("Path mismatch: $path !== /$file");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
 | |
| 		$prefix = 'DISTINCT ON (filename)';
 | |
| 		$suffix = 'ORDER BY filename';
 | |
| 	} else {
 | |
| 		$prefix = '';
 | |
| 		$suffix = 'GROUP BY filename';
 | |
| 	}
 | |
| 	$r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix",
 | |
| 		dbesc($folder),
 | |
| 		intval($channel_id)
 | |
| 	);
 | |
| 
 | |
| 	foreach ($r as $rr) {
 | |
| 		//logger('filename: ' . $rr['filename'], LOGGER_DEBUG);
 | |
| 		if (intval($rr['is_dir'])) {
 | |
| 			$ret[] = new RedDAV\RedDirectory($path . '/' . $rr['filename'], $auth);
 | |
| 		} else {
 | |
| 			$ret[] = new RedDAV\RedFile($path . '/' . $rr['filename'], $rr, $auth);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return $ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * @brief TODO What exactly is this function for?
 | |
|  *
 | |
|  * @fixme function name looks like a class name, should we rename it?
 | |
|  *
 | |
|  * @param string $file
 | |
|  *  path to file or directory
 | |
|  * @param RedBasicAuth &$auth
 | |
|  * @param boolean $test (optional) enable test mode
 | |
|  * @return RedFile|RedDirectory|boolean|null
 | |
|  * @throw \Sabre\DAV\Exception\Forbidden
 | |
|  */
 | |
| function RedFileData($file, &$auth, $test = false) {
 | |
| 	logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA);
 | |
| 
 | |
| 	$x = strpos($file, '/cloud');
 | |
| 	if ($x === 0) {
 | |
| 		$file = substr($file, 6);
 | |
| 	}
 | |
| 	else {
 | |
| 		$x = strpos($file,'/dav');
 | |
| 		if($x === 0)
 | |
| 			$file = substr($file,4);
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	if ((! $file) || ($file === '/')) {
 | |
| 		return new RedDAV\RedDirectory('/', $auth);
 | |
| 	}
 | |
| 
 | |
| 	$file = trim($file, '/');
 | |
| 
 | |
| 	$path_arr = explode('/', $file);
 | |
| 
 | |
| 	if (! $path_arr)
 | |
| 		return null;
 | |
| 
 | |
| 	$channel_name = $path_arr[0];
 | |
| 
 | |
| 	$r = q("select channel_id from channel where channel_address = '%s' limit 1",
 | |
| 		dbesc($channel_name)
 | |
| 	);
 | |
| 
 | |
| 	if (! $r)
 | |
| 		return null;
 | |
| 
 | |
| 	$channel_id = $r[0]['channel_id'];
 | |
| 
 | |
| 	$path = '/' . $channel_name;
 | |
| 
 | |
| 	$auth->owner_id = $channel_id;
 | |
| 
 | |
| 	$permission_error = false;
 | |
| 
 | |
| 	$folder = '';
 | |
| 
 | |
| 	require_once('include/security.php');
 | |
| 	$perms = permissions_sql($channel_id);
 | |
| 
 | |
| 	$errors = false;
 | |
| 
 | |
| 	for ($x = 1; $x < count($path_arr); $x++) {		
 | |
| 		$r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms",
 | |
| 			dbesc($folder),
 | |
| 			dbesc($path_arr[$x]),
 | |
| 			intval($channel_id)
 | |
| 		);
 | |
| 
 | |
| 		if ($r && intval($r[0]['is_dir'])) {
 | |
| 			$folder = $r[0]['hash'];
 | |
| 			$path = $path . '/' . $r[0]['filename'];
 | |
| 		}
 | |
| 		if (! $r) {
 | |
| 			$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach 
 | |
| 				where folder = '%s' and filename = '%s' and uid = %d $perms order by filename limit 1",
 | |
| 				dbesc($folder),
 | |
| 				dbesc(basename($file)),
 | |
| 				intval($channel_id)
 | |
| 			);
 | |
| 		}
 | |
| 		if (! $r) {
 | |
| 			$errors = true;
 | |
| 			$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach 
 | |
| 				where folder = '%s' and filename = '%s' and uid = %d order by filename limit 1",
 | |
| 				dbesc($folder),
 | |
| 				dbesc(basename($file)),
 | |
| 				intval($channel_id)
 | |
| 			);
 | |
| 			if ($r)
 | |
| 				$permission_error = true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if ($path === '/' . $file) {
 | |
| 		if ($test)
 | |
| 			return true;
 | |
| 		// final component was a directory.
 | |
| 		return new RedDAV\RedDirectory($file, $auth);
 | |
| 	}
 | |
| 
 | |
| 	if ($errors) {
 | |
| 		logger('not found ' . $file);
 | |
| 		if ($test)
 | |
| 			return false;
 | |
| 		if ($permission_error) {
 | |
| 			logger('permission error ' . $file);
 | |
| 			throw new DAV\Exception\Forbidden('Permission denied.');
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if ($r) {
 | |
| 		if ($test)
 | |
| 			return true;
 | |
| 
 | |
| 		if (intval($r[0]['is_dir'])) {
 | |
| 			return new RedDAV\RedDirectory($path . '/' . $r[0]['filename'], $auth);
 | |
| 		} else {
 | |
| 			return new RedDAV\RedFile($path . '/' . $r[0]['filename'], $r[0], $auth);
 | |
| 		}
 | |
| 	}
 | |
| 	return false;
 | |
| } |