Files
crm.clientright.ru/crm_extensions/file_storage/NextcloudClient.php

368 lines
13 KiB
PHP
Raw Normal View History

<?php
/**
* Nextcloud WebDAV Client (Fixed)
* Клиент для работы с Nextcloud через WebDAV API
*/
class NextcloudClient {
private $baseUrl;
private $username;
private $password;
private $activeFolder;
public function __construct($config) {
$this->baseUrl = rtrim($config['base_url'], '/');
$this->username = $config['username'];
$this->password = $config['password'];
$this->activeFolder = trim($config['active_folder'], '/');
}
/**
* Загрузка файла в Nextcloud
*/
public function uploadFile($localPath, $remotePath) {
try {
// Убираем activeFolder из remotePath если он уже там есть
if (strpos($remotePath, $this->activeFolder) === 0) {
$fullRemotePath = $remotePath;
} else {
$fullRemotePath = $this->activeFolder . '/' . ltrim($remotePath, '/');
}
$url = $this->baseUrl . '/remote.php/dav/files/' . $this->username . '/' . $fullRemotePath;
echo "Uploading to URL: $url\n";
// Создаём папку если не существует
$this->ensureFolderExists(dirname($fullRemotePath));
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_INFILE => fopen($localPath, 'r'),
CURLOPT_INFILESIZE => filesize($localPath),
CURLOPT_USERPWD => $this->username . ':' . $this->password,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
CURLOPT_HTTPHEADER => [
'Content-Type: ' . $this->getMimeType($localPath)
]
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception('Curl error: ' . $error);
}
if ($httpCode < 200 || $httpCode >= 300) {
throw new Exception('HTTP error: ' . $httpCode . ' - ' . $response);
}
return [
'success' => true,
'remote_path' => $fullRemotePath,
'url' => $url
];
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Создание папки (публичный метод)
*/
public function createFolder($folderPath) {
try {
$this->ensureFolderExists($folderPath);
return [
'success' => true,
'folder_path' => $folderPath
];
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Создание папки (улучшенная версия)
*/
private function ensureFolderExists($folderPath) {
if (empty($folderPath) || $folderPath === '.') {
return;
}
// Разбиваем путь на части
$parts = explode('/', trim($folderPath, '/'));
$currentPath = '';
foreach ($parts as $part) {
if (empty($part)) continue;
$currentPath .= '/' . $part;
$url = $this->baseUrl . '/remote.php/dav/files/' . $this->username . $currentPath;
echo "Creating folder: $url\n";
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'MKCOL',
CURLOPT_USERPWD => $this->username . ':' . $this->password,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
echo "Folder creation result: HTTP $httpCode\n";
// 201 = created, 405 = already exists, оба OK
if ($httpCode !== 201 && $httpCode !== 405) {
echo "Response: $response\n";
if ($error) {
throw new Exception("Curl error creating folder '$currentPath': $error");
} else {
throw new Exception("HTTP error creating folder '$currentPath': $httpCode - $response");
}
}
}
}
/**
* Получение ID файла из Nextcloud
*/
public function getFileId($remotePath) {
try {
$fullRemotePath = $this->activeFolder . '/' . ltrim($remotePath, '/');
$url = $this->baseUrl . '/remote.php/dav/files/' . $this->username . '/' . $fullRemotePath;
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'PROPFIND',
CURLOPT_USERPWD => $this->username . ':' . $this->password,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Content-Type: application/xml',
'Depth: 0'
],
CURLOPT_POSTFIELDS => '<?xml version="1.0" encoding="UTF-8"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:fileid/>
</d:prop>
</d:propfind>'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 207 && $response) {
$xml = simplexml_load_string($response);
if ($xml) {
foreach ($xml->xpath('//oc:fileid') as $element) {
return (string)$element;
}
}
}
return null;
} catch (Exception $e) {
error_log("Error getting file ID: " . $e->getMessage());
return null;
}
}
/**
* Создание прямой ссылки для редактирования файла
*/
public function createDirectEditLink($remotePath, $recordId, $fileName = null) {
// Создаем ссылку на файловый менеджер Nextcloud с открытием файла
if ($fileName === null) {
$fileName = basename($remotePath);
}
// Убираем подчеркивание в начале, если есть
if (substr($fileName, 0, 1) === '_') {
$fileName = substr($fileName, 1);
}
$editUrl = $this->baseUrl . '/apps/files/?dir=/crm/crm2/CRM_Active_Files/Documents/' . $recordId . '&openfile=' . urlencode($fileName);
return [
'success' => true,
'edit_url' => $editUrl,
'direct_url' => $editUrl,
'file_id' => null
];
}
/**
* Создание ссылки для редактирования файла
*/
public function createEditLink($remotePath, $permissions = 3) {
try {
$fullRemotePath = $this->activeFolder . '/' . ltrim($remotePath, '/');
// Создаём публичную ссылку через OCS API
$url = $this->baseUrl . '/ocs/v2.php/apps/files_sharing/api/v1/shares';
$postData = http_build_query([
'path' => '/' . $fullRemotePath,
'shareType' => 3, // Public link
'permissions' => $permissions, // 1=read, 2=update, 3=read+update
'format' => 'json'
]);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_USERPWD => $this->username . ':' . $this->password,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'OCS-APIRequest: true',
'Content-Type: application/x-www-form-urlencoded'
]
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception('Failed to create share link: HTTP ' . $httpCode . ' - ' . $response);
}
$data = json_decode($response, true);
if (!$data || $data['ocs']['meta']['statuscode'] !== 200) {
$message = $data['ocs']['meta']['message'] ?? 'Unknown OCS error';
throw new Exception('OCS error: ' . $message);
}
$shareUrl = $data['ocs']['data']['url'];
// Для редактирования добавляем параметр
$editUrl = $shareUrl . '/edit';
return [
'success' => true,
'share_url' => $shareUrl,
'edit_url' => $editUrl,
'share_id' => $data['ocs']['data']['id']
];
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Проверка существования файла
*/
public function fileExists($remotePath) {
$fullRemotePath = $this->activeFolder . '/' . ltrim($remotePath, '/');
$url = $this->baseUrl . '/remote.php/dav/files/' . $this->username . '/' . $fullRemotePath;
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'HEAD',
CURLOPT_USERPWD => $this->username . ':' . $this->password,
CURLOPT_NOBODY => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode === 200;
}
/**
* Скачивание файла из Nextcloud
*/
public function downloadToTemp($remotePath) {
$fullRemotePath = $this->activeFolder . '/' . ltrim($remotePath, '/');
$url = $this->baseUrl . '/remote.php/dav/files/' . $this->username . '/' . $fullRemotePath;
$tempFile = sys_get_temp_dir() . '/' . uniqid('nextcloud_download_') . '_' . basename($remotePath);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_USERPWD => $this->username . ':' . $this->password,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120
]);
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception('Download failed: HTTP ' . $httpCode);
}
file_put_contents($tempFile, $result);
return $tempFile;
}
/**
* Удаление файла
*/
public function deleteFile($remotePath) {
$fullRemotePath = $this->activeFolder . '/' . ltrim($remotePath, '/');
$url = $this->baseUrl . '/remote.php/dav/files/' . $this->username . '/' . $fullRemotePath;
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_USERPWD => $this->username . ':' . $this->password,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode === 204; // 204 = No Content (успешное удаление)
}
/**
* Получение MIME типа файла
*/
private function getMimeType($filePath) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filePath);
finfo_close($finfo);
return $mimeType ?: 'application/octet-stream';
}
}