15

I understand that PHP's mysql_* functions are deprecated and I should not be using them.

However, we have several legacy MySQL 4.0 databases, which neither the mysqli_* nor PDO functions support connecting to. What is the best way to continue using the latest PHP versions and still be able to connect to these databases?

(Based on the description at the top of the PDO intro page, I initially thought PDO might be an option, but the Changelog further down the page suggests that support for pre-4.1 has been dropped in PHP 5.4)

I understand that MySQL 4.0 is 10 years old and the real problem here is that we're still using it. Upgrading MySQL is a separate issue that's outside the scope of both my influence and this question. What I do have control over is the PHP version that we use - and I'd hate to have to stop upgrading PHP just because we need to connect to some old databases.

Even PDO will no longer connect to these old MySQL servers.

I should also clarify that we have several legacy applications accessing these databases, and we want to change these applications as little as possible. They are not in active development, and testing a change that involved rewriting large sections of code would quickly balloon into a rather large QA project.

For this reason, invasive solutions such as rewriting the code or upgrading the MySQL version, are highly unlikely to be worthwhile. If they are the only solutions available, we'll probably end up doing nothing - using mysql_* as long as possible, and then freezing the PHP version (at least for these apps) as soon as the latest PHP can no longer connect.

On the other hand, technically complex solutions (such as compiling something from scratch) are definitely possible, and are actually preferred to making extensive code changes.

Dharman
  • 30,962
  • 25
  • 85
  • 135
jcsanyi
  • 8,133
  • 2
  • 29
  • 52
  • What is the problem with using mysql_* ? I can guess what u'll tell me, but then, this would be the same answer to you using php4... – Itay Moav -Malimovka Jun 13 '13 at 23:05
  • @Itay It's not a problem at the moment, but I'm looking ahead to when the mysql_ functions will be actually removed. – jcsanyi Jun 13 '13 at 23:07
  • 3
    Since you're planning to continually upgrade PHP, is it feasible to upgrade to a newer version of MySQL also? – j883376 Jun 13 '13 at 23:26
  • 1
    According to the page you linked to (specifically, the changelog section), the PDO and mysqli libraries only differ in their support for MySQL 4.1, with mysqli actually having more support, not less. Neither supports 4.0 as of PHP 5.4 – IMSoP Jun 17 '13 at 23:51
  • @IMSoP Thanks! I originally just read the intro, which suggests it would work - but you're right, the Changelog seems to say otherwise. I've updated my question to reflect this. – jcsanyi Jun 18 '13 at 00:47
  • 3
    Have you tried searching http://careers.stackoverflow.com/ for an answer? – Danack Jun 18 '13 at 01:16
  • Do you *really* upgrade PHP? Just curious, what PHP version you are using at the moment? Don't you have a problem with `pass by reference`, `register globals`, `magic quotes`, OOP syntax and many more major incompatibilities? – Your Common Sense Jun 18 '13 at 03:18
  • @YourCommonSense yes, we do upgrade PHP. We're currently running the latest 5.3 on our production systems, and we're evaluating 5.4 in one of our test environments. `register globals` and `magic quotes` have been config'd off in our systems for a LONG time, so are not a problem. `pass by reference` caused a slight problem, but was just a straightforward syntax fix without any actual functional changes. – jcsanyi Jun 18 '13 at 06:04

7 Answers7

11

You can use either mysql_* functions or PDO to connect from PHP 5.4 to MySQL 4.0. I just built MySQL 4.0.30 and launched it with MySQL Sandbox. Then I tested the code example below successfully.

However, you can't use the TCP/IP protocol.

You can only access MySQL locally, using the unix socket. Use a hostname of 'localhost' and make sure your php.ini has configured the mysql.default_socket correctly for your MySQL instance.

To use the local access method, your PHP application and your database server must be installed on the same host.

<?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);
}

Here's the output of the above script on my system:

PHP VERSION = 5.4.15

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

TEST PDO_MYSQL:
Array
(
    [MySQL VERSION] => 4.0.30
)
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
2

Why not upgrade mysql? If you want minimal change, then upgrading to 4.1 is enough to mysqli running. I think this is the first thing that you should try because you can have a test environment to see if the old apps worked with 4.1. You also have the list of changes in 4.1 that you might need to check, they're in http://dev.mysql.com/doc/refman/4.1/en/upgrading-from-previous-series.html

If testing 4.1 expose some issues, then you'll know that a more radical change will be needed and you need that information to build a strategy. I know that you want to keep updating PHP, just don't leave mysql and the OS left behind. I'd have a stable combination of mysql, os and php to run in production. When it's time to move on, build a complete new environment.

imel96
  • 1,385
  • 11
  • 18
2

The legacy mysql_* functions were removed in 5.5.0, which was released today (6/20/2013). I realize your hands are tied in regards to this old database, but keep in mind what you are now experiencing is know as technical debt, and it's an important concept to understand and to explain to the people in charge.

I'm sure you already know the dangers of old software (exploits, etc) but obviously this applies to your PHP as well. Currently 5.4.x is still supported, but generally speaking only the 2 most recent versions of PHP are supported, so that means 5.3.x is expiring soon, and only 5.5.x and 5.4.x are supported. Because of your need for legacy MySQL, you're already using the oldest supported PHP, and that's a dangerous game to play.

If you were hoping for some silver bullet, I can't put it any simpler than: there isn't one. You have to make a hard choice, support legacy and open yourself up to eventual exploits, or draw a line in the sand and just say no. I'd like to say, in all my years of IT, I've never heard anybody say (particularly on the business side of things) how happy they were for keeping with the old legacy stuff.

TravisO
  • 9,406
  • 4
  • 36
  • 44
1

From mysql_* to PDO isn't really that bad, PDO just seems a little frightening at first, and agreed, is somewhat more complicated, at least for retrieving data from queries (IMO).

It might be a bit at first, but it shouldn't be too bad, and it's more secure as well, in addition to being one of the two current standards.

For example,

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

and

mysql_query($sql)

become

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

and

$statement = $link->prepare($sql);
$statement->execute(values);
Serdnad
  • 602
  • 2
  • 9
  • 17
1

This could be quite a simple solution... As you are running legacy applications on a outdated MySQL Database revision.. Why don't you keep contiunity? I'm assuming that the applications are hosted on a server which is maintained by yourself and not a third party (web hosting)

What i'd suggest doing is having a different machine.. Possibly a Virtual Server running mysql4.0 and a version of PHP which suits the applications.. Then migrate all legacy over to the new server.. Then you will no have to worry about the removal/depreciation of mysql_* functions..

With your main server, keep upgrading as you wish to keep with your current development requirements?

Daryl Gill
  • 5,464
  • 9
  • 36
  • 69
  • Thanks @Daryl. This is essentially a version of the fallback plan that I mentioned in my question. It would work, but I'm really hoping that we can come up with some better options. – jcsanyi Jun 18 '13 at 00:52
0

This is an old question, but surprisingly relevant. The answer is actually pretty easy. If you have an old mysql that you need data pulled out from, via a "new" version of PHP, just setup a slave with a new version of MariaDB. It should be part of your migration process.

Replicate to a new version of MariaDB, and connect to that slave to read data (and you should set it up as a read-only replica).

-1

This answer was written while the OP believed PDO could connect to MySQL 4.

What you could maybe do is rewriting the mysql functions with the PDO driver, so you don't change your original code. If I take the examples given by Serdnad, you could do something like:

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);
}

Well, there are quite a few mysql_* functions but in the end you can find out which ones you really use (which might be only a few) with a simple regex search in your source.

I think you'd have to be smart with some functions such as mysql_escape_string, mysql_affected_rows, or mysql_insert_id but I am pretty sure it's doable.

If your extension is still active when you redefine the functions you will get a fatal error that you can avoid by using a namespace, which would be easy to add to your code. If you disable mysql ext I think you can achieve your goal without changing a line of your original code.

Nabab
  • 2,608
  • 1
  • 19
  • 32
  • 1
    +1 The name collision problem can also be solved by wrapping your definitions in a block like `if (!function_exists('mysql_connect')){ ... }` – grossvogel Jun 17 '13 at 23:47
  • Thanks, @Nabab. I originally liked the sound of this solution, but it now looks like even PDO will not work. See my updated question above. – jcsanyi Jun 18 '13 at 00:49
  • 2
    @YourCommonSense: The original question included the OP's belief that PDO would in fact support the mysql version in use even though mysqli_ would not and mysql_ would be removed. This answer lost its value when that belief was disproved, but that hardly makes it imaginary. – grossvogel Jun 18 '13 at 17:17
  • How could this work? If PDO won't support connections to MySQL 4.0, then naively wrapping PDO with functions named 'mysql_...' won't do any magic... – ElmoVanKielmo Jun 19 '13 at 08:30
  • @ElmoVanKielmo: when I posted this, the "Updated (2)" part of the question didn't exist. If you had read the comment above yours you would have known. – Nabab Jun 19 '13 at 12:05
  • @Nabab, this doesn't change the facts: 1. Your `mysql_connect` wrapper is buggy (`mydb` is hardcoded) - if one really had db named `mydb`, then accidental lack of subsequent call to `mysql_select_db` and issuing queries could change data stored in wrong db. 2. We should not give a confusing name to any identifier in our code - one could be convinced, that the code is using mysql extension, while suddenly PDO error comes out. 3. Refactoring is better than patching, so "achieve your goal without changing a line of your original code" is not an argument for me. – ElmoVanKielmo Jun 19 '13 at 13:32
  • @ElmoVanKielmo: 1. Hardcoded is not buggy. PDO needs a database name while mysql_connect doesn't, so mydb was just an example of default db (could have been information_schema). 2. The question was how to change the driver without changing the code. An alternative name could have been adopted, that was up to the OP. 3. OP apparently didn't want to refactor. "Better" is your opinion, I was just answering the question, or trying to. – Nabab Jun 19 '13 at 13:44
  • @Nabab, okay, I revoked downvote, but I have some suggestions: 1. Consider adding optional `$dbname` parameter to `connect` function with default value of your choice (something that is not likely to be a real database name) - it will be more verbose and will allow to omit `select_db` call in new code. 2 and 3. "we want to change these applications as little as possible" - I would insist to name the wrappers like `pdo_mysql_connect`, `pdo_mysql_select_db` etc. Again more verbose and refactoring existing code is a piece of cake - any modern IDE automates this process. – ElmoVanKielmo Jun 19 '13 at 14:03
  • @ElmoVanKielmo: I would but as someone said it's now an imaginary answer for an imaginary question, so I guess we're having an imaginary debate ;) – Nabab Jun 19 '13 at 14:06