A modern PHP 8.0+ gallery CMS designed for ordinary shared hosting. The application uses the filesystem as the authoritative source for gallery structure, while storing all metadata, access rules, votes, user accounts, and audit logs in MySQL or MariaDB.
Current Version: 0.66+
Key Benefit: Deploy in minutes on shared hosting. No npm, no Composer, no framework overhead. Just PHP + MySQL.
- Filesystem-first design - Galleries are folders on disk; the database mirrors and enhances them
- Nested galleries - Create gallery hierarchies with unlimited depth
- Gallery discovery - Automatically detect and import new folders
- Manual creation - Create empty gallery folders from the admin interface
- Bulk operations - Rename, delete, move, reorder, or change visibility for multiple galleries at once
- Gallery metadata - Title, description, optional date range, cover image, custom slug
- Folder management - Moving galleries physically relocates the folder tree on disk
- Upload interface - Upload multiple images to a gallery via browser
- Automatic scanning - Detect newly added files on the filesystem
- Image editing - Edit title, caption, tags, visibility, sort order per image
- Bulk image operations - Reorder, tag, or delete multiple images
- EXIF display - Show image metadata (camera, lens, ISO, GPS coordinates) on public pages
- EXIF/GPS defaults - GPS maps and coordinates are enabled globally by default, with per-gallery inherit, force on and force off controls plus a dashboard reset for all overrides
- EXIF date suggestions - Suggest gallery date ranges from original photo capture dates, including subgalleries, with one reusable editor component for full admin pages and side panels plus editable admin approval
- GPS maps - Render interactive maps when images have location data and the effective EXIF/GPS policy allows display
- Automatic generation - Create optimized thumbnails during import or on-demand
- Multiple formats - JPEG and WebP variants for browser compatibility
- Responsive sizing - Automatically serve appropriately-sized images for device
- Quality tuning - Configurable JPEG quality with automatic size optimization
- DNG RAW support - Generate display masters from DNG raw files
- Lazy loading - Deferred thumbnail loading in fullscreen gallery
- Maintenance tools - Regenerate, delete, or verify thumbnail cache
- Visibility modes - Public, draft (admin-only), or private (password/token protected)
- Password protection - Per-gallery passwords with session-scoped unlock
- Share links - Generate time-limited or permanent share tokens
- Inheritance - Child galleries inherit parent access rules
- Admin-only zones - Some galleries only visible when logged in
- Reusable tags - Global tag system shared across all galleries and images
- Tag metadata - Display name, slug, description, usage statistics
- Gallery tagging - Apply multiple tags to galleries for organization
- Image tagging - Tag individual images for detailed categorization
- Public tag pages - Generate filterable listing pages by tag
- Tag suggestions - Auto-complete tag input when editing
- Tag management - Admin interface to create, rename, edit, or delete tags
- Image voting - Visitors can rate images (+1/-1 or like/dislike)
- Gallery voting - Rate entire galleries
- Score display - Show aggregated scores on public pages
- Vote persistence - Track per-user votes (anonymous via IP hash, logged-in via session)
- Togglable voting - Enable/disable voting per gallery
- Top navigation shortcuts - Optionally show up to three admin-selected favorite galleries or the main gallery page as direct header buttons
- Breadcrumbs - Navigate hierarchy on public pages
- Gallery cards - Display subgalleries with cover images and metadata
- Pagination - Handle large galleries without overwhelming the browser
- Fullscreen viewer - Lightbox with keyboard navigation, zoom, EXIF overlay
- Picture game - Side-by-side image comparison game (optional per-gallery)
- ZIP archives - Download a single gallery or all accessible galleries
- Streaming - Archives streamed directly (not stored on disk)
- Signed downloads - Optional signature verification for secure links
- Theme editor - Customize colors, fonts, spacing and default lightbox browsing mode from the admin interface
- Lightbox browsing modes - Use the classic single image viewer, a picture strip, or a focused 3D carousel as a Theme default with per-gallery overrides
- Dark mode - Switch between light and dark themes
- Language support - English and Czech; easily extensible
- Gallery branding - Per-gallery logo, background, cover image
- Site branding - Site-wide logo and background
- Custom CSS - Direct CSS editing for advanced customization
- Layout control - Choose gallery card layout (vertical/horizontal) and favorite gallery/main-page shortcuts
- One-click updates - Check GitHub and install newer versions from admin dashboard
- Update channels - Follow stable or beta release branches
- Patch notes viewer - Cached release notes with version browsing
- Backup on update - Overwritten files preserved under
cache/updates/backups - Emergency recovery - Revert to stable branch from
reset.php - Database migrations - Automatic schema evolution with admin-triggerable execution
- Overview of galleries, images, and system status
- Quick-access links to common tasks
- Rendering performance profiler (development mode)
- Database integrity checker
- Thumbnail cache analyzer
- Scan
galleries/folder for new directories - Preview detected galleries with folder paths and titles
- Bulk import with optional thumbnail generation
- Create completely new galleries from scratch
- Multi-file upload to existing or new gallery
- Progress bar for transfer and thumbnail generation
- Immediate scanning after upload
- Validation of file types and sizes
- Gallery list with filtering and search
- Expandable/collapsible hierarchy tree
- Bulk rename, delete, move galleries
- Reorder galleries within parent hierarchy
- Inline gallery editing with side panel
- Cover image selection and upload
- Manual gallery date ranges with From and To fields
- EXIF-derived date range suggestions that can be applied directly from a gallery editor without a full page reload, or reviewed, edited and ignored per gallery branch
- Per-gallery image grid
- Bulk image tagging and visibility changes
- Inline image editing with side panel
- Drag-and-drop image reordering
- Image caption and metadata editing
- EXIF preview and GPS display
- Create, edit, rename, or delete tags
- Add descriptions and display names
- View usage statistics per tag
- Bulk tag operations
- Tag auto-complete in edit forms
- Comprehensive audit trail of all admin actions
- Filter by action type, gallery, image, date range
- HTTP method and AJAX flag diagnostics
- Request fingerprinting for security analysis
- Export logs as JSON, CSV, or ZIP
- Status tracking (To Do, In Progress, Done, Waiting)
- Database integrity verification
- File-to-database consistency checking
- Automatic thumbnail rebuilding when needed
- Database migration runner
- File permission diagnostics
- Username and password management
- Optional recovery email for password reset
- Email delivery settings (PHP mail() or SMTP)
- SMTP configuration with TLS/SSL options
- Password reset link lifetime configuration
- Test email functionality
- Anonymous usage statistics (opt-in)
- Gallery and image counts
- Feature usage analytics
- Privacy-respecting collection (no personal data)
- Export and review collected data
- Disable telemetry completely if desired
The easiest way to install on shared hosting is the one-file bootstrap installer:
- Create database - Create an empty MySQL or MariaDB database in your hosting control panel
- Upload one file - Upload
setup-gallery.phpvia FTP to your web directory - Open in browser - Visit
https://example.com/setup-gallery.php - Run installer - Click "Download and start installer"
- Configure - Enter database credentials, choose admin username/password
- Done - The installer sets up everything automatically
The bootstrap installer:
- Downloads the full application from GitHub directly on your server
- Checks if the gallery is already installed (prevents accidental overwrites)
- Creates the database schema via migrations
- Creates the first admin account
- Generates
config.phpwith your settings - Creates
galleries/andcache/folders
After successful installation, you can delete setup-gallery.php via FTP as an extra hardening step.
Minimum:
- PHP 8.0 or newer
- MySQL 5.7+ or MariaDB 10.2+
- PDO MySQL extension
- ZipArchive extension
- GD extension (for thumbnail generation)
Recommended:
- Apache with
.htaccesssupport (for pretty URLs) - Outbound HTTPS access (for updates and GitHub release notes)
Shared hosting considerations:
- Query-string routes work without Apache rewrites
- If FTP upload limits file size, split the upload (e.g.,
public/assets/separately) - Contact host support if outbound downloads are blocked
If you prefer to upload the complete package manually:
- Upload all files to your web server via FTP or your host's file manager
- Open the site in your browser - it automatically redirects to the installer
- Choose your setup mode:
- Shared hosting: Use existing database (create via control panel first)
- Local/VPS: Let installer create database and user
- Enter database credentials and first admin username/password
- The installer creates everything and locks itself with
cache/installed.lock
If you prefer command-line setup or your host doesn't allow browser installation:
# 1. Copy example config
cp config.example.php config.php
# 2. Edit config.php with your database credentials, paths, etc.
nano config.php
# 3. Create database (via MySQL client or phpMyAdmin)
mysql -u root -p < schema.sql
# 4. Run migrations
php scripts/migrate.php
# 5. Create first admin account
php scripts/create_admin.php myusername mypasswordThen visit https://example.com/index.php?page=setup&key=YOUR_SETUP_KEY to verify schema is current.
Run locally with PHP's built-in server:
# From repository root, serve galleries/ as public
php -S localhost:8000 index.php
# Or serve public/ as root
php -S localhost:8000 -t public public/index.phpThen open http://localhost:8000/ in your browser.
- Log in at
?page=admin_loginwith the admin account you created during installation - Go to Discovery to scan for new gallery folders on disk
- Review detected folders and import selected ones
- Leave "Create optimized thumbnails" checked for better performance
- Watch progress bar for import and thumbnail generation
Option A: From FTP (for advanced users)
- Create a folder under
galleries/with image files - Use admin Discovery to import the new folder
Option B: From Admin Interface
- Click Create empty gallery on the dashboard
- Enter gallery name and choose parent gallery
- (Optional) Upload images immediately
- Publish when ready
Option A: Upload from Admin
- Select a gallery and click Upload photos
- Drag-and-drop files or click to browse
- With JavaScript enabled, see transfer and thumbnail progress
- After upload, images are scanned and thumbnails created
Option B: Via FTP
- Upload image files to the gallery folder via FTP
- Use admin Scan for new images to import them
- Create thumbnails from the admin interface
- Use Gallery list to view the hierarchy
- Bulk actions to rename, move, or change visibility of multiple galleries at once
- Drag-and-drop reordering to change display order (JavaScript enabled)
- Edit gallery to change metadata, date range, cover image, tags, description layout, or lightbox browsing-mode override
- Use the EXIF date suggestion beside the gallery date range to apply a range computed from that gallery and all subgalleries; the same component is used in the full editor and side-panel editor, JavaScript updates the fields in place, and the normal POST fallback still works
- Use Review branch suggestions or Gallery dates in Admin maintenance to approve, edit or ignore EXIF-derived ranges for a parent trip gallery and its subgalleries
- Select a gallery to see its images
- Click image thumbnail to open the side panel editor
- Edit title, caption, tags, visibility, or sort order
- Or bulk edit multiple images at once
- Go to Tags in the admin menu
- Create new tags with display names, slugs, and descriptions
- View usage statistics for each tag
- Rename, edit, or delete tags
- Tags auto-complete when editing galleries or images
- Go to Integrity to verify database consistency
- The checker looks for:
- Orphaned gallery records (no folder on disk)
- Missing images in database but visible on disk
- Thumbnail cache health
- File permission issues
- Go to View log to see all admin actions
- Filter by type, gallery, date, or search text
- Mark items as To Do, In Progress, Done, or Waiting
- Export logs as JSON/CSV/ZIP for auditing
- Old logs are kept (retention configurable)
- Go to Updates to check GitHub for new versions
- See available versions and read patch notes
- Click Update to download and install
- Backup of overwritten files saved under
cache/updates/backups/ - Your
config.php, galleries, and custom CSS are never overwritten
- Go to Theme to customize colors, fonts, layout, and the default lightbox browsing mode
- Choose light or dark mode
- Set default gallery card layout (vertical or horizontal)
- Choose language (English, Czech, etc.)
- Upload site-wide logo and background
- Edit raw CSS if you need advanced styling
When you see a "migration pending" notice on the dashboard:
- Click Run database migration (appears automatically)
- Or visit Admin > Migrations
- The runner executes all pending migrations in order
- No action needed after - new features become available
The application reads configuration from config.php (generated during installation). You typically don't need to edit this manually, but key settings include:
$config = [
'database_host' => 'localhost',
'database_name' => 'gallery',
'database_user' => 'gallery_user',
'database_password' => 'secure_password',
'galleries_root' => dirname(__DIR__) . '/galleries',
'zip_cache_path' => dirname(__DIR__) . '/cache/zip',
'base_url' => '', // relative URLs when empty
'admin_session_name' => 'GALLERY_ADMIN_SESSION',
'visitor_vote_secret' => 'random_string_for_vote_hashing',
'setup_key' => '', // set during install, clear after
];For developers interested in the codebase structure, see ARCHITECTURE.md for:
- Request routing and controller dispatch
- Data model and relationships
- Service layer organization
- Feature implementation details
- Performance optimizations
- Security practices
- Database migration system
By default, thumbnails are generated automatically during import. You can fine-tune this:
- Batch generation - Go to Thumbnails to regenerate missing thumbnails in bulk
- Quality settings - Edit in theme settings to balance quality vs. file size
- WebP support - Modern browsers download smaller files automatically
- Lazy loading - Fullscreen galleries defer thumbnail loading
For galleries with 1000+ images:
- Enable pagination in theme settings (defaults to 50 per page)
- Use filtering/search to narrow results
- Create sub-galleries to organize logically
- Add tags to improve findability
On shared hosting with limited resources:
- Disable telemetry if not needed (admin > telemetry settings)
- Delete old logs (admin > logs, export, then prune)
- Clean thumbnail cache periodically (admin > thumbnails > delete thumbnails)
- Use image compression before uploading (optional but recommended)
- Admin passwords are hashed with bcrypt (PHP's
password_hash()) - Gallery passwords are hashed and checked per-visit
- Password reset links are token-based with expiration
- Admin sessions use secure cookies:
HttpOnly- JavaScript cannot accessSameSite=Lax- CSRF protection- HTTPS-only when SSL is detected
- Timeout: browser session (closes when browser exits)
- File type validation (MIME type checking)
- Extension whitelist (only images allowed)
- Uploaded files never executable (
.htaccessprevents PHP execution) - Filenames sanitized to prevent path traversal
- All queries use parameterized statements (no SQL injection)
- Prepared statements with bound variables throughout
- Connection-level permissions (can't drop tables, etc.)
- All user-controlled content HTML-escaped
- Attribute escaping for URLs and form fields
- JSON encoding for API responses
- All state-changing requests require CSRF token
- Token regenerated per-session
- Validated on every POST/PUT/DELETE
- Every admin action logged with:
- Timestamp and action type
- Subject (gallery, image, etc.)
- User account
- HTTP method and IP fingerprint
- Logs exportable for compliance
The codebase is organized for easy extension:
- New controller - Add file in
app/controllers/ - New service - Add file in
app/services/for business logic - New route - Register in
app/bootstrap.phproute table - New migration - Add dated file in
database/migrations/ - Translations - Add strings to
app/lang/en.json,cs.json
- Strict types enabled (
declare(strict_types=1)) - Type hints on all function parameters and returns
- HTML escaping with
e()helper - SQL parameterization with
?placeholders - No external dependencies (pure PHP)
Run the included test files:
php tests/gallery_visibility_model_test.php
php tests/gallery_branding_model_test.phpOr integrate with your test runner (PHPUnit, etc.)
- Go to Discovery and click Scan for new galleries
- Select the folder and click Import
- Check that folder is in the configured
galleries_root - Verify folder has readable image files
- Check that GD extension is installed:
php -m | grep gd - Go to Thumbnails and try manual regeneration
- Check folder permissions:
galleries/must be writable - Review admin log for error messages
If you lose the admin password and can't log in:
- Use the password reset email feature (if configured)
- Or visit
?page=setup&key=YOUR_SETUP_KEYif you know the setup key - Or use CLI:
php scripts/create_admin.php newusername newpassword
- Verify credentials in
config.phpmatch your database - Check database server is running
- Verify user has correct permissions on the database
- For shared hosting, use localhost or 127.0.0.1
- Verify Apache
.htaccesssupport is enabled - Check rewrite module:
apache2ctl -M | grep rewrite - Query-string routes always work (fallback):
?page=gallery&slug=...
- Source Code: https://github.com/klusik/PHP_gallery
- License: MIT (see LICENSE file)
- Author: Rudolf Klusal (@klusik)
For issues, questions, or contributions, please open an issue on GitHub.
See PATCH_NOTES.md for detailed version history and recent changes.
PHP Gallery CMS - Simple, powerful, and runs everywhere. Enjoy! 🎉