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(); ?>