Project Description: A simple web application developed in PHP, MySQL, and HTML/CSS that allows administrators to manage British Columbia wines and provides users with a recommender interface to find wines based on criteria like colour, body, sweetness, and specific flavor notes.
-
Complete CRUD Operations
- Create, Read, Update, and Delete wine records
- Image upload and deletion (managed during creation and editing)
- Relational data management for wine flavor notes (many-to-many relationship)
-
User Authentication
- Secure registration and login system for administrators
- Passwords securely stored using
password_hash() - Session-based access control to protect the
/Privateadmin directory
-
Data Validation
- Server-side validation for all admin forms.
- Required field validation for core inputs (Name, Winery, Region, etc.)
- Price validation (numeric and positive check)
- Secure file upload validation (type, size, and PHP error checking).
- Input persistence upon validation failure
-
Database Integrity
- Foreign Key constraints enforce the link between
wineandtasting-notes - Deletion cleanup using transactions to remove associated tasting notes before deleting the main wine record
- Prevents orphaned data and maintains relational integrity
- Foreign Key constraints enforce the link between
-
Security Features
- Prepared Statements (PDO) utilized for all database interaction to prevent SQL Injection.
- XSS Protection with
html_escape() - Safe file handling using unique filenames and secured file paths.
-
Public Filtering & UI
- Relational Recommender Engine capable of querying wines by multiple criteria (Colour, Body, Sweetness) and arrays of flavor notes.
- Responsive design for accessibility.
- Clear success/error messaging (via
$_SESSIONand form display). - Image previews displayed during the editing process.
- PHP 8.1+ - Server-side scripting
- MySQL - Database management
- PDO - Database abstraction layer
- HTML5 - Page structure
- CSS3 - Styling and layout
- Prepared Statements - SQL injection prevention
BC-WINE-RECOMMENDER/
├── Private/
│ ├── includes/
│ ├── header_private.php # Admin dashboard header
│ └──side_nav.php # Side navigation for Admin dashboard
│ ├── add_wine.php # Add wine
│ ├── dashboard.php # Admin dashboard
│ ├── delete-wine.php # Delete wine
│ ├── edit-wine.php # Edit wine
│ ├── logout.php # Redirect to login
│ └── manage_wines.php # View all wines
├── Public/
│ ├── images/ # User uploaded wine images
│ ├── includes/
│ ├── config.php # Configuration settings
│ ├── create_first_admin.php # Used to create first admin
│ ├── Database.php # Database connection & helpers
│ ├── footer.php # Header template
│ ├── nav.php # Navigation template
│ └── process_filters.php # Process filters & redirect to recommended
│ ├── about.php # About page
│ ├── index.php # Home page
│ ├── login.php # Login page
│ ├── recommended.php # Recommended wines page
│ ├── database.sql # Database schema & sample data
│ ├── register.php # New user registration
│ └── styles.css # CSS Styles
├── README.md # This file
└── wine_db.sql # Wine database
- PHP 8.1 or higher
- MySQL 5.7 or higher (or MariaDB).
- Apache/Nginx web server.
- PDO MySQL extension enabled
-
Create a new MySQL database:
CREATE DATABASE bc_wine_recommender CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
Import the database schema:
mysql -u root -p bc_wine_recommender < wine_db.sqlOr use phpMyAdmin to import the
wine_db.sqlfile.
Edit the database connection file, Public/includes/Database.php, and update the credentials and paths:
// Database Connection Credentials
define('DB_HOST', 'localhost');
define('DB_NAME', 'bc_wine_recommender');
define('DB_USER', 'your_username');
define('DB_PASS', 'your_password');
// File Upload Path Constant (Adjust if your base path changes)
define('UPLOAD_PATH', __DIR__ . '/../images/');Make sure the images/ directory is writable:
chmod 755 images/Navigate to: http://localhost/BC-WINE-RECOMMENDER/Public/
This section covers the CRUD operations for the wine records, including image and tasting note management.
- Navigate to Admin > Manage Wines.
- View all wines listed with the Name, Colour, Price, and edit and delete actions.
- Click EDIT to modify a wine's profile, image, and tasting notes.
- Click DELETE to permanently remove a wine record.
- Click the "ADD NEW WINE" button.
- Enter mandatory Product Information (Name, Winery, Region, Description).
- Upload an image file for the wine label (optional, but recommended).
- Enter the Recommendation Filters (Colour, Body, Sweetness, Price).
- Select all applicable Tasting Notes (flavor profiles) from the grid.
- Click "SAVE NEW WINE".
- Click the EDIT button on any wine from the list.
- Modify any text fields, dropdown selections, or price.
- To change the image, click "Choose File" and upload a new image; the system will automatically delete the old image file upon successful update.
- Modify the Tasting Notes by checking/unchecking the relevant checkboxes.
- Click "Save Wine Profile Changes".
- Click the DELETE button next to the desired wine.
- Confirm the deletion.
- The main wine record, along with all associated tasting notes and the physical image file will be automatically deleted due to the database integrity setup.
This section covers the registration and access features for administrators.
- Navigate to the
/Public/register.phpURL. - Enter a unique Username.
- Enter and confirm a strong Password (minimum 8 characters).
- Click "Register".
- Navigate to
/Public/login.php. - Enter your registered Username and Password.
- Click "Log In" to be redirected to the Dashboard.
- Click the "Log Out" link (usually located in the navigation bar) to clear your session and return to the login screen.
This technique prevents SQL Injection by sending the query structure and the data to the database separately.
// Example from edit-wine.php (using positional placeholders)
$sql_wine_update = "
UPDATE wine SET
name = ?, winery = ?, region = ?, colour = ?, body = ?,
sweetness = ?, price = ?, description = ?, image_url = ?
WHERE wine_id = ?
";
// ... execution follows using executePS($pdo, $sql_wine_update, $params_wine_update);- Used in
add-wine.phpto retrieve the automatically generatedwine_idafter inserting the new wine record, which is necessary for immediately linking the tasting notes in the next step.
- Used in the authentication and login process to verify that exactly one row (the admin user) matches the provided credentials.
- Database Transactions: Implemented in
edit-wine.phpanddelete-wine.phpto guarantee that multi-step operations (e.g., deleting notes AND deleting wine) either fully succeed or fully fail (COMMITorROLLBACK), ensuring data integrity. - Duplicate Handling: The specific
try...catchlogic is used inregister.php(and should be used inadd-wine.php) to catch database errors (like unique constraint violations) and display a user-friendly error message instead of crashing.
- The code follows the sequential flow of checking conditions: check for
$_GETID, check for$_POSTsubmission, validate data, process database operations if no errors, and finally, display errors or redirect. This ensures user input is retained on failure.
- Robust logic in
edit-wine.phpensures files are checked for type and size, given a unique filename to prevent collisions, and the old file is safely deleted when replaced.
id- **Primary key **name- Name of the winewinery- Winery namecolour- Colour of winebody- Body of winesweetness- Sweetness of winedescription- Brief description of wineimage_url- Image urlupdated_at- Timestamp of last update
note_id- **Primary key **wine_id- **Foreign key ** towinetable. Links the note to a specific wineflavour_note- Flavour notes of wine
id- **Primary key **username- Unique login usernamepassword- Securely stored password
- All database queries use prepared statements
- No direct SQL string concatenation
- All output rendered to the user is passed through escaping functions.
- Using the native
htmlspecialchars()function and/or a customhtml_escape()helper function
- Validation of file extension and size limits
- Generation of a unique filename for storage
- Password Hashing
The database includes sample data:
- 14 sample wine records
- The related flavour notes for the 14 wines
- 3 admin users
- Check database credentials (
config.php) - Ensure MySQL service is running
- Verify the database exists
- Check
uploads/directory permissions (should be writable, e.g.,755). - Verify PHP limits in
php.ini:upload_max_filesizeandpost_max_size
- Enable error reporting in development mode (
config.php) - Check PHP error logs for the fatal error message
- Ensure PHP PDO MySQL extension is installed
- User Roles: Implement Admin/User roles to prevent unauthorized users from deleting wines
- Backend Access: Block non-admin users from accessing the backend/management pages
- Filters: Make the price and region filters on
recommender.phpfunctional - Surprise Button: Add the random selection logic (e.g.,
ORDER BY RAND() LIMIT 1) to the "Surprise Me" button.
- Advanced Filtering: Add filtering options for Grape Variety and Score.
- Recommendation Logic: Implement smarter logic to recommend wines based on shared characteristics.