Files
crm.clientright.ru/crm_extensions/file_storage/batch_phase2_update.php

179 lines
5.8 KiB
PHP
Raw Normal View History

<?php
/**
* Batch Phase 2 Update - массовое обновление записей в vtiger_notes для переключения на S3
*
* Этот скрипт:
* 1. Находит все записи с s3_key, но еще не переключенные на External (filelocationtype != 'E')
* 2. Обновляет их пакетами, используя данные из migration_results_*.json
* 3. Создает резервные копии перед обновлением
*/
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::',
'activate-external::'
]);
$limit = isset($opts['limit']) ? (int)$opts['limit'] : 100;
$offset = isset($opts['offset']) ? (int)$opts['offset'] : 0;
$dryRun = isset($opts['dry-run']) ? (int)$opts['dry-run'] !== 0 : true;
$activateExternal = isset($opts['activate-external']) ? (int)$opts['activate-external'] !== 0 : true;
// 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 . '/phase2_batch_update.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 to get S3 URLs
function loadMigrationResults() {
global $ROOT;
$resultsDir = $ROOT . 'crm_extensions/file_storage/';
$files = glob($resultsDir . 'migration_results_*.json');
$urlMap = [];
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']) && isset($item['url'])) {
$urlMap[$item['notesid']] = $item['url'];
}
}
}
}
logln("Loaded " . count($urlMap) . " S3 URLs from migration results");
return $urlMap;
}
logln("Starting Phase 2 batch update");
logln("Parameters: limit=$limit, offset=$offset, dry-run=" . ($dryRun ? 'true' : 'false') . ", activate-external=" . ($activateExternal ? 'true' : 'false'));
// Load S3 URLs
$urlMap = loadMigrationResults();
// Find records that need updating
$query = "SELECT notesid, filename, s3_key, s3_bucket, filelocationtype
FROM vtiger_notes
WHERE s3_key IS NOT NULL
AND s3_key != ''
AND filelocationtype != 'E'
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 to update (offset=$offset, limit=$limit)");
if (empty($records)) {
logln("No records to update. Migration Phase 2 may be complete.");
exit(0);
}
$updated = 0;
$skipped = 0;
$errors = 0;
foreach ($records as $record) {
$notesid = $record['notesid'];
$currentFilename = $record['filename'];
$s3Key = $record['s3_key'];
$s3Bucket = $record['s3_bucket'];
$currentType = $record['filelocationtype'];
// Get S3 URL from migration results
$s3Url = isset($urlMap[$notesid]) ? $urlMap[$notesid] : null;
if (!$s3Url) {
// Construct URL from bucket and key
$s3Url = "https://s3.twcstorage.ru/$s3Bucket/" . urlencode($s3Key);
logln("CONSTRUCTED URL for notesid=$notesid: $s3Url");
}
logln("Processing notesid=$notesid, current_type=$currentType");
if (!$dryRun) {
// Create backup
$backupDir = $ROOT . 'crm_extensions/file_storage/backups/';
if (!is_dir($backupDir)) mkdir($backupDir, 0755, true);
$backupFile = $backupDir . 'phase2_batch_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 ($activateExternal) {
$updateQuery = "UPDATE vtiger_notes
SET filename = ?, filelocationtype = 'E'
WHERE notesid = ?";
$stmt = $mysqli->prepare($updateQuery);
$stmt->bind_param('si', $s3Url, $notesid);
} else {
// Just update filename, keep filelocationtype as is
$updateQuery = "UPDATE vtiger_notes
SET filename = ?
WHERE notesid = ?";
$stmt = $mysqli->prepare($updateQuery);
$stmt->bind_param('si', $s3Url, $notesid);
}
if ($stmt->execute()) {
logln("UPDATED notesid=$notesid -> External URL: $s3Url");
$updated++;
} else {
logln("ERROR updating notesid=$notesid: " . $stmt->error);
$errors++;
}
$stmt->close();
} else {
logln("DRY-RUN: Would update notesid=$notesid -> $s3Url" . ($activateExternal ? " (External)" : ""));
$updated++;
}
}
logln("Phase 2 batch update completed:");
logln("- Updated: $updated");
logln("- Skipped: $skipped");
logln("- Errors: $errors");
logln("- Mode: " . ($dryRun ? "DRY-RUN" : "LIVE"));
$mysqli->close();
?>