Search by

alvesbeto / mysql2pdo

alvesbeto

Legacy mysql_* functions for PHP 8+, implemented on ext-pdo (MySQL driver compatibility shim)

Package info

github.com/alvesbeto/mysql2pdo

pkg:composer/alvesbeto/mysql2pdo

Statistics

Installs: 17

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.5 2026-11-03 23:40 UTC

This package is auto-updated.

Last update: 2026-11-03 23:49:54 UTC


README

Legacy mysql_* functions for PHP 8+, implemented on ext-pdo (MySQL driver).

PHP removed the old mysql extension in 7.0. Many applications still call mysql_connect, mysql_query, mysql_fetch_assoc, and the rest. This Composer library registers those global functions again and delegates to PDO under the hood, so you can run on PHP 8 without rewriting every query at once.

The shim implements all 48 functions from the official PHP mysql reference, plus mysql_multi_query_script for batched SQL.

This is a compatibility shim, not a reimplementation of the C extension.

Requirements

Requirement Notes
PHP ^8.0 (see composer.json)
Extension pdo + MySQL driver (pdo_mysql on most Linux builds)
Database server Any MySQL or MariaDB version your PDO MySQL driver supports

You must install and enable ext-pdo and the MySQL PDO driver in php.ini. This package does not ship a database server or Docker setup.

Installation

From Packagist (recommended)

Stable release 1.0.0+ on Packagist:

composer require alvesbeto/mysql2pdo:^1.0

For bleeding-edge main:

composer require alvesbeto/mysql2pdo:dev-main

From a local clone (path repository)

Use this when the package lives next to your app in a monorepo or you are hacking on mysql2pdo itself.

Add to the consumer project's composer.json:

{
    "repositories": [
        {
            "type": "path",
            "url": "../mysql2pdo",
            "options": {
                "symlink": true
            }
        }
    ],
    "require": {
        "alvesbeto/mysql2pdo": "@dev"
    }
}

Then run:

composer update alvesbeto/mysql2pdo

Adjust url to the relative or absolute path of this repository.

Without Composer (discouraged)

Load the two source files in this order:

require_once '/path/to/mysql2pdo/src/mysql2pdo.class.php';
require_once '/path/to/mysql2pdo/src/mysql2pdo.func.php';

Quick start

  1. Load autoload before any mysql_* call (typically in your bootstrap):
require_once __DIR__ . '/vendor/autoload.php';
  1. Use the API like PHP 5 did. Connection and result handles are ShimLink and ShimResult objects, not resource types:
$link = mysql_connect('127.0.0.1', 'user', 'password');
if (!$link) {
    die('Connection failed: ' . mysql_error());
}

mysql_select_db('my_database', $link);

$result = mysql_query('SELECT id, name FROM customers LIMIT 10', $link);
while ($row = mysql_fetch_assoc($result)) {
    echo $row['name'] . "\n";
}
mysql_free_result($result);

Successful mysql_connect / mysql_pconnect do not change charset. Use mysql_set_charset($charset, $link) or mysql_query('SET NAMES …', $link) like you would on PHP 5.

Default connection (mysql2pdo::$currObj)

After mysql_connect, many functions accept an optional $link. If you omit it, they use the last connection stored in mysql2pdo::$currObj (same idea as classic mysql_*):

$link = mysql_connect($host, $user, $pass);
mysql_query("SET time_zone = '-03:00'"); // uses $link via $currObj

If your app keeps the link in a variable (for example $db_link), pass it explicitly: mysql_query($sql, $db_link).

Calling mysql_select_db($database, $link) with an explicit connection also updates $currObj, so the next mysql_query($sql) without a link uses that same connection.

mysql_connect vs mysql_pconnect: mysql_connect reuses a valid $currObj when $new_link is false; pass $new_link = true for a second connection. mysql_pconnect always opens a new p: connection and always sets $currObj (see docs/API.md).

SSL / socket: set $client_flags to MYSQL_CLIENT_SSL and provide MYSQL2PDO_SSL_* env vars, or set MYSQL2PDO_UNIX_SOCKET for plain localhost. See docs/API.md.

Legacy is_resource($link): use $link instanceof \Mysql2pdo\Driver\ShimLink or the helpers is_resource_custom() / get_resource_type_custom() (MySQL2PDO-style migration).

mysql_query warnings: the global function emits an extra PHP warning when there is no connection; mysql2pdo::mysql_query() logs only. mysql_unbuffered_query does not perform those connection checks—use it only when the link is known good.

Migrating from copied shim files

If you previously shipped copies of mysql2pdo.class.php and mysql2pdo.func.php inside the project (common in legacy codebases):

// Before
require_once __DIR__ . '/classes/config/mysql2pdo.class.php';
require_once __DIR__ . '/classes/config/mysql2pdo.func.php';

// After Composer install
require_once __DIR__ . '/vendor/autoload.php';

Remove the old copies once autoload is in place to avoid loading the shim twice.

Encapsulation: only this package talks to PDO (PdoExecutor). Application code should keep using mysql_*.

How Composer autoload works

Mechanism File What it loads
classmap src/mysql2pdo.class.php Global facade mysql2pdo (+ fallback autoload for Mysql2pdo\…)
psr-4 src/Mysql2pdo/ One class per shim under Mysql2pdo\Shim\
files src/mysql2pdo.func.php Global mysql_* functions and MYSQL_* constants

If the shim is included twice in one request, guards skip redefinition:

  • Class: class_exists('mysql2pdo', false)
  • Functions: function_exists('mysql_affected_rows') (first function in the block)

Extensions beyond classic mysql_*

Symbol Purpose
mysql_multi_query_script($link, $script) Run a multi-statement SQL script via PDO, draining result sets
mysql2pdo::resolveLink($link) Normalize a link to ShimLink (advanced / internal)
is_resource_custom($var) / get_resource_type_custom($var) Legacy is_resource / get_resource_type migration helpers

See docs/API.md for the full function list and return types.

Namespaced API (maintainers / new code)

Namespace Mysql2pdo. Each legacy function has a dedicated class with a single static entrypoint:

use Mysql2pdo\Shim\MysqlQuery;
use Mysql2pdo\ResolveLink;

// Same PDO backend as mysql_query(); skips procedural trigger_error on bad link
MysqlQuery::invoke('SELECT 1', $link);

ResolveLink::invoke($link); // ShimLink|null

Global mysql_* and mysql2pdo:: remain the default for legacy apps.

Behavior to know before production

Connection handles and is_resource()

On PHP 8, $link and query results are shim objects. Prefer is_resource_custom($link) or $link instanceof \Mysql2pdo\Driver\ShimLink (and your app’s connection bootstrap). Before freeing, guard with a truthy $result; mysql_free_result($result) is a safe no-op when the result is invalid.

mysql_close()

mysql_close() clears the current link when applicable and releases the PDO handle (ShimLink::$pdo becomes null). It still returns true for invalid links (shutdown-handler friendly). After close, mysql_ping fails until you mysql_connect again—useful in long-lived workers and serverless-style runtimes.

Legacy API notes

Function Note
mysql_escape_string() No connection required; less accurate than mysql_real_escape_string() when a link is available
mysql_pconnect() Always opens a new persistent connection; does not reuse $currObj like mysql_connect; may echo connect errors from the class layer

This package does not emit PHP deprecations on mysql_* calls — it exists so legacy code keeps running on PHP 8+.

Query helpers

Topic Detail
mysql_query() Global: error_log + trigger_error if no connection; class method: log only, stricter host_info check
mysql_unbuffered_query() No empty-query or connection guards in the shim—unlike mysql_query()

Security

This shim does not add prepared statements. mysql_real_escape_string() uses PDO quoting when the link is valid; otherwise it falls back to addslashes() (legacy adapter behavior).

For new code, prefer PDO prepared statements or an ORM. Do not grow new SQL built from string concatenation.

Constants

If not already defined, the shim defines MYSQL_BOTH, MYSQL_NUM, MYSQL_ASSOC, and the MYSQL_CLIENT_* flags (legacy numeric values).

Developing this package

From the repository root:

composer validate --strict
composer dump-autoload -o
php -l src/mysql2pdo.class.php
php -l src/mysql2pdo.func.php
php -r "require 'vendor/autoload.php'; var_dump(function_exists('mysql_connect'), class_exists('mysql2pdo'));"

Expected output: bool(true) bool(true).

Integration tests

composer test

Uses Docker (MariaDB on port 3307), database mysql2pdo_test, and removes the container and volume when finished. Default output is testdox.

composer test:ci          # compact summary for CI
composer test -- --debug  # maximum PHPUnit detail

Maintainers and coding agents: start at AGENTS.md (index: .agents/index.md). Shim contract: .agents/specs/shim-behavior.md.

License

MIT — see LICENSE.

Credits

Implementation evolved from earlier mysql2i-style adapters used in legacy PHP codebases. Source comments credit contributors for parts of mysql_field_flags / mysql_field_type (php.net / Stack Overflow).