elFinder::upload PHP Метод

upload() защищенный Метод

Save uploaded files
Автор: Dmitry (dio) Levashov
protected upload ( $args ) : array
Результат array
    protected function upload($args)
    {
        $ngReg = '/[\\/\\?*:|"<>]/';
        $target = $args['target'];
        $volume = $this->volume($target);
        $files = isset($args['FILES']['upload']) && is_array($args['FILES']['upload']) ? $args['FILES']['upload'] : array();
        $header = empty($args['html']) ? array() : array('header' => 'Content-Type: text/html; charset=utf-8');
        $result = array_merge(array('added' => array()), $header);
        $paths = $args['upload_path'] ? $args['upload_path'] : array();
        $chunk = $args['chunk'] ? $args['chunk'] : '';
        $cid = $args['cid'] ? (int) $args['cid'] : '';
        $mtimes = $args['mtime'] ? $args['mtime'] : array();
        $renames = $hashes = array();
        $suffix = '~';
        if ($args['renames'] && is_array($args['renames'])) {
            $renames = array_flip($args['renames']);
            if (is_string($args['suffix']) && !preg_match($ngReg, $args['suffix'])) {
                $suffix = $args['suffix'];
            }
        }
        if ($args['hashes'] && is_array($args['hashes'])) {
            $hashes = array_flip($args['hashes']);
        }
        if (!$volume) {
            return array_merge(array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_TRGDIR_NOT_FOUND, '#' . $target)), $header);
        }
        // regist Shutdown function
        $GLOBALS['elFinderTempFiles'] = array();
        // 		if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
        // 			$shutdownfunc = function(){ // <- Parse error on PHP < 5.3 ;-(
        // 				foreach(array_keys($GLOBALS['elFinderTempFiles']) as $f){
        // 					unlink($f);
        // 				}
        // 			};
        // 		} else {
        $shutdownfunc = create_function('', '
				foreach(array_keys($GLOBALS[\'elFinderTempFiles\']) as $f){
					is_file($f) && unlink($f);
				}
			');
        //		}
        register_shutdown_function($shutdownfunc);
        // file extentions table by MIME
        $extTable = array_flip(array_unique($volume->getMimeTable()));
        if (empty($files)) {
            //--- This part is unnecessary code from 2.1.7 START ---//
            if (!$args['upload'] && $args['name'] && is_array($args['name'])) {
                $error = '';
                $result['name'] = array();
                foreach ($args['name'] as $_i => $_name) {
                    if (!$volume->isUploadableByName($_name)) {
                        $error = $this->error(self::ERROR_UPLOAD_FILE, $_name, self::ERROR_UPLOAD_FILE_MIME);
                        break;
                    }
                    $result['name'][$_i] = preg_replace($ngReg, '_', $_name);
                }
                if ($error) {
                    $result['error'] = $error;
                    return $result;
                }
                $result = array_merge_recursive($result, $this->ls($args));
                if (empty($result['list'])) {
                    $result['name'] = array();
                } else {
                    // It is using the old(<=2.1.6) JavaScript in the new(>2.1.6) back-end?
                    unset($result['list']['exists'], $result['list']['hashes']);
                    $result['name'] = array_merge(array_intersect($result['name'], $result['list']));
                }
                return $result;
            }
            //--- This part is unnessesaly code from 2.1.7 END ---//
            if (isset($args['upload']) && is_array($args['upload']) && ($tempDir = $this->getTempDir($volume->getTempPath()))) {
                $names = array();
                foreach ($args['upload'] as $i => $url) {
                    // check chunked file upload commit
                    if ($args['chunk']) {
                        if ($url === 'chunkfail' && $args['mimes'] === 'chunkfail') {
                            $this->checkChunkedFile(null, $chunk, $cid, $tempDir);
                            if (preg_match('/^(.+)(\\.\\d+_(\\d+))\\.part$/s', $chunk, $m)) {
                                $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $m[1], self::ERROR_UPLOAD_TRANSFER);
                            }
                            return $result;
                        } else {
                            $tmpfname = $tempDir . '/' . $args['chunk'];
                            $files['tmp_name'][$i] = $tmpfname;
                            $files['name'][$i] = $url;
                            $files['error'][$i] = 0;
                            $GLOBALS['elFinderTempFiles'][$tmpfname] = true;
                            break;
                        }
                    }
                    $tmpfname = $tempDir . DIRECTORY_SEPARATOR . 'ELF_FATCH_' . md5($url . microtime(true));
                    $_name = '';
                    // check is data:
                    if (substr($url, 0, 5) === 'data:') {
                        list($data, $args['name'][$i]) = $this->parse_data_scheme($url, $extTable);
                    } else {
                        $fp = fopen($tmpfname, 'wb');
                        $data = $this->get_remote_contents($url, 30, 5, 'Mozilla/5.0', $fp);
                        $_POST['overwrite'] = false;
                        $_name = preg_replace('~^.*?([^/#?]+)(?:\\?.*)?(?:#.*)?$~', '$1', rawurldecode($url));
                        // Check `Content-Disposition` response header
                        if ($data && ($headers = get_headers($url, true)) && !empty($headers['Content-Disposition'])) {
                            if (preg_match('/filename\\*?=(?:([a-zA-Z0-9_-]+?)\'\')?"?([a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) {
                                $_name = rawurldecode($m[2]);
                                if ($m[1] && strtoupper($m[1]) !== 'UTF-8' && function_exists('mb_convert_encoding')) {
                                    $_name = mb_convert_encoding($_name, 'UTF-8', $m[1]);
                                }
                            }
                        }
                    }
                    if ($data) {
                        if (isset($args['name'][$i])) {
                            $_name = $args['name'][$i];
                        }
                        if ($_name) {
                            $_ext = '';
                            if (preg_match('/(\\.[a-z0-9]{1,7})$/', $_name, $_match)) {
                                $_ext = $_match[1];
                            }
                            if (is_resource($data) && fclose($data) || file_put_contents($tmpfname, $data)) {
                                $GLOBALS['elFinderTempFiles'][$tmpfname] = true;
                                $_name = preg_replace($ngReg, '_', $_name);
                                list($_a, $_b) = array_pad(explode('.', $_name, 2), 2, '');
                                if ($_b === '') {
                                    if ($_ext) {
                                        rename($tmpfname, $tmpfname . $_ext);
                                        $tmpfname = $tmpfname . $_ext;
                                    }
                                    $_b = $this->detectFileExtension($tmpfname);
                                    $_name = $_a . $_b;
                                } else {
                                    $_b = '.' . $_b;
                                }
                                if (isset($names[$_name])) {
                                    $_name = $_a . '_' . $names[$_name]++ . $_b;
                                } else {
                                    $names[$_name] = 1;
                                }
                                $files['tmp_name'][$i] = $tmpfname;
                                $files['name'][$i] = $_name;
                                $files['error'][$i] = 0;
                            } else {
                                unlink($tmpfname);
                            }
                        }
                    }
                }
            }
            if (empty($files)) {
                return array_merge(array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_UPLOAD_NO_FILES)), $header);
            }
        }
        $addedDirs = array();
        foreach ($files['name'] as $i => $name) {
            if (($error = $files['error'][$i]) > 0) {
                $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE ? self::ERROR_UPLOAD_FILE_SIZE : self::ERROR_UPLOAD_TRANSFER);
                $this->uploadDebug = 'Upload error code: ' . $error;
                break;
            }
            $tmpname = $files['tmp_name'][$i];
            $path = $paths && isset($paths[$i]) ? $paths[$i] : '';
            $mtime = isset($mtimes[$i]) ? $mtimes[$i] : 0;
            if ($name === 'blob') {
                if ($chunk) {
                    if ($tempDir = $this->getTempDir($volume->getTempPath())) {
                        list($tmpname, $name) = $this->checkChunkedFile($tmpname, $chunk, $cid, $tempDir, $volume);
                        if ($tmpname) {
                            if ($name === false) {
                                preg_match('/^(.+)(\\.\\d+_(\\d+))\\.part$/s', $chunk, $m);
                                $result['error'] = $this->error(self::ERROR_UPLOAD_FILE, $m[1], $tmpname);
                                $result['_chunkfailure'] = true;
                                $this->uploadDebug = 'Upload error: ' . $tmpname;
                            } else {
                                if ($name) {
                                    $result['_chunkmerged'] = basename($tmpname);
                                    $result['_name'] = $name;
                                    $result['_mtime'] = $mtime;
                                }
                            }
                        }
                    } else {
                        $result['error'] = $this->error(self::ERROR_UPLOAD_FILE, $chunk, self::ERROR_UPLOAD_TRANSFER);
                        $this->uploadDebug = 'Upload error: unable open tmp file';
                    }
                    return $result;
                } else {
                    // for form clipboard with Google Chrome
                    $type = $files['type'][$i];
                    $ext = isset($extTable[$type]) ? '.' . $extTable[$type] : '';
                    $name = substr(md5(basename($tmpname)), 0, 8) . $ext;
                }
            }
            // do hook function 'upload.presave'
            if (!empty($this->listeners['upload.presave'])) {
                foreach ($this->listeners['upload.presave'] as $handler) {
                    call_user_func_array($handler, array(&$path, &$name, $tmpname, $this, $volume));
                }
            }
            if ($mtime) {
                touch($tmpname, $mtime);
            }
            if (($fp = fopen($tmpname, 'rb')) == false) {
                $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, self::ERROR_UPLOAD_TRANSFER);
                $this->uploadDebug = 'Upload error: unable open tmp file';
                if (!is_uploaded_file($tmpname)) {
                    if (unlink($tmpname)) {
                        unset($GLOBALS['elFinderTempFiles'][$tmpfname]);
                    }
                    continue;
                }
                break;
            }
            $rnres = array();
            if ($path !== '' && $path !== $target) {
                if ($dir = $volume->dir($path)) {
                    $_target = $path;
                    if (!isset($addedDirs[$path])) {
                        $addedDirs[$path] = true;
                        $result['added'][] = $dir;
                    }
                } else {
                    $result['error'] = $this->error(self::ERROR_UPLOAD, self::ERROR_TRGDIR_NOT_FOUND, 'hash@' . $path);
                    break;
                }
            } else {
                $_target = $target;
                // file rename for backup
                if (isset($renames[$name])) {
                    $dir = $volume->realpath($_target);
                    if (isset($hashes[$name])) {
                        $hash = $hashes[$name];
                    } else {
                        $hash = $volume->getHash($dir, $name);
                    }
                    $rnres = $this->rename(array('target' => $hash, 'name' => $volume->uniqueName($dir, $name, $suffix, true, 0)));
                    if (!empty($rnres['error'])) {
                        $result['warning'] = $rnres['error'];
                        break;
                    }
                }
            }
            if (!$_target || ($file = $volume->upload($fp, $_target, $name, $tmpname, $hashes)) === false) {
                $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $volume->error());
                fclose($fp);
                if (!is_uploaded_file($tmpname)) {
                    if (unlink($tmpname)) {
                        unset($GLOBALS['elFinderTempFiles'][$tmpname]);
                    }
                    continue;
                }
                break;
            }
            is_resource($fp) && fclose($fp);
            if (!is_uploaded_file($tmpname)) {
                clearstatcache();
                if (!is_file($tmpname) || unlink($tmpname)) {
                    unset($GLOBALS['elFinderTempFiles'][$tmpname]);
                }
            }
            $result['added'][] = $file;
            if ($rnres) {
                $result = array_merge_recursive($result, $rnres);
            }
        }
        if ($GLOBALS['elFinderTempFiles']) {
            foreach (array_keys($GLOBALS['elFinderTempFiles']) as $_temp) {
                unlink($_temp);
            }
        }
        $result['removed'] = $volume->removed();
        if (!empty($args['node'])) {
            $result['callback'] = array('node' => $args['node'], 'bind' => 'upload');
        }
        return $result;
    }