![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/public_html/cron/ |
<?php
// Credit Expiration Cron Job
// This script should be run daily via cron to expire credits and commercial rights
require_once __DIR__ . '/../config/database.php';
// Set timezone
date_default_timezone_set('UTC');
// Log file for expiration events
$log_file = __DIR__ . '/../logs/credit_expirations.log';
function logExpirationEvent($event_type, $data) {
global $log_file;
$log_entry = [
'timestamp' => date('Y-m-d H:i:s'),
'event_type' => $event_type,
'data' => $data
];
file_put_contents($log_file, json_encode($log_entry) . "\n", FILE_APPEND | LOCK_EX);
}
try {
$pdo = getDBConnection();
// Get current timestamp
$now = date('Y-m-d H:i:s');
logExpirationEvent('cron_started', [
'timestamp' => $now,
'message' => 'Credit expiration cron job started'
]);
// Find users with expired subscriptions
// This includes users who have subscription_expires set and it's in the past
// AND their plan is not already 'free' (to avoid processing the same users multiple times)
// EXCLUDE users with premium package credits (premium credits never expire)
$stmt = $pdo->prepare("
SELECT u.id, u.name, u.email, u.credits, u.subscription_expires, u.plan
FROM users u
WHERE u.subscription_expires IS NOT NULL
AND u.subscription_expires < ?
AND u.plan != 'free'
AND NOT EXISTS (
SELECT 1 FROM credit_purchases cp
WHERE cp.user_id = u.id
AND cp.package = 'premium'
AND cp.expires_at IS NULL
)
");
$stmt->execute([$now]);
$expired_users = $stmt->fetchAll(PDO::FETCH_ASSOC);
$expired_count = 0;
$total_credits_expired = 0;
foreach ($expired_users as $user) {
try {
// Start transaction for this user
$pdo->beginTransaction();
$credits_before = $user['credits'];
$plan_before = $user['plan'];
// Update user: set plan to 'free', expire credits, and revoke commercial rights
// IMPORTANT: Users must maintain active subscription (minimum $5 Essential) to keep commercial rights
$stmt = $pdo->prepare("
UPDATE users
SET plan = 'free',
credits = 0,
commercial_rights_expires = subscription_expires,
updated_at = NOW()
WHERE id = ?
");
$stmt->execute([$user['id']]);
// Revoke commercial rights from all tracks created by this user
// Users must maintain subscription to keep commercial rights (per terms)
$stmt = $pdo->prepare("
UPDATE music_tracks
SET commercial_rights = 'none'
WHERE user_id = ?
AND commercial_rights IN ('full', 'grace')
AND commercial_rights_expires IS NULL
");
$stmt->execute([$user['id']]);
// Also set commercial_rights_expires on tracks to mark when rights were revoked
$stmt = $pdo->prepare("
UPDATE music_tracks
SET commercial_rights_expires = ?
WHERE user_id = ?
AND commercial_rights = 'none'
AND commercial_rights_expires IS NULL
");
$stmt->execute([$user['subscription_expires'], $user['id']]);
// Commit transaction
$pdo->commit();
// Log the expiration
logExpirationEvent('subscription_expired', [
'user_id' => $user['id'],
'name' => $user['name'],
'email' => $user['email'],
'credits_expired' => $credits_before,
'plan_before' => $plan_before,
'plan_after' => 'free',
'expiration_date' => $user['subscription_expires'],
'note' => 'Credits include permanent commercial rights per terms - only subscription tracks affected'
]);
// Send expiration notification email
sendExpirationNotification($user);
$expired_count++;
$total_credits_expired += $credits_before;
} catch (Exception $e) {
// Rollback on error
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
logExpirationEvent('expiration_error', [
'user_id' => $user['id'],
'error' => $e->getMessage()
]);
}
}
// Log summary
logExpirationEvent('cron_completed', [
'users_expired' => $expired_count,
'total_credits_expired' => $total_credits_expired,
'timestamp' => date('Y-m-d H:i:s')
]);
// Also check for users approaching expiration (send warnings)
checkApproachingExpirations();
echo "Credit expiration cron completed successfully.\n";
echo "Expired users: $expired_count\n";
echo "Total credits expired: $total_credits_expired\n";
} catch (Exception $e) {
logExpirationEvent('cron_error', [
'error' => $e->getMessage(),
'timestamp' => date('Y-m-d H:i:s')
]);
echo "Error in credit expiration cron: " . $e->getMessage() . "\n";
}
function sendExpirationNotification($user) {
// Send email notification to user about expired subscription
$subject = "Your SoundStudioPro Subscription Has Expired";
$user_name = $user['name'] ?? $user['username'] ?? 'User';
$message = "
Dear {$user_name},
Your SoundStudioPro subscription has expired as of {$user['subscription_expires']}.
Your account has been downgraded to the Free plan. Your credits have expired.
To continue creating music with commercial licensing rights and access to Pro features, please purchase a new credit package at:
https://soundstudiopro.com/account_settings.php?tab=subscription
Thank you for using SoundStudioPro!
Best regards,
The SoundStudioPro Team
";
// In production, use your email system
// mail($user['email'], $subject, $message);
logExpirationEvent('expiration_email_sent', [
'user_id' => $user['id'],
'email' => $user['email']
]);
}
function checkApproachingExpirations() {
global $pdo;
try {
// Check for users whose credits expire in the next 7 days
$warning_date = date('Y-m-d H:i:s', strtotime('+7 days'));
$now = date('Y-m-d H:i:s');
// Exclude premium package users from expiration warnings (premium credits never expire)
$stmt = $pdo->prepare("
SELECT u.id, u.name, u.email, u.credits, u.subscription_expires
FROM users u
WHERE u.subscription_expires IS NOT NULL
AND u.subscription_expires BETWEEN ? AND ?
AND (u.expiration_warning_sent = 0 OR u.expiration_warning_sent IS NULL)
AND u.plan != 'free'
AND NOT EXISTS (
SELECT 1 FROM credit_purchases cp
WHERE cp.user_id = u.id
AND cp.package = 'premium'
AND cp.expires_at IS NULL
)
");
$stmt->execute([$now, $warning_date]);
$approaching_users = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($approaching_users as $user) {
sendExpirationWarning($user);
// Mark warning as sent
$stmt = $pdo->prepare("
UPDATE users
SET expiration_warning_sent = 1
WHERE id = ?
");
$stmt->execute([$user['id']]);
}
logExpirationEvent('approaching_expirations_checked', [
'warning_date' => $warning_date,
'users_warned' => count($approaching_users),
'timestamp' => date('Y-m-d H:i:s')
]);
} catch (Exception $e) {
logExpirationEvent('approaching_expirations_error', [
'error' => $e->getMessage(),
'timestamp' => date('Y-m-d H:i:s')
]);
}
}
function sendExpirationWarning($user) {
$days_remaining = ceil((strtotime($user['subscription_expires']) - time()) / (24 * 60 * 60));
$user_name = $user['name'] ?? $user['username'] ?? 'User';
$subject = "Your SoundStudioPro Subscription Expires Soon";
$message = "
Dear {$user_name},
Your SoundStudioPro subscription will expire in {$days_remaining} days.
Current credits: {$user['credits']}
Expiration date: {$user['subscription_expires']}
To maintain your Pro/Starter/Premium plan benefits and commercial licensing rights, please renew your subscription at:
https://soundstudiopro.com/account_settings.php?tab=subscription
Thank you for using SoundStudioPro!
Best regards,
The SoundStudioPro Team
";
// In production, use your email system
// mail($user['email'], $subject, $message);
logExpirationEvent('expiration_warning_sent', [
'user_id' => $user['id'],
'email' => $user['email'],
'days_remaining' => $days_remaining
]);
}
?>