- 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
495 lines
16 KiB
Markdown
495 lines
16 KiB
Markdown
# 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
|
|
```sql
|
|
- 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
|
|
```sql
|
|
- 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 albums
|
|
- `src/pages/gallery/view_album.php` - Detailed album view with photo grid and lightbox
|
|
- `src/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 uploads
|
|
- `src/processors/update_album.php` - Updates album metadata and handles additional photo uploads
|
|
- `src/processors/delete_album.php` - Deletes entire album with all photos and files
|
|
- `src/processors/delete_photo.php` - Deletes individual photos from album
|
|
- `src/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**:
|
|
```json
|
|
[
|
|
{
|
|
"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**:
|
|
```json
|
|
{ "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
|
|
1. User clicks "Create Album" button on gallery page
|
|
2. Navigates to create_album.php
|
|
3. Enters album title (required) and description (optional)
|
|
4. Drags and drops or selects multiple photo files
|
|
5. Clicks "Create Album" button
|
|
6. 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
|
|
|
|
### Editing an Album
|
|
1. User clicks "Edit Album" button on album view page
|
|
2. Navigates to create_album.php?id={album_id}
|
|
3. Form prepopulates with current album data
|
|
4. Existing photos displayed in grid with delete buttons
|
|
5. Can add more photos by uploading new files
|
|
6. Clicks "Update Album" button
|
|
7. 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
|
|
1. User clicks delete (X) button on photo in edit form
|
|
2. JavaScript shows confirmation dialog
|
|
3. Sends POST to delete_photo with photo_id and csrf_token
|
|
4. delete_photo.php:
|
|
- Verifies ownership through album
|
|
- Deletes file from disk
|
|
- Removes from database
|
|
- Updates cover_image if needed
|
|
- Returns JSON success response
|
|
5. Page reloads to show updated photo list
|
|
|
|
### Deleting an Album
|
|
1. User clicks "Delete Album" button in edit form
|
|
2. JavaScript shows confirmation dialog
|
|
3. Navigates to delete_album.php?id={album_id}
|
|
4. 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
|
|
1. Multiple albums per user (modify UNIQUE constraint)
|
|
2. Album visibility settings (private/members-only/public)
|
|
3. Album categories/tags
|
|
4. Photo ordering/reordering in album
|
|
5. Photo batch operations (delete multiple, move between albums)
|
|
6. Album sharing/collaboration
|
|
7. Photo comments/ratings
|
|
8. Admin gallery management
|
|
9. Automatic image optimization/compression
|
|
10. Photo metadata preservation (EXIF)
|
|
11. Album archives/export
|
|
12. 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
|
|
1. Run migration 003 to create tables
|
|
2. Create `/assets/uploads/gallery/` directory with proper permissions
|
|
3. Ensure PHP can write to upload directory (755 or 777)
|
|
4. Test file upload with valid and invalid files
|
|
|
|
### Post-Deployment
|
|
1. Verify gallery link appears in header menu
|
|
2. Test creating first album in production
|
|
3. Test file uploads with various image formats
|
|
4. Monitor disk space usage for uploads
|
|
5. 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_albums` and `photos` tables in database backups
|
|
- Consider separate backup for large image files
|
|
|
|
## Known Limitations
|
|
|
|
1. **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.
|
|
|
|
2. **No album visibility control**: All member albums are visible to all members. Could add privacy settings in future.
|
|
|
|
3. **No photo ordering UI**: Photos ordered by display_order but no UI to reorder them. Captions show filename by default.
|
|
|
|
4. **No album categories**: All albums mixed in one carousel. Could add filtering/categories.
|
|
|
|
5. **Image optimization**: No automatic compression/optimization. Large images stored as-is.
|
|
|
|
6. **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
|
|
|