You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Upgrading a real SMF 2.1 forum to 3.0 stops at DropTimeOffset, and two further defects surface immediately after the upgrade finishes. All three are engine-independent; the PostgreSQL-only blockers on the same journey are #9519.
I found these by restoring the committed SMF 2.1.7 baseline from #9330 (403 members, 6 000 messages, 24 boards) and running upgrade.php over it.
1. DropTimeOffset reads a column the query does not select.
$request = $this->query(
'SELECT DISTINCT time_offset FROM {db_prefix}members WHERE timezone = {empty}',
);
while ($row = Db::$db->fetch_assoc($request)) {
if (isset($offsets[$row['offset']])) { // line 70continue;
}
$offset = (int) ($forum_utc_offset + $row['time_offset'] * 3600);
...$offsets[$row['time_offset']] = ...; // line 86 reads $row['offset']
Two of the three reads use $row['offset'], which does not exist. $offsets therefore ends up with a single entry keyed by the empty string, and the UPDATE built from it binds '' to a {float:…} placeholder:
Wrong value type sent to the database. Floating point number expected. (d41d8cd98f00b204e9800998ecf8427e)
d41d8cd98f00b204e9800998ecf8427e is md5(''), which is where the empty key surfaces.
2. The same migration then fails on the placeholder names.
With the column name corrected, the next statement is:
PHP casts numeric string array keys to integers, so $offset is an int and, under declare(strict_types=1):
md5(): Argument #1 ($string) must be of type string, int given
Both need fixing before a forum with time offsets can be upgraded at all — and a 2.1 forum where nobody set a timezone is the normal case, since 2.1 stored offsets rather than zones.
3. After the upgrade, a member with two-factor authentication cannot log in.
The password is accepted and the redirect to the second factor happens, and then:
Cannot assign null to property SMF\User::$dataset of type SMF\UserDataset
That is Sources/User.php:4265, $this->dataset = $profile['dataset'];, reached with a profile that has no dataset key. Two more are logged alongside it:
2: Undefined array key "linktree"
2: foreach() argument must be of type array|object, null given
The account is simply locked out — there is no way past the second factor. #9302 touches LoginTFA.php, but only to change parent::validatePasswordFlood() to Security::validatePasswordFlood() on the wrong-code path, so it does not cover this.
4. Background tasks queued under 2.1 keep their old class names.
smf_background_tasks survives the upgrade untouched, so rows written by 2.1 still name 2.1 classes:
Invalid background task specified: class CreatePost_Notify_Background not found
Invalid background task specified: class Update_TLD_Regex not found
3.0 calls that first one SMF\Tasks\CreatePost_Notify. The rows are never removed, so the task runner rediscovers them on every pass and logs the same error indefinitely.
MySQL 8.4; also reproduced on PostgreSQL 17 for (1) and (2)
PHP Version
8.4.24
Logs
# 1
PHP Warning: Undefined array key "offset"in .../Migration/v3_0/DropTimeOffset.php on line 70
PHP Warning: Undefined array key "offset"in .../Migration/v3_0/DropTimeOffset.php on line 86
Wrong value type sent to the database. Floating point number expected. (d41d8cd98f00b204e9800998ecf8427e)
# 2
+++ Removing time_offset column from members table... failed with error:
"md5(): Argument #1 ($string) must be of type string, int given"# 3
Cannot assign null to property SMF\User::$dataset of type SMF\UserDataset
# 4
SELECT DISTINCT task_class FROM smf_background_tasks;
CreatePost_Notify_Background
\SMF\Tasks\Utf8EntityDecode
SMF\Tasks\FetchSMfiles
SMF\Tasks\UpdateSpoofDetectorNames
SMF\Tasks\SendDigests
Additional Information
Found while testing #9517; none of these are related to it — DropTimeOffset.php, User.php, LoginTFA.php and TaskRunner.php are byte-identical between release-3.0 and that branch. Once (1) and (2) are patched the upgrade completes on MySQL and the forum works.
Related: #9519 (the PostgreSQL-only blockers on the same upgrade), #9330 (the 2.1 baseline used to reproduce this).
Basic Information
Upgrading a real SMF 2.1 forum to 3.0 stops at
DropTimeOffset, and two further defects surface immediately after the upgrade finishes. All three are engine-independent; the PostgreSQL-only blockers on the same journey are #9519.I found these by restoring the committed SMF 2.1.7 baseline from #9330 (403 members, 6 000 messages, 24 boards) and running
upgrade.phpover it.1.
DropTimeOffsetreads a column the query does not select.Sources/Maintenance/Migration/v3_0/DropTimeOffset.phpselectstime_offset:Two of the three reads use
$row['offset'], which does not exist.$offsetstherefore ends up with a single entry keyed by the empty string, and theUPDATEbuilt from it binds''to a{float:…}placeholder:d41d8cd98f00b204e9800998ecf8427eismd5(''), which is where the empty key surfaces.2. The same migration then fails on the placeholder names.
With the column name corrected, the next statement is:
PHP casts numeric string array keys to integers, so
$offsetis anintand, underdeclare(strict_types=1):Both need fixing before a forum with time offsets can be upgraded at all — and a 2.1 forum where nobody set a timezone is the normal case, since 2.1 stored offsets rather than zones.
3. After the upgrade, a member with two-factor authentication cannot log in.
The password is accepted and the redirect to the second factor happens, and then:
That is
Sources/User.php:4265,$this->dataset = $profile['dataset'];, reached with a profile that has nodatasetkey. Two more are logged alongside it:The account is simply locked out — there is no way past the second factor. #9302 touches
LoginTFA.php, but only to changeparent::validatePasswordFlood()toSecurity::validatePasswordFlood()on the wrong-code path, so it does not cover this.4. Background tasks queued under 2.1 keep their old class names.
smf_background_taskssurvives the upgrade untouched, so rows written by 2.1 still name 2.1 classes:3.0 calls that first one
SMF\Tasks\CreatePost_Notify. The rows are never removed, so the task runner rediscovers them on every pass and logs the same error indefinitely.Steps to reproduce
time_offsetand an emptytimezone.upgrade.php.DropTimeOffsetdefects and run it again.smf_log_errorsfor a few minutes.Expected result
The upgrader runs to the end. Members log in, second factor included. Nothing accumulates in the error log.
Actual result
DropTimeOffsetwith the floating point message.md5()type error.action=logintfais a 500 and the account cannot get in.Version/Git revision
3.0 Alpha 4,
release-3.0at bfbca5bDatabase Engine
All
Database Version
MySQL 8.4; also reproduced on PostgreSQL 17 for (1) and (2)
PHP Version
8.4.24
Logs
Additional Information
Found while testing #9517; none of these are related to it —
DropTimeOffset.php,User.php,LoginTFA.phpandTaskRunner.phpare byte-identical betweenrelease-3.0and that branch. Once (1) and (2) are patched the upgrade completes on MySQL and the forum works.Related: #9519 (the PostgreSQL-only blockers on the same upgrade), #9330 (the 2.1 baseline used to reproduce this).