FILEUP



LOG | FILES | OVERVIEW


<?php 
require_once "configuration.php";
require_once "user.php";
require_once "misc.php";
require_once "node.php";

/*handles database stuff*/
	class Database
	{
		public $pdo;


		public function __construct()
		{
			global $domain_name;
			global $database_name;
			global $database_username;
			global $database_password;
			global $database_location;

				$this->pdo=new PDO("mysql:dbname={$database_name};host={$database_location}",$database_username,$database_password);
		}

		/*returns NULL if this isn't a user, otherwise returns the user in the form of the User class*/
		function get_user(string $user) 
		{
			$ret=new User;

			$prep=$this->pdo->prepare("select user_id,username,email,home_directory from users where username=:username");
			$prep->bindParam(':username',$user);

			$prep->execute();

			$hold=$prep->fetch(PDO::FETCH_ASSOC);

			if(isset($hold["user_id"]))
			{
				$ret->user_id=$hold["user_id"];
				$ret->username=$hold["username"];
				$ret->email_address=$hold["email"];
				$ret->home_directory=$hold["home_directory"];
				return $ret;
			}else
			{
				return NULL;
			}
		}
		/*returns false if this isn't a user or the password is incorrect, otherwise returns the userid*/
		function authenticate(string $user, string $password) 
		{
			$ret=new User;

			$prep=$this->pdo->prepare("select user_id,username,email,password,home_directory from users where username=:username");
			$prep->bindParam(':username',$user);
			$prep->execute();

			$hold=$prep->fetch(PDO::FETCH_ASSOC);

			if($hold)
			{
				if(password_verify($password,$hold["password"]))
				{
					$ret->user_id=$hold["user_id"];
					$ret->username=$hold["username"];
					$ret->email_address=$hold["email"];
					$ret->home_directory=$hold["home_directory"];
					return $ret;
				}else
				{
					return false;
				}
			}else
			{
				return false;
			}
		}

		/*returns assoc array , or NULL on error*/
		function get_nodes_with_name($name)
		{
			$statement=$this->pdo->prepare(
					"select node_id
					 from node_links
					 where name=:name"
					);
			$statement->bindParam(':name',$name);
			if($statement->execute()==false)
			{
				error_log("there was a problem with the sql statement at get_nodes_with_name");
				return NULL;
			}
			return $statement->fetchAll(PDO::FETCH_ASSOC);
		}

		/*returns id or NULL on error*/
		function get_node_with_code($code)
		{
			$statement=$this->pdo->prepare(
					"select node_id as id
					 from nodes
					 where code=:code"
					);
			$statement->bindParam(':code',$code);
			if($statement->execute()==false)
			{
				error_log("there was a problem with the sql statement at get_nodes_with_code");
				return NULL;
			}
			$ret= $statement->fetch(PDO::FETCH_ASSOC);
			if(isset($ret["id"]))
			{
				return $ret["id"];
			}else
			{
				return NULL;
			}
		}
		/* I think this only makes sense if node is a dir*/
		/* returns assoc array of nodes*/
		/* returns permissions as well*/
		function get_links_of(int $node_id,int $user_id)
		{
			$statement=$this->pdo->prepare("
							select node_links.node_id as id,
								node_links.name as name,
								node_links.note as note,
								nodes.is_directory as is_directory,
								nodes.code as code,
								nodes.type as mimetype,
								node_access.can_view as can_view,
								node_access.can_edit as can_edit
								from node_links
								inner join nodes on
									nodes.node_id=node_links.node_id
								inner join node_access on 
									node_access.node_id=node_links.node_id
								where 
								node_links.directory_id=:id and
								node_access.user_id=:user_id
							");
			$statement->bindParam(':id',$node_id);
			$statement->bindParam(':user_id',$user_id);
			if($statement->execute()==false)
			{
				error_log("there is an error in the sql statement in get_links_of");
				return [];
			}
			return $statement->fetchAll(PDO::FETCH_ASSOC);
		}

		/*if both are not null returns the id of the node with the name name in the directory_id node*/
		function get_node_id(string $name,int $directory_id)
		{
			$statement=$this->pdo->prepare("
					select node_links.node_id as id
					from node_links 
					inner join nodes on
					nodes.node_id=node_links.node_id 
					where node_links.name=:name and node_links.directory_id=:directory_id
				");
			$statement->bindParam(':name',$name);
			$statement->bindParam(':directory_id',$directory_id);
			if($statement->execute()==false)
			{
				error_log("there is an error in the sql statement in get_node_id");
				return NULL;
			}
			$hold=$statement->fetch(PDO::FETCH_ASSOC);
			if(gettype($hold)!="array")
			{
				return NULL;
			}else
			{
				return $hold["id"];
			}

		}





		/*is used to get a random codename for the node as well*/
		function get_random_node_name(string $prefix)
		{
			do{
				$proposal=uniqid($prefix,true);
			}while(count($this->get_nodes_with_name($proposal))!=0);
			return $proposal;
		}


		function get_permissions(int $node_id,int $user_id)
		{

			$prep=$this->pdo->prepare("
							select can_view,can_edit
							from node_access
							where node_id=:node and user_id=:user
							");
			$prep->bindParam(':node',$node_id);
			$prep->bindParam(':user',$user_id);
			if($prep->execute()==false)
			{
				error_log("there is an error with the sql statemtent at get_permissions");
				return NULL;
			}
			$ret=$prep->fetch(PDO::FETCH_ASSOC);
			if(gettype($ret)=="boolean")
			{
				$prep=$this->pdo->prepare("insert into 
							node_access(node_id,user_id,can_view,can_edit)
							values(:node,:user,false,false)");
				$prep->bindParam(':node',$node_id);
				$prep->bindParam(':user',$user_id);
				if($prep->execute()==false)
				{
					error_log("couldnt create access entry in get_permissions2");
					return NULL;
				}



				$prep=$this->pdo->prepare("
								select can_view,can_edit
								from node_access
								where node_id=:node and user_id=:user
								");
				$prep->bindParam(':node',$node_id);
				$prep->bindParam(':user',$user_id);
				if($prep->execute()==false)
				{
					error_log("there is an error with the sql statemtent at get_permissions3");
					return NULL;
				}
				$ret=$prep->fetch(PDO::FETCH_ASSOC);
			}
			return $ret;
		}

		function give_view_access(int $node_id,int $user_id)
		{
			$permissions=$this->get_permissions($node_id,$user_id);
			/*this isn't futile because we create access entries in get_permission if there are none*/
			if($permissions["can_view"]==false)
			{
				$prep=$this->pdo->prepare("update node_access 
								set can_view=true
								where node_id=:node and user_id=:user
								");
				$prep->bindParam(':node',$node_id);
				$prep->bindParam(':user',$user_id);
				if($prep->execute()==false)
				{
					error_log("could not execute sql statement in guve_view_access");
				}

			}
		}

		function give_edit_access(int $node_id,int $user_id)
		{
			$permissions=$this->get_permissions($node_id,$user_id);
			/*this isn't futile because we create access entries in get_permission if there are none*/
			if($permissions["can_edit"]==false)
			{
				$prep=$this->pdo->prepare("update node_access 
								set can_edit=true
								where node_id=:node and user_id=:user
								");
				$prep->bindParam(':node',$node_id);
				$prep->bindParam(':user',$user_id);
				if($prep->execute()==false)
				{
					error_log("could not execute sql statement in give_edit_access");
				}

			}
		}
		/*returns NULL if directory or error*/
		function get_code_of_node(int $node_id)
		{
			global $storage_root;

			$prep=$this->pdo->prepare("select code
						   from nodes
						   where node_id=:id
						  ");
			$prep->bindParam(':id',$node_id);
			if($prep->execute()==false)
			{
				error_log("could not execute sql statement in get_file_location_of_node");
				return NULL;
			}
			$hold=$prep->fetch(PDO::FETCH_ASSOC);
			if(count($hold)!=1)
			{
				return NULL;
			}else
			{
				/*BEWARE*/
				return $hold["code"];
			}
		}
		/*
		   we remove the node and
		   1. move the file represented by the node to the trash folder
		   2. remove the file
		   depends on the conf file
		 */
		function delete_node_by_id(int $node_id)
		{
			global $has_trash;
			global $storage_root;

			$location=get_file_location_of_node($node_id);

			/*actually delete the file*/
			if($has_trash)
			{
				/*BEWARE*/
				if(!copy($storage_root."/".$location,$storage_root."/trash/".$location))
				{
					error_log("could not copy file aborting node deletion in delete_node_by_id");
					return;
				}
			}
			unlink($storage_root."/".$location);

			if($location==NULL)
			{
				error_log("trying to delete a node that does not exist in delete_node_by_id!");
				return;
			}
			$prep=$this->pdo->prepare("delete
						   from nodes
						   where node_id=:id
						   ");
			$prep->bindParam(':id',$node_id);
			if($prep->execute()==false)
			{
				error_log("sql statement in delete_node_by_id could not execute");
				return NULL;
			}
		}

		/*this is used to create seperate roots for the users*/
		function create_dangling_directory(): int
		{
			$code_name=$this->get_random_node_name("");
			global $storage_root;

			/*create directory node*/
			$prep=$this->pdo->prepare("insert into nodes(is_directory,relative_path,code) values(true,:root,:code)");
			$prep->bindParam(':code',$code_name);
			$prep->bindParam(':root',$code_name);
			if($prep->execute()==false)
			{
				error_log("tried to create a dangling directory but sql statement failed. Fatal error!");
				exit(1);
			}
			/*give permissions*/

			$id=$this->get_node_with_code($code_name);
			if($id==NULL)
			{
				error_log("created a dangling directory but couldn't find it afterward. Fatal error!");
				exit(1);
			}

			//print count($id);
			return $id;
		}


		/*links source to target*/
		function link_nodes(int $target_id,int $source_id,string $name,string $note)
		{
			$statement=$this->pdo->prepare("
							insert into node_links(directory_id,node_id,name,note)
							values (:dir,:node,:name,:note)
							");
			$statement->bindParam(':dir',$target_id);
			$statement->bindParam(':node',$source_id);
			$statement->bindParam(':name',$name);
			$statement->bindParam(':note',$note);
			if($statement->execute()==false)
			{
				error_log("there was an error with the statement ni link_nodes");
			}
		}


		function unlink_nodes(int $dir_id, string $filename)
		{
			global $storage_root;
			/*TODO delet this*/
			error_log("in unlink nodes");
			$prep=$this->pdo->prepare("delete from node_links
						   where directory_id=:dir_id and name=:name
						");
			$prep->bindParam(':dir_id',$dir_id);
			$prep->bindParam(':name',$filename);
			if($prep->execute()==false)
			{
				error_log("there was an error with the first statement in unlink_nodes");
				return;
			}
			error_log("in pre stuff in unlink nodes");
			$prep=$this->pdo->prepare("select count(1) as count from trash");
			$prep->execute() or die(1);
			do{


				$prep=$this->pdo->prepare("select count(1) as count from super_trash");
				$prep->execute() or die(1);
				$super_trash_count=$prep->fetch(PDO::FETCH_ASSOC);
				$prep=$this->pdo->prepare("delete from super_trash");
				$prep->execute() or die(1);



				$prep=$this->pdo->prepare("select count(1) as count from trash");
				$prep->execute() or die(1);
				$trash_count=$prep->fetch(PDO::FETCH_ASSOC);
				$prep=$this->pdo->prepare("delete from trash");
				$prep->execute() or die(1);

				error_log("asdf: ".$trash_count["count"]." ".$super_trash_count["count"]);
			}while($trash_count["count"]!=$super_trash_count["count"]);

			$prep=$this->pdo->prepare("select code from nodes where node_id in
							(select node_id from super_trash)");
			$prep->execute() or die(1);
			$res=$prep->fetchAll(PDO::FETCH_ASSOC);
			foreach($res as $node)
			{
				unlink($storage_root."/".$node["code"]);
				error_log("deleting: ".$storage_root."/".$node["code"]);
			}
			$prep=$this->pdo->prepare("delete from nodes where node_id in
								(select node_id from super_trash)");
			$prep->execute() or die(1);
			$prep=$this->pdo->prepare("delete from super_trash");
			$prep->execute() or die(1);


		}

		function create_home_directory()
		{
			$home_id=$this->create_dangling_directory();
			$trash_folder_id=$this->create_dangling_directory();
			$this->link_nodes($home_id,$trash_folder_id,"trash","trash folder");

			$share_folder_id=$this->create_dangling_directory();
			$this->link_nodes($home_id,$share_folder_id,"share","shared things go in here");

			$ret=array("home" => $home_id, "trash" => $trash_folder_id , "share" =>$share_folder_id);
			return $ret;
		}

		function check_if_name_is_taken(string $filename,int $dir_id):bool
		{
			if($this->get_node_id($filename,$dir_id)!=NULL)
			{
				return true;
			}else
			{
				return false;
			}

		}
		function create_shared_node(string $password,int $node_id,string $users)
		{
			$code=$this->get_random_node_name("");
			$prep=$this->pdo->prepare("insert into shared_nodes(node_id,passcode,code,is_public)
							values (:id,:pass,:code,:is_public)
						");
			$prep->bindParam(':id',$node_id);
			$prep->bindParam(':pass',$password);
			$prep->bindParam(':code',$code);
			if($users=="")
			{
				$is_public=1;
			}else
			{
				$is_public=0;
				error_log("shared with $users is set to public=$is_public");
			}
			$prep->bindParam(':is_public',$is_public);

			if($prep->execute()==false)
			{
				error_log("could not create shared node in create_shared_node");
				return NULL;
			}
			$shared_node=new Shared_Node();
			$shared_node->code=$code;
			$shared_node->node_id=$node_id;
			$shared_node->password=$password;
			return $shared_node;
		}
		function get_node(int $node_id)
		{
			$prep=$this->pdo->prepare("select * from nodes where node_id=:id");
			$prep->bindParam(':id',$node_id);
			if($prep->execute()==false)
			{
				error_log("sql statement at get_node failed");
				return NULL;
			}
			$nod=$prep->fetch(PDO::FETCH_ASSOC);
			$ret=new Node();

			$ret->node_id=$nod["node_id"];
			$ret->is_directory=$nod["is_directory"];
			$ret->relative_path=$nod["relative_path"];
			$ret->type=$nod["type"];
			$ret->code=$nod["code"];

			return $ret;

		}
		/*returns the file name as it must be in the filesystem relative to the storage root*/
		function create_file_node(string $filename,string $note,int $dir_id,string $mimetype,User $user,$overwrite)
		{
			global $storage_root;
			if($filename==NULL)return "error";
			/*checkout the directory*/
			$dir_prep=$this->pdo->prepare("
							select 
							nodes.is_directory as is_directory,
							node_access.can_edit as can_edit
							from nodes
							inner join node_access on 
							nodes.node_id=node_access.node_id
							where nodes.node_id=:dir_id
							");
			$dir_prep->bindParam(':dir_id',$dir_id);
			if($dir_prep->execute()==false)
			{
				error_log("could not exedude dir sql statement in create_file_node");
				return -1;
		        }

			$dir=$dir_prep->fetch(PDO::FETCH_ASSOC);
			if($dir == false)
			{
				error_log("create_file_node dir isnt a directory");
				return -1;
			}
			if($dir["is_directory"]==false)
			{
				/*remove this TODO*/
				error_log("create_file_node: dir is not a directory directory=".print_r($dir).gettype($dir));
				return -1;
			}
			if($dir["can_edit"]==false)
			{
				/*TODO*/
				/*remove this TODO*/
				error_log("create_file_node: dir is not modifiable");
				return -1;
			}

			/*check if node with given name exists*/
			//if($this->check_if_name_is_taken($filename,$dir_id))
			$node_id=$this->get_node_id($filename,$dir_id);
			if($node_id!=NULL)
			{
				if($overwrite==1)
				{
					$code=$this->get_code_of_node($node_id);
					$prepare=$this->pdo->prepare("
							update nodes
							set type=:type
							where node_id=:id
							");
					$prepare->bindParam(':type',$mimetype);
					$prepare->bindParam(':id',$node_id);
					if($prepare->execute()==false)
					{
						error_log("could not rewrite filenode in create_file_node");
						return "error";
					}else
					{
						return $code;
					}
				}else
				{
					error_log("filename taken");
					return "filename taken";
				}
			}
			/*generate the node*/
			$code=$this->get_random_node_name("");
			$prep=$this->pdo->prepare("insert into nodes(is_directory,relative_path,code,type)
						   values(false,:root,:code,:type)
						   ");
			$prep->bindParam(':root',$code);
			$prep->bindParam(':code',$code);
			$prep->bindParam(':type',$mimetype);

			if($prep->execute()==false)
			{
				error_log("could not upload file");
				/*not so quiet error*/
				return "error";
			}
			$new_id=$this->get_node_with_code($code);
			/*link the node to the directory*/
			$this->link_nodes($dir_id,$new_id,$filename,$note);
			/*give permissions to the creator*/

			$this->give_view_access($new_id,$user->user_id);
			$this->give_edit_access($new_id,$user->user_id);
			return $code;
		}
		/*checks if there is a link between two node_id-s*/
		function are_linked(int $directory_id,int $node_id): bool
		{
			$prepare=$this->pdo->prepare("select node_id
						      from node_links
						      where node_id=:node_id and directory_id=:dir_id
						      ");
			$prepare->bindParam(':node_id',$node_id);
			$prepare->bindParam(':dir_id',$directory_id);
			if($prepare->execute()==false)
			{
				error_log("there is an sql error in are_linked");
				/*quiet error*/
				return false;
			}
			if(count($prepare->fetch(PDO::FETCH_ASSOC))==1)
			{
				return true;
			}else
			{
				return false;
			}
		}
		function get_shared_node(string $code)
		{
			$prepare=$this->pdo->prepare("
							select * from shared_nodes where code=:code	
					");
			$prepare->bindParam(':code',$code);
			if($prepare->execute()==false)
			{
				error_log("sql statement at get_shared_node failed");
				return NULL;
			}
			$ret=$prepare->fetch(PDO::FETCH_ASSOC);
			$nod=new Shared_Node();
			$nod->node_id=$ret["node_id"];
			$nod->password=$ret["passcode"];
			$nod->code=$ret["code"];
			$nod->is_public=$ret["is_public"];
			return $nod;
		}

		/*returns false if username is taken, email is not checked here*/
		function register_user(string $user,string $password,string $email) : bool
		{
			$hold=$this->get_user($user);
			global $domain_name;
			global $has_email_verification;
			global $password_hash_algo;


			if($hold)
			{
				return false;
			}else
			{
				if($has_email_verification)
				{
					generate_email_verification_link();
				}else
				{
					$hashed_pass=password_hash($password,$password_hash_algo);
					$dirs=$this->create_home_directory();
					$prep=$this->pdo->prepare("insert into users(username,password,email,home_directory) values(:username,:password,:email,:dir)");
					$prep->bindParam(':username',$user);
					$prep->bindParam(':password',$hashed_pass);
					$prep->bindParam(':email',$email);
					$prep->bindParam(':dir',$dirs["home"]);
					if($prep->execute()==false)
					{
						error_log("can't create user because there was an error in the sql statement");
						/*todo make an error page*/
						exit(1);
					}
					$user_id=$this->get_user($user)->user_id;
					$this->give_view_access($dirs["home"],$user_id);
					$this->give_edit_access($dirs["home"],$user_id);

					$this->give_view_access($dirs["trash"],$user_id);
					$this->give_edit_access($dirs["trash"],$user_id);

					$this->give_view_access($dirs["share"],$user_id);
					$this->give_edit_access($dirs["share"],$user_id);
				}
				return true;
			}
		}
	}

$database=new Database();
?>