PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.18
ووسلام – همگام سازی ووکامرس و باسلام v1.10.18
1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 1.8.5 1.8.6 1.8.7 1.8.4 All 51 releases
sync-basalam / includes / Services / MediaUploadService.php

MediaUploadService.php in ووسلام – همگام سازی ووکامرس و باسلام 1.10.18, at includes/Services/MediaUploadService.php

202 lines 7.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SyncBasalam\Services;
4
5 use SyncBasalam\Admin\Settings\SettingsConfig;
6 use SyncBasalam\Config\Endpoints;
7 use SyncBasalam\Logger\Logger;
8
9 defined('ABSPATH') || exit;
10
11 class MediaUploadService
12 {
13 private const UPLOAD_PREFERENCE = 'presigned_post';
14
15 private $apiService;
16
17 public function __construct($apiService = null)
18 {
19 $this->apiService = $apiService ?: syncBasalamContainer()->get(ApiServiceManager::class);
20 }
21
22 public function uploadPhoto(string $filePath, array $options = []): array
23 {
24 return $this->upload($filePath, 'product.photo', 'تصویر', $options);
25 }
26
27 public function uploadVideo(string $filePath, array $options = []): array
28 {
29 return $this->upload($filePath, 'product.video', 'ویدیو', $options);
30 }
31
32 private function upload(string $filePath, string $fileType, string $fileLabel, array $options): array
33 {
34 $token = (string) syncBasalamSettings()->getSettings(SettingsConfig::TOKEN);
35 if ($token === '') throw new \RuntimeException('توکن باسلا�
36 یافت نشد. ابتدا اتصال باسلا�
37 را انجا�
38 دهید.');
39
40 $mimeType = $this->detectMimeType($filePath);
41 $fileSize = filesize($filePath);
42 $checksum = hash_file('sha256', $filePath);
43
44 if ($fileSize === false || $checksum === false) {
45 throw new \RuntimeException('خواندن اطلاعات فایل ' . esc_html($fileLabel) . ' برای آپلود نا�
46 وفق بود.');
47 }
48
49 $headers = ['Authorization' => 'Bearer ' . $token];
50 $request = $this->apiService->post(Endpoints::MEDIA_UPLOAD_REQUEST, [
51 'file_name' => basename($filePath),
52 'mime_type' => $mimeType,
53 'size' => (int) $fileSize,
54 'file_type' => $fileType,
55 'checksum_sha256' => $checksum,
56 'upload_preference' => self::UPLOAD_PREFERENCE,
57 'multipart_part_size_bytes' => 0,
58 ], $headers);
59
60 $uploadRequest = $this->decodeBody($request['body'] ?? null);
61 $fileId = $uploadRequest['file_id'] ?? null;
62 $strategy = $uploadRequest['upload_strategy'] ?? '';
63
64 if (!$fileId || $strategy !== 'presigned_post') {
65 Logger::error('پاسخ درخواست آپلود ' . esc_html($fileLabel) . ' باسلا�
66
67 عتبر نیست.', [
68 'status_code' => $request['status_code'] ?? 0,
69 'upload_strategy' => $strategy,
70 'response_body' => $uploadRequest,
71 ]);
72 throw new \RuntimeException('باسلا�
73 لینک �
74 عتبر آپلود ' . esc_html($fileLabel) . ' برنگرداند.');
75 }
76
77 $staging = $uploadRequest['staging'] ?? [];
78 $uploadUrl = $staging['url'] ?? '';
79 $fields = $staging['fields'] ?? [];
80
81 if (!is_string($uploadUrl) || $uploadUrl === '' || !is_array($fields) || empty($fields)) {
82 throw new \RuntimeException('اطلاعات لینک آپلود ' . esc_html($fileLabel) . ' باسلا�
83 ناقص است.');
84 }
85
86 $uploadResponse = $this->apiService->upload($uploadUrl, $filePath, $fields, [], $options);
87 $uploadStatus = (int) ($uploadResponse['status_code'] ?? 0);
88
89 if ($uploadStatus < 200 || $uploadStatus >= 300) {
90 throw new \RuntimeException($uploadResponse['error'] ?? 'ارسال فایل ' . esc_html($fileLabel) . ' به لینک باسلا�
91 نا�
92 وفق بود.');
93 }
94
95 $complete = $this->apiService->post(Endpoints::MEDIA_UPLOAD_COMPLETE, [
96 'file_id' => $fileId,
97 ], $headers);
98 $completeStatus = (int) ($complete['status_code'] ?? 0);
99
100 if ($completeStatus < 200 || $completeStatus >= 300) {
101 throw new \RuntimeException($complete['error'] ?? 'نهایی‌سازی آپلود ' . esc_html($fileLabel) . ' در باسلا�
102 نا�
103 وفق بود.');
104 }
105
106 $completedMedia = $this->decodeBody($complete['body'] ?? null);
107 $normalized = $this->normalizeCompletedMedia($completedMedia, (string) $fileId);
108
109 if ($normalized === null) {
110 $maxAttempts = $fileType === 'product.video' ? 60 : 15;
111 $normalized = $this->waitForCompletedMedia((string) $fileId, $headers, $fileLabel, $maxAttempts);
112 }
113
114 if ($normalized === null) {
115 Logger::error('پاسخ نهایی آپلود ' . esc_html($fileLabel) . ' باسلا�
116 شناسه رسانه ندارد.', [
117 'file_id' => $fileId,
118 'status_code' => $complete['status_code'] ?? 0,
119 'response_body' => $completedMedia,
120 ]);
121 throw new \RuntimeException('باسلا�
122 شناسه نهایی ' . esc_html($fileLabel) . ' آپلودشده را برنگرداند.');
123 }
124
125 return $normalized;
126 }
127
128 private function waitForCompletedMedia(string $fileId, array $headers, string $fileLabel, int $maxAttempts): ?array
129 {
130 $url = sprintf(Endpoints::MEDIA_UPLOAD_STATUS, rawurlencode($fileId));
131
132 for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
133 $status = $this->apiService->get($url, $headers);
134 $statusCode = (int) ($status['status_code'] ?? 0);
135
136 if ($statusCode >= 200 && $statusCode < 300) {
137 $statusBody = $this->decodeBody($status['body'] ?? null);
138 $normalized = $this->normalizeCompletedMedia($statusBody, $fileId);
139 if ($normalized !== null) return $normalized;
140
141 if (isset($statusBody['status']) && in_array($statusBody['status'], ['failed', 'aborted'], true)) {
142 throw new \RuntimeException('پردازش ' . esc_html($fileLabel) . ' آپلودشده در باسلا�
143 نا�
144 وفق بود.');
145 }
146 }
147
148 if ($attempt < $maxAttempts - 1) sleep(1);
149 }
150
151 return null;
152 }
153
154 private function detectMimeType(string $filePath): string
155 {
156 return MediaMimeType::detect($filePath);
157 }
158
159 private function decodeBody($body): array
160 {
161 if (is_array($body)) return $body;
162 if (!is_string($body) || $body === '') return [];
163
164 $decoded = json_decode($body, true);
165 return is_array($decoded) ? $decoded : [];
166 }
167
168 private function normalizeCompletedMedia(array $body, string $requestFileId): ?array
169 {
170 $data = isset($body['data']) && is_array($body['data']) ? $body['data'] : $body;
171 $ready = $data['ready'] ?? null;
172 $status = isset($data['status']) && is_string($data['status']) ? strtolower($data['status']) : null;
173
174 if (isset($data['media']) && is_array($data['media'])) $data = $data['media'];
175 if (isset($data['file']) && is_array($data['file'])) $data = $data['file'];
176
177 if (isset($data['status']) && is_string($data['status'])) $status = strtolower($data['status']);
178 if (array_key_exists('ready', $data)) $ready = $data['ready'];
179
180 if (in_array($status, ['failed', 'aborted'], true)) {
181 throw new \RuntimeException('پردازش فایل آپلودشده در باسلا�
182 نا�
183 وفق بود.');
184 }
185
186 if ($ready === false || in_array($status, ['initiated', 'uploading', 'processing', 'queued'], true)) {
187 return null;
188 }
189
190 $mediaId = $data['id'] ?? $data['media_id'] ?? null;
191 if ($mediaId === null || $mediaId === '') return null;
192
193 $url = $data['urls']['primary'] ?? $data['url'] ?? $data['media_url'] ?? null;
194
195 return [
196 'file_id' => $mediaId,
197 'url' => is_string($url) ? $url : null,
198 'upload_file_id' => $requestFileId,
199 ];
200 }
201 }
202