Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/ui/uploader/ |
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/ui/uploader/package.php |
<?php namespace Bitrix\Main\UI\Uploader; use Bitrix\Main\ArgumentException; use Bitrix\Main\ArgumentNullException; use Bitrix\Main\Error; use Bitrix\Main\NotImplementedException; use Bitrix\Main\Web\Uri; use Bitrix\Main\Context; class Package { /* @var string $index Package ID. */ protected $index; /* @var Log $cidLog */ protected $cidLog = null; /* @var Log $log */ protected $log = null; /** @var string $path Path to temp directory. */ protected $path; /** @var string $CID Control exemplar ID. */ protected $CID; /* @var array */ protected $copies = array( "default" => array( "width" => null, "height" => null ) ); /* @var Storable */ protected $storage; /** @var array File */ public $files = array(); /** @var string */ public $controlId = "fileUploader"; /* * @var string $script Url to uploading page for forming url to view * @var array $processTime Time limits */ protected $processTime = array( // Time limits "max" => 30, "start" => 0, "current" => 0); /** * Package constructor. * @param $path * @param $CID * @param $index * @throws ArgumentNullException * @throws NotImplementedException */ public function __construct($path, $CID, $index) { if (!is_string($path)) throw new ArgumentNullException("path"); $this->path = $path; $this->setCid($CID); $this->cidLog = new Log($this->path.$this->getCid().".log"); $this->setIndex($index); $this->request = Context::getCurrent()->getRequest(); if (!$this->request->isPost()) throw new NotImplementedException("File uploader support only POST method."); $post = Context::getCurrent()->getRequest()->getPostList()->toArray(); $post = $post[Uploader::INFO_NAME]; if (!preg_match("/^([0-9]+)$/", $post["filesCount"])) { throw new ArgumentException("The value filesCount must be an integer", "packageIndex"); } $this->log = new Log($this->path.$this->getIndex().".package"); if (!isset($this->log["CID"])) { $this->log["CID"] = $this->getCid(); $this->log["pIndex"] = $this->getIndex(); $this->log["filesCount"] = intval($post["filesCount"]); $this->log["files"] = array(); } $this->processTime["max"] = intval(ini_get("max_execution_time")) * 0.75; $this->processTime["start"] = time(); set_time_limit(0); return $this; } protected function setIndex($index) { if (!is_string($index)) throw new ArgumentNullException("packageIndex"); if (!preg_match("/^pIndex([0-9]+)$/", $index)) throw new ArgumentException("Index must be a string like '^pIndex([0-9]+)$'", "packageIndex"); $this->index = $index; } /** * Returns package Index. * @return string */ public function getIndex() { return $this->index; } /** * Returns package Log of Control Exemplar. * @return Log */ public function getCidLog($key = null) { if (is_null($key)) return $this->cidLog->getLog(); $log = $this->cidLog->getLog(); return $log[$key]; } /** * Returns package Log. * @return array|mixed */ public function getLog($key = null) { if (is_null($key)) return $this->log->getLog(); $log = $this->log->getLog(); return $log[$key]; } /** * Returns file array. * @return array */ public function getFile($id) { return $this->files[$id]; } protected function setCid($CID) { if (!is_string($CID)) throw new ArgumentNullException("CID"); else if (strpos($CID, "/") !== false) throw new ArgumentException("CID contains a forbidden symbol /"); $this->CID = preg_replace("/[^a-z0-9_\\-.]/i", "_", $CID); } /** * @return string */ public function getCid() { return $this->CID; } /** * @return string */ public function getPath() { return $this->path; } /** * @param array $params * @return $this * @throws \Exception */ public function setStorage(array $params) { $params = array_change_key_case($params, CASE_LOWER); try { if (array_key_exists("cloud", $params) && $params["cloud"] === true && (\CUtil::Unformat(ini_get("upload_max_filesize")) / 1024 / 1024) >= 5) $this->storage = new CloudStorage($params); } catch(\Exception $e) { } if (!($this->storage instanceof Storable)) { $this->storage = new Storage($params); } return $this; } /** * @return Storable */ public function getStorage() { return $this->storage; } /** * @param array $params * @return $this */ public function setCopies(array $params) { foreach ($params as $code => $p) { $this->copies[$code] = $p; } return $this; } /** * @return array */ public function getCopies() { return $this->copies; } /** * Decodes and converts keys(!) and values * @param $data * @return array */ protected static function unescape($data) { if(is_array($data)) { $res = array(); foreach($data as $k => $v) { $k = Uri::urnDecode($k, "UTF-8"); $res[$k] = self::unescape($v); } } else { $res = Uri::urnDecode($data, "UTF-8"); } return $res; } /** * Main function for uploading data. * * @throws NotImplementedException * @return array */ public function checkPost($fileLimits) { $unescapedPost = self::unescape( Context::getCurrent()->getRequest()->getPostList()->toArrayRaw() ?? Context::getCurrent()->getRequest()->getPostList()->toArray() ); $postFiles = $unescapedPost[Uploader::FILE_NAME]; $post = $unescapedPost[Uploader::INFO_NAME]; if (!(is_array($post) && $this->log["filesCount"] > 0 && $post["filesCount"] == $this->log["filesCount"] && is_array($postFiles) && !empty($postFiles)) ) return array(); $files = self::unescape( Context::getCurrent()->getRequest()->getFileList()->toArrayRaw() ?? Context::getCurrent()->getRequest()->getFileList()->toArray() ); $files = $files[Uploader::FILE_NAME]; $type = $post["type"] ?? null; if ($type !== "brief") // If it is IE8 { $error = ""; if ($this->log["executeStatus"] != "executed") { $eventName = ($this->cidLog["executeStatus"] === "executed" ? "onUploadIsContinued" : "onUploadIsStarted"); $this->cidLog["executeStatus"] = "executed"; foreach(GetModuleEvents(Uploader::EVENT_NAME, $eventName, true) as $event) { if (ExecuteModuleEventEx($event, array(&$this->log, &$this->cidLog, &$unescapedPost, &$files, &$error)) === false) throw new NotImplementedException($error); } $eventName = "onPackageIsStarted"; } else { $eventName = "onPackageIsContinued"; } $this->log["executeStatus"] = "executed"; foreach(GetModuleEvents(Uploader::EVENT_NAME, $eventName, true) as $event) { if (ExecuteModuleEventEx($event, array(&$this->log, &$this->cidLog, &$unescapedPost, &$files, &$error)) === false) throw new NotImplementedException($error); } } $filesRaw = array(); // $_POST foreach($postFiles as $fileID => $file) { if (is_array($file)) { if (isset($file["removed"])) { $f = array_merge($file, array("id" => $fileID)); File::deleteCache($this, $f); $filesRaw[] = [ 'id' => $fileID, 'removed' => 'Y' ]; } else if (isset($file["restored"])) { $f = array_merge($file, array("id" => $fileID)); if ($f["restored"] === "Y") { File::deleteCache($this, $f); } else { $filesRaw[] = $f; } } if (array_key_exists("files", $file) && is_array($file["files"])) { foreach ($file["files"] as $serviceName => $f) { if (is_array($f) && array_key_exists("tmp_url", $f)) { /** * $file = array( * "id" => "file4545454", * "name" => "Foxes.jpg", * "~name" => "default", * "type" => "image/jpg" * ); */ $filesRaw[] = array_merge($f, array( "id" => $fileID, "code" => $serviceName )); } } } } } // $_FILES if (is_array($files)) { foreach($files["name"] as $fileID => $fileNames) { if (is_array($fileNames)) { foreach ($fileNames as $fileName => $val) { $filesRaw[] = array( "id" => $fileID, "code" => $fileName, "tmp_name" => $files["tmp_name"][$fileID][$fileName], "type" => $files["type"][$fileID][$fileName], "size" => $files["size"][$fileID][$fileName], "error" => $files["error"][$fileID][$fileName] ); } } else { $filesRaw[] = array( "id" => $fileID, "code" => $fileNames, "tmp_name" => $files["tmp_name"][$fileID], "type" => $files["type"][$fileID], "size" => $files["size"][$fileID], "error" => $files["error"][$fileID] ); } } } $file = null; $filesFromLog = is_array($this->log["files"]) ? $this->log["files"] : array(); $filesOnThisPack = array(); if ($fileRaw = reset($filesRaw)) { $this->log["uploadStatus"] = "inprogress"; do { if (!array_key_exists($fileRaw["id"], $postFiles)) continue; if (!$this->checkTime()) break; if (!array_key_exists($fileRaw["id"], $filesOnThisPack)) { if (!empty($fileRaw["removed"])) { $file = new FileRemoved($this, [ 'id' => $fileRaw['id'], 'name' => $postFiles[$fileRaw["id"]]["name"] ]); } else { $file = new File($this, array( "id" => $fileRaw["id"], "name" => $postFiles[$fileRaw["id"]]["name"], "type" => $postFiles[$fileRaw["id"]]["type"], "size" => $postFiles[$fileRaw["id"]]["size"] ) + (is_array($postFiles[$fileRaw["id"]]) ? $postFiles[$fileRaw["id"]] : [])); if (isset($fileRaw["restored"])) { if ($file->isExecuted()) $file->setExecuteStatus("none"); $fileRaw = $file->getFile("default"); if (empty($fileRaw) || !is_array($fileRaw)) $file->addError(new Error(\Bitrix\Main\Localization\Loc::getMessage("BXU_FileIsNotRestored"), "BXU350.0")); } } $filesOnThisPack[$fileRaw["id"]] = $file; } /* @var File $file */ $file = $filesOnThisPack[$fileRaw["id"]]; if ($file->hasError() || $file instanceof FileRemoved) { continue; } $result = File::checkFile($fileRaw, $file, $fileLimits + array("path" => $this->getPath())); if ($result->isSuccess() && ($result = $file->saveFile($fileRaw, $this->getStorage(), $this->getCopies())) && $result->isSuccess() && $type !== "brief" && $file->isUploaded() && !$file->isExecuted() ) { $file->setExecuteStatus("executed"); $fileArray = $file->toArray(); foreach(GetModuleEvents(Uploader::EVENT_NAME, "onFileIsUploaded", true) as $event) { $error = ""; if (!ExecuteModuleEventEx($event, array($file->getHash(), &$fileArray, &$this->log, &$this->cidLog, &$error))) { $result->addError(new Error($error, "BXU350.1")); break; } } $file->fromArray($fileArray); } if (!$result->isSuccess()) $file->addError($result->getErrorCollection()->current()); } while ($fileRaw = next($filesRaw)); } $response = array(); /* @var File $file */ foreach ($filesOnThisPack as $file) { $response[$file->getId()] = $file->toArray(); $filesFromLog[$file->getId()] = $response[$file->getId()]["status"] = $file->isUploaded() ? "uploaded" : "inprogress"; if ($file->hasError()) { $response[$file->getId()]["status"] = "error"; $response[$file->getId()]["error"] = $file->getErrorMessage(); $filesFromLog[$file->getId()] = "error"; } } $this->files = $filesOnThisPack; $this->log["files"] = $filesFromLog; $declaredFiles = (int) $this->log["filesCount"]; $cnt = 0; foreach ($filesFromLog as $status) $cnt += ($status == "uploaded" || $status == "error" ? 1 : 0); if ($declaredFiles > 0 && $declaredFiles <= $cnt) { if ($type !== "brief") // If it is IE8 { $this->log["uploadStatus"] = "uploaded"; $error = ""; foreach(GetModuleEvents(Uploader::EVENT_NAME, "onPackageIsFinished", true) as $event) { if (ExecuteModuleEventEx($event, array(&$this->log, &$this->cidLog, &$unescapedPost, &$response, &$error)) === false) throw new NotImplementedException($error); } } } return $response; } /** * @return bool */ public function checkTime() { if ($this->processTime["max"] > 0) { $res = (microtime(true) - START_EXEC_TIME); return $res < $this->processTime["max"]; } return true; } /** * this function just merge 2 arrays with a lot of deep keys * array_merge replaces keys in second level and deeper * array_merge_recursive multiplies similar keys * @param $res * @param $res2 * @return array */ public static function merge($res, $res2) { $res = is_array($res) ? $res : array(); $res2 = is_array($res2) ? $res2 : array(); foreach ($res2 as $key => $val) { if (array_key_exists($key, $res) && is_array($val)) $res[$key] = self::merge($res[$key], $val); else $res[$key] = $val; } return $res; } } ?>