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)。

FramadateFramadate自托管PHPMariaDB2026/11/01

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)

二、前置条件

安装前确认四项条件,缺一都会在后续步骤报错:

  1. PHP 版本:源码 app/inc/constants.php 钉住最低版本 const PHP_NEEDED_VERSION = '7.3';,Ubuntu 22.04 自带 PHP 8.1 满足;但 PHP 8.1 存在两处兼容性缺陷(strftime、SMTP 默认开启),本文与第九章、后续排错文档已给出修复动作。
  2. 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
  1. Apache mod_rewrite:启用「干净链接」(/dvdEakcXnbWf7eXf 形式的投票短 URL)依赖 rewrite 模块与 AllowOverride All,实测已加载:
apache2ctl -M 2>/dev/null | grep -E "rewrite|php"
 php_module (shared)
 rewrite_module (shared)
  1. 可写目录: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_phpPHP 解释器嵌入 Apache 进程内单机小流量、配置最简(本文方案 A)
Nginx/Apache + PHP-FPMWeb 服务器经 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.182021-12-21依赖更新;弃管的 SimpleMDE 换成 EasyMDE 分支;强制校验投票截止日期
1.1.172021-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(PHPMailer SMTP 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&comma; librement&period; - 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&comma; librement&period; - 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 等公共包若被其他应用共享则保留)。

十一、参考链接

Ubuntu 22.04 安装 Framadate 1.1.19 指南 - Quzuo