کانال نوحه و مداحی ناب

API های کامل برای مدیریت سامانه درج آگهی به زبان PHP

در اینجا API های کامل برای مدیریت سامانه درج آگهی به زبان PHP ارائه می‌دهم:

1. فایل پیکربندی (config.php)

php
<?php
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    exit(0);
}

// تنظیمات دیتابیس
define('DB_HOST', 'localhost');
define('DB_USER', 'username');
define('DB_PASS', 'password');
define('DB_NAME', 'advertising_system');
define('DB_CHARSET', 'utf8mb4');

// تنظیمات آپلود
define('UPLOAD_DIR', 'uploads/');
define('MAX_FILE_SIZE', 5 * 1024 * 1024); // 5MB
define('ALLOWED_TYPES', ['jpg', 'jpeg', 'png', 'gif']);

// تابع اتصال به دیتابیس
function getDBConnection() {
    $conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
    if ($conn->connect_error) {
        http_response_code(500);
        echo json_encode(['success' => false, 'message' => 'Database connection failed']);
        exit;
    }
    $conn->set_charset(DB_CHARSET);
    return $conn;
}

// تابع پاسخ استاندارد
function sendResponse($success, $data = null, $message = '', $statusCode = 200) {
    http_response_code($statusCode);
    echo json_encode([
        'success' => $success,
        'message' => $message,
        'data' => $data,
        'timestamp' => date('Y-m-d H:i:s')
    ], JSON_UNESCAPED_UNICODE);
    exit;
}

// تابع اعتبارسنجی JWT
function validateToken() {
    $headers = getallheaders();
    $token = isset($headers['Authorization']) ? str_replace('Bearer ', '', $headers['Authorization']) : '';
    
    if (empty($token)) {
        sendResponse(false, null, 'Access token required', 401);
    }
    
    $userId = verifyJWT($token);
    if (!$userId) {
        sendResponse(false, null, 'Invalid or expired token', 401);
    }
    
    return $userId;
}

function verifyJWT($token) {
    // پیاده‌سازی ساده JWT (در پروژه واقعی از کتابخانه استفاده کنید)
    try {
        $parts = explode('.', $token);
        if (count($parts) !== 3) return false;
        
        $payload = json_decode(base64_decode($parts[1]), true);
        if (!$payload || !isset($payload['user_id']) || $payload['exp'] < time()) {
            return false;
        }
        
        return $payload['user_id'];
    } catch (Exception $e) {
        return false;
    }
}

// تابع تولید JWT
function generateJWT($userId, $userType) {
    $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
    $payload = json_encode([
        'user_id' => $userId,
        'user_type' => $userType,
        'iat' => time(),
        'exp' => time() + (24 * 60 * 60) // 24 ساعت
    ]);
    
    $base64Header = base64_encode($header);
    $base64Payload = base64_encode($payload);
    
    $signature = hash_hmac('sha256', $base64Header . "." . $base64Payload, 'your-secret-key');
    $base64Signature = base64_encode($signature);
    
    return $base64Header . "." . $base64Payload . "." . $base64Signature;
}

// تابع آپلود فایل
function uploadFile($file, $adId) {
    if ($file['error'] !== UPLOAD_ERR_OK) {
        throw new Exception('File upload error');
    }
    
    // بررسی حجم فایل
    if ($file['size'] > MAX_FILE_SIZE) {
        throw new Exception('File size too large');
    }
    
    // بررسی نوع فایل
    $fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    if (!in_array($fileExtension, ALLOWED_TYPES)) {
        throw new Exception('Invalid file type');
    }
    
    // ایجاد پوشه اگر وجود ندارد
    if (!is_dir(UPLOAD_DIR)) {
        mkdir(UPLOAD_DIR, 0755, true);
    }
    
    // تولید نام فایل
    $fileName = uniqid() . '_' . $adId . '.' . $fileExtension;
    $filePath = UPLOAD_DIR . $fileName;
    
    if (!move_uploaded_file($file['tmp_name'], $filePath)) {
        throw new Exception('Failed to save file');
    }
    
    // ایجاد thumbnail (ساده)
    $thumbnailPath = UPLOAD_DIR . 'thumb_' . $fileName;
    createThumbnail($filePath, $thumbnailPath, 200, 200);
    
    return [
        'path' => $filePath,
        'thumbnail' => $thumbnailPath,
        'filename' => $fileName
    ];
}

function createThumbnail($source, $dest, $width, $height) {
    // پیاده‌سازی ساده ایجاد thumbnail
    // در پروژه واقعی از GD یا Imagick استفاده کنید
    copy($source, $dest);
}
?>

2. API مدیریت کاربران (auth_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];
$conn = getDBConnection();

switch ($method) {
    case 'POST':
        $action = $_GET['action'] ?? '';
        switch ($action) {
            case 'register':
                registerUser();
                break;
            case 'login':
                loginUser();
                break;
            case 'forgot-password':
                forgotPassword();
                break;
            case 'reset-password':
                resetPassword();
                break;
            default:
                sendResponse(false, null, 'Invalid action', 400);
        }
        break;
    case 'GET':
        getProfile();
        break;
    case 'PUT':
        updateProfile();
        break;
    default:
        sendResponse(false, null, 'Method not allowed', 405);
}

function registerUser() {
    global $conn;
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    $required = ['username', 'email', 'password', 'first_name', 'last_name'];
    foreach ($required as $field) {
        if (!isset($data[$field]) || empty($data[$field])) {
            sendResponse(false, null, "Field $field is required", 400);
        }
    }
    
    // بررسی تکراری نبودن username و email
    $checkQuery = "SELECT UserID FROM Users WHERE Username = ? OR Email = ?";
    $checkStmt = $conn->prepare($checkQuery);
    $checkStmt->bind_param("ss", $data['username'], $data['email']);
    $checkStmt->execute();
    
    if ($checkStmt->get_result()->num_rows > 0) {
        sendResponse(false, null, 'Username or email already exists', 400);
    }
    
    // هش کردن رمز عبور
    $passwordHash = password_hash($data['password'], PASSWORD_DEFAULT);
    $verificationToken = bin2hex(random_bytes(32));
    
    $query = "INSERT INTO Users (Username, Email, PasswordHash, FirstName, LastName, Phone, VerificationToken) 
              VALUES (?, ?, ?, ?, ?, ?, ?)";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param(
        "sssssss",
        $data['username'],
        $data['email'],
        $passwordHash,
        $data['first_name'],
        $data['last_name'],
        $data['phone'] ?? null,
        $verificationToken
    );
    
    if ($stmt->execute()) {
        $userId = $stmt->insert_id;
        
        // ایجاد پروفایل کاربر
        $profileQuery = "INSERT INTO UserProfiles (UserID) VALUES (?)";
        $profileStmt = $conn->prepare($profileQuery);
        $profileStmt->bind_param("i", $userId);
        $profileStmt->execute();
        
        // فعال‌سازی بسته رایگان
        activateFreePackage($userId);
        
        // ارسال ایمیل verification (در پروژه واقعی)
        
        sendResponse(true, [
            'user_id' => $userId,
            'message' => 'User registered successfully. Please check your email for verification.'
        ], 'Registration successful', 201);
    } else {
        sendResponse(false, null, 'Registration failed', 500);
    }
}

function activateFreePackage($userId) {
    global $conn;
    
    $packageQuery = "SELECT PackageID FROM UserPackages WHERE PackageType = 'Free'";
    $packageResult = $conn->query($packageQuery);
    $freePackage = $packageResult->fetch_assoc();
    
    if ($freePackage) {
        $startDate = date('Y-m-d H:i:s');
        $endDate = date('Y-m-d H:i:s', strtotime('+30 days'));
        
        $subscriptionQuery = "
            INSERT INTO UserSubscriptions (UserID, PackageID, StartDate, EndDate, IsActive) 
            VALUES (?, ?, ?, ?, TRUE)
        ";
        $subscriptionStmt = $conn->prepare($subscriptionQuery);
        $subscriptionStmt->bind_param("iiss", $userId, $freePackage['PackageID'], $startDate, $endDate);
        $subscriptionStmt->execute();
    }
}

function loginUser() {
    global $conn;
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    if (!isset($data['username']) || !isset($data['password'])) {
        sendResponse(false, null, 'Username and password are required', 400);
    }
    
    $query = "
        SELECT u.*, up.CompanyName, s.PackageID, p.PackageType, p.AutoApprove 
        FROM Users u
        LEFT JOIN UserProfiles up ON u.UserID = up.UserID
        LEFT JOIN UserSubscriptions s ON u.UserID = s.UserID AND s.IsActive = TRUE
        LEFT JOIN UserPackages p ON s.PackageID = p.PackageID
        WHERE u.Username = ? OR u.Email = ?
    ";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param("ss", $data['username'], $data['username']);
    $stmt->execute();
    $result = $stmt->get_result();
    
    if ($result->num_rows === 0) {
        sendResponse(false, null, 'Invalid credentials', 401);
    }
    
    $user = $result->fetch_assoc();
    
    if (!password_verify($data['password'], $user['PasswordHash'])) {
        sendResponse(false, null, 'Invalid credentials', 401);
    }
    
    if (!$user['IsActive']) {
        sendResponse(false, null, 'Account is deactivated', 403);
    }
    
    // به‌روزرسانی آخرین لاگین
    $updateQuery = "UPDATE Users SET LastLogin = NOW() WHERE UserID = ?";
    $updateStmt = $conn->prepare($updateQuery);
    $updateStmt->bind_param("i", $user['UserID']);
    $updateStmt->execute();
    
    // تولید توکن
    $token = generateJWT($user['UserID'], $user['UserType']);
    
    sendResponse(true, [
        'token' => $token,
        'user' => [
            'user_id' => $user['UserID'],
            'username' => $user['Username'],
            'email' => $user['Email'],
            'first_name' => $user['FirstName'],
            'last_name' => $user['LastName'],
            'user_type' => $user['UserType'],
            'company_name' => $user['CompanyName'],
            'package_type' => $user['PackageType'],
            'auto_approve' => (bool)$user['AutoApprove']
        ]
    ], 'Login successful');
}

function getProfile() {
    global $conn;
    
    $userId = validateToken();
    
    $query = "
        SELECT 
            u.UserID, u.Username, u.Email, u.FirstName, u.LastName, u.Phone, u.Avatar,
            u.UserType, u.IsVerified, u.CreatedAt,
            up.CompanyName, up.Website, up.Address, up.City, up.Province, up.PostalCode,
            up.Bio, up.SocialMedia, up.NotificationPreferences,
            s.PackageID, p.PackageName, p.PackageType, s.EndDate as SubscriptionEnd
        FROM Users u
        LEFT JOIN UserProfiles up ON u.UserID = up.UserID
        LEFT JOIN UserSubscriptions s ON u.UserID = s.UserID AND s.IsActive = TRUE
        LEFT JOIN UserPackages p ON s.PackageID = p.PackageID
        WHERE u.UserID = ?
    ";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param("i", $userId);
    $stmt->execute();
    $result = $stmt->get_result();
    
    if ($result->num_rows === 0) {
        sendResponse(false, null, 'User not found', 404);
    }
    
    $user = $result->fetch_assoc();
    
    // تبدیل JSON fields به array
    if ($user['SocialMedia']) {
        $user['SocialMedia'] = json_decode($user['SocialMedia'], true);
    }
    if ($user['NotificationPreferences']) {
        $user['NotificationPreferences'] = json_decode($user['NotificationPreferences'], true);
    }
    
    sendResponse(true, $user, 'Profile retrieved successfully');
}

function updateProfile() {
    global $conn;
    
    $userId = validateToken();
    $data = json_decode(file_get_contents("php://input"), true);
    
    $conn->begin_transaction();
    
    try {
        // به‌روزرسانی اطلاعات کاربر
        $userFields = [];
        $userParams = [];
        $userTypes = "";
        
        $updatableUserFields = ['FirstName', 'LastName', 'Phone', 'Avatar'];
        foreach ($updatableUserFields as $field) {
            if (isset($data[$field])) {
                $userFields[] = "$field = ?";
                $userParams[] = $data[$field];
                $userTypes .= "s";
            }
        }
        
        if (!empty($userFields)) {
            $userParams[] = $userId;
            $userTypes .= "i";
            
            $userQuery = "UPDATE Users SET " . implode(", ", $userFields) . " WHERE UserID = ?";
            $userStmt = $conn->prepare($userQuery);
            $userStmt->bind_param($userTypes, ...$userParams);
            $userStmt->execute();
        }
        
        // به‌روزرسانی پروفایل
        $profileFields = [];
        $profileParams = [];
        $profileTypes = "";
        
        $updatableProfileFields = [
            'CompanyName', 'Website', 'Address', 'City', 'Province', 'PostalCode', 'Bio',
            'SocialMedia', 'NotificationPreferences'
        ];
        
        foreach ($updatableProfileFields as $field) {
            if (isset($data[$field])) {
                $profileFields[] = "$field = ?";
                if (in_array($field, ['SocialMedia', 'NotificationPreferences'])) {
                    $profileParams[] = json_encode($data[$field]);
                } else {
                    $profileParams[] = $data[$field];
                }
                $profileTypes .= "s";
            }
        }
        
        if (!empty($profileFields)) {
            $profileParams[] = $userId;
            $profileTypes .= "i";
            
            $profileQuery = "UPDATE UserProfiles SET " . implode(", ", $profileFields) . " WHERE UserID = ?";
            $profileStmt = $conn->prepare($profileQuery);
            $profileStmt->bind_param($profileTypes, ...$profileParams);
            $profileStmt->execute();
        }
        
        $conn->commit();
        sendResponse(true, null, 'Profile updated successfully');
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to update profile', 500);
    }
}
?>

3. API مدیریت آگهی‌ها (ads_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];
$conn = getDBConnection();

switch ($method) {
    case 'GET':
        getAds();
        break;
    case 'POST':
        createAd();
        break;
    case 'PUT':
        updateAd();
        break;
    case 'DELETE':
        deleteAd();
        break;
}

function getAds() {
    global $conn;
    
    $adId = $_GET['ad_id'] ?? null;
    $userId = $_GET['user_id'] ?? null;
    $categoryId = $_GET['category_id'] ?? null;
    $status = $_GET['status'] ?? null;
    $search = $_GET['search'] ?? null;
    $page = $_GET['page'] ?? 1;
    $limit = $_GET['limit'] ?? 20;
    $offset = ($page - 1) * $limit;
    
    $whereConditions = ["a.Status != 'Draft'"];
    $params = [];
    $types = "";
    
    if ($adId) {
        $whereConditions[] = "a.AdID = ?";
        $params[] = $adId;
        $types .= "i";
    }
    
    if ($userId) {
        $whereConditions[] = "a.UserID = ?";
        $params[] = $userId;
        $types .= "i";
    }
    
    if ($categoryId) {
        $whereConditions[] = "a.CategoryID = ?";
        $params[] = $categoryId;
        $types .= "i";
    }
    
    if ($status) {
        $whereConditions[] = "a.Status = ?";
        $params[] = $status;
        $types .= "s";
    }
    
    $whereClause = implode(" AND ", $whereConditions);
    
    // اگر جستجو وجود دارد
    if ($search) {
        $whereClause .= " AND (MATCH(a.Title, a.Description, a.ShortDescription) AGAINST(? IN NATURAL LANGUAGE MODE) OR a.Title LIKE ?)";
        $params[] = $search;
        $params[] = "%$search%";
        $types .= "ss";
    }
    
    // گرفتن تعداد کل
    $countQuery = "
        SELECT COUNT(*) as total 
        FROM Advertisements a 
        WHERE $whereClause
    ";
    $countStmt = $conn->prepare($countQuery);
    if (!empty($params)) {
        $countStmt->bind_param($types, ...$params);
    }
    $countStmt->execute();
    $totalResult = $countStmt->get_result();
    $total = $totalResult->fetch_assoc()['total'];
    
    // گرفتن آگهی‌ها
    $query = "
        SELECT 
            a.AdID, a.Title, a.Slug, a.ShortDescription, a.Price, a.Currency, 
            a.IsNegotiable, a.Status, a.IsPremium, a.IsUrgent, a.ViewCount,
            a.LikeCount, a.ExpiryDate, a.CreatedAt,
            c.CategoryName, c.CategorySlug,
            u.UserID, u.Username, u.FirstName, u.LastName, up.CompanyName,
            (SELECT ImagePath FROM AdImages WHERE AdID = a.AdID AND IsPrimary = TRUE LIMIT 1) as PrimaryImage,
            COUNT(DISTINCT f.FavoriteID) as FavoriteCount
        FROM Advertisements a
        INNER JOIN Categories c ON a.CategoryID = c.CategoryID
        INNER JOIN Users u ON a.UserID = u.UserID
        LEFT JOIN UserProfiles up ON u.UserID = up.UserID
        LEFT JOIN Favorites f ON a.AdID = f.AdID
        WHERE $whereClause
        GROUP BY a.AdID
        ORDER BY 
            a.IsPremium DESC,
            a.IsUrgent DESC,
            a.FeaturedUntil DESC,
            a.CreatedAt DESC
        LIMIT ? OFFSET ?
    ";
    
    $params[] = $limit;
    $params[] = $offset;
    $types .= "ii";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    $result = $stmt->get_result();
    
    $ads = [];
    while ($row = $result->fetch_assoc()) {
        $ads[] = $row;
    }
    
    sendResponse(true, [
        'ads' => $ads,
        'pagination' => [
            'page' => intval($page),
            'limit' => intval($limit),
            'total' => $total,
            'pages' => ceil($total / $limit)
        ]
    ], 'Ads retrieved successfully');
}

function createAd() {
    global $conn;
    
    $userId = validateToken();
    
    // بررسی subscription کاربر
    $subscriptionQuery = "
        SELECT p.*, s.EndDate 
        FROM UserSubscriptions s 
        INNER JOIN UserPackages p ON s.PackageID = p.PackageID 
        WHERE s.UserID = ? AND s.IsActive = TRUE AND s.EndDate > NOW()
    ";
    $subscriptionStmt = $conn->prepare($subscriptionQuery);
    $subscriptionStmt->bind_param("i", $userId);
    $subscriptionStmt->execute();
    $subscription = $subscriptionStmt->get_result()->fetch_assoc();
    
    if (!$subscription) {
        sendResponse(false, null, 'No active subscription found', 403);
    }
    
    // بررسی تعداد آگهی‌های فعال کاربر
    $activeAdsQuery = "SELECT COUNT(*) as active_ads FROM Advertisements WHERE UserID = ? AND Status IN ('Pending', 'Approved')";
    $activeAdsStmt = $conn->prepare($activeAdsQuery);
    $activeAdsStmt->bind_param("i", $userId);
    $activeAdsStmt->execute();
    $activeAds = $activeAdsStmt->get_result()->fetch_assoc()['active_ads'];
    
    if ($activeAds >= $subscription['MaxAds']) {
        sendResponse(false, null, 'Maximum ads limit reached for your package', 403);
    }
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    $required = ['title', 'category_id', 'description', 'contact_info'];
    foreach ($required as $field) {
        if (!isset($data[$field]) || empty($data[$field])) {
            sendResponse(false, null, "Field $field is required", 400);
        }
    }
    
    $conn->begin_transaction();
    
    try {
        // تولید slug
        $slug = generateSlug($data['title']);
        
        // تعیین وضعیت آگهی
        $status = 'Pending';
        if ($subscription['AutoApprove']) {
            $status = 'Approved';
        }
        
        // تاریخ انقضا
        $expiryDays = 30; // از تنظیمات سیستم بگیرید
        $expiryDate = date('Y-m-d H:i:s', strtotime("+$expiryDays days"));
        
        $query = "
            INSERT INTO Advertisements (
                UserID, CategoryID, Title, Slug, Description, ShortDescription,
                Price, Currency, IsNegotiable, ContactInfo, LocationInfo,
                Status, IsPremium, IsUrgent, ExpiryDate
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ";
        
        $stmt = $conn->prepare($query);
        $stmt->bind_param(
            "iissssdssssssss",
            $userId,
            $data['category_id'],
            $data['title'],
            $slug,
            $data['description'],
            $data['short_description'] ?? null,
            $data['price'] ?? 0,
            $data['currency'] ?? 'IRT',
            $data['is_negotiable'] ?? false,
            json_encode($data['contact_info']),
            isset($data['location_info']) ? json_encode($data['location_info']) : null,
            $status,
            $data['is_premium'] ?? false,
            $data['is_urgent'] ?? false,
            $expiryDate
        );
        
        $stmt->execute();
        $adId = $stmt->insert_id;
        
        // ذخیره ویژگی‌های آگهی
        if (isset($data['attributes']) && is_array($data['attributes'])) {
            foreach ($data['attributes'] as $attributeId => $value) {
                saveAttributeValue($adId, $attributeId, $value);
            }
        }
        
        $conn->commit();
        
        sendResponse(true, [
            'ad_id' => $adId,
            'slug' => $slug,
            'status' => $status
        ], 'Ad created successfully', 201);
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to create ad: ' . $e->getMessage(), 500);
    }
}

function generateSlug($title) {
    global $conn;
    
    $slug = preg_replace('/[^\p{L}\p{N}\s]/u', '', $title);
    $slug = str_replace(' ', '-', $slug);
    $slug = strtolower($slug);
    $slug = preg_replace('/-+/', '-', $slug);
    $slug = trim($slug, '-');
    
    // بررسی تکراری نبودن
    $baseSlug = $slug;
    $counter = 1;
    
    while (true) {
        $checkQuery = "SELECT AdID FROM Advertisements WHERE Slug = ?";
        $checkStmt = $conn->prepare($checkQuery);
        $checkStmt->bind_param("s", $slug);
        $checkStmt->execute();
        
        if ($checkStmt->get_result()->num_rows === 0) {
            break;
        }
        
        $slug = $baseSlug . '-' . $counter;
        $counter++;
    }
    
    return $slug;
}

function saveAttributeValue($adId, $attributeId, $value) {
    global $conn;
    
    $query = "
        INSERT INTO AdAttributeValues (AdID, AttributeID, StringValue, NumberValue, BooleanValue, DateValue)
        VALUES (?, ?, ?, ?, ?, ?)
    ";
    
    $stmt = $conn->prepare($query);
    
    // تشخیص نوع مقدار بر اساس نوع attribute
    $attributeQuery = "SELECT AttributeType FROM AdAttributes WHERE AttributeID = ?";
    $attributeStmt = $conn->prepare($attributeQuery);
    $attributeStmt->bind_param("i", $attributeId);
    $attributeStmt->execute();
    $attributeType = $attributeStmt->get_result()->fetch_assoc()['AttributeType'];
    
    $stringValue = null;
    $numberValue = null;
    $booleanValue = null;
    $dateValue = null;
    
    switch ($attributeType) {
        case 'Text':
        case 'Select':
            $stringValue = $value;
            break;
        case 'Number':
            $numberValue = $value;
            break;
        case 'Boolean':
            $booleanValue = $value;
            break;
        case 'Date':
            $dateValue = $value;
            break;
    }
    
    $stmt->bind_param(
        "iissis",
        $adId, $attributeId, $stringValue, $numberValue, $booleanValue, $dateValue
    );
    $stmt->execute();
}

function updateAd() {
    global $conn;
    
    $userId = validateToken();
    $adId = $_GET['ad_id'];
    
    if (!$adId) {
        sendResponse(false, null, 'Ad ID is required', 400);
    }
    
    // بررسی مالکیت آگهی
    $ownershipQuery = "SELECT UserID, Status FROM Advertisements WHERE AdID = ?";
    $ownershipStmt = $conn->prepare($ownershipQuery);
    $ownershipStmt->bind_param("i", $adId);
    $ownershipStmt->execute();
    $ad = $ownershipStmt->get_result()->fetch_assoc();
    
    if (!$ad) {
        sendResponse(false, null, 'Ad not found', 404);
    }
    
    if ($ad['UserID'] != $userId) {
        sendResponse(false, null, 'You are not authorized to update this ad', 403);
    }
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    $conn->begin_transaction();
    
    try {
        $fields = [];
        $params = [];
        $types = "";
        
        $updatableFields = [
            'Title', 'CategoryID', 'Description', 'ShortDescription', 'Price',
            'IsNegotiable', 'ContactInfo', 'LocationInfo', 'IsPremium', 'IsUrgent'
        ];
        
        foreach ($updatableFields as $field) {
            if (isset($data[strtolower($field)])) {
                $fields[] = "$field = ?";
                $value = $data[strtolower($field)];
                
                if (in_array($field, ['ContactInfo', 'LocationInfo'])) {
                    $value = json_encode($value);
                }
                
                $params[] = $value;
                $types .= "s";
            }
        }
        
        if (isset($data['title'])) {
            // اگر عنوان تغییر کرده، slug جدید تولید کن
            $fields[] = "Slug = ?";
            $params[] = generateSlug($data['title']);
            $types .= "s";
        }
        
        if (!empty($fields)) {
            $params[] = $adId;
            $types .= "i";
            
            $query = "UPDATE Advertisements SET " . implode(", ", $fields) . " WHERE AdID = ?";
            $stmt = $conn->prepare($query);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
        }
        
        // به‌روزرسانی ویژگی‌ها
        if (isset($data['attributes']) && is_array($data['attributes'])) {
            // حذف ویژگی‌های قبلی
            $deleteQuery = "DELETE FROM AdAttributeValues WHERE AdID = ?";
            $deleteStmt = $conn->prepare($deleteQuery);
            $deleteStmt->bind_param("i", $adId);
            $deleteStmt->execute();
            
            // درج ویژگی‌های جدید
            foreach ($data['attributes'] as $attributeId => $value) {
                saveAttributeValue($adId, $attributeId, $value);
            }
        }
        
        $conn->commit();
        sendResponse(true, null, 'Ad updated successfully');
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to update ad: ' . $e->getMessage(), 500);
    }
}
?>

4. API مدیریت تصاویر آگهی (images_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];
$conn = getDBConnection();

switch ($method) {
    case 'POST':
        uploadAdImage();
        break;
    case 'DELETE':
        deleteAdImage();
        break;
    case 'PUT':
        setPrimaryImage();
        break;
    default:
        sendResponse(false, null, 'Method not allowed', 405);
}

function uploadAdImage() {
    global $conn;
    
    $userId = validateToken();
    $adId = $_POST['ad_id'] ?? null;
    
    if (!$adId || !isset($_FILES['image'])) {
        sendResponse(false, null, 'Ad ID and image file are required', 400);
    }
    
    // بررسی مالکیت آگهی
    $ownershipQuery = "SELECT UserID FROM Advertisements WHERE AdID = ?";
    $ownershipStmt = $conn->prepare($ownershipQuery);
    $ownershipStmt->bind_param("i", $adId);
    $ownershipStmt->execute();
    $ad = $ownershipStmt->get_result()->fetch_assoc();
    
    if (!$ad || $ad['UserID'] != $userId) {
        sendResponse(false, null, 'You are not authorized to upload images for this ad', 403);
    }
    
    // بررسی تعداد تصاویر
    $subscriptionQuery = "
        SELECT p.MaxImagesPerAd 
        FROM UserSubscriptions s 
        INNER JOIN UserPackages p ON s.PackageID = p.PackageID 
        WHERE s.UserID = ? AND s.IsActive = TRUE
    ";
    $subscriptionStmt = $conn->prepare($subscriptionQuery);
    $subscriptionStmt->bind_param("i", $userId);
    $subscriptionStmt->execute();
    $subscription = $subscriptionStmt->get_result()->fetch_assoc();
    
    $imageCountQuery = "SELECT COUNT(*) as image_count FROM AdImages WHERE AdID = ?";
    $imageCountStmt = $conn->prepare($imageCountQuery);
    $imageCountStmt->bind_param("i", $adId);
    $imageCountStmt->execute();
    $imageCount = $imageCountStmt->get_result()->fetch_assoc()['image_count'];
    
    if ($imageCount >= $subscription['MaxImagesPerAd']) {
        sendResponse(false, null, 'Maximum images limit reached for this ad', 403);
    }
    
    try {
        $fileInfo = uploadFile($_FILES['image'], $adId);
        
        // بررسی اینکه آیا این اولین تصویر است
        $isPrimary = ($imageCount === 0);
        
        $query = "
            INSERT INTO AdImages (AdID, ImagePath, ImageThumbnail, IsPrimary, SortOrder)
            VALUES (?, ?, ?, ?, ?)
        ";
        
        $sortOrder = $imageCount + 1;
        
        $stmt = $conn->prepare($query);
        $stmt->bind_param(
            "sssii",
            $adId,
            $fileInfo['path'],
            $fileInfo['thumbnail'],
            $isPrimary,
            $sortOrder
        );
        $stmt->execute();
        
        $imageId = $stmt->insert_id;
        
        sendResponse(true, [
            'image_id' => $imageId,
            'path' => $fileInfo['path'],
            'thumbnail' => $fileInfo['thumbnail'],
            'is_primary' => $isPrimary
        ], 'Image uploaded successfully', 201);
        
    } catch (Exception $e) {
        sendResponse(false, null, 'Failed to upload image: ' . $e->getMessage(), 500);
    }
}

function deleteAdImage() {
    global $conn;
    
    $userId = validateToken();
    $imageId = $_GET['image_id'];
    
    if (!$imageId) {
        sendResponse(false, null, 'Image ID is required', 400);
    }
    
    // بررسی مالکیت تصویر
    $ownershipQuery = "
        SELECT ai.ImageID, ai.ImagePath, ai.ImageThumbnail, ai.IsPrimary, a.UserID 
        FROM AdImages ai
        INNER JOIN Advertisements a ON ai.AdID = a.AdID
        WHERE ai.ImageID = ?
    ";
    $ownershipStmt = $conn->prepare($ownershipQuery);
    $ownershipStmt->bind_param("i", $imageId);
    $ownershipStmt->execute();
    $image = $ownershipStmt->get_result()->fetch_assoc();
    
    if (!$image) {
        sendResponse(false, null, 'Image not found', 404);
    }
    
    if ($image['UserID'] != $userId) {
        sendResponse(false, null, 'You are not authorized to delete this image', 403);
    }
    
    $conn->begin_transaction();
    
    try {
        // حذف فایل‌های فیزیکی
        if (file_exists($image['ImagePath'])) {
            unlink($image['ImagePath']);
        }
        if (file_exists($image['ImageThumbnail'])) {
            unlink($image['ImageThumbnail']);
        }
        
        // حذف از دیتابیس
        $deleteQuery = "DELETE FROM AdImages WHERE ImageID = ?";
        $deleteStmt = $conn->prepare($deleteQuery);
        $deleteStmt->bind_param("i", $imageId);
        $deleteStmt->execute();
        
        // اگر تصویر حذف شده primary بود، اولین تصویر دیگر را primary کن
        if ($image['IsPrimary']) {
            $newPrimaryQuery = "
                SELECT ImageID FROM AdImages 
                WHERE AdID = (SELECT AdID FROM AdImages WHERE ImageID = ?) 
                ORDER BY SortOrder ASC 
                LIMIT 1
            ";
            $newPrimaryStmt = $conn->prepare($newPrimaryQuery);
            $newPrimaryStmt->bind_param("i", $imageId);
            $newPrimaryStmt->execute();
            $newPrimary = $newPrimaryStmt->get_result()->fetch_assoc();
            
            if ($newPrimary) {
                $updatePrimaryQuery = "UPDATE AdImages SET IsPrimary = TRUE WHERE ImageID = ?";
                $updatePrimaryStmt = $conn->prepare($updatePrimaryQuery);
                $updatePrimaryStmt->bind_param("i", $newPrimary['ImageID']);
                $updatePrimaryStmt->execute();
            }
        }
        
        $conn->commit();
        sendResponse(true, null, 'Image deleted successfully');
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to delete image: ' . $e->getMessage(), 500);
    }
}
?>

5. API مدیریت دسته‌بندی‌ها (categories_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];

if ($method == 'GET') {
    getCategories();
} else {
    sendResponse(false, null, 'Method not allowed', 405);
}

function getCategories() {
    global $conn;
    
    $parentId = $_GET['parent_id'] ?? null;
    $includeAttributes = $_GET['include_attributes'] ?? false;
    
    $query = "
        SELECT 
            c.CategoryID, c.CategoryName, c.CategorySlug, c.Description,
            c.Icon, c.ParentCategoryID, c.SortOrder, c.IsActive,
            pc.CategoryName as ParentCategoryName,
            COUNT(DISTINCT a.AdID) as AdCount
        FROM Categories c
        LEFT JOIN Categories pc ON c.ParentCategoryID = pc.CategoryID
        LEFT JOIN Advertisements a ON c.CategoryID = a.CategoryID AND a.Status = 'Approved'
        WHERE c.IsActive = TRUE
    ";
    
    $params = [];
    $types = "";
    
    if ($parentId !== null) {
        $query .= " AND c.ParentCategoryID = ?";
        $params[] = $parentId;
        $types .= "i";
    } else {
        $query .= " AND c.ParentCategoryID IS NULL";
    }
    
    $query .= " GROUP BY c.CategoryID ORDER BY c.SortOrder, c.CategoryName";
    
    $stmt = $conn->prepare($query);
    if (!empty($params)) {
        $stmt->bind_param($types, ...$params);
    }
    $stmt->execute();
    $result = $stmt->get_result();
    
    $categories = [];
    while ($row = $result->fetch_assoc()) {
        if ($includeAttributes) {
            $row['attributes'] = getCategoryAttributes($row['CategoryID']);
        }
        $categories[] = $row;
    }
    
    sendResponse(true, $categories, 'Categories retrieved successfully');
}

function getCategoryAttributes($categoryId) {
    global $conn;
    
    $query = "
        SELECT AttributeID, AttributeName, AttributeType, IsRequired, Options
        FROM AdAttributes 
        WHERE CategoryID = ? AND IsActive = TRUE
        ORDER BY SortOrder
    ";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param("i", $categoryId);
    $stmt->execute();
    $result = $stmt->get_result();
    
    $attributes = [];
    while ($row = $result->fetch_assoc()) {
        if ($row['Options']) {
            $row['Options'] = json_decode($row['Options'], true);
        }
        $attributes[] = $row;
    }
    
    return $attributes;
}
?>

6. فایل روتر اصلی (router.php)

php
<?php
include 'config.php';

$request_uri = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($request_uri, PHP_URL_PATH);

// مسیرهای API
$routes = [
    'GET' => [
        '/api/ads' => 'ads_api.php',
        '/api/categories' => 'categories_api.php',
        '/api/profile' => 'auth_api.php',
        '/api/user/ads' => 'ads_api.php?user_only=true'
    ],
    'POST' => [
        '/api/auth/register' => 'auth_api.php?action=register',
        '/api/auth/login' => 'auth_api.php?action=login',
        '/api/ads' => 'ads_api.php',
        '/api/ads/images' => 'images_api.php'
    ],
    'PUT' => [
        '/api/profile' => 'auth_api.php',
        '/api/ads' => 'ads_api.php',
        '/api/ads/images/primary' => 'images_api.php?action=set_primary'
    ],
    'DELETE' => [
        '/api/ads' => 'ads_api.php',
        '/api/ads/images' => 'images_api.php'
    ]
];

// پیدا کردن مسیر منطبق
$matched = false;
foreach ($routes[$method] as $route => $file) {
    if (strpos($path, $route) === 0) {
        include($file);
        $matched = true;
        break;
    }
}

if (!$matched) {
    sendResponse(false, null, 'Endpoint not found', 404);
}
?>

7. مثال استفاده از API ها

javascript
// ثبت‌نام کاربر
fetch('/api/auth/register', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
        username: 'user123',
        email: 'user@example.com',
        password: 'password123',
        first_name: 'علی',
        last_name: 'محمدی',
        phone: '09123456789'
    })
});

// ورود کاربر
fetch('/api/auth/login', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
        username: 'user123',
        password: 'password123'
    })
});

// ایجاد آگهی جدید
fetch('/api/ads', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer your-jwt-token'
    },
    body: JSON.stringify({
        title: 'فروش خودروی صندوق دار',
        category_id: 2,
        description: 'خودروی سالم و بدون رنگ',
        short_description: 'فروش خودروی مدل 1400',
        price: 500000000,
        is_negotiable: true,
        contact_info: {
            phone: '09123456789',
            email: 'user@example.com'
        },
        location_info: {
            city: 'تهران',
            province: 'تهران',
            address: 'میدان انقلاب'
        },
        attributes: {
            1: '1400', // سال ساخت
            2: '150000' // کارکرد
        }
    })
});

// آپلود تصویر برای آگهی
const formData = new FormData();
formData.append('ad_id', 123);
formData.append('image', fileInput.files[0]);

fetch('/api/ads/images', {
    method: 'POST',
    headers: {
        'Authorization': 'Bearer your-jwt-token'
    },
    body: formData
});

// گرفتن لیست آگهی‌ها
fetch('/api/ads?page=1&limit=20&category_id=2')
    .then(response => response.json())
    .then(data => console.log(data));

این API های کامل تمام نیازهای یک سامانه درج آگهی را پوشش می‌دهند و می‌توانند بر اساس نیازهای خاص توسعه داده شوند.

 
کانال نوحه و مداحی ناب

نظرات (۰)
هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی