Files
crm.clientright.ru/crm_extensions/file_storage/api/open_file.php
Fedor 3fb2ad5f60 feat: Project file migration and Nextcloud integration
- Added project file migration script with sanitization (underscores)
- Fixed Nextcloud editor integration (urldecode, basename fix)
- Added 'Open Project Folder in Nextcloud' button
- 223 projects migrated (completed + archived)
- URL decoding fix for Cyrillic filenames
2025-10-22 18:29:02 +03:00

163 lines
6.5 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
/**
* Простой редирект на файл в Nextcloud БЕЗ CSRF проверок
*/
// Получаем параметры
$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : '';
$recordId = isset($_GET['recordId']) ? $_GET['recordId'] : '';
// Если fileName содержит полный URL, извлекаем только имя файла
if (strpos($fileName, 'http') === 0) {
$fileName = urldecode($fileName);
// ИСПРАВЛЕНИЕ: используем правильное извлечение имени файла
$lastSlash = strrpos($fileName, '/');
if ($lastSlash !== false) {
$fileName = substr($fileName, $lastSlash + 1);
} else {
$fileName = basename($fileName);
}
$fileName = trim($fileName);
error_log("Nextcloud Editor: Извлечено имя файла из URL: {$fileName}");
}
// Настройки Nextcloud
$nextcloudUrl = 'https://office.clientright.ru:8443';
$username = 'admin';
$password = 'office';
// Подключаемся к БД чтобы получить название проекта
chdir('/var/www/fastuser/data/www/crm.clientright.ru');
require_once 'include/utils/utils.php';
require_once 'include/database/PearDatabase.php';
global $adb;
// Функция для санитизации названия папки
function sanitizeFolderName($name) {
$name = str_replace(['/', '\\', ':', '*', '?', '"', '<', '>', '|', '#'], '_', $name);
$name = preg_replace('/\s+/', '_', $name);
return trim($name);
}
// Найдём projectid по связи документа → проекта
$docId = $recordId;
$projectId = null;
try {
$sqlProject = "SELECT r.crmid AS projectid
FROM vtiger_senotesrel r
INNER JOIN vtiger_crmentity e ON e.crmid = r.crmid
WHERE r.notesid = ? AND e.setype = 'Project'
ORDER BY r.crmid DESC LIMIT 1";
$resProject = $adb->pquery($sqlProject, [$docId]);
if ($resProject && $adb->num_rows($resProject) > 0) {
$projectRow = $adb->fetchByAssoc($resProject);
$projectId = (string)$projectRow['projectid'];
}
} catch (Exception $e) {
error_log('Nextcloud Editor: DB error while resolving project by document: ' . $e->getMessage());
}
// Получаем название проекта из БД (если нашли projectId)
$projectName = null;
if ($projectId) {
$sql = "SELECT projectname FROM vtiger_project WHERE projectid = ?";
$result = $adb->pquery($sql, [$projectId]);
if ($result && $adb->num_rows($result) > 0) {
$row = $adb->fetchByAssoc($result);
$projectName = sanitizeFolderName($row['projectname']);
}
}
// Формируем пути к файлу в Nextcloud
// НОВЫЙ формат: crm/crm2/CRM_Active_Files/Documents/{ProjectName}_{ProjectID}/{fileName}
// СТАРЫЙ формат: crm/crm2/CRM_Active_Files/Documents/{DocumentID}/{fileName}
// Вспомогательная функция: кодирование пути по сегментам (WebDAV)
$encodePath = function(array $segments) {
return implode('/', array_map('rawurlencode', $segments));
};
// Список путей для логирования (читаемые) и для запроса (url-encoded)
$humanPaths = [];
$requestPaths = [];
if ($projectName && $projectId) {
$humanPaths[] = "crm/crm2/CRM_Active_Files/Documents/{$projectName}_{$projectId}/{$fileName}";
$requestPaths[] = $encodePath(['crm','crm2','CRM_Active_Files','Documents',"{$projectName}_{$projectId}",$fileName]);
}
// Резерв - старый формат (папка по documentId)
$humanPaths[] = "crm/crm2/CRM_Active_Files/Documents/{$docId}/{$fileName}";
$requestPaths[] = $encodePath(['crm','crm2','CRM_Active_Files','Documents',(string)$docId,$fileName]);
$fileId = null;
$usedPath = null;
// Пробуем найти файл по всем возможным путям
for ($i = 0; $i < count($requestPaths); $i++) {
$tryPath = $requestPaths[$i];
$logPath = $humanPaths[$i];
$propfindUrl = $nextcloudUrl . '/remote.php/dav/files/' . $username . '/' . $tryPath;
// error_log("Nextcloud Editor: PROPFIND -> {$propfindUrl} (читаемый путь: {$logPath})");
// XML запрос для получения fileid
$xmlRequest = '<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:fileid/>
</d:prop>
</d:propfind>';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $propfindUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PROPFIND');
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Depth: 0',
'Content-Type: application/xml'
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($response === false) {
error_log("Nextcloud Editor: Ошибка cURL: " . $curlError);
continue; // Пробуем следующий путь
}
if ($httpCode === 207 && $response) { // 207 = Multi-Status для PROPFIND
// Простой regex для извлечения fileid
if (preg_match('/<oc:fileid>(\d+)<\/oc:fileid>/', $response, $matches)) {
$fileId = $matches[1];
$usedPath = $tryPath;
error_log("Nextcloud Editor: ✅ fileId получен: {$fileId} (путь: {$usedPath})");
break; // Нашли файл, выходим из цикла
}
}
// error_log("Nextcloud Editor: Файл не найден по пути: {$logPath} (HTTP {$httpCode})");
}
if (!$fileId) {
// Простая ошибка без отладки
$errorMsg = "❌ Ошибка: Не удалось получить fileId для файла {$fileName}";
error_log("Nextcloud Editor ERROR: " . $errorMsg);
die($errorMsg);
}
// Формируем URL для Nextcloud
// РАБОЧИЙ ФОРМАТ - редирект на файл с автооткрытием редактора!
$redirectUrl = $nextcloudUrl . '/apps/files/files/' . $fileId . '?dir=/&editing=true&openfile=true';
// Логирование
error_log("Nextcloud Editor: Redirect to $redirectUrl for file $fileName (ID: $fileId)");
// Делаем редирект
header('Location: ' . $redirectUrl);
exit;
?>