请注意,在所有 >=Windows 7 服务器上,主机名“localhost”将创建一个非常昂贵的查找(约 1 秒)。
这是因为从 Windows 7 开始,hosts 文件不再预先配置
127.0.0.1 localhost
了。
因此,如果您注意到连接创建时间过长,请尝试使用“127.0.0.1”代替。
(PHP 5, PHP 7, PHP 8)
mysqli::__construct -- mysqli::connect -- mysqli_connect — 打开与 MySQL 服务器的新连接
面向对象风格
$hostname
= null
,$username
= null
,$password
= null
,$database
= null
,$port
= null
,$socket
= null
$hostname
= null
,$username
= null
,$password
= null
,$database
= null
,$port
= null
,$socket
= null
过程化风格
$hostname
= null
,$username
= null
,$password
= null
,$database
= null
,$port
= null
,$socket
= null
打开与 MySQL 服务器的连接。
hostname
可以是主机名或 IP 地址。当传递 null
时,该值将从 mysqli.default_host 中获取。如果可能,将使用管道而不是 TCP/IP 协议。如果一起提供了主机名和端口号,例如 localhost:3308
,则使用 TCP/IP 协议。
使用 p:
在主机名前缀打开一个持久连接。 mysqli_change_user() 会自动在从连接池中打开的连接上调用。
username
MySQL 用户名或 null
以根据 mysqli.default_user ini 选项来假设用户名。
password
MySQL 密码或 null
以根据 mysqli.default_pw ini 选项来假设密码。
database
执行查询时要使用的默认数据库或 null
。
port
要尝试连接到 MySQL 服务器的端口号或 null
以根据 mysqli.default_port ini 选项来假设端口。
socket
要使用的套接字或命名管道,或 null
以根据 mysqli.default_socket ini 选项来假设套接字。
注意:
指定
socket
参数不会明确确定在连接到 MySQL 服务器时要使用的连接类型。连接到 MySQL 数据库的方式由hostname
参数决定。
mysqli_connect() 返回一个表示与 MySQL 服务器连接的对象,如果失败则返回 false
。
mysqli::connect() 在成功时返回 true
,失败时返回 false
。在 PHP 8.1.0 之前,在成功时返回 null
。
如果启用了 mysqli 错误报告 (MYSQLI_REPORT_ERROR
) 并且请求的操作失败,则会生成警告。如果此外,模式设置为 MYSQLI_REPORT_STRICT
,则会抛出 mysqli_sql_exception 而不是警告。
示例 #1 mysqli::__construct() 示例
面向对象风格
<?php
/* 在尝试建立连接之前,你应该为 mysqli 启用错误报告 */
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'my_db');
/* 在建立连接后设置所需的字符集 */
$mysqli->set_charset('utf8mb4');
printf("成功... %s\n", $mysqli->host_info);
过程化风格
<?php
/* 在尝试建立连接之前,你应该为 mysqli 启用错误报告 */
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = mysqli_connect('localhost', 'my_user', 'my_password', 'my_db');
/* 在建立连接后设置所需的字符集 */
mysqli_set_charset($mysqli, 'utf8mb4');
printf("成功... %s\n", mysqli_get_host_info($mysqli));
上面的示例将输出类似于以下内容:
Success... localhost via TCP/IP
示例 #2 扩展 mysqli 类
<?php
class FooMysqli extends mysqli {
public function __construct($host, $user, $pass, $db, $port, $socket, $charset) {
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
parent::__construct($host, $user, $pass, $db, $port, $socket);
$this->set_charset($charset);
}
}
$db = new FooMysqli('localhost', 'my_user', 'my_password', 'my_db', 3306, null, 'utf8mb4');
示例 #3 手动错误处理
如果禁用错误报告,开发人员有责任检查和处理故障
面向对象风格
<?php
error_reporting(0);
mysqli_report(MYSQLI_REPORT_OFF);
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'my_db');
if ($mysqli->connect_errno) {
throw new RuntimeException('mysqli 连接错误: ' . $mysqli->connect_error);
}
/* 在建立连接后设置所需的字符集 */
$mysqli->set_charset('utf8mb4');
if ($mysqli->errno) {
throw new RuntimeException('mysqli 错误: ' . $mysqli->error);
}
过程化风格
<?php
error_reporting(0);
mysqli_report(MYSQLI_REPORT_OFF);
$mysqli = mysqli_connect('localhost', 'my_user', 'my_password', 'my_db');
if (mysqli_connect_errno()) {
throw new RuntimeException('mysqli 连接错误: ' . mysqli_connect_error());
}
/* 在建立连接后设置所需的字符集 */
mysqli_set_charset($mysqli, 'utf8mb4');
if (mysqli_errno($mysqli)) {
throw new RuntimeException('mysqli 错误: ' . mysqli_error($mysqli));
}
注意:
MySQLnd 始终假设服务器默认字符集。此字符集在连接握手/身份验证期间发送,mysqlnd 将使用它。
Libmysqlclient 使用在 my.cnf 中设置的默认字符集,或者通过在调用 mysqli_real_connect() 之前,但在调用 mysqli_init() 之后,显式调用 mysqli_options() 来设置。
注意:
面向对象风格:如果连接失败,仍然会返回一个对象。要检查连接是否失败,请使用 mysqli_connect_error() 函数或 mysqli->connect_error 属性,如前面的示例所示。
注意:
如果需要设置选项,例如连接超时,则必须使用 mysqli_real_connect()。
注意:
使用不带参数的构造函数与调用 mysqli_init() 相同。
注意:
错误“无法创建 TCP/IP 套接字 (10106)” 通常意味着 variables_order 配置指令不包含字符
E
。在 Windows 上,如果环境未被复制,SYSTEMROOT
环境变量将不可用,PHP 将无法加载 Winsock。
请注意,在所有 >=Windows 7 服务器上,主机名“localhost”将创建一个非常昂贵的查找(约 1 秒)。
这是因为从 Windows 7 开始,hosts 文件不再预先配置
127.0.0.1 localhost
了。
因此,如果您注意到连接创建时间过长,请尝试使用“127.0.0.1”代替。
请在建立连接后使用 set_charset("utf8"),以避免出现奇怪的字符串问题。我不知道为什么文档没有警告你这些问题。
我们花了很长时间才弄清楚到底发生了什么,因为我们使用的是 mb_detect_encoding,它表示所有内容都是 UTF-8,但当然显示结果是错误的。如果我们使用 iconv 从 ISO-8859-1 转换为 UTF-8,字符串看起来就正常了,即使数据库中的所有内容都具有正确的排序规则。所以最终,连接才是过滤器,虽然此函数的注释提到了默认字符集,但这几乎读起来像是一个旁注,而不是处理 UTF 和 PHP/MySQL 时的一个核心问题。
只是想为任何想要使用 MySQLi 持久连接功能的人添加一个注释;重要的是要注意,PHP 为每个数据库用户打开并保留一个连接,并为每个进程保留一个连接。
这意味着如果您托管多个应用程序,每个应用程序都有自己的数据库用户(这是良好的做法),那么您最终将使 PHP 可能持有的连接数量成倍增加。
例如,如果您将 PHP 配置为最多有八个工作进程,并且您经常使用四个不同的数据库用户,那么您的 MySQL 服务器需要接受至少 32 个连接,否则它将耗尽。
但是,如果您想最小化连接数量,您可以做的是打开使用“访客”用户(除了登录之外没有任何权限)的连接,然后使用 ->change_user() 切换到更有权限的用户,然后在完成后切换回访客用户。由于所有连接都属于访客用户,因此 PHP 应该只为每个工作进程维护一个连接。
有一个单独的端口参数,与 mysql_connect 不同。但是,在主机参数中使用 host:port 实际上是有效的。
有一个警告。如果主机是'localhost',那么端口将被忽略,无论您使用端口参数还是我上面提到的隐式语法。这是因为'localhost' 将使其使用 unix 套接字而不是 TCP/IP。
如果您想通过备用端口(而不是 3306)连接,例如当您使用 ssh 隧道连接到另一个主机时,使用“localhost”作为主机名将不起作用。
使用 127.0.0.1 将有效。显然,如果您将主机指定为“localhost”,构造函数将忽略作为构造函数参数指定的端口。
public mysqli::__construct(
string $hostname = ini_get("mysqli.default_host"),
string $username = ini_get("mysqli.default_user"),
string $password = ini_get("mysqli.default_pw"),
string $database = "",
int $port = ini_get("mysqli.default_port"),
string $socket = ini_get("mysqli.default_socket")
)
mysqli 构造函数会查看主 PHP.ini 值。
如果您使用的是某种本地 ini 覆盖,请将 ini_get 添加到您的 php 脚本中
$mysqli = new mysqli(ini_get("mysqli.default_host"),ini_get("mysqli.default_user"),ini_get("mysqli.default_pw"))
应该注意的是,在 PHP 7(至少 v7.0.2)上,在连接到'localhost' 时将空字符串 '' 传递给端口参数将完全阻止连接成功。
为了解决这个问题,请使用'null'。
如果你遇到这样的错误
无法连接到 'localhost' 上的 MySQL 服务器 (10061)
并且你使用了命名管道/套接字连接(或者不确定你是如何安装 MySQL 服务器的),请尝试以下连接命令
<?php
mysqli_connect('.', $user_name, $password, $database_name, null, 'mysql');
?>
当使用命名管道时,'.' 作为主机名是绝对必要的。'localhost' 将不起作用。'mysql' 是管道/套接字的标准名称。
连接到 mysql 的更安全、更独立于语言的方法是使用 READ_DEFAULT_FILE 选项。这将工作负载移交给 mysql 库,允许配置文件本身超出语言范围。
配置文件本身类似于这样
[client]
user=user_u
password=user_password
host=dbhost
port=3306
database=the_database
default-character-set=utf8
以下代码片段(在 OO mysql_i 格式中)
$sqlconf='/var/private/my.cnf';
$sql = new mysqli;
$sql->init();
$sql->options(MYSQLI_READ_DEFAULT_FILE,$sqlconf);
$sql->real_connect();
mysqli 可以以令人惊讶的方式成功,具体取决于授予用户的权限。例如,
GRANT USAGE ON *.* TO 'myuser'@'localhost' IDENTIFIED BY PASSWORD 'mypassword';
GRANT ALL PRIVILEGES ON `database_a`.* TO 'myuser'@'localhost';
CREATE DATABASE database_b;
<?php
$db = new mysqli('localhost', 'myuser', 'mypassword', 'database_b');
if ($db->connect_error) {
die('Connect Error (' . $db->connect_errno . ') '
. $mysqli->connect_error);
}
printf("SQLSTATE: %s\n", $this->db->sqlstate);
printf("Warning Count: %s\n", $db->warning_count);
$db->close();
?>
将输出
SQLSTATE: 00000
Warning Count: 0
所以,一切都很好 - 你已经连接到数据库并执行 mysqli 方法。 除了,生活并不美好,因为你实际上并没有使用 database_b,因为 myuser 对它没有任何权限。 在你尝试执行后续操作之前,你不会发现这一点,那时你会得到一个错误,“MYSQL 错误:没有选择数据库”,你会发现自己在挠头,想“你是什么意思,当然我选择了数据库;我在调用构造函数时选择了”。
因此,你可能希望在连接到 mysql 后执行额外的检查,以确认你实际上不仅连接到 mysql 服务器,而且连接到实际的数据库
<?php
$db = new mysqli('localhost', 'myuser', 'mypassword', 'database_b');
if ($db->connect_error) {
die('Connect Error (' . $db->connect_errno . ') '
. $mysqli->connect_error);
} elseif ($result = $db->query("SELECT DATABASE()")) {
$row = $result->fetch_row();
if ($row[0] != 'database_b') {
//oops! 我们连接到 mysql,但没有连接到 database_b
}
}
?>
我的一个朋友遇到了 CMS Piwigo 的突然错误。我发现
- 他有一个主机规则来使用 PHP 5.6。
- 主机使用 5.6.6,使用 phpinfo(); 验证。
- CMS 将数据库名称参数声明为 null。
该画廊 CMS 无法连接到 MySQL,只留下了关于它的警告消息。
我们尝试恢复到 PHP 5.5,CMS 再次运行。
然后我们切换回 5.6.6 并更改了这些行
$dbname = null;
$mysqli = new mysqli($host, $user, $password, $dbname, $port, $socket);
到
$dbname = ''; // 使用空字符串,而不是 null
$mysqli = new mysqli($host, $user, $password, $dbname, $port, $socket);
它运行了!
因此,如果你犯了同样的错误,在手册要求使用空字符串的地方使用了 null,你应该考虑修正你的代码。
注意,mysqli_connect() 不返回资源!它返回 mysqli 类的实例 (https://php.net/manual/class.mysqli.php) 旧的 mysql_connect() 函数确实返回了一个资源。
如果你想连接到 Windows 上的本地命名管道,并且你得到错误“php_network_getaddresses: getaddrinfo failed: No such host is known.”,即使你使用“.”作为主机,请检查你是否使用的是 mysqlnd 驱动程序:如果这是真的,那么你可能需要更新到 php 5.4 版本
Windows 的命名管道支持在 PHP 5.4.0 版本中添加。
@ https://php.net/manual/en/mysqlnd.overview.php
希望这能节省你一些时间。