Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
storage.php
1<?php
7
8interface Storable
9{
14 public function copy($path, array $file);
15}
16
17class Storage implements Storable
18{
19 protected $path = "";
20
21 protected static $lastId = null;
22 protected static $descriptor = null;
23
24 function __construct()
25 {
26 }
27
28 private static function flush()
29 {
30 if (!is_null(self::$descriptor))
31 {
32 @fflush(self::$descriptor);
33 @flock(self::$descriptor, LOCK_UN);
34 @fclose(self::$descriptor);
35 self::$descriptor = null;
36 }
37 }
38 function __destruct()
39 {
40 self::flush();
41 }
42
48 public function copy($path, array $file)
49 {
50 $result = new Result();
51 $directory = \CBXVirtualIo::GetInstance()->getDirectory($path);
52
53 $newFile = $directory->GetPathWithName()."/".$file["code"];
54 $result->setData(array(
55 "size" => $file["size"],
56 "tmp_name" => $newFile,
57 "type" => $file["type"]
58 ));
59 if (mb_substr($newFile, -mb_strlen($file['tmp_name'])) == $file['tmp_name'])
60 {
61
62 }
63 else if (!$directory->create())
64 {
65 $result->addError(new Error(Loc::getMessage("BXU_TemporaryDirectoryIsNotCreated"), "BXU347.1"));
66 }
67 elseif (array_key_exists('tmp_url', $file))
68 {
69 if (!((!file_exists($newFile) || @unlink($newFile)) && File::http()->download($file['tmp_url'], $newFile) !== false))
70 $result->addError(new Error(Loc::getMessage("BXU_FileIsNotUploaded"), "BXU347.2.1"));
71 }
72 else if (!file_exists($file['tmp_name']))
73 {
74 $result->addError(new Error(Loc::getMessage("BXU_FileIsNotUploaded"), "BXU347.2.1"));
75 }
76 else if (!file_exists($file['tmp_name']))
77 {
78 $result->addError(new Error(Loc::getMessage("BXU_FileIsNotUploaded"), "BXU347.2.2"));
79 }
80 elseif (array_key_exists('start', $file))
81 {
82 $result = $this->copyChunk($newFile, $file);
83 }
84 else if (!((!file_exists($newFile) || @unlink($newFile)) && move_uploaded_file($file['tmp_name'], $newFile)))
85 {
86 $result->addError(new Error(Loc::getMessage("BXU_FileIsNotUploaded"), "BXU347.2.4"));
87 }
88 else
89 {
90 $result->setData(array(
91 "size" => filesize($newFile),
92 "tmp_name" => $newFile,
93 "type" => ($file["type"] ?: \CFile::GetContentType($newFile))
94 ));
95 }
96 return $result;
97 }
103 public function copyChunk($path, array $chunk)
104 {
105 $result = new Result();
106 if (is_null(self::$descriptor) || self::$lastId != $path)
107 {
108 self::flush();
109 self::$descriptor = $fdst = fopen($path, 'cb');
110 @chmod($path, BX_FILE_PERMISSIONS);
111 }
112 else
113 $fdst = self::$descriptor;
114
115 if (!$fdst)
116 {
117 $result->addError(new Error(Loc::getMessage("BXU_TemporaryFileIsNotCreated"), "BXU349.1"));
118 }
119 else if (!flock($fdst, LOCK_EX))
120 {
121 $result->addError(new Error(Loc::getMessage("BXU_FileIsLocked"), "BXU349.100"));
122 }
123 else
124 {
125 $buff = 4096;
126 if (($fsrc = fopen($chunk['tmp_name'], 'r')))
127 {
128 fseek($fdst, $chunk["start"], SEEK_SET);
129 while(!feof($fsrc) && ($data = fread($fsrc, $buff)))
130 {
131 if ($data !== '')
132 {
133 fwrite($fdst, $data);
134 }
135 else
136 {
137 $result->addError(new Error(Loc::getMessage("BXU_FilePartCanNotBeRead"), "BXU349.2"));
138 break;
139 }
140 }
141 fclose($fsrc);
142 unlink($chunk['tmp_name']);
143 }
144 else
145 {
146 $result->addError(new Error(Loc::getMessage("BXU_FilePartCanNotBeOpened"), "BXU349.3"));
147 }
148 }
149 if (!$result->isSuccess())
150 {
151 self::flush();
152 }
153
154 $result->setData(array(
155 "size" => $chunk["~size"],
156 "tmp_name" => $path,
157 "type" => $chunk["type"]
158 ));
159
160 return $result;
161 }
162
163 public function flushDescriptor()
164 {
165 self::flush();
166 }
167}
168
169class CloudStorage extends Storage implements Storable
170{
171 protected $moduleId = "main";
172 function __construct($params)
173 {
174 if(!Loader::includeModule("clouds"))
175 throw new \Bitrix\Main\NotImplementedException();
176 if (is_array($params))
177 {
178 $params = array_change_key_case($params, CASE_LOWER);
179 $this->moduleId = ($params["moduleid"] ?: $this->moduleId);
180 }
181 }
182
187 private function findBucket($file)
188 {
189
190 $bucket = \CCloudStorage::findBucketForFile(array('FILE_SIZE' => $file['size'], 'MODULE_ID' => $this->moduleId), $file["name"] ?? '');
191 if(!$bucket || !$bucket->init())
192 {
193 return null;
194 }
195 return $bucket;
196 }
197 protected function moveIntoCloud(\CCloudStorageBucket $bucket, $path, $file)
198 {
199 $result = new Result();
200 $absPath = \CTempFile::getAbsoluteRoot();
201 $relativePath = $path;
202 if (mb_substr($path, 0, mb_strlen($absPath)) == $absPath && mb_strpos($path, "/bxu/") > 0)
203 $relativePath = mb_substr($path, mb_strpos($path, "/bxu/"));
204 $subdir = explode("/", trim($relativePath, "/"));
205 $filename = array_pop($subdir);
206 if (!isset(\Bitrix\Main\Application::getInstance()->getSession()["upload_tmp"]))
207 {
208 \Bitrix\Main\Application::getInstance()->getSession()["upload_tmp"] = array();
209 }
210
211 if (!isset(\Bitrix\Main\Application::getInstance()->getSession()["upload_tmp"][$path]))
212 {
213 $relativePath = \Bitrix\Main\Application::getInstance()->getSession()["upload_tmp"][$path] =\CCloudTempFile::GetDirectoryName($bucket, 12).$filename;
214 }
215 else
216 {
217 $relativePath = \Bitrix\Main\Application::getInstance()->getSession()["upload_tmp"][$path];
218 }
219
220 $upload = new \CCloudStorageUpload($relativePath);
221 $finished = false;
222 if(!$upload->isStarted() && !$upload->start($bucket->ID, $file["size"], $file["type"]))
223 {
224 $result->addError(new Error(Loc::getMessage("BXU_FileTransferIntoTheCloudIsFailed"), "BXU346.2"));
225 }
226 else if (!($fileContent = \Bitrix\Main\IO\File::getFileContents($file["tmp_name"])))
227 {
228 $result->addError(new Error(Loc::getMessage("BXU_FileIsFailedToRead"), "BXU346.3"));
229 }
230 else
231 {
232 $fails = 0;
233 $success = false;
234 while ($upload->hasRetries())
235 {
236 if (method_exists($upload, "part") && $upload->part($fileContent, ($file["number"] ?? 0)) ||
237 !method_exists($upload, "part") && $upload->next($fileContent))
238 {
239 $success = true;
240 break;
241 }
242 $fails++;
243 }
244 if (!$success)
245 {
246 $result->addError(new Error("Could not upload file for {$fails} times.", "BXU346.4"));
247 }
248 else if (isset($file["count"]) && $upload->GetPartCount() < $file["count"])
249 {
250 }
251 else if (!$upload->finish())
252 {
253 $result->addError(new Error("Could not resume file transfer.", "BXU346.5"));
254 }
255 else
256 {
257 $finished = true;
258 }
259 }
260
261 $result->setData(array(
262 "tmp_name" => $bucket->getFileSRC($relativePath),
263 "size" => $file["size"],
264 "type" => $file["type"],
265 "finished" => $finished
266 ));
267 return $result;
268 }
269
270 public function copy($path, array $file)
271 {
272 $result = parent::copy($path, $file);
273 if ($result->isSuccess())
274 {
275 if (!array_key_exists('start', $file))
276 {
277 $res = $result->getData();
278 $file["tmp_name"] = $res["tmp_name"];
279 $file["size"] = $res["size"];
280 $file["type"] = $res["type"];
281 $info = (new \Bitrix\Main\File\Image($file["tmp_name"]))->getInfo();
282 if($info)
283 {
284 $file["width"] = $info->getWidth();
285 $file["height"] = $info->getHeight();
286 }
287 else
288 {
289 $file["width"] = 0;
290 $file["height"] = 0;
291 }
292 if ($bucket = $this->findBucket($file))
293 {
294 unset($file["count"]);
295 if (($r = $this->moveIntoCloud($bucket, $file["tmp_name"], $file)) && $r->isSuccess())
296 {
297 $res = $r->getData();
298 $result->setData(array(
299 "size" => $file["size"],
300 "file_size" => $file["size"],
301 "tmp_name" => $res["tmp_name"],
302 "type" => $file["type"],
303 "width" => $file["width"],
304 "height" => $file["height"],
305 "bucketId" => $bucket->ID
306 ));
307 }
308 if ($r->getErrors())
309 {
310 $result->addErrors($r->getErrors());
311 }
312 @unlink($path);
313 }
314 }
315 else if ($file["start"] <= 0)
316 {
317 $res = $result->getData();
318 if (($info = (new \Bitrix\Main\File\Image($file["tmp_name"]))->getInfo()))
319 {
320 $file["width"] = $info->getWidth();
321 $file["height"] = $info->getHeight();
322 $result->setData(array_merge($res, ["width" => $file["width"], "height" => $file["height"]]));
323 }
324 }
325 }
326 return $result;
327 }
333 public function copyChunk($path, array $file)
334 {
335 if ($bucket = $this->findBucket(array(
336 "name" => $file["~name"],
337 "size" => $file["~size"],
338 )))
339 {
340 if (($result = $this->moveIntoCloud($bucket, $path, array_merge($file, array("size" => $file["~size"])))) &&
341 $result->isSuccess() && ($res = $result->getData()) && $res["finished"] === true)
342 {
343 $res = $result->getData();
344 $result->setData(array(
345 "size" => $file["~size"],
346 "file_size" => $file["~size"],
347 "tmp_name" => $res["tmp_name"],
348 "type" => $file["type"],
349 "bucketId" => $bucket->ID
350 ));
351 }
352 }
353 else
354 {
355 $result = parent::copyChunk($path, $file);
356 }
357 return $result;
358 }
359
365 public static function checkBucket($id)
366 {
367 $res = false;
368 if(Loader::includeModule("clouds"))
369 {
370 $r = \CCloudStorageBucket::GetAllBuckets();
371 $res = (is_array($r) && array_key_exists($id, $r));
372 }
373 return $res;
374 }
375}
static includeModule($moduleName)
Definition loader.php:69
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
moveIntoCloud(\CCloudStorageBucket $bucket, $path, $file)
Definition storage.php:197
copyChunk($path, array $chunk)
Definition storage.php:103
copy($path, array $file)
Definition storage.php:48