ONLINE AUCTION SYSTEM
Introduction
The Online Auction System is a dynamic web platform that enables users to list items for auction and place bids on items they wish to purchase. The system supports multiple auction types including regular auctions, reserve price auctions, and featured listings. Users can track their bids, manage their listings, and receive notifications on auction status. The platform includes both user and admin interfaces with comprehensive auction management features. Real-time bidding updates, automatic outbid notifications, and secure payment processing make this a complete auction marketplace solution.
Project Features
User Features:
- User Registration and Email Verification
- User Login with Remember Me
- Browse Active Auctions by Categories
- Advanced Search with Filters (Price, Category, Condition)
- View Auction Details with Countdown Timer
- Place Bids on Active Auctions
- Automatic Outbid Email Notifications
- Watchlist/Favorite Auctions
- Create New Auction Listings with Multiple Images
- Reserve Price Option for Sellers
- Buy It Now Option for Immediate Purchase
- Manage My Auctions (Edit, Cancel, Relist)
- Track Bidding History
- View Won Auctions and Payment Status
- Seller Rating and Reviews System
- Secure Payment Integration (PayPal/Stripe Demo)
- User Dashboard with Statistics
- Profile Management with Avatar Upload
- Message Center for Buyer-Seller Communication
- Bid Auto-Refresh with AJAX
- Auction Ending Soon Alerts
Admin Features:
- Admin Dashboard with Real-time Analytics
- User Management (View, Edit, Suspend, Ban)
- Auction Management (Approve, Reject, Feature)
- Category Management (Add, Edit, Delete)
- Reported Auctions Management
- Transaction Monitoring and Fee Calculation
- Site Settings Configuration
- Commission and Fee Management
- Banner and Promotional Management
- Email Template Management
- System Logs and Error Reports
- Backup and Restore Functionality
- Sales and Revenue Reports
- Featured Auction Management
Project File Structure
online-auction-system/ │ ├── assets/ │ ├── css/ │ │ ├── style.css │ │ ├── admin-style.css │ │ ├── responsive.css │ │ └── bootstrap.min.css │ ├── js/ │ │ ├── main.js │ │ ├── auction.js │ │ ├── bidding.js │ │ ├── countdown.js │ │ ├── admin.js │ │ └── jquery.min.js │ └── images/ │ ├── auctions/ │ ├── categories/ │ ├── avatars/ │ └── banners/ │ ├── uploads/ │ ├── auction_images/ │ └── temp/ │ ├── database/ │ └── auction_system.sql │ ├── includes/ │ ├── config.php │ ├── db_connection.php │ ├── functions.php │ ├── auth.php │ ├── auction_functions.php │ ├── bidding_functions.php │ ├── payment_functions.php │ └── notification_functions.php │ ├── admin/ │ ├── index.php │ ├── login.php │ ├── logout.php │ ├── dashboard.php │ ├── users.php │ ├── user-details.php │ ├── auctions.php │ ├── auction-details.php │ ├── approve-auction.php │ ├── categories.php │ ├── add-category.php │ ├── edit-category.php │ ├── delete-category.php │ ├── transactions.php │ ├── reports.php │ ├── settings.php │ ├── featured-auctions.php │ ├── reported-auctions.php │ ├── messages.php │ ├── email-templates.php │ ├── backup.php │ └── profile.php │ ├── user/ │ ├── index.php │ ├── register.php │ ├── login.php │ ├── logout.php │ ├── verify-email.php │ ├── forgot-password.php │ ├── reset-password.php │ ├── dashboard.php │ ├── profile.php │ ├── create-auction.php │ ├── edit-auction.php │ ├── my-auctions.php │ ├── my-bids.php │ ├── won-auctions.php │ ├── watchlist.php │ ├── auction-details.php │ ├── place-bid.php │ ├── buy-now.php │ ├── payment.php │ ├── payment-success.php │ ├── leave-review.php │ ├── messages.php │ ├── conversation.php │ ├── notifications.php │ └── settings.php │ ├── api/ │ ├── get-bids.php │ ├── place-bid.php │ ├── check-auction-status.php │ ├── search-auctions.php │ ├── upload-image.php │ ├── notifications.php │ └── auto-refresh.php │ ├── index.php ├── auctions.php ├── auction.php ├── categories.php ├── search.php ├── about.php ├── contact.php ├── faq.php ├── how-it-works.php ├── terms.php ├── privacy.php ├── sitemap.php ├── 404.php ├── .htaccess └── robots.txt
Database Schema (auction_system.sql)
-- Create Database
CREATE DATABASE IF NOT EXISTS auction_system;
USE auction_system;
-- Table: users
CREATE TABLE users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
full_name VARCHAR(100),
phone VARCHAR(20),
address TEXT,
city VARCHAR(50),
state VARCHAR(50),
country VARCHAR(50),
postal_code VARCHAR(20),
avatar VARCHAR(255),
role ENUM('user', 'admin', 'moderator') DEFAULT 'user',
status ENUM('active', 'suspended', 'banned') DEFAULT 'active',
email_verified BOOLEAN DEFAULT FALSE,
verification_token VARCHAR(100),
reset_token VARCHAR(100),
reset_expiry DATETIME,
last_login DATETIME,
last_ip VARCHAR(45),
rating DECIMAL(3,2) DEFAULT 0.00,
total_reviews INT DEFAULT 0,
total_auctions INT DEFAULT 0,
total_sales INT DEFAULT 0,
total_purchases INT DEFAULT 0,
balance DECIMAL(10,2) DEFAULT 0.00,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_email (email),
INDEX idx_status (status),
INDEX idx_role (role)
);
-- Insert default admin
INSERT INTO users (username, email, password, full_name, role, email_verified)
VALUES ('admin', '[email protected]', MD5('Admin@123'), 'System Administrator', 'admin', TRUE);
-- Insert sample user
INSERT INTO users (username, email, password, full_name, email_verified)
VALUES ('john_doe', '[email protected]', MD5('John@123'), 'John Doe', TRUE);
-- Table: categories
CREATE TABLE categories (
category_id INT PRIMARY KEY AUTO_INCREMENT,
category_name VARCHAR(100) NOT NULL,
category_slug VARCHAR(100) UNIQUE NOT NULL,
category_description TEXT,
parent_category_id INT,
category_image VARCHAR(255),
icon VARCHAR(50),
is_active BOOLEAN DEFAULT TRUE,
display_order INT DEFAULT 0,
auction_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (parent_category_id) REFERENCES categories(category_id) ON DELETE CASCADE,
INDEX idx_parent (parent_category_id),
INDEX idx_active (is_active)
);
-- Insert default categories
INSERT INTO categories (category_name, category_slug, icon, display_order) VALUES
('Electronics', 'electronics', 'fa-laptop', 1),
('Fashion', 'fashion', 'fa-tshirt', 2),
('Home & Garden', 'home-garden', 'fa-home', 3),
('Sports & Outdoors', 'sports-outdoors', 'fa-futbol', 4),
('Collectibles & Art', 'collectibles-art', 'fa-paint-brush', 5),
('Books & Media', 'books-media', 'fa-book', 6),
('Jewelry & Watches', 'jewelry-watches', 'fa-gem', 7),
('Toys & Hobbies', 'toys-hobbies', 'fa-gamepad', 8),
('Automotive', 'automotive', 'fa-car', 9),
('Real Estate', 'real-estate', 'fa-building', 10);
-- Table: auctions
CREATE TABLE auctions (
auction_id INT PRIMARY KEY AUTO_INCREMENT,
seller_id INT NOT NULL,
category_id INT NOT NULL,
title VARCHAR(200) NOT NULL,
slug VARCHAR(250) UNIQUE NOT NULL,
description TEXT NOT NULL,
short_description VARCHAR(500),
condition ENUM('new', 'like-new', 'good', 'fair', 'poor') DEFAULT 'good',
starting_price DECIMAL(10,2) NOT NULL,
reserve_price DECIMAL(10,2),
current_price DECIMAL(10,2),
buy_it_now_price DECIMAL(10,2),
min_bid_increment DECIMAL(10,2) DEFAULT 1.00,
quantity INT DEFAULT 1,
featured BOOLEAN DEFAULT FALSE,
featured_until DATETIME,
status ENUM('pending', 'active', 'ended', 'sold', 'cancelled', 'rejected') DEFAULT 'pending',
start_time DATETIME NOT NULL,
end_time DATETIME NOT NULL,
view_count INT DEFAULT 0,
bid_count INT DEFAULT 0,
watcher_count INT DEFAULT 0,
winner_id INT,
sold_price DECIMAL(10,2),
payment_status ENUM('pending', 'paid', 'shipped', 'completed', 'disputed') DEFAULT 'pending',
shipping_cost DECIMAL(10,2) DEFAULT 0.00,
shipping_details TEXT,
payment_method VARCHAR(50),
payment_date DATETIME,
is_reported BOOLEAN DEFAULT FALSE,
report_reason TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (seller_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (category_id) REFERENCES categories(category_id),
FOREIGN KEY (winner_id) REFERENCES users(user_id) ON DELETE SET NULL,
INDEX idx_status (status),
INDEX idx_seller (seller_id),
INDEX idx_category (category_id),
INDEX idx_featured (featured),
INDEX idx_endtime (end_time),
INDEX idx_search (title, description),
FULLTEXT INDEX ft_search (title, description)
);
-- Table: auction_images
CREATE TABLE auction_images (
image_id INT PRIMARY KEY AUTO_INCREMENT,
auction_id INT NOT NULL,
image_path VARCHAR(255) NOT NULL,
is_primary BOOLEAN DEFAULT FALSE,
display_order INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (auction_id) REFERENCES auctions(auction_id) ON DELETE CASCADE,
INDEX idx_auction (auction_id)
);
-- Table: bids
CREATE TABLE bids (
bid_id INT PRIMARY KEY AUTO_INCREMENT,
auction_id INT NOT NULL,
bidder_id INT NOT NULL,
bid_amount DECIMAL(10,2) NOT NULL,
is_winning BOOLEAN DEFAULT FALSE,
bid_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR(45),
FOREIGN KEY (auction_id) REFERENCES auctions(auction_id) ON DELETE CASCADE,
FOREIGN KEY (bidder_id) REFERENCES users(user_id) ON DELETE CASCADE,
INDEX idx_auction (auction_id),
INDEX idx_bidder (bidder_id),
INDEX idx_amount (bid_amount)
);
-- Table: watchlist
CREATE TABLE watchlist (
watch_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
auction_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (auction_id) REFERENCES auctions(auction_id) ON DELETE CASCADE,
UNIQUE KEY unique_watch (user_id, auction_id)
);
-- Table: reviews
CREATE TABLE reviews (
review_id INT PRIMARY KEY AUTO_INCREMENT,
auction_id INT NOT NULL,
reviewer_id INT NOT NULL,
reviewee_id INT NOT NULL,
rating INT NOT NULL CHECK (rating >= 1 AND rating <= 5),
comment TEXT,
response TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (auction_id) REFERENCES auctions(auction_id) ON DELETE CASCADE,
FOREIGN KEY (reviewer_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (reviewee_id) REFERENCES users(user_id) ON DELETE CASCADE,
UNIQUE KEY unique_review (auction_id, reviewer_id),
INDEX idx_reviewee (reviewee_id)
);
-- Table: messages
CREATE TABLE messages (
message_id INT PRIMARY KEY AUTO_INCREMENT,
sender_id INT NOT NULL,
receiver_id INT NOT NULL,
auction_id INT,
subject VARCHAR(200),
message TEXT NOT NULL,
is_read BOOLEAN DEFAULT FALSE,
parent_message_id INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (sender_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (receiver_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (auction_id) REFERENCES auctions(auction_id) ON DELETE SET NULL,
FOREIGN KEY (parent_message_id) REFERENCES messages(message_id) ON DELETE CASCADE,
INDEX idx_conversation (sender_id, receiver_id),
INDEX idx_read (is_read)
);
-- Table: transactions
CREATE TABLE transactions (
transaction_id INT PRIMARY KEY AUTO_INCREMENT,
auction_id INT NOT NULL,
buyer_id INT NOT NULL,
seller_id INT NOT NULL,
amount DECIMAL(10,2) NOT NULL,
commission DECIMAL(10,2) NOT NULL,
seller_amount DECIMAL(10,2) NOT NULL,
payment_method VARCHAR(50),
transaction_status ENUM('pending', 'completed', 'failed', 'refunded') DEFAULT 'pending',
payment_id VARCHAR(100),
payer_email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (auction_id) REFERENCES auctions(auction_id) ON DELETE CASCADE,
FOREIGN KEY (buyer_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (seller_id) REFERENCES users(user_id) ON DELETE CASCADE,
INDEX idx_auction (auction_id),
INDEX idx_buyer (buyer_id),
INDEX idx_seller (seller_id)
);
-- Table: notifications
CREATE TABLE notifications (
notification_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
type ENUM('outbid', 'won', 'ended', 'payment', 'message', 'review', 'system') NOT NULL,
title VARCHAR(200),
message TEXT,
link VARCHAR(500),
is_read BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE,
INDEX idx_user (user_id),
INDEX_idx_read (is_read)
);
-- Table: site_settings
CREATE TABLE site_settings (
setting_id INT PRIMARY KEY AUTO_INCREMENT,
setting_key VARCHAR(100) UNIQUE NOT NULL,
setting_value TEXT,
setting_type ENUM('text', 'number', 'boolean', 'json') DEFAULT 'text',
setting_description TEXT,
updated_by INT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (updated_by) REFERENCES users(user_id) ON DELETE SET NULL
);
-- Insert default settings
INSERT INTO site_settings (setting_key, setting_value, setting_type, setting_description) VALUES
('site_name', 'AuctionHub', 'text', 'Website name'),
('site_url', 'http://localhost/online-auction-system/', 'text', 'Website URL'),
('admin_email', '[email protected]', 'text', 'Administrator email'),
('commission_rate', '5.00', 'number', 'Commission rate for sales (%)'),
('min_auction_duration', '1', 'number', 'Minimum auction duration in days'),
('max_auction_duration', '30', 'number', 'Maximum auction duration in days'),
('max_images_per_auction', '10', 'number', 'Maximum images per auction'),
('enable_paypal', '1', 'boolean', 'Enable PayPal payment'),
('enable_stripe', '1', 'boolean', 'Enable Stripe payment'),
('paypal_email', '[email protected]', 'text', 'PayPal business email'),
('stripe_publishable_key', '', 'text', 'Stripe publishable key'),
('stripe_secret_key', '', 'text', 'Stripe secret key'),
('maintenance_mode', '0', 'boolean', 'Maintenance mode status'),
('registration_enabled', '1', 'boolean', 'Enable user registration'),
('email_verification', '1', 'boolean', 'Require email verification'),
('auto_approve_auctions', '0', 'boolean', 'Automatically approve new auctions');
-- Table: activity_logs
CREATE TABLE activity_logs (
log_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
action VARCHAR(100) NOT NULL,
details TEXT,
ip_address VARCHAR(45),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE SET NULL,
INDEX idx_user (user_id),
INDEX idx_action (action),
INDEX idx_created (created_at)
);
-- Table: reported_auctions
CREATE TABLE reported_auctions (
report_id INT PRIMARY KEY AUTO_INCREMENT,
auction_id INT NOT NULL,
reporter_id INT NOT NULL,
reason ENUM('fake', 'misleading', 'inappropriate', 'copyright', 'other') NOT NULL,
description TEXT,
status ENUM('pending', 'reviewed', 'resolved', 'dismissed') DEFAULT 'pending',
reviewed_by INT,
reviewed_at DATETIME,
action_taken TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (auction_id) REFERENCES auctions(auction_id) ON DELETE CASCADE,
FOREIGN KEY (reporter_id) REFERENCES users(user_id) ON DELETE CASCADE,
FOREIGN KEY (reviewed_by) REFERENCES users(user_id) ON DELETE SET NULL,
INDEX idx_status (status)
);
Core PHP Files
1. includes/config.php
<?php
// Database configuration
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'auction_system');
// Application configuration
define('SITE_NAME', 'AuctionHub');
define('SITE_URL', 'http://localhost/online-auction-system/');
define('ADMIN_URL', SITE_URL . 'admin/');
define('USER_URL', SITE_URL . 'user/');
define('UPLOAD_DIR', $_SERVER['DOCUMENT_ROOT'] . '/online-auction-system/uploads/');
define('AUCTION_IMG_DIR', UPLOAD_DIR . 'auction_images/');
define('TEMP_DIR', UPLOAD_DIR . 'temp/');
// Auction settings
define('MIN_AUCTION_DAYS', 1);
define('MAX_AUCTION_DAYS', 30);
define('MAX_IMAGES_PER_AUCTION', 10);
define('COMMISSION_RATE', 5.00); // Percentage
define('MIN_BID_INCREMENT', 1.00);
define('AUTO_RELIST_EXPIRED', false);
// Pagination settings
define('ITEMS_PER_PAGE', 20);
define('AUCTIONS_PER_PAGE', 12);
// Security settings
define('SESSION_TIMEOUT', 7200); // 2 hours
define('ENABLE_SSL', false);
define('HASH_COST', 10);
define('CSRF_TOKEN_NAME', 'csrf_token');
// Email settings
define('SMTP_HOST', 'smtp.gmail.com');
define('SMTP_PORT', 587);
define('SMTP_USER', '[email protected]');
define('SMTP_PASS', 'your-password');
define('SMTP_ENCRYPTION', 'tls');
define('FROM_EMAIL', '[email protected]');
define('FROM_NAME', 'Auction System');
// Payment settings
define('PAYPAL_MODE', 'sandbox'); // sandbox or live
define('PAYPAL_CLIENT_ID', 'your-paypal-client-id');
define('PAYPAL_SECRET', 'your-paypal-secret');
define('STRIPE_PUBLISHABLE_KEY', 'your-stripe-publishable-key');
define('STRIPE_SECRET_KEY', 'your-stripe-secret-key');
// Timezone
date_default_timezone_set('UTC');
// Error reporting (disable in production)
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Start session if not started
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// Set default currency
define('CURRENCY', '$');
?>
2. includes/db_connection.php
<?php
require_once 'config.php';
class Database {
private $connection;
private static $instance = null;
private $stmt;
private function __construct() {
$this->connect();
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new Database();
}
return self::$instance;
}
private function connect() {
$this->connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($this->connection->connect_error) {
die("Connection failed: " . $this->connection->connect_error);
}
$this->connection->set_charset("utf8mb4");
}
public function getConnection() {
return $this->connection;
}
public function escape($string) {
return $this->connection->real_escape_string(trim($string));
}
public function query($sql) {
return $this->connection->query($sql);
}
public function prepare($sql) {
$this->stmt = $this->connection->prepare($sql);
return $this->stmt;
}
public function execute($params = []) {
if (!empty($params) && $this->stmt) {
$types = '';
$values = [];
foreach ($params as $param) {
if (is_int($param)) {
$types .= 'i';
} elseif (is_float($param)) {
$types .= 'd';
} elseif (is_string($param)) {
$types .= 's';
} else {
$types .= 'b';
}
$values[] = $param;
}
$this->stmt->bind_param($types, ...$values);
}
return $this->stmt->execute();
}
public function getResult() {
return $this->stmt->get_result();
}
public function fetchAssoc() {
return $this->stmt->get_result()->fetch_assoc();
}
public function fetchAll() {
return $this->stmt->get_result()->fetch_all(MYSQLI_ASSOC);
}
public function lastInsertId() {
return $this->connection->insert_id;
}
public function affectedRows() {
return $this->connection->affected_rows;
}
public function beginTransaction() {
$this->connection->begin_transaction();
}
public function commit() {
$this->connection->commit();
}
public function rollback() {
$this->connection->rollback();
}
public function __destruct() {
if ($this->stmt) {
$this->stmt->close();
}
if ($this->connection) {
$this->connection->close();
}
}
}
// Global database instance
$db = Database::getInstance();
$conn = $db->getConnection();
?>
3. includes/functions.php
<?php
require_once 'db_connection.php';
// Redirect to specified page
function redirect($url) {
header("Location: $url");
exit();
}
// Check if user is logged in
function isLoggedIn() {
return isset($_SESSION['user_id']) && !empty($_SESSION['user_id']);
}
// Check if admin is logged in
function isAdmin() {
return isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin';
}
// Get current user ID
function getCurrentUserId() {
return $_SESSION['user_id'] ?? 0;
}
// Get current user role
function getCurrentUserRole() {
return $_SESSION['user_role'] ?? 'guest';
}
// Sanitize input
function sanitize($input) {
global $conn;
return $conn->real_escape_string(trim(htmlspecialchars($input, ENT_QUOTES, 'UTF-8')));
}
// Generate CSRF token
function generateCSRFToken() {
if (!isset($_SESSION[CSRF_TOKEN_NAME])) {
$_SESSION[CSRF_TOKEN_NAME] = bin2hex(random_bytes(32));
}
return $_SESSION[CSRF_TOKEN_NAME];
}
// Verify CSRF token
function verifyCSRFToken($token) {
return isset($_SESSION[CSRF_TOKEN_NAME]) && hash_equals($_SESSION[CSRF_TOKEN_NAME], $token);
}
// Format currency
function formatCurrency($amount) {
return CURRENCY . number_format($amount, 2);
}
// Format date
function formatDate($date, $format = 'M d, Y H:i') {
return date($format, strtotime($date));
}
// Time ago function
function timeAgo($datetime) {
$time = strtotime($datetime);
$now = time();
$diff = $now - $time;
if ($diff < 60) {
return $diff . ' seconds ago';
} elseif ($diff < 3600) {
$mins = floor($diff / 60);
return $mins . ' minute' . ($mins > 1 ? 's' : '') . ' ago';
} elseif ($diff < 86400) {
$hours = floor($diff / 3600);
return $hours . ' hour' . ($hours > 1 ? 's' : '') . ' ago';
} elseif ($diff < 2592000) {
$days = floor($diff / 86400);
return $days . ' day' . ($days > 1 ? 's' : '') . ' ago';
} else {
return date('M d, Y', $time);
}
}
// Get time remaining for auction
function getTimeRemaining($end_time) {
$now = time();
$end = strtotime($end_time);
$diff = $end - $now;
if ($diff <= 0) {
return ['expired' => true, 'text' => 'Ended'];
}
$days = floor($diff / 86400);
$hours = floor(($diff % 86400) / 3600);
$minutes = floor(($diff % 3600) / 60);
$seconds = $diff % 60;
if ($days > 0) {
return ['expired' => false, 'text' => $days . 'd ' . $hours . 'h left'];
} elseif ($hours > 0) {
return ['expired' => false, 'text' => $hours . 'h ' . $minutes . 'm left'];
} elseif ($minutes > 0) {
return ['expired' => false, 'text' => $minutes . 'm ' . $seconds . 's left'];
} else {
return ['expired' => false, 'text' => $seconds . 's left'];
}
}
// Generate slug
function generateSlug($string) {
$string = strtolower($string);
$string = preg_replace('/[^a-z0-9-]/', '-', $string);
$string = preg_replace('/-+/', '-', $string);
return trim($string, '-');
}
// Upload image
function uploadImage($file, $target_dir, $max_size = 5242880) {
$errors = [];
$success = false;
$filename = '';
// Check if file is uploaded
if (!isset($file) || $file['error'] !== UPLOAD_ERR_OK) {
$errors[] = 'No file uploaded or upload error';
return ['success' => false, 'errors' => $errors];
}
// Check file size
if ($file['size'] > $max_size) {
$errors[] = 'File size must be less than ' . ($max_size / 1048576) . 'MB';
return ['success' => false, 'errors' => $errors];
}
// Check file type
$allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime_type, $allowed_types)) {
$errors[] = 'Only JPG, PNG, GIF and WEBP images are allowed';
return ['success' => false, 'errors' => $errors];
}
// Generate unique filename
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
$filename = uniqid() . '_' . time() . '.' . $extension;
$target_path = $target_dir . $filename;
// Create directory if not exists
if (!file_exists($target_dir)) {
mkdir($target_dir, 0755, true);
}
// Move uploaded file
if (move_uploaded_file($file['tmp_name'], $target_path)) {
$success = true;
// Create thumbnail for large images
if ($file['size'] > 1048576) { // If larger than 1MB
createThumbnail($target_path, $target_path, 1200, 1200);
}
} else {
$errors[] = 'Failed to upload file';
}
return [
'success' => $success,
'filename' => $filename,
'errors' => $errors
];
}
// Create thumbnail
function createThumbnail($source, $destination, $max_width, $max_height) {
list($width, $height, $type) = getimagesize($source);
$ratio = min($max_width / $width, $max_height / $height);
$new_width = $width * $ratio;
$new_height = $height * $ratio;
$thumb = imagecreatetruecolor($new_width, $new_height);
switch ($type) {
case IMAGETYPE_JPEG:
$source_img = imagecreatefromjpeg($source);
break;
case IMAGETYPE_PNG:
$source_img = imagecreatefrompng($source);
imagealphablending($thumb, false);
imagesavealpha($thumb, true);
break;
case IMAGETYPE_GIF:
$source_img = imagecreatefromgif($source);
break;
default:
return false;
}
imagecopyresampled($thumb, $source_img, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
switch ($type) {
case IMAGETYPE_JPEG:
imagejpeg($thumb, $destination, 85);
break;
case IMAGETYPE_PNG:
imagepng($thumb, $destination, 8);
break;
case IMAGETYPE_GIF:
imagegif($thumb, $destination);
break;
}
imagedestroy($source_img);
imagedestroy($thumb);
return true;
}
// Get user by ID
function getUserById($user_id) {
global $conn;
$sql = "SELECT * FROM users WHERE user_id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $user_id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
// Get category by ID
function getCategoryById($category_id) {
global $conn;
$sql = "SELECT * FROM categories WHERE category_id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $category_id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
// Get all categories
function getAllCategories($active_only = true) {
global $conn;
$sql = "SELECT * FROM categories";
if ($active_only) {
$sql .= " WHERE is_active = 1";
}
$sql .= " ORDER BY display_order, category_name";
$result = $conn->query($sql);
return $result->fetch_all(MYSQLI_ASSOC);
}
// Get auction by ID
function getAuctionById($auction_id) {
global $conn;
$sql = "SELECT a.*, u.username as seller_username, u.full_name as seller_name,
u.rating as seller_rating, u.total_reviews as seller_reviews,
c.category_name, c.category_slug
FROM auctions a
JOIN users u ON a.seller_id = u.user_id
JOIN categories c ON a.category_id = c.category_id
WHERE a.auction_id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $auction_id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
// Get auction images
function getAuctionImages($auction_id) {
global $conn;
$sql = "SELECT * FROM auction_images WHERE auction_id = ? ORDER BY is_primary DESC, display_order";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $auction_id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
}
// Get bids for auction
function getAuctionBids($auction_id, $limit = null) {
global $conn;
$sql = "SELECT b.*, u.username, u.full_name
FROM bids b
JOIN users u ON b.bidder_id = u.user_id
WHERE b.auction_id = ?
ORDER BY b.bid_amount DESC, b.bid_time DESC";
if ($limit) {
$sql .= " LIMIT ?";
}
$stmt = $conn->prepare($sql);
if ($limit) {
$stmt->bind_param("ii", $auction_id, $limit);
} else {
$stmt->bind_param("i", $auction_id);
}
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
}
// Get highest bid for auction
function getHighestBid($auction_id) {
global $conn;
$sql = "SELECT * FROM bids WHERE auction_id = ? ORDER BY bid_amount DESC LIMIT 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $auction_id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
// Check if user is watching auction
function isWatching($user_id, $auction_id) {
global $conn;
$sql = "SELECT * FROM watchlist WHERE user_id = ? AND auction_id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ii", $user_id, $auction_id);
$stmt->execute();
$result = $stmt->get_result();
return $result->num_rows > 0;
}
// Add to watchlist
function addToWatchlist($user_id, $auction_id) {
global $conn;
if (isWatching($user_id, $auction_id)) {
return false;
}
$sql = "INSERT INTO watchlist (user_id, auction_id) VALUES (?, ?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ii", $user_id, $auction_id);
if ($stmt->execute()) {
// Increment watcher count
$conn->query("UPDATE auctions SET watcher_count = watcher_count + 1 WHERE auction_id = $auction_id");
return true;
}
return false;
}
// Remove from watchlist
function removeFromWatchlist($user_id, $auction_id) {
global $conn;
$sql = "DELETE FROM watchlist WHERE user_id = ? AND auction_id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ii", $user_id, $auction_id);
if ($stmt->execute() && $stmt->affected_rows > 0) {
// Decrement watcher count
$conn->query("UPDATE auctions SET watcher_count = watcher_count - 1 WHERE auction_id = $auction_id");
return true;
}
return false;
}
// Create notification
function createNotification($user_id, $type, $title, $message, $link = null) {
global $conn;
$sql = "INSERT INTO notifications (user_id, type, title, message, link) VALUES (?, ?, ?, ?, ?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param("issss", $user_id, $type, $title, $message, $link);
return $stmt->execute();
}
// Get user notifications
function getUserNotifications($user_id, $unread_only = false, $limit = 10) {
global $conn;
$sql = "SELECT * FROM notifications WHERE user_id = ?";
if ($unread_only) {
$sql .= " AND is_read = 0";
}
$sql .= " ORDER BY created_at DESC LIMIT ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ii", $user_id, $limit);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
}
// Mark notification as read
function markNotificationRead($notification_id, $user_id) {
global $conn;
$sql = "UPDATE notifications SET is_read = 1 WHERE notification_id = ? AND user_id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ii", $notification_id, $user_id);
return $stmt->execute();
}
// Get site setting
function getSetting($key, $default = null) {
global $conn;
$sql = "SELECT setting_value FROM site_settings WHERE setting_key = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $key);
$stmt->execute();
$result = $stmt->get_result();
if ($row = $result->fetch_assoc()) {
return $row['setting_value'];
}
return $default;
}
// Log activity
function logActivity($user_id, $action, $details = null) {
global $conn;
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$sql = "INSERT INTO activity_logs (user_id, action, details, ip_address, user_agent)
VALUES (?, ?, ?, ?, ?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param("issss", $user_id, $action, $details, $ip, $user_agent);
return $stmt->execute();
}
// Pagination function
function paginate($current_page, $total_pages, $url_pattern) {
$html = '<ul class="pagination">';
// Previous button
if ($current_page > 1) {
$html .= '<li class="page-item"><a class="page-link" href="' . str_replace('{page}', $current_page - 1, $url_pattern) . '">Previous</a></li>';
} else {
$html .= '<li class="page-item disabled"><span class="page-link">Previous</span></li>';
}
// Page numbers
for ($i = 1; $i <= $total_pages; $i++) {
if ($i == $current_page) {
$html .= '<li class="page-item active"><span class="page-link">' . $i . '</span></li>';
} else {
$html .= '<li class="page-item"><a class="page-link" href="' . str_replace('{page}', $i, $url_pattern) . '">' . $i . '</a></li>';
}
}
// Next button
if ($current_page < $total_pages) {
$html .= '<li class="page-item"><a class="page-link" href="' . str_replace('{page}', $current_page + 1, $url_pattern) . '">Next</a></li>';
} else {
$html .= '<li class="page-item disabled"><span class="page-link">Next</span></li>';
}
$html .= '</ul>';
return $html;
}
?>
4. includes/auction_functions.php
<?php
require_once 'functions.php';
class AuctionManager {
private $conn;
private $user_id;
public function __construct($user_id = null) {
global $conn;
$this->conn = $conn;
$this->user_id = $user_id ?: getCurrentUserId();
}
// Create new auction
public function createAuction($data, $images = []) {
// Validate required fields
$required = ['title', 'description', 'category_id', 'starting_price', 'duration'];
foreach ($required as $field) {
if (empty($data[$field])) {
return ['success' => false, 'message' => ucfirst($field) . ' is required'];
}
}
// Validate duration
$min_days = getSetting('min_auction_duration', MIN_AUCTION_DAYS);
$max_days = getSetting('max_auction_duration', MAX_AUCTION_DAYS);
if ($data['duration'] < $min_days || $data['duration'] > $max_days) {
return ['success' => false, 'message' => "Duration must be between $min_days and $max_days days"];
}
// Validate starting price
if ($data['starting_price'] < 0.01) {
return ['success' => false, 'message' => 'Starting price must be at least 0.01'];
}
// Validate reserve price if set
if (!empty($data['reserve_price']) && $data['reserve_price'] < $data['starting_price']) {
return ['success' => false, 'message' => 'Reserve price must be greater than or equal to starting price'];
}
// Validate buy it now price if set
if (!empty($data['buy_it_now_price']) && $data['buy_it_now_price'] < $data['starting_price']) {
return ['success' => false, 'message' => 'Buy it now price must be greater than or equal to starting price'];
}
// Set timestamps
$start_time = date('Y-m-d H:i:s');
$end_time = date('Y-m-d H:i:s', strtotime("+{$data['duration']} days"));
// Generate slug
$slug = generateSlug($data['title']);
$slug = $this->makeSlugUnique($slug);
// Insert auction
$sql = "INSERT INTO auctions (
seller_id, category_id, title, slug, description, short_description,
condition, starting_price, reserve_price, current_price, buy_it_now_price,
min_bid_increment, quantity, start_time, end_time, shipping_details
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$stmt = $this->conn->prepare($sql);
$current_price = $data['starting_price'];
$short_desc = substr($data['description'], 0, 200) . '...';
$stmt->bind_param(
"iissssssdddiiiss",
$this->user_id,
$data['category_id'],
$data['title'],
$slug,
$data['description'],
$short_desc,
$data['condition'],
$data['starting_price'],
$data['reserve_price'] ?? null,
$current_price,
$data['buy_it_now_price'] ?? null,
$data['min_bid_increment'] ?? MIN_BID_INCREMENT,
$data['quantity'] ?? 1,
$start_time,
$end_time,
$data['shipping_details'] ?? null
);
if ($stmt->execute()) {
$auction_id = $this->conn->insert_id;
// Upload images
if (!empty($images)) {
$this->uploadAuctionImages($auction_id, $images);
}
// Log activity
logActivity($this->user_id, 'create_auction', "Created auction: {$data['title']}");
// Update user auction count
$this->conn->query("UPDATE users SET total_auctions = total_auctions + 1 WHERE user_id = $this->user_id");
return [
'success' => true,
'auction_id' => $auction_id,
'slug' => $slug,
'message' => 'Auction created successfully'
];
}
return ['success' => false, 'message' => 'Failed to create auction: ' . $this->conn->error];
}
// Upload auction images
private function uploadAuctionImages($auction_id, $images) {
$max_images = getSetting('max_images_per_auction', MAX_IMAGES_PER_AUCTION);
$count = 0;
$primary_set = false;
foreach ($images as $index => $image) {
if ($count >= $max_images) break;
$result = uploadImage($image, AUCTION_IMG_DIR);
if ($result['success']) {
$is_primary = (!$primary_set) ? 1 : 0;
if ($is_primary) $primary_set = true;
$sql = "INSERT INTO auction_images (auction_id, image_path, is_primary, display_order)
VALUES (?, ?, ?, ?)";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("isii", $auction_id, $result['filename'], $is_primary, $index);
$stmt->execute();
$count++;
}
}
}
// Make slug unique
private function makeSlugUnique($slug) {
$original = $slug;
$counter = 1;
while ($this->slugExists($slug)) {
$slug = $original . '-' . $counter;
$counter++;
}
return $slug;
}
// Check if slug exists
private function slugExists($slug) {
$sql = "SELECT auction_id FROM auctions WHERE slug = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("s", $slug);
$stmt->execute();
$result = $stmt->get_result();
return $result->num_rows > 0;
}
// Get user's auctions
public function getUserAuctions($status = null, $limit = null, $offset = 0) {
$sql = "SELECT a.*, c.category_name,
(SELECT COUNT(*) FROM bids WHERE auction_id = a.auction_id) as bid_count,
(SELECT MAX(bid_amount) FROM bids WHERE auction_id = a.auction_id) as highest_bid
FROM auctions a
JOIN categories c ON a.category_id = c.category_id
WHERE a.seller_id = ?";
if ($status) {
if (is_array($status)) {
$placeholders = implode(',', array_fill(0, count($status), '?'));
$sql .= " AND a.status IN ($placeholders)";
} else {
$sql .= " AND a.status = ?";
}
}
$sql .= " ORDER BY a.created_at DESC";
if ($limit) {
$sql .= " LIMIT ? OFFSET ?";
}
$stmt = $this->conn->prepare($sql);
// Build parameters array
$params = [$this->user_id];
$types = "i";
if ($status) {
if (is_array($status)) {
$params = array_merge($params, $status);
$types .= str_repeat('s', count($status));
} else {
$params[] = $status;
$types .= "s";
}
}
if ($limit) {
$params[] = $limit;
$params[] = $offset;
$types .= "ii";
}
$stmt->bind_param($types, ...$params);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
}
// Update auction
public function updateAuction($auction_id, $data) {
// Check ownership
if (!$this->isOwner($auction_id)) {
return ['success' => false, 'message' => 'You do not own this auction'];
}
// Check if auction can be edited (only pending or active with no bids)
$auction = getAuctionById($auction_id);
if ($auction['status'] != 'pending' && $auction['status'] != 'active') {
return ['success' => false, 'message' => 'Auction cannot be edited in its current state'];
}
if ($auction['bid_count'] > 0) {
return ['success' => false, 'message' => 'Cannot edit auction with existing bids'];
}
// Build update query
$updates = [];
$params = [];
$types = "";
$allowed = ['title', 'description', 'category_id', 'condition', 'starting_price',
'reserve_price', 'buy_it_now_price', 'min_bid_increment', 'quantity',
'shipping_details'];
foreach ($allowed as $field) {
if (isset($data[$field])) {
$updates[] = "$field = ?";
$params[] = $data[$field];
$types .= is_numeric($data[$field]) ? "i" : "s";
}
}
if (empty($updates)) {
return ['success' => false, 'message' => 'No fields to update'];
}
// Add auction_id to params
$params[] = $auction_id;
$types .= "i";
$sql = "UPDATE auctions SET " . implode(', ', $updates) . " WHERE auction_id = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param($types, ...$params);
if ($stmt->execute()) {
logActivity($this->user_id, 'update_auction', "Updated auction ID: $auction_id");
return ['success' => true, 'message' => 'Auction updated successfully'];
}
return ['success' => false, 'message' => 'Failed to update auction'];
}
// Cancel auction
public function cancelAuction($auction_id) {
// Check ownership
if (!$this->isOwner($auction_id)) {
return ['success' => false, 'message' => 'You do not own this auction'];
}
// Check if auction can be cancelled
$auction = getAuctionById($auction_id);
if ($auction['status'] != 'pending' && $auction['status'] != 'active') {
return ['success' => false, 'message' => 'Auction cannot be cancelled in its current state'];
}
if ($auction['bid_count'] > 0) {
// Notify bidders
$bids = getAuctionBids($auction_id);
foreach ($bids as $bid) {
createNotification(
$bid['bidder_id'],
'system',
'Auction Cancelled',
"The auction '{$auction['title']}' has been cancelled by the seller.",
SITE_URL . 'auction.php?slug=' . $auction['slug']
);
}
}
$sql = "UPDATE auctions SET status = 'cancelled' WHERE auction_id = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("i", $auction_id);
if ($stmt->execute()) {
logActivity($this->user_id, 'cancel_auction', "Cancelled auction ID: $auction_id");
return ['success' => true, 'message' => 'Auction cancelled successfully'];
}
return ['success' => false, 'message' => 'Failed to cancel auction'];
}
// Relist auction
public function relistAuction($auction_id, $duration = null) {
// Check ownership
if (!$this->isOwner($auction_id)) {
return ['success' => false, 'message' => 'You do not own this auction'];
}
$auction = getAuctionById($auction_id);
if ($auction['status'] != 'ended' && $auction['status'] != 'sold') {
return ['success' => false, 'message' => 'Only ended or sold auctions can be relisted'];
}
if (!$duration) {
$duration = getSetting('min_auction_duration', MIN_AUCTION_DAYS);
}
$start_time = date('Y-m-d H:i:s');
$end_time = date('Y-m-d H:i:s', strtotime("+$duration days"));
$sql = "UPDATE auctions SET
status = 'pending',
start_time = ?,
end_time = ?,
current_price = starting_price,
winner_id = NULL,
sold_price = NULL,
payment_status = 'pending'
WHERE auction_id = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("ssi", $start_time, $end_time, $auction_id);
if ($stmt->execute()) {
logActivity($this->user_id, 'relist_auction', "Relisted auction ID: $auction_id");
return ['success' => true, 'message' => 'Auction relisted successfully'];
}
return ['success' => false, 'message' => 'Failed to relist auction'];
}
// Check if user owns auction
private function isOwner($auction_id) {
$sql = "SELECT seller_id FROM auctions WHERE auction_id = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("i", $auction_id);
$stmt->execute();
$result = $stmt->get_result();
$auction = $result->fetch_assoc();
return $auction && $auction['seller_id'] == $this->user_id;
}
// Get active auctions with filters
public static function getActiveAuctions($filters = [], $page = 1, $per_page = AUCTIONS_PER_PAGE) {
global $conn;
$where = ["status = 'active'"];
$params = [];
$types = "";
// Category filter
if (!empty($filters['category'])) {
$where[] = "a.category_id = ?";
$params[] = $filters['category'];
$types .= "i";
}
// Price range
if (!empty($filters['min_price'])) {
$where[] = "a.current_price >= ?";
$params[] = $filters['min_price'];
$types .= "d";
}
if (!empty($filters['max_price'])) {
$where[] = "a.current_price <= ?";
$params[] = $filters['max_price'];
$types .= "d";
}
// Condition
if (!empty($filters['condition'])) {
if (is_array($filters['condition'])) {
$placeholders = implode(',', array_fill(0, count($filters['condition']), '?'));
$where[] = "a.condition IN ($placeholders)";
$params = array_merge($params, $filters['condition']);
$types .= str_repeat('s', count($filters['condition']));
} else {
$where[] = "a.condition = ?";
$params[] = $filters['condition'];
$types .= "s";
}
}
// Search query
if (!empty($filters['search'])) {
$where[] = "(a.title LIKE ? OR a.description LIKE ?)";
$search_term = "%{$filters['search']}%";
$params[] = $search_term;
$params[] = $search_term;
$types .= "ss";
}
// Featured only
if (!empty($filters['featured'])) {
$where[] = "a.featured = 1";
}
// Ending soon (within 24 hours)
if (!empty($filters['ending_soon'])) {
$where[] = "a.end_time BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 24 HOUR)";
}
// New listings (last 24 hours)
if (!empty($filters['new'])) {
$where[] = "a.created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)";
}
$where_clause = implode(' AND ', $where);
// Count total records
$count_sql = "SELECT COUNT(*) as total FROM auctions a WHERE $where_clause";
$count_stmt = $conn->prepare($count_sql);
if (!empty($params)) {
$count_stmt->bind_param($types, ...$params);
}
$count_stmt->execute();
$count_result = $count_stmt->get_result();
$total_records = $count_result->fetch_assoc()['total'];
$total_pages = ceil($total_records / $per_page);
// Get records for current page
$offset = ($page - 1) * $per_page;
$sql = "SELECT a.*, u.username, u.full_name, u.rating,
c.category_name, c.category_slug,
(SELECT image_path FROM auction_images WHERE auction_id = a.auction_id AND is_primary = 1 LIMIT 1) as primary_image,
(SELECT COUNT(*) FROM bids WHERE auction_id = a.auction_id) as bid_count,
(SELECT MAX(bid_amount) FROM bids WHERE auction_id = a.auction_id) as highest_bid
FROM auctions a
JOIN users u ON a.seller_id = u.user_id
JOIN categories c ON a.category_id = c.category_id
WHERE $where_clause
ORDER BY a.featured DESC, a.end_time ASC
LIMIT ? OFFSET ?";
$stmt = $conn->prepare($sql);
// Add pagination parameters
$all_params = array_merge($params, [$per_page, $offset]);
$all_types = $types . "ii";
if (!empty($all_params)) {
$stmt->bind_param($all_types, ...$all_params);
}
$stmt->execute();
$result = $stmt->get_result();
return [
'auctions' => $result->fetch_all(MYSQLI_ASSOC),
'total' => $total_records,
'pages' => $total_pages,
'current_page' => $page
];
}
}
?>
5. includes/bidding_functions.php
<?php
require_once 'functions.php';
class BiddingManager {
private $conn;
private $user_id;
public function __construct($user_id = null) {
global $conn;
$this->conn = $conn;
$this->user_id = $user_id ?: getCurrentUserId();
}
// Place a bid
public function placeBid($auction_id, $bid_amount) {
// Check if user is logged in
if (!$this->user_id) {
return ['success' => false, 'message' => 'Please login to place a bid'];
}
// Get auction details
$auction = getAuctionById($auction_id);
if (!$auction) {
return ['success' => false, 'message' => 'Auction not found'];
}
// Check if auction is active
if ($auction['status'] != 'active') {
return ['success' => false, 'message' => 'This auction is not active'];
}
// Check if auction has ended
if (strtotime($auction['end_time']) < time()) {
return ['success' => false, 'message' => 'This auction has ended'];
}
// Check if user is the seller
if ($auction['seller_id'] == $this->user_id) {
return ['success' => false, 'message' => 'You cannot bid on your own auction'];
}
// Get current highest bid
$highest_bid = getHighestBid($auction_id);
$current_price = $highest_bid ? $highest_bid['bid_amount'] : $auction['starting_price'];
// Validate bid amount
if ($bid_amount <= $current_price) {
return ['success' => false, 'message' => 'Bid must be higher than current price'];
}
// Check minimum bid increment
$min_increment = $auction['min_bid_increment'];
if ($bid_amount < $current_price + $min_increment) {
return ['success' => false, 'message' => 'Bid must be at least ' . formatCurrency($current_price + $min_increment)];
}
// Check if user has enough balance (if using wallet system)
// $user = getUserById($this->user_id);
// if ($user['balance'] < $bid_amount) {
// return ['success' => false, 'message' => 'Insufficient balance'];
// }
// Begin transaction
$this->conn->begin_transaction();
try {
// Insert bid
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$sql = "INSERT INTO bids (auction_id, bidder_id, bid_amount, ip_address) VALUES (?, ?, ?, ?)";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("iids", $auction_id, $this->user_id, $bid_amount, $ip);
$stmt->execute();
$bid_id = $this->conn->insert_id;
// Update auction current price and bid count
$sql = "UPDATE auctions SET current_price = ?, bid_count = bid_count + 1 WHERE auction_id = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("di", $bid_amount, $auction_id);
$stmt->execute();
// Mark previous winning bid as not winning
if ($highest_bid) {
$sql = "UPDATE bids SET is_winning = 0 WHERE bid_id = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("i", $highest_bid['bid_id']);
$stmt->execute();
// Notify previous bidder that they've been outbid
if ($highest_bid['bidder_id'] != $this->user_id) {
$this->sendOutbidNotification($highest_bid['bidder_id'], $auction);
}
}
// Mark new bid as winning
$sql = "UPDATE bids SET is_winning = 1 WHERE bid_id = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("i", $bid_id);
$stmt->execute();
// Add to watchlist automatically
addToWatchlist($this->user_id, $auction_id);
// Log activity
logActivity($this->user_id, 'place_bid', "Placed bid of $bid_amount on auction ID: $auction_id");
// Commit transaction
$this->conn->commit();
// Notify seller
$this->notifySeller($auction['seller_id'], $auction, $bid_amount);
return [
'success' => true,
'bid_id' => $bid_id,
'message' => 'Bid placed successfully',
'new_price' => $bid_amount,
'bid_count' => $auction['bid_count'] + 1
];
} catch (Exception $e) {
$this->conn->rollback();
return ['success' => false, 'message' => 'Failed to place bid: ' . $e->getMessage()];
}
}
// Buy it now
public function buyItNow($auction_id) {
// Check if user is logged in
if (!$this->user_id) {
return ['success' => false, 'message' => 'Please login to purchase'];
}
// Get auction details
$auction = getAuctionById($auction_id);
if (!$auction) {
return ['success' => false, 'message' => 'Auction not found'];
}
// Check if buy it now is available
if (empty($auction['buy_it_now_price'])) {
return ['success' => false, 'message' => 'Buy it now not available for this auction'];
}
// Check if auction is active
if ($auction['status'] != 'active') {
return ['success' => false, 'message' => 'This auction is not active'];
}
// Check if user is the seller
if ($auction['seller_id'] == $this->user_id) {
return ['success' => false, 'message' => 'You cannot buy your own item'];
}
// Begin transaction
$this->conn->begin_transaction();
try {
// Update auction status
$sql = "UPDATE auctions SET
status = 'sold',
winner_id = ?,
sold_price = buy_it_now_price,
payment_status = 'pending',
end_time = NOW()
WHERE auction_id = ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("ii", $this->user_id, $auction_id);
$stmt->execute();
// Log activity
logActivity($this->user_id, 'buy_it_now', "Purchased auction ID: $auction_id for " . $auction['buy_it_now_price']);
// Commit transaction
$this->conn->commit();
// Create transaction record
$this->createTransaction($auction_id, $this->user_id, $auction['seller_id'], $auction['buy_it_now_price']);
// Notify seller
$this->notifySellerPurchase($auction['seller_id'], $auction, $this->user_id);
// Notify other bidders that auction ended
$this->notifyBiddersAuctionEnded($auction_id, $auction);
return [
'success' => true,
'message' => 'Item purchased successfully',
'redirect' => SITE_URL . 'user/payment.php?auction_id=' . $auction_id
];
} catch (Exception $e) {
$this->conn->rollback();
return ['success' => false, 'message' => 'Failed to complete purchase: ' . $e->getMessage()];
}
}
// Create transaction record
private function createTransaction($auction_id, $buyer_id, $seller_id, $amount) {
$commission_rate = getSetting('commission_rate', COMMISSION_RATE);
$commission = $amount * ($commission_rate / 100);
$seller_amount = $amount - $commission;
$sql = "INSERT INTO transactions (auction_id, buyer_id, seller_id, amount, commission, seller_amount)
VALUES (?, ?, ?, ?, ?, ?)";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("iiiddd", $auction_id, $buyer_id, $seller_id, $amount, $commission, $seller_amount);
return $stmt->execute();
}
// Send outbid notification
private function sendOutbidNotification($user_id, $auction) {
$title = "You've been outbid!";
$message = "Someone placed a higher bid on '{$auction['title']}'. Place another bid to win!";
$link = SITE_URL . 'auction.php?slug=' . $auction['slug'];
createNotification($user_id, 'outbid', $title, $message, $link);
// Send email
$this->sendEmailNotification($user_id, $title, $message, $link);
}
// Notify seller of new bid
private function notifySeller($seller_id, $auction, $bid_amount) {
$title = "New bid on your auction";
$message = "Someone placed a bid of " . formatCurrency($bid_amount) . " on '{$auction['title']}'";
$link = SITE_URL . 'user/auction-details.php?id=' . $auction['auction_id'];
createNotification($seller_id, 'bid', $title, $message, $link);
}
// Notify seller of purchase
private function notifySellerPurchase($seller_id, $auction, $buyer_id) {
$buyer = getUserById($buyer_id);
$title = "Item sold!";
$message = "Your item '{$auction['title']}' was purchased by {$buyer['username']}";
$link = SITE_URL . 'user/my-auctions.php';
createNotification($seller_id, 'sold', $title, $message, $link);
}
// Notify bidders auction ended
private function notifyBiddersAuctionEnded($auction_id, $auction) {
$sql = "SELECT DISTINCT bidder_id FROM bids WHERE auction_id = ? AND bidder_id != ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("ii", $auction_id, $auction['winner_id']);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$title = "Auction ended";
$message = "The auction for '{$auction['title']}' has ended. You did not win this item.";
$link = SITE_URL . 'auction.php?slug=' . $auction['slug'];
createNotification($row['bidder_id'], 'ended', $title, $message, $link);
}
}
// Get user's bidding history
public function getBiddingHistory($status = null, $limit = null, $offset = 0) {
$sql = "SELECT b.*, a.title, a.slug, a.status as auction_status, a.end_time,
a.seller_id, a.buy_it_now_price,
u.username as seller_username,
(SELECT image_path FROM auction_images WHERE auction_id = a.auction_id AND is_primary = 1 LIMIT 1) as primary_image
FROM bids b
JOIN auctions a ON b.auction_id = a.auction_id
JOIN users u ON a.seller_id = u.user_id
WHERE b.bidder_id = ?";
if ($status) {
$sql .= " AND a.status = ?";
}
$sql .= " ORDER BY b.bid_time DESC";
if ($limit) {
$sql .= " LIMIT ? OFFSET ?";
}
$stmt = $this->conn->prepare($sql);
if ($status && $limit) {
$stmt->bind_param("isii", $this->user_id, $status, $limit, $offset);
} elseif ($status) {
$stmt->bind_param("is", $this->user_id, $status);
} elseif ($limit) {
$stmt->bind_param("iii", $this->user_id, $limit, $offset);
} else {
$stmt->bind_param("i", $this->user_id);
}
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
}
// Get won auctions
public function getWonAuctions() {
$sql = "SELECT a.*, u.username as seller_username, u.full_name as seller_name,
t.transaction_id, t.payment_status, t.amount
FROM auctions a
JOIN users u ON a.seller_id = u.user_id
LEFT JOIN transactions t ON a.auction_id = t.auction_id
WHERE a.winner_id = ? AND a.status IN ('sold', 'ended')
ORDER BY a.end_time DESC";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("i", $this->user_id);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
}
// Simple email notification (placeholder - implement with PHPMailer)
private function sendEmailNotification($user_id, $subject, $message, $link) {
// In production, use PHPMailer or similar
// $user = getUserById($user_id);
// mail($user['email'], $subject, $message);
}
}
?>
6. index.php (Homepage)
<?php
require_once 'includes/config.php';
require_once 'includes/functions.php';
require_once 'includes/auction_functions.php';
// Get featured auctions
$featured = AuctionManager::getActiveAuctions(['featured' => true], 1, 6);
// Get ending soon auctions
$ending_soon = AuctionManager::getActiveAuctions(['ending_soon' => true], 1, 6);
// Get categories
$categories = getAllCategories();
// Get recent auctions
$recent = AuctionManager::getActiveAuctions(['new' => true], 1, 8);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo SITE_NAME; ?> - Online Auction Platform</title>
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<!-- Navigation -->
<nav class="navbar">
<div class="container">
<div class="nav-brand">
<a href="index.php">
<i class="fas fa-gavel"></i>
<?php echo SITE_NAME; ?>
</a>
</div>
<div class="nav-search">
<form action="search.php" method="GET">
<input type="text" name="q" placeholder="Search for anything...">
<button type="submit"><i class="fas fa-search"></i></button>
</form>
</div>
<ul class="nav-menu">
<li><a href="auctions.php">Browse</a></li>
<li><a href="categories.php">Categories</a></li>
<li><a href="how-it-works.php">How It Works</a></li>
<?php if (isLoggedIn()): ?>
<li class="dropdown">
<a href="#" class="dropdown-toggle">
<i class="fas fa-user-circle"></i>
<?php echo $_SESSION['username']; ?>
</a>
<ul class="dropdown-menu">
<li><a href="user/dashboard.php"><i class="fas fa-tachometer-alt"></i> Dashboard</a></li>
<li><a href="user/my-auctions.php"><i class="fas fa-list"></i> My Auctions</a></li>
<li><a href="user/my-bids.php"><i class="fas fa-gavel"></i> My Bids</a></li>
<li><a href="user/watchlist.php"><i class="fas fa-heart"></i> Watchlist</a></li>
<li><a href="user/messages.php"><i class="fas fa-envelope"></i> Messages</a></li>
<li><a href="user/profile.php"><i class="fas fa-user-cog"></i> Profile</a></li>
<li><a href="user/logout.php"><i class="fas fa-sign-out-alt"></i> Logout</a></li>
</ul>
</li>
<?php else: ?>
<li><a href="user/login.php">Login</a></li>
<li><a href="user/register.php" class="btn-register">Sign Up</a></li>
<?php endif; ?>
</ul>
</div>
</nav>
<!-- Hero Section -->
<section class="hero">
<div class="container">
<div class="hero-content">
<h1>Discover Amazing Items at Unbeatable Prices</h1>
<p>Join millions of buyers and sellers on the world's most exciting auction platform</p>
<div class="hero-buttons">
<a href="auctions.php" class="btn btn-primary">Start Bidding</a>
<a href="user/create-auction.php" class="btn btn-secondary">Sell an Item</a>
</div>
<div class="hero-stats">
<div class="stat">
<span class="stat-number">500K+</span>
<span class="stat-label">Active Users</span>
</div>
<div class="stat">
<span class="stat-number">1M+</span>
<span class="stat-label">Items Sold</span>
</div>
<div class="stat">
<span class="stat-number">50K+</span>
<span class="stat-label">Live Auctions</span>
</div>
</div>
</div>
<div class="hero-image">
<img src="assets/images/hero-auction.svg" alt="Auction Illustration">
</div>
</div>
</section>
<!-- Categories Section -->
<section class="categories-section">
<div class="container">
<h2 class="section-title">Browse by Category</h2>
<div class="categories-grid">
<?php foreach ($categories as $category): ?>
<a href="auctions.php?category=<?php echo $category['category_id']; ?>" class="category-card">
<i class="fas <?php echo $category['icon']; ?>"></i>
<h3><?php echo $category['category_name']; ?></h3>
<span class="category-count"><?php echo $category['auction_count']; ?> items</span>
</a>
<?php endforeach; ?>
</div>
</div>
</section>
<!-- Featured Auctions -->
<?php if (!empty($featured['auctions'])): ?>
<section class="featured-auctions">
<div class="container">
<h2 class="section-title">Featured Auctions</h2>
<div class="auctions-grid">
<?php foreach ($featured['auctions'] as $auction): ?>
<div class="auction-card">
<div class="auction-image">
<img src="uploads/auction_images/<?php echo $auction['primary_image'] ?? 'default.jpg'; ?>"
alt="<?php echo htmlspecialchars($auction['title']); ?>">
<?php if ($auction['featured']): ?>
<span class="featured-badge">Featured</span>
<?php endif; ?>
</div>
<div class="auction-details">
<h3><a href="auction.php?slug=<?php echo $auction['slug']; ?>"><?php echo htmlspecialchars($auction['title']); ?></a></h3>
<div class="auction-seller">
<i class="fas fa-user"></i> <?php echo htmlspecialchars($auction['username']); ?>
</div>
<div class="auction-price">
<span class="current-price"><?php echo formatCurrency($auction['current_price']); ?></span>
<span class="bid-count"><?php echo $auction['bid_count']; ?> bids</span>
</div>
<div class="auction-timer" data-end="<?php echo $auction['end_time']; ?>">
<i class="fas fa-clock"></i>
<span class="time-remaining"><?php echo getTimeRemaining($auction['end_time'])['text']; ?></span>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</section>
<?php endif; ?>
<!-- Ending Soon -->
<?php if (!empty($ending_soon['auctions'])): ?>
<section class="ending-soon">
<div class="container">
<h2 class="section-title">Ending Soon</h2>
<div class="auctions-grid">
<?php foreach ($ending_soon['auctions'] as $auction): ?>
<div class="auction-card ending-soon">
<div class="auction-image">
<img src="uploads/auction_images/<?php echo $auction['primary_image'] ?? 'default.jpg'; ?>"
alt="<?php echo htmlspecialchars($auction['title']); ?>">
<span class="urgent-badge">Ending Soon</span>
</div>
<div class="auction-details">
<h3><a href="auction.php?slug=<?php echo $auction['slug']; ?>"><?php echo htmlspecialchars($auction['title']); ?></a></h3>
<div class="auction-price">
<span class="current-price"><?php echo formatCurrency($auction['current_price']); ?></span>
</div>
<div class="auction-timer urgent" data-end="<?php echo $auction['end_time']; ?>">
<i class="fas fa-hourglass-half"></i>
<span class="time-remaining"><?php echo getTimeRemaining($auction['end_time'])['text']; ?></span>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</section>
<?php endif; ?>
<!-- How It Works -->
<section class="how-it-works">
<div class="container">
<h2 class="section-title">How It Works</h2>
<div class="steps">
<div class="step">
<div class="step-number">1</div>
<i class="fas fa-user-plus"></i>
<h3>Create Account</h3>
<p>Sign up for free and start exploring thousands of auctions</p>
</div>
<div class="step">
<div class="step-number">2</div>
<i class="fas fa-search"></i>
<h3>Find Items</h3>
<p>Browse categories or search for specific items you want</p>
</div>
<div class="step">
<div class="step-number">3</div>
<i class="fas fa-gavel"></i>
<h3>Place Bids</h3>
<p>Bid on items and win them at the best prices</p>
</div>
<div class="step">
<div class="step-number">4</div>
<i class="fas fa-truck"></i>
<h3>Receive Items</h3>
<p>Pay securely and get your items delivered</p>
</div>
</div>
</div>
</section>
<!-- CTA Section -->
<section class="cta">
<div class="container">
<h2>Ready to start bidding?</h2>
<p>Join our community of buyers and sellers today</p>
<div class="cta-buttons">
<a href="user/register.php" class="btn btn-primary btn-large">Create Free Account</a>
<a href="auctions.php" class="btn btn-outline-light btn-large">Browse Auctions</a>
</div>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-section">
<h4><?php echo SITE_NAME; ?></h4>
<p>The premier online auction platform for buyers and sellers.</p>
</div>
<div class="footer-section">
<h4>Quick Links</h4>
<ul>
<li><a href="about.php">About Us</a></li>
<li><a href="how-it-works.php">How It Works</a></li>
<li><a href="faq.php">FAQ</a></li>
<li><a href="contact.php">Contact</a></li>
</ul>
</div>
<div class="footer-section">
<h4>Legal</h4>
<ul>
<li><a href="terms.php">Terms of Service</a></li>
<li><a href="privacy.php">Privacy Policy</a></li>
<li><a href="returns.php">Returns Policy</a></li>
</ul>
</div>
<div class="footer-section">
<h4>Follow Us</h4>
<div class="social-links">
<a href="#"><i class="fab fa-facebook"></i></a>
<a href="#"><i class="fab fa-twitter"></i></a>
<a href="#"><i class="fab fa-instagram"></i></a>
<a href="#"><i class="fab fa-linkedin"></i></a>
</div>
</div>
</div>
<div class="footer-bottom">
<p>© <?php echo date('Y'); ?> <?php echo SITE_NAME; ?>. All rights reserved.</p>
</div>
</div>
</footer>
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/main.js"></script>
<script src="assets/js/countdown.js"></script>
<script>
// Initialize countdown timers
document.querySelectorAll('.auction-timer').forEach(timer => {
const endTime = timer.dataset.end;
updateCountdown(timer, endTime);
});
</script>
</body>
</html>
How to Use This Project - Step by Step Guide
Step 1: System Requirements
- XAMPP/WAMP/MAMP (PHP 7.4+)
- MySQL 5.7+ or MariaDB
- Web server (Apache/Nginx)
- Web browser (Chrome, Firefox, Edge)
- 2GB RAM minimum
- 500MB free disk space
Step 2: Installation Process
2.1 Download and Setup
- Install XAMPP/WAMP
- Download from official websites
- Install with default settings
- Start Apache and MySQL services
- Create Project Folder
# Navigate to htdocs (XAMPP) or www (WAMP) cd C:\xampp\htdocs\ # Create project folder mkdir online-auction-system # Extract all files into this folder
2.2 Database Configuration
- Open phpMyAdmin
- Navigate to http://localhost/phpmyadmin
- Login with default credentials (root, no password)
- Create Database
- Click "New" on left sidebar
- Enter database name:
auction_system - Choose utf8mb4_general_ci collation
- Click "Create"
- Import Database
- Select the newly created database
- Click "Import" tab
- Choose file:
database/auction_system.sql - Click "Go" to import
- Verify Import
- Check if all tables are created (users, auctions, bids, etc.)
- Default admin user should be created
2.3 Configure Project
- Update Configuration
- Open
includes/config.php - Update database credentials if needed:
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', ''); // Add password if set
define('DB_NAME', 'auction_system');
- Set Folder Permissions
# Create upload directories mkdir uploads mkdir uploads/auction_images mkdir uploads/temp # Set permissions (Linux/Mac) chmod -R 755 uploads/ chmod -R 755 assets/images/ # Windows: Right-click folders -> Properties -> Security -> Give write permissions
- Configure Email Settings (Optional)
- Update SMTP settings in
includes/config.php - Set your email credentials for notifications
Step 3: Access the System
3.1 Frontend Access
- Open browser and go to:
http://localhost/online-auction-system/ - You should see the homepage with:
- Navigation menu
- Hero section
- Categories grid
- Featured auctions
- Ending soon auctions
3.2 Admin Access
- Admin login:
http://localhost/online-auction-system/admin/login.php - Default credentials:
- Username:
admin - Password:
Admin@123
Step 4: Test User Features
4.1 User Registration
- Click "Sign Up" in navigation
- Fill registration form:
- Username
- Password
- Full name (optional)
- Submit form
- Check email for verification link (if enabled)
4.2 User Login
- Click "Login" in navigation
- Enter credentials
- Verify redirect to dashboard
4.3 Browse Auctions
- Click "Browse" in navigation
- View all active auctions
- Use filters:
- Category
- Price range
- Condition
- Sort by:
- Ending soonest
- Newest
- Price: Low to High
- Price: High to Low
4.4 View Auction Details
- Click on any auction
- View:
- Images gallery
- Description
- Current price
- Time remaining
- Bid history
- Seller information
- Add to watchlist
- Share auction
4.5 Place a Bid
- Login to your account
- Navigate to an active auction
- Enter bid amount in the bid form
- Click "Place Bid"
- Verify bid appears in bid history
- Check outbid notification (if applicable)
4.6 Create an Auction
- Login and go to Dashboard
- Click "Create New Auction"
- Fill auction details:
- Title (required)
- Category (required)
- Description (required)
- Condition
- Starting price (required)
- Reserve price (optional)
- Buy it now price (optional)
- Duration in days
- Upload images (up to 10)
- Submit for approval
- Check status in "My Auctions"
4.7 Manage Watchlist
- Browse auctions
- Click heart icon to add to watchlist
- Go to Dashboard > Watchlist
- View all watched auctions
- Remove from watchlist
4.8 Track Bids
- Go to Dashboard > My Bids
- View:
- Active bids
- Winning bids
- Lost bids
- Click on auction to bid again
4.9 Buy It Now
- Find auction with Buy It Now option
- Click "Buy It Now" button
- Confirm purchase
- Proceed to payment
4.10 Leave Reviews
- After winning an auction
- Go to Dashboard > Won Auctions
- Click "Leave Review"
- Rate seller (1-5 stars)
- Write review comment
Step 5: Test Admin Features
5.1 Admin Dashboard
- Login as admin
- View dashboard statistics:
- Total users
- Total auctions
- Active auctions
- Total revenue
- Recent activity
5.2 User Management
- Go to Admin > Users
- View all registered users
- Search/filter users
- Edit user details
- Suspend/activate users
- Delete users (if needed)
5.3 Auction Management
- Go to Admin > Auctions
- View pending auctions for approval
- Approve or reject auctions
- Feature/unfeature auctions
- View all auctions with filters
- Edit/remove inappropriate auctions
5.4 Category Management
- Go to Admin > Categories
- Add new categories
- Edit existing categories
- Delete categories
- Set category icons and order
5.5 Transaction Monitoring
- Go to Admin > Transactions
- View all completed sales
- Track payment status
- Calculate commissions
- Generate reports
5.6 Site Settings
- Go to Admin > Settings
- Configure:
- Site name and URL
- Commission rate
- Auction duration limits
- Image upload limits
- Email settings
- Payment gateway settings
Step 6: Advanced Features
6.1 Email Notifications
The system sends email notifications for:
- Registration verification
- Password reset
- Outbid alerts
- Auction won
- Auction ended
- New bids on your items
- Payment received
6.2 Real-time Updates
- Bid updates via AJAX
- Countdown timers
- Auto-refresh of bid history
- Live outbid notifications
6.3 Payment Integration
The system supports:
- PayPal integration (sandbox/live)
- Stripe payment gateway
- Manual payment processing
- Transaction tracking
6.4 Search Functionality
- Full-text search on auction titles and descriptions
- Filter by category, price, condition
- Sort by multiple criteria
- Pagination support
Step 7: Customization Options
7.1 Theme Customization
- Modify CSS variables in
assets/css/style.css - Change color scheme
- Update logo and branding
- Customize layout
7.2 Feature Configuration
Edit includes/config.php to:
- Enable/disable features
- Change auction duration limits
- Set commission rates
- Configure payment gateways
- Modify email templates
7.3 Language/Internationalization
- Add language files
- Modify currency settings
- Set timezone
- Add multi-language support
Step 8: Security Considerations
8.1 Implemented Security Features
- Password hashing (MD5 - upgrade to password_hash for production)
- CSRF protection
- SQL injection prevention (prepared statements)
- XSS protection (htmlspecialchars)
- Session management
- Input validation
- File upload restrictions
8.2 Production Security Checklist
- [ ] Change default admin password
- [ ] Enable HTTPS/SSL
- [ ] Update password hashing to bcrypt
- [ ] Set proper file permissions
- [ ] Enable firewall
- [ ] Regular backups
- [ ] Monitor error logs
- [ ] Rate limiting on API
- [ ] CAPTCHA on forms
Step 9: Troubleshooting Common Issues
9.1 Database Connection Error
- Check MySQL service is running
- Verify credentials in config.php
- Check database exists
9.2 File Upload Issues
- Check folder permissions
- Verify PHP upload limits in php.ini
- Check file size and type restrictions
9.3 Email Not Working
- Verify SMTP settings
- Check spam folder
- Test with mail() function first
9.4 Session Issues
- Clear browser cache
- Check session save path
- Verify cookie settings
9.5 Payment Gateway Issues
- Use sandbox mode for testing
- Check API credentials
- Verify webhook URLs
Step 10: Deployment to Production
10.1 Server Requirements
- PHP 7.4 or higher
- MySQL 5.7 or higher
- Apache/Nginx with mod_rewrite
- SSL certificate
- 2GB RAM minimum
- 20GB storage
10.2 Deployment Steps
- Prepare Files
- Remove debug code
- Minify CSS/JS
- Optimize images
- Update configuration
- Upload Files
- Use FTP or Git deployment
- Set correct permissions
- Create upload directories
- Database Migration
- Export local database
- Import to production server
- Update database credentials
- Configure Server
- Enable mod_rewrite
- Set PHP memory limit
- Configure email server
- Set up cron jobs for:
- Auction status updates
- Email notifications
- Backup tasks
- Testing
- Test all features
- Check responsive design
- Verify payment gateways
- Test email notifications
- Go Live
- Update DNS records
- Enable HTTPS
- Monitor error logs
- Set up analytics
System Features Summary
For Users:
- ✅ User registration and login
- ✅ Email verification
- ✅ Password recovery
- ✅ Browse auctions by category
- ✅ Advanced search with filters
- ✅ View auction details with images
- ✅ Place bids with automatic outbid notification
- ✅ Buy it now option
- ✅ Watchlist/favorite auctions
- ✅ Create and manage auctions
- ✅ Track bidding history
- ✅ View won auctions
- ✅ Leave seller reviews
- ✅ Message system
- ✅ Dashboard with statistics
- ✅ Profile management
For Sellers:
- ✅ Create auction listings
- ✅ Upload multiple images
- ✅ Set reserve price
- ✅ Set buy it now price
- ✅ Manage active auctions
- ✅ View bid history
- ✅ Relist unsold items
- ✅ Track sales
- ✅ Communicate with buyers
- ✅ Receive payment notifications
For Admins:
- ✅ Complete dashboard
- ✅ User management
- ✅ Auction moderation
- ✅ Category management
- ✅ Transaction monitoring
- ✅ Site settings
- ✅ Report generation
- ✅ Featured auction management
- ✅ System logs
- ✅ Email template management
Technical Features:
- ✅ Responsive design
- ✅ Mobile-friendly
- ✅ SEO optimized URLs
- ✅ AJAX real-time updates
- ✅ Secure payment integration
- ✅ Email notifications
- ✅ Search functionality
- ✅ Pagination
- ✅ File upload with validation
- ✅ Session management
- ✅ CSRF protection
- ✅ SQL injection prevention
This comprehensive Online Auction System provides a complete marketplace solution with all the features needed for a successful auction platform. The modular architecture allows for easy customization and scaling. Both user and admin interfaces are intuitive and feature-rich, making it suitable for small to medium-sized auction websites.