- Added software.php for managing software versions, including download and purchase actions. - Created upgrade_paths.php for handling upgrade paths management. - Developed user_licenses.php for managing user licenses. - Introduced version_access_rules.php for managing access rules for software versions. - Implemented frontend functions in functions.js for interacting with the software upgrade API. - Added version_access.php for user access validation and license management. - Created upgrades.php for displaying available upgrades and handling user interactions. - Enhanced UI with responsive design and progress indicators for downloads and purchases.
282 lines
8.3 KiB
PHP
282 lines
8.3 KiB
PHP
<?php
|
|
|
|
function getUserOwnedVersions($userId) {
|
|
global $pdo;
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT sv.*, ul.license_key, ul.purchased_at
|
|
FROM user_licenses ul
|
|
JOIN software_versions sv ON ul.version_id = sv.id
|
|
WHERE ul.user_id = ? AND ul.status = 'active'
|
|
ORDER BY sv.major_version DESC, sv.minor_version DESC
|
|
");
|
|
$stmt->execute([$userId]);
|
|
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
function getLatestOwnedVersion($userId) {
|
|
$versions = getUserOwnedVersions($userId);
|
|
return !empty($versions) ? $versions[0] : null;
|
|
}
|
|
|
|
function checkVersionAccess($userId, $versionId) {
|
|
global $pdo;
|
|
|
|
// Get version and its access rules
|
|
$stmt = $pdo->prepare("
|
|
SELECT sv.*, var.access_type, var.requires_base_version, var.price
|
|
FROM software_versions sv
|
|
JOIN version_access_rules var ON sv.id = var.version_id
|
|
WHERE sv.id = ?
|
|
");
|
|
$stmt->execute([$versionId]);
|
|
$version = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$version) {
|
|
return ['accessible' => false, 'reason' => 'Version not found'];
|
|
}
|
|
|
|
switch ($version['access_type']) {
|
|
case 'free_all':
|
|
// Free for everyone (like v0.99)
|
|
return [
|
|
'accessible' => true,
|
|
'reason' => 'free_for_all',
|
|
'price' => 0.00,
|
|
'requires_payment' => false
|
|
];
|
|
|
|
case 'free_for_owners':
|
|
// Free for owners of required base version (like v1.1 for v1.0 owners)
|
|
if ($version['requires_base_version']) {
|
|
$hasBaseVersion = userOwnsVersion($userId, $version['requires_base_version']);
|
|
|
|
if ($hasBaseVersion) {
|
|
return [
|
|
'accessible' => true,
|
|
'reason' => 'free_upgrade',
|
|
'price' => 0.00,
|
|
'requires_payment' => false
|
|
];
|
|
} else {
|
|
return [
|
|
'accessible' => false,
|
|
'reason' => 'requires_base_version',
|
|
'required_version' => $version['requires_base_version'],
|
|
'price' => $version['price'],
|
|
'requires_payment' => true
|
|
];
|
|
}
|
|
}
|
|
return ['accessible' => false, 'reason' => 'invalid_access_rule'];
|
|
|
|
case 'paid':
|
|
case 'paid_upgrade':
|
|
// Check if user already owns this version
|
|
if (userOwnsVersionById($userId, $versionId)) {
|
|
return [
|
|
'accessible' => true,
|
|
'reason' => 'already_owned',
|
|
'price' => 0.00,
|
|
'requires_payment' => false
|
|
];
|
|
}
|
|
|
|
// Check for upgrade pricing
|
|
$upgradeInfo = getUpgradePrice($userId, $versionId);
|
|
|
|
return [
|
|
'accessible' => false,
|
|
'reason' => 'requires_purchase',
|
|
'price' => $upgradeInfo['price'],
|
|
'original_price' => $version['price'],
|
|
'is_upgrade' => $upgradeInfo['is_upgrade'],
|
|
'requires_payment' => true
|
|
];
|
|
|
|
default:
|
|
return ['accessible' => false, 'reason' => 'unknown_access_type'];
|
|
}
|
|
}
|
|
|
|
function userOwnsVersion($userId, $version) {
|
|
global $pdo;
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT COUNT(*)
|
|
FROM user_licenses ul
|
|
JOIN software_versions sv ON ul.version_id = sv.id
|
|
WHERE ul.user_id = ? AND sv.version = ? AND ul.status = 'active'
|
|
");
|
|
$stmt->execute([$userId, $version]);
|
|
|
|
return $stmt->fetchColumn() > 0;
|
|
}
|
|
|
|
function userOwnsVersionById($userId, $versionId) {
|
|
global $pdo;
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT COUNT(*)
|
|
FROM user_licenses
|
|
WHERE user_id = ? AND version_id = ? AND status = 'active'
|
|
");
|
|
$stmt->execute([$userId, $versionId]);
|
|
|
|
return $stmt->fetchColumn() > 0;
|
|
}
|
|
|
|
function getUpgradePrice($userId, $targetVersionId) {
|
|
global $pdo;
|
|
|
|
// Get user's owned versions
|
|
$ownedVersions = getUserOwnedVersions($userId);
|
|
|
|
if (empty($ownedVersions)) {
|
|
// No owned versions, return full price
|
|
$stmt = $pdo->prepare("
|
|
SELECT var.price
|
|
FROM version_access_rules var
|
|
WHERE var.version_id = ?
|
|
");
|
|
$stmt->execute([$targetVersionId]);
|
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
return [
|
|
'price' => $result['price'] ?? 0.00,
|
|
'is_upgrade' => false
|
|
];
|
|
}
|
|
|
|
// Check for upgrade paths
|
|
$bestUpgradePrice = null;
|
|
$fromVersion = null;
|
|
|
|
foreach ($ownedVersions as $ownedVersion) {
|
|
$stmt = $pdo->prepare("
|
|
SELECT upgrade_price, is_free
|
|
FROM upgrade_paths
|
|
WHERE from_version_id = ? AND to_version_id = ?
|
|
");
|
|
$stmt->execute([$ownedVersion['id'], $targetVersionId]);
|
|
$upgrade = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($upgrade) {
|
|
if ($upgrade['is_free']) {
|
|
return [
|
|
'price' => 0.00,
|
|
'is_upgrade' => true,
|
|
'from_version' => $ownedVersion['version']
|
|
];
|
|
}
|
|
|
|
if ($bestUpgradePrice === null || $upgrade['upgrade_price'] < $bestUpgradePrice) {
|
|
$bestUpgradePrice = $upgrade['upgrade_price'];
|
|
$fromVersion = $ownedVersion['version'];
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($bestUpgradePrice !== null) {
|
|
return [
|
|
'price' => $bestUpgradePrice,
|
|
'is_upgrade' => true,
|
|
'from_version' => $fromVersion
|
|
];
|
|
}
|
|
|
|
// No upgrade path, return full price
|
|
$stmt = $pdo->prepare("
|
|
SELECT var.price
|
|
FROM version_access_rules var
|
|
WHERE var.version_id = ?
|
|
");
|
|
$stmt->execute([$targetVersionId]);
|
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
return [
|
|
'price' => $result['price'] ?? 0.00,
|
|
'is_upgrade' => false
|
|
];
|
|
}
|
|
|
|
function grantLicense($pdo, $userId, $versionId, $transactionId = null) {
|
|
// Generate unique license key
|
|
$licenseKey = generateLicenseKey($userId, $versionId);
|
|
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO user_licenses (user_id, version_id, license_key, transaction_id, status)
|
|
VALUES (?, ?, ?, ?, 'active')
|
|
ON DUPLICATE KEY UPDATE status = 'active', license_key = ?
|
|
");
|
|
|
|
return $stmt->execute([$userId, $versionId, $licenseKey, $transactionId, $licenseKey]);
|
|
}
|
|
|
|
function generateLicenseKey($userId, $versionId) {
|
|
// Generate a unique license key
|
|
$data = $userId . '-' . $versionId . '-' . time() . '-' . bin2hex(random_bytes(8));
|
|
return strtoupper(substr(hash('sha256', $data), 0, 29)); // Format: XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
|
|
}
|
|
|
|
function generateSecureDownloadToken($pdo, $userId, $versionId) {
|
|
// Generate random token
|
|
$token = bin2hex(random_bytes(32));
|
|
|
|
// Store token with expiration (5 minutes)
|
|
$expiresAt = date('Y-m-d H:i:s', time() + 300);
|
|
|
|
$stmt = $pdo->prepare(
|
|
"INSERT INTO download_tokens (token, user_id, version_id, expires_at, used)
|
|
VALUES (?, ?, ?, ?, 0)"
|
|
);
|
|
$stmt->execute([$token, $userId, $versionId, $expiresAt]);
|
|
|
|
return $token;
|
|
}
|
|
|
|
function validateUserAccess($userId, $versionId) {
|
|
global $pdo;
|
|
|
|
// Check if version requires payment
|
|
$stmt = $pdo->prepare("
|
|
SELECT var.access_type
|
|
FROM version_access_rules var
|
|
WHERE var.version_id = ?
|
|
");
|
|
$stmt->execute([$versionId]);
|
|
$accessRule = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$accessRule) {
|
|
return false;
|
|
}
|
|
|
|
if ($accessRule['access_type'] === 'free_all') {
|
|
return true; // Free for everyone
|
|
}
|
|
|
|
// Check if user has valid license
|
|
$stmt = $pdo->prepare(
|
|
"SELECT COUNT(*) FROM user_licenses
|
|
WHERE user_id = ? AND version_id = ? AND status = 'active'"
|
|
);
|
|
$stmt->execute([$userId, $versionId]);
|
|
|
|
return $stmt->fetchColumn() > 0;
|
|
}
|
|
|
|
function logDownload($pdo, $userId, $versionId) {
|
|
$stmt = $pdo->prepare("
|
|
INSERT INTO download_logs (user_id, version_id, ip_address, user_agent, downloaded_at)
|
|
VALUES (?, ?, ?, ?, NOW())
|
|
");
|
|
$stmt->execute([
|
|
$userId,
|
|
$versionId,
|
|
$_SERVER['REMOTE_ADDR'] ?? '',
|
|
$_SERVER['HTTP_USER_AGENT'] ?? ''
|
|
]);
|
|
}
|
|
|
|
?>
|