Files
crm.clientright.ru/upload_file_n8n.php

403 lines
17 KiB
PHP
Executable File
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
// upload_documents_to_crm.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Быстрый ping для проверки доступности скрипта из браузера/HTTP-клиента
if (isset($_GET['ping'])) {
header('Content-Type: text/plain; charset=utf-8');
echo 'pong';
exit;
}
// Подключение к CRM
require_once('config.inc.php');
require_once('include/Webservices/Utils.php');
require_once('include/Webservices/Create.php');
require_once('include/Webservices/Login.php');
require_once('include/Webservices/AuthToken.php');
require_once('include/Webservices/AddRelated.php');
require_once('include/utils/utils.php');
require_once('includes/Loader.php');
vimport('includes.runtime.Globals');
require_once('include/database/PearDatabase.php');
require_once('modules/Users/Users.php');
// Инициализируем подключение к БД явно
$adb = PearDatabase::getInstance();
// Управление вербозностью: для POST по умолчанию тихий режим (чистый JSON)
$__IS_POST__ = (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST');
$__VERBOSE__ = (!$__IS_POST__) || (isset($_GET['verbose']) && $_GET['verbose'] == '1');
if ($__IS_POST__) {
// В API-режиме скрываем любые варнинги/эхо и возвращаем только JSON
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
}
// Глобальный логгер для этого эндпоинта
if (!function_exists('writeLog')) {
function writeLog($message) {
$logFile = '/logs/upload_documents.log';
$timestamp = date('Y-m-d H:i:s');
file_put_contents($logFile, "[$timestamp] $message\n", FILE_APPEND | LOCK_EX);
}
}
// Унифицированный JSON-ответ и обработка фатальных ошибок для POST
function json_response($payload, $code = 200) {
if (!headers_sent()) {
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
}
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
}
if ($__IS_POST__) {
register_shutdown_function(function () {
$e = error_get_last();
if ($e && in_array($e['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
writeLog('FATAL: '.$e['message'].' in '.$e['file'].':'.$e['line']);
json_response([
'success' => false,
'error' => [
'type' => 'fatal',
'message' => 'Internal error',
]
], 500);
}
});
}
/**
* Функция для получения entity ID по имени модуля
*/
function vtws_getEntityId($entityName) {
global $adb;
$wsrs = $adb->pquery('select id from vtiger_ws_entity where name=?', array($entityName));
if ($wsrs && $adb->num_rows($wsrs) == 1) {
$wsid = $adb->query_result($wsrs, 0, 0);
} else {
$wsid = 0;
}
return $wsid;
}
/**
* Функция для получения webservice ID пользователя
*/
function getWebserviceUserId($userId) {
global $adb;
$entityId = vtws_getEntityId('Users');
return $entityId . 'x' . $userId;
}
/**
* Функция для получения webservice ID проекта
*/
function getWebserviceProjectId($projectId) {
global $adb;
$entityId = vtws_getEntityId('Project');
return $entityId . 'x' . $projectId;
}
/**
* Префикс WS для папок документов
*/
function getDocumentFoldersWsPrefix() {
global $adb;
$rs = $adb->pquery("SELECT id FROM vtiger_ws_entity WHERE name=?", ['DocumentFolders']);
if ($rs && $adb->num_rows($rs) > 0) {
return (int)$adb->query_result($rs, 0, 'id');
}
return 22;
}
/**
* Получить WS ID папки по имени, иначе null
*/
function getFolderWsIdByName($folderName) {
global $adb;
$rs = $adb->pquery('SELECT folderid FROM vtiger_attachmentsfolder WHERE foldername = ? LIMIT 1', [$folderName]);
if ($rs && $adb->num_rows($rs) > 0) {
$folderId = (int)$adb->query_result($rs, 0, 'folderid');
$prefix = getDocumentFoldersWsPrefix();
return $prefix . 'x' . $folderId;
}
return null;
}
/**
* Безопасная аутентификация через challenge/response
*/
function authenticateWithCRM($username) {
// 1) Получаем challenge токен
$challenge = vtws_getchallenge($username);
if (empty($challenge['token'])) {
throw new Exception('Не удалось получить challenge token');
}
// 2) Берем accesskey пользователя
$user = new Users();
$userId = $user->retrieve_user_id($username);
if (!$userId) {
throw new Exception("Пользователь {$username} не найден");
}
$accessKey = vtws_getUserAccessKey($userId);
if (!$accessKey) {
throw new Exception('Access key пользователя не найден');
}
// 3) Логинимся
$generatedKey = md5($challenge['token'] . $accessKey);
$loggedUser = vtws_login($username, $generatedKey);
// Для отладки можно писать в лог
// error_log("WS login ok for $username, token={$challenge['token']} md5=$generatedKey");
// Установим $current_user для операций CRMEntity
global $current_user;
$current_user = new Users();
$current_user->retrieveCurrentUserInfoFromFile((int)$userId);
return $loggedUser;
}
/**
* Функция для получения ID папки по умолчанию
*/
function getDefaultFolderId() {
global $adb;
$result = $adb->pquery('SELECT folderid FROM vtiger_attachmentsfolder WHERE foldername = ? LIMIT 1', array('Default'));
if ($result && $adb->num_rows($result) > 0) {
$folderId = $adb->query_result($result, 0, 'folderid');
$entityId = vtws_getEntityId('DocumentFolders');
return $entityId . 'x' . $folderId;
}
return '22x1'; // Fallback ID
}
/**
* Основная функция для создания документов в CRM
*/
function createDocumentsInCRM($filesArray, $adminUsername = 'api') {
global $adb;
writeLog("🚀 Начинаем создание документов для пользователя: $adminUsername");
try {
writeLog("🔐 Попытка аутентификации...");
// Проверяем существование пользователя
$user = new Users();
$userId = $user->retrieve_user_id($adminUsername);
if (!$userId) {
throw new Exception("Пользователь '$adminUsername' не найден");
}
writeLog("✅ Пользователь найден, ID: $userId");
// Безопасная аутентификация
$authenticatedUser = authenticateWithCRM($adminUsername);
writeLog("✅ Аутентификация успешна");
$results = [];
foreach ($filesArray as $index => $fileData) {
writeLog("📄 Обрабатываем файл #$index: " . ($fileData['file_name'] ?? 'Unknown'));
try {
// Получаем webservice ID пользователя и проекта
$assignedUserId = getWebserviceUserId($fileData['user_id']);
$projectId = getWebserviceProjectId($fileData['projectid']);
// Папка: сначала пробуем 'Суд', иначе Default
$folderId = getFolderWsIdByName('Суд');
if (!$folderId) {
$folderId = getDefaultFolderId();
writeLog("⚠️ Папка 'Суд' не найдена, используем по умолчанию: $folderId");
} else {
writeLog("📁 Используем папку 'Суд': $folderId");
}
writeLog("🔗 WebService IDs - User: $assignedUserId, Project: $projectId, Folder: $folderId");
// Формируем данные документа
$documentData = [
'notes_title' => $fileData['description'] ?: $fileData['file_name'],
'filename' => $fileData['url'],
'assigned_user_id' => $assignedUserId,
'notecontent' => 'Автоматически загружен из S3. Контакт: ' . $fileData['contactid'],
'filetype' => 'application/pdf',
'filesize' => '0',
'filelocationtype' => 'E',
'fileversion' => '1.0',
'filestatus' => '1',
'filedownloadcount' => '0',
'folderid' => $folderId,
'created_user_id' => $assignedUserId,
'starred' => '0',
'tags' => 'S3,автозагрузка'
];
writeLog("📋 Данные документа подготовлены: " . json_encode($documentData, JSON_UNESCAPED_UNICODE));
// Создаем документ
$document = vtws_create('Documents', $documentData, $authenticatedUser);
if ($document && isset($document['id'])) {
writeLog("✅ Документ создан с ID: " . $document['id']);
// Привязываем документ к проекту
try {
vtws_add_related($projectId, $document['id'], false, $authenticatedUser);
writeLog("✅ Документ привязан к проекту");
$results[] = [
'status' => 'success',
'file_name' => $fileData['file_name'],
'document_id' => $document['id'],
'project_id' => $fileData['projectid'],
'url' => $fileData['url'],
'message' => 'Документ успешно создан и привязан к проекту'
];
} catch (Exception $e) {
// Fallback: привязываем напрямую через CRMEntity
writeLog("⚠️ Webservice AddRelated не сработал: " . $e->getMessage() . ". Пытаемся привязать напрямую...");
require_once 'data/CRMEntity.php';
require_once 'modules/Vtiger/CRMEntity.php';
$docIds = vtws_getIdComponents($document['id']);
$docNumericId = (int)$docIds[1];
$focus = CRMEntity::getInstance('Project');
relateEntities($focus, 'Project', (int)$fileData['projectid'], 'Documents', $docNumericId);
writeLog("✅ Привязка выполнена напрямую (Project {$fileData['projectid']} -> Document {$docNumericId})");
$results[] = [
'status' => 'success',
'file_name' => $fileData['file_name'],
'document_id' => $document['id'],
'project_id' => $fileData['projectid'],
'url' => $fileData['url'],
'message' => 'Документ создан и привязан к проекту (fallback)'
];
}
} else {
writeLog("❌ Ошибка создания документа");
$results[] = [
'status' => 'error',
'file_name' => $fileData['file_name'],
'project_id' => $fileData['projectid'],
'url' => $fileData['url'],
'message' => 'Ошибка создания документа'
];
}
} catch (Exception $e) {
writeLog("❌ Критическая ошибка для файла: " . $e->getMessage());
$results[] = [
'status' => 'error',
'file_name' => $fileData['file_name'] ?? 'Unknown',
'project_id' => $fileData['projectid'] ?? 'Unknown',
'url' => $fileData['url'] ?? 'Unknown',
'message' => 'Ошибка: ' . $e->getMessage()
];
}
}
writeLog("🏁 Обработка завершена. Всего файлов: " . count($filesArray));
return $results;
} catch (Exception $e) {
writeLog("💥 Критическая ошибка: " . $e->getMessage());
return [
'status' => 'critical_error',
'message' => 'Ошибка аутентификации в CRM: ' . $e->getMessage()
];
}
}
/**
* Получение access key пользователя
*/
function vtws_getUserAccessKey($userId) {
global $adb;
$sql = "SELECT accesskey FROM vtiger_users WHERE id = ?";
$result = $adb->pquery($sql, array($userId));
if ($result && $adb->num_rows($result) > 0) {
return $adb->query_result($result, 0, 'accesskey');
}
return null;
}
// Пример использования:
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Получаем JSON данные (без BOM) и пробуем распознать формат
writeLog('POST '.$_SERVER['REQUEST_URI'].' CT='.(isset($_SERVER['CONTENT_TYPE'])?$_SERVER['CONTENT_TYPE']:'').', CL='.(isset($_SERVER['CONTENT_LENGTH'])?$_SERVER['CONTENT_LENGTH']:'').' UA='.(isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:'').', IP='.(isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:'') );
$input = file_get_contents('php://input');
writeLog('RAW BODY: '.substr($input,0,2048).(strlen($input)>2048?'...<truncated>':''));
$input = ltrim($input, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
$filesArray = json_decode($input, true);
if (json_last_error() !== JSON_ERROR_NONE) {
writeLog('JSON ERROR: '.json_last_error_msg());
json_response(['success' => false, 'error' => ['message' => 'Invalid JSON: '.json_last_error_msg()]], 400);
exit;
}
// Авто-распаковка n8n-форматов:
// 1) [{"data":[...]}]
if (is_array($filesArray) && count($filesArray) === 1 && isset($filesArray[0]['data']) && is_array($filesArray[0]['data'])) {
$filesArray = $filesArray[0]['data'];
}
// 2) {"data":[...]}
if (is_array($filesArray) && isset($filesArray['data']) && is_array($filesArray['data'])) {
$filesArray = $filesArray['data'];
}
if (!is_array($filesArray)) {
writeLog('BAD FORMAT: not an array after normalization');
json_response(['success' => false, 'error' => ['message' => 'JSON must be an array of file items']], 400);
exit;
}
writeLog('ITEMS: '.count($filesArray));
// Создаем документы
$results = createDocumentsInCRM($filesArray);
writeLog('DONE: processed='.count($filesArray));
// Возвращаем результат
json_response([
'success' => true,
'results' => $results,
'total_processed' => count($filesArray)
]);
} else {
// Тестовый запуск с вашими данными
$testData = [
[
"session_token" => "sess_dedc540e-f60d-491b-b6bb-ef7f7d04a366",
"user_id" => 1,
"contactid" => 120374,
"description" => "Иск",
"projectid" => 354918,
"pages" => 2,
"url" => "https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/120374/1757346451126.pdf",
"file_name" => "1757346451126.pdf"
],
[
"session_token" => "sess_dedc540e-f60d-491b-b6bb-ef7f7d04a366",
"user_id" => 1,
"contactid" => 120374,
"description" => "доказательство направления претензии",
"projectid" => 354918,
"pages" => 4,
"url" => "https://s3.twcstorage.ru/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/clientright/120374/1757346454717.pdf",
"file_name" => "1757346454717.pdf"
]
];
$results = createDocumentsInCRM($testData);
header('Content-Type: application/json');
echo json_encode([
'success' => true,
'results' => $results,
'total_processed' => count($testData)
], JSON_UNESCAPED_UNICODE);
}
?>