1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
FileItem.php
См. документацию.
1<?php
2
3namespace Bitrix\Im\V2\Entity\File;
4
5use Bitrix\Disk\Document\Flipchart\Configuration;
6use Bitrix\Disk\Document\OnlyOffice\Templates\CreateDocumentByCallTemplateScenario;
7use Bitrix\Disk\Driver;
8use Bitrix\Disk\File;
9use Bitrix\Disk\Folder;
10use Bitrix\Disk\Security\ParameterSigner;
11use Bitrix\Disk\TypeFile;
12use Bitrix\Disk\Ui\FileAttributes;
13use Bitrix\Disk\UI\Viewer\Renderer\Board;
14use Bitrix\Im\Common;
15use Bitrix\Im\V2\Chat;
16use Bitrix\Im\V2\Common\ContextCustomer;
17use Bitrix\Im\V2\Entity\User\User;
18use Bitrix\Im\V2\Entity\User\UserPopupItem;
19use Bitrix\Im\V2\Message;
20use Bitrix\Im\V2\Rest\PopupData;
21use Bitrix\Im\V2\Rest\PopupDataAggregatable;
22use Bitrix\Im\V2\Rest\RestEntity;
23use Bitrix\Im\V2\Result;
24use Bitrix\Main\DI\ServiceLocator;
25use Bitrix\Main\Engine\UrlManager;
26use Bitrix\Main\Loader;
27use Bitrix\Main\Localization\Loc;
28
30{
31 use ContextCustomer;
32
33 private const QUICK_ACCESS_SCOPE_PREFIX = 'chat_';
34 public const MAX_PREVIEW_IMAGE_SIZE = 1280;
35 private const ANIMATED_IMAGE_EXTENSIONS = ['gif', 'webp'];
36
37 protected ?int $chatId = null;
38 protected ?int $diskFileId = null;
39 protected ?File $diskFile = null;
40 protected ?string $contentType = null;
41
46 public function __construct($diskFile, ?int $chatId = null)
47 {
48 if ($diskFile instanceof File)
49 {
50 $this->setDiskFile($diskFile);
51 }
52 elseif (is_numeric($diskFile))
53 {
54 $this->diskFileId = (int)$diskFile;
55 }
56 if ($chatId)
57 {
58 $this->setChatId($chatId);
59 }
60 }
61
62 public static function getRestEntityName(): string
63 {
64 return 'file';
65 }
66
67 public static function initByDiskFileId(int $diskFileId, ?int $chatId = null): ?self
68 {
70
71 if ($diskFile === null)
72 {
73 return null;
74 }
75
76 return new static($diskFile, $chatId);
77 }
78
79 public static function getDiskFileIdsFromBbCodesInText(string $text): array
80 {
81 $matches = [];
82 preg_match_all("/\[DISK=([0-9]+)\]/i", $text, $matches);
83
84 return $matches[1];
85 }
86
87 public static function removeDiskBbCodesFromText(string $text): string
88 {
89 return preg_replace("/\[DISK\=([0-9]+)\]/i", '', $text);
90 }
91
92 public static function getQuickAccessScope(int $chatId): string
93 {
94 return self::QUICK_ACCESS_SCOPE_PREFIX . $chatId;
95 }
96
97 public function setDiskFile(File $diskFile): self
98 {
99 $this->diskFile = $diskFile;
100 $this->diskFileId = $diskFile->getId();
101
102 return $this;
103 }
104
105 public function getDiskFile(): ?File
106 {
107 if (!$this->diskFile instanceof File)
108 {
109 $this->diskFile = File::getById($this->diskFileId);
110 }
111
112 return $this->diskFile;
113 }
114
115 public function getDiskFileId(): int
116 {
117 if ($this->diskFileId)
118 {
119 return $this->diskFileId;
120 }
121
122 return $this->getDiskFile()->getId();
123 }
124
125 public function getChatId(): ?int
126 {
127 return $this->chatId;
128 }
129
130 public function setChatId(?int $chatId): self
131 {
132 $this->chatId = $chatId;
133 return $this;
134 }
135
136 public function markAsFile(): self
137 {
138 $diskFile = $this->getDiskFile();
139 if (!$diskFile)
140 {
141 return $this;
142 }
143
144 $fileType = (int)$diskFile->getTypeFile();
145
146 if ($fileType === TypeFile::IMAGE || $fileType === TypeFile::VIDEO)
147 {
148 $diskFile->changeCode(\Bitrix\Im\V2\Link\File\FileItem::MEDIA_ORIGINAL_CODE);
149 }
150
151 return $this;
152 }
153
157 public function copyTo(Folder $folder): Result
158 {
159 $result = new Result();
160 $userId = $this->getContext()->getUserId();
161 $diskFile = $this->getDiskFile();
162
163 if ($diskFile === null)
164 {
165 return $result->addError(new FileError(FileError::NOT_FOUND));
166 }
167
168 $copy = $diskFile->copyTo($folder, $userId, true);
169
170 if (!$copy instanceof File)
171 {
172 return $result->addError(new FileError(FileError::COPY_ERROR));
173 }
174
175 return $result->setResult(new static($copy, $this->getChatId()));
176 }
177
178 public function getCopyToChat(Chat $chat): ?self
179 {
180 if (!Loader::includeModule('disk'))
181 {
182 return null;
183 }
184
185 $folder = $chat->getOrCreateDiskFolder();
186 $diskFile = $this->getDiskFile()?->getRealObject();
187
188 if (!($folder instanceof Folder) || $diskFile === null)
189 {
190 return null;
191 }
192
193 $newFileModel = $diskFile->copyTo($folder, $chat->getContext()->getUserId(), true);
194
195 if (!($newFileModel instanceof File))
196 {
197 return null;
198 }
199
200 if ($diskFile->getCode() === \Bitrix\Im\V2\Link\File\FileItem::MEDIA_ORIGINAL_CODE)
201 {
202 $newFileModel->changeCode(\Bitrix\Im\V2\Link\File\FileItem::MEDIA_ORIGINAL_CODE);
203 }
204
205 $newFileModel->increaseGlobalContentVersion();
206
207 return new static($newFileModel, $chat->getId());
208 }
209
210 public function getPopupData(array $excludedList = []): PopupData
211 {
212 return new PopupData([new UserPopupItem([$this->getDiskFile()->getCreatedBy()])], $excludedList);
213 }
214
215 public function getMessageOut(): string
216 {
217 Message::loadPhrases();
218 $diskFile = $this->getDiskFile();
219
220 if (!$diskFile)
221 {
222 return '';
223 }
224
225 return $diskFile->getName() . ' (' . \CFile::formatSize($diskFile->getSize()) . ')'
226 . "\n" . Loc::getMessage('IM_MESSAGE_FILE_DOWN')
227 . ' ' . $this->getDownloadLink()
228 . "\n";
229 }
230
231 public function toRestFormat(array $option = []): array
232 {
233 $diskFile = $this->getDiskFile();
234 $author = User::getInstance((int)$diskFile?->getCreatedBy());
235 return [
236 'id' => (int)$diskFile?->getId(),
237 'chatId' => (int)$this->getChatId(),
238 'date' => $diskFile?->getCreateTime()?->format('c'),
239 'type' => $this->getContentType(),
240 'name' => $diskFile?->getName(),
241 'extension' => mb_strtolower($diskFile?->getExtension() ?? ''),
242 'size' => (int)$diskFile?->getSize(),
243 'image' => $this->getPreviewSizes() ?? false,
244 'status' => $diskFile?->getGlobalContentVersion() > 1? 'done': 'upload',
245 'progress' => $diskFile?->getGlobalContentVersion() > 1? 100: -1,
246 'authorId' => (int)$diskFile?->getCreatedBy(),
247 'authorName' => $author->getName(),
248 'urlPreview' => $this->getPreviewLink(),
249 'urlShow' => $this->getShowLink(),
250 'urlDownload' => $this->getDownloadLink(),
251 'viewerAttrs' => $this->getViewerAttributes(),
252 'mediaUrl' => $this->getMediaUrl(),
253 ];
254 }
255
256 private function getMediaUrl(): array
257 {
258 return [
259 'preview' => [
260 250 => $this->getPreviewLinkBySize(250, true),
261 ],
262 ];
263 }
264
270 public function getContentType(): string
271 {
272 if (isset($this->contentType))
273 {
274 return $this->contentType;
275 }
276
277 if ($this->getDiskFile()->getCode() === \Bitrix\Im\V2\Link\File\FileItem::MEDIA_ORIGINAL_CODE)
278 {
279 return 'file';
280 }
281
282 $diskTypeFile = $this->getDiskFile()->getTypeFile();
283
284 switch ($diskTypeFile)
285 {
286 case TypeFile::IMAGE:
287 return 'image';
288 case TypeFile::VIDEO:
289 return 'video';
290 case TypeFile::AUDIO:
291 return 'audio';
292 default:
293 return 'file';
294 }
295 }
296
297 public function setContentType(string $contentType): self
298 {
299 $this->contentType = $contentType;
300
301 return $this;
302 }
303
304 private function getPreviewSizes(): ?array
305 {
306 $previewParameters = [];
307 $diskFile = $this->getDiskFile();
308
309 if (TypeFile::isImage($diskFile))
310 {
311 $previewParameters = $diskFile->getFile();
312 }
313 if (TypeFile::isVideo($diskFile->getName()))
314 {
315 $previewParameters = $diskFile->getView()->getPreviewData();
316 }
317
318 if (empty($previewParameters))
319 {
320 return null;
321 }
322
323 return [
324 'height' => (int)$previewParameters['HEIGHT'],
325 'width' => (int)$previewParameters['WIDTH'],
326 ];
327 }
328
329 private function getPreviewLink(): string
330 {
331 $diskFile = $this->getDiskFile();
332 if (!isset($diskFile))
333 {
334 return '';
335 }
336
337 return match (true)
338 {
339 $this->isAnimatedImage() => $this->getDownloadLink(),
340 TypeFile::isImage($diskFile) => $this->isOversized() ? $this->getShowLink() : $this->getDownloadLink(),
341 $diskFile->getView()->getPreviewData() !== null => $this->getFilePreviewLink(),
342 default => '',
343 };
344 }
345
346 private function isOversized(?int $maxSize = null): bool
347 {
348 $maxSize ??= self::MAX_PREVIEW_IMAGE_SIZE;
349
350 $fileData = $this->getDiskFile()?->getFile() ?? [];
351 $sourceImageWidth = $fileData['WIDTH'] ?? 0;
352 $sourceImageHeight = $fileData['HEIGHT'] ?? 0;
353
354 return $sourceImageHeight > $maxSize || $sourceImageWidth > $maxSize;
355 }
356
357 private function getPreviewLinkBySize(int $size, bool $exact = false): string
358 {
359 $diskFile = $this->getDiskFile();
360 if (!isset($diskFile))
361 {
362 return '';
363 }
364
365 $previewData = $diskFile->getView()->getPreviewData();
366
367 return match (true)
368 {
369 $this->isAnimatedImage() , $previewData !== null => $this->getFilePreviewLink($size, $exact),
370 TypeFile::isImage($diskFile) => $this->isOversized($size)
371 ? $this->getShowLink($size, $exact)
372 : $this->getDownloadLink()
373 ,
374 default => '',
375 };
376 }
377
378 private function getShowLink(?int $size = self::MAX_PREVIEW_IMAGE_SIZE, $exact = false): string
379 {
380 if (TypeFile::isImage($this->getDiskFile() ?? ''))
381 {
382 return $this->getLink(new FileLinkConfig('disk.api.file.showImage', $size, $exact));
383 }
384
385 return $this->getDownloadLink();
386 }
387
388 private function getDownloadLink(): string
389 {
390 return $this->getLink(new FileLinkConfig('disk.api.file.download'));
391 }
392
393 private function getFilePreviewLink(?int $size = self::MAX_PREVIEW_IMAGE_SIZE, $exact = false): string
394 {
395 $linkConfig = new FileLinkConfig('disk.api.file.showPreview', $size, $exact, 'preview.jpg');
396
397 return $this->getLink($linkConfig);
398 }
399
400 private function getLink(FileLinkConfig $linkConfig): string
401 {
402 $diskFile = $this->getDiskFile();
403 if (!$diskFile)
404 {
405 return '';
406 }
407
408 $params = $this->getLinkParams($linkConfig);
409 $urlManager = UrlManager::getInstance();
410
411 return Common::getPublicDomain() . $urlManager->create($linkConfig->action, $params)->getUri();
412 }
413
414 private function getLinkParams(FileLinkConfig $linkConfig): array
415 {
416 $diskFile = $this->getDiskFile();
417 if (!$diskFile)
418 {
419 return [];
420 }
421
422 $params = [
423 'humanRE' => 1,
424 'fileId' => $diskFile->getId(),
425 ];
426
427 $size = $linkConfig->size;
428 if (isset($size))
429 {
430 $params['width'] = $size;
431 $params['height'] = $size;
432 $params['signature'] = ParameterSigner::getImageSignature($diskFile->getId(), $size, $size);
433 }
434
435 $params['exact'] = $linkConfig->exact ? 'Y' : 'N';
436
437 $quickAccessToken = $this->getQuickAccessToken();
438 if ($quickAccessToken !== null)
439 {
440 $params['_esd'] = $quickAccessToken;
441 }
442
443 // Adding the file extension to the end of the URL to ensure that various parsers and clients
444 // can correctly identify the type of resource (e.g., .jpg, .png, .pdf).
445 // This helps avoid issues where the absence of an extension might cause incorrect handling of the link.
446 $params['fileName'] = $linkConfig->forceFileName ?? $diskFile->getName();
447
448 return $params;
449 }
450
451 private function isAnimatedImage(): bool
452 {
453 return in_array($this->getDiskFile()?->getExtension(), self::ANIMATED_IMAGE_EXTENSIONS, true);
454 }
455
456 private function getQuickAccessSupportedFileTypes(): array
457 {
458 return [TypeFile::IMAGE, TypeFile::VIDEO];
459 }
460
461 private function isQuickAccessSupported(): bool
462 {
463 $diskFile = $this->getDiskFile();
464 $diskFileType = $diskFile ? (int)$diskFile->getTypeFile() : null;
465 $supportedTypes = $this->getQuickAccessSupportedFileTypes();
466
467 return in_array($diskFileType, $supportedTypes, true);
468 }
469
470 private function getQuickAccessToken(): ?string
471 {
472 $file = $this->getDiskFile();
473 $chatId = $this->getChatId();
474 if (
475 $file === null
476 || $chatId === null
477 || !$this->isQuickAccessSupported()
478 || !ServiceLocator::getInstance()->has('disk.scopeTokenService')
479 )
480 {
481 return null;
482 }
483
485 $scopeTokenService = ServiceLocator::getInstance()->get('disk.scopeTokenService');
486
487 return $scopeTokenService?->getEncryptedScopeForObject($file, $scope);
488
489 }
490
491 private function getViewerAttributes(): ?array
492 {
493 $diskFile = $this->getDiskFile();
494 try
495 {
496 $fileData = $diskFile->getFile() ?? [];
497 if ($fileData && $fileData['CONTENT_TYPE'] === 'application/octet-stream' && GetFileExtension($diskFile->getName()) === 'board')
498 {
499 $fileData['CONTENT_TYPE'] = 'application/board';
500 }
501
502 $viewerType = FileAttributes::buildByFileData($fileData, $this->getDownloadLink())
503 ->setObjectId($diskFile->getId())
504 ->setGroupBy($this->getChatId() ?? $diskFile->getParentId())
505 ->setAttribute('data-im-chat-id', $this->getChatId())
506 ->setTitle($diskFile->getName())
507 ->addAction([
508 'type' => 'download',
509 ])
510 ->addAction([
511 'type' => 'copyToMe',
512 'text' => Loc::getMessage('IM_FILE_ITEM_ACTION_SAVE_TO_OWN_FILES'),
513 'action' => 'BXIM.disk.saveToDiskAction',
514 'params' => [
515 'fileId' => $diskFile->getId(),
516 ],
517 'extension' => 'disk.viewer.actions',
518 'buttonIconClass' => 'ui-btn-icon-cloud',
519 ])
520 ;
521
522 if ($viewerType->getTypeClass() === FileAttributes::JS_TYPE_CLASS_ONLYOFFICE)
523 {
524 $viewerType->setTypeClass('BX.Messenger.Integration.Viewer.OnlyOfficeChatItem');
525 if (
526 $diskFile->getCode() === CreateDocumentByCallTemplateScenario::CODE_RESUME
527 || $diskFile->getRealObject()->getCode() === CreateDocumentByCallTemplateScenario::CODE_RESUME
528 )
529 {
530 $viewerType->setTypeClass('BX.Messenger.Integration.Viewer.OnlyOfficeResumeItem');
531 }
532
533 $viewerType->setExtension('im.integration.viewer');
534 }
535
536 if ($viewerType->getViewerType() === Board::JS_TYPE_BOARD && Configuration::isBoardsEnabled())
537 {
538 $uri = Driver::getInstance()->getUrlManager()->getUrlForViewBoard($diskFile->getId(), false, 'chat');
539 $viewerType->addAction([
540 'type' => 'open',
541 'buttonIconClass' => ' ',
542 'action' => 'BX.Disk.Viewer.Actions.openInNewTab',
543 'params' => [
544 'url' => $uri,
545 ],
546 ]);
547 }
548
549 if ($viewerType->getViewerType() !== \Bitrix\Main\UI\Viewer\Renderer\Renderer::JS_TYPE_UNKNOWN)
550 {
551 return $viewerType->toDataSet();
552 }
553 }
554 catch (\Bitrix\Main\ArgumentException $exception)
555 {
556 return null;
557 }
558
559 return null;
560 }
561
562 public function getId(): int
563 {
564 return $this->getDiskFileId();
565 }
566}
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static getPublicDomain()
Определения common.php:8
static getRestEntityName()
Определения FileItem.php:62
string $contentType
Определения FileItem.php:40
setDiskFile(File $diskFile)
Определения FileItem.php:97
static getQuickAccessScope(int $chatId)
Определения FileItem.php:92
toRestFormat(array $option=[])
Определения FileItem.php:231
setChatId(?int $chatId)
Определения FileItem.php:130
getPopupData(array $excludedList=[])
Определения FileItem.php:210
static removeDiskBbCodesFromText(string $text)
Определения FileItem.php:87
setContentType(string $contentType)
Определения FileItem.php:297
getCopyToChat(Chat $chat)
Определения FileItem.php:178
static initByDiskFileId(int $diskFileId, ?int $chatId=null)
Определения FileItem.php:67
copyTo(Folder $folder)
Определения FileItem.php:157
const MAX_PREVIEW_IMAGE_SIZE
Определения FileItem.php:34
static getDiskFileIdsFromBbCodesInText(string $text)
Определения FileItem.php:79
__construct($diskFile, ?int $chatId=null)
Определения FileItem.php:46
static getInstance()
Определения application.php:98
Определения result.php:20
static getById($id)
Определения datamanager.php:364
static has($entityName)
Определения entity.php:89
getCode()
Определения entity.php:804
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
if(file_exists($_SERVER['DOCUMENT_ROOT'] . "/urlrewrite.php")) $uri
Определения urlrewrite.php:61
GetFileExtension($path)
Определения tools.php:2972
Определения ActionUuid.php:3
Определения Image.php:9
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$text
Определения template_pdf.php:79
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$option
Определения options.php:1711
$matches
Определения index.php:22