连接到旧的MySQL服务器

15
我知道PHP的mysql_*函数已经被弃用了,我不应该再使用它们。
然而,我们有几个遗留的MySQL 4.0数据库,既不支持mysqli_*函数,也不支持PDO函数连接。那么,在继续使用最新的PHP版本的同时,如何能够连接到这些数据库呢?
(根据PDO介绍页面顶部的描述,我最初认为PDO可能是一个选择,但页面下方的变更日志表明,PHP 5.4中已经放弃了对4.1之前版本的支持)
我明白MySQL 4.0已经有10年的历史了,而真正的问题在于我们仍在使用它。升级MySQL是一个独立的问题,超出了我影响力和这个问题的范围。我能控制的是我们使用的PHP版本,而且我不想因为需要连接到一些旧数据库而停止升级PHP。
即使是PDO也无法连接到这些旧的MySQL服务器。
我还要澄清一点,我们有几个遗留应用程序访问这些数据库,我们希望尽量少改动这些应用程序。它们没有在积极开发,而且测试一个涉及重写大量代码的更改将很快演变成一个相当大的QA项目。
因此,像重写代码或升级MySQL版本这样的侵入性解决方案很可能不值得。如果它们是唯一可用的解决方案,我们可能最终什么都不做 - 尽可能长时间使用mysql_*,然后在最新的PHP无法连接时冻结PHP版本(至少对于这些应用程序)。
另一方面,技术复杂的解决方案(例如从头开始编译某些东西)绝对是可行的,而且实际上比进行大量代码更改更可取。

使用mysql_*有什么问题吗?我可以猜到你会告诉我什么,但是,这对于你使用php4来说也是同样的答案... - Itay Moav -Malimovka
3
既然您计划不断升级PHP,那么升级到新版本的MySQL是否可行呢? - j883376
1
根据您提供的页面(具体来说是更改日志部分),PDO和mysqli库仅在它们对MySQL 4.1的支持方面有所不同,实际上mysqli具有更多的支持而不是更少。从PHP 5.4开始,两者都不再支持4.0。 - IMSoP
3
你尝试过在 http://careers.stackoverflow.com/ 上搜索答案吗? - Danack
你真的要升级 PHP 吗?只是好奇,你目前使用的 PHP 版本是什么?你没有遇到“按引用传递”、“注册全局变量”、“魔术引号”、“面向对象语法”等许多主要不兼容性问题吗? - Your Common Sense
显示剩余3条评论
7个回答

11

您可以使用mysql_*函数或PDO来从PHP 5.4连接到MySQL 4.0。我刚刚构建了MySQL 4.0.30,并使用MySQL Sandbox启动它。然后我成功地测试了下面的代码示例。

但是,您不能使用TCP/IP协议。

您只能使用unix套接字本地访问MySQL。使用主机名“localhost”,并确保您的php.ini已经正确配置了mysql.default_socket以针对您的MySQL实例。

为了使用本地访问方式,您的PHP应用程序和数据库服务器必须安装在同一主机上。

<?php

print "PHP VERSION = " . phpversion() . "\n";

print "\nTEST DEPRECATED EXT/MYSQL:\n";
mysql_connect('localhost', 'msandbox', 'msandbox');
$result = mysql_query("SELECT VERSION() AS 'MySQL VERSION'");
while ($row = mysql_fetch_assoc($result)) {
  print_r($row);
}

print "\nTEST PDO_MYSQL:\n";
try {
  $dbh = new PDO('mysql:host=localhost', 'msandbox', 'msandbox');
  $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch(PDOException $err) {
  die($err->getMessage());
}

$stmt = $dbh->prepare("SELECT VERSION() AS 'MySQL VERSION'");
$result = $stmt->execute();
foreach ($stmt->fetchAll() as $row) {
  print_r($row);
}

以下是在我的系统上运行上述脚本的输出:

PHP VERSION = 5.4.15

TEST DEPRECATED EXT/MYSQL:
Array
(
    [MySQL VERSION] => 4.0.30
)

TEST PDO_MYSQL:
Array
(
    [MySQL VERSION] => 4.0.30
)

2
为什么不升级mysql?如果你想要最小的改变,那么升级到4.1就足以运行mysqli。我认为这是你应该尝试的第一件事,因为你可以有一个测试环境来查看旧应用程序是否与4.1兼容。你还需要检查4.1中可能需要的更改列表,它们在http://dev.mysql.com/doc/refman/4.1/en/upgrading-from-previous-series.html中。
如果测试4.1暴露出一些问题,那么你就知道需要进行更彻底的改变,并且你需要这些信息来制定策略。我知道你想保持更新PHP,只是不要让mysql和操作系统落后。我会有一个稳定的mysql、操作系统和php组合来运行生产环境。当是时候转移,建立一个全新的环境。

2
“mysql_*”函数在5.5.0版本中被移除,该版本于2013年6月20日发布。我知道你对这个老数据库束手无策,但要记住,你现在经历的就是所谓的技术债务,这是一个重要的概念,需要向负责人解释清楚。
我相信你已经了解旧软件(如漏洞等)的危险性,但这同样适用于你的PHP版本。目前5.4.x仍然受到支持,但一般来说,只有最近的两个版本的PHP才会得到支持。这意味着5.3.x即将过期,只有5.5.x和5.4.x受到支持。由于你需要使用旧版MySQL,你已经在使用最老的支持PHP版本,这是一个危险的游戏。
如果你希望有什么灵丹妙药,那我只能说:并没有。你必须做出艰难的选择,支持传统遗留系统并最终暴露自己于攻击之下,或者划清界限,坚决拒绝。在我的多年IT经验中,我从未听过有人(特别是在商业领域)因为坚持使用旧的遗留系统而感到满意。

1

从mysql_*到PDO并不是太难,只是一开始PDO可能会有点令人害怕,而且确实更加复杂,至少对于从查询中检索数据而言(在我看来)。

一开始可能有点困难,但应该不会太糟糕,而且它也更安全,除此之外,它还是当前两个标准之一。

例如,

$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');

并且

mysql_query($sql)

成为

$link = new PDO("mysql:host=localhost;dbname=$dbname", $dbuser, $dbpass);

并且

$statement = $link->prepare($sql);
$statement->execute(values);

另外,请查看我上面更新的问题。似乎即使在PHP 5.4中,PDO也不是一个选项。 - jcsanyi

1
这可能是一个相当简单的解决方案...由于您正在运行过时的MySQL数据库版本上的传统应用程序..为什么不保持连续性?我假设这些应用程序托管在您自己维护而不是第三方(web hosting)的服务器上

我建议使用另一台机器.. 可能是运行mysql4.0和适合应用程序的PHP版本的虚拟服务器..然后将所有遗留问题迁移到新服务器上..然后您将不必担心删除/取消 mysql_* 函数..

对于您的主服务器,随意升级以满足当前的开发要求即可。


谢谢@Daryl。这本质上是我在问题中提到的备用计划的一个版本。它可以工作,但我真的希望我们能想出更好的选择。 - jcsanyi

0

这是一个老问题,但仍然非常相关。答案其实很简单。如果你需要从旧版mysql中提取数据,并通过“新”版本的PHP进行操作,只需使用新版本的MariaDB设置从库即可。这应该是您迁移过程的一部分。

复制到新版本的MariaDB,并连接到该从库以读取数据(并且您应该将其设置为只读副本)


-1

这个答案是在OP认为PDO可以连接到MySQL 4时编写的。

你可以尝试使用PDO驱动程序重写mysql函数,这样就不需要改变原始代码。如果我采用Serdnad给出的示例,你可以这样做:

function mysql_connect($dbhost, $dbusr, $dbpass){
  return new PDO("mysql:host=$dbhost;dbname=mydb", $dbuser, $dbpass);
}

function mysql_select_db($db, $link=false){
  // If you were not using the link argument you might use some global instead
  $link->query("USE $db");
  return 1;
}

function mysql_query($sql, $link=false){
  // If you were not using the link argument you might use some global instead
  $statement = $link->prepare($sql);
  return $statement->execute(values);
}

嗯,有相当多的mysql_*函数,但最终你可以通过在源代码中进行简单的正则表达式搜索找出你真正使用的函数(可能只有几个)。

我认为你需要聪明地使用一些函数,例如mysql_escape_string、mysql_affected_rows或mysql_insert_id,但我相信这是可行的。

如果您重新定义函数时扩展仍处于活动状态,您将收到致命错误,您可以通过使用命名空间来避免这种情况,这很容易添加到您的代码中。如果您禁用mysql扩展,我认为您可以在不更改原始代码的情况下实现您的目标。


1
名称冲突问题也可以通过像 if(!function_exists('mysql_connect')){ ... } 这样将您的定义封装在块中来解决。 - grossvogel
谢谢,@Nabab。我最初很喜欢这个解决方案的声音,但现在看起来即使是PDO也行不通。请参见我上面更新的问题。 - jcsanyi
2
@YourCommonSense:原始问题包括OP的信念,即PDO实际上将支持正在使用的mysql版本,即使mysqli_不支持并且mysql_将被删除。当这种信念被证明是错误的时,这个答案失去了它的价值,但这并不意味着它是虚构的。 - grossvogel
@ElmoVanKielmo:1.硬编码不会有bug。PDO需要数据库名称,而mysql_connect则不需要,因此mydb只是默认数据库的示例(也可以是information_schema)。2.问题是如何在不更改代码的情况下更改驱动程序。可以采用替代名称,这取决于OP。3.OP显然不想重构。“更好”是你的意见,我只是回答问题或尝试回答问题。 - Nabab
@ElmoVanKielmo:我本来想回答的,但正如有人所说,这已经成为了一个虚构问题的虚构答案,所以我猜我们正在进行一场虚构的辩论 ;) - Nabab
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接