svalavuo 6 дней назад
Родитель
Сommit
5b51411ce0
14 измененных файлов с 2010 добавлено и 38 удалено
  1. 88 0
      INSTALL.md
  2. 122 11
      README.md
  3. 326 0
      admin/categories.php
  4. 8 0
      admin/edit.php
  5. 8 0
      admin/index.php
  6. 212 0
      admin/ldap-users.php
  7. 24 4
      admin/login.php
  8. 273 0
      admin/publications.php
  9. 106 0
      css/style.css
  10. 84 6
      includes/auth.php
  11. 250 0
      includes/ldap.php
  12. 358 0
      public/categories.php
  13. 8 5
      setup/database.sql
  14. 143 12
      setup/setup.php

+ 88 - 0
INSTALL.md

@@ -0,0 +1,88 @@
+# Installation Guide
+
+## Quick Setup
+
+### 1. Prerequisites
+- PHP 7.4+ with extensions: PDO, PDO_MySQL, mbstring, LDAP (optional)
+- MariaDB 10.3+ or MySQL 5.7+
+- Web server (Apache, Nginx, or PHP built-in server)
+
+### 2. Database Setup
+```sql
+CREATE DATABASE webpub;
+CREATE USER 'webpub_user'@'localhost' IDENTIFIED BY 'your_password';
+GRANT ALL PRIVILEGES ON webpub.* TO 'webpub_user'@'localhost';
+FLUSH PRIVILEGES;
+```
+
+### 3. Web Server Setup
+Place files in web directory:
+```
+/var/www/html/website/
+```
+
+### 4. Run Setup Wizard
+1. Navigate to: `http://your-domain.com/setup/`
+2. Follow the installation steps
+3. Configure database and authentication (optional LDAP)
+4. Complete installation
+
+### 5. Secure Installation
+```bash
+rm -rf /var/www/html/website/setup/
+chmod 755 /var/www/html/website/
+chmod 644 /var/www/html/website/includes/config.php
+```
+
+## Access Points
+
+- **Public Site**: `http://your-domain.com/public/`
+- **Admin Panel**: `http://your-domain.com/admin/`
+- **Login**: `http://your-domain.com/admin/login.php`
+
+## LDAP Configuration (Optional)
+
+During setup, enable LDAP authentication with these settings:
+
+### Active Directory Example
+```
+LDAP Server Host: ad.example.com
+LDAP Port: 389
+LDAP Base DN: dc=example,dc=com
+User Search Filter: (sAMAccountName={username})
+Email Attribute: mail
+Name Attribute: cn
+```
+
+### OpenLDAP Example
+```
+LDAP Server Host: ldap.example.com
+LDAP Port: 389
+LDAP Base DN: ou=users,dc=example,dc=com
+User Search Filter: (uid={username})
+Email Attribute: mail
+Name Attribute: cn
+```
+
+## Troubleshooting
+
+### Common Issues
+1. **Database Connection**: Check credentials and server status
+2. **File Permissions**: Ensure web server can write to includes/ directory
+3. **LDAP Connection**: Test with external LDAP tools first
+4. **PHP Errors**: Check error logs for detailed messages
+
+### Debug Mode
+Add to top of files for debugging:
+```php
+ini_set('display_errors', 1);
+error_reporting(E_ALL);
+```
+
+## Security Notes
+
+- Delete setup directory after installation
+- Use HTTPS in production
+- Secure LDAP connections with LDAPS
+- Regular updates of PHP and database
+- Monitor authentication logs

+ 122 - 11
README.md

@@ -10,6 +10,8 @@ A simple, clean web publication system built with PHP and MariaDB. This system a
 - **Search**: Full-text search across publications
 - **Responsive Design**: Mobile-friendly interface for both admin and public sites
 - **User Authentication**: Secure login system with password hashing
+- **LDAP Integration**: Optional LDAP directory authentication for enterprise environments
+- **User Management**: Import and manage LDAP users in the system
 - **SEO Friendly**: Clean URLs and meta information
 
 ## Requirements
@@ -18,6 +20,7 @@ A simple, clean web publication system built with PHP and MariaDB. This system a
 - MariaDB 10.3+ or MySQL 5.7+
 - Web server (Apache, Nginx, or PHP built-in server)
 - PHP extensions: PDO, PDO_MySQL, mbstring
+- **For LDAP support**: PHP LDAP extension (optional)
 
 ## Installation
 
@@ -43,12 +46,91 @@ Place the files in your web root or a subdirectory. For example:
 ### 3. Run Setup Script
 
 1. Ensure the `setup/` directory is accessible via web browser
-2. Navigate to: `http://your-domain.com/web-pub-system/setup/`
+2. Navigate to: `http://your-domain.com/setup/`
 3. Follow the installation wizard:
    - Enter database connection details
    - Set site title and admin credentials
+   - **Optional**: Configure LDAP authentication (see LDAP section below)
    - Complete the installation
 
+## LDAP Authentication
+
+The system supports optional LDAP directory authentication for enterprise environments.
+
+### LDAP Setup During Installation
+
+When running the setup script, you can enable LDAP authentication by checking the "Enable LDAP Authentication" option. You'll need to provide:
+
+- **LDAP Server Host**: Your LDAP server hostname or IP address
+- **LDAP Port**: Usually 389 (standard) or 636 (LDAPS)
+- **LDAP Base DN**: The base distinguished name for your directory (e.g., `dc=example,dc=com`)
+- **User Search Filter**: Filter to find users (default: `(uid={username})`)
+- **Bind DN/Password**: Optional service account for LDAP queries
+- **Attribute Mapping**: Email and name attributes from your directory
+
+### LDAP Configuration Examples
+
+#### Active Directory
+```
+LDAP Server Host: ad.example.com
+LDAP Port: 389
+LDAP Base DN: dc=example,dc=com
+User Search Filter: (sAMAccountName={username})
+Email Attribute: mail
+Name Attribute: cn
+```
+
+#### OpenLDAP
+```
+LDAP Server Host: ldap.example.com
+LDAP Port: 389
+LDAP Base DN: ou=users,dc=example,dc=com
+User Search Filter: (uid={username})
+Email Attribute: mail
+Name Attribute: cn
+```
+
+### LDAP User Management
+
+After enabling LDAP authentication:
+
+1. **Access LDAP Users**: Navigate to Admin Panel > LDAP Users
+2. **Search Users**: Use the search interface to find directory users
+3. **Import Users**: Select users and import them into the system
+4. **Authentication**: Users can now login with their directory credentials
+
+### LDAP Authentication Flow
+
+1. User enters directory username and password
+2. System searches LDAP directory for the user
+3. System attempts to bind with user credentials
+4. If successful, user is authenticated and session is created
+5. User information is synchronized with local database
+
+### LDAP Troubleshooting
+
+#### Common Issues
+
+1. **Connection Failed**: Check LDAP server hostname, port, and network connectivity
+2. **Bind Failed**: Verify bind DN and password if using service account
+3. **User Not Found**: Check base DN and user search filter
+4. **Authentication Failed**: Ensure user exists in directory and password is correct
+
+#### Debug Steps
+
+1. Enable PHP error logging
+2. Test LDAP connection with external tools (ldapsearch, Apache Directory Studio)
+3. Check system logs for LDAP connection errors
+4. Verify LDAP server accessibility from web server
+
+### Security Considerations
+
+- Use LDAPS (port 636) for secure connections in production
+- Store bind passwords securely in configuration
+- Limit LDAP service account permissions
+- Monitor LDAP authentication logs
+- Regularly review imported user accounts
+
 ### 4. Secure Installation
 
 After successful installation:
@@ -67,14 +149,15 @@ After successful installation:
 ## Directory Structure
 
 ```
-web-pub-system/
+website/
 |-- admin/                  # Admin interface files
 |   |-- index.php          # Dashboard
-|   |-- login.php          # Login page
+|   |-- login.php          # Login page (supports LDAP)
 |   |-- edit.php           # Create/edit publications
 |   |-- logout.php         # Logout handler
 |   |-- publications.php   # Publication management
 |   |-- categories.php     # Category management
+|   |-- ldap-users.php      # LDAP user management
 |-- public/                 # Public-facing pages
 |   |-- index.php          # Homepage with publication list
 |   |-- publication.php   # Individual publication view
@@ -83,13 +166,14 @@ web-pub-system/
 |-- includes/              # Core PHP classes
 |   |-- config.php         # Configuration (created during setup)
 |   |-- database.php       # Database connection class
-|   |-- auth.php           # Authentication class
+|   |-- auth.php           # Authentication class (supports LDAP)
+|   |-- ldap.php           # LDAP authentication class
 |   |-- publication.php    # Publication model class
 |-- css/                   # Stylesheets
-|   |-- style.css          # Main stylesheet
+|   |-- style.css          # Main stylesheet (includes LDAP styles)
 |-- setup/                 # Installation files (delete after use)
-|   |-- setup.php          # Setup wizard
-|   |-- database.sql       # Database schema
+|   |-- setup.php          # Setup wizard (includes LDAP config)
+|   |-- database.sql       # Database schema (supports LDAP)
 |-- README.md              # This file
 ```
 
@@ -97,13 +181,24 @@ web-pub-system/
 
 ### Admin Panel
 
-1. Access the admin panel at: `http://your-domain.com/web-pub-system/admin/`
-2. Login with the credentials you created during setup
+1. Access the admin panel at: `http://your-domain.com/admin/`
+2. Login with your credentials (local or LDAP)
 3. From the dashboard you can:
    - Create new publications
    - Edit existing publications
    - Manage categories
    - View statistics
+   - **If LDAP enabled**: Manage LDAP users (import, search, sync)
+
+### LDAP User Management
+
+If LDAP authentication is enabled:
+
+1. **Import Users**: Navigate to Admin Panel > LDAP Users
+2. **Search Directory**: Find users by username, name, or email
+3. **Bulk Import**: Select multiple users and import them
+4. **User Roles**: Imported users get default "editor" role
+5. **Login**: Users authenticate with directory credentials
 
 ### Creating Publications
 
@@ -119,7 +214,7 @@ web-pub-system/
 
 ### Public Site
 
-The public site is available at: `http://your-domain.com/web-pub-system/public/`
+The public site is available at: `http://your-domain.com/public/`
 
 Features:
 - Browse all published publications
@@ -141,8 +236,19 @@ define('DB_PASS', 'your_db_password');
 
 // Site configuration
 define('SITE_TITLE', 'Web Publication System');
-define('SITE_URL', 'http://your-domain.com/web-pub-system/');
+define('SITE_URL', 'http://your-domain.com/');
 define('ADMIN_EMAIL', 'admin@example.com');
+
+// LDAP configuration (if enabled)
+define('LDAP_ENABLED', true);
+define('LDAP_HOST', 'ldap.example.com');
+define('LDAP_PORT', '389');
+define('LDAP_BASE_DN', 'dc=example,dc=com');
+define('LDAP_USER_FILTER', '(uid={username})');
+define('LDAP_BIND_DN', 'cn=admin,dc=example,dc=com');
+define('LDAP_BIND_PASSWORD', 'bind_password');
+define('LDAP_EMAIL_ATTRIBUTE', 'mail');
+define('LDAP_NAME_ATTRIBUTE', 'cn');
 ```
 
 ## Security Considerations
@@ -152,6 +258,11 @@ define('ADMIN_EMAIL', 'admin@example.com');
 3. **File permissions**: Ensure proper file permissions on sensitive files
 4. **HTTPS**: Use HTTPS in production for secure login
 5. **Regular updates**: Keep PHP and MariaDB updated
+6. **LDAP Security**: 
+   - Use LDAPS for secure LDAP connections
+   - Limit LDAP service account permissions
+   - Securely store LDAP bind credentials
+   - Monitor LDAP authentication logs
 
 ## Customization
 

+ 326 - 0
admin/categories.php

@@ -0,0 +1,326 @@
+<?php
+require_once '../includes/config.php';
+require_once '../includes/database.php';
+require_once '../includes/auth.php';
+require_once '../includes/publication.php';
+
+// Include LDAP class if LDAP is enabled
+if (LDAP_ENABLED) {
+    require_once '../includes/ldap.php';
+}
+
+$auth = new Auth();
+$auth->requireAuth();
+
+$publication = new Publication();
+$user = $auth->getUser();
+
+// Handle actions
+$action = $_GET['action'] ?? '';
+$message = '';
+$category = null;
+
+if ($action === 'edit' && isset($_GET['id'])) {
+    $id = (int)$_GET['id'];
+    $category = $publication->db->fetch("SELECT * FROM categories WHERE id = ?", [$id]);
+    if (!$category) {
+        die('Category not found');
+    }
+}
+
+if ($action === 'delete' && isset($_GET['id'])) {
+    $id = (int)$_GET['id'];
+    try {
+        // Check if category has publications
+        $pubCount = $publication->db->fetch("SELECT COUNT(*) as count FROM publication_categories WHERE category_id = ?", [$id])['count'];
+        if ($pubCount > 0) {
+            $message = 'Cannot delete category with associated publications';
+        } else {
+            $publication->db->delete('categories', 'id = ?', [$id]);
+            $message = 'Category deleted successfully';
+        }
+    } catch (Exception $e) {
+        $message = 'Error deleting category: ' . $e->getMessage();
+    }
+}
+
+// Handle form submission
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+    $name = trim($_POST['name'] ?? '');
+    $description = trim($_POST['description'] ?? '');
+    $categoryId = (int)($_POST['category_id'] ?? 0);
+    
+    $errors = [];
+    
+    if (empty($name)) $errors[] = 'Category name is required';
+    
+    if (empty($errors)) {
+        try {
+            if ($categoryId > 0) {
+                // Update existing category
+                $publication->db->update('categories', [
+                    'name' => $name,
+                    'description' => $description
+                ], 'id = ?', [$categoryId]);
+                $message = 'Category updated successfully';
+            } else {
+                // Create new category
+                $publication->db->insert('categories', [
+                    'name' => $name,
+                    'description' => $description
+                ]);
+                $message = 'Category created successfully';
+            }
+            
+            // Redirect to avoid form resubmission
+            header('Location: categories.php?message=' . urlencode($message));
+            exit;
+            
+        } catch (Exception $e) {
+            if (strpos($e->getMessage(), 'Duplicate') !== false) {
+                $errors[] = 'Category name already exists';
+            } else {
+                $errors[] = 'Error saving category: ' . $e->getMessage();
+            }
+        }
+    }
+    
+    // Preserve form data on error
+    $category = [
+        'name' => $name,
+        'description' => $description,
+        'id' => $categoryId
+    ];
+}
+
+// Get all categories
+$categories = $publication->getCategories();
+
+// Handle message from redirect
+if (isset($_GET['message'])) {
+    $message = htmlspecialchars($_GET['message']);
+}
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Categories - <?php echo SITE_TITLE; ?></title>
+    <link rel="stylesheet" href="../css/style.css">
+</head>
+<body>
+    <div class="admin-layout">
+        <header class="admin-header">
+            <div class="header-content">
+                <h1><?php echo SITE_TITLE; ?></h1>
+                <nav class="admin-nav">
+                    <a href="index.php" class="nav-link">Dashboard</a>
+                    <a href="publications.php" class="nav-link">Publications</a>
+                    <a href="categories.php" class="nav-link active">Categories</a>
+                    <?php if (LDAP_ENABLED): ?>
+                        <a href="ldap-users.php" class="nav-link">LDAP Users</a>
+                    <?php endif; ?>
+                    <a href="logout.php" class="nav-link">Logout</a>
+                </nav>
+                <div class="user-info">
+                    Welcome, <?php echo htmlspecialchars($user['username']); ?>
+                </div>
+            </div>
+        </header>
+
+        <main class="admin-main">
+            <div class="page-header">
+                <h2>Categories</h2>
+                <a href="categories.php?action=edit" class="btn btn-primary">Create New Category</a>
+            </div>
+            
+            <?php if ($message): ?>
+                <div class="alert alert-<?php echo strpos($message, 'Error') === false ? 'success' : 'error'; ?>">
+                    <?php echo $message; ?>
+                </div>
+            <?php endif; ?>
+
+            <?php if ($action === 'edit' || !empty($errors)): ?>
+                <div class="form-section">
+                    <h3><?php echo $category && $category['id'] > 0 ? 'Edit Category' : 'Create Category'; ?></h3>
+                    
+                    <?php if (!empty($errors)): ?>
+                        <div class="alert alert-error">
+                            <?php foreach ($errors as $error): ?>
+                                <p><?php echo htmlspecialchars($error); ?></p>
+                            <?php endforeach; ?>
+                        </div>
+                    <?php endif; ?>
+                    
+                    <form method="post" class="category-form">
+                        <input type="hidden" name="category_id" value="<?php echo $category['id'] ?? 0; ?>">
+                        
+                        <div class="form-group">
+                            <label for="name">Category Name *</label>
+                            <input type="text" id="name" name="name" 
+                                   value="<?php echo htmlspecialchars($category['name'] ?? ''); ?>" required>
+                        </div>
+                        
+                        <div class="form-group">
+                            <label for="description">Description</label>
+                            <textarea id="description" name="description" rows="3"><?php echo htmlspecialchars($category['description'] ?? ''); ?></textarea>
+                        </div>
+                        
+                        <div class="form-actions">
+                            <button type="submit" class="btn btn-primary">
+                                <?php echo $category && $category['id'] > 0 ? 'Update' : 'Create'; ?> Category
+                            </button>
+                            <a href="categories.php" class="btn btn-secondary">Cancel</a>
+                        </div>
+                    </form>
+                </div>
+            <?php endif; ?>
+
+            <div class="categories-list">
+                <h3>Existing Categories</h3>
+                
+                <?php if (empty($categories)): ?>
+                    <p class="text-center">No categories found. Create your first category above.</p>
+                <?php else: ?>
+                    <div class="category-grid">
+                        <?php foreach ($categories as $cat): ?>
+                            <div class="category-card">
+                                <div class="category-header">
+                                    <h4><?php echo htmlspecialchars($cat['name']); ?></h4>
+                                    <div class="category-actions">
+                                        <a href="categories.php?action=edit&id=<?php echo $cat['id']; ?>" class="btn btn-sm">Edit</a>
+                                        <a href="categories.php?action=delete&id=<?php echo $cat['id']; ?>" 
+                                           class="btn btn-sm btn-danger" 
+                                           onclick="return confirm('Are you sure you want to delete this category?')">
+                                            Delete
+                                        </a>
+                                    </div>
+                                </div>
+                                
+                                <?php if ($cat['description']): ?>
+                                    <p class="category-description"><?php echo htmlspecialchars($cat['description']); ?></p>
+                                <?php endif; ?>
+                                
+                                <div class="category-stats">
+                                    <span class="publication-count">
+                                        <?php echo $cat['publication_count']; ?> publication(s)
+                                    </span>
+                                    <span class="created-date">
+                                        Created <?php echo date('M j, Y', strtotime($cat['created_at'])); ?>
+                                    </span>
+                                </div>
+                            </div>
+                        <?php endforeach; ?>
+                    </div>
+                <?php endif; ?>
+            </div>
+        </main>
+    </div>
+
+    <style>
+        .page-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 2rem;
+        }
+        
+        .form-section {
+            background: white;
+            padding: 2rem;
+            border-radius: 0.5rem;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            margin-bottom: 2rem;
+        }
+        
+        .category-form {
+            max-width: 600px;
+        }
+        
+        .categories-list {
+            background: white;
+            padding: 2rem;
+            border-radius: 0.5rem;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+        }
+        
+        .category-grid {
+            display: grid;
+            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+            gap: 1.5rem;
+            margin-top: 1.5rem;
+        }
+        
+        .category-card {
+            border: 1px solid #dee2e6;
+            border-radius: 0.5rem;
+            padding: 1.5rem;
+            background: #f8f9fa;
+        }
+        
+        .category-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 1rem;
+        }
+        
+        .category-header h4 {
+            margin: 0;
+            color: #495057;
+        }
+        
+        .category-actions {
+            display: flex;
+            gap: 0.5rem;
+        }
+        
+        .category-description {
+            color: #6c757d;
+            margin-bottom: 1rem;
+            font-size: 0.875rem;
+        }
+        
+        .category-stats {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            font-size: 0.75rem;
+            color: #6c757d;
+        }
+        
+        .publication-count {
+            font-weight: 500;
+        }
+        
+        .text-center {
+            text-align: center;
+            padding: 2rem;
+            color: #6c757d;
+        }
+        
+        @media (max-width: 768px) {
+            .page-header {
+                flex-direction: column;
+                gap: 1rem;
+                align-items: stretch;
+            }
+            
+            .category-grid {
+                grid-template-columns: 1fr;
+            }
+            
+            .category-header {
+                flex-direction: column;
+                gap: 1rem;
+                align-items: stretch;
+            }
+            
+            .category-actions {
+                justify-content: center;
+            }
+        }
+    </style>
+</body>
+</html>

+ 8 - 0
admin/edit.php

@@ -4,6 +4,11 @@ require_once '../includes/database.php';
 require_once '../includes/auth.php';
 require_once '../includes/publication.php';
 
+// Include LDAP class if LDAP is enabled
+if (LDAP_ENABLED) {
+    require_once '../includes/ldap.php';
+}
+
 $auth = new Auth();
 $auth->requireAuth();
 
@@ -96,6 +101,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                     <a href="index.php" class="nav-link">Dashboard</a>
                     <a href="publications.php" class="nav-link">Publications</a>
                     <a href="categories.php" class="nav-link">Categories</a>
+                    <?php if (LDAP_ENABLED): ?>
+                        <a href="ldap-users.php" class="nav-link">LDAP Users</a>
+                    <?php endif; ?>
                     <a href="logout.php" class="nav-link">Logout</a>
                 </nav>
                 <div class="user-info">

+ 8 - 0
admin/index.php

@@ -4,6 +4,11 @@ require_once '../includes/database.php';
 require_once '../includes/auth.php';
 require_once '../includes/publication.php';
 
+// Include LDAP class if LDAP is enabled
+if (LDAP_ENABLED) {
+    require_once '../includes/ldap.php';
+}
+
 $auth = new Auth();
 $auth->requireAuth();
 
@@ -47,6 +52,9 @@ $recentPublications = $publication->getAll('all', 10);
                     <a href="index.php" class="nav-link active">Dashboard</a>
                     <a href="publications.php" class="nav-link">Publications</a>
                     <a href="categories.php" class="nav-link">Categories</a>
+                    <?php if (LDAP_ENABLED): ?>
+                        <a href="ldap-users.php" class="nav-link">LDAP Users</a>
+                    <?php endif; ?>
                     <a href="logout.php" class="nav-link">Logout</a>
                 </nav>
                 <div class="user-info">

+ 212 - 0
admin/ldap-users.php

@@ -0,0 +1,212 @@
+<?php
+require_once '../includes/config.php';
+require_once '../includes/database.php';
+require_once '../includes/auth.php';
+require_once '../includes/ldap.php';
+
+$auth = new Auth();
+$auth->requireAuth();
+
+if (!LDAP_ENABLED) {
+    header('Location: index.php');
+    exit;
+}
+
+$ldap = new LDAPAuth();
+$db = Database::getInstance();
+
+$query = $_GET['q'] ?? '';
+$users = [];
+
+if ($query) {
+    $users = $ldap->searchUsers($query);
+}
+
+// Handle user import
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['import_users'])) {
+    $selectedUsers = $_POST['users'] ?? [];
+    
+    foreach ($selectedUsers as $username) {
+        $userInfo = $ldap->getUserInfo($username);
+        if ($userInfo) {
+            $auth->createLDAPUser($username, $userInfo);
+        }
+    }
+    
+    header('Location: ldap-users.php?imported=' . count($selectedUsers));
+    exit;
+}
+
+$user = $auth->getUser();
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>LDAP Users - <?php echo SITE_TITLE; ?></title>
+    <link rel="stylesheet" href="../css/style.css">
+</head>
+<body>
+    <div class="admin-layout">
+        <header class="admin-header">
+            <div class="header-content">
+                <h1><?php echo SITE_TITLE; ?></h1>
+                <nav class="admin-nav">
+                    <a href="index.php" class="nav-link">Dashboard</a>
+                    <a href="publications.php" class="nav-link">Publications</a>
+                    <a href="categories.php" class="nav-link">Categories</a>
+                    <a href="ldap-users.php" class="nav-link active">LDAP Users</a>
+                    <a href="logout.php" class="nav-link">Logout</a>
+                </nav>
+                <div class="user-info">
+                    Welcome, <?php echo htmlspecialchars($user['username']); ?>
+                </div>
+            </div>
+        </header>
+
+        <main class="admin-main">
+            <h2>LDAP Directory Users</h2>
+            
+            <?php if (isset($_GET['imported'])): ?>
+                <div class="alert alert-success">
+                    <?php echo (int)$_GET['imported']; ?> users imported successfully.
+                </div>
+            <?php endif; ?>
+
+            <div class="ldap-search">
+                <form method="get" class="search-form">
+                    <input type="text" name="q" placeholder="Search LDAP users..." 
+                           value="<?php echo htmlspecialchars($query); ?>">
+                    <button type="submit" class="btn btn-primary">Search</button>
+                </form>
+                
+                <?php if ($ldap->testConnection()): ?>
+                    <p class="ldap-status status-ok">LDAP connection: OK</p>
+                <?php else: ?>
+                    <p class="ldap-status status-error">LDAP connection: Failed</p>
+                <?php endif; ?>
+            </div>
+
+            <?php if ($query && !empty($users)): ?>
+                <?php if (count($users) > 0): ?>
+                    <form method="post" class="ldap-import-form">
+                        <div class="table-container">
+                            <table class="admin-table">
+                                <thead>
+                                    <tr>
+                                        <th>
+                                            <input type="checkbox" id="selectAll" onchange="toggleAllCheckboxes()">
+                                        </th>
+                                        <th>Username</th>
+                                        <th>Name</th>
+                                        <th>Email</th>
+                                        <th>Actions</th>
+                                    </tr>
+                                </thead>
+                                <tbody>
+                                    <?php foreach ($users as $ldapUser): ?>
+                                        <?php
+                                        // Check if user already exists
+                                        $existingUser = $db->fetch("SELECT id FROM users WHERE username = ?", [$ldapUser['username']]);
+                                        ?>
+                                        <tr class="<?php echo $existingUser ? 'user-exists' : ''; ?>">
+                                            <td>
+                                                <input type="checkbox" name="users[]" 
+                                                       value="<?php echo htmlspecialchars($ldapUser['username']); ?>"
+                                                       <?php echo $existingUser ? 'disabled' : ''; ?>>
+                                            </td>
+                                            <td><?php echo htmlspecialchars($ldapUser['username']); ?></td>
+                                            <td><?php echo htmlspecialchars($ldapUser['name'] ?? 'N/A'); ?></td>
+                                            <td><?php echo htmlspecialchars($ldapUser['email'] ?? 'N/A'); ?></td>
+                                            <td>
+                                                <?php if ($existingUser): ?>
+                                                    <span class="status-badge status-published">Already Imported</span>
+                                                <?php else: ?>
+                                                    <button type="button" class="btn btn-sm" 
+                                                            onclick="importSingleUser('<?php echo htmlspecialchars($ldapUser['username']); ?>')">
+                                                        Import
+                                                    </button>
+                                                <?php endif; ?>
+                                            </td>
+                                        </tr>
+                                    <?php endforeach; ?>
+                                </tbody>
+                            </table>
+                        </div>
+                        
+                        <div class="form-actions">
+                            <button type="submit" name="import_users" class="btn btn-primary">
+                                Import Selected Users
+                            </button>
+                            <a href="index.php" class="btn btn-secondary">Back to Dashboard</a>
+                        </div>
+                    </form>
+                <?php endif; ?>
+            <?php elseif ($query): ?>
+                <p>No users found matching "<?php echo htmlspecialchars($query); ?>"</p>
+            <?php else: ?>
+                <p>Enter a search query to find LDAP users available for import.</p>
+            <?php endif; ?>
+        </main>
+    </div>
+
+    <script>
+        function toggleAllCheckboxes() {
+            const selectAll = document.getElementById('selectAll');
+            const checkboxes = document.querySelectorAll('input[name="users[]"]:not(:disabled)');
+            
+            checkboxes.forEach(checkbox => {
+                checkbox.checked = selectAll.checked;
+            });
+        }
+        
+        function importSingleUser(username) {
+            const form = document.createElement('form');
+            form.method = 'post';
+            form.innerHTML = '<input type="hidden" name="users[]" value="' + username + '"><input type="hidden" name="import_users" value="1">';
+            document.body.appendChild(form);
+            form.submit();
+        }
+    </script>
+
+    <style>
+        .ldap-search {
+            background: white;
+            padding: 1.5rem;
+            border-radius: 0.5rem;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            margin-bottom: 2rem;
+        }
+        
+        .ldap-status {
+            margin-top: 1rem;
+            padding: 0.5rem;
+            border-radius: 0.25rem;
+            font-weight: 500;
+        }
+        
+        .status-ok {
+            background-color: #d4edda;
+            color: #155724;
+        }
+        
+        .status-error {
+            background-color: #f8d7da;
+            color: #721c24;
+        }
+        
+        .user-exists {
+            background-color: #f8f9fa;
+            opacity: 0.7;
+        }
+        
+        .ldap-import-form {
+            background: white;
+            padding: 1.5rem;
+            border-radius: 0.5rem;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+        }
+    </style>
+</body>
+</html>

+ 24 - 4
admin/login.php

@@ -3,6 +3,11 @@ require_once '../includes/config.php';
 require_once '../includes/database.php';
 require_once '../includes/auth.php';
 
+// Include LDAP class if LDAP is enabled
+if (LDAP_ENABLED) {
+    require_once '../includes/ldap.php';
+}
+
 $auth = new Auth();
 
 if ($auth->isLoggedIn()) {
@@ -39,6 +44,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
         <div class="login-form">
             <h1>Admin Login</h1>
             
+            <?php if (LDAP_ENABLED): ?>
+                <div class="auth-info">
+                    <p class="ldap-notice">
+                        <strong>LDAP Authentication Enabled</strong><br>
+                        Please login with your directory credentials.
+                    </p>
+                </div>
+            <?php endif; ?>
+            
             <?php if (!empty($errors)): ?>
                 <div class="alert alert-error">
                     <?php foreach ($errors as $error): ?>
@@ -49,13 +63,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
             
             <form method="post">
                 <div class="form-group">
-                    <label for="username">Username:</label>
-                    <input type="text" id="username" name="username" required>
+                    <label for="username">
+                        <?php echo LDAP_ENABLED ? 'Directory Username:' : 'Username:'; ?>
+                    </label>
+                    <input type="text" id="username" name="username" required 
+                           placeholder="<?php echo LDAP_ENABLED ? 'Enter your directory username' : 'Enter username'; ?>">
                 </div>
                 
                 <div class="form-group">
-                    <label for="password">Password:</label>
-                    <input type="password" id="password" name="password" required>
+                    <label for="password">
+                        <?php echo LDAP_ENABLED ? 'Directory Password:' : 'Password:'; ?>
+                    </label>
+                    <input type="password" id="password" name="password" required
+                           placeholder="<?php echo LDAP_ENABLED ? 'Enter your directory password' : 'Enter password'; ?>">
                 </div>
                 
                 <button type="submit" class="btn btn-primary">Login</button>

+ 273 - 0
admin/publications.php

@@ -0,0 +1,273 @@
+<?php
+require_once '../includes/config.php';
+require_once '../includes/database.php';
+require_once '../includes/auth.php';
+require_once '../includes/publication.php';
+
+// Include LDAP class if LDAP is enabled
+if (LDAP_ENABLED) {
+    require_once '../includes/ldap.php';
+}
+
+$auth = new Auth();
+$auth->requireAuth();
+
+$publication = new Publication();
+$user = $auth->getUser();
+
+// Handle actions
+$action = $_GET['action'] ?? '';
+$message = '';
+
+if ($action === 'delete' && isset($_GET['id'])) {
+    $id = (int)$_GET['id'];
+    try {
+        $publication->delete($id);
+        $message = 'Publication deleted successfully';
+    } catch (Exception $e) {
+        $message = 'Error deleting publication: ' . $e->getMessage();
+    }
+}
+
+// Get filter parameters
+$status = $_GET['status'] ?? 'all';
+$search = $_GET['search'] ?? '';
+$page = max(1, (int)($_GET['page'] ?? 1));
+$limit = 20;
+$offset = ($page - 1) * $limit;
+
+// Get publications
+if ($search) {
+    $publications = $publication->search($search, $status === 'all' ? 'all' : $status);
+    $totalPublications = count($publications);
+    // Apply pagination
+    $publications = array_slice($publications, $offset, $limit);
+} else {
+    $publications = $publication->getAll($status === 'all' ? 'all' : $status, $limit, $offset);
+    $totalPublications = $publication->db->fetch("SELECT COUNT(*) as count FROM publications" . ($status !== 'all' ? " WHERE status = '$status'" : ""))['count'];
+}
+
+$totalPages = ceil($totalPublications / $limit);
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Publications - <?php echo SITE_TITLE; ?></title>
+    <link rel="stylesheet" href="../css/style.css">
+</head>
+<body>
+    <div class="admin-layout">
+        <header class="admin-header">
+            <div class="header-content">
+                <h1><?php echo SITE_TITLE; ?></h1>
+                <nav class="admin-nav">
+                    <a href="index.php" class="nav-link">Dashboard</a>
+                    <a href="publications.php" class="nav-link active">Publications</a>
+                    <a href="categories.php" class="nav-link">Categories</a>
+                    <?php if (LDAP_ENABLED): ?>
+                        <a href="ldap-users.php" class="nav-link">LDAP Users</a>
+                    <?php endif; ?>
+                    <a href="logout.php" class="nav-link">Logout</a>
+                </nav>
+                <div class="user-info">
+                    Welcome, <?php echo htmlspecialchars($user['username']); ?>
+                </div>
+            </div>
+        </header>
+
+        <main class="admin-main">
+            <div class="page-header">
+                <h2>Publications</h2>
+                <a href="edit.php" class="btn btn-primary">Create New Publication</a>
+            </div>
+            
+            <?php if ($message): ?>
+                <div class="alert alert-<?php echo strpos($message, 'Error') === false ? 'success' : 'error'; ?>">
+                    <?php echo htmlspecialchars($message); ?>
+                </div>
+            <?php endif; ?>
+
+            <div class="filters">
+                <form method="get" class="filter-form">
+                    <div class="filter-group">
+                        <label for="status">Status:</label>
+                        <select id="status" name="status" onchange="this.form.submit()">
+                            <option value="all" <?php echo $status === 'all' ? 'selected' : ''; ?>>All</option>
+                            <option value="published" <?php echo $status === 'published' ? 'selected' : ''; ?>>Published</option>
+                            <option value="draft" <?php echo $status === 'draft' ? 'selected' : ''; ?>>Draft</option>
+                            <option value="archived" <?php echo $status === 'archived' ? 'selected' : ''; ?>>Archived</option>
+                        </select>
+                    </div>
+                    
+                    <div class="filter-group">
+                        <label for="search">Search:</label>
+                        <input type="text" id="search" name="search" value="<?php echo htmlspecialchars($search); ?>" placeholder="Search publications...">
+                    </div>
+                    
+                    <button type="submit" class="btn btn-sm">Filter</button>
+                    <?php if ($search || $status !== 'all'): ?>
+                        <a href="publications.php" class="btn btn-sm btn-secondary">Clear</a>
+                    <?php endif; ?>
+                </form>
+            </div>
+
+            <div class="table-container">
+                <table class="admin-table">
+                    <thead>
+                        <tr>
+                            <th>Title</th>
+                            <th>Author</th>
+                            <th>Status</th>
+                            <th>Created</th>
+                            <th>Updated</th>
+                            <th>Actions</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        <?php if (empty($publications)): ?>
+                            <tr>
+                                <td colspan="6" class="text-center">No publications found.</td>
+                            </tr>
+                        <?php else: ?>
+                            <?php foreach ($publications as $pub): ?>
+                                <tr>
+                                    <td>
+                                        <a href="edit.php?id=<?php echo $pub['id']; ?>">
+                                            <?php echo htmlspecialchars($pub['title']); ?>
+                                        </a>
+                                        <?php if ($pub['summary']): ?>
+                                            <div class="summary-preview">
+                                                <?php echo htmlspecialchars(substr($pub['summary'], 0, 100)) . (strlen($pub['summary']) > 100 ? '...' : ''); ?>
+                                            </div>
+                                        <?php endif; ?>
+                                    </td>
+                                    <td><?php echo htmlspecialchars($pub['author']); ?></td>
+                                    <td>
+                                        <span class="status-badge status-<?php echo $pub['status']; ?>">
+                                            <?php echo ucfirst($pub['status']); ?>
+                                        </span>
+                                    </td>
+                                    <td><?php echo date('M j, Y', strtotime($pub['created_at'])); ?></td>
+                                    <td><?php echo date('M j, Y', strtotime($pub['updated_at'])); ?></td>
+                                    <td>
+                                        <div class="action-buttons">
+                                            <a href="public/publication.php?id=<?php echo $pub['id']; ?>" class="btn btn-sm" target="_blank">View</a>
+                                            <a href="edit.php?id=<?php echo $pub['id']; ?>" class="btn btn-sm">Edit</a>
+                                            <?php if ($pub['status'] === 'draft'): ?>
+                                                <a href="edit.php?id=<?php echo $pub['id']; ?>&action=publish" class="btn btn-sm btn-success">Publish</a>
+                                            <?php endif; ?>
+                                            <a href="publications.php?action=delete&id=<?php echo $pub['id']; ?>" 
+                                               class="btn btn-sm btn-danger" 
+                                               onclick="return confirm('Are you sure you want to delete this publication?')">
+                                                Delete
+                                            </a>
+                                        </div>
+                                    </td>
+                                </tr>
+                            <?php endforeach; ?>
+                        <?php endif; ?>
+                    </tbody>
+                </table>
+            </div>
+
+            <?php if ($totalPages > 1): ?>
+                <div class="pagination">
+                    <?php if ($page > 1): ?>
+                        <a href="?<?php echo http_build_query(array_merge($_GET, ['page' => $page - 1])); ?>" class="pagination-link">« Previous</a>
+                    <?php endif; ?>
+
+                    <?php for ($i = 1; $i <= $totalPages; $i++): ?>
+                        <?php if ($i == $page): ?>
+                            <span class="pagination-current"><?php echo $i; ?></span>
+                        <?php else: ?>
+                            <a href="?<?php echo http_build_query(array_merge($_GET, ['page' => $i])); ?>" class="pagination-link"><?php echo $i; ?></a>
+                        <?php endif; ?>
+                    <?php endfor; ?>
+
+                    <?php if ($page < $totalPages): ?>
+                        <a href="?<?php echo http_build_query(array_merge($_GET, ['page' => $page + 1])); ?>" class="pagination-link">Next »</a>
+                    <?php endif; ?>
+                </div>
+            <?php endif; ?>
+        </main>
+    </div>
+
+    <style>
+        .page-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 2rem;
+        }
+        
+        .filters {
+            background: white;
+            padding: 1.5rem;
+            border-radius: 0.5rem;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            margin-bottom: 2rem;
+        }
+        
+        .filter-form {
+            display: flex;
+            gap: 1rem;
+            align-items: end;
+            flex-wrap: wrap;
+        }
+        
+        .filter-group {
+            display: flex;
+            flex-direction: column;
+            gap: 0.5rem;
+        }
+        
+        .filter-group label {
+            font-weight: 500;
+            font-size: 0.875rem;
+        }
+        
+        .filter-group input,
+        .filter-group select {
+            min-width: 150px;
+        }
+        
+        .summary-preview {
+            font-size: 0.75rem;
+            color: #6c757d;
+            margin-top: 0.25rem;
+            max-width: 300px;
+        }
+        
+        .action-buttons {
+            display: flex;
+            gap: 0.5rem;
+            flex-wrap: wrap;
+        }
+        
+        .text-center {
+            text-align: center;
+            padding: 2rem;
+            color: #6c757d;
+        }
+        
+        @media (max-width: 768px) {
+            .page-header {
+                flex-direction: column;
+                gap: 1rem;
+                align-items: stretch;
+            }
+            
+            .filter-form {
+                flex-direction: column;
+                align-items: stretch;
+            }
+            
+            .action-buttons {
+                flex-direction: column;
+            }
+        }
+    </style>
+</body>
+</html>

+ 106 - 0
css/style.css

@@ -682,6 +682,108 @@ textarea {
     margin-top: 2rem;
 }
 
+/* LDAP Authentication Styles */
+.auth-info {
+    background-color: #e3f2fd;
+    border: 1px solid #bbdefb;
+    border-radius: 0.375rem;
+    padding: 1rem;
+    margin-bottom: 1.5rem;
+}
+
+.ldap-notice {
+    color: #1565c0;
+    font-size: 0.875rem;
+    margin: 0;
+}
+
+.ldap-notice strong {
+    color: #0d47a1;
+}
+
+.help-text {
+    font-size: 0.75rem;
+    color: #6c757d;
+    margin-top: 0.25rem;
+    font-style: italic;
+}
+
+/* LDAP Users Page Styles */
+.ldap-search {
+    background: white;
+    padding: 1.5rem;
+    border-radius: 0.5rem;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    margin-bottom: 2rem;
+}
+
+.ldap-status {
+    margin-top: 1rem;
+    padding: 0.5rem;
+    border-radius: 0.25rem;
+    font-weight: 500;
+}
+
+.status-ok {
+    background-color: #d4edda;
+    color: #155724;
+}
+
+.status-error {
+    background-color: #f8d7da;
+    color: #721c24;
+}
+
+.user-exists {
+    background-color: #f8f9fa;
+    opacity: 0.7;
+}
+
+.ldap-import-form {
+    background: white;
+    padding: 1.5rem;
+    border-radius: 0.5rem;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* Setup Form Enhancements */
+.setup-form {
+    background: white;
+    padding: 2rem;
+    border-radius: 0.5rem;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    max-width: 800px;
+    margin: 0 auto;
+}
+
+.setup-form h2 {
+    border-bottom: 2px solid #007bff;
+    padding-bottom: 0.5rem;
+    margin-top: 2rem;
+    margin-bottom: 1.5rem;
+}
+
+.setup-form h2:first-child {
+    margin-top: 0;
+}
+
+.setup-form h3 {
+    color: #495057;
+    font-size: 1.125rem;
+    margin-bottom: 1rem;
+}
+
+.setup-form input[type="checkbox"] {
+    width: auto;
+    margin-right: 0.5rem;
+}
+
+.setup-form label {
+    font-weight: 500;
+    margin-bottom: 0.5rem;
+    display: block;
+}
+
 /* Responsive Design */
 @media (max-width: 768px) {
     .content-layout {
@@ -725,6 +827,10 @@ textarea {
     .category-checkboxes {
         grid-template-columns: 1fr;
     }
+    
+    .setup-form {
+        padding: 1rem;
+    }
 }
 
 @media (max-width: 480px) {

+ 84 - 6
includes/auth.php

@@ -6,21 +6,45 @@
 
 class Auth {
     private $db;
+    private $ldap;
     
     public function __construct() {
         $this->db = Database::getInstance();
+        if (LDAP_ENABLED) {
+            $this->ldap = new LDAPAuth();
+        }
     }
     
     public function login($username, $password) {
+        // First, try to find user in database
         $sql = "SELECT * FROM users WHERE username = ?";
         $user = $this->db->fetch($sql, [$username]);
         
-        if ($user && password_verify($password, $user['password'])) {
-            $_SESSION['user_id'] = $user['id'];
-            $_SESSION['username'] = $user['username'];
-            $_SESSION['role'] = $user['role'];
-            $_SESSION['logged_in'] = true;
-            return true;
+        if (!$user) {
+            return false;
+        }
+        
+        // Check authentication based on user's auth type
+        if ($user['auth_type'] === 'ldap' && LDAP_ENABLED) {
+            // LDAP authentication
+            if ($this->ldap->authenticate($username, $password)) {
+                // Get LDAP user info and update database
+                $ldapUserInfo = $this->ldap->getUserInfo($username);
+                if ($ldapUserInfo) {
+                    $this->updateUserFromLDAP($user['id'], $ldapUserInfo);
+                }
+                
+                $this->createSession($user);
+                $this->updateLastLogin($user['id']);
+                return true;
+            }
+        } elseif ($user['auth_type'] === 'local') {
+            // Local authentication
+            if ($user['password'] && password_verify($password, $user['password'])) {
+                $this->createSession($user);
+                $this->updateLastLogin($user['id']);
+                return true;
+            }
         }
         
         return false;
@@ -56,6 +80,60 @@ class Auth {
     public function isAdmin() {
         return $this->isLoggedIn() && $_SESSION['role'] === 'admin';
     }
+    
+    private function createSession($user) {
+        $_SESSION['user_id'] = $user['id'];
+        $_SESSION['username'] = $user['username'];
+        $_SESSION['role'] = $user['role'];
+        $_SESSION['auth_type'] = $user['auth_type'];
+        $_SESSION['logged_in'] = true;
+    }
+    
+    private function updateLastLogin($userId) {
+        $sql = "UPDATE users SET last_login = NOW() WHERE id = ?";
+        $this->db->query($sql, [$userId]);
+    }
+    
+    private function updateUserFromLDAP($userId, $ldapUserInfo) {
+        $updateData = [];
+        
+        if (isset($ldapUserInfo['email'])) {
+            $updateData['email'] = $ldapUserInfo['email'];
+        }
+        
+        if (isset($ldapUserInfo['ldap_dn'])) {
+            $updateData['ldap_dn'] = $ldapUserInfo['ldap_dn'];
+        }
+        
+        if (!empty($updateData)) {
+            $this->db->update('users', $updateData, 'id = ?', [$userId]);
+        }
+    }
+    
+    public function createLDAPUser($username, $ldapUserInfo) {
+        // Check if user already exists
+        $sql = "SELECT id FROM users WHERE username = ?";
+        $existing = $this->db->fetch($sql, [$username]);
+        
+        if ($existing) {
+            return $existing['id'];
+        }
+        
+        // Create new user from LDAP
+        $userData = [
+            'username' => $username,
+            'email' => $ldapUserInfo['email'] ?? '',
+            'role' => 'editor', // Default role for LDAP users
+            'auth_type' => 'ldap',
+            'ldap_dn' => $ldapUserInfo['ldap_dn'] ?? ''
+        ];
+        
+        return $this->db->insert('users', $userData);
+    }
+    
+    public function getAuthType() {
+        return $_SESSION['auth_type'] ?? 'local';
+    }
 }
 
 // Initialize session

+ 250 - 0
includes/ldap.php

@@ -0,0 +1,250 @@
+<?php
+/**
+ * LDAP Authentication Class
+ * Handles LDAP directory authentication and user information retrieval
+ */
+
+class LDAPAuth {
+    private $connection;
+    private $config;
+    
+    public function __construct() {
+        $this->config = [
+            'host' => LDAP_HOST,
+            'port' => LDAP_PORT,
+            'base_dn' => LDAP_BASE_DN,
+            'user_filter' => LDAP_USER_FILTER,
+            'bind_dn' => LDAP_BIND_DN,
+            'bind_password' => LDAP_BIND_PASSWORD,
+            'email_attribute' => LDAP_EMAIL_ATTRIBUTE,
+            'name_attribute' => LDAP_NAME_ATTRIBUTE
+        ];
+    }
+    
+    public function authenticate($username, $password) {
+        try {
+            // Connect to LDAP server
+            $this->connect();
+            
+            // First bind with service account if configured
+            if (!empty($this->config['bind_dn'])) {
+                if (!ldap_bind($this->connection, $this->config['bind_dn'], $this->config['bind_password'])) {
+                    throw new Exception('LDAP bind failed with service account');
+                }
+            }
+            
+            // Search for user
+            $filter = str_replace('{username}', ldap_escape($username, '', LDAP_ESCAPE_FILTER), $this->config['user_filter']);
+            $search = ldap_search($this->connection, $this->config['base_dn'], $filter, [$this->config['email_attribute'], $this->config['name_attribute'], 'dn']);
+            
+            if (!$search) {
+                throw new Exception('LDAP search failed');
+            }
+            
+            $entries = ldap_get_entries($this->connection, $search);
+            
+            if ($entries['count'] === 0) {
+                return false;
+            }
+            
+            $user_dn = $entries[0]['dn'];
+            
+            // Try to bind with user credentials
+            if (@ldap_bind($this->connection, $user_dn, $password)) {
+                return true;
+            }
+            
+            return false;
+            
+        } catch (Exception $e) {
+            error_log('LDAP Authentication Error: ' . $e->getMessage());
+            return false;
+        } finally {
+            $this->disconnect();
+        }
+    }
+    
+    public function getUserInfo($username) {
+        try {
+            $this->connect();
+            
+            // Bind with service account if configured
+            if (!empty($this->config['bind_dn'])) {
+                if (!ldap_bind($this->connection, $this->config['bind_dn'], $this->config['bind_password'])) {
+                    throw new Exception('LDAP bind failed with service account');
+                }
+            }
+            
+            // Search for user
+            $filter = str_replace('{username}', ldap_escape($username, '', LDAP_ESCAPE_FILTER), $this->config['user_filter']);
+            $search = ldap_search($this->connection, $this->config['base_dn'], $filter, [
+                $this->config['email_attribute'], 
+                $this->config['name_attribute'], 
+                'dn',
+                'cn',
+                'givenName',
+                'sn',
+                'mail',
+                'uid'
+            ]);
+            
+            if (!$search) {
+                throw new Exception('LDAP search failed');
+            }
+            
+            $entries = ldap_get_entries($this->connection, $search);
+            
+            if ($entries['count'] === 0) {
+                return null;
+            }
+            
+            $user_entry = $entries[0];
+            
+            $userInfo = [
+                'ldap_dn' => $user_entry['dn'],
+                'username' => $username,
+                'email' => $this->getLdapAttribute($user_entry, $this->config['email_attribute']),
+                'name' => $this->getLdapAttribute($user_entry, $this->config['name_attribute']),
+                'first_name' => $this->getLdapAttribute($user_entry, 'givenName'),
+                'last_name' => $this->getLdapAttribute($user_entry, 'sn'),
+                'full_name' => $this->getLdapAttribute($user_entry, 'cn'),
+                'uid' => $this->getLdapAttribute($user_entry, 'uid')
+            ];
+            
+            return $userInfo;
+            
+        } catch (Exception $e) {
+            error_log('LDAP User Info Error: ' . $e->getMessage());
+            return null;
+        } finally {
+            $this->disconnect();
+        }
+    }
+    
+    public function testConnection() {
+        try {
+            $this->connect();
+            
+            // Test bind
+            if (!empty($this->config['bind_dn'])) {
+                $bind_result = ldap_bind($this->connection, $this->config['bind_dn'], $this->config['bind_password']);
+            } else {
+                $bind_result = ldap_bind($this->connection);
+            }
+            
+            if (!$bind_result) {
+                throw new Exception('LDAP bind failed');
+            }
+            
+            // Test search
+            $search = ldap_search($this->connection, $this->config['base_dn'], '(objectClass=*)', ['dn']);
+            if (!$search) {
+                throw new Exception('LDAP search failed');
+            }
+            
+            return true;
+            
+        } catch (Exception $e) {
+            error_log('LDAP Connection Test Error: ' . $e->getMessage());
+            return false;
+        } finally {
+            $this->disconnect();
+        }
+    }
+    
+    private function connect() {
+        $connection_string = $this->config['host'] . ':' . $this->config['port'];
+        
+        $this->connection = ldap_connect($connection_string);
+        
+        if (!$this->connection) {
+            throw new Exception('Failed to connect to LDAP server');
+        }
+        
+        // Set LDAP options
+        ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3);
+        ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0);
+        
+        // Enable TLS if using port 636
+        if ($this->config['port'] == 636) {
+            if (!ldap_start_tls($this->connection)) {
+                throw new Exception('Failed to start TLS');
+            }
+        }
+    }
+    
+    private function disconnect() {
+        if ($this->connection) {
+            ldap_close($this->connection);
+            $this->connection = null;
+        }
+    }
+    
+    private function getLdapAttribute($entry, $attribute) {
+        if (isset($entry[$attribute])) {
+            if ($entry[$attribute]['count'] > 1) {
+                return $entry[$attribute][0]; // Return first value for multi-valued attributes
+            }
+            return $entry[$attribute][0];
+        }
+        return null;
+    }
+    
+    public function searchUsers($query = '', $limit = 50) {
+        try {
+            $this->connect();
+            
+            // Bind with service account if configured
+            if (!empty($this->config['bind_dn'])) {
+                if (!ldap_bind($this->connection, $this->config['bind_dn'], $this->config['bind_password'])) {
+                    throw new Exception('LDAP bind failed with service account');
+                }
+            }
+            
+            // Build search filter
+            if ($query) {
+                $escaped_query = ldap_escape($query, '', LDAP_ESCAPE_FILTER);
+                $filter = "(&(|(uid=*$escaped_query*)(cn=*$escaped_query*)(mail=*$escaped_query*)(givenName=*$escaped_query*)(sn=*$escaped_query*))(!(objectClass=computer)))";
+            } else {
+                $filter = "(&(objectClass=person)(!(objectClass=computer)))";
+            }
+            
+            $search = ldap_search($this->connection, $this->config['base_dn'], $filter, [
+                'uid',
+                'cn',
+                'givenName',
+                'sn',
+                'mail',
+                'dn'
+            ]);
+            
+            if (!$search) {
+                throw new Exception('LDAP search failed');
+            }
+            
+            ldap_control_paged_result($this->connection, $limit);
+            $entries = ldap_get_entries($this->connection, $search);
+            
+            $users = [];
+            for ($i = 0; $i < $entries['count']; $i++) {
+                $user_entry = $entries[$i];
+                $users[] = [
+                    'username' => $this->getLdapAttribute($user_entry, 'uid'),
+                    'name' => $this->getLdapAttribute($user_entry, 'cn'),
+                    'first_name' => $this->getLdapAttribute($user_entry, 'givenName'),
+                    'last_name' => $this->getLdapAttribute($user_entry, 'sn'),
+                    'email' => $this->getLdapAttribute($user_entry, 'mail'),
+                    'ldap_dn' => $user_entry['dn']
+                ];
+            }
+            
+            return $users;
+            
+        } catch (Exception $e) {
+            error_log('LDAP User Search Error: ' . $e->getMessage());
+            return [];
+        } finally {
+            $this->disconnect();
+        }
+    }
+}

+ 358 - 0
public/categories.php

@@ -0,0 +1,358 @@
+<?php
+require_once '../includes/config.php';
+require_once '../includes/database.php';
+require_once '../includes/publication.php';
+
+$publication = new Publication();
+
+$category = $_GET['category'] ?? '';
+$page = max(1, (int)($_GET['page'] ?? 1));
+$limit = 10;
+$offset = ($page - 1) * $limit;
+
+// Get categories for sidebar
+$categories = $publication->getCategories();
+
+// Get publications for selected category or all categories
+if ($category) {
+    $publications = $publication->getByCategory($category, 'published');
+    $totalPublications = count($publications);
+    // Apply pagination
+    $publications = array_slice($publications, $offset, $limit);
+    $currentCategory = $category;
+} else {
+    // Show all publications when no specific category is selected
+    $publications = $publication->getAll('published', $limit, $offset);
+    $totalPublications = $publication->db->fetch("SELECT COUNT(*) as count FROM publications WHERE status = 'published'")['count'];
+    $currentCategory = '';
+}
+
+// Calculate pagination
+$totalPages = ceil($totalPublications / $limit);
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Categories - <?php echo SITE_TITLE; ?></title>
+    <link rel="stylesheet" href="../css/style.css">
+</head>
+<body>
+    <header class="site-header">
+        <div class="container">
+            <h1><a href="index.php"><?php echo SITE_TITLE; ?></a></h1>
+            <nav class="main-nav">
+                <a href="index.php">Home</a>
+                <a href="categories.php" class="active">Categories</a>
+                <a href="search.php">Search</a>
+            </nav>
+        </div>
+    </header>
+
+    <div class="container">
+        <div class="content-layout">
+            <aside class="sidebar">
+                <div class="sidebar-section">
+                    <h3>Search</h3>
+                    <form method="get" action="search.php" class="search-form">
+                        <input type="text" name="q" placeholder="Search publications...">
+                        <button type="submit" class="btn btn-sm">Search</button>
+                    </form>
+                </div>
+
+                <div class="sidebar-section">
+                    <h3>Categories</h3>
+                    <ul class="category-list">
+                        <li>
+                            <a href="categories.php" <?php echo empty($currentCategory) ? 'class="active"' : ''; ?>>
+                                All Categories
+                            </a>
+                        </li>
+                        <?php foreach ($categories as $cat): ?>
+                            <li>
+                                <a href="categories.php?category=<?php echo urlencode($cat['name']); ?>" 
+                                   <?php echo $currentCategory === $cat['name'] ? 'class="active"' : ''; ?>>
+                                    <?php echo htmlspecialchars($cat['name']); ?>
+                                    <span class="count">(<?php echo $cat['publication_count']; ?>)</span>
+                                </a>
+                            </li>
+                        <?php endforeach; ?>
+                    </ul>
+                </div>
+
+                <div class="sidebar-section">
+                    <h3>Category Stats</h3>
+                    <div class="category-stats">
+                        <div class="stat-item">
+                            <span class="stat-label">Total Categories:</span>
+                            <span class="stat-value"><?php echo count($categories); ?></span>
+                        </div>
+                        <div class="stat-item">
+                            <span class="stat-label">Total Publications:</span>
+                            <span class="stat-value">
+                                <?php echo array_sum(array_column($categories, 'publication_count')); ?>
+                            </span>
+                        </div>
+                    </div>
+                </div>
+            </aside>
+
+            <main class="main-content">
+                <div class="page-header">
+                    <h2>
+                        <?php if ($currentCategory): ?>
+                            Category: <?php echo htmlspecialchars($currentCategory); ?>
+                        <?php else: ?>
+                            All Categories
+                        <?php endif; ?>
+                    </h2>
+                    
+                    <?php if ($currentCategory): ?>
+                        <a href="categories.php" class="btn btn-secondary">View All Categories</a>
+                    <?php endif; ?>
+                </div>
+
+                <?php if ($currentCategory): ?>
+                    <div class="category-info">
+                        <?php
+                        $categoryInfo = array_filter($categories, function($cat) use ($currentCategory) {
+                            return $cat['name'] === $currentCategory;
+                        });
+                        $categoryInfo = reset($categoryInfo);
+                        ?>
+                        <?php if ($categoryInfo && $categoryInfo['description']): ?>
+                            <div class="category-description">
+                                <p><?php echo htmlspecialchars($categoryInfo['description']); ?></p>
+                            </div>
+                        <?php endif; ?>
+                        
+                        <p class="results-count">
+                            <?php echo $totalPublications; ?> publications in this category
+                        </p>
+                    </div>
+                <?php else: ?>
+                    <div class="category-overview">
+                        <h3>Category Overview</h3>
+                        <div class="category-grid">
+                            <?php foreach ($categories as $cat): ?>
+                                <?php if ($cat['publication_count'] > 0): ?>
+                                    <div class="category-card">
+                                        <h4>
+                                            <a href="categories.php?category=<?php echo urlencode($cat['name']); ?>">
+                                                <?php echo htmlspecialchars($cat['name']); ?>
+                                            </a>
+                                        </h4>
+                                        <?php if ($cat['description']): ?>
+                                            <p class="category-description">
+                                                <?php echo htmlspecialchars(substr($cat['description'], 0, 150)) . (strlen($cat['description']) > 150 ? '...' : ''); ?>
+                                            </p>
+                                        <?php endif; ?>
+                                        <div class="category-meta">
+                                            <span class="publication-count"><?php echo $cat['publication_count']; ?> publications</span>
+                                            <a href="categories.php?category=<?php echo urlencode($cat['name']); ?>" class="view-link">
+                                                View Publications
+                                            </a>
+                                        </div>
+                                    </div>
+                                <?php endif; ?>
+                            <?php endforeach; ?>
+                        </div>
+                    </div>
+                <?php endif; ?>
+
+                <?php if ($currentCategory && !empty($publications)): ?>
+                    <div class="publication-list">
+                        <h3>Publications in <?php echo htmlspecialchars($currentCategory); ?></h3>
+                        <?php foreach ($publications as $pub): ?>
+                            <article class="publication-summary">
+                                <h3>
+                                    <a href="publication.php?id=<?php echo $pub['id']; ?>">
+                                        <?php echo htmlspecialchars($pub['title']); ?>
+                                    </a>
+                                </h3>
+                                
+                                <?php if ($pub['summary']): ?>
+                                    <p class="summary"><?php echo htmlspecialchars($pub['summary']); ?></p>
+                                <?php endif; ?>
+                                
+                                <div class="meta">
+                                    <span class="author">By <?php echo htmlspecialchars($pub['author']); ?></span>
+                                    <span class="date"><?php echo date('F j, Y', strtotime($pub['created_at'])); ?></span>
+                                    <?php if ($pub['categories']): ?>
+                                        <span class="categories">
+                                            <?php foreach (explode(',', $pub['categories']) as $cat): ?>
+                                                <a href="categories.php?category=<?php echo urlencode(trim($cat)); ?>" class="category-tag">
+                                                    <?php echo htmlspecialchars(trim($cat)); ?>
+                                                </a>
+                                            <?php endforeach; ?>
+                                        </span>
+                                    <?php endif; ?>
+                                </div>
+                            </article>
+                        <?php endforeach; ?>
+                    </div>
+
+                    <?php if ($totalPages > 1): ?>
+                        <div class="pagination">
+                            <?php if ($page > 1): ?>
+                                <a href="?category=<?php echo urlencode($currentCategory); ?>&page=<?php echo $page - 1; ?>" class="pagination-link">« Previous</a>
+                            <?php endif; ?>
+
+                            <?php for ($i = 1; $i <= $totalPages; $i++): ?>
+                                <?php if ($i == $page): ?>
+                                    <span class="pagination-current"><?php echo $i; ?></span>
+                                <?php else: ?>
+                                    <a href="?category=<?php echo urlencode($currentCategory); ?>&page=<?php echo $i; ?>" class="pagination-link"><?php echo $i; ?></a>
+                                <?php endif; ?>
+                            <?php endfor; ?>
+
+                            <?php if ($page < $totalPages): ?>
+                                <a href="?category=<?php echo urlencode($currentCategory); ?>&page=<?php echo $page + 1; ?>" class="pagination-link">Next »</a>
+                            <?php endif; ?>
+                        </div>
+                    <?php endif; ?>
+                <?php elseif ($currentCategory): ?>
+                    <p>No publications found in this category.</p>
+                <?php endif; ?>
+            </main>
+        </div>
+    </div>
+
+    <footer class="site-footer">
+        <div class="container">
+            <p>&copy; <?php echo date('Y'); ?> <?php echo SITE_TITLE; ?>. All rights reserved.</p>
+        </div>
+    </footer>
+
+    <style>
+        .page-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 2rem;
+        }
+        
+        .category-info {
+            background: #f8f9fa;
+            padding: 1.5rem;
+            border-radius: 0.5rem;
+            margin-bottom: 2rem;
+            border-left: 4px solid #007bff;
+        }
+        
+        .category-description {
+            margin-bottom: 1rem;
+        }
+        
+        .category-description p {
+            margin: 0;
+            color: #495057;
+        }
+        
+        .category-overview {
+            margin-bottom: 2rem;
+        }
+        
+        .category-grid {
+            display: grid;
+            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+            gap: 1.5rem;
+            margin-top: 1.5rem;
+        }
+        
+        .category-card {
+            background: white;
+            padding: 1.5rem;
+            border-radius: 0.5rem;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            border: 1px solid #dee2e6;
+        }
+        
+        .category-card h4 {
+            margin-bottom: 1rem;
+        }
+        
+        .category-card h4 a {
+            color: #007bff;
+            text-decoration: none;
+        }
+        
+        .category-card h4 a:hover {
+            text-decoration: underline;
+        }
+        
+        .category-card .category-description {
+            color: #6c757d;
+            margin-bottom: 1rem;
+            font-size: 0.875rem;
+        }
+        
+        .category-meta {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            font-size: 0.875rem;
+        }
+        
+        .publication-count {
+            color: #6c757d;
+            font-weight: 500;
+        }
+        
+        .view-link {
+            color: #007bff;
+            text-decoration: none;
+        }
+        
+        .view-link:hover {
+            text-decoration: underline;
+        }
+        
+        .category-stats {
+            background: white;
+            padding: 1rem;
+            border-radius: 0.375rem;
+            border: 1px solid #dee2e6;
+        }
+        
+        .stat-item {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 0.5rem;
+        }
+        
+        .stat-item:last-child {
+            margin-bottom: 0;
+        }
+        
+        .stat-label {
+            color: #6c757d;
+            font-size: 0.875rem;
+        }
+        
+        .stat-value {
+            font-weight: 600;
+            color: #495057;
+        }
+        
+        @media (max-width: 768px) {
+            .page-header {
+                flex-direction: column;
+                gap: 1rem;
+                align-items: stretch;
+            }
+            
+            .category-grid {
+                grid-template-columns: 1fr;
+            }
+            
+            .category-meta {
+                flex-direction: column;
+                gap: 0.5rem;
+                align-items: flex-start;
+            }
+        }
+    </style>
+</body>
+</html>

+ 8 - 5
setup/database.sql

@@ -17,14 +17,17 @@ CREATE TABLE publications (
     published_at TIMESTAMP NULL
 );
 
--- Users table for admin authentication
+-- Users table for admin authentication with LDAP support
 CREATE TABLE users (
     id INT AUTO_INCREMENT PRIMARY KEY,
     username VARCHAR(50) UNIQUE NOT NULL,
-    password VARCHAR(255) NOT NULL,
+    password VARCHAR(255),
     email VARCHAR(255),
     role ENUM('admin', 'editor') DEFAULT 'editor',
-    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+    auth_type ENUM('local', 'ldap') DEFAULT 'local',
+    ldap_dn VARCHAR(255),
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    last_login TIMESTAMP NULL
 );
 
 -- Categories table
@@ -45,8 +48,8 @@ CREATE TABLE publication_categories (
 );
 
 -- Insert default admin user (password: admin123)
-INSERT INTO users (username, password, email, role) VALUES 
-('admin', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'admin@example.com', 'admin');
+INSERT INTO users (username, password, email, role, auth_type) VALUES 
+('admin', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'admin@example.com', 'admin', 'local');
 
 -- Insert sample categories
 INSERT INTO categories (name, description) VALUES 

+ 143 - 12
setup/setup.php

@@ -19,6 +19,17 @@ $admin_username = 'admin';
 $admin_password = '';
 $admin_email = '';
 
+// LDAP configuration
+$ldap_enabled = false;
+$ldap_host = '';
+$ldap_port = '389';
+$ldap_base_dn = '';
+$ldap_user_filter = '(uid={username})';
+$ldap_bind_dn = '';
+$ldap_bind_password = '';
+$ldap_email_attribute = 'mail';
+$ldap_name_attribute = 'cn';
+
 $errors = [];
 $success = false;
 
@@ -32,12 +43,33 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
     $admin_username = trim($_POST['admin_username'] ?? 'admin');
     $admin_password = trim($_POST['admin_password'] ?? '');
     $admin_email = trim($_POST['admin_email'] ?? '');
+    
+    // LDAP configuration
+    $ldap_enabled = isset($_POST['ldap_enabled']);
+    $ldap_host = trim($_POST['ldap_host'] ?? '');
+    $ldap_port = trim($_POST['ldap_port'] ?? '389');
+    $ldap_base_dn = trim($_POST['ldap_base_dn'] ?? '');
+    $ldap_user_filter = trim($_POST['ldap_user_filter'] ?? '(uid={username})');
+    $ldap_bind_dn = trim($_POST['ldap_bind_dn'] ?? '');
+    $ldap_bind_password = trim($_POST['ldap_bind_password'] ?? '');
+    $ldap_email_attribute = trim($_POST['ldap_email_attribute'] ?? 'mail');
+    $ldap_name_attribute = trim($_POST['ldap_name_attribute'] ?? 'cn');
 
     // Validation
     if (empty($db_user)) $errors[] = 'Database username is required';
-    if (empty($admin_password)) $errors[] = 'Admin password is required';
     if (empty($admin_email)) $errors[] = 'Admin email is required';
     if (!filter_var($admin_email, FILTER_VALIDATE_EMAIL)) $errors[] = 'Invalid email format';
+    
+    // If LDAP is disabled, require admin password
+    if (!$ldap_enabled && empty($admin_password)) {
+        $errors[] = 'Admin password is required when LDAP is disabled';
+    }
+    
+    // LDAP validation
+    if ($ldap_enabled) {
+        if (empty($ldap_host)) $errors[] = 'LDAP host is required when LDAP is enabled';
+        if (empty($ldap_base_dn)) $errors[] = 'LDAP base DN is required when LDAP is enabled';
+    }
 
     if (empty($errors)) {
         try {
@@ -54,9 +86,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
             $pdo->exec($sql);
 
             // Update admin user with provided credentials
-            $hashed_password = password_hash($admin_password, PASSWORD_DEFAULT);
-            $stmt = $pdo->prepare("UPDATE users SET username = ?, password = ?, email = ? WHERE username = 'admin'");
-            $stmt->execute([$admin_username, $hashed_password, $admin_email]);
+            if ($ldap_enabled) {
+                // For LDAP, don't require local password
+                $stmt = $pdo->prepare("UPDATE users SET username = ?, email = ?, auth_type = 'ldap' WHERE username = 'admin'");
+                $stmt->execute([$admin_username, $admin_email]);
+            } else {
+                $hashed_password = password_hash($admin_password, PASSWORD_DEFAULT);
+                $stmt = $pdo->prepare("UPDATE users SET username = ?, password = ?, email = ?, auth_type = 'local' WHERE username = 'admin'");
+                $stmt->execute([$admin_username, $hashed_password, $admin_email]);
+            }
 
             // Create configuration file
             $config_content = "<?php\n";
@@ -68,7 +106,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
             $config_content .= "// Site configuration\n";
             $config_content .= "define('SITE_TITLE', '$site_title');\n";
             $config_content .= "define('SITE_URL', '" . ($_SERVER['HTTPS'] ? 'https' : 'http') . "://{$_SERVER['HTTP_HOST']}" . dirname($_SERVER['PHP_SELF']) . "/../');\n";
-            $config_content .= "define('ADMIN_EMAIL', '$admin_email');\n";
+            $config_content .= "define('ADMIN_EMAIL', '$admin_email');\n\n";
+            $config_content .= "// LDAP configuration\n";
+            $config_content .= "define('LDAP_ENABLED', " . ($ldap_enabled ? 'true' : 'false') . ");\n";
+            $config_content .= "define('LDAP_HOST', '$ldap_host');\n";
+            $config_content .= "define('LDAP_PORT', '$ldap_port');\n";
+            $config_content .= "define('LDAP_BASE_DN', '$ldap_base_dn');\n";
+            $config_content .= "define('LDAP_USER_FILTER', '$ldap_user_filter');\n";
+            $config_content .= "define('LDAP_BIND_DN', '$ldap_bind_dn');\n";
+            $config_content .= "define('LDAP_BIND_PASSWORD', '$ldap_bind_password');\n";
+            $config_content .= "define('LDAP_EMAIL_ATTRIBUTE', '$ldap_email_attribute');\n";
+            $config_content .= "define('LDAP_NAME_ATTRIBUTE', '$ldap_name_attribute');\n";
 
             if (file_put_contents('../includes/config.php', $config_content)) {
                 $success = true;
@@ -143,16 +191,72 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                     <input type="text" id="site_title" name="site_title" value="<?php echo htmlspecialchars($site_title); ?>" required>
                 </div>
 
-                <h2>Administrator Account</h2>
-
+                <h2>Authentication Configuration</h2>
+                
                 <div class="form-group">
-                    <label for="admin_username">Admin Username:</label>
-                    <input type="text" id="admin_username" name="admin_username" value="<?php echo htmlspecialchars($admin_username); ?>" required>
+                    <label>
+                        <input type="checkbox" id="ldap_enabled" name="ldap_enabled" <?php echo $ldap_enabled ? 'checked' : ''; ?> onchange="toggleLdapFields()">
+                        Enable LDAP Authentication
+                    </label>
+                    <p class="help-text">When enabled, users will authenticate against LDAP directory instead of local database.</p>
                 </div>
 
-                <div class="form-group">
-                    <label for="admin_password">Admin Password:</label>
-                    <input type="password" id="admin_password" name="admin_password" required>
+                <div id="ldap_fields" style="display: <?php echo $ldap_enabled ? 'block' : 'none'; ?>;">
+                    <h3>LDAP Configuration</h3>
+                    
+                    <div class="form-group">
+                        <label for="ldap_host">LDAP Server Host:</label>
+                        <input type="text" id="ldap_host" name="ldap_host" value="<?php echo htmlspecialchars($ldap_host); ?>" <?php echo $ldap_enabled ? 'required' : ''; ?>>
+                    </div>
+
+                    <div class="form-group">
+                        <label for="ldap_port">LDAP Port:</label>
+                        <input type="text" id="ldap_port" name="ldap_port" value="<?php echo htmlspecialchars($ldap_port); ?>">
+                    </div>
+
+                    <div class="form-group">
+                        <label for="ldap_base_dn">LDAP Base DN:</label>
+                        <input type="text" id="ldap_base_dn" name="ldap_base_dn" value="<?php echo htmlspecialchars($ldap_base_dn); ?>" <?php echo $ldap_enabled ? 'required' : ''; ?> placeholder="Example: dc=example,dc=com">
+                    </div>
+
+                    <div class="form-group">
+                        <label for="ldap_user_filter">User Search Filter:</label>
+                        <input type="text" id="ldap_user_filter" name="ldap_user_filter" value="<?php echo htmlspecialchars($ldap_user_filter); ?>" placeholder="Example: (uid={username})">
+                    </div>
+
+                    <div class="form-group">
+                        <label for="ldap_bind_dn">Bind DN (optional):</label>
+                        <input type="text" id="ldap_bind_dn" name="ldap_bind_dn" value="<?php echo htmlspecialchars($ldap_bind_dn); ?>" placeholder="Leave empty for anonymous bind">
+                    </div>
+
+                    <div class="form-group">
+                        <label for="ldap_bind_password">Bind Password (optional):</label>
+                        <input type="password" id="ldap_bind_password" name="ldap_bind_password" value="<?php echo htmlspecialchars($ldap_bind_password); ?>">
+                    </div>
+
+                    <div class="form-group">
+                        <label for="ldap_email_attribute">Email Attribute:</label>
+                        <input type="text" id="ldap_email_attribute" name="ldap_email_attribute" value="<?php echo htmlspecialchars($ldap_email_attribute); ?>">
+                    </div>
+
+                    <div class="form-group">
+                        <label for="ldap_name_attribute">Name Attribute:</label>
+                        <input type="text" id="ldap_name_attribute" name="ldap_name_attribute" value="<?php echo htmlspecialchars($ldap_name_attribute); ?>">
+                    </div>
+                </div>
+
+                <div id="local_auth_fields" style="display: <?php echo $ldap_enabled ? 'none' : 'block'; ?>;">
+                    <h3>Local Administrator Account</h3>
+
+                    <div class="form-group">
+                        <label for="admin_username">Admin Username:</label>
+                        <input type="text" id="admin_username" name="admin_username" value="<?php echo htmlspecialchars($admin_username); ?>" <?php echo !$ldap_enabled ? 'required' : ''; ?>>
+                    </div>
+
+                    <div class="form-group">
+                        <label for="admin_password">Admin Password:</label>
+                        <input type="password" id="admin_password" name="admin_password" <?php echo !$ldap_enabled ? 'required' : ''; ?>>
+                    </div>
                 </div>
 
                 <div class="form-group">
@@ -164,5 +268,32 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
             </form>
         <?php endif; ?>
     </div>
+    <script>
+        function toggleLdapFields() {
+            const ldapEnabled = document.getElementById('ldap_enabled').checked;
+            const ldapFields = document.getElementById('ldap_fields');
+            const localAuthFields = document.getElementById('local_auth_fields');
+            const adminUsername = document.getElementById('admin_username');
+            const adminPassword = document.getElementById('admin_password');
+            const ldapHost = document.getElementById('ldap_host');
+            const ldapBaseDn = document.getElementById('ldap_base_dn');
+            
+            if (ldapEnabled) {
+                ldapFields.style.display = 'block';
+                localAuthFields.style.display = 'none';
+                adminUsername.removeAttribute('required');
+                adminPassword.removeAttribute('required');
+                ldapHost.setAttribute('required', 'required');
+                ldapBaseDn.setAttribute('required', 'required');
+            } else {
+                ldapFields.style.display = 'none';
+                localAuthFields.style.display = 'block';
+                adminUsername.setAttribute('required', 'required');
+                adminPassword.setAttribute('required', 'required');
+                ldapHost.removeAttribute('required');
+                ldapBaseDn.removeAttribute('required');
+            }
+        }
+    </script>
 </body>
 </html>