Ubuntu 22.04 安装 Framadate 1.1.19 指南
Framadate 1.1.19 在 Ubuntu 22.04.5 上的完整安装实测:Apache+mod_php 生产方案、php -S 最小形态、含 vendor 离线包方案三条路径,覆盖源码下载、composer 依赖(含代理降级说明)、安装向导迁移建表、clean URL 与端到端验证(监听端口 8145)。
Ubuntu 22.04 安装 Framadate 1.1.19 指南
目标:在一台全新的 Ubuntu 22.04.5 LTS 服务器上,从零安装 Framadate 1.1.19 日程投票服务并完成端到端验证(建票、投票、CSV/ICS 导出)。本文共给出三种安装方案——Apache + mod_php 生产方案、php -S 内置服务器最小形态、含 vendor 的离线包方案,全部已在监听端口 8145 的真实环境逐条实测通过。软件背景与选型对比见 《Framadate 1.1.19 介绍与选型指南》。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Web 服务器:Apache 2.4.52-1ubuntu4.25(mod_php 模式,监听 8145 端口)
- PHP:8.1.2-1ubuntu2.28(cli + libapache2-mod-php8.1)
- 数据库:MariaDB 10.6.23(
1:10.6.23-0ubuntu0.22.04.1) - 依赖管理:Composer 2.2.6(apt 源
2.2.6-2ubuntu4) - 应用代码目录:
/var/www/framadate(属主www-data:www-data) - 数据库名/账号:
framadate/framadate(密码q1w2e3r4,表前缀fd_) - 应用版本:Framadate 1.1.19(源码包 sha256
160dd2efa1aa5be8945d65778dbd2328166fafafa29c5c823053e2112224a478)
二、前置条件
安装前确认四项条件,缺一都会在后续步骤报错:
- PHP 版本:源码
app/inc/constants.php钉住最低版本const PHP_NEEDED_VERSION = '7.3';,Ubuntu 22.04 自带 PHP 8.1 满足;但 PHP 8.1 存在两处兼容性缺陷(strftime、SMTP 默认开启),本文与第九章、后续排错文档已给出修复动作。 - PHP 扩展:
intl、mbstring、openssl、pdo_mysql、xml、zip、curl。安装向导的体检页admin/check.php会逐项检查,实测回显:
php -m | grep -iE "^(pdo_mysql|mbstring|intl|xml|zip|curl|json)$"
curl
intl
json
mbstring
pdo_mysql
xml
zip
- Apache mod_rewrite:启用「干净链接」(
/dvdEakcXnbWf7eXf形式的投票短 URL)依赖 rewrite 模块与AllowOverride All,实测已加载:
apache2ctl -M 2>/dev/null | grep -E "rewrite|php"
php_module (shared)
rewrite_module (shared)
- 可写目录:Smarty 编译缓存目录
tpl_c/必须对www-data可写,实测权限:
stat -c "%U:%G %a %n" /var/www/framadate/tpl_c
www-data:www-data 755 /var/www/framadate/tpl_c
💡 技术拓展:PHP 应用的执行方式不止 mod_php 一种。常见形态对比——
方式 原理 适用场景 Apache mod_php PHP 解释器嵌入 Apache 进程内 单机小流量、配置最简(本文方案 A) Nginx/Apache + PHP-FPM Web 服务器经 FastCGI 调用独立 php-fpm 进程池 生产高并发、内存可控 php -S 内置服务器 PHP CLI 自带单线程 HTTP 服务 开发调试、功能验证,禁用于生产(本文方案 B) CLI/内置 cgi 按需单次执行 定时任务脚本 本文生产主线采用 mod_php(与 Ubuntu 默认
libapache2-mod-php包一致、步骤最少);Framadate 官方文档同样只要求「任意能执行 PHP 的 Web 服务器」,换 PHP-FPM 仅需替换 vhost 中的解释器配置,应用侧无差异。
💡 技术拓展:数据库引擎选择。Framadate 通过 PDO DSN(
DB_CONNECTION_STRING)连接数据库,看似可换引擎,但核心类FramaDB::allTables()使用SHOW TABLES这类 MySQL 系专属语法,迁移脚本亦按 MySQL 语法编写——实际仅支持 MySQL / MariaDB,PostgreSQL 不可用。本文采用 Ubuntu 22.04 默认的 MariaDB 10.6。
三、版本选型说明
| 版本 | 发布日期 | 要点 |
|---|---|---|
| 1.1.19(本文采用) | 2021-12-23 | 最新稳定版;仅修复邮件头 X-Mailer 被判垃圾的问题 |
| 1.1.18 | 2021-12-21 | 依赖更新;弃管的 SimpleMDE 换成 EasyMDE 分支;强制校验投票截止日期 |
| 1.1.17 | 2021-10-18 | 新增把「最优选项」导出为 ICS 日历文件 |
版本与日期取自官方仓库 CHANGELOG.md 头部实测(1.1.19 条目原文:Remove the X-Mailer header in e-mails, as this causes some email servers to see emails sent by Framadate as spam)。选型结论:直接用 1.1.19——它是官方 releases 订阅源中的最新版(2026-11-01 查询确认此后无新版本),1.1.x 系列数据库结构一致,装 1.1.17/1.1.18 后续也只是走同一迁移路径。
注意:GitHub 的 tag 源码归档包(framadate-1.1.19.tar.gz,2,926,008 字节)不含 vendor/ 依赖目录,装完代码必须再执行 composer 拉取 14 个生产依赖(见 4.5 节);这是自托管安装最常见的踩坑点。
四、方案 A:Apache + mod_php 生产安装(主线)
4.1 方案说明
全在线安装:apt 装齐 Apache/PHP/MariaDB/Composer,从 GitHub 下载 1.1.19 tag 源码归档,composer 拉依赖,配置 8145 端口 vhost 与 .htaccess 干净链接,最后走 Web 安装向导完成数据库迁移建表。适合可访问外网的正式部署。
4.2 安装系统依赖包
apt-get update
apt-get install -y apache2 libapache2-mod-php php php-cli php-mysql \
php-mbstring php-xml php-zip php-curl php-intl mariadb-server composer
输出节选(实测首尾):安装事务共带入 60 余个包,关键包落版本如下(dpkg -l 实测):
apache2 2.4.52-1ubuntu4.25
libapache2-mod-php8.1 8.1.2-1ubuntu2.28
mariadb-server 1:10.6.23-0ubuntu0.22.04.1
composer 2.2.6-2ubuntu4
php-mysql 2:8.1+92ubuntu1
验证四个组件版本与 systemd 状态:
apache2 -v; php -v | head -1; mariadb --version; composer --version
systemctl is-active apache2
systemctl is-active mariadb
Server version: Apache/2.4.52 (Ubuntu)
PHP 8.1.2-1ubuntu2.28 (cli) (built: Oct 19 2026 18:54:45) (NTS)
mariadb Ver 15.1 Distrib 10.6.23-MariaDB, for debian-linux-gnu (x86_64) using EditLine wrapper
Composer 2.2.6 2022-02-04 17:00:38
active
active
4.3 创建数据库与授权
以 root 登录 MariaDB,建库、建专用账号并授权(演示口令按规范落实际值):
mysql -uroot -e "CREATE DATABASE framadate CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'framadate'@'localhost' IDENTIFIED BY 'q1w2e3r4';
GRANT ALL PRIVILEGES ON framadate.* TO 'framadate'@'localhost';
FLUSH PRIVILEGES;"
验证授权生效:
mysql -uroot -e "SHOW GRANTS FOR 'framadate'@'localhost';"
Grants for framadate@localhost
GRANT USAGE ON *.* TO `framadate`@`localhost` IDENTIFIED BY PASSWORD '*0971389F8E7F1AEB999104BDA7A0FA145087F348'
GRANT ALL PRIVILEGES ON `framadate`.* TO `framadate`@`localhost`
⚠️ 注意:MariaDB 10.6 在 Ubuntu 上 root 默认走 unix_socket 认证,
mysql -uroot需以系统 root 身份执行;应用账号framadate仅授予framadate.*,遵循最小权限。
4.4 下载并部署源码包
wget https://github.com/framasoft/Framadate/archive/refs/tags/1.1.19.tar.gz \
-O framadate-1.1.19.tar.gz
sha256sum framadate-1.1.19.tar.gz
ls -l framadate-1.1.19.tar.gz
160dd2efa1aa5be8945d65778dbd2328166fafafa29c5c823053e2112224a478 framadate-1.1.19.tar.gz
-rw-r--r-- 1 root root 2926008 Nov 1 20:45 framadate-1.1.19.tar.gz
解包并放入 Web 根,属主交给 Apache 运行账号:
tar xzf framadate-1.1.19.tar.gz
mv framadate-1.1.19 /var/www/framadate
chown -R www-data:www-data /var/www/framadate
ls /var/www/framadate | head -12
action
admin
adminstuds.php
app
AUTHORS.md
bandeaux.php
CHANGELOG.md
compare.php
composer.json
composer.lock
create_classic_poll.php
css
顶层即多页应用入口:index.php(首页)、create_date_poll.php(建时间投票)、studs.php(投票页)、adminstuds.php(管理页)、exportcsv.php(CSV 导出)、maintenance.php(降级页)、admin/(安装/迁移/清理等运维页)。
4.5 composer 安装生产依赖
cd /var/www/framadate
composer install --no-dev
⚠️ 网络说明(实测降级记录):composer 需从
framagit.org拉取o80/i18n(dev-develop 分支,走 git clone)。该域名直连实测超时失败:Failed to execute git clone --mirror 'https://framagit.org/framasoft/framadate/o80-i18n' ... Failed to connect to framagit.org port 443 after 137538 ms。当前环境直连不通时,代理192.168.1.72:7897实测可用(192.168.1.62:7897实测不可用),设置环境变量后重跑即成功:export http_proxy=http://192.168.1.72:7897 https_proxy=http://192.168.1.72:7897 composer install --no-dev
安装完成后核对依赖清单(composer show 实测,共 14 个生产包):
doctrine/lexer 1.2.1
egulias/email-validator 3.1.2
erusev/parsedown 1.7.4
ircmaxell/password-compat dev-master dfdbc46
o80/i18n dev-develop 7b59cf9
phpmailer/phpmailer v6.5.3
roave/security-advisories dev-master fff5363
sabre/uri 2.2.2
sabre/vobject 4.4.1
sabre/xml 2.2.5
smarty/smarty v4.0.0
symfony/polyfill-intl-idn v1.23.0
symfony/polyfill-intl-normalizer v1.23.0
symfony/polyfill-php72 v1.23.0
模板引擎 Smarty 4、日历对象 sabre/vobject(ICS 导出)、PHPMailer(通知邮件)三大件都在其中;roave/security-advisories 会在安装时拦截已知漏洞版本的依赖,属安全防线而非运行时组件。
4.6 配置 Apache 虚拟主机(8145 端口)
先确认端口空闲,再写 vhost:
ss -ltn | grep 8145
(无输出,端口空闲)
新建 /etc/apache2/sites-available/framadate.conf(实测文件全文):
<VirtualHost *:8145>
ServerName framadate.local
DocumentRoot /var/www/framadate
<Directory /var/www/framadate>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/framadate_error.log
CustomLog ${APACHE_LOG_DIR}/framadate_access.log combined
</VirtualHost>
AllowOverride All 是干净链接生效的前提(允许应用目录的 .htaccess 覆盖主配置)。让 Apache 监听 8145 并启用站点:
echo "Listen 8145" >> /etc/apache2/ports.conf
a2enmod rewrite
a2ensite framadate.conf
systemctl reload apache2
验证 vhost 与监听:
apache2ctl -S 2>&1 | sed -n "2,3p"
ss -ltn | grep 8145
VirtualHost configuration:
*:8145 framadate.local (/etc/apache2/sites-enabled/framadate.conf:1)
LISTEN 0 511 0.0.0.0:8145 0.0.0.0:* users:(("apache2",pid=15383,fd=4),("apache2",pid=15388,fd=4))
(ss 回显节选:监听进程为 apache2 主进程 15383 及其余 5 个工作子进程,此处展示前两个。)
4.7 启用干净链接(.htaccess)
源码自带规则模板 htaccess.txt,复制为 .htaccess 即启用(配置项 URL_PROPRE = true 与之配套):
cd /var/www/framadate
cp htaccess.txt .htaccess
chown www-data:www-data .htaccess
head -14 .htaccess
######################
# .htaccess example. #
######################
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule . - [L]
RewriteRule ^([a-zA-Z0-9-]+)$ studs.php?poll=$1 [L]
RewriteRule ^([a-zA-Z0-9-]+)/action/([a-zA-Z_-]+)/(.+)$ studs.php?poll=$1&$2=$3
规则把 /dvdEakcXnbWf7eXf 重写为 studs.php?poll=dvdEakcXnbWf7eXf,把 /dvdEakcXnbWf7eXf/action/get_ical_file/MDgtMTEtMjAyNnwxNDowMA 这类带 base64url 动作参数的路径重写为 studs.php?poll=dvdEakcXnbWf7eXf&get_ical_file=MDgtMTEtMjAyNnwxNDowMA 形式的请求——这正是 ICS 日历导出的入口格式。
4.8 运行 Web 安装向导与数据库迁移
浏览器访问 http://<服务器IP>:8145/:首次运行(app/inc/config.php 尚不存在)会自动进入 admin/install.php 安装向导。向导两步:第 1 步环境体检(即 4.3 节前置条件的在线版);第 2 步填写数据库 DSN、账号、表前缀(mysql:host=localhost;dbname=framadate;port=3306、framadate/q1w2e3r4、fd_),提交后向导生成 app/inc/config.php 并自动执行 admin/migration.php 建表。
实测迁移与建表结果:
mysql -uframadate -pq1w2e3r4 framadate -e "SHOW TABLES;"
Tables_in_framadate
fd_comment
fd_framadate_migration
fd_poll
fd_slot
fd_vote
迁移记录表逐条留痕(输出节选,实测首尾;13 条迁移全部登记):
id name execute_date
1 Framadate\Migration\From_0_0_to_0_8_Migration 2026-11-01 14:18:49
13 Framadate\Migration\Fix_MySQL_No_Zero_Date 2026-11-01 14:18:49
💡 说明:
migration.php内置 14 个迁移类(其中AddColumn_ValueMax_In_poll_For_1_1在清单中重复出现一次,实际执行 13 条)。迁移按记录表判重,可安全重跑:再次访问admin/migration.php返回 200 且逐条显示Passé(已执行跳过),实测幂等。
⚠️ 注意(实测坑):向导第 2 步生成的
config.php模板把'use_smtp' => true硬编码写入,而新装机器通常没有本机 SMTP——后果是建票最后一步点「创建」直接 HTTP 500(PHPMailerSMTP connect() failed),且 500 发生在投票已写库之后,会留下「已建票但没拿到管理链接」的孤儿票。无邮件需求时装完立即关闭邮件开关并清孤儿票:sed -i "s/'use_smtp' => true/'use_smtp' => false/" /var/www/framadate/app/inc/config.php mysql -uframadate -pq1w2e3r4 framadate -e \ "DELETE FROM fd_poll WHERE creation_date > NOW() - INTERVAL 10 MINUTE AND id NOT IN (SELECT poll_id FROM fd_vote);"完整错误回显与定位过程见第九章 9.2。
若不便走浏览器向导,也可手工落配置:把 4.4 节源码包中的 app/inc/config.php.sample 复制为 app/inc/config.php,改 DB_CONNECTION_STRING、DB_USER、DB_PASSWORD 三处即可(向导生成的文件与该 sample 结构完全一致),随后访问一次 admin/migration.php 完成建表。
4.9 systemd 托管
Apache 与 MariaDB 均为发行版 systemd 单元,设置开机自启并确认:
systemctl enable apache2
systemctl enable mariadb
systemctl is-enabled apache2
systemctl is-enabled mariadb
systemctl status apache2 --no-pager -l | head -6
enabled
enabled
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2026-11-01 14:30:17 UTC; 7min ago
Docs: https://httpd.apache.org/docs/2.4/
Process: 15379 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
Main PID: 15383 (apache2)
4.10 端到端验证
首页与干净链接投票页:
curl -sI http://localhost:8145/ | head -4
curl -s http://localhost:8145/ | grep -oE "<title>[^<]*" | head -1
curl -s -o /dev/null -w "cleanUrl投票页 %{http_code}\n" http://localhost:8145/dvdEakcXnbWf7eXf
curl -s -o /dev/null -w "install.php重访 %{http_code} -> %{redirect_url}\n" http://localhost:8145/admin/install.php
HTTP/1.1 200 OK
Date: Sun, 01 Nov 2026 14:38:14 GMT
Server: Apache/2.4.52 (Ubuntu)
Set-Cookie: PHPSESSID=rhpelae42dcgc1sq46ug964bv1; path=/
<title>Organiser des rendez-vous simplement, librement. - Framadate
cleanUrl投票页 200
install.php重访 302 -> http://localhost:8145/
已配置实例重访 install.php 会被 302 弹回首页(防重复安装),属正常行为。
建票→投票→导出全链路实测:三步向导建「日期投票」得公开链接 dvdEakcXnbWf7eXf 与管理链接(24 位 admin_id);两名投票人提交后查库:
mysql -uframadate -pq1w2e3r4 framadate -e "SELECT name,choices FROM fd_vote;"
curl -s "http://localhost:8145/exportcsv.php?poll=dvdEakcXnbWf7eXf" | head -4
name choices
Alice 20
Bob 12
,"01/01/1970","01/01/1970","01/01/1970","01/01/1970","01/01/1970","01/01/1970","08/11/2026","08/11/2026","08/11/2026",
,"","","","","","","10:00","14:00","",
"Alice","Oui","Non",
"Bob","Si nécessaire","Oui",
fd_vote.choices 的值 20/12 是「每位投票人对各时间槽的表态」按位编码(0=拒绝、1=待定、2=同意;20 即第一槽同意、第二槽拒绝)。CSV 表头出现 01/01/1970 列属正常:建票时日期网格中未勾选的空槽(fd_slot.title 为空)经 strftime 渲染成纪元零点,导出正文数据不受影响。
五、方案 B:php -S 内置服务器最小形态
5.1 方案说明
不装 Apache,直接用 PHP 自带 HTTP 服务器把 4.2~4.5 节部署好的代码跑起来,用于功能验证、内网临时试用或排障对照。单线程、无访问日志切分、不解析 .htaccess,禁止生产使用。
5.2 启动与验证
cd /var/www/framadate
php -S 127.0.0.1:8113 -t /var/www/framadate &
sleep 2
curl -s -o /dev/null -w "php -S 首页: %{http_code}\n" http://127.0.0.1:8113/
php -S 首页: 200
[Sun Nov 1 14:39:45 2026] PHP 8.1.2-1ubuntu2.28 Development Server (http://127.0.0.1:8113) started
[Sun Nov 1 14:39:47 2026] 127.0.0.1:51552 Accepted
[127.0.0.1:51552] 127.0.0.1:51552 [200]: GET /
php -S 不支持 .htaccess,干净链接失效,投票页须用查询串形式访问,实测 200:
curl -s -o /dev/null -w "php -S 投票页: %{http_code}\n" \
"http://127.0.0.1:8111/studs.php?poll=dvdEakcXnbWf7eXf"
php -S 投票页: 200
⚠️ 注意:php -S 单线程串行处理请求,页面内若有自回调(如再拉静态资源)会明显变慢;用完
kill %1关闭即可。
六、方案 C:离线包部署(网络隔离环境)
6.1 方案说明
Framadate 无发行版软件包,内网隔离机无法执行 4.5 节的 composer 拉依赖。做法:在联网机按方案 A 装好代码与 vendor/ 后,把「代码+依赖」整体打成离线包传输,目标机解包即用。
6.2 打包与传输
联网机上执行(排除含密码的运行时配置,其余全量入包):
cd /var/www
tar czf /root/framadate-1.1.19-offline.tar.gz \
--exclude="framadate/app/inc/config.php" framadate
ls -lh /root/framadate-1.1.19-offline.tar.gz
-rw-r--r-- 1 root root 3.6M Nov 1 14:38 /root/framadate-1.1.19-offline.tar.gz
包体 3.6M(纯源码包 2.8M + vendor 依赖),经 scp/U 盘送达目标机。
6.3 目标机解包与验证
目标机只需 apt 装 apache2 libapache2-mod-php php-mysql mariadb-server(或离线 debs)+ 建库授权(同 4.3 节),然后:
mkdir -p /opt/framadate-offline
tar xzf /root/framadate-1.1.19-offline.tar.gz -C /opt/framadate-offline
cp /var/www/framadate/app/inc/config.php /opt/framadate-offline/framadate/app/inc/config.php
chown -R www-data:www-data /opt/framadate-offline/framadate
php -S 127.0.0.1:8112 -t /opt/framadate-offline/framadate &
sleep 2
curl -s -o /dev/null -w "离线包php -S 8112: %{http_code}\n" http://127.0.0.1:8112/
离线包php -S 8112: 200
<title>Organiser des rendez-vous simplement, librement. - Framadate
💡 说明:目标机若无现成 config,从包内
app/inc/config.php.sample复制并按 4.8 节改三处 DB 参数即可;迁移表fd_framadate_migration随 mysqldump 数据一起恢复时,admin/migration.php重跑显示全部Passé,无需重复迁移。
七、方案对比与选择建议
| 维度 | 方案 A(Apache+mod_php) | 方案 B(php -S) | 方案 C(离线包) |
|---|---|---|---|
| 版本 | 1.1.19 源码 + composer 在线拉依赖 | 同 A(复用 A 的代码目录) | 同 A(依赖已封入 3.6M 包) |
| 是否需联网 | 需(GitHub + packagist + framagit,后者可能要代理) | 否 | 仅打包机需 |
| 安装方式 | apt + tar + composer | 复用 A 产物 | tar 解包 |
| systemd 来源/服务名 | apache2.service、mariadb.service | 无(手工进程) | 同 A |
| 监听端口 | 8145(可改) | 8113(临时) | 8145 或任意 |
| 干净链接 | 支持(.htaccess+rewrite) | 不支持(查询串访问) | 取决于 Web 服务器 |
| 适用 | 生产/长期运行 | 验证、试跑、排障 | 内网隔离交付 |
选择建议:能联网、要长期跑——方案 A;只想先验证功能或临时救急——方案 B;交付进网闸内网——方案 C。三者应用层完全同源,切换无数据迁移成本。
八、配置说明
应用配置集中在 /var/www/framadate/app/inc/config.php(安装向导生成或 sample 复制),关键项实测:
const DB_CONNECTION_STRING = 'mysql:host=localhost;dbname=framadate;port=3306';
const DB_USER= 'framadate';
const DB_PASSWORD = 'q1w2e3r4';
const TABLENAME_PREFIX = 'fd_';
const DEFAULT_LANGUAGE = 'fr';
const URL_PROPRE = true;
const PURGE_DELAY = 60;
const MAX_SLOTS_PER_POLL = 366;
$config = [
'use_smtp' => false,
'smtp_options' => [ 'host' => 'localhost', 'port' => 25, 'auth' => false ],
'show_what_is_that' => true,
'default_poll_duration' => 180,
'user_can_add_img_or_link' => true,
'markdown_editor_by_default' => true,
];
DB_CONNECTION_STRING/DB_USER/DB_PASSWORD:PDO DSN 与账号,改库只动这三处;TABLENAME_PREFIX:表前缀,默认fd_,迁移记录表实际名为fd_framadate_migration(前缀+MIGRATION_TABLE 拼接);DEFAULT_LANGUAGE:界面主语言,默认fr,访客可用?lang=en切英文;URL_PROPRE:置true必须同时完成 4.7 节.htaccess+AllowOverride All,否则投票短链 404;use_smtp:新装务必确认是false(见 4.8 节 ⚠️);PURGE_DELAY/MAX_SLOTS_PER_POLL:过期宽限天数与单票最大时间槽数,运维含义见运维篇。
Apache 侧另有两处:/etc/apache2/sites-available/framadate.conf(vhost)与 ports.conf 的 Listen 8145;日志在 ${APACHE_LOG_DIR} 即 /var/log/apache2/framadate_{access,error}.log。
九、常见问题
9.1 composer install 卡在 git clone 超时
现象:Failed to execute git clone --mirror 'https://framagit.org/framasoft/framadate/o80-i18n',Failed to connect to framagit.org port 443 after 137538 ms。原因:o80/i18n 依赖钉在 framagit.org 的 dev-develop 分支,不经 packagist 分发、必须现场 git clone,直连该站超时。解决:走代理重试(实测 192.168.1.72:7897 可用、192.168.1.62:7897 不可用):
export http_proxy=http://192.168.1.72:7897 https_proxy=http://192.168.1.72:7897
composer install --no-dev
或直接采用方案 C 从联网机搬运 vendor。
9.2 建票确认步 HTTP 500:SMTP connect() failed
实测错误日志原文(/var/log/apache2/framadate_error.log):
PHP Fatal error: Uncaught PHPMailer\PHPMailer\Exception: SMTP connect() failed.
https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting
in /var/www/framadate/vendor/phpmailer/phpmailer/src/PHPMailer.php:1982
#2 /var/www/framadate/app/classes/Framadate/Services/MailService.php(67)
#3 /var/www/framadate/create_date_poll.php(213): Framadate\Services\MailService->send()
定位:向导生成的 config.php 硬编码 'use_smtp' => true,create_date_poll.php 第 213 行建票后立刻发管理员邮件,本机无 SMTP 即 500。解决:use_smtp 改 false(见 4.8 节命令);注意 500 前投票已写库,按 4.8 节 DELETE 清掉孤儿票再重建,否则库里多一条拿不到管理链接的票。
9.3 投票短链 404
干净链接依赖三件套:URL_PROPRE = true、.htaccess 存在、vhost 的 AllowOverride All。缺一时短链 /dvdEakcXnbWf7eXf 404,而查询串 studs.php?poll=dvdEakcXnbWf7eXf 仍正常。逐项核对:
ls -l /var/www/framadate/.htaccess
grep -n "AllowOverride" /etc/apache2/sites-available/framadate.conf
apache2ctl -M | grep rewrite
9.4 CSV 导出 HTTP 500:strftime TypeError
实测错误日志原文:
PHP Fatal error: Uncaught TypeError: strftime(): Argument #2 ($timestamp) must be
of type ?int, string given in /var/www/framadate/exportcsv.php:80
原因:PHP 8.1 起 strftime() 第二参强制 int,而 fd_slot.title 从库取出是字符串。修复(本项目已停更、无官方补丁,需本地打):
cp /var/www/framadate/exportcsv.php /var/www/framadate/exportcsv.php.bak
sed -i 's/strftime(\$format, \$slot->title)/strftime($format, (int) $slot->title)/' \
/var/www/framadate/exportcsv.php
打完补丁 exportcsv.php 实测 200,text/csv 正常出文件(回显见 4.10 节)。
9.5 升级/重跑迁移会不会重复建表
不会。admin/migration.php 以 fd_framadate_migration 记录表判重,实测重跑返回 200、逐条 Passé(跳过),详见运维篇升级章节。
十、卸载与清理
按安装逆序清理(演示环境执行):
systemctl stop apache2
rm -f /etc/apache2/sites-enabled/framadate.conf
rm -f /etc/apache2/sites-available/framadate.conf
sed -i '/^Listen 8145$/d' /etc/apache2/ports.conf
rm -rf /var/www/framadate
rm -f /root/framadate-1.1.19-offline.tar.gz
mysql -uroot -e "DROP DATABASE framadate; DROP USER 'framadate'@'localhost';"
systemctl start apache2
验证端口与库均已消失:
ss -ltn | grep 8145; mysql -uroot -e "SHOW DATABASES LIKE 'framadate';"
(两条命令均无输出)
如连运行环境一并移除:apt-get purge -y framadate相关php包 按 4.2 节清单反向卸载即可(php-mysql 等公共包若被其他应用共享则保留)。
十一、参考链接
- 《Framadate 1.1.19 介绍与选型指南》(本专栏认知篇:架构、数据模型与选型对比)
- 《Bitpoll 0.11.0 介绍与选型指南》(同生态 Django 系投票工具,选型对照组)
- Framadate 源码仓库:https://github.com/framasoft/Framadate (tag 1.1.19 归档即本文 sha256 对应包)
- 官方仓库(主战场):https://framagit.org/framasoft/framadate
- 源码包内官方文档:
INSTALL.md、doc/TECHNICAL.md、doc/TREEVIEW.md - PHP 官方手册(strftime 8.1 变更):https://www.php.net/manual/en/function.strftime.php