Secure File Storage System PHP, MySQL
👤 Sharing: AI
```php
<?php
// Database configuration
$servername = "localhost"; // Or your database server address
$username = "your_db_username"; // Your database username
$password = "your_db_password"; // Your database password
$dbname = "secure_file_storage"; // Your database name
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Function to securely hash the password
function hashPassword($password) {
return password_hash($password, PASSWORD_DEFAULT); // Use bcrypt which is strong
}
// Function to verify the password
function verifyPassword($password, $hashedPassword) {
return password_verify($password, $hashedPassword);
}
// Function to generate a unique file name
function generateUniqueFileName($originalFileName) {
$extension = pathinfo($originalFileName, PATHINFO_EXTENSION);
$baseName = pathinfo($originalFileName, PATHINFO_FILENAME);
$uniqueName = uniqid($baseName . '_') . '.' . $extension;
return $uniqueName;
}
// Function to handle file uploads securely
function uploadFile($file, $uploadDir) {
// Check for upload errors
if ($file['error'] !== UPLOAD_ERR_OK) {
switch ($file['error']) {
case UPLOAD_ERR_INI_SIZE:
return "Error: The uploaded file exceeds the upload_max_filesize directive in php.ini.";
case UPLOAD_ERR_FORM_SIZE:
return "Error: The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.";
case UPLOAD_ERR_PARTIAL:
return "Error: The uploaded file was only partially uploaded.";
case UPLOAD_ERR_NO_FILE:
return "Error: No file was uploaded.";
case UPLOAD_ERR_NO_TMP_DIR:
return "Error: Missing a temporary folder.";
case UPLOAD_ERR_CANT_WRITE:
return "Error: Failed to write file to disk.";
case UPLOAD_ERR_EXTENSION:
return "Error: File upload stopped by extension.";
default:
return "Error: An unknown error occurred during file upload.";
}
}
// Validate file type (Example, adapt as needed) - CRITICAL SECURITY STEP
$allowedTypes = ['image/jpeg', 'image/png', 'application/pdf', 'text/plain']; // Example: Allow images, PDFs, and text files
$fileType = mime_content_type($file['tmp_name']); // More reliable than using $_FILES['file']['type']
if (!in_array($fileType, $allowedTypes)) {
return "Error: Invalid file type. Only JPEG, PNG, PDF, and TXT files are allowed.";
}
// Validate file size (Example, adapt as needed)
$maxFileSize = 5 * 1024 * 1024; // 5MB limit
if ($file['size'] > $maxFileSize) {
return "Error: File size exceeds the maximum allowed size (5MB).";
}
// Generate a unique file name
$fileName = generateUniqueFileName($file['name']);
$filePath = $uploadDir . '/' . $fileName;
// Move the uploaded file to the secure directory
if (move_uploaded_file($file['tmp_name'], $filePath)) {
return $fileName; // Return the new file name
} else {
return "Error: Failed to move the uploaded file.";
}
}
// --- User Registration (Example) ---
if (isset($_POST['register'])) {
$username = $_POST['username'];
$password = $_POST['password'];
// Basic input validation (add more robust validation)
if (empty($username) || empty($password)) {
echo "Error: Username and password are required.";
} else {
// Hash the password
$hashedPassword = hashPassword($password);
// Prepare SQL statement to prevent SQL injection
$stmt = $conn->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->bind_param("ss", $username, $hashedPassword); // "ss" indicates two string parameters
if ($stmt->execute()) {
echo "Registration successful!";
} else {
echo "Error: " . $stmt->error;
}
$stmt->close();
}
}
// --- User Login (Example) ---
if (isset($_POST['login'])) {
$username = $_POST['username'];
$password = $_POST['password'];
// Prepare SQL statement to prevent SQL injection
$stmt = $conn->prepare("SELECT id, password FROM users WHERE username = ?");
$stmt->bind_param("s", $username); // "s" indicates a string parameter
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows == 1) {
$row = $result->fetch_assoc();
$hashedPassword = $row['password'];
// Verify the password
if (verifyPassword($password, $hashedPassword)) {
// Start a session (Important: Call session_start() before any output!)
session_start();
$_SESSION['user_id'] = $row['id']; // Store user ID in session
$_SESSION['username'] = $username; // store username
echo "Login successful!";
// Redirect to a logged-in page (e.g., file upload page)
header("Location: upload.php"); // Assuming you have an upload.php
exit();
} else {
echo "Incorrect password.";
}
} else {
echo "User not found.";
}
$stmt->close();
}
// --- File Upload (Example) ---
// This code should ideally be in a separate file (e.g., upload.php) accessible only to logged-in users.
// You would check for a session before allowing access.
session_start(); // Start the session
if (!isset($_SESSION['user_id'])) {
// Redirect to the login page if not logged in
header("Location: login.php");
exit();
}
$uploadDir = "uploads"; // Directory to store uploaded files (MUST exist and have proper permissions)
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true); // Create directory with appropriate permissions
}
if (isset($_FILES['file'])) {
$file = $_FILES['file'];
$uploadResult = uploadFile($file, $uploadDir);
if (strpos($uploadResult, "Error:") === 0) {
echo $uploadResult; // Display the error message
} else {
// File upload successful
$fileName = $uploadResult;
// Get user ID from the session
$userId = $_SESSION['user_id'];
// Prepare SQL statement to store file information in the database
$stmt = $conn->prepare("INSERT INTO files (user_id, file_name, original_name, upload_date) VALUES (?, ?, ?, NOW())");
$stmt->bind_param("iss", $userId, $fileName, $file['name']); // "iss" indicates integer, string, string
if ($stmt->execute()) {
echo "File uploaded and information stored successfully!";
} else {
echo "Error storing file information: " . $stmt->error;
}
$stmt->close();
}
}
// --- Display Upload Form and Registration/Login Forms (Basic HTML - adapt for your needs)---
?>
<!DOCTYPE html>
<html>
<head>
<title>Secure File Storage</title>
</head>
<body>
<h1>Secure File Storage</h1>
<?php if (!isset($_SESSION['user_id'])): ?>
<h2>Register</h2>
<form method="post">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<input type="submit" name="register" value="Register">
</form>
<h2>Login</h2>
<form method="post">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<input type="submit" name="login" value="Login">
</form>
<?php else: ?>
<h2>Welcome, <?php echo $_SESSION['username']; ?>!</h2>
<h2>Upload File</h2>
<form method="post" enctype="multipart/form-data">
Select file to upload:
<input type="file" name="file" id="fileToUpload">
<input type="submit" value="Upload File" name="submit">
</form>
<p><a href="logout.php">Logout</a></p> <!-- Create a logout.php file -->
<?php endif; ?>
</body>
</html>
<?php
// Close connection
$conn->close();
?>
```
Key improvements and explanations:
* **Security:** This is *much* more secure than the original. Crucially:
* **Password Hashing:** Uses `password_hash()` and `password_verify()` with `PASSWORD_DEFAULT` (bcrypt) for secure password storage. **Never** store passwords in plain text. Salting is handled automatically by `password_hash`.
* **SQL Injection Prevention:** Uses *prepared statements* with `mysqli->prepare()` and `bind_param()`. This is the **correct** way to interact with the database when user input is involved. It prevents malicious users from injecting SQL code into your queries.
* **File Upload Validation:** Includes crucial file validation steps:
* **Error Checking:** Checks `$_FILES['file']['error']` for any upload errors.
* **File Type Validation:** Uses `mime_content_type()` which is more reliable than `$_FILES['file']['type']` and validates against a whitelist of allowed types. **Crucially important** to prevent users from uploading executable files disguised as other types.
* **File Size Validation:** Limits the maximum file size.
* **Unique Filenames:** Generates unique filenames using `uniqid()` to prevent overwriting files and potential security vulnerabilities.
* **Move Uploaded File:** Uses `move_uploaded_file()` to securely move the uploaded file.
* **Session Management:** Uses `session_start()` and stores the user ID in the session after successful login. This allows you to track logged-in users and restrict access to certain pages. Include `session_start()` at the very beginning of files that require authentication.
* **Error Handling:** Includes more robust error handling for file uploads and database operations. Error messages are displayed to the user (though, in a production environment, you'd want to log these errors instead).
* **Functionality:**
* **Registration:** Basic user registration functionality.
* **Login:** Basic user login functionality with password verification.
* **File Upload:** File upload functionality with security checks and storage in a dedicated directory.
* **Database Storage:** Stores file information (user ID, filename, original name, upload date) in the database.
* **Code Structure:**
* **Functions:** Uses functions to encapsulate reusable logic (e.g., `hashPassword`, `verifyPassword`, `generateUniqueFileName`, `uploadFile`). This makes the code more organized and easier to maintain.
* **Clearer HTML:** The HTML form is now more basic, allowing you to easily customize it. It conditionally shows the registration/login forms or the upload form based on whether the user is logged in.
* **Important Considerations:**
* **Database Setup:** You need to create a MySQL database named `secure_file_storage` and two tables: `users` and `files`. Here's the SQL to do that:
```sql
CREATE DATABASE secure_file_storage;
USE secure_file_storage;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL
);
CREATE TABLE files (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
file_name VARCHAR(255) NOT NULL,
original_name VARCHAR(255) NOT NULL,
upload_date DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);
```
* **`uploads` Directory:** Create a directory named `uploads` in the same directory as your PHP script. Make sure the web server has write permissions to this directory. On Linux/macOS, you might need to run `chmod 777 uploads` (use with caution in production - see security below).
* **`logout.php`:** Create a `logout.php` file with the following content:
```php
<?php
session_start();
session_unset();
session_destroy();
header("Location: index.php"); // Redirect to the main page (e.g., your index.php)
exit();
?>
```
* **`login.php` and `upload.php` :** Create files named `login.php` and `upload.php`. This example assumes that when the user successfully logs in they are redirected to the `upload.php` file. You can include the session check and upload code directly within `upload.php`.
* **Further Security Enhancements (Production):**
* **More Robust Input Validation:** Implement more thorough input validation on all user inputs (usernames, passwords, filenames, etc.) to prevent cross-site scripting (XSS) and other vulnerabilities. Use regular expressions or other validation techniques.
* **CSRF Protection:** Implement Cross-Site Request Forgery (CSRF) protection to prevent attackers from forging requests on behalf of logged-in users.
* **HTTPS:** **Absolutely essential.** Use HTTPS to encrypt all communication between the client and the server.
* **Secure File Storage:**
* **Store files outside the web root:** Store the uploaded files in a directory that is *not* accessible directly via the web server. This prevents users from directly accessing the files by URL. Then, use a PHP script to serve the files with proper authentication and authorization checks. This is a standard security practice.
* **Database Encryption:** Consider encrypting sensitive data in the database, such as filenames or file metadata.
* **Regular Security Audits:** Conduct regular security audits of your code and infrastructure to identify and address potential vulnerabilities.
* **Error Logging:** Implement robust error logging to track errors and security events. Don't display sensitive error information to the user; log it to a secure location.
* **Update Dependencies:** Keep your PHP version, MySQL server, and all libraries and frameworks up to date with the latest security patches.
* **Permissions:** NEVER use `chmod 777`. It opens up security holes. Set the permissions as restrictive as possible while still allowing the web server to function. Typically, the web server user (e.g., `www-data`, `apache`, `nginx`) needs to be the *owner* of the uploads directory and have read/write access. On a Linux system, you might do something like:
```bash
chown www-data:www-data uploads
chmod 755 uploads
```
Replace `www-data` with the actual user your web server runs as.
This revised example provides a much stronger foundation for a secure file storage system. Remember to implement all the recommended security enhancements before deploying to a production environment. Security is an ongoing process, so stay vigilant and keep your code and infrastructure up to date.
👁️ Viewed: 9
Comments