# Исправление сохранения файлов в 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=", ``` **Изменение:** Добавлен параметр `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 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= ``` ### 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, отредактировать и сохранить!** 🚀