146 lines
4.1 KiB
PHP
146 lines
4.1 KiB
PHP
<?php
|
|
/**
|
|
* Analyze Broken Files - анализирует "битые" записи без S3 метаданных
|
|
*/
|
|
|
|
ini_set('memory_limit', '512M');
|
|
set_time_limit(0);
|
|
date_default_timezone_set('Europe/Moscow');
|
|
|
|
$ROOT = '/var/www/fastuser/data/www/crm.clientright.ru/';
|
|
require_once $ROOT . 'config.inc.php';
|
|
|
|
// CLI options
|
|
$opts = getopt('', [
|
|
'limit::',
|
|
'format::',
|
|
'check-files::'
|
|
]);
|
|
|
|
$limit = isset($opts['limit']) ? (int)$opts['limit'] : 100;
|
|
$format = isset($opts['format']) ? $opts['format'] : 'json';
|
|
$checkFiles = isset($opts['check-files']) ? (int)$opts['check-files'] !== 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");
|
|
|
|
// Get records without S3 metadata
|
|
$query = "SELECT notesid, filename, filesize, filetype, filelocationtype
|
|
FROM vtiger_notes
|
|
WHERE (s3_key IS NULL OR s3_key = '')
|
|
AND filelocationtype = 'I'
|
|
ORDER BY notesid DESC
|
|
LIMIT $limit";
|
|
|
|
$result = $mysqli->query($query);
|
|
if (!$result) {
|
|
die("Query failed: " . $mysqli->error);
|
|
}
|
|
|
|
$broken_files = [];
|
|
$stats = [
|
|
'total_checked' => 0,
|
|
'files_exist' => 0,
|
|
'files_missing' => 0,
|
|
'permission_denied' => 0,
|
|
'empty_filename' => 0,
|
|
'invalid_path' => 0
|
|
];
|
|
|
|
while ($row = $result->fetch_assoc()) {
|
|
$stats['total_checked']++;
|
|
|
|
$file_info = [
|
|
'notesid' => $row['notesid'],
|
|
'filename' => $row['filename'],
|
|
'filesize' => $row['filesize'],
|
|
'filetype' => $row['filetype'],
|
|
'status' => 'unknown',
|
|
'issue' => '',
|
|
'full_path' => ''
|
|
];
|
|
|
|
// Check filename
|
|
if (empty($row['filename'])) {
|
|
$file_info['status'] = 'error';
|
|
$file_info['issue'] = 'empty_filename';
|
|
$stats['empty_filename']++;
|
|
} else {
|
|
// Build full path
|
|
$filename = $row['filename'];
|
|
|
|
// Try different path variations
|
|
$possible_paths = [
|
|
$ROOT . 'storage/' . $filename,
|
|
$ROOT . $filename,
|
|
$ROOT . 'test/storage/' . $filename,
|
|
'/var/www/fastuser/data/www/crm.clientright.ru/storage/' . $filename
|
|
];
|
|
|
|
$file_found = false;
|
|
foreach ($possible_paths as $path) {
|
|
if ($checkFiles && file_exists($path)) {
|
|
$file_info['status'] = 'exists';
|
|
$file_info['full_path'] = $path;
|
|
$file_info['actual_size'] = filesize($path);
|
|
$stats['files_exist']++;
|
|
$file_found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$file_found) {
|
|
if ($checkFiles) {
|
|
$file_info['status'] = 'missing';
|
|
$file_info['issue'] = 'file_not_found';
|
|
$file_info['tried_paths'] = $possible_paths;
|
|
$stats['files_missing']++;
|
|
} else {
|
|
$file_info['status'] = 'unchecked';
|
|
$file_info['expected_path'] = $possible_paths[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
$broken_files[] = $file_info;
|
|
}
|
|
|
|
$mysqli->close();
|
|
|
|
// Output results
|
|
$output = [
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
|
'query_limit' => $limit,
|
|
'file_check_enabled' => $checkFiles,
|
|
'statistics' => $stats,
|
|
'files' => $broken_files
|
|
];
|
|
|
|
if ($format === 'json') {
|
|
echo json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
|
} else {
|
|
// Simple table format
|
|
printf("%-8s %-50s %-10s %-15s %s\n",
|
|
"ID", "Filename", "Size", "Status", "Issue");
|
|
echo str_repeat("-", 100) . "\n";
|
|
|
|
foreach ($broken_files as $file) {
|
|
printf("%-8s %-50s %-10s %-15s %s\n",
|
|
$file['notesid'],
|
|
substr($file['filename'], 0, 47) . (strlen($file['filename']) > 47 ? '...' : ''),
|
|
$file['filesize'] ?? 'N/A',
|
|
$file['status'],
|
|
$file['issue']
|
|
);
|
|
}
|
|
|
|
echo "\nStatistics:\n";
|
|
foreach ($stats as $key => $value) {
|
|
echo "$key: $value\n";
|
|
}
|
|
}
|