- Added photo gallery carousel view (gallery.php) with all member albums - Implemented album detail view with responsive photo grid and lightbox - Created album creation/editing form with drag-and-drop photo uploads - Added backend processors for album CRUD operations and photo management - Implemented API endpoints for fetching and deleting photos - Added database migration for photo_albums and photos tables - Included comprehensive feature documentation with testing checklist - Updated .htaccess with URL rewrite rules for gallery routes - Added Gallery link to Members Area menu in header - Created upload directory structure (/assets/uploads/gallery/) - Implemented security: CSRF tokens, ownership verification, file validation - Added transaction safety with rollback on errors and cleanup - Features: Lightbox with keyboard navigation, drag-and-drop uploads, responsive design
16 KiB
Photo Gallery Feature - Complete Implementation
Overview
The Photo Gallery feature allows 4WDCSA members to create, manage, and view photo albums with a carousel interface for browsing and a lightbox viewer for detailed photo viewing.
Database Schema
photo_albums table
- album_id (INT, PK, AUTO_INCREMENT)
- user_id (INT, FK to users)
- title (VARCHAR 255, NOT NULL)
- description (TEXT, nullable)
- cover_image (VARCHAR 500, nullable - stores file path)
- created_at (TIMESTAMP)
- updated_at (TIMESTAMP)
- UNIQUE INDEX on user_id (one album per user for now, can be modified)
- INDEX on created_at for sorting
photos table
- photo_id (INT, PK, AUTO_INCREMENT)
- album_id (INT, FK to photo_albums, CASCADE DELETE)
- file_path (VARCHAR 500, NOT NULL)
- caption (VARCHAR 500, nullable)
- display_order (INT, default 0)
- created_at (TIMESTAMP)
- INDEX on album_id for quick lookups
- INDEX on display_order for sorting
File Structure
Pages (Public-Facing)
src/pages/gallery/gallery.php- Main carousel view of all albumssrc/pages/gallery/view_album.php- Detailed album view with photo grid and lightboxsrc/pages/gallery/create_album.php- Form to create new albums and upload initial photos
Processors (Backend Logic)
src/processors/save_album.php- Creates new album and handles initial photo uploadssrc/processors/update_album.php- Updates album metadata and handles additional photo uploadssrc/processors/delete_album.php- Deletes entire album with all photos and filessrc/processors/delete_photo.php- Deletes individual photos from albumsrc/processors/get_album_photos.php- API endpoint returning album photos as JSON
Styling
All styling is embedded in each PHP file using <style> tags for consistency with existing pattern.
Features
Gallery View (gallery.php)
Purpose: Display all photo albums in a carousel format
Features:
- Bootstrap carousel with Previous/Next buttons
- Album cards showing:
- Cover image
- Album title
- Description
- Creator avatar and name
- Photo count
- "View Album" button
- "Create Album" button (visible to all members)
- Empty state message for members with no albums
- Responsive design for mobile/tablet/desktop
Access Control:
- Members-only (redirects non-members to membership page)
- Verified membership required
Album Detail View (view_album.php)
Purpose: Display all photos from a single album with lightbox viewer
Features:
- Album header with:
- Creator information (avatar, name)
- Album title and description
- Photo count
- "Edit Album" button (visible only to album owner)
- Responsive photo grid layout
- Click any photo to open lightbox viewer
- Lightbox features:
- Full-screen image display
- Previous/Next navigation buttons
- Caption display
- Keyboard navigation:
- Arrow Left: Previous photo
- Arrow Right: Next photo
- Escape: Close lightbox
- Close button (X)
- Empty state message with "Add Photos" link for album owner
- "Back to Gallery" button at bottom
Access Control:
- Public albums visible to all members
- Edit button visible only to album owner
Create/Edit Album (create_album.php)
Purpose: Create new albums or edit existing albums with photo uploads
Features:
- Album title input (required, validates with validateName())
- Description textarea (optional, max 500 characters)
- Drag-and-drop file upload area
- File selection click-to-upload
- Selected files list showing filename and size
- Photo grid showing existing photos (edit mode only)
- Delete button on each existing photo
- Delete album button (edit mode only)
- Submit and Cancel buttons
File Upload Validation:
- Allowed formats: JPG, PNG, GIF, WEBP
- Max file size: 5MB per image
- Validates MIME type and file size
- Generates unique filenames with uniqid()
- Stores in
/assets/uploads/gallery/{album_id}/
Form Behavior:
- Create mode: Only allows setting album metadata and initial photos
- Edit mode: Shows existing photos, allows adding new photos, allows editing metadata
- First uploaded photo becomes cover image (auto-selected)
- Photos can be deleted before submission (edit mode)
- Form prepopulation on edit (title, description, existing photos)
Access Control:
- Members-only
- Edit form checks album ownership before allowing edits
- Redirect to gallery if not owner of album being edited
API Endpoints
GET /get_album_photos
Returns JSON array of photos for an album
Parameters:
id: Album ID (GET parameter)
Response:
[
{
"photo_id": 1,
"file_path": "/assets/uploads/gallery/1/photo_abc123.jpg",
"caption": "Sample photo",
"display_order": 1
}
]
Access Control: Members-only, owner of album only
POST /delete_photo
Deletes a photo and updates album cover if needed
Parameters:
photo_id: Photo ID (POST)csrf_token: CSRF token (POST)
Response:
{ "success": true }
Side Effects:
- Deletes photo file from disk
- Removes photo from database
- Updates album cover image if deleted photo was cover
- Sets cover to first remaining photo or NULL if no photos left
Access Control: Members-only, owner of album only
Workflow Examples
Creating an Album
- User clicks "Create Album" button on gallery page
- Navigates to create_album.php
- Enters album title (required) and description (optional)
- Drags and drops or selects multiple photo files
- Clicks "Create Album" button
- save_album.php:
- Creates album directory:
/assets/uploads/gallery/{album_id}/ - Validates each photo (mime type, file size)
- Moves photos to album directory with unique names
- Sets first photo as cover_image
- Inserts album record and photo records in transaction
- Redirects to view_album page for newly created album
- Creates album directory:
Editing an Album
- User clicks "Edit Album" button on album view page
- Navigates to create_album.php?id={album_id}
- Form prepopulates with current album data
- Existing photos displayed in grid with delete buttons
- Can add more photos by uploading new files
- Clicks "Update Album" button
- update_album.php:
- Verifies ownership
- Updates album metadata
- Validates and uploads any new photos
- Appends new photos to existing ones (doesn't overwrite)
- Redirects back to view_album
Deleting a Photo
- User clicks delete (X) button on photo in edit form
- JavaScript shows confirmation dialog
- Sends POST to delete_photo with photo_id and csrf_token
- delete_photo.php:
- Verifies ownership through album
- Deletes file from disk
- Removes from database
- Updates cover_image if needed
- Returns JSON success response
- Page reloads to show updated photo list
Deleting an Album
- User clicks "Delete Album" button in edit form
- JavaScript shows confirmation dialog
- Navigates to delete_album.php?id={album_id}
- delete_album.php:
- Verifies ownership
- Deletes all photo files from disk
- Deletes all photo records from database
- Deletes album directory
- Deletes album record
- Redirects to gallery page
URL Routing (.htaccess)
/gallery → src/pages/gallery/gallery.php
/create_album → src/pages/gallery/create_album.php
/edit_album → src/pages/gallery/create_album.php (id parameter determines mode)
/view_album → src/pages/gallery/view_album.php
/save_album → src/processors/save_album.php (POST only)
/update_album → src/processors/update_album.php (POST only)
/delete_album → src/processors/delete_album.php (GET with id parameter)
/delete_photo → src/processors/delete_photo.php (POST only)
/get_album_photos → src/processors/get_album_photos.php (GET with id parameter)
Security Features
Authentication
- All pages check for
$_SESSION['user_id'] - Non-members redirected to membership page
- Non-authenticated users redirected to login
Authorization
- Album ownership verified before allowing edits
- Album ownership verified before allowing deletes
- Only album owner can edit or delete photos
- Only album owner can see edit buttons
Data Validation
- Album title validated with validateName() function
- Description length limited to 500 characters
- File uploads validated for:
- MIME type (only image formats allowed)
- File size (max 5MB)
- File extension check
- Filename sanitized with uniqid() to prevent conflicts
CSRF Protection
- All forms include csrf_token
- Processors validate CSRF token before processing
- POST-only operations protected
Transaction Safety
- Album creation uses transaction
- Creates directory
- Inserts album record
- Inserts photo records
- Commits all or rolls back all on error
- Handles cleanup on failure:
- Deletes partial uploads
- Removes album directory
- Removes album record from database
Error Handling
Validation Errors
- File too large: "File too large: {filename}"
- Invalid file type: "Invalid file type: {filename}"
- Missing album title: "Album title is required and must be valid"
- Description too long: "Description must be 500 characters or less"
Permission Errors
- Not authenticated: Redirects to login
- Not a member: Redirects to membership page
- Not album owner: Returns 403 Forbidden with error message
- Album not found: Returns 404 with redirect to gallery
Upload Errors
- Directory creation failure: "Failed to create album directory"
- File move failure: "Failed to upload: {filename}"
- Database insert failure: HTTP 400 with error message
Recovery
- All upload errors trigger transaction rollback
- Partial files cleaned up on failure
- Album record deleted if transaction fails
- Directory removed if transaction fails
Testing Checklist
Album Creation
- Create album with title only
- Create album with title and description
- Upload single photo to new album
- Upload multiple photos to new album
- Verify first photo becomes cover
- Verify files stored in correct directory
- Verify album appears in carousel
Album Editing
- Edit album title
- Edit album description
- Add photos to existing album
- Add many photos at once (10+)
- Delete photos from album
- Delete last photo (cover updates to NULL)
- Delete album cover, verify new cover assigned
- Verify edit unavailable for non-owner
Album Viewing
- View album as owner
- View album as other member
- View album with many photos
- Photo grid responsive on mobile
- Photo grid responsive on tablet
- All photos display correct captions
Lightbox
- Open lightbox from first photo
- Open lightbox from middle photo
- Open lightbox from last photo
- Next button navigates forward
- Previous button navigates backward
- Next button wraps to first photo from last
- Previous button wraps to last photo from first
- Arrow key navigation works
- Escape key closes lightbox
- Click X button closes lightbox
- Photo caption displays correctly
Gallery Page
- Carousel displays all albums
- Previous/Next buttons work
- Album cards show cover image
- Album cards show correct photo count
- Create Album button visible
- Create Album button navigates correctly
- Edit button visible only to owner
- Empty gallery state shows correct message
- Empty gallery has Create Album link
Access Control
- Non-members cannot access gallery
- Non-members cannot create albums
- Non-members cannot edit albums
- Users cannot edit others' albums
- Users cannot delete others' albums
- Users cannot delete others' photos
File Uploads
- JPG files accepted
- PNG files accepted
- GIF files accepted
- WEBP files accepted
- BMP files rejected
- ZIP files rejected
- Files over 5MB rejected
- Files exactly 5MB accepted
- Drag and drop upload works
- Click-to-upload works
Database
- Albums table has correct structure
- Photos table has correct structure
- Foreign keys work correctly
- Cascade delete removes photos when album deleted
- Unique constraint prevents duplicate user ownership
- Indexes created for performance
Navigation
- Gallery link appears in Members Area menu
- Gallery link visible only for logged-in users
- Gallery link locked (with icon) for non-members
- "View Album" button navigates to album detail
- "Edit Album" button navigates to edit form
- "Back to Gallery" button returns to gallery
- "Add Photos" link in empty album goes to edit form
Future Enhancements
Possible Features
- Multiple albums per user (modify UNIQUE constraint)
- Album visibility settings (private/members-only/public)
- Album categories/tags
- Photo ordering/reordering in album
- Photo batch operations (delete multiple, move between albums)
- Album sharing/collaboration
- Photo comments/ratings
- Admin gallery management
- Automatic image optimization/compression
- Photo metadata preservation (EXIF)
- Album archives/export
- Photo search across all albums
Schema Changes Required
- Remove UNIQUE constraint on user_id to allow multiple albums per user
- Add visibility enum field to photo_albums
- Add category_id FK to photo_albums
- Add user_id to photos for future permission model
- Add updated_at timestamps to photos for tracking
Deployment Notes
Pre-Deployment
- Run migration 003 to create tables
- Create
/assets/uploads/gallery/directory with proper permissions - Ensure PHP can write to upload directory (755 or 777)
- Test file upload with valid and invalid files
Post-Deployment
- Verify gallery link appears in header menu
- Test creating first album in production
- Test file uploads with various image formats
- Monitor disk space usage for uploads
- Set up automated cleanup for orphaned files (if needed)
Permissions
/assets/uploads/gallery/
Permissions: 755 (rwxr-xr-x)
Owner: web server user
Individual album directories:
Permissions: 755 (rwxr-xr-x)
Created automatically by application
Photo files:
Permissions: 644 (rw-r--r--)
Created automatically by application
Backups
- Include
/assets/uploads/gallery/in backup routine - Include
photo_albumsandphotostables in database backups - Consider separate backup for large image files
Known Limitations
-
One album per user: Current schema design with UNIQUE constraint on user_id allows only one album per user. Can be modified if multiple albums per user needed.
-
No album visibility control: All member albums are visible to all members. Could add privacy settings in future.
-
No photo ordering UI: Photos ordered by display_order but no UI to reorder them. Captions show filename by default.
-
No album categories: All albums mixed in one carousel. Could add filtering/categories.
-
Image optimization: No automatic compression/optimization. Large images stored as-is.
-
No EXIF data: Photo metadata stripped during upload. Could preserve orientation/metadata.
Troubleshooting
Photos not uploading
- Check
/assets/uploads/gallery/exists and is writable - Verify file sizes under 5MB
- Confirm image MIME types are jpeg, png, gif, or webp
- Check PHP error logs for upload errors
Album cover not updating
- Verify cover_image field in database
- Check if photo file path stored correctly
- Confirm image file exists on disk
Lightbox not opening
- Check browser console for JavaScript errors
- Verify image paths are accessible
- Confirm file URLs accessible directly
Permission denied errors
- Check album owner verification logic
- Verify CSRF tokens being passed correctly
- Confirm user_id matches in session
Memory issues with large uploads
- Reduce PHP memory_limit if needed
- Split large batches of photos into smaller uploads
- Consider image optimization/compression