1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
storage_service_google.php
См. документацию.
1<?php
3
5{
6 protected $new_end_point;
7
8 public function GetObject()
9 {
11 }
12
13 public function GetID()
14 {
15 return 'google_storage';
16 }
17
18 public function GetName()
19 {
20 return 'Google Storage';
21 }
22
23 public function GetLocationList()
24 {
25 return [
26 'EU' => 'Europe',
27 'US' => 'United States',
28 ];
29 }
30
31 public function GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
32 {
34 {
35 $arSettings = $_POST['SETTINGS'][$this->GetID()];
36 }
37 else
38 {
39 $arSettings = unserialize($arBucket['SETTINGS'], ['allowed_classes' => false]);
40 }
41
42 if (!is_array($arSettings))
43 {
44 $arSettings = ['PROJECT_ID' => '', 'ACCESS_KEY' => '', 'SECRET_KEY' => ''];
45 }
46
47 $htmlID = htmlspecialcharsbx($this->GetID());
48
49 $result = '
50 <tr id="SETTINGS_0_' . $htmlID . '" style="display:' . ($cur_SERVICE_ID == $this->GetID() || !$bServiceSet ? '' : 'none') . '" class="settings-tr adm-detail-required-field">
51 <td>' . GetMessage('CLO_STORAGE_GOOGLE_EDIT_PROJECT_ID') . ':</td>
52 <td><input type="hidden" name="SETTINGS[' . $htmlID . '][PROJECT_ID]" id="' . $htmlID . 'PROJECT_ID" value="' . htmlspecialcharsbx($arSettings['PROJECT_ID']) . '"><input type="text" size="55" name="' . $htmlID . 'INP_" id="' . $htmlID . 'INP_PROJECT_ID" value="' . htmlspecialcharsbx($arSettings['PROJECT_ID']) . '" ' . ($arBucket['READ_ONLY'] == 'Y' ? '"disabled"' : '') . ' onchange="BX(\'' . $htmlID . 'PROJECT_ID\').value = this.value"></td>
53 </tr>
54 <tr id="SETTINGS_1_' . $htmlID . '" style="display:' . ($cur_SERVICE_ID == $this->GetID() || !$bServiceSet ? '' : 'none') . '" class="settings-tr adm-detail-required-field">
55 <td>' . GetMessage('CLO_STORAGE_GOOGLE_EDIT_ACCESS_KEY') . ':</td>
56 <td><input type="hidden" name="SETTINGS[' . $htmlID . '][ACCESS_KEY]" id="' . $htmlID . 'ACCESS_KEY" value="' . htmlspecialcharsbx($arSettings['ACCESS_KEY']) . '"><input type="text" size="55" name="' . $htmlID . 'INP_ACCESS_KEY" id="' . $htmlID . 'INP_ACCESS_KEY" value="' . htmlspecialcharsbx($arSettings['ACCESS_KEY']) . '" ' . ($arBucket['READ_ONLY'] == 'Y' ? '"disabled"' : '') . ' onchange="BX(\'' . $htmlID . 'ACCESS_KEY\').value = this.value"></td>
57 </tr>
58 <tr id="SETTINGS_2_' . $htmlID . '" style="display:' . ($cur_SERVICE_ID == $this->GetID() || !$bServiceSet ? '' : 'none') . '" class="settings-tr adm-detail-required-field">
59 <td>' . GetMessage('CLO_STORAGE_GOOGLE_EDIT_SECRET_KEY') . ':</td>
60 <td><input type="hidden" name="SETTINGS[' . $htmlID . '][SECRET_KEY]" id="' . $htmlID . 'SECRET_KEY" value="' . htmlspecialcharsbx($arSettings['SECRET_KEY']) . '"><input type="text" size="55" name="' . $htmlID . 'INP_SECRET_KEY" id="' . $htmlID . 'INP_SECRET_KEY" value="' . htmlspecialcharsbx($arSettings['SECRET_KEY']) . '" autocomplete="off" ' . ($arBucket['READ_ONLY'] == 'Y' ? '"disabled"' : '') . ' onchange="BX(\'' . $htmlID . 'SECRET_KEY\').value = this.value"></td>
61 </tr>
62 <tr id="SETTINGS_3_' . $htmlID . '" style="display:' . ($cur_SERVICE_ID == $this->GetID() || !$bServiceSet ? '' : 'none') . '" class="settings-tr">
63 <td>&nbsp;</td>
64 <td>' . BeginNote() . GetMessage('CLO_STORAGE_GOOGLE_EDIT_HELP') . EndNote() . '</td>
65 </tr>
66 ';
67 return $result;
68 }
69
70 public function CheckSettings($arBucket, &$arSettings)
71 {
72 global $APPLICATION;
73 $aMsg = [];
74
75 $result = [
76 'PROJECT_ID' => is_array($arSettings) ? trim($arSettings['PROJECT_ID']) : '',
77 'ACCESS_KEY' => is_array($arSettings) ? trim($arSettings['ACCESS_KEY']) : '',
78 'SECRET_KEY' => is_array($arSettings) ? trim($arSettings['SECRET_KEY']) : '',
79 ];
80
81 if ($arBucket['READ_ONLY'] !== 'Y' && !mb_strlen($result['PROJECT_ID']))
82 {
83 $aMsg[] = ['id' => $this->GetID() . 'INP_PROJECT_ID', 'text' => GetMessage('CLO_STORAGE_GOOGLE_EMPTY_PROJECT_ID')];
84 }
85
86 if ($arBucket['READ_ONLY'] !== 'Y' && !mb_strlen($result['ACCESS_KEY']))
87 {
88 $aMsg[] = ['id' => $this->GetID() . 'INP_ACCESS_KEY', 'text' => GetMessage('CLO_STORAGE_GOOGLE_EMPTY_ACCESS_KEY')];
89 }
90
91 if ($arBucket['READ_ONLY'] !== 'Y' && !mb_strlen($result['SECRET_KEY']))
92 {
93 $aMsg[] = ['id' => $this->GetID() . 'INP_SECRET_KEY', 'text' => GetMessage('CLO_STORAGE_GOOGLE_EMPTY_SECRET_KEY')];
94 }
95
96 if (!empty($aMsg))
97 {
98 $e = new CAdminException($aMsg);
99 $APPLICATION->ThrowException($e);
100 return false;
101 }
102 else
103 {
104 $arSettings = $result;
105 }
106
107 return true;
108 }
109
110 public function CreateBucket($arBucket)
111 {
112 global $APPLICATION;
113
114 if ($arBucket['LOCATION'])
115 {
116 $content =
117 '<CreateBucketConfiguration>'
118 . '<LocationConstraint>' . $arBucket['LOCATION'] . '</LocationConstraint>'
119 . '</CreateBucketConfiguration>';
120 }
121 else
122 {
123 $content = '';
124 }
125
126 $response = $this->SendRequest(
127 $arBucket['SETTINGS']['ACCESS_KEY'],
128 $arBucket['SETTINGS']['SECRET_KEY'],
129 'PUT',
130 $arBucket['BUCKET'],
131 '/',
132 '',
133 $content,
134 [
135 'x-goog-project-id' => $arBucket['SETTINGS']['PROJECT_ID'],
136 ]
137 );
138
139 if ($this->status == 409/*Already exists*/)
140 {
141 $APPLICATION->ResetException();
142 return true;
143 }
144 elseif (is_array($response))
145 {
146 return true;
147 }
148 else
149 {
150 if (defined('BX_CLOUDS_ERROR_DEBUG'))
151 {
152 AddMessage2Log($this);
153 }
154 return false;
155 }
156 }
157
158 public function DeleteBucket($arBucket)
159 {
160 global $APPLICATION;
161
162 if ($arBucket['PREFIX'])
163 {
164 //Do not delete bucket if there is some files left
165 if (!$this->IsEmptyBucket($arBucket))
166 {
167 return false;
168 }
169
170 //Do not delete bucket if there is some files left in other prefixes
171 $arAllBucket = $arBucket;
172 $arBucket['PREFIX'] = '';
173 if (!$this->IsEmptyBucket($arAllBucket))
174 {
175 return true;
176 }
177 }
178
179 $response = $this->SendRequest(
180 $arBucket['SETTINGS']['ACCESS_KEY'],
181 $arBucket['SETTINGS']['SECRET_KEY'],
182 'DELETE',
183 $arBucket['BUCKET']
184 );
185
186 if ($this->status == 204/*No content*/ || $this->status == 404/*Not exists*/)
187 {
188 $APPLICATION->ResetException();
189 return true;
190 }
191 elseif (is_array($response))
192 {
193 return true;
194 }
195 else
196 {
197 if (defined('BX_CLOUDS_ERROR_DEBUG'))
198 {
199 AddMessage2Log($this);
200 }
201 return false;
202 }
203 }
204
205 public function IsEmptyBucket($arBucket)
206 {
207 global $APPLICATION;
208
209 $response = $this->SendRequest(
210 $arBucket['SETTINGS']['ACCESS_KEY'],
211 $arBucket['SETTINGS']['SECRET_KEY'],
212 'GET',
213 $arBucket['BUCKET'],
214 '/',
215 '?max-keys=1' . ($arBucket['PREFIX'] ? '&prefix=' . $arBucket['PREFIX'] : '')
216 );
217
218 if ($this->status == 404)
219 {
220 $APPLICATION->ResetException();
221 return true;
222 }
223 elseif (is_array($response))
224 {
225 return
226 !isset($response['ListBucketResult'])
227 || !is_array($response['ListBucketResult'])
228 || !isset($response['ListBucketResult']['#'])
229 || !is_array($response['ListBucketResult']['#'])
230 || !isset($response['ListBucketResult']['#']['Contents'])
231 || !is_array($response['ListBucketResult']['#']['Contents']);
232 }
233 else
234 {
235 return false;
236 }
237 }
238
245 public function GetFileSRC($arBucket, $arFile, $encoded = true)
246 {
247 if ($arBucket['CNAME'])
248 {
249 $host = $arBucket['CNAME'];
250 }
251 else
252 {
253 $host = $arBucket['BUCKET'] . '.commondatastorage.googleapis.com';
254 }
255
256 if (is_array($arFile))
257 {
258 $URI = ltrim($arFile['SUBDIR'] . '/' . $arFile['FILE_NAME'], '/');
259 }
260 else
261 {
262 $URI = ltrim($arFile, '/');
263 }
264
265 if ($arBucket['PREFIX'])
266 {
267 if (mb_substr($URI, 0, mb_strlen($arBucket['PREFIX']) + 1) !== $arBucket['PREFIX'] . '/')
268 {
269 $URI = $arBucket['PREFIX'] . '/' . $URI;
270 }
271 }
272
273 /* @var \Bitrix\Main\HttpRequest $request */
274 $request = \Bitrix\Main\Context::getCurrent()->getRequest();
275 $proto = $request->isHttps() ? 'https' : 'http';
276
277 if ($encoded)
278 {
279 return $proto . '://' . $host . '/' . CCloudUtil::URLEncode($URI, 'UTF-8', true);
280 }
281 else
282 {
283 return $proto . '://' . $host . '/' . $URI;
284 }
285 }
286
287 public function FileExists($arBucket, $filePath)
288 {
289 global $APPLICATION;
290
291 if ($arBucket['PREFIX'])
292 {
293 if (mb_substr($filePath, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
294 {
295 $filePath = '/' . $arBucket['PREFIX'] . '/' . ltrim($filePath, '/');
296 }
297 }
298 $filePath = CCloudUtil::URLEncode($filePath, 'UTF-8', true);
299
300 $this->SendRequest(
301 $arBucket['SETTINGS']['ACCESS_KEY'],
302 $arBucket['SETTINGS']['SECRET_KEY'],
303 'HEAD',
304 $arBucket['BUCKET'],
305 $filePath
306 );
307
308 if ($this->status == 200)
309 {
310 if (isset($this->headers['Content-Length']) && $this->headers['Content-Length'] > 0)
311 {
312 return $this->headers['Content-Length'];
313 }
314 else
315 {
316 return true;
317 }
318 }
319 elseif ($this->status == 206)
320 {
321 $APPLICATION->ResetException();
322 return true;
323 }
324 else//if($this->status == 404)
325 {
326 $APPLICATION->ResetException();
327 return false;
328 }
329 }
330
331 public function FileCopy($arBucket, $arFile, $filePath)
332 {
333 global $APPLICATION;
334
335 if ($arBucket['PREFIX'])
336 {
337 if (mb_substr($filePath, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
338 {
339 $filePath = '/' . $arBucket['PREFIX'] . '/' . ltrim($filePath, '/');
340 }
341 }
342
343 $this->SendRequest(
344 $arBucket['SETTINGS']['ACCESS_KEY'],
345 $arBucket['SETTINGS']['SECRET_KEY'],
346 'PUT',
347 $arBucket['BUCKET'],
348 CCloudUtil::URLEncode($filePath, 'UTF-8', true),
349 '',
350 '',
351 [
352 'x-goog-acl' => 'public-read',
353 'x-goog-copy-source' => CCloudUtil::URLEncode('/' . $arBucket['BUCKET'] . '/' . ($arBucket['PREFIX'] ? $arBucket['PREFIX'] . '/' : '') . ($arFile['SUBDIR'] ? $arFile['SUBDIR'] . '/' : '') . $arFile['FILE_NAME'], 'UTF-8', true),
354 'Content-Type' => $arFile['CONTENT_TYPE']
355 ]
356 );
357
358 if ($this->status == 200)
359 {
360 return $this->GetFileSRC($arBucket, $filePath);
361 }
362 else//if($this->status == 404)
363 {
364 if (defined('BX_CLOUDS_ERROR_DEBUG'))
365 {
366 AddMessage2Log($this);
367 }
368 $APPLICATION->ResetException();
369 return false;
370 }
371 }
372
373 public function DeleteFile($arBucket, $filePath)
374 {
375 global $APPLICATION;
376
377 if ($arBucket['PREFIX'])
378 {
379 if (mb_substr($filePath, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
380 {
381 $filePath = '/' . $arBucket['PREFIX'] . '/' . ltrim($filePath, '/');
382 }
383 }
384 $filePath = CCloudUtil::URLEncode($filePath, 'UTF-8', true);
385
386 $this->SendRequest(
387 $arBucket['SETTINGS']['ACCESS_KEY'],
388 $arBucket['SETTINGS']['SECRET_KEY'],
389 'DELETE',
390 $arBucket['BUCKET'],
391 $filePath
392 );
393
394 if ($this->status == 204 || $this->status == 404)
395 {
396 $APPLICATION->ResetException();
397 return true;
398 }
399 else
400 {
401 if (defined('BX_CLOUDS_ERROR_DEBUG'))
402 {
403 AddMessage2Log($this);
404 }
405 $APPLICATION->ResetException();
406 return false;
407 }
408 }
409
410 public function SaveFile($arBucket, $filePath, $arFile)
411 {
412 global $APPLICATION;
413
414 if ($arBucket['PREFIX'])
415 {
416 if (mb_substr($filePath, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
417 {
418 $filePath = '/' . $arBucket['PREFIX'] . '/' . ltrim($filePath, '/');
419 }
420 }
421 $filePath = CCloudUtil::URLEncode($filePath, 'UTF-8', true);
422
423 $this->SendRequest(
424 $arBucket['SETTINGS']['ACCESS_KEY'],
425 $arBucket['SETTINGS']['SECRET_KEY'],
426 'PUT',
427 $arBucket['BUCKET'],
428 $filePath,
429 '',
430 $arFile['content'] ?? fopen($arFile['tmp_name'], 'rb'),
431 [
432 'x-goog-acl' => 'public-read',
433 'Content-Type' => $arFile['type'],
434 'Content-Length' => (array_key_exists('content', $arFile) ? strlen($arFile['content']) : filesize($arFile['tmp_name'])),
435 ]
436 );
437
438 if ($this->status == 200)
439 {
440 return true;
441 }
442 else
443 {
444 if (defined('BX_CLOUDS_ERROR_DEBUG'))
445 {
446 AddMessage2Log($this);
447 }
448 $APPLICATION->ResetException();
449 return false;
450 }
451 }
452
453 public function ListFiles($arBucket, $filePath, $bRecursive = false)
454 {
455 global $APPLICATION;
456
457 $result = [
458 'dir' => [],
459 'file' => [],
460 'file_size' => [],
461 'file_mtime' => [],
462 'file_hash' => [],
463 'last_key' => '',
464 ];
465
466 $filePath = trim($filePath, '/');
467 if ($filePath !== '')
468 {
469 $filePath .= '/';
470 }
471
472 if ($arBucket['PREFIX'])
473 {
474 if (mb_substr($filePath, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
475 {
476 $filePath = $arBucket['PREFIX'] . '/' . ltrim($filePath, '/');
477 }
478 }
479 $filePath = str_replace(' ', '+', $filePath);
480
481 $marker = '';
482 while (true)
483 {
484 $response = $this->SendRequest(
485 $arBucket['SETTINGS']['ACCESS_KEY'],
486 $arBucket['SETTINGS']['SECRET_KEY'],
487 'GET',
488 $arBucket['BUCKET'],
489 '/',
490 '?' . ($bRecursive ? '' : 'delimiter=/&') . 'prefix=' . rawurlencode($filePath) . '&marker=' . rawurlencode($marker)
491 );
492 if (
493 $this->status == 200
494 && is_array($response)
495 && isset($response['ListBucketResult'])
496 && is_array($response['ListBucketResult'])
497 && isset($response['ListBucketResult']['#'])
498 && is_array($response['ListBucketResult']['#'])
499 )
500 {
501 if (
502 isset($response['ListBucketResult']['#']['CommonPrefixes'])
503 && is_array($response['ListBucketResult']['#']['CommonPrefixes'])
504 )
505 {
506 foreach ($response['ListBucketResult']['#']['CommonPrefixes'] as $a)
507 {
508 $dir_name = mb_substr(rtrim($a['#']['Prefix'][0]['#'], '/'), mb_strlen($filePath));
509 $result['dir'][] = $dir_name;
510 }
511 }
512
513 if (
514 isset($response['ListBucketResult']['#']['Contents'])
515 && is_array($response['ListBucketResult']['#']['Contents'])
516 )
517 {
518 foreach ($response['ListBucketResult']['#']['Contents'] as $a)
519 {
520 $file_name = mb_substr($a['#']['Key'][0]['#'], mb_strlen($filePath));
521 $result['file'][] = $file_name;
522 $result['file_size'][] = $a['#']['Size'][0]['#'];
523 $result['file_mtime'][] = mb_substr($a['#']['LastModified'][0]['#'], 0, 19);
524 $result['file_hash'][] = trim($a['#']['ETag'][0]['#'], '"');
525 $result['last_key'] = $file_name;
526 }
527 }
528
529 if (
530 isset($response['ListBucketResult']['#']['IsTruncated'])
531 && is_array($response['ListBucketResult']['#']['IsTruncated'])
532 && $response['ListBucketResult']['#']['IsTruncated'][0]['#'] === 'true'
533 && $response['ListBucketResult']['#']['NextMarker'][0]['#'] <> ''
534 )
535 {
536 $marker = $response['ListBucketResult']['#']['NextMarker'][0]['#'];
537 continue;
538 }
539 else
540 {
541 break;
542 }
543 }
544 else
545 {
546 if (defined('BX_CLOUDS_ERROR_DEBUG'))
547 {
548 AddMessage2Log($this);
549 }
550 $APPLICATION->ResetException();
551 return false;
552 }
553 }
554
555 return $result;
556 }
557
558 protected function StartUpload($arBucket, $filePath, $ContentType)
559 {
560 $filePath = '/' . trim($filePath, '/');
561 if ($arBucket['PREFIX'])
562 {
563 if (mb_substr($filePath, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
564 {
565 $filePath = '/' . $arBucket['PREFIX'] . $filePath;
566 }
567 }
568 $filePathU = CCloudUtil::URLEncode($filePath, 'UTF-8', true);
569
570 $this->SendRequest(
571 $arBucket['SETTINGS']['ACCESS_KEY'],
572 $arBucket['SETTINGS']['SECRET_KEY'],
573 'POST',
574 $arBucket['BUCKET'],
575 $filePathU,
576 '',
577 '',
578 [
579 'x-goog-acl' => 'public-read',
580 'x-goog-resumable' => 'start',
581 'Content-Type' => $ContentType,
582 ]
583 );
584
585 if (
586 $this->status == 201
587 && is_array($this->headers)
588 && isset($this->headers['Location'])
589 && preg_match('/upload_id=(.*)$/', $this->headers['Location'], $match)
590 )
591 {
592 return [
593 'filePath' => $filePath,
594 'filePos' => 0,
595 'upload_id' => $match[1],
596 ];
597 }
598
599 if (defined('BX_CLOUDS_ERROR_DEBUG'))
600 {
601 AddMessage2Log($this);
602 }
603
604 return false;
605 }
606
607 public function InitiateMultipartUpload($arBucket, &$NS, $filePath, $fileSize, $ContentType)
608 {
609 $upload_info = $this->StartUpload($arBucket, $filePath, $ContentType);
610 if ($upload_info)
611 {
612 $upload_info['fileSize'] = $fileSize;
613 $upload_info['ContentType'] = $ContentType;
614 $NS = $upload_info;
615 return true;
616 }
617 else
618 {
619 return false;
620 }
621 }
622
623 public function GetMinUploadPartSize()
624 {
625 return 5 * 1024 * 1024; //5MB
626 }
627
628 private function UploadRange($filePathU, $arBucket, &$NS, $data, $pos)
629 {
630 $this->SendRequest(
631 $arBucket['SETTINGS']['ACCESS_KEY'],
632 $arBucket['SETTINGS']['SECRET_KEY'],
633 'PUT',
634 $arBucket['BUCKET'],
635 $filePathU . '?upload_id=' . rawurlencode($NS['upload_id']),
636 '',
637 '',
638 [
639 'Content-Range' => 'bytes */' . $NS['fileSize'],
640 ]
641 );
642
643 $data_len = strlen($data);
644
645 $this->SendRequest(
646 $arBucket['SETTINGS']['ACCESS_KEY'],
647 $arBucket['SETTINGS']['SECRET_KEY'],
648 'PUT',
649 $arBucket['BUCKET'],
650 $filePathU . '?upload_id=' . rawurlencode($NS['upload_id']),
651 '',
652 $data,
653 [
654 'Content-Range' => 'bytes ' . $pos . '-' . ($pos + $data_len - 1) . '/' . $NS['fileSize'],
655 ]
656 );
657 }
658
659 public function UploadPartNo($arBucket, &$NS, $data, $part_no)
660 {
661 global $APPLICATION;
662 $part_no = intval($part_no);
663
664 $found = false;
665 if (isset($NS['Parts']))
666 {
667 foreach ($NS['Parts'] as $first_part_no => $part)
668 {
669 if ($part['part_no'] === ($part_no - 1))
670 {
671 $found = $first_part_no;
672 break;
673 }
674 }
675 }
676 else
677 {
678 $NS['Parts'] = [];
679 }
680
681 if ($found === false)
682 {
683 $partFileName = '/' . trim($NS['filePath'], '/') . '.tmp' . $part_no;
684 if ($arBucket['PREFIX'])
685 {
686 if (mb_substr($partFileName, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
687 {
688 $partFileName = '/' . $arBucket['PREFIX'] . $partFileName;
689 }
690 }
691 $upload_info = $this->StartUpload($arBucket, $partFileName, $NS['ContentType']);
692 if ($upload_info)
693 {
694 $upload_info['fileSize'] = '*';
695 $upload_info['part_no'] = $part_no;
696 $found = $part_no;
697 $NS['Parts'][$part_no] = $upload_info;
698 ksort($NS['Parts']);
699 }
700 else
701 {
702 return false;
703 }
704 }
705
706 $NS['Parts'][$found]['part_no'] = $part_no;
707 if (
708 (isset($NS['Parts'][$part_no + 1]))
709 || (($NS['Parts'][$found]['part_no'] * $this->GetMinUploadPartSize() + $this->GetMinUploadPartSize()) >= $NS['fileSize'])
710 )
711 {
712 $data_len = strlen($data);
713 $NS['Parts'][$found]['fileSize'] = $NS['Parts'][$found]['filePos'] + $data_len;
714 }
715
716 $filePath = $NS['Parts'][$found]['filePath'];
717 $filePathU = CCloudUtil::URLEncode($filePath, 'UTF-8', true);
718
719 $this->UploadRange($filePathU, $arBucket, $NS['Parts'][$found], $data, $NS['Parts'][$found]['filePos']);
720
721 if (
722 $this->status == 308
723 && is_array($this->headers)
724 && preg_match('/^bytes=(\\d+)-(\\d+)$/', $this->headers['Range'], $match)
725 )
726 {
727 $APPLICATION->ResetException();
728 $NS['Parts'][$found]['filePos'] = $match[2] + 1;
729 return true;
730 }
731 elseif ($this->status == 200)
732 {
733 return true;
734 }
735 else
736 {
737 if (defined('BX_CLOUDS_ERROR_DEBUG'))
738 {
739 AddMessage2Log($this);
740 }
741 return false;
742 }
743 }
744
745 public function UploadPart($arBucket, &$NS, $data)
746 {
747 global $APPLICATION;
748
749 $filePath = '/' . trim($NS['filePath'], '/');
750 if ($arBucket['PREFIX'])
751 {
752 if (mb_substr($filePath, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
753 {
754 $filePath = '/' . $arBucket['PREFIX'] . $filePath;
755 }
756 }
757 $filePathU = CCloudUtil::URLEncode($filePath, 'UTF-8', true);
758
759 $this->UploadRange($filePathU, $arBucket, $NS, $data, $NS['filePos']);
760
761 if (
762 $this->status == 308
763 && is_array($this->headers)
764 && preg_match('/^bytes=(\\d+)-(\\d+)$/', $this->headers['Range'], $match)
765 )
766 {
767 $APPLICATION->ResetException();
768 $NS['filePos'] = $match[2] + 1;
769 return true;
770 }
771 elseif ($this->status == 200)
772 {
773 return true;
774 }
775 else
776 {
777 if (defined('BX_CLOUDS_ERROR_DEBUG'))
778 {
779 AddMessage2Log($this);
780 }
781 return false;
782 }
783 }
784
785 public function CompleteMultipartUpload($arBucket, &$NS)
786 {
787 if (isset($NS['Parts']))
788 {
789 // https://cloud.google.com/storage/docs/xml-api/put-object-compose
790 $filePath = '/' . trim($NS['filePath'], '/');
791 if ($arBucket['PREFIX'])
792 {
793 if (mb_substr($filePath, 0, mb_strlen($arBucket['PREFIX']) + 2) !== '/' . $arBucket['PREFIX'] . '/')
794 {
795 $filePath = '/' . $arBucket['PREFIX'] . $filePath;
796 }
797 }
798 $filePathU = CCloudUtil::URLEncode($filePath, 'UTF-8', true);
799
800 $xml = '<ComposeRequest>';
801 foreach ($NS['Parts'] as $part)
802 {
803 $xml .= '<Component><Name>' . ltrim($part['filePath'], '/') . '</Name></Component>';
804 }
805 $xml .= '</ComposeRequest>';
806
807 $this->SendRequest(
808 $arBucket['SETTINGS']['ACCESS_KEY'],
809 $arBucket['SETTINGS']['SECRET_KEY'],
810 'PUT',
811 $arBucket['BUCKET'],
812 $filePathU . '?compose',
813 '',
814 $xml,
815 [
816 'x-goog-acl' => 'public-read',
817 'Content-Type' => $NS['ContentType'],
818 ]
819 );
820
821 if ($this->status == 200)
822 {
823 foreach ($NS['Parts'] as $part)
824 {
825 $this->DeleteFile($arBucket, $part['filePath']);
826 }
827 return true;
828 }
829 else
830 {
831 if (defined('BX_CLOUDS_ERROR_DEBUG'))
832 {
833 AddMessage2Log($this);
834 }
835 return false;
836 }
837 }
838 return true;
839 }
840
841 public function SendRequest($access_key, $secret_key, $verb, $bucket, $file_name='/', $params='', $content='', $additional_headers=[])
842 {
843 global $APPLICATION;
844 $this->status = 0;
845
846 if (isset($additional_headers['Content-Type']))
847 {
848 $ContentType = $additional_headers['Content-Type'];
849 unset($additional_headers['Content-Type']);
850 }
851 else
852 {
853 $ContentType = $content ? 'text/plain' : '';
854 }
855
856 if (!array_key_exists('x-goog-api-version', $additional_headers))
857 {
858 $additional_headers['x-goog-api-version'] = '1';
859 }
860
861 $RequestMethod = $verb;
862 $RequestURI = $file_name;
863 $RequestDATE = gmdate('D, d M Y H:i:s', time()) . ' GMT';
864
865 //Prepare Signature
866 $CanonicalizedAmzHeaders = '';
867 ksort($additional_headers);
868 foreach ($additional_headers as $key => $value)
869 {
870 if (preg_match('/^x-goog-/', $key))
871 {
872 $CanonicalizedAmzHeaders .= $key . ':' . $value . "\n";
873 }
874 }
875
876 $CanonicalizedResource = '/' . $bucket . $RequestURI;
877
878 $StringToSign = $RequestMethod . "\n\n"
879 . $ContentType . "\n"
880 . $RequestDATE . "\n"
881 . $CanonicalizedAmzHeaders . $CanonicalizedResource
882 ;
883
884 $Signature = base64_encode($this->hmacsha1($StringToSign, $secret_key));
885 $Authorization = 'GOOG1 ' . $access_key . ':' . $Signature;
886
888 'redirect' => false,
889 'streamTimeout' => $this->streamTimeout,
890 ]);
891 if (isset($additional_headers['option-file-result']))
892 {
893 $request->setOutputStream($additional_headers['option-file-result']);
894 }
895
896 $request->setHeader('Date', $RequestDATE);
897 $request->setHeader('Authorization', $Authorization);
898 foreach ($additional_headers as $key => $value)
899 {
900 if (!preg_match('/^option-/', $key))
901 {
902 $request->setHeader($key, $value);
903 }
904 }
905
906 if (
907 $this->new_end_point
908 && preg_match('#^(http|https)://' . preg_quote($bucket, '#') . '(.+)/#', $this->new_end_point, $match))
909 {
910 $host = $match[2];
911 }
912 else
913 {
914 $host = $bucket . '.commondatastorage.googleapis.com';
915 }
916
917 $was_end_point = $this->new_end_point;
918 $this->new_end_point = '';
919
920 $this->status = 0;
921 $this->host = $host;
922 $this->verb = $RequestMethod;
923 $this->url = 'http://' . $host . $RequestURI . $params;
924 $this->headers = [];
925 $this->errno = 0;
926 $this->errstr = '';
927 $this->result = '';
928
929 $stime = 0;
930 $logRequest = false;
931 if (defined('BX_CLOUDS_TRACE') && $verb !== 'GET' && $verb !== 'HEAD')
932 {
933 $stime = microtime(1);
934 $logRequest = [
935 'request_id' => md5((string)mt_rand()),
936 'portal' => $_SERVER['HTTP_HOST'],
937 'verb' => $this->verb,
938 'url' => $this->url,
939 ];
940 AddMessage2Log(json_encode($logRequest), 'clouds', 20);
941 }
942
943 $request->setHeader('Content-type', $ContentType);
944 $request->query($this->verb, $this->url, $content);
945
946 $this->status = $request->getStatus();
947 foreach ($request->getHeaders() as $key => $value)
948 {
949 $this->headers[$key] = is_array($value) ? $value[0] : $value;
950 }
951 $this->errstr = implode("\n", $request->getError());
952 $this->errno = $this->errstr ? 255 : 0;
953 $this->result = $request->getResult();
954
955 if ($logRequest)
956 {
957 $logRequest['status'] = $this->status;
958 $logRequest['time'] = round(microtime(true) - $stime, 6);
959 $logRequest['headers'] = $this->headers;
960 AddMessage2Log(json_encode($logRequest), 'clouds', 0);
961 }
962
963 if ($this->status == 200)
964 {
965 if (isset($additional_headers['option-raw-result']))
966 {
967 return $this->result;
968 }
969 elseif ($this->result)
970 {
971 $obXML = new CDataXML;
972 $text = preg_replace('/<' . '\\?XML.*?\\?' . '>/i', '', $this->result);
973 if ($obXML->LoadString($text))
974 {
975 $arXML = $obXML->GetArray();
976 if (is_array($arXML))
977 {
978 return $arXML;
979 }
980 }
981 //XML parse error
982 $APPLICATION->ThrowException(GetMessage('CLO_STORAGE_GOOGLE_XML_PARSE_ERROR', ['#errno#' => 1]));
983 return false;
984 }
985 else
986 {
987 //Empty success result
988 return [];
989 }
990 }
991 elseif (
992 $this->status == 307 //Temporary redirect
993 && isset($this->headers['Location'])
994 && !$was_end_point //No recurse yet
995 )
996 {
997 $this->new_end_point = $this->headers['Location'];
998 return $this->SendRequest(
1000 $secret_key,
1001 $verb,
1002 $bucket,
1003 $file_name,
1004 $params,
1005 $content,
1006 $additional_headers
1007 );
1008 }
1009 elseif ($this->status > 0)
1010 {
1011 if ($this->result)
1012 {
1013 $obXML = new CDataXML;
1014 if ($obXML->LoadString($this->result))
1015 {
1016 $arXML = $obXML->GetArray();
1017 if (is_array($arXML) && is_string($arXML['Error']['#']['Message'][0]['#']))
1018 {
1019 $APPLICATION->ThrowException(GetMessage('CLO_STORAGE_GOOGLE_XML_ERROR', ['#errmsg#' => trim($arXML['Error']['#']['Message'][0]['#'], '.')]));
1020 return false;
1021 }
1022 }
1023 }
1024 $APPLICATION->ThrowException(GetMessage('CLO_STORAGE_GOOGLE_XML_PARSE_ERROR', ['#errno#' => 2]));
1025 return false;
1026 }
1027 else
1028 {
1029 $APPLICATION->ThrowException(GetMessage('CLO_STORAGE_GOOGLE_XML_PARSE_ERROR', ['#errno#' => 3]));
1030 return false;
1031 }
1032 }
1033
1034 public function hmacsha1($data, $key)
1035 {
1036 if (mb_strlen($key) > 64)
1037 {
1038 $key = pack('H*', sha1($key));
1039 }
1040 $key = str_pad($key, 64, chr(0x00));
1041 $ipad = str_repeat(chr(0x36), 64);
1042 $opad = str_repeat(chr(0x5c), 64);
1043 $hmac = pack('H*', sha1(($key ^ $opad) . pack('H*', sha1(($key ^ $ipad) . $data))));
1044 return $hmac;
1045 }
1046}
global $APPLICATION
Определения include.php:80
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
Определения catalog_reindex.php:36
DeleteFile($arBucket, $filePath)
Определения storage_service_google.php:373
StartUpload($arBucket, $filePath, $ContentType)
Определения storage_service_google.php:558
InitiateMultipartUpload($arBucket, &$NS, $filePath, $fileSize, $ContentType)
Определения storage_service_google.php:607
FileExists($arBucket, $filePath)
Определения storage_service_google.php:287
UploadPart($arBucket, &$NS, $data)
Определения storage_service_google.php:745
SendRequest($access_key, $secret_key, $verb, $bucket, $file_name='/', $params='', $content='', $additional_headers=[])
Определения storage_service_google.php:841
GetFileSRC($arBucket, $arFile, $encoded=true)
Определения storage_service_google.php:245
FileCopy($arBucket, $arFile, $filePath)
Определения storage_service_google.php:331
UploadPartNo($arBucket, &$NS, $data, $part_no)
Определения storage_service_google.php:659
CompleteMultipartUpload($arBucket, &$NS)
Определения storage_service_google.php:785
SaveFile($arBucket, $filePath, $arFile)
Определения storage_service_google.php:410
ListFiles($arBucket, $filePath, $bRecursive=false)
Определения storage_service_google.php:453
CheckSettings($arBucket, &$arSettings)
Определения storage_service_google.php:70
GetSettingsHTML($arBucket, $bServiceSet, $cur_SERVICE_ID, $bVarsFromForm)
Определения storage_service_google.php:31
static URLEncode($str, $charset, $file_name=false)
Определения util.php:10
Определения xml.php:396
$content
Определения commerceml.php:144
$data['IS_AVAILABLE']
Определения .description.php:13
$bVarsFromForm
Определения file_edit.php:44
EndNote()
Определения filter_tools.php:601
BeginNote($sParams='', $sMessParams='')
Определения filter_tools.php:589
$_SERVER["DOCUMENT_ROOT"]
Определения cron_frame.php:9
if(!defined('NOT_CHECK_PERMISSIONS')) $NS
Определения backup.php:24
AddMessage2Log($text, $module='', $traceDepth=6, $showArgs=false)
Определения tools.php:3941
htmlspecialcharsbx($string, $flags=ENT_COMPAT, $doubleEncode=true)
Определения tools.php:2701
IncludeModuleLangFile($filepath, $lang=false, $bReturnArray=false)
Определения tools.php:3778
GetMessage($name, $aReplace=null)
Определения tools.php:3397
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$text
Определения template_pdf.php:79
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
else $a
Определения template.php:137
$access_key
Определения result.php:8
$response
Определения result.php:21