1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
Uploader.php
См. документацию.
1<?php
2
3namespace Bitrix\UI\FileUploader;
4
5use Bitrix\Main\ORM\Objectify\State;
6use Bitrix\Main\Security\Sign\Signer;
7use Bitrix\Main\UI\Viewer\ItemAttributes;
8use Bitrix\UI\FileUploader\Contracts\CustomFingerprint;
9use Bitrix\UI\FileUploader\Contracts\CustomLoad;
10use Bitrix\UI\FileUploader\Contracts\CustomRemove;
11
13{
15
17 {
18 $this->controller = $controller;
19 }
20
22 {
23 return $this->controller;
24 }
25
26 public function upload(Chunk $chunk, string $token = null): UploadResult
27 {
28 $controller = $this->getController();
29 $uploadResult = new UploadResult();
30 if ($chunk->isFirst())
31 {
32 // Common file validation (uses in CFile::SaveFile)
33 $commitOptions = $controller->getCommitOptions();
34 $error = \CFile::checkFile(
35 [
36 'name' => $chunk->getName(),
37 'size' => $chunk->getFileSize(),
38 'type' => $chunk->getType()
39 ],
40 0,
41 false,
42 false,
43 $commitOptions->isForceRandom(),
44 $commitOptions->isSkipExtension()
45 );
46
47 if ($error !== '')
48 {
49 return $this->handleUploadError(
50 $uploadResult->addError(new UploaderError('CHECK_FILE_FAILED', $error)),
52 );
53 }
54
55 // Controller Validation
56 $validationResult = $chunk->validate($controller->getConfiguration());
57 if (!$validationResult->isSuccess())
58 {
59 return $this->handleUploadError($uploadResult->addErrors($validationResult->getErrors()), $controller);
60 }
61
62 ['width' => $width, 'height' => $height] = $validationResult->getData();
63 $chunk->setWidth((int)$width);
64 $chunk->setHeight((int)$height);
65
66 $uploadRequest = new UploadRequest($chunk->getName(), $chunk->getType(), $chunk->getSize());
67 $uploadRequest->setWidth($chunk->getWidth());
68 $uploadRequest->setHeight($chunk->getHeight());
69
70 // Temporary call for compatibility
71 // $canUploadResult = $controller->canUpload($uploadRequest);
72 $canUploadResult = call_user_func([$controller, 'canUpload'], $uploadRequest);
73 if (($canUploadResult instanceof CanUploadResult) && !$canUploadResult->isSuccess())
74 {
75 return $this->handleUploadError($uploadResult->addErrors($canUploadResult->getErrors()), $controller);
76 }
77 else if (!is_bool($canUploadResult) || $canUploadResult === false)
78 {
79 return $this->handleUploadError(
80 $uploadResult->addError(new UploaderError(UploaderError::FILE_UPLOAD_ACCESS_DENIED)),
82 );
83 }
84
85 $createResult = TempFile::create($chunk, $controller);
86 if (!$createResult->isSuccess())
87 {
88 return $this->handleUploadError($uploadResult->addErrors($createResult->getErrors()), $controller);
89 }
90
92 $tempFile = $createResult->getData()['tempFile'];
93 $uploadResult->setTempFile($tempFile);
94 $uploadResult->setToken($this->generateToken($tempFile));
95
96 $controller->onUploadStart($uploadResult);
97 if (!$uploadResult->isSuccess())
98 {
99 return $this->handleUploadError($uploadResult, $controller);
100 }
101 }
102 else
103 {
104 if (empty($token))
105 {
106 return $this->handleUploadError(
107 $uploadResult->addError(new UploaderError(UploaderError::EMPTY_TOKEN)),
109 );
110 }
111
112 $guid = $this->getGuidFromToken($token);
113 if (!$guid)
114 {
115 return $this->handleUploadError(
116 $uploadResult->addError(new UploaderError(UploaderError::INVALID_SIGNATURE)),
118 );
119 }
120
121 $tempFile = TempFileTable::getList([
122 'filter' => [
123 '=GUID' => $guid,
124 '=UPLOADED' => false,
125 ],
126 ])->fetchObject();
127
128 if (!$tempFile)
129 {
130 return $this->handleUploadError(
131 $uploadResult->addError(new UploaderError(UploaderError::UNKNOWN_TOKEN)),
133 );
134 }
135
136 $uploadResult->setTempFile($tempFile);
137 $uploadResult->setToken($token);
138
139 $appendResult = $tempFile->append($chunk);
140 if (!$appendResult->isSuccess())
141 {
142 return $this->handleUploadError($uploadResult->addErrors($appendResult->getErrors()), $controller);
143 }
144 }
145
146 if ($uploadResult->isSuccess() && $chunk->isLast())
147 {
148 $commitResult = $tempFile->commit($controller->getCommitOptions());
149 if (!$commitResult->isSuccess())
150 {
151 return $this->handleUploadError($uploadResult->addErrors($commitResult->getErrors()), $controller);
152 }
153
154 $fileInfo = $this->createFileInfo($uploadResult->getToken());
155 $uploadResult->setFileInfo($fileInfo);
156 $uploadResult->setDone(true);
157
158 $controller->onUploadComplete($uploadResult);
159 if (!$uploadResult->isSuccess())
160 {
161 return $this->handleUploadError($uploadResult, $controller);
162 }
163 }
164
165 return $uploadResult;
166 }
167
168 private function handleUploadError(UploadResult $uploadResult, UploaderController $controller): UploadResult
169 {
170 $controller->onUploadError($uploadResult);
171
172 if (!$uploadResult->isSuccess())
173 {
174 $tempFile = $uploadResult->getTempFile();
175 if ($tempFile !== null && $tempFile->state !== State::DELETED)
176 {
177 $tempFile->delete();
178 }
179 }
180
181 return $uploadResult;
182 }
183
184 public function generateToken(TempFile $tempFile): string
185 {
186 $guid = $tempFile->getGuid();
187 $salt = $this->getTokenSalt([$guid]);
188 $signer = new Signer();
189
190 return $signer->sign($guid, $salt);
191 }
192
193 private function getGuidFromToken(string $token): ?string
194 {
195 $parts = explode('.', $token, 2);
196 if (count($parts) !== 2)
197 {
198 return null;
199 }
200
201 [$guid, $signature] = $parts;
202 if (empty($guid) || empty($signature))
203 {
204 return null;
205 }
206
207 $salt = $this->getTokenSalt([$guid]);
208 $signer = new Signer();
209
210 if (!$signer->validate($guid, $signature, $salt))
211 {
212 return null;
213 }
214
215 return $guid;
216 }
217
218 private function getTokenSalt($params = []): string
219 {
220 $controller = $this->getController();
221 $options = $controller->getOptions();
222 ksort($options);
223
224 $fingerprint =
225 $controller instanceof CustomFingerprint
226 ? $controller->getFingerprint()
227 : (string)\bitrix_sessid()
228 ;
229
230 return md5(serialize(
231 array_merge(
232 $params,
233 [
234 $controller->getName(),
235 $options,
236 $fingerprint,
237 ]
238 )
239 ));
240 }
241
242 public function load(array $ids): LoadResultCollection
243 {
244 $controller = $this->getController();
245 if ($controller instanceof CustomLoad)
246 {
247 return $controller->load($ids);
248 }
249
250 $results = new LoadResultCollection();
251 [$bfileIds, $tempFileIds] = $this->splitIds($ids);
252 $fileOwnerships = new FileOwnershipCollection($bfileIds);
253
254 // Files from b_file
255 if ($fileOwnerships->count() > 0)
256 {
257 $controller = $this->getController();
258 if ($controller->canView())
259 {
260 $controller->verifyFileOwner($fileOwnerships);
261 }
262
263 foreach ($fileOwnerships as $fileOwnership)
264 {
265 if ($fileOwnership->isOwn())
266 {
267 $loadResult = $this->loadFile($fileOwnership->getId());
268 }
269 else
270 {
271 $loadResult = new LoadResult($fileOwnership->getId());
272 $loadResult->addError(new UploaderError(UploaderError::FILE_LOAD_ACCESS_DENIED));
273 }
274
275 $results->add($loadResult);
276 }
277 }
278
279 // Temp Files
280 if (count($tempFileIds) > 0)
281 {
282 foreach ($tempFileIds as $tempFileId)
283 {
284 $loadResult = $this->loadTempFile($tempFileId);
285 $results->add($loadResult);
286 }
287 }
288
289 return $results;
290 }
291
292 public function getFileInfo(array $ids): array
293 {
294 $result = [];
295 $loadResults = $this->load(array_unique($ids));
296 foreach ($loadResults as $loadResult)
297 {
298 if ($loadResult->isSuccess() && $loadResult->getFile() !== null)
299 {
300 $result[] = $loadResult->getFile()->jsonSerialize();
301 }
302 }
303
304 return $result;
305 }
306
307 public function remove(array $ids): RemoveResultCollection
308 {
309 $controller = $this->getController();
310 if ($controller instanceof CustomRemove)
311 {
312 return $controller->remove($ids);
313 }
314
315 $results = new RemoveResultCollection();
316 [$bfileIds, $tempFileIds] = $this->splitIds($ids);
317
318 // Files from b_file
319 if (count($bfileIds) > 0)
320 {
321 $fileOwnerships = new FileOwnershipCollection($bfileIds);
322 if ($controller->canRemove())
323 {
324 $controller->verifyFileOwner($fileOwnerships);
325 }
326
327 foreach ($fileOwnerships as $fileOwnership)
328 {
329 $removeResult = new RemoveResult($fileOwnership->getId());
330 if ($fileOwnership->isOwn())
331 {
332 // TODO: remove file
333 }
334 else
335 {
336 $removeResult->addError(new UploaderError(UploaderError::FILE_REMOVE_ACCESS_DENIED));
337 }
338
339 $results->add($removeResult);
340 }
341 }
342
343 // Temp Files
344 if (count($tempFileIds) > 0)
345 {
346 foreach ($tempFileIds as $tempFileId)
347 {
348 $removeResult = new RemoveResult($tempFileId);
349 $results->add($removeResult);
350
351 $guid = $this->getGuidFromToken($tempFileId);
352 if (!$guid)
353 {
354 $removeResult->addError(new UploaderError(UploaderError::INVALID_SIGNATURE));
355 continue;
356 }
357
358 $tempFile = TempFileTable::getList([
359 'filter' => [
360 '=GUID' => $guid,
361 ],
362 ])->fetchObject();
363
364 if ($tempFile)
365 {
366 $tempFile->delete();
367 }
368 }
369 }
370
371 return $results;
372 }
373
374 public function getPendingFiles(array $tempFileIds): PendingFileCollection
375 {
376 $pendingFiles = new PendingFileCollection();
377 foreach ($tempFileIds as $tempFileId)
378 {
379 if (!is_string($tempFileId) || empty($tempFileId))
380 {
381 continue;
382 }
383
384 $pendingFile = new PendingFile($tempFileId);
385 $pendingFiles->add($pendingFile);
386
387 $guid = $this->getGuidFromToken($tempFileId);
388 if (!$guid)
389 {
390 $pendingFile->addError(new UploaderError(UploaderError::INVALID_SIGNATURE));
391
392 continue;
393 }
394
395 $tempFile = TempFileTable::getList([
396 'filter' => [
397 '=GUID' => $guid,
398 '=UPLOADED' => true,
399 ],
400 ])->fetchObject();
401
402 if (!$tempFile)
403 {
404 $pendingFile->addError(new UploaderError(UploaderError::UNKNOWN_TOKEN));
405
406 continue;
407 }
408
409 $pendingFile->setTempFile($tempFile);
410 }
411
412 return $pendingFiles;
413 }
414
415 private function loadFile(int $fileId): LoadResult
416 {
417 $result = new LoadResult($fileId);
418 if ($fileId < 1)
419 {
421 }
422
423 $fileInfo = $this->createFileInfo($fileId);
424 if ($fileInfo)
425 {
426 $result->setFile($fileInfo);
427 }
428 else
429 {
430 return $result->addError(new UploaderError(UploaderError::FILE_LOAD_FAILED));
431 }
432
433 return $result;
434 }
435
436 private function loadTempFile(string $tempFileId): LoadResult
437 {
438 $result = new LoadResult($tempFileId);
439 $guid = $this->getGuidFromToken($tempFileId);
440 if (!$guid)
441 {
442 return $result->addError(new UploaderError(UploaderError::INVALID_SIGNATURE));
443 }
444
445 $tempFile = TempFileTable::getList([
446 'filter' => [
447 '=GUID' => $guid,
448 '=UPLOADED' => true,
449 ],
450 ])->fetchObject();
451
452 if (!$tempFile)
453 {
454 return $result->addError(new UploaderError(UploaderError::UNKNOWN_TOKEN));
455 }
456
457 $fileInfo = $this->createFileInfo($tempFileId);
458 if ($fileInfo)
459 {
460 $result->setFile($fileInfo);
461 }
462 else
463 {
464 return $result->addError(new UploaderError(UploaderError::FILE_LOAD_FAILED));
465 }
466
467 return $result;
468 }
469
470 private function createFileInfo($fileId): ?FileInfo
471 {
472 $fileInfo = is_int($fileId) ? FileInfo::createFromBFile($fileId) : FileInfo::createFromTempFile($fileId);
473 if ($fileInfo)
474 {
475 $downloadUrl = (string)UrlManager::getDownloadUrl($this->getController(), $fileInfo);
476 $fileInfo->setDownloadUrl($downloadUrl);
477
478 $fileInfo->setViewerAttrs($this->prepareViewerAttrs($fileInfo, $downloadUrl));
479
480 if ($fileInfo->isImage())
481 {
482 $config = $this->getController()->getConfiguration();
483 if ($config->shouldTreatOversizeImageAsFile())
484 {
485 $treatImageAsFile = $config->shouldTreatImageAsFile($fileInfo);
486 $fileInfo->setTreatImageAsFile($treatImageAsFile);
487 }
488
489 if (!$fileInfo->shouldTreatImageAsFile())
490 {
491 $rectangle = PreviewImage::getSize($fileInfo);
492 $previewUrl = (string)UrlManager::getPreviewUrl($this->getController(), $fileInfo);
493 $fileInfo->setPreviewUrl($previewUrl, $rectangle->getWidth(), $rectangle->getHeight());
494 }
495 }
496 }
497
498 return $fileInfo;
499 }
500
501 private function prepareViewerAttrs(FileInfo $fileInfo, string $downloadUrl): array
502 {
503 $fileData = [
504 'ID' => $fileInfo->getId(),
505 'CONTENT_TYPE' => $fileInfo->getContentType(),
506 'ORIGINAL_NAME' => $fileInfo->getName(),
507 'WIDTH' => $fileInfo->getWidth(),
508 'HEIGHT' => $fileInfo->getHeight(),
509 'FILE_SIZE' => $fileInfo->getSize(),
510 ];
511
512 return ItemAttributes::buildByFileData($fileData, $downloadUrl)
513 ->setTitle($fileInfo->getName())
514 ->toDataSet()
515 ;
516 }
517
518 private function splitIds(array $ids): array
519 {
520 $fileIds = [];
521 $tempFileIds = [];
522 foreach ($ids as $id)
523 {
524 if (is_numeric($id))
525 {
526 $fileIds[] = (int)$id;
527 }
528 else
529 {
530 $tempFileIds[] = (string)$id;
531 }
532 }
533
534 return [$fileIds, $tempFileIds];
535 }
536}
static getList(array $parameters=array())
Определения datamanager.php:431
getFileSize()
Определения Chunk.php:193
setWidth(int $width)
Определения Chunk.php:228
validate(Configuration $config)
Определения Chunk.php:281
setHeight(int $height)
Определения Chunk.php:238
getHeight()
Определения Chunk.php:233
static createFromBFile(int $id)
Определения FileInfo.php:31
static getSize(FileInfo $fileInfo, PreviewImageOptions $options=null)
Определения PreviewImage.php:10
static create(Chunk $chunk, UploaderController $controller)
Определения TempFile.php:14
load(array $ids)
Определения Uploader.php:242
generateToken(TempFile $tempFile)
Определения Uploader.php:184
__construct(UploaderController $controller)
Определения Uploader.php:16
getFileInfo(array $ids)
Определения Uploader.php:292
UploaderController $controller
Определения Uploader.php:14
getPendingFiles(array $tempFileIds)
Определения Uploader.php:374
static getDownloadUrl(UploaderController $controller, FileInfo $fileInfo)
Определения UrlManager.php:10
static getPreviewUrl(UploaderController $controller, FileInfo $fileInfo)
Определения UrlManager.php:18
$options
Определения commerceml2.php:49
</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
bitrix_sessid()
Определения tools.php:4656
$config
Определения quickway.php:69
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$width
Определения html.php:68
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$error
Определения subscription_card_product.php:20