Make WordPress Core

Opened 4 weeks ago

Closed 4 weeks ago

Last modified 3 weeks ago

#62035 closed defect (bug) (fixed)

SITE_ID_CURRENT_SITE broken in 6.3 or later

Reported by: scottculverhouse's profile scottculverhouse Owned by: sergeybiryukov's profile SergeyBiryukov
Milestone: 6.7 Priority: normal
Severity: normal Version: 6.3
Component: Networks and Sites Keywords: has-patch has-unit-tests needs-testing
Focuses: multisite Cc:

Description

We set the constants

<?php
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 2);

This was working up until 6.3 where the following commit was added

I believe this is a bug for the following reasons

  1. The typecast of SITE_ID_CURRENT_SITE to int
  2. along with the strict comparison
  3. and $this->id is always a string

Attachments (2)

class-wp-network.php.diff (1.2 KB) - added by scottculverhouse 4 weeks ago.
Diff adding debugging to class-wp-network.php
62035.diff (459 bytes) - added by SergeyBiryukov 4 weeks ago.

Download all attachments as: .zip

Change History (17)

#1 follow-up: @ironprogrammer
4 weeks ago

  • Keywords reporter-feedback added

Welcome to Trac, and thanks for the report, @scottculverhouse!

Could you provide additional information on the error or what isn't working as expected since the strict comparison update? Since version 4.6, the network ID has been an int, and enforced as such by the getter/setter. In the updated code, $this->id shouldn't be a string (compared with $this->blog_id which is still a string for backward compat).

I'm marking this ticket with reporter-feedback to signal that more information has been requested. Thanks!

#2 in reply to: ↑ 1 @scottculverhouse
4 weeks ago

  • Summary changed from BLOG_ID_CURRENT_SITE broken in 6.3 or later to SITE_ID_CURRENT_SITE broken in 6.3 or later

Replying to ironprogrammer:

Could you provide additional information on the error or what isn't working as expected since the strict comparison update? Since version 4.6, the network ID has been an int, and enforced as such by the getter/setter. In the updated code, $this->id shouldn't be a string (compared with $this->blog_id which is still a string for backward compat).

Thanks for your prompt response, I think something funky is going on but can't put my finger on it. I've added some var_dump inside __get / __isset & __set to see what's going on. Also added a var_dump($this->id) which is returning string(1) "1". Please see attached diff.

The output of this debugging is as follows

string(5) "__get"
string(2) "id"
string(7) "__isset"
string(7) "blog_id"
string(5) "__get"
string(7) "blog_id"
string(30) "top of get_main_site_id method"
string(1) "1"
stopped

So to me it appears the var_dump($this->id); is not going through __get magic method. Like I said something "funky is going on", I'm not familiar with the WP source code so hope this helps.

@scottculverhouse
4 weeks ago

Diff adding debugging to class-wp-network.php

#3 @scottculverhouse
4 weeks ago

Also to clarify the blog_id isn't getting set correctly when we use SITE_ID_CURRENT_SITE and BLOG_ID_CURRENT_SITE in our wp-config.php This previously worked with WP < 6.3

I'm on your slack if you want to DM for more info.

#4 follow-up: @spacedmonkey
4 weeks ago

Mind taking a look @SergeyBiryukov ?

#5 in reply to: ↑ 4 ; follow-up: @SergeyBiryukov
4 weeks ago

Replying to spacedmonkey:

Mind taking a look @SergeyBiryukov ?

Thanks for the ping! I saw the ticket, but I can't figure out how to reproduce this yet. $this->id should only ever be an int, as noted in comment:1::

Since version 4.6, the network ID has been an int, and enforced as such by the getter/setter. In the updated code, $this->id shouldn't be a string (compared with $this->blog_id which is still a string for backward compat).

Last edited 4 weeks ago by SergeyBiryukov (previous) (diff)

@SergeyBiryukov
4 weeks ago

#6 in reply to: ↑ 5 ; follow-up: @SergeyBiryukov
4 weeks ago

  • Keywords has-patch added; reporter-feedback removed
  • Milestone changed from Awaiting Review to 6.7
  • Owner set to SergeyBiryukov
  • Status changed from new to accepted

Replying to SergeyBiryukov:

I saw the ticket, but I can't figure out how to reproduce this yet. $this->id should only ever be an int

Hmm, I was able to reproduce it with class-wp-network.php.diff.

When a new WP_Network instance is created, it sets the initial properties as retrieved from the database:

WP_Network::get_instance() {
    ...
    $_network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d LIMIT 1", $network_id ) );
    ...
    return new WP_Network( $_network );
}

WP_Network::__construct( $network ) {
    ...
    foreach ( get_object_vars( $network ) as $key => $value ) {
        $this->$key = $value;
    }
    ...
}

This is where $this->id is set to a string, so it appears that [37870] / #37050 didn't quite work as expected: despite being documented as an int, $this->id is still a string in practice.

62035.diff fixes the issue in my testing, but this could use some unit tests.

This ticket was mentioned in PR #7345 on WordPress/wordpress-develop by @ironprogrammer.


4 weeks ago
#7

  • Keywords has-unit-tests added

Uses setters when constructing a WP_Network object. Ensures that WP_Network::id is stored internally as int, as follow-up to changeset 37870.

Trac ticket: https://core.trac.wordpress.org/ticket/62035

#8 in reply to: ↑ 6 ; follow-up: @ironprogrammer
4 weeks ago

  • Keywords needs-testing added

Replying to SergeyBiryukov:

62035.diff fixes the issue in my testing, but this could use some unit tests.

Thanks for the patch, @SergeyBiryukov! I've submitted PR #7345 which includes a unit test for the type of WP_Network::id. The other consideration might be to verify that WP_Network::blog_id is string (enforcing future backward compat), but I wanted to seek input before adding that.

#9 @SergeyBiryukov
4 weeks ago

In 59020:

Networks and Sites: Set WP_Network properties via setters upon creation.

This ensures that WP_Network::$id is stored internally as int, to match the documented type.

Follow-up to [37870].

Props ironprogrammer, scottculverhouse, spacedmonkey, SergeyBiryukov.
See #62035.

@SergeyBiryukov commented on PR #7345:


4 weeks ago
#10

Thanks for the PR! Merged in r59020.

#11 in reply to: ↑ 8 @SergeyBiryukov
4 weeks ago

Replying to ironprogrammer:

I've submitted PR #7345 which includes a unit test for the type of WP_Network::id. The other consideration might be to verify that WP_Network::blog_id is string (enforcing future backward compat), but I wanted to seek input before adding that.

The test looks perfect, thank you!

Indeed, it would be great to verify the type of WP_Network::blog_id as well, keeping the ticket open for that for now.

#12 @SergeyBiryukov
4 weeks ago

  • Resolution set to fixed
  • Status changed from accepted to closed

In 59021:

Tests: Add tests to ensure that the WP_Network::$blog_id property is a string.

Follow-up to [34097], [36340], [37657], [37870], [37871], [59020].

Fixes #62035.

#13 follow-up: @scottculverhouse
3 weeks ago

Great work guys and thanks again for the prompt response / turnaround.

I guess this issue is how PHP is tokenising the code and doesn't process $this->$key = $value the same as $this->id = $value therefore not passing to the __set().

#14 in reply to: ↑ 13 ; follow-up: @SergeyBiryukov
3 weeks ago

Replying to scottculverhouse:

I guess this issue is how PHP is tokenising the code and doesn't process $this->$key = $value the same as $this->id = $value therefore not passing to the __set().

Thanks for the ticket! Right, in my testing it also appears that __get() is only called when retrieving the property value outside of the class, but not within methods of the same class.

For example,

class A {

	private $test = '1';

	public function __get( $key ) {
		switch ( $key ) {
			case 'test':
				return (int) $this->test;
		}

		return null;
	}

	public function get_test_value() {
		return $this->test;
	}
}

$a = new A;
var_dump( $a->test );
var_dump( $a->get_test_value() );

outputs:

int(1)
string(1) "1"

which explains the previous discrepancy here.

#15 in reply to: ↑ 14 @scottculverhouse
3 weeks ago

Replying to SergeyBiryukov:

Right, in my testing it also appears that __get() is only called when retrieving the property value outside of the class, but not within methods of the same class.

Ah ok that worth noting

Note: See TracTickets for help on using tickets.