Versions covered: 5.0.2 → 6.1.1-RC.2
Purpose: one-page upgrade & compatibility reference with short migration examples you can share with your team.
Between 5.0.2 and 6.1.1-RC.2 the extension added Firebird 4/5 type support, new transaction/INI options, client-version helpers, and changed some runtime behaviors that may break existing code:
- INT128 values are represented as strings (5.0.2).
- New IBASE_LOCK_TIMEOUT + INI options to control lock timeouts (6.1.1-RC.0).
- Extension now supports long metadata (names) and more Firebird types (6.1.1-RC.0).
- ibase_close() behavior changed: now closes the connection immediately instead of decrementing a refcount (6.1.1-RC.2).
- Fetching TIME fields with IBASE_UNIXTIME now returns a time string instead of negative numeric values (6.1.1-RC.2).
- New helpers: ibase_get_client_version(), ibase_get_client_major_version(), ibase_get_client_minor_version().
Change: ibase_close($link) now closes the DB connection immediately (no internal refcount decrement behavior). Code that relied on implicit sharing / refcounting may now see connections closed earlier.
Recommended approaches:
- Do not call ibase_close() in code paths where other parts of the application still rely on the same connection — only close when you truly want the connection gone.
- Use persistent connections where appropriate (if your workload fits persistent connections).
- Explicit connection-lifetime management: open, use, close within the same scope or use wrappers.
Examples
Old (implicitly relied on refcount):
function querySomething() {
$link = $GLOBALS['FB_LINK']; // shared global
// do queries...
ibase_close($link); // previously might have just decreased refcount
}New — Option A: do not close shared connections (recommended for shared/global link):
// initialize once at bootstrap
$GLOBALS['FB_LINK'] = ibase_connect($dsn, $user, $pass);
// when using connection, DON'T call ibase_close() if other code still needs it
function querySomething() {
$link = $GLOBALS['FB_LINK'];
// do queries...
// DO NOT call ibase_close($link) here
}New — Option B: explicit scoped usage (close when done):
function withConnection(callable $fn) {
$link = ibase_connect($dsn, $user, $pass);
try {
return $fn($link);
} finally {
ibase_close($link); // safe: connection used only here
}
}
// usage:
withConnection(function($link) {
// do work, will be closed automatically afterwards
});New — Option C: persistent connection (if appropriate):
$link = ibase_pconnect($dsn, $user, $pass);
// don't call ibase_close() on a persistent connectionChecklist:
- Audit places where ibase_close() is called on shared/global links. Remove or relocate close calls.
- Prefer explicit lifetime scoping or persistent connections as needed.
Change: fetching TIME fields with the IBASE_UNIXTIME flag may now return a string (e.g., "HH:MM:SS" or with fractional seconds) instead of earlier numeric/negative values.
Compatibility helper: Accept both numeric and string results.
function ibase_time_to_seconds($value) {
// If old numeric behavior (seconds)
if (is_int($value) || is_float($value)) {
return (int)$value;
}
// If new string behavior "HH:MM:SS" or "HH:MM:SS.sss"
if (is_string($value)) {
// Try to parse "HH:MM:SS" (allow fractional seconds)
if (preg_match('/^(-?\d+):(\d+):(\d+(?:\.\d+)?)$/', $value, $m)) {
$hours = (int)$m[1];
$minutes = (int)$m[2];
$seconds = (float)$m[3];
return (int)($hours * 3600 + $minutes * 60 + floor($seconds));
}
// fallback: try DateTime parsing (assumes value is a time-of-day)
$dt = DateTime::createFromFormat('H:i:s', $value);
if ($dt !== false) {
$midnight = DateTime::createFromFormat('Y-m-d H:i:s', $dt->format('Y-m-d') . ' 00:00:00');
return (int)$dt->getTimestamp() - (int)$midnight->getTimestamp();
}
}
// unknown format
return null;
}Action items:
- Update code that assumed numeric (possibly negative) values — use the helper above or adapt parsing.
- Add unit tests for TIME fields to ensure both legacy numeric and new string cases are handled.
Change: INT128 values returned by the extension are converted to strings because PHP doesn't have a native 128-bit integer.
Best practices:
- Treat INT128 columns as strings in PHP.
- If you need arithmetic on INT128, use arbitrary-precision libraries: GMP or BCMath.
Example using GMP (recommended for integer math):
$int128str = ibase_query_value(...); // returns string like "170141183460469231731687303715884105727"
if (extension_loaded('gmp')) {
$g = gmp_init($int128str);
$two = gmp_init('2');
$sum = gmp_add($g, $two);
echo gmp_strval($sum);
} elseif (extension_loaded('bcmath')) {
// bc* functions for decimal math
$sum = bcadd($int128str, '2');
} else {
// fallback: keep as string; or add dependency to gmp/bcmath
}Checklist:
- Replace any (int) casts or numeric expectations for INT128 columns.
- Add tests, and consider adding a runtime check to detect large-int columns and choose an appropriate library.
Use these to pick code paths depending on fbclient version / extension capability:
$full = ibase_get_client_version(); // e.g. "4.0.0" or string the function returns
$major = ibase_get_client_major_version(); // int
$minor = ibase_get_client_minor_version(); // int
if ($major >= 4) {
// enable Firebird 4/5 type handling
}Action:
- Add initialization-time checks and warnings/logs when fbclient is not new enough for expected features.
New INI options (example usage):
// set in php.ini or runtime (runtime only affects subsequent operations)
ini_set("ibase.default_trans_params", IBASE_READ | IBASE_NOWAIT);
ini_set("ibase.default_lock_timeout", "30"); // secondsNotes:
- The lock timeout option is used when you include IBASE_LOCK_TIMEOUT in transaction params.
- Ensure fbclient supports these options where you need them.
Test:
- Add tests that start transactions with lock timeout and verify expected wait/timeout behavior under contention.
Change: support for longer table and field names.
Impact:
- Generally improves compatibility if you previously had truncated names.
- Check code that assumed fixed/short name lengths (e.g., substrings) and update if needed.
- Functional tests for all queries that use:
- INT128 columns (read/write/compare)
- TIME/TIMESTAMP fields (with and without IBASE_UNIXTIME)
- Transactions with lock contention, verifying IBASE_LOCK_TIMEOUT behavior
- Connection lifecycle tests (shared connection, closing in different places)
- Integration tests to verify:
- Code paths that call ibase_close() still behave correctly after the change
- Behavior when fbclient is an older version (fallbacks)
- Add runtime telemetry or warnings in bootstrap if ibase_get_client_major_version() < expected.
- Update dev/staging with php-firebird 6.1.1-RC.2 (or latest RC) and updated fbclient (4/5 if you want Firebird 4/5 features).
- Run the tests in the checklist; fix parsing/close-call issues flagged by tests.
- Deploy to canary environment, monitor connection/transaction behavior and time parsing.
- Full rollout.
- RC releases are pre-release; maintainers recommend thorough testing before production.
- If your codebase is large, run an automated scan for:
- Calls to ibase_close(
- Direct numeric casts on result columns that may be INT128
- Usage of IBASE_UNIXTIME and code that assumes numeric output