问题:PHP的 MySQL 相关扩展未正确安装
此问题疑似 1Panel 的 bug
我在腾讯的大陆地区公网服务器和VMWare做了相同的尝试,均为此结果
复现:
系统:Debian 12 amd64
使用一键命令安装的1panel
1panel version: v1.10.2-lts
mode: stable
在运行环境中新增PHP运行环境,
名称我输入了 PHP82
PHP 版本我选择了 8.2.15
我尝试过的扩展源:ustc和tuna
扩展模板默认
扩展:mysqli, pdo_mysql
构建日志:build.log
#0 building with "default" instance using docker driver
#1 [1panel-php internal] load build definition from Dockerfile
#1 transferring dockerfile: 1.25kB done
#1 DONE 0.0s
#2 [1panel-php internal] load metadata for docker.io/library/php:8.2.15-fpm-alpine
#2 DONE 1.1s
#3 [1panel-php internal] load .dockerignore
#3 transferring context: 2B done
#3 DONE 0.0s
#4 [1panel-php 1/12] FROM docker.io/library/php:8.2.15-fpm-alpine@sha256:9f358983faaf1b5902ef9e6303ebc863b9be793a13e66094e366732c20fe3e7e
#4 DONE 0.0s
#5 [1panel-php internal] load build context
#5 transferring context: 5.10MB 0.0s done
#5 DONE 0.0s
#6 [1panel-php 9/12] RUN apk add gnu-libiconv libstdc++ --no-cache --repository http://mirrors.ustc.edu.cn/alpine/edge/community/ --allow-untrusted
#6 CACHED
#7 [1panel-php 3/12] ADD ./extensions/install-php-extensions /usr/local/bin/
#7 CACHED
#8 [1panel-php 6/12] WORKDIR /tmp/extensions
#8 CACHED
#9 [1panel-php 7/12] RUN chmod +x install.sh && sh install.sh && rm -rf /tmp/extensions
#9 CACHED
#10 [1panel-php 2/12] RUN if [ mirrors.ustc.edu.cn ] ; then sed -i "s/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g" /etc/apk/repositories ; fi
#10 CACHED
#11 [1panel-php 8/12] RUN apk --no-cache add tzdata && cp "/usr/share/zoneinfo/Asia/Shanghai" /etc/localtime && echo "Asia/Shanghai" > /etc/timezone
#11 CACHED
#12 [1panel-php 11/12] RUN apk --no-cache add shadow && usermod -u 1000 www-data && groupmod -g 1000 www-data
#12 CACHED
#13 [1panel-php 5/12] COPY ./extensions /tmp/extensions
#13 CACHED
#14 [1panel-php 10/12] RUN curl -o /usr/bin/composer https://mirrors.aliyun.com/composer/composer.phar && chmod +x /usr/bin/composer
#14 CACHED
#15 [1panel-php 4/12] RUN chmod uga+x /usr/local/bin/install-php-extensions
#15 CACHED
#16 [1panel-php 12/12] WORKDIR /www
#16 CACHED
#17 [1panel-php] exporting to image
#17 exporting layers done
#17 writing image sha256:5d7d6b237d25cbbab89ce67f190e799e001a3b83efc8b703a6d0ae8ee0dc741d done
#17 naming to docker.io/library/1panel-php:8.2.15 done
#17 DONE 0.0s
然后我选择了上面构建的运行环境新建了一个网站,参数除域名输入框外均为默认
我创建了一个test.php
内容如下:
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// 数据库连接配置
$dbConfig = [
'host' => 'localhost',
'username' => 'main_site',
'password' => 'fmtbeGnsdk66rAci',
'database' => 'main_site'
];
// 文件操作配置
$fileConfig = [
'filename' => 'test_iejfhruguryhirg.txt',
'fileContent' => '测试的文件内容😊'
];
// 检测 MySQLi 扩展是否可用
if (extension_loaded('mysqli')) {
// MySQLi 连接数据库
$mysqli = new mysqli($dbConfig['host'], $dbConfig['username'], $dbConfig['password'], $dbConfig['database']);
// 检查 MySQLi 连接是否成功
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: " . $mysqli->connect_error;
} else {
echo "MySQLi connected successfully<br>";
}
// 关闭 MySQLi 连接
$mysqli->close();
} else {
echo "MySQLi extension is not available<br>";
}
echo "<br>";
// 检测 PDO 扩展是否可用
if (extension_loaded('pdo')) {
// PDO 连接数据库
try {
$pdo = new PDO("mysql:host={$dbConfig['host']};dbname={$dbConfig['database']}", $dbConfig['username'], $dbConfig['password']);
// 设置 PDO 错误模式为异常
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "PDO connected successfully<br>";
} catch(PDOException $e) {
echo "PDO connection failed: " . $e->getMessage();
}
} else {
echo "PDO extension is not available<br>";
}
echo "<br>";
// 文件读写测试
$filename = $fileConfig['filename'];
$fileContent = $fileConfig['fileContent'];
// 写入文件
if (file_put_contents($filename, $fileContent) !== false) {
echo "成功:写入文件成功<br>";
} else {
echo "失败:写入文件失败<br>";
}
// 读取文件
$fileData = file_get_contents($filename);
if ($fileData !== false) {
echo "成功:读取文件内容【{$fileData}】<br>";
} else {
echo "失败:读取文件失败<br>";
}
// 删除文件
if (unlink($filename)) {
echo "成功:文件已删除<br>";
} else {
echo "失败:文件删除失败<br>";
}
上述脚本我自己写的用于测试基本功能。文件测试没有问题,可以忽略。数据库连接测试存在问题
我的MySQL是从应用商店安装的8.2.0版本,已勾选端口外部访问
我也正确的在面板上创建了代码配置中的MySQL数据库和用户名,我使用Navcat工具测试了MySQL连接,连接成功,且CURD操作没有问题
我访问test.php报错
Fatal error: Uncaught mysqli_sql_exception: No such file or directory in /www/sites/my_domain/index/test.php:24 Stack trace: #0 /www/sites/my_domain/index/test.php(24): mysqli->__construct('localhost', 'main_site', Object(SensitiveParameterValue), 'main_site') #1 {main} thrown in /www/sites/my_domain/index/test.php on line 24
这说明1Panel自动配置的扩展存在问题
也就是PHP 连接不上MySQL,缺失连接驱动?
我的站点php配置如下:我没有做任何修改(由于论坛篇幅有限,我展示的删除了注释的部分)
[PHP]engine = On
short_open_tag = Off
precision = 14output_buffering = 4096
zlib.output_compression = Offimplicit_flush = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions =
disable_classes =
zend.enable_gc = On
expose_php = Offmax_execution_time = 30
max_input_time = 60
memory_limit = 256M
;
;
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Offignore_repeated_source = Offreport_memleaks = Ontrack_errors = Off
html_errors = Onerror_log = /var/log/php/php.error.log
variables_order = "GPCS"
request_order = "GP"register_argc_argv = Off
auto_globals_jit = Onpost_max_size = 100M
auto_prepend_file =
auto_append_file =
;default_mimetype = "text/html"
default_charset = "UTF-8";;
doc_root =
user_dir =
enable_dl = Off
file_uploads = Onupload_max_filesize = 50Mmax_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
;
;
;
;
;
;
;
;;;
[CLI Server]
cli_server.color = On
[Date]date.timezone = Asia/Shanghai
[filter]
[iconv][intl]
[sqlite3][Pcre]
[Pdo]
[Pdo_mysql]pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[Phar][mail function]SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1ibase.max_persistent = -1ibase.max_links = -1ibase.timestampformat = "%Y-%m-%d %H:%M:%S"ibase.dateformat = "%Y-%m-%d"ibase.timeformat = "%H:%M:%S"
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off[OCI8]
[PostgreSQL]pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[bcmath]bcmath.scale = 0
[browscap]
[Session]session.save_handler = files
;
;
;;
;;
;session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = phpsession.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180session.use_trans_sid = 0session.sid_length = 26session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 5[Assertion]
zend.assertions = -1[COM]
[mbstring][gd]
[exif][Tidy]tidy.clean_output = Off
[soap]soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[dba][opcache]
[curl]
[openssl]
[XDebug]
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_host = host.docker.internal
xdebug.remote_log = /var/log/php/xdebug.log
SERVER_ENV=develop
yaf.use_spl_autoload=1
[xhprof]
猜测可能的问题原因
mysqli.default_socket =
和
pdo_mysql.default_socket=
均为空
而翻阅mysqli的源代码,可以从源代码中找出了这么一段
if (host_len == sizeof("localhost") - 1 && !strncasecmp(host, "localhost", host_len)) {
DBG_INF_FMT("socket=%s", socket_or_pipe? socket_or_pipe:"n/a");
if (!socket_or_pipe) {
socket_or_pipe = "/tmp/mysql.sock";
}
transport_len = mnd_sprintf(&transport, 0, "unix://%s", socket_or_pipe);
unix_socket = TRUE;
}
如果使用localhost,就使用unixdomain,文件路径就是参数中的socket,但如果这个参数是空,那么写死了/tmp/mysql.sock。这么说来上面报错不存在的地址就是在源代码中给写死了,所以需要1panel设置为正确的值。
而1panel并未设置为正确的值导致连接失败
由于我的能力和精力有限,还要忙工作,我旧先把问题丢到贵站论坛了,有望大佬解决