diff --git a/.github/workflows/Typecho-release-Ci.yml b/.github/workflows/Typecho-release-Ci.yml index 7a2f65fb..08f4d117 100644 --- a/.github/workflows/Typecho-release-Ci.yml +++ b/.github/workflows/Typecho-release-Ci.yml @@ -1,14 +1,14 @@ name: Typecho Build Release Ci on: - push: - tags: - - 'v*' + release: + types: [published] + jobs: build: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Build run: | mkdir build @@ -17,27 +17,14 @@ jobs: chmod 755 build/usr/uploads/ rm -rf build/admin/src cd build && zip -q -r typecho.zip * && mv typecho.zip ../ && cd - - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: ${{ github.ref }} - draft: true - prerelease: false - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: shogo82148/actions-upload-release-asset@v1 with: - upload_url: ${{ steps.create_release.outputs.upload_url }} + upload_url: ${{ github.event.release.upload_url }} asset_path: ./typecho.zip asset_name: typecho.zip asset_content_type: application/zip - - name: Trigger langs build + - name: Trigger language build run: | curl -XPOST -H "Authorization: token ${{ secrets.WORKFLOW_TOKEN }}" \ -H "Accept: application/vnd.github.everest-preview+json" \ diff --git a/admin/custom-fields.php b/admin/custom-fields.php index 39e52ae8..8e94b0bd 100644 --- a/admin/custom-fields.php +++ b/admin/custom-fields.php @@ -9,8 +9,8 @@ $defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaul class="i-caret-right"> - - + + @@ -37,12 +37,14 @@ $defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaul value="int" selected> +
+ rows="2"> diff --git a/admin/manage-comments.php b/admin/manage-comments.php index c85e8a3c..22f0d489 100644 --- a/admin/manage-comments.php +++ b/admin/manage-comments.php @@ -131,7 +131,7 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
author(true); ?> mail): ?> -
mail(); ?> +
mail(); ?> ip): ?>
ip(); ?> diff --git a/install.php b/install.php index f4cc9971..3c98e925 100644 --- a/install.php +++ b/install.php @@ -1031,8 +1031,7 @@ function install_step_2_perform() ->addRule('dbFile', 'required', _t('确认您的配置')) ->addRule('dbFile', function (string $path) { $pattern = "/^(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i"; - if (strstr(PHP_OS, 'WIN')) - { + if (strstr(PHP_OS, 'WIN')) { $pattern = "/(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i"; } return !!preg_match($pattern, $path); @@ -1077,7 +1076,12 @@ function install_step_2_perform() $installDb->addServer($dbConfig, \Typecho\Db::READ | \Typecho\Db::WRITE); $installDb->query('SELECT 1=1'); } catch (\Typecho\Db\Adapter\ConnectionException $e) { - install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装: "%s"', $e->getMessage())); + $code = $e->getCode(); + if (('Mysql' == $type && 1049 == $code) || ('Pgsql' == $type && 7 == $code)) { + install_raise_error(_t('数据库: "%s"不存在,请手动创建后重试', $config['dbDatabase'])); + } else { + install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装: "%s"', $e->getMessage())); + } } catch (\Typecho\Db\Exception $e) { install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage())); } diff --git a/var/Typecho/Common.php b/var/Typecho/Common.php index 02937782..7bdb18cc 100644 --- a/var/Typecho/Common.php +++ b/var/Typecho/Common.php @@ -83,7 +83,7 @@ namespace Typecho { $isPlugin = false; // detect if class is predefined - if (strpos($className, '\\') !== false) { + if ($isNamespace) { $isPlugin = strpos(ltrim($className, '\\'), PLUGIN_NAMESPACE . '\\') !== false; if ($isPlugin) { diff --git a/var/Typecho/Validate.php b/var/Typecho/Validate.php index 4e371172..ae8a3a5d 100644 --- a/var/Typecho/Validate.php +++ b/var/Typecho/Validate.php @@ -96,7 +96,8 @@ class Validate */ public static function email(string $str): bool { - return filter_var($str, FILTER_VALIDATE_EMAIL) !== false; + $email = filter_var($str, FILTER_SANITIZE_EMAIL); + return !!filter_var($str, FILTER_VALIDATE_EMAIL) && ($email === $str); } /** @@ -110,10 +111,8 @@ class Validate */ public static function url(string $str): bool { - return filter_var( - $str, - FILTER_VALIDATE_URL - ) !== false; + $url = Common::safeUrl($str); + return !!filter_var($str, FILTER_VALIDATE_URL) && ($url === $str); } /** diff --git a/var/Typecho/Widget/Helper/Form/Element.php b/var/Typecho/Widget/Helper/Form/Element.php index 7389ebdd..984864c5 100644 --- a/var/Typecho/Widget/Helper/Form/Element.php +++ b/var/Typecho/Widget/Helper/Form/Element.php @@ -217,7 +217,7 @@ abstract class Element extends Layout public function value($value): Element { $this->value = $value; - $this->inputValue($value); + $this->inputValue($value ?? ''); return $this; } diff --git a/var/Typecho/Widget/Helper/Form/Element/Checkbox.php b/var/Typecho/Widget/Helper/Form/Element/Checkbox.php index 15353975..b931d692 100644 --- a/var/Typecho/Widget/Helper/Form/Element/Checkbox.php +++ b/var/Typecho/Widget/Helper/Form/Element/Checkbox.php @@ -61,7 +61,7 @@ class Checkbox extends Element */ protected function inputValue($value) { - $values = is_array($value) ? $value : [$value]; + $values = is_null($value) ? [] : (is_array($value) ? $value : [$value]); foreach ($this->options as $option) { $option->removeAttribute('checked'); diff --git a/var/Widget/Archive.php b/var/Widget/Archive.php index 4d902bc9..674a1b42 100644 --- a/var/Widget/Archive.php +++ b/var/Widget/Archive.php @@ -918,7 +918,7 @@ class Archive extends Contents */ public function related(int $limit = 5, ?string $type = null): Contents { - $type = strtolower($type); + $type = strtolower($type ?? ''); switch ($type) { case 'author': diff --git a/var/Widget/Base/Comments.php b/var/Widget/Base/Comments.php index f318711b..2c468e08 100644 --- a/var/Widget/Base/Comments.php +++ b/var/Widget/Base/Comments.php @@ -306,6 +306,18 @@ class Comments extends Base implements QueryInterface echo Common::subStr(strip_tags($this->content), 0, $length, $trim); } + /** + * 输出邮箱地址 + * + * @param bool $link + * @return void + */ + public function mail(bool $link = false) + { + $mail = htmlspecialchars($this->mail); + echo $link ? 'mailto:' . $mail : $mail; + } + /** * 获取查询对象 * diff --git a/var/Widget/Base/Contents.php b/var/Widget/Base/Contents.php index 5f871de6..6dca0b12 100644 --- a/var/Widget/Base/Contents.php +++ b/var/Widget/Base/Contents.php @@ -346,41 +346,42 @@ class Contents extends Base implements QueryInterface * * @param string $name * @param string $type - * @param string $value + * @param mixed $value * @param integer $cid * @return integer|bool * @throws Exception */ - public function setField(string $name, string $type, string $value, int $cid) + public function setField(string $name, string $type, $value, int $cid) { if ( empty($name) || !$this->checkFieldName($name) - || !in_array($type, ['str', 'int', 'float']) + || !in_array($type, ['str', 'int', 'float', 'json']) ) { return false; } + if ($type === 'json') { + $value = json_encode($value); + } + $exist = $this->db->fetchRow($this->db->select('cid')->from('table.fields') ->where('cid = ? AND name = ?', $cid, $name)); + $rows = [ + 'type' => $type, + 'str_value' => 'str' == $type || 'json' == $type ? $value : null, + 'int_value' => 'int' == $type ? intval($value) : 0, + 'float_value' => 'float' == $type ? floatval($value) : 0 + ]; + if (empty($exist)) { - return $this->db->query($this->db->insert('table.fields') - ->rows([ - 'cid' => $cid, - 'name' => $name, - 'type' => $type, - 'str_value' => 'str' == $type ? $value : null, - 'int_value' => 'int' == $type ? intval($value) : 0, - 'float_value' => 'float' == $type ? floatval($value) : 0 - ])); + $rows['cid'] = $cid; + $rows['name'] = $name; + + return $this->db->query($this->db->insert('table.fields')->rows($rows)); } else { return $this->db->query($this->db->update('table.fields') - ->rows([ - 'type' => $type, - 'str_value' => 'str' == $type ? $value : null, - 'int_value' => 'int' == $type ? intval($value) : 0, - 'float_value' => 'float' == $type ? floatval($value) : 0 - ]) + ->rows($rows) ->where('cid = ? AND name = ?', $cid, $name)); } } @@ -872,7 +873,8 @@ class Contents extends Base implements QueryInterface ->where('cid = ?', $this->cid)); foreach ($rows as $row) { - $fields[$row['name']] = $row[$row['type'] . '_value']; + $value = 'json' == $row['type'] ? json_decode($row['str_value'], true) : $row[$row['type'] . '_value']; + $fields[$row['name']] = $value; } return new Config($fields); diff --git a/var/Widget/Contents/Post/Edit.php b/var/Widget/Contents/Post/Edit.php index fa8c1e5d..1679d7c4 100644 --- a/var/Widget/Contents/Post/Edit.php +++ b/var/Widget/Contents/Post/Edit.php @@ -229,8 +229,14 @@ class Edit extends Contents implements ActionInterface if (preg_match("/^fields\[(.+)\]$/", $name, $matches)) { $name = $matches[1]; } else { + $inputName = 'fields[' . $name . ']'; + if (preg_match("/^(.+)\[\]$/", $name, $matches)) { + $name = $matches[1]; + $inputName = 'fields[' . $name . '][]'; + } + foreach ($item->inputs as $input) { - $input->setAttribute('name', 'fields[' . $name . ']'); + $input->setAttribute('name', $inputName); } } @@ -662,8 +668,8 @@ class Edit extends Contents implements ActionInterface } $customFields = $this->request->getArray('fields'); - if (!empty($customFields)) { - $fields = array_merge($fields, $customFields); + foreach ($customFields as $key => $val) { + $fields[$key] = [is_array($val) ? 'json' : 'str', $val]; } return $fields; diff --git a/var/Widget/Themes/Config.php b/var/Widget/Themes/Config.php index 02bda8f8..ab97a269 100644 --- a/var/Widget/Themes/Config.php +++ b/var/Widget/Themes/Config.php @@ -71,7 +71,9 @@ class Config extends BaseOptions if (!empty($inputs)) { foreach ($inputs as $key => $val) { - $form->getInput($key)->value($this->options->{$key}); + if (isset($this->options->{$key})) { + $form->getInput($key)->value($this->options->{$key}); + } } }