'短文本(text)', self::TYPE_TEXTAREA => '长文本(textarea)', self::TYPE_RADIO => '横向单选(radio)', self::TYPE_CHECKBOX => '横向多选(checkbox)', self::TYPE_SELECT => '下拉单选(select)', self::TYPE_IMAGE => '图片(image)', self::TYPE_FILE => '文件(file)', ]; public function radio($name, $options, $current = null) { $arr = []; foreach ($options as $value => $label) { $arr[] = sprintf( '', $name, $value, (string)$current === (string)$value ? ' checked' : '', $label ); } return implode('', $arr); } function buildFieldForm(array $row = []) { global $lang_fields; $trName = tr($lang_fields['col_name'] . '*', '  仅允许数字、字母、下划线', 1, '', true); $trLabel = tr($lang_fields['col_label'] . '*', '', 1, '', true); $trType = tr($lang_fields['col_type'] . '*', $this->radio('type', self::$types, $row['type'] ?? null), 1, '', true); $trRequired = tr($lang_fields['col_required'] . '*', $this->radio('required', ['0' => '否', '1' => '是'], $row['required'] ?? null), 1, '', true); $trHelp = tr($lang_fields['col_help'], '', 1, '', true); $trOptions = tr($lang_fields['col_options'], '
类型为单选、多选、下拉时必填,一行一个,格式:选项值|选项描述文本', 1, '', true); $id = $row['id'] ?? 0; $form = <<

{$lang_fields['text_field']}

{$trName} {$trLabel} {$trType} {$trRequired} {$trHelp} {$trOptions}
HTML; return $form; } function buildFieldTable() { global $lang_fields; $perPage = 10; $total = get_row_count('torrents_custom_fields'); list($paginationTop, $paginationBottom, $limit) = pager($perPage, $total, "?"); $sql = "select * from torrents_custom_fields order by id asc $limit"; $res = sql_query($sql); $header = [ 'id' => $lang_fields['col_id'], 'name' => $lang_fields['col_name'], 'label' => $lang_fields['col_label'], 'type_text' => $lang_fields['col_type'], 'required_text' => $lang_fields['col_required'], 'action' => $lang_fields['col_action'], ]; $rows = []; while ($row = mysql_fetch_assoc($res)) { $row['required_text'] = $row['required'] ? '是' : '否'; $row['type_text'] = self::$types[$row['type']] ?? ''; $row['action'] = sprintf( "%s | %s", $row['id'], $lang_fields['js_sure_to_delete_this'], $lang_fields['text_delete'], $row['id'], $lang_fields['text_edit'] ); $rows[] = $row; } $head = <<{$lang_fields['field_management']} -
{$lang_fields['text_manage']} {$lang_fields['text_add']}
HEAD; $table = $this->buildTable($header, $rows); return $head . $table . $paginationBottom; } public function save($data) { $attributes = []; if (empty($data['name'])) { throw new \InvalidArgumentException("Name 必须"); } if (!preg_match('/^\w+$/', $data['name'])) { throw new \InvalidArgumentException("Name 非法"); } $attributes['name'] = $data['name']; if (empty($data['label'])) { throw new \InvalidArgumentException("显示标签 必须"); } $attributes['label'] = $data['label']; if (empty($data['type'])) { throw new \InvalidArgumentException("类型 必须"); } if (!isset(self::$types[$data['type']])) { throw new \InvalidArgumentException("类型 非法"); } $attributes['type'] = $data['type']; if (!isset($data['required'])) { throw new \InvalidArgumentException("不能为空 必须"); } if (!in_array($data['required'], ["0", "1"], true)) { throw new \InvalidArgumentException("不能为空 非法"); } $attributes['required'] = $data['required']; $attributes['help'] = $data['help'] ?? ''; $attributes['options'] = trim($data['options'] ?? ''); $now = date('Y-m-d H:i:s'); $attributes['updated_at'] = $now; $table = 'torrents_custom_fields'; if (!empty($data['id'])) { $result = DB::update($table, $attributes, "id = " . sqlesc($data['id'])); } else { $attributes['created_at'] = $now; $result = DB::insert($table, $attributes); } return $result; } public function buildTable(array $header, array $rows) { $table = ''; foreach ($header as $key => $value) { $table .= sprintf('', $value); } $table .= ''; foreach ($rows as $row) { $table .= ''; foreach ($header as $headerKey => $headerValue) { $table .= sprintf('', $row[$headerKey] ?? ''); } $table .= ''; } $table .= '
%s
%s
'; return $table; } public function buildFieldCheckbox($name, $current = []) { $sql = 'select * from torrents_custom_fields'; $res = sql_query($sql); $checkbox = []; if (!is_array($current)) { $current = explode(',', $current); } while ($row = mysql_fetch_assoc($res)) { $checkbox[] = sprintf( '', $name, $row['id'], in_array($row['id'], $current) ? ' checked' : '', "{$row['label']}({$row['id']})" ); } return implode('', $checkbox); } public function renderUploadPage(array $customValues = []) { $searchBoxId = get_setting('main.browsecat'); $searchBox = DB::getOne('searchbox', "id = $searchBoxId"); if (empty($searchBox)) { throw new \RuntimeException("Invalid search box: $searchBoxId"); } $sql = sprintf('select * from torrents_custom_fields where id in (%s)', $searchBox['custom_fields']); $res = sql_query($sql); $html = ''; while ($row = mysql_fetch_assoc($res)) { $name = "custom_fields[{$row['id']}]"; $currentValue = $customValues[$row['id']] ?? ''; if ($row['type'] == self::TYPE_TEXT) { $html .= tr($row['label'], sprintf('', $name, $currentValue), 1); } elseif ($row['type'] == self::TYPE_TEXTAREA) { $html .= tr($row['label'], sprintf('', $name, $currentValue), 1); } elseif ($row['type'] == self::TYPE_RADIO || $row['type'] == self::TYPE_CHECKBOX) { if ($row['type'] == self::TYPE_CHECKBOX) { $name .= '[]'; } $part = ""; foreach (preg_split('/[\r\n]+/', trim($row['options'])) as $option) { if (empty($option) || ($pos = strpos($option, '|')) === false) { continue; } $value = substr($option, 0, $pos); $label = substr($option, $pos + 1); $checked = ""; if ($row['type'] == self::TYPE_RADIO && (string)$currentValue === (string)$value) { $checked = " checked"; } if ($row['type'] == self::TYPE_CHECKBOX && in_array($value, (array)$currentValue)) { $checked = " checked"; } $part .= sprintf( '', $row['type'], $name, $value, $checked, $label ); } $html .= tr($row['label'], $part, 1); } elseif ($row['type'] == self::TYPE_SELECT) { $part = ''; $html .= tr($row['label'], $part, 1); } elseif ($row['type'] == self::TYPE_IMAGE) { $callbackFunc = "preview_custom_field_image_" . $row['id']; $iframeId = "iframe_$callbackFunc"; $inputId = "input_$callbackFunc"; $imgId = "attach" . $row['id']; $previewBoxId = "preview_$callbackFunc"; $y = ''; $y .= sprintf('', $inputId, $name, $currentValue); $y .= '
'; if (!empty($currentValue)) { if (substr($currentValue, 0, 4) == 'http') { $y .= formatImg($currentValue, true, 700, 0, $imgId); } else { $y .= format_comment($currentValue); } } $y .= '
'; $y .= << function {$callbackFunc}(delkey, url) { var previewBox = $('$previewBoxId') var existsImg = $('$imgId') var input = $('$inputId') if (existsImg) { previewBox.removeChild(existsImg) input.value = '' } var img = document.createElement('img') img.src=url img.setAttribute('onload', 'Scale(this, 700, 0);') img.setAttribute('onclick', 'Preview(this);') input.value = '[attach]' + delkey + '[/attach]' img.id='$imgId' previewBox.appendChild(img) } JS; $html .= tr($row['label'], $y, 1); } elseif ($row['type'] == self::TYPE_FILE) { $html .= tr($row['label'], sprintf('', $name), 1); } } return $html; } public function listTorrentCustomField($torrentId) { $res = sql_query("select v.*, f.type as custom_field_type from torrents_custom_field_values v inner join torrents_custom_fields f on v.custom_field_id = f.id where torrent_id = $torrentId"); $result = []; while ($row = mysql_fetch_assoc($res)) { if ($row['custom_field_type'] == self::TYPE_CHECKBOX) { $result[$row['custom_field_id']][] = $row['custom_field_value']; } else { $result[$row['custom_field_id']] = $row['custom_field_value']; } } return $result; } }