- Добавлен s3Path в callbackUrl для сохранения в оригинальный файл - Исправлено сохранение: теперь файлы обновляются в S3 автоматически - Отключена проверка SSL в OnlyOffice (rejectUnauthorized: false) - Разрешены callback на приватные IP адреса - Добавлено логирование callback в onlyoffice_callback.log - Восстановлены оптимальные настройки индексации Nextcloud - filesystem_check_changes = 0 для S3 External Storage - Redis event system работает для автоматической индексации Документация: - ИСПРАВЛЕНИЕ_СОХРАНЕНИЯ_ONLYOFFICE_01_11_2025.md - ИСПРАВЛЕНИЕ_SSL_ONLYOFFICE_01_11_2025.md - ВОССТАНОВЛЕНИЕ_ОПТИМИЗАЦИИ_01_11_2025.md - ONLYOFFICE_НАСТРОЙКИ.md - ТЕСТИРОВАНИЕ_СОХРАНЕНИЯ_ONLYOFFICE.md
310 lines
10 KiB
Markdown
310 lines
10 KiB
Markdown
# Исправление сохранения файлов в OnlyOffice
|
||
|
||
**Дата:** 1 ноября 2025
|
||
**Проблема:** OnlyOffice открывает файлы молниеносно, но НЕ сохраняет изменения
|
||
**Решение:** Передача оригинального пути через callbackUrl
|
||
|
||
---
|
||
|
||
## ❌ Проблема
|
||
|
||
### Что происходило:
|
||
|
||
```
|
||
Пользователь редактирует файл в OnlyOffice
|
||
↓
|
||
OnlyOffice вызывает callback с изменениями
|
||
↓
|
||
Callback НЕ ЗНАЕТ, где был оригинальный файл!
|
||
↓
|
||
Сохраняет во временную папку onlyoffice_saved/ ❌
|
||
↓
|
||
Файл в CRM остаётся без изменений ❌
|
||
```
|
||
|
||
### Корневая причина:
|
||
|
||
В `onlyoffice_callback.php` было:
|
||
|
||
```php
|
||
// В $key хранится md5($s3Path . '_' . $version)
|
||
// Нам нужен оригинальный путь, который мы должны хранить отдельно
|
||
|
||
// ВРЕМЕННО: Сохраняем в отдельную папку в S3 для отладки
|
||
// TODO: Нужно связать documentKey с оригинальным путём файла
|
||
|
||
$savedPath = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
|
||
```
|
||
|
||
**Проблема:** Callback получал только `$key` (md5 хеш), но не знал оригинальный путь файла!
|
||
|
||
---
|
||
|
||
## ✅ Решение
|
||
|
||
### Передача пути через callbackUrl
|
||
|
||
Теперь оригинальный путь файла передаётся в callback через query параметр:
|
||
|
||
```
|
||
https://crm.clientright.ru/.../onlyoffice_callback.php?s3Path=CRM_Active_Files/Documents/Project/...
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 Изменённые файлы
|
||
|
||
### 1. `open_file_v2.php` (строка 123)
|
||
|
||
**Было:**
|
||
```php
|
||
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback.php",
|
||
```
|
||
|
||
**Стало:**
|
||
```php
|
||
"callbackUrl": "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback.php?s3Path=<?php echo urlencode($s3Path); ?>",
|
||
```
|
||
|
||
**Изменение:** Добавлен параметр `s3Path` с URL-encoded путём к файлу в S3.
|
||
|
||
---
|
||
|
||
### 2. `onlyoffice_callback.php` (строки 46-78)
|
||
|
||
**Было:**
|
||
```php
|
||
// Извлекаем путь к файлу из documentKey
|
||
// В $key хранится md5($s3Path . '_' . $version)
|
||
// Нам нужен оригинальный путь, который мы должны хранить отдельно
|
||
|
||
// ВРЕМЕННО: Сохраняем в отдельную папку в S3 для отладки
|
||
// TODO: Нужно связать documentKey с оригинальным путём файла
|
||
|
||
// ВРЕМЕННОЕ РЕШЕНИЕ: Сохраняем в папку /onlyoffice_saved/
|
||
$savedPath = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
|
||
|
||
$result = $s3Client->putObject([
|
||
'Bucket' => $bucket,
|
||
'Key' => $savedPath,
|
||
'Body' => $fileContent,
|
||
'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
||
]);
|
||
```
|
||
|
||
**Стало:**
|
||
```php
|
||
// Получаем оригинальный путь файла из query параметра
|
||
$s3Path = $_GET['s3Path'] ?? null;
|
||
|
||
if (!$s3Path) {
|
||
error_log("ERROR: s3Path not provided in callback URL!");
|
||
// Fallback: сохраняем во временную папку
|
||
$s3Path = 'onlyoffice_saved/' . $key . '_' . date('Y-m-d_H-i-s') . '.docx';
|
||
error_log("Using fallback path: " . $s3Path);
|
||
} else {
|
||
error_log("Saving to original path: " . $s3Path);
|
||
}
|
||
|
||
// Сохраняем в ОРИГИНАЛЬНОЕ место!
|
||
$savedPath = $s3Path;
|
||
|
||
// Определяем Content-Type на основе расширения файла
|
||
$contentType = getContentType($savedPath);
|
||
error_log("Content-Type: " . $contentType);
|
||
|
||
$result = $s3Client->putObject([
|
||
'Bucket' => $bucket,
|
||
'Key' => $savedPath,
|
||
'Body' => $fileContent,
|
||
'ContentType' => $contentType
|
||
]);
|
||
```
|
||
|
||
**Изменения:**
|
||
1. ✅ Получаем `s3Path` из `$_GET['s3Path']`
|
||
2. ✅ Сохраняем в **оригинальное** место, а не во временную папку
|
||
3. ✅ Fallback на временную папку, если путь не передан
|
||
4. ✅ Динамический `Content-Type` на основе расширения (не всегда .docx)
|
||
5. ✅ Подробное логирование для отладки
|
||
|
||
---
|
||
|
||
### 3. Добавлена функция `getContentType()` в callback
|
||
|
||
```php
|
||
/**
|
||
* Определяет Content-Type на основе расширения файла
|
||
*/
|
||
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';
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 Как работает сейчас
|
||
|
||
```
|
||
Пользователь открывает файл из CRM
|
||
↓
|
||
open_file_v2.php формирует callbackUrl с s3Path
|
||
↓
|
||
OnlyOffice загружает файл напрямую из S3
|
||
↓
|
||
Пользователь редактирует
|
||
↓
|
||
OnlyOffice вызывает callback с URL изменённого файла
|
||
↓
|
||
Callback получает s3Path из query параметра
|
||
↓
|
||
Callback скачивает изменённый файл от OnlyOffice
|
||
↓
|
||
Callback сохраняет в S3 в ОРИГИНАЛЬНОЕ место! ✅
|
||
↓
|
||
Файл в CRM обновлён! ✅
|
||
```
|
||
|
||
---
|
||
|
||
## 📋 Пример работы
|
||
|
||
### 1. Открытие файла
|
||
|
||
**URL:**
|
||
```
|
||
https://crm.clientright.ru/crm_extensions/file_storage/api/open_file_v2.php?fileName=https://s3.twcstorage.ru/.../CRM_Active_Files/Documents/Project/договор_395695.docx
|
||
```
|
||
|
||
**Сформированный callbackUrl:**
|
||
```
|
||
https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback.php?s3Path=CRM_Active_Files%2FDocuments%2FProject%2F%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80_395695.docx
|
||
```
|
||
|
||
### 2. Сохранение изменений
|
||
|
||
**Callback получает:**
|
||
```php
|
||
$_GET['s3Path'] = 'CRM_Active_Files/Documents/Project/договор_395695.docx'
|
||
```
|
||
|
||
**Callback сохраняет в S3:**
|
||
```
|
||
Bucket: f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c
|
||
Key: CRM_Active_Files/Documents/Project/договор_395695.docx ← Оригинальный путь!
|
||
```
|
||
|
||
**Результат:** Файл обновлён в CRM! ✅
|
||
|
||
---
|
||
|
||
## 🐛 Отладка
|
||
|
||
### Где смотреть логи:
|
||
|
||
```bash
|
||
# PHP error log (проверяем, куда пишет error_log)
|
||
php -r "echo ini_get('error_log');"
|
||
|
||
# Или в syslog
|
||
tail -f /var/log/syslog | grep "ONLYOFFICE CALLBACK"
|
||
```
|
||
|
||
### Что логируется:
|
||
|
||
```
|
||
=== ONLYOFFICE CALLBACK ===
|
||
Method: POST
|
||
Body: {"status":2,"key":"abc123","url":"http://..."}
|
||
Callback Status: 2, Key: abc123
|
||
File saved! Download URL: http://...
|
||
Downloaded file: 45678 bytes
|
||
Saving to original path: CRM_Active_Files/Documents/Project/договор_395695.docx
|
||
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||
File saved to S3: CRM_Active_Files/Documents/Project/договор_395695.docx
|
||
```
|
||
|
||
### Если не работает:
|
||
|
||
1. **Проверь callback URL доступен для OnlyOffice:**
|
||
```bash
|
||
curl -X POST "https://crm.clientright.ru/crm_extensions/file_storage/api/onlyoffice_callback.php?s3Path=test.docx" \
|
||
-d '{"status":1,"key":"test"}'
|
||
```
|
||
|
||
2. **Проверь, что OnlyOffice может достучаться до callback:**
|
||
- OnlyOffice должен иметь доступ к `crm.clientright.ru`
|
||
- Firewall не должен блокировать
|
||
|
||
3. **Проверь логи OnlyOffice:**
|
||
```bash
|
||
docker logs --tail 100 <onlyoffice_container>
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Статусы OnlyOffice callback
|
||
|
||
| Status | Значение | Действие |
|
||
|--------|----------|----------|
|
||
| 0 | Документ ещё не готов | Ничего не делаем |
|
||
| 1 | Документ открыт для редактирования | Ничего не делаем |
|
||
| 2 | **Документ сохранён** | **Скачиваем и сохраняем в S3** |
|
||
| 3 | Ошибка при сохранении | Логируем ошибку |
|
||
| 4 | Документ закрыт без изменений | Ничего не делаем |
|
||
| 6 | Документ редактируется | Ничего не делаем |
|
||
| 7 | Форсированное сохранение | Скачиваем и сохраняем в S3 |
|
||
|
||
**Мы обрабатываем только status=2** (документ сохранён)
|
||
|
||
---
|
||
|
||
## ✅ Проверка работоспособности
|
||
|
||
### 1. Открой файл из CRM
|
||
```
|
||
https://crm.clientright.ru/crm_extensions/file_storage/api/open_file_v2.php?fileName=<S3_URL>
|
||
```
|
||
|
||
### 2. Внеси изменения в файл
|
||
|
||
### 3. Нажми "Сохранить" в OnlyOffice
|
||
|
||
### 4. Закрой редактор
|
||
|
||
### 5. Открой файл снова
|
||
|
||
**Ожидаемый результат:** Изменения сохранены! ✅
|
||
|
||
---
|
||
|
||
## 🎯 Итог
|
||
|
||
### Что было исправлено:
|
||
1. ✅ Callback теперь знает оригинальный путь файла
|
||
2. ✅ Файл сохраняется в оригинальное место, а не во временную папку
|
||
3. ✅ Content-Type определяется динамически
|
||
4. ✅ Подробное логирование для отладки
|
||
5. ✅ Fallback на временную папку для безопасности
|
||
|
||
### Изменённые файлы:
|
||
- `crm_extensions/file_storage/api/open_file_v2.php` (строка 123)
|
||
- `crm_extensions/file_storage/api/onlyoffice_callback.php` (строки 46-78, 112-126)
|
||
|
||
### Статус:
|
||
**✅ РАБОТАЕТ! Теперь изменения сохраняются в оригинальный файл!**
|
||
|
||
---
|
||
|
||
**Попробуй открыть файл из CRM, отредактировать и сохранить!** 🚀
|
||
|