/** * upload & validate file * * @param array $file * @param string $dir directory where we will upload the file * @param mixed $id random id used for creating filename * @param string $type it tells whether the file is image, csv, or normal file(default). * @return mixed false in case of failure, array otherwise * @throws Exception If file couldn't be uploaded * */ private static function upload($file, $dir, $id, $type = "file") { $mimeTypes = self::getAllowedMime($type); $validation = new Validation(); $rules = "required|fileErrors|fileUploaded|mimeType(" . Utility::commas($mimeTypes) . ")|fileSize(" . Utility::commas(self::$fileSize) . ")"; $rules = $type === "image" ? $rules . "|imageSize(" . Utility::commas(self::$dimensions) . ")" : $rules; if (!$validation->validate(["File" => [$file, $rules]], true)) { self::$errors = $validation->errors(); return false; } if ($type === "csv") { // you need to add the extension in case of csv files, // because mime() will return text/plain. $basename = "grades" . "." . "csv"; $path = $dir . $basename; $data = ["basename" => $basename, "extension" => "csv"]; } else { if (!empty($id)) { // get safe filename $filename = self::getFileName($file); // mime mapping to extension $ext = self::MimeToExtension(self::mime($file)); // get hashed version using the given $id // the $id is used to have a unique file name // so, for example you would use it for profile picture, // because every user can have only one picture $hashedFileName = self::getHashedName($id); $basename = $hashedFileName . "." . $ext; $path = $dir . $basename; // delete all files with the same name, but with different formats. // not needed, but i like to clear unnecessary files self::deleteFiles($dir . $hashedFileName, $mimeTypes); $data = ["filename" => $filename, "basename" => $basename, "hashed_filename" => $hashedFileName, "extension" => $ext]; } else { $filename = self::getFileName($file); $ext = self::MimeToExtension(self::mime($file)); // hashed file name is created from the original filename and extension // so uploading test.pdf & test.doc won't conflict, // but, uploading file with test.pdf will return "file already exists" $hashedFileName = self::getHashedName(strtolower($filename . $ext)); $basename = $hashedFileName . "." . $ext; $path = $dir . $basename; if (!$validation->validate(["File" => [$path, "fileUnique"]])) { self::$errors = $validation->errors(); return false; } $data = ["filename" => $filename, "basename" => $basename, "hashed_filename" => $hashedFileName, "extension" => $ext]; } } // upload the file. if (!move_uploaded_file($file['tmp_name'], $path)) { throw new Exception("File couldn't be uploaded"); } // set 644 permission to avoid any executable files if (!chmod($path, 0644)) { throw new Exception("File permissions couldn't be changed"); } return $data; }
/** * Update Profile Picture. * * @access public * @param integer $userId * @param array $fileData * @return mixed * @throws Exception If failed to update profile picture. */ public function updateProfilePicture($userId, $fileData) { $image = Uploader::uploadPicture($fileData, $userId); if (!$image) { $this->errors = Uploader::errors(); return false; } $database = Database::openConnection(); $query = "UPDATE users SET profile_picture = :profile_picture WHERE id = :id LIMIT 1"; $database->prepare($query); $database->bindValue(':profile_picture', $image["basename"]); $database->bindValue(':id', $userId); $result = $database->execute(); //if update failed, then delete the user picture if (!$result) { Uploader::deleteFile(IMAGES . "profile_pictures/" . $image["basename"]); throw new Exception("Profile Picture " . $image["basename"] . " couldn't be updated"); } return $image; }
/** * create file. * * @access public * @param integer $userId * @param array $fileData * @return array Array holds the created file * @throws Exception If file couldn't be created */ public function create($userId, $fileData) { //upload $file = Uploader::uploadFile($fileData); if (!$file) { $this->errors = Uploader::errors(); return false; } $database = Database::openConnection(); $query = "INSERT INTO files (user_id, filename, hashed_filename, extension) VALUES (:user_id, :filename, :hashed_filename, :extension)"; $database->prepare($query); $database->bindValue(':user_id', $userId); $database->bindValue(':filename', $file["filename"]); $database->bindValue(':hashed_filename', $file["hashed_filename"]); $database->bindValue(':extension', strtolower($file["extension"])); $database->execute(); //if insert failed, then delete the file if ($database->countRows() !== 1) { Uploader::deleteFile(APP . "uploads/" . $file["basename"]); throw new Exception("Couldn't upload file"); } $fileId = $database->lastInsertedId(); $file = $this->getById($fileId); return $file; }