'Project', 'Contacts' => 'Contacts', 'Accounts' => 'Accounts', 'Invoice' => 'Invoice', 'Quotes' => 'Quotes', 'SalesOrder' => 'SalesOrder', 'PurchaseOrder' => 'PurchaseOrder', 'HelpDesk' => 'HelpDesk', 'Leads' => 'Leads', 'Potentials' => 'Potentials' ]; $moduleFolder = $moduleFolders[$module] ?? 'Other'; // Формируем имя папки записи $recordName = preg_replace('/[\/\\\\:\*\?"<>\|]/', '_', $recordName); // Убираем недопустимые символы $folderName = $recordName . '_' . $recordId; // Формируем путь к файлу в Nextcloud $ncPath = "/crm/crm2/CRM_Active_Files/Documents/{$moduleFolder}/{$folderName}/{$fileName}.{$fileType}"; $webdavUrl = $nextcloudUrl . '/remote.php/dav/files/' . $username . $ncPath; error_log("=== CREATE NEXTCLOUD FILE ==="); error_log("Module: " . $module); error_log("Record ID: " . $recordId); error_log("File name: " . $fileName); error_log("File type: " . $fileType); error_log("Nextcloud path: " . $ncPath); error_log("WebDAV URL: " . $webdavUrl); // СОЗДАЁМ ФАЙЛ ЧЕРЕЗ NEXTCLOUD OCS API (Direct Editing) // Используем встроенный API Nextcloud для создания нового файла $templateMap = [ 'docx' => 'onlyoffice', 'xlsx' => 'onlyoffice', 'pptx' => 'onlyoffice' ]; $editorId = $templateMap[$fileType] ?? 'onlyoffice'; // Используем OCS API v2 для создания нового файла $createUrl = $nextcloudUrl . '/ocs/v2.php/apps/files/api/v1/directEditing/create'; $postData = http_build_query([ 'path' => $ncPath, 'editorId' => $editorId, 'templateId' => '', 'templateType' => $fileType ]); error_log("Creating file via OCS API: " . $createUrl); error_log("Post data: " . $postData); // Вызываем API создания $ch = curl_init($createUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'OCS-APIRequest: true', 'Content-Type: application/x-www-form-urlencoded', 'Accept: application/json' ]); curl_setopt($ch, CURLOPT_USERPWD, "$username:$password"); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); error_log("OCS API response code: " . $httpCode); error_log("OCS API response: " . substr($response, 0, 500)); // Если API сработал - парсим ответ и получаем URL редактора if ($httpCode === 200) { $data = json_decode($response, true); if (isset($data['ocs']['data']['url'])) { $editorUrl = $data['ocs']['data']['url']; error_log("Got editor URL from API: " . $editorUrl); header('Location: ' . $nextcloudUrl . $editorUrl); exit; } } // Если API не сработал - создаём файл НАПРЯМУЮ В S3 и открываем через OnlyOffice! error_log("OCS API failed, creating file directly in S3"); // Извлекаем S3 путь из Nextcloud пути // /crm/crm2/CRM_Active_Files/... → crm2/CRM_Active_Files/... $s3Path = ltrim($ncPath, '/'); // S3 credentials $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'; // Создаём минимальный пустой файл $emptyContent = createEmptyFile($fileType); error_log("Creating file in S3: " . $s3Path . " (" . strlen($emptyContent) . " bytes)"); // Загружаем файл в S3 try { $result = $s3Client->putObject([ 'Bucket' => $bucket, 'Key' => $s3Path, 'Body' => $emptyContent, 'ContentType' => getContentType($fileType) ]); error_log("✅ File created in S3!"); } catch (Exception $e) { error_log("Failed to create file in S3: " . $e->getMessage()); die("❌ Не удалось создать файл в S3: " . $e->getMessage()); } // Формируем S3 URL $s3Url = 'https://s3.twcstorage.ru/' . $bucket . '/' . $s3Path; error_log("S3 URL: " . $s3Url); // Публикуем событие в Redis для индексации Nextcloud try { // Используем Predis (установлен через composer) $redis = new Predis\Client([ 'scheme' => 'tcp', 'host' => '147.45.146.17', 'port' => 6379, 'password' => 'CRM_Redis_Pass_2025_Secure!' ]); $event = json_encode([ 'type' => 'file_created', 'source' => 'crm_create_file', 'path' => $s3Path, 'timestamp' => time() ]); $redis->publish('crm:file:events', $event); error_log("✅ Published event to Redis"); } catch (Exception $e) { error_log("Redis publish failed: " . $e->getMessage()); } // Открываем файл НАПРЯМУЮ через OnlyOffice (быстро!) $redirectUrl = '/crm_extensions/file_storage/api/open_file_v2.php?recordId=' . urlencode($recordId) . '&fileName=' . urlencode($s3Url); error_log("Redirecting to OnlyOffice: " . $redirectUrl); // Редирект header('Location: ' . $redirectUrl); exit; /** * Создаёт минимальное пустое содержимое для Office файла */ function createEmptyFile($fileType) { // Используем готовые минимальные шаблоны $templatePath = __DIR__ . '/../templates/empty.' . $fileType; if (file_exists($templatePath)) { $content = file_get_contents($templatePath); error_log("Using template: " . $templatePath . " (" . strlen($content) . " bytes)"); return $content; } error_log("Template not found: " . $templatePath); // Fallback: пустая строка (не будет работать, но хотя бы не упадёт) return ''; } /** * Определяет Content-Type для файла */ function getContentType($fileType) { $types = [ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'doc' => 'application/msword', 'xls' => 'application/vnd.ms-excel', 'ppt' => 'application/vnd.ms-powerpoint' ]; return $types[$fileType] ?? 'application/octet-stream'; } ?>