Files
crm.clientright.ru/crm_extensions/file_storage/api/open_file_v2.php
Fedor 269c7ea216 feat: OnlyOffice Standalone integration with S3 direct URLs
 ЧТО СДЕЛАНО:
- Поднят новый standalone OnlyOffice Document Server (порт 8083)
- Настроен Nginx для доступа через office.clientright.ru:9443
- Создан open_file_v3_standalone.php для работы с новым OnlyOffice
- Реализована поддержка прямых S3 URL (bucket публичный)
- Добавлен s3_proxy.php с поддержкой Range requests
- Создан onlyoffice_callback.php для сохранения (базовая версия)
- Файлы успешно открываются и загружаются!

⚠️ TODO (на завтра):
- Доработать onlyoffice_callback.php для сохранения обратно в ОРИГИНАЛЬНЫЙ путь в S3
- Добавить Redis маппинг documentKey → S3 path
- Обновить CRM JS для использования open_file_v3_standalone.php
- Протестировать сохранение файлов
- Удалить тестовые файлы

📊 РЕЗУЛЬТАТ:
- OnlyOffice Standalone РАБОТАЕТ! 
- Файлы открываются напрямую из S3 
- Редактор загружается БЫСТРО 
- Автосохранение настроено  (но нужна доработка callback)
2025-11-01 01:02:03 +03:00

238 lines
8.9 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
/**
* ФИНАЛ: OnlyOffice + Pre-signed S3 URL
* Теперь с CORS и правильными настройками!
*/
require_once '/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/shared/EnvLoader.php';
EnvLoader::load('/var/www/fastuser/data/www/crm.clientright.ru/crm_extensions/.env');
error_reporting(E_ALL);
ini_set('display_errors', 1);
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
if (empty($fileName)) {
die("❌ fileName не указан");
}
// Извлекаем S3 путь
$s3Path = '';
if (strpos($fileName, 'http') === 0) {
$fileName = urldecode($fileName);
$bucketId = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$pos = strpos($fileName, $bucketId . '/');
if ($pos !== false) {
$s3Path = substr($fileName, $pos + strlen($bucketId) + 1);
}
}
if (empty($s3Path)) {
die("Не удалось извлечь путь из URL");
}
// Извлекаем расширение файла
$ext = strtolower(pathinfo($s3Path, PATHINFO_EXTENSION));
// ПРЯМОЙ S3 URL (bucket публичный, CORS настроен!)
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
$s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path;
// Генерируем версию и ключ документа
$version = time();
// СЛУЧАЙНЫЙ ключ при каждом запросе, чтобы OnlyOffice не использовал кеш!
$documentKey = md5($s3Path . '_' . $version);
// ПРЯМОЙ S3 URL (bucket публичный, поэтому pre-signed URL не нужен!)
// Bucket поддерживает Range requests и CORS из коробки
$fileUrl = $s3Url;
// ОТЛАДКА: Логируем все параметры
error_log("=== OPEN FILE DEBUG ===");
error_log("S3 Path: " . $s3Path);
error_log("File URL: " . $fileUrl);
error_log("File extension: " . $ext);
error_log("Document Key (unique): " . $documentKey);
error_log("Version: " . $version);
$fileBasename = basename($s3Path);
$fileType = getFileType($ext);
$officeFormats = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
if (!in_array($ext, $officeFormats)) {
header('Location: ' . $s3Url);
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title><?php echo htmlspecialchars($fileBasename); ?></title>
<script src="https://office.clientright.ru:9443/web-apps/apps/api/documents/api.js?v=<?php echo time(); ?>"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
padding: 0;
}
#editor {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="editor"></div>
<script>
// Отладка в консоль
console.log('📁 Файл:', <?php echo json_encode($fileBasename); ?>);
console.log('🔗 S3 URL:', <?php echo json_encode($fileUrl); ?>);
console.log('🔑 Document Key (unique):', <?php echo json_encode($documentKey); ?>);
console.log('✅ Standalone OnlyOffice (9443) + Direct S3 URL!');
new DocsAPI.DocEditor("editor", {
"documentType": "<?php echo $fileType; ?>",
"document": {
"fileType": "<?php echo $ext; ?>",
"key": "<?php echo $documentKey; ?>",
"title": <?php echo json_encode($fileBasename); ?>,
"url": <?php echo json_encode($fileUrl); ?>,
"permissions": {
"comment": true,
"download": true,
"edit": true,
"print": true,
"review": true
}
},
"editorConfig": {
"mode": "edit",
"lang": "ru",
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback.php",
"user": {
"id": "user_<?php echo $recordId ?? 'guest'; ?>",
"name": "CRM User"
},
"customization": {
"autosave": true,
"chat": false,
"comments": true,
"compactHeader": false,
"compactToolbar": false,
"help": true,
"hideRightMenu": false,
"logo": {
"image": "https://crm.clientright.ru/layouts/v7/skins/images/logo.png",
"imageEmbedded": "https://crm.clientright.ru/layouts/v7/skins/images/logo.png"
},
"zoom": 100
}
},
"height": "100%",
"width": "100%",
"type": "desktop",
"events": {
"onReady": function() {
console.log('✅ Editor ready!');
},
"onDocumentReady": function() {
console.log('✅ Document loaded!');
},
"onError": function(event) {
console.error('❌ OnlyOffice Error FULL:', JSON.stringify(event, null, 2));
console.error('Event data:', event.data);
console.error('Error code:', event.data.errorCode);
console.error('Error description:', event.data.errorDescription);
// Тестируем доступность URL из браузера
console.log('🧪 Testing S3 URL from browser...');
fetch(<?php echo json_encode($fileUrl); ?>, { method: 'HEAD' })
.then(response => {
console.log('✅ Browser can access S3:', response.status);
})
.catch(error => {
console.error('❌ Browser CANNOT access S3:', error);
});
alert('Ошибка загрузки документа:\n\n' +
'Code: ' + event.data.errorCode + '\n' +
'Description: ' + event.data.errorDescription + '\n\n' +
'Используется Pre-signed URL из S3\n\n' +
'Смотри консоль браузера (F12) для деталей!');
},
"onWarning": function(event) {
console.warn('⚠️ OnlyOffice Warning:', event);
}
}
});
</script>
</body>
</html>
<?php
function getFileType($ext) {
if (in_array($ext, ['doc', 'docx'])) return 'word';
if (in_array($ext, ['xls', 'xlsx'])) return 'cell';
if (in_array($ext, ['ppt', 'pptx'])) return 'slide';
return 'word';
}
function generatePresignedUrl($s3Key, $expirationSeconds) {
try {
require_once '/var/www/fastuser/data/www/crm.clientright.ru/vendor/autoload.php';
$s3Client = new Aws\S3\S3Client([
'version' => 'latest',
'region' => 'ru-1',
'endpoint' => 'https://s3.twcstorage.ru',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => EnvLoader::getRequired('S3_ACCESS_KEY'),
'secret' => EnvLoader::getRequired('S3_SECRET_KEY')
],
'suppress_php_deprecation_warning' => true
]);
$bucket = 'f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c';
// КЛЮЧ: Минимальные параметры = правильная подпись!
$cmd = $s3Client->getCommand('GetObject', [
'Bucket' => $bucket,
'Key' => $s3Key
]);
$request = $s3Client->createPresignedRequest($cmd, "+{$expirationSeconds} seconds");
return (string)$request->getUri();
} catch (Exception $e) {
error_log("Pre-signed URL error: " . $e->getMessage());
return null;
}
}
function getContentType($filename) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$types = [
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls' => 'application/vnd.ms-excel',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'ppt' => 'application/vnd.ms-powerpoint',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
];
return $types[$ext] ?? 'application/octet-stream';
}
?>