部署SCNUOJ
前置条件:服务器为2核4G内存60G硬盘5M带宽的腾讯云,ubuntu20.04,刚租完开机的初始状态
安装
拉仓库
腾讯云默认登录是 ubuntu
用户,先提个权:
1 | sudo su |
root 下才能操作并新建这个 /var/www/scnuoj
目录,以该目录为项目根目录。
因为下文
git clone
会新建文件夹,所以实际上在/var/www
执行下面 clone 即可
在项目根目录下,克隆仓库:(仓库大小约 ,且可能腾讯云限速问题,故需要一定时间)
1 | git clone https://github.com/scnu-socoding/scnuoj.git |
(
https 不行,会GnuTLS recv error (-54): Error in the pull function.
)git 协议不行,如果本地 git 没有配置用户的话,所以推荐 https 协议
新机子没有密钥,不能 clone,可以生成一个,如:
1 ssh-keygen -t rsa -C "lr580@scnu.edu.cn" #一路回车
装依赖
腾讯云初始无 composer,需要先:
1 apt install composer
composer install
会安装当前目录下的composer.json
的内容,用于管理 PHP 依赖看看自己装没装 PHP 或核对版本,使用
php -v
,查看 composer 需要的版本:
1 composer show --platform
使用 root 用户,执行:(虽然 root 会提示 Do not run Composer as root/super user!
,但是这个目录只有 root 有权限)
1 | composer install |
如果遇到了:
1
2 the requested PHP extension curl is missing from your system
the requested PHP extension dom is missing from your system安装 php 扩展
ext-dom
和ext-curl
,如:(非 root 则 sudo)
1
2 apt-get install php7.4-dom
apt-get install php-curl当前还没启动服务器,如果启动了,要重启 apache 或 nginx
如果一直卡 connecting,可以连镜像站:
1
2
3 composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
#取消镜像站:
composer config -g --unset repos.packagist以 font awesome 为例,如果镜像也不行,可以手动下载:
如在 release 找到对应版本(卡connecting的版本),下载 source code,发给服务器。(我在做这个的时候,connecting 转龟速 download 了,所以暂时不管这个了,这个没做下去)
数据库
LNMP 其实本来应该 composer 前做的,但是我盲了
LNMP Linux + NGINX + MariaDB + PHP(7.4 或更高版本)
需要到的 PHP 插件包括 php-curl
, php-xml
, php-fpm
, php-mysql
。除去上面装了的,还需要安装:
1 | apt-get install php-xml |
查看有没有装数据库:
1 mysql --version发现没有,证明 MySQL 或 MariaDB 都没装
安装:
1 | apt-get install mariadb-server |
root 下执行 mysql
进入数据库,给数据库添加管理员帐号:(账号密码自取,这里任意)
1 | create user 'lr580'@'localhost' identified by '1437abcd'; |
新建个数据库:
1 | create database scnuoj; |
编辑项目根目录 config/db.php
,修改 username
, password
和对应 dsn
,分别是数据库用户名、密码、数据库名,改这几行:
1 | 'dsn' => 'mysql:host=localhost;dbname=scnuoj', |
nginx
查
nginx -v
发现没装 nginx。
安装 nginx:
1 | apt-get install nginx |
修改 /etc/nginx/sites-enabled/default
,为:
1 | server { |
解读:
第二行表示 IPv4 端口,第三行是 IPv6 端口。
在项目根目录
web/
是 PHP 页面所在,故/var/www/scnuoj/web
对应那个 PHP 服务器根目录
client_max_body_size
不限制客户端请求的请求体大小。通常,这个设置用来控制上传文件的大小默认索引网页和服务器名配置
将根目录
/
的请求尝试查找匹配的文件或目录,找不到给 index以
.php
结尾的,特殊处理,连接到套接字shell 输入下面指令看看那个 pass 是不是存在:
1
2
3
4
5 if stat /var/run/php/php7.4-fpm.sock &> /dev/null; then
echo "Unix socket exists."
else
echo "Unix socket does not exist."
fi如果上面 LNMP 装了那个插件,应该是 exists 的。
看看 ngnix 是否启动、是否开机自启:
1
2 systemctl is-active nginx
systemctl is-enabled nginx
重启 nginx:
1 | nginx -t #检查配置语法错误 |
启动后,任意客户端尝试访问
http://114.132.159.213/
,发现 500,能访问。证明腾讯云默认开了防火墙。
yii
在项目根目录执行:
1 | ./yii install |
判题配置
sh 命令执行:
1 | useradd -m -u 1536 judge |
-m
是创建家目录,-u
制定 UID。
在 judge/
下执行:
1 | make |
执行 make 失败,报错为:
1
2
3
4
5
6 gcc -std=gnu99 -Wall -c -I/usr/local/mysql/include/mysql -I/usr/include/mysql src/dispatcher.c
src/dispatcher.c:33:10: fatal error: mysql/mysql.h: No such file or directory
33 | #include <mysql/mysql.h>
| ^~~~~~~~~~~~~~~
compilation terminated.
make: *** [makefile:2: all] Error 1执行命令:
1 apt-get install libmysqlclient-dev之后再执行,成功,一堆 warning,暂时不管。
启动判题机:
1 ./dispather关闭判题机:
1 pkill -9 dispatcher
以 OI 模式启动判题机:
1 | ./dispather -o |
Polygon 判题机部署,在项目 polygon/
目录:
1 | make |
启动出题系统判题机:
1 | ./polygon |
数据库初始化
在 nginx 后,500 了,但是没管,现在开始修复。
开启 DEBUG,在 web/inedx.php
,注释第四第五行的 defined。
发现无 scnuoj 数据库。上一步没新建,所以数据库那里新建一下。
下一个问题是数据库的数据表不存在。
受 升级指引 灵感启发,考虑数据库迁移当初始化,执行:
1 | ./yii migrate |
之后需要输入 yes,然后输入账号密码和邮箱,是登录该 OJ 的管理员账号基本信息。
重启判题机。至此,部署完毕,访问网页正常。
安装编程语言
然而,发现只有 C 和 python 能过题,C++ 和 java 并不能过题。继续检查:
1
2
3
4 gcc --version
g++ --version
java --version # javac --version
python --version # python3 --version
发现没有安装 c++ 和 java,进行安装:
1 | apt install g++ |
安装结束,重新判题,都能过题,其中 C++ 版本为 201402。
验证码支持
继续测试,发现无法注册新用户。报错为:
1 | Invalid Configuration – yii\base\InvalidConfigException |
查找 PHP 配置文件位置:
1 php -i | grep 'Loaded Configuration File'
找不到 extension=gd
和 extension=imagick
扩展,故安装 PHP 扩展:
1 | apt-get install php-gd |
两个图像处理库,能够支持生成图片验证码。
执行后,可以正常注册新用户。
下载测试点支持
无法下载测试点,也无法根据输入生成输出。
提示: 服务器未启用 php-zip
扩展,如需下载测试数据,请安装 php-zip
扩展。
1 | sudo apt install php-zip |
看到后台最大上传文件大小 8M,单个文件 2M,想改一下。
找到 PIP 路径,如输出 php -ini
看,或者直接盲猜 /etc/php/7.4/fpm/php.ini
。
可以 ps aux | grep php
找。
PHP CLI (Command Line Interface) 改这个没用
PHP-FPM (FastCGI Process Manager) 这个才是跑 OJ 的
修改:(第一个单文件,第二个总)
1 | upload_max_filesize = 100M |
vscode remote ssh 改不了可以先 chmod 改完再弄回去
重启:(非 root 不 sudo 可能要登录密码)
1 | sudo systemctl restart php7.4-fpm |
如果改的是 cli 路径下的配置文件,则后台不见效。
二次开发SCNUOJ
学号前端修改
前端、注册把昵称改成真实姓名,学号改成学校班级,先查查有什么文件:
1 | grep -rnl "学号" . |
r
递归,n
显示行号,l
显示文件路径
找到有:
1 | ./modules/admin/views/user/index.php |
全部 ctrl+f 改即可。
昵称同理。修改:
1 | controllers/GroupController.php |
发现问题,注册时输入学号只能输入数字,无法输入任意字符。
修改:models/SignupForm.php
,注释掉 rules()
里边的:
1 | ['studentNumber', 'integer'], |
关闭评论区
偷懒,考虑虚假关闭:只不显示前端进去的入口,但是直接 url 可以访问,不真的控制权限。
根据主页提示词,找到讨论区主页:
1 grep -r "仅展示最近三十则讨论消息,在问题页可以查看该 问题下的所有讨论。"发现是:
1 views/discuss/index.php开 F12,看讨论标签,发现是
fa-comment
。可以把这行字关掉。如改成:
1 <i class="fas fa-fw fa-info-circle"></i> 论坛功能不予开放,不便之处敬请谅解。
阅读 view/problem/view.php
,发现有 Yii::$app->setting->get('isDiscuss')
继续搜索:grep -r isDiscuss
,找到有效的:
1 | modules/admin/views/setting/index.php |
——原来,本来就有这个功能,后台直接选择即可。没事了。
备案号添加
域名证书可以在腾讯云直接点击容易搜到下载,如果是腾讯云买的域名
需要添加两个东西,理论上有内容就行,没有样式要求规定。这里懒,所以只渲染出内容即可。
找到主页为 views/site/index.php
,可以在最底下追加:
1 | <footer> |
其中,备案号,可以在 href 里搜,如直接搜 young-oj.cn
,就出来了。
之后再更新
修改代码结果页
很多人反馈说“标准输出”与“答案”有歧义,
通过 grep -r "标准输出" .
和 "答案"
,找到修改页为 var/www/scnuoj/web/js/app.js
的第二个搜索项(或全部),修改即可。
交 pr。
排行榜缓存优化
加载排行榜很慢需要重新计算,考虑缓存优化。下下策:隐藏接口。
中策:修改数据库结构,加表。
据说有现成实现,可以调用 Yii 的缓存功能,如:参考文献
1
2 $cache = Yii::$app->cache;
$tags = $cache->get('problem-tags');
1
2
3
4
5
6
7
8
9
10
11
12
13 public function getExpensiveQueryResult()
{
$cacheKey = 'expensive-query-result';
$data = Yii::$app->cache->get($cacheKey);
if ($data === false) {
// 缓存中没有数据,执行数据库查询
$data = $this->executeExpensiveQuery();
// 将查询结果存储到缓存中,设置有效期为 600 秒(10分钟)
Yii::$app->cache->set($cacheKey, $data, 600);
}
return $data;
}
顾名思义找到控制器为 controllers/RatingController.php
,视图为 views/rating/index.php
。
GPT 给出对 actionIndex()
的修改为:
1 | public function actionIndex() |
添加显示上次更新的时间:
1 | // ...之前的代码 |
视图合适地方添加:
1 | <?php if (isset($lastUpdated)): ?> |
调试用,马上刷新缓存:
1 | public function actionClearCache() |
1 | <?= Html::a('刷新榜单', ['rating/clear-cache'], ['class' => 'btn btn-warning']) ?> |
合并前端样式以美观化,按钮管理员可见:
1 | <style> |
因为没有报错,所以 OJ 本来就支持 Yii cache 功能,不需要额外配置。pr。
后来,发现无法翻页,翻页后仍在第一页。修改前没这个 bug。考虑修复。
问题出在 offset 存缓存了,修改一下逻辑。修改为:
1 | public function actionIndex() |
重新 pr。
后来发现显示的排名不正确,多了一个页的偏移,故修改视图的:
1 | $num = $k + $currentPage * $defaultPageSize + 1; |
为:
1 | $num = $k + ($currentPage-1) * $defaultPageSize + 1; |
再次 pr。
注册时输入昵称
找到 views/site/signup.php
,在 <?php $form = ActiveForm::begin(['id' => 'form-signup']); ?>
下合适位置添加:
1 | <small class="text-secondary">请在这里填写你的昵称。若缺省则与用户名一致。</small> |
找到 modes/SignupForm.php
,在 signup
将:
1 | $user->nickname = $this->username; |
改为:
1 | $user->nickname = $this->nickname; |
在 rules()
函数里添加:
1 | ['nickname', 'string', 'max' => 16, 'message' => '长度不超过 16 字符'], |
阅读 models/User.php
的 attributeLabels
,它是上文 placeholder 的填充物,发现需要设置 Yii::t
(messages/zh-CN/app.php
)。所以依葫芦画瓢,在 models/SignupForm.php
的对应方法 attributeLabels
添加:
1 | 'nickname' => Yii::t('app', 'Nickname'), |
在 model/SignupForm.php
class 定义添加成员属性:
1 | public $nickname; |
最后更新: 2024年01月22日 16:36
原始链接: https://lr580.github.io/2023/09/02/SCNUOJ%E9%83%A8%E7%BD%B2/