193 lines
6.3 KiB
PHP
193 lines
6.3 KiB
PHP
<?php
|
|
/**
|
|
* Populate S3 Metadata - заполняет S3 метаданные для записей из migration_results_*.json
|
|
*
|
|
* Этот скрипт:
|
|
* 1. Читает все migration_results_*.json файлы
|
|
* 2. Находит записи в vtiger_notes без S3 метаданных
|
|
* 3. Заполняет s3_key, s3_bucket, s3_etag из результатов миграции
|
|
* 4. Опционально переключает на External тип
|
|
*/
|
|
|
|
ini_set('memory_limit', '512M');
|
|
set_time_limit(0);
|
|
date_default_timezone_set('Europe/Moscow');
|
|
|
|
$ROOT = '/var/www/fastuser/data/www/crm.clientright.ru/';
|
|
|
|
// Dependencies
|
|
require_once $ROOT . 'config.inc.php';
|
|
|
|
// CLI options
|
|
$opts = getopt('', [
|
|
'limit::',
|
|
'offset::',
|
|
'dry-run::',
|
|
'switch-to-external::'
|
|
]);
|
|
|
|
$limit = isset($opts['limit']) ? (int)$opts['limit'] : 500;
|
|
$offset = isset($opts['offset']) ? (int)$opts['offset'] : 0;
|
|
$dryRun = isset($opts['dry-run']) ? (int)$opts['dry-run'] !== 0 : true;
|
|
$switchToExternal = isset($opts['switch-to-external']) ? (int)$opts['switch-to-external'] !== 0 : false;
|
|
|
|
// Database connection
|
|
$mysqli = new mysqli($dbconfig['db_server'], $dbconfig['db_username'], $dbconfig['db_password'], $dbconfig['db_name']);
|
|
if ($mysqli->connect_error) {
|
|
die("Connection failed: " . $mysqli->connect_error);
|
|
}
|
|
$mysqli->set_charset("utf8");
|
|
|
|
// Logging
|
|
$logDir = $ROOT . 'logs';
|
|
if (!is_dir($logDir)) mkdir($logDir, 0755, true);
|
|
$logFile = $logDir . '/populate_s3_metadata.log';
|
|
|
|
function logln($msg) {
|
|
global $logFile;
|
|
$line = '[' . date('Y-m-d H:i:s') . '] ' . $msg . PHP_EOL;
|
|
file_put_contents($logFile, $line, FILE_APPEND | LOCK_EX);
|
|
echo $line;
|
|
}
|
|
|
|
// Load migration results
|
|
function loadMigrationResults() {
|
|
global $ROOT;
|
|
$resultsDir = $ROOT . 'crm_extensions/file_storage/';
|
|
$files = glob($resultsDir . 'migration_results_*.json');
|
|
|
|
$s3Data = [];
|
|
foreach ($files as $file) {
|
|
$data = json_decode(file_get_contents($file), true);
|
|
if (isset($data['copied'])) {
|
|
foreach ($data['copied'] as $item) {
|
|
if (isset($item['notesid'])) {
|
|
$s3Data[$item['notesid']] = [
|
|
'key' => $item['key'] ?? null,
|
|
'bucket' => $item['bucket'] ?? null,
|
|
'etag' => $item['etag'] ?? null,
|
|
'url' => $item['url'] ?? null,
|
|
'size' => $item['size'] ?? null,
|
|
'mimeType' => $item['mimeType'] ?? null
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
logln("Loaded S3 metadata for " . count($s3Data) . " files from migration results");
|
|
return $s3Data;
|
|
}
|
|
|
|
logln("Starting S3 metadata population");
|
|
logln("Parameters: limit=$limit, offset=$offset, dry-run=" . ($dryRun ? 'true' : 'false') . ", switch-to-external=" . ($switchToExternal ? 'true' : 'false'));
|
|
|
|
// Load S3 data
|
|
$s3Data = loadMigrationResults();
|
|
|
|
// Find records that need S3 metadata
|
|
$query = "SELECT notesid, filename, filelocationtype
|
|
FROM vtiger_notes
|
|
WHERE (s3_key IS NULL OR s3_key = '')
|
|
AND filelocationtype = 'I'
|
|
LIMIT $limit OFFSET $offset";
|
|
|
|
$result = $mysqli->query($query);
|
|
if (!$result) {
|
|
die("Query failed: " . $mysqli->error);
|
|
}
|
|
|
|
$records = [];
|
|
while ($row = $result->fetch_assoc()) {
|
|
$records[] = $row;
|
|
}
|
|
|
|
logln("Found " . count($records) . " records without S3 metadata (offset=$offset, limit=$limit)");
|
|
|
|
if (empty($records)) {
|
|
logln("No records to update.");
|
|
exit(0);
|
|
}
|
|
|
|
$updated = 0;
|
|
$skipped = 0;
|
|
$errors = 0;
|
|
|
|
foreach ($records as $record) {
|
|
$notesid = $record['notesid'];
|
|
$currentFilename = $record['filename'];
|
|
$currentType = $record['filelocationtype'];
|
|
|
|
// Check if we have S3 data for this record
|
|
if (!isset($s3Data[$notesid])) {
|
|
logln("SKIP notesid=$notesid - no S3 data found in migration results");
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
$s3Info = $s3Data[$notesid];
|
|
$s3Key = $s3Info['key'];
|
|
$s3Bucket = $s3Info['bucket'];
|
|
$s3Etag = $s3Info['etag'];
|
|
$s3Url = $s3Info['url'];
|
|
|
|
if (!$s3Key || !$s3Bucket) {
|
|
logln("SKIP notesid=$notesid - incomplete S3 data");
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
logln("Processing notesid=$notesid");
|
|
|
|
if (!$dryRun) {
|
|
// Create backup
|
|
$backupDir = $ROOT . 'crm_extensions/file_storage/backups/';
|
|
if (!is_dir($backupDir)) mkdir($backupDir, 0755, true);
|
|
|
|
$backupFile = $backupDir . 'populate_s3_backup_' . $notesid . '_' . date('Ymd_His') . '.json';
|
|
$backup = [
|
|
'notesid' => $notesid,
|
|
'original_filename' => $currentFilename,
|
|
'original_filelocationtype' => $currentType,
|
|
'timestamp' => date('c')
|
|
];
|
|
file_put_contents($backupFile, json_encode($backup, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
|
|
// Update database
|
|
if ($switchToExternal) {
|
|
$updateQuery = "UPDATE vtiger_notes
|
|
SET s3_key = ?, s3_bucket = ?, s3_etag = ?, filename = ?, filelocationtype = 'E'
|
|
WHERE notesid = ?";
|
|
$stmt = $mysqli->prepare($updateQuery);
|
|
$stmt->bind_param('ssssi', $s3Key, $s3Bucket, $s3Etag, $s3Url, $notesid);
|
|
} else {
|
|
$updateQuery = "UPDATE vtiger_notes
|
|
SET s3_key = ?, s3_bucket = ?, s3_etag = ?
|
|
WHERE notesid = ?";
|
|
$stmt = $mysqli->prepare($updateQuery);
|
|
$stmt->bind_param('sssi', $s3Key, $s3Bucket, $s3Etag, $notesid);
|
|
}
|
|
|
|
if ($stmt->execute()) {
|
|
logln("UPDATED notesid=$notesid -> S3 metadata populated" . ($switchToExternal ? " + External" : ""));
|
|
$updated++;
|
|
} else {
|
|
logln("ERROR updating notesid=$notesid: " . $stmt->error);
|
|
$errors++;
|
|
}
|
|
$stmt->close();
|
|
} else {
|
|
logln("DRY-RUN: Would populate S3 metadata for notesid=$notesid" . ($switchToExternal ? " + switch to External" : ""));
|
|
$updated++;
|
|
}
|
|
}
|
|
|
|
logln("S3 metadata population completed:");
|
|
logln("- Updated: $updated");
|
|
logln("- Skipped: $skipped");
|
|
logln("- Errors: $errors");
|
|
logln("- Mode: " . ($dryRun ? "DRY-RUN" : "LIVE"));
|
|
|
|
$mysqli->close();
|
|
?>
|