hasProp('removeBtn')) $this->setProp('removeBtn', common::hasPriv('file', 'delete')); if(!$this->hasProp('totalFileSize')) { $maxFileSize = ini_get('post_max_size'); $lastChar = substr($maxFileSize, -1); $fileSizeUnit = array('K', 'M', 'G', 'T'); if(in_array($lastChar, $fileSizeUnit)) $maxFileSize .= 'B'; $this->setProp('totalFileSize', $maxFileSize); } if(!$this->hasProp('maxFileSize')) { $maxFileSize = ini_get('upload_max_filesize'); $lastChar = substr($maxFileSize, -1); $fileSizeUnit = array('K', 'M', 'G', 'T'); if(in_array($lastChar, $fileSizeUnit)) $maxFileSize .= 'B'; $this->setProp('maxFileSize', $maxFileSize); } if(!$this->hasProp('tip')) { global $lang; $this->setProp('tip', sprintf($lang->noticeDrag, '{maxFileSize}')); } if(!$this->hasProp('exceededCountTip')) { global $app, $lang; $app->loadLang('file'); $this->setProp('exceededCountHint', sprintf($lang->file->errorFileCount, '{maxCount}')); } if(!$this->hasProp('exceededTotalSizeTip')) { global $app, $lang; $app->loadLang('file'); $maxUploadSize = strtoupper(ini_get('post_max_size')); $this->setProp('exceededTotalSizeTip', sprintf($lang->file->errorFileSize, $maxUploadSize)); } /* Auto prepend suffix "[]" to multiple mode. */ $name = $this->prop('name'); if(!str_ends_with($name, ']') && ($this->prop('multiple') !== false || $this->prop('maxFileCount') !== 1)) { $this->setProp('name', $name . '[]'); } if($this->prop('defaultFiles') && $this->prop('extra')) { $defaultFiles = array(); foreach($this->prop('defaultFiles') as $file) { if($file->extra !== $this->prop('extra')) continue; $defaultFiles[] = $file; } $this->setProp('defaultFiles', $defaultFiles); } if($this->hasProp('accept')) { $accept = explode(',', $this->prop('accept')); $dangers = explode(',', $app->config->file->dangers); $filteredAccept = array_filter($accept, function($item) use ($dangers) { $item = strtolower($item); $ext = ltrim($item, '.'); return !in_array($ext, $dangers); }); $newAccept = implode(',', $filteredAccept); $this->setProp('accept', $newAccept); } /* Check file type. */ $acceptFileTypes = $this->prop('accept') ? ',' . str_replace('.', '', $this->prop('accept')) . ',' : ''; $checkFiles = jsCallback('file') ->const('dangerFileTypes', ",{$app->config->file->dangers},") ->const('dangerFile', $lang->file->dangerFile) ->const('acceptFileTypes', $acceptFileTypes) ->do(<<<'JS' const typeIndex = file.name.lastIndexOf("."); const fileType = "," + file.name.slice(typeIndex + 1) + ","; if(acceptFileTypes) { if(acceptFileTypes.indexOf(fileType) == -1) { zui.Modal.alert(dangerFile); return false; } } else if(dangerFileTypes.indexOf(fileType) > -1) { zui.Modal.alert(dangerFile); return false; } JS ); /* Get onAdd function.*/ $onAdd = $this->prop('onAdd'); if($onAdd) { if(is_object($onAdd)) { /* * 获取在 ui 界面上通过 jsCallback 和 js 定义的 onAdd 函数。 * eg: 1. $onAdd = jsCallbakc()..; * fileSelector(set::onAdd($onAdd)); * 2. $onAdd = js()..; * fileSelector(set::onAdd($onAdd)); */ $objectClass = get_class($onAdd); if($objectClass == 'zin\js') $onAdd = $onAdd->toJS(); if($objectClass == 'zin\jsCallback') $onAdd = $onAdd->buildBody(); if(!is_object($onAdd)) $checkFiles = $checkFiles->do($onAdd); } else { /* 获取在 ui 界面上通过 jsRaw 定义的 onAdd 函数。 eg: fileSelector(set::onAdd(jsRaw('window.onAdd'))); */ $onAdd = js::value($onAdd); $checkFiles = $checkFiles->call($onAdd, jsRaw('file')); } } $checkFiles = $checkFiles->do('return file'); $this->setProp('onAdd', $checkFiles); } /** * Build the widget. * * @access protected * @return mixed */ protected function build() { global $app, $lang; $app->control->loadModel('file'); $savePath = $app->control->file->savePath; if(!is_writable($savePath)) return div(setClass('file-selector-box p-4'), html(sprintf($lang->file->errorCanNotWrite, $savePath, dirname($savePath, 2)))); return zui::fileSelector(inherit($this)); } }