Sindbad~EG File Manager

Current Path : /var/www/html/ch.sumar.com.py/wp-content/plugins/migrator-plugin-0.1.0/
Upload File :
Current File : /var/www/html/ch.sumar.com.py/wp-content/plugins/migrator-plugin-0.1.0/DATABASE_EXPORT_FIX.md

# Database Export Temp File Fix

## Problem Identified
The database export was creating **multiple separate temp files** instead of accumulating all table data into one file during chunked processing.

### Root Cause
Each database export chunk was creating a new temp file due to overly aggressive collision detection:

1. **Chunk 1**: Creates `db_export_temp_xyz.sql` with tables 1-5
2. **Chunk 2**: Detects "conflict" → creates `db_export_temp_xyz_123_456.sql` with tables 6-10  
3. **Chunk 3**: Detects "conflict" → creates `db_export_temp_xyz_789_101.sql` with tables 11-15

**Result**: Only the LAST temp file (with final few tables) got compressed into the final `.sql.gz`. All previous temp files with other tables were abandoned.

### Evidence from Logs
```
[09:01:45] Using temp file: db_export_temp_db_4f55154f120fa9ab_17518787734515_2858043_20250707-085933.sql
[09:01:52] Temp file conflict detected, using unique name: db_export_temp_db_4f55154f120fa9ab_17518787734515_2858043_20250707-085933_2865947_17518789120705.sql
[09:01:59] Temp file conflict detected, using unique name: db_export_temp_db_4f55154f120fa9ab_17518787734515_2858043_20250707-085933_2867953_17518789190314.sql
```

System found 59 tables but final SQL only contained 4 tables (from the last temp file).

## Solution Applied

### 1. Fixed Temp File Path Consistency
**File**: `custom-migrator/includes/class-database-exporter.php`

**Change**: Modified `setup_output_file()` method to reuse existing temp file path during resume operations:

```php
// CRITICAL FIX: For resume operations, reuse the existing temp file path
// This prevents creating multiple temp files and losing data
if ($is_resume && !empty($this->state['temp_file_path'])) {
    $this->temp_file_path = $this->state['temp_file_path'];
    $this->filesystem->log("Resuming with existing temp file: " . basename($this->temp_file_path));
} else {
    // For fresh start, get new temp file path (deterministic naming)
    $this->temp_file_path = $this->get_temp_file_path($sql_file);
    $this->state['temp_file_path'] = $this->temp_file_path;
}
```

### 2. Enhanced Collision Detection Logic
**File**: `custom-migrator/includes/class-database-exporter.php`

**Change**: Made collision detection smarter to allow reusing temp files from the same export session:

```php
// ENHANCED SAFETY CHECK: Only add uniqueness if file exists and is from a different session
if (file_exists($temp_path)) {
    $file_age = time() - filemtime($temp_path);
    
    // If temp file exists and is very recent (less than 2 minutes), check if it's our session
    if ($file_age < 120) {
        // Check if this might be from the current export session by examining file size
        $file_size = filesize($temp_path);
        
        // If file is very small (less than 1KB), it's likely abandoned - safe to reuse
        // If file is substantial but old enough (over 5 minutes), also safe to reuse
        if ($file_size < 1024 || $file_age > 300) {
            $this->filesystem->log("Reusing temp file (size: " . $this->format_bytes($file_size) . ", age: " . round($file_age) . "s): " . basename($temp_path));
        } else {
            // Recent substantial file - might be from concurrent process, make unique
            // ... create unique temp file
        }
    } else {
        // Old temp file, safe to reuse after cleanup
        $this->filesystem->log("Reusing temp file after cleanup: " . basename($temp_path));
    }
}
```

### 3. State Persistence Between Chunks
**File**: `custom-migrator/includes/class-fallback-exporter.php`

**Change**: Added `temp_file_path` to the resume state passed between chunks:

```php
if (isset($params['tables_processed']) && $params['tables_processed'] > 0) {
    $resume_state = array(
        'tables_processed' => (int)$params['tables_processed'],
        'table_offset' => isset($params['table_offset']) ? (int)$params['table_offset'] : 0,
        'total_tables' => isset($params['total_tables']) ? (int)$params['total_tables'] : 0,
        'rows_exported' => isset($params['rows_exported']) ? (int)$params['rows_exported'] : 0,
        'bytes_written' => isset($params['bytes_written']) ? (int)$params['bytes_written'] : 0,
        'temp_file_path' => isset($params['temp_file_path']) ? $params['temp_file_path'] : null, // ADDED
    );
}
```

And ensured it gets passed back in the response:

```php
'params' => array_merge($params, array(
    'tables_processed' => $result['tables_processed'],
    'table_offset' => isset($result['state']['table_offset']) ? $result['state']['table_offset'] : 0,
    'total_tables' => $result['total_tables'],
    'rows_exported' => $result['rows_exported'],
    'bytes_written' => $result['bytes_written'],
    'temp_file_path' => isset($result['state']['temp_file_path']) ? $result['state']['temp_file_path'] : null // ADDED
))
```

## Benefits

1. **All Tables Included**: All 59 tables now get included in the final SQL export
2. **Production Safe**: Maintains safety against concurrent processes
3. **Backward Compatible**: Doesn't break existing functionality
4. **Memory Efficient**: Single temp file approach reduces disk usage
5. **Clear Logging**: Better visibility into temp file operations

## Testing

The fix ensures that when you see logs like:
```
Found 59 database tables to export
Database export completed: 59 tables, 30648 rows
```

Your final `.sql.gz` file will actually contain **all 59 tables** instead of just the last few tables from the final chunk.

## Production Impact

This fix resolves the critical data loss issue where only a subset of database tables were being included in exports, ensuring complete and reliable WordPress site migrations. 

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists