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

179 lines
5.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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();
?>