queueManager = new VQueueManager(); } /** * Handle cleanup job * @param array $data Cleanup configuration data * @return array Cleanup result */ public function handle($data) { $cleanupType = $data['type'] ?? 'full'; $this->logProgress('Starting system cleanup', [ 'type' => $cleanupType, 'data' => $data ]); $results = []; try { switch ($cleanupType) { case 'full': $results = $this->performFullCleanup($data); break; case 'logs': $results['logs'] = $this->cleanupLogs($data); break; case 'temp_files': $results['temp_files'] = $this->cleanupTempFiles($data); break; case 'old_sessions': $results['sessions'] = $this->cleanupOldSessions($data); break; case 'failed_uploads': $results['failed_uploads'] = $this->cleanupFailedUploads($data); break; case 'analytics': $results['analytics'] = $this->cleanupOldAnalytics($data); break; default: throw new Exception("Unknown cleanup type: {$cleanupType}"); } $this->logProgress('System cleanup completed', [ 'type' => $cleanupType, 'results' => $results ]); return [ 'success' => true, 'type' => $cleanupType, 'results' => $results, 'message' => 'Cleanup completed successfully' ]; } catch (Exception $e) { $this->logError('System cleanup failed', [ 'type' => $cleanupType, 'error' => $e->getMessage() ]); throw $e; } } /** * Perform full system cleanup * @param array $data Configuration data * @return array Cleanup results */ private function performFullCleanup($data) { $results = []; $this->updateProgress(1, 8, 'Cleaning up logs'); $results['logs'] = $this->cleanupLogs($data); $this->updateProgress(2, 8, 'Cleaning up temporary files'); $results['temp_files'] = $this->cleanupTempFiles($data); $this->updateProgress(3, 8, 'Cleaning up old sessions'); $results['sessions'] = $this->cleanupOldSessions($data); $this->updateProgress(4, 8, 'Cleaning up failed uploads'); $results['failed_uploads'] = $this->cleanupFailedUploads($data); $this->updateProgress(5, 8, 'Cleaning up old analytics'); $results['analytics'] = $this->cleanupOldAnalytics($data); $this->updateProgress(6, 8, 'Cleaning up queue jobs'); $results['queue_jobs'] = $this->queueManager->cleanupOldJobs( $data['queue_retention_hours'] ?? 24 ); $this->updateProgress(7, 8, 'Cleaning up orphaned files'); $results['orphaned_files'] = $this->cleanupOrphanedFiles($data); $this->updateProgress(8, 8, 'Optimizing database'); $results['database'] = $this->optimizeDatabase($data); return $results; } /** * Cleanup old log files * @param array $data Configuration data * @return array Cleanup result */ private function cleanupLogs($data) { $logDir = _FPATH . 'f_data/logs/'; $retentionDays = $data['log_retention_days'] ?? 30; $cutoffTime = time() - ($retentionDays * 24 * 3600); $deletedFiles = 0; $deletedSize = 0; if (is_dir($logDir)) { $files = glob($logDir . '*.log'); foreach ($files as $file) { if (filemtime($file) < $cutoffTime) { $size = filesize($file); if (unlink($file)) { $deletedFiles++; $deletedSize += $size; } } } } return [ 'deleted_files' => $deletedFiles, 'deleted_size' => $deletedSize, 'retention_days' => $retentionDays ]; } /** * Cleanup temporary files * @param array $data Configuration data * @return array Cleanup result */ private function cleanupTempFiles($data) { $tempDir = _FPATH . 'f_data/temp/'; $maxAge = $data['temp_file_max_age_hours'] ?? 24; $cutoffTime = time() - ($maxAge * 3600); $deletedFiles = 0; $deletedSize = 0; if (is_dir($tempDir)) { $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($tempDir, RecursiveDirectoryIterator::SKIP_DOTS) ); foreach ($iterator as $file) { if ($file->isFile() && $file->getMTime() < $cutoffTime) { $size = $file->getSize(); if (unlink($file->getPathname())) { $deletedFiles++; $deletedSize += $size; } } } } return [ 'deleted_files' => $deletedFiles, 'deleted_size' => $deletedSize, 'max_age_hours' => $maxAge ]; } /** * Cleanup old sessions * @param array $data Configuration data * @return array Cleanup result */ private function cleanupOldSessions($data) { $maxAge = $data['session_max_age_hours'] ?? 168; // 7 days $cutoffTime = date('Y-m-d H:i:s', time() - ($maxAge * 3600)); try { $db = $this->getDatabase(); // Cleanup database sessions if using database session storage $query = "DELETE FROM db_sessions WHERE last_activity < ?"; $db->doQuery($query, [$cutoffTime]); $deletedSessions = $db->getAffectedRows(); return [ 'deleted_db_sessions' => $deletedSessions, 'max_age_hours' => $maxAge ]; } catch (Exception $e) { $this->logError('Session cleanup failed', [ 'error' => $e->getMessage() ]); return [ 'error' => $e->getMessage(), 'deleted_db_sessions' => 0 ]; } } /** * Cleanup failed uploads * @param array $data Configuration data * @return array Cleanup result */ private function cleanupFailedUploads($data) { $maxAge = $data['failed_upload_max_age_hours'] ?? 48; $cutoffTime = date('Y-m-d H:i:s', time() - ($maxAge * 3600)); try { $db = $this->getDatabase(); // Find failed uploads $query = "SELECT file_key, usr_id FROM db_videofiles WHERE processing_status = 'failed' AND processed_at < ?"; $result = $db->doQuery($query, [$cutoffTime]); $deletedRecords = 0; $deletedFiles = 0; $deletedSize = 0; while ($row = $db->doFetch($result)) { // Delete associated files $userDir = _FPATH . 'f_data/media/' . $row['usr_id'] . '/'; $videoFiles = glob($userDir . $row['file_key'] . '*'); foreach ($videoFiles as $file) { if (is_file($file)) { $deletedSize += filesize($file); if (unlink($file)) { $deletedFiles++; } } } // Delete database record $deleteQuery = "DELETE FROM db_videofiles WHERE file_key = ?"; $db->doQuery($deleteQuery, [$row['file_key']]); $deletedRecords++; } return [ 'deleted_records' => $deletedRecords, 'deleted_files' => $deletedFiles, 'deleted_size' => $deletedSize, 'max_age_hours' => $maxAge ]; } catch (Exception $e) { $this->logError('Failed upload cleanup failed', [ 'error' => $e->getMessage() ]); return [ 'error' => $e->getMessage(), 'deleted_records' => 0, 'deleted_files' => 0 ]; } } /** * Cleanup old analytics data * @param array $data Configuration data * @return array Cleanup result */ private function cleanupOldAnalytics($data) { $retentionDays = $data['analytics_retention_days'] ?? 90; $cutoffTime = date('Y-m-d H:i:s', time() - ($retentionDays * 24 * 3600)); try { $db = $this->getDatabase(); $deletedRecords = 0; // Cleanup video analytics $query = "DELETE FROM db_video_analytics WHERE created_at < ?"; $db->doQuery($query, [$cutoffTime]); $deletedRecords += $db->getAffectedRows(); // Cleanup video views $query = "DELETE FROM db_video_views WHERE created_at < ?"; $db->doQuery($query, [$cutoffTime]); $deletedRecords += $db->getAffectedRows(); return [ 'deleted_records' => $deletedRecords, 'retention_days' => $retentionDays ]; } catch (Exception $e) { $this->logError('Analytics cleanup failed', [ 'error' => $e->getMessage() ]); return [ 'error' => $e->getMessage(), 'deleted_records' => 0 ]; } } /** * Cleanup orphaned files * @param array $data Configuration data * @return array Cleanup result */ private function cleanupOrphanedFiles($data) { $mediaDir = _FPATH . 'f_data/media/'; $deletedFiles = 0; $deletedSize = 0; try { if (!is_dir($mediaDir)) { return [ 'deleted_files' => 0, 'deleted_size' => 0, 'message' => 'Media directory not found' ]; } // Get all file keys from database $db = $this->getDatabase(); $query = "SELECT file_key FROM db_videofiles UNION SELECT file_key FROM db_imagefiles UNION SELECT file_key FROM db_audiofiles UNION SELECT file_key FROM db_documentfiles"; $result = $db->doQuery($query); $validKeys = []; while ($row = $db->doFetch($result)) { $validKeys[] = $row['file_key']; } // Scan media directory for orphaned files $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($mediaDir, RecursiveDirectoryIterator::SKIP_DOTS) ); foreach ($iterator as $file) { if ($file->isFile()) { $filename = $file->getFilename(); // Extract file key from filename (assuming format: filekey.extension) $fileKey = pathinfo($filename, PATHINFO_FILENAME); if (!in_array($fileKey, $validKeys)) { $size = $file->getSize(); if (unlink($file->getPathname())) { $deletedFiles++; $deletedSize += $size; } } } } return [ 'deleted_files' => $deletedFiles, 'deleted_size' => $deletedSize, 'scanned_keys' => count($validKeys) ]; } catch (Exception $e) { $this->logError('Orphaned files cleanup failed', [ 'error' => $e->getMessage() ]); return [ 'error' => $e->getMessage(), 'deleted_files' => 0, 'deleted_size' => 0 ]; } } /** * Optimize database * @param array $data Configuration data * @return array Optimization result */ private function optimizeDatabase($data) { try { $db = $this->getDatabase(); $optimizedTables = 0; // Get all tables $query = "SHOW TABLES"; $result = $db->doQuery($query); while ($row = $db->doFetch($result)) { $table = array_values($row)[0]; // Optimize table $optimizeQuery = "OPTIMIZE TABLE `{$table}`"; $db->doQuery($optimizeQuery); $optimizedTables++; } return [ 'optimized_tables' => $optimizedTables, 'message' => 'Database optimization completed' ]; } catch (Exception $e) { $this->logError('Database optimization failed', [ 'error' => $e->getMessage() ]); return [ 'error' => $e->getMessage(), 'optimized_tables' => 0 ]; } } }