Problem/Motivation

PHP 7.3 will released late 2018. We should be compatible the moment it lands.

Errors fixed:

  • Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /var/www/html/core/modules/file/file.module
  • PHPUnit\Framework\Exception: PHP Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /var/www/html/core/tests/Drupal/KernelTests/AssertConfigTrait.php
  • Exception: Warning: session_id(): Cannot change session id when session is active Drupal\Core\Session\SessionManager->regenerate()() (Line: 222)

Proposed resolution

Fix all test failures on PHP 7.3. Some workarounds for PHP 7.3 bugs are necessary. Resolving these is tracked in #3001920: Investigate PHP 7.3 workarounds

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

CommentFileSizeAuthor
#42 2989734-2-41.patch8.12 KBalexpott
#42 38-41-interdiff.txt1.55 KBalexpott
#38 2989734-2-38.patch8.82 KBalexpott
#38 36-38-interdiff.txt869 bytesalexpott
#36 2989734-2-36.patch8.93 KBalexpott
#36 33-36-interdiff.txt1.32 KBalexpott
#33 2989734-2-33.patch7.92 KBalexpott
#33 25-33-interdiff.txt933 bytesalexpott
#25 2989734-2-25.patch7.65 KBalexpott
#25 24-25-interdiff.txt967 bytesalexpott
#24 2989734-2-24.patch6.7 KBalexpott
#24 23-24-interdiff.txt1.01 KBalexpott
#23 2989734-2-23.patch5.7 KBalexpott
#23 16-23-interdiff.txt1.01 KBalexpott
#16 2989734-2-14.patch4.58 KBalexpott
#15 2989734-2-15.patch5.32 KBalexpott
#15 14-15-interdiff.txt752 bytesalexpott
#14 2989734-2-14.patch4.58 KBalexpott
#14 12-14-interdiff.txt742 bytesalexpott
#12 2989734-2-12.patch3.86 KBalexpott
#12 11-12-interdiff.txt562 bytesalexpott
#11 6-11-interdiff.txt1.59 KBalexpott
#11 2989734-2-11.patch3.31 KBalexpott
#6 2989734-6.patch4.9 KBalexpott
#6 2-6-interdiff.txt1.62 KBalexpott
#2 2989734-2.patch3.09 KBalexpott
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alexpott created an issue. See original summary.

alexpott’s picture

The one that seems to be causing the most warnings is https://wiki.php.net/rfc/continue_on_switch_deprecation and this reveals that file.module probably is not working as intended.

Status: Needs review » Needs work

The last submitted patch, 2: 2989734-2.patch, failed testing. View results

mondrake’s picture

alexpott’s picture

+++ b/core/lib/Drupal/Core/Session/SessionManager.php
@@ -218,6 +218,7 @@ public function regenerate($destroy = FALSE, $lifetime = NULL) {
     if ($this->isStarted()) {
       $old_session_id = $this->getId();
+      session_destroy();
     }
     session_id(Crypt::randomBytesBase64());

So this is not going to work :( The only reliable solution I've found so far is not migrating the session during an install. Which feels really bad.

alexpott’s picture

So here's the bad fix for the session issue. I think we might need to work on #2238561: Use the default PHP session ID instead of generating a custom one

And also weirdly $this->getSession()->getPage()->getHtml() in tests does not work but $this->getSession()->getPage()->getContent() does. I've not dug into why and where the problem lies.

Status: Needs review » Needs work

The last submitted patch, 6: 2989734-6.patch, failed testing. View results

dpi’s picture

Title: PHP 7.3 compatiblity » PHP 7.3 compatibiity
dpi’s picture

Title: PHP 7.3 compatibiity » PHP 7.3 compatibility

Fail

Ayesh’s picture

alexpott’s picture

Let's remove the session changes and see where we are at. PHP 7.3 has some changes in the beta that have fixed a few errors as far as I can see.

alexpott’s picture

I'm not convinced we're regenerating the session ID correctly. Reading the SYmfony docs it says

     * This method must invoke session_regenerate_id($destroy) unless
     * this interface is used for a storage object designed for unit
     * or functional testing where a real PHP session would interfere
     * with testing.

We're not calling session_regenerate_id() - we're doing session_id(Crypt::randomBytesBase64()); which seems wrong. PHP will assign a random session ID and we should be using session_regenerate_id() to generate a new ID for an existing session.

Berdir’s picture

@alexpott: That sounds very related to #2238561: Use the default PHP session ID instead of generating a custom one, we always set our session ID ourself currently. And according to the patch in the other issue, that whole code block only exists because we do things our way.

alexpott’s picture

@Berdir thanks for finding that issue and yes it does seem very related. I think the approach here is okay to get PHP 7.3 compatibility and then we can deal with the bigger issue of what code do we actually still need there. With the current patch we use PHP's inbuilt session ID creation which according to that issue is as security as what we do in HEAD.

The migrate fails in #12appear to be a regression introduced in PHP 7.3 - there's something that we can serialize and unserialize in PrivateTempStore that works on 7.2 but not in 7.3. However the bigger question is why are we serializing so much in the batch. I've been try to extract the bit that is causing the fail to open a sensible bug report on bugs.php.net but not managed to so far. But our other option here is to use DependencySerializationTrait in PrivateTempStore which stops this from happening and seems very sensible to me.

The fails in Drupal\KernelTests\Core\Entity\EntityQueryTest and Drupal\Tests\migrate\Unit\MigrationPluginManagerTest are not happening locally for me on PHP 7.3.0beta3.

alexpott’s picture

Working on the testbot fail in Drupal\KernelTests\Core\Entity\EntityQueryTest...

    // Calculate the cartesian product of the unit array by looking at the
    // bits of $i and add the unit at the bits that are 1. For example,
    // decimal 13 is binary 1101 so unit 3,2 and 0 will be added to the
    // entity.

Not the simplest thing to wokr out how PHP 7.3 might be messing this up :) ... and only on testbot.

alexpott’s picture

+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php
@@ -139,6 +139,7 @@ protected function setUp() {
           list($field_name, $langcode, $values) = $units[$key];
+          $this->assertTrue($entity->hasTranslation($langcode), "Entity has translation. Key $key Value: " . print_r($units[$key], TRUE));
           $entity->getTranslation($langcode)->{$field_name}[] = $values;

Uhoh - how has the act of checking for the language fixed the test? That's not fair. Re-uploading the patch from #14 to make sure it's not something fixed the PHP7.3 build.

alexpott’s picture

oh nice as @Berdir put it... we have a Heisenbug :(

alexpott’s picture

Title: PHP 7.3 compatibility » PHP 7.3 compatibility part 1
Version: 8.7.x-dev » 8.6.x-dev
Issue summary: View changes

Discussed with @catch. We agreed that as PHP 7.3 release is imminent and the beta is out now we could proceed with this issue as it is and handle the other two fails in a followup. This means that 8.6.2 will hopefully support PHP 7.3 without warnings.

Opened #3001920: Investigate PHP 7.3 workarounds

catch’s picture

The session changes here are much more minimal than the ones in #2238561: Use the default PHP session ID instead of generating a custom one, which additionally removes some other @todos and workarounds. Is there a reason not to bump that issue and get it done, or are you deliberately making a smaller change and leaving that as a follow-up? I can see arguments for both..

Everything else looks straightforward.

alexpott’s picture

@catch I deliberately made the smallest change. And yeah this is the most tricky part of this patch. I played with #2238561: Use the default PHP session ID instead of generating a custom one yesterday to try to bump that one in front. It appears that not setting the session id causes some problems for our installer. So this patch would put us in the interesting state of assigning our own session ID unless we migrate sessions and regenerate one when we'll let PHP do the generation. On one hand I don't think this really matters, on the other it feels very inconsistent. I'll try and work on #2238561: Use the default PHP session ID instead of generating a custom one and see what I can work out - because I think getting it done is the right course but to be pragmatic if we haven't got it done and in 8.6.2 then we should consider going forward here without it.

tacituseu’s picture

There's also a PDOException generated by Drupal\Tests\Component\Serialization\YamlPeclTest (see console log).

alexpott’s picture

@tacituseu that'll be because the test is skipped because there is no yaml extension built. So there is no file :) - we can fix that in simpletest_phpunit_testcase_to_row().

alexpott’s picture

This should pass Drupal\Tests\Component\Serialization\YamlPeclTest

alexpott’s picture

I've got a workaround for the EntityQueryTest - perhaps we can re-purpose #3001920: Investigate PHP 7.3 workarounds to remove PHP 7.3 workarounds.

alexpott’s picture

Title: PHP 7.3 compatibility part 1 » PHP 7.3 compatibility
FileSize
967 bytes
7.65 KB

So the fail in \Drupal\Tests\migrate\Unit\MigrationPluginManagerTest is actual a real fail. We should be guaranteeing a stable sort but it's not. So let's make it a stable sort so migrations will run in the same order regardless of PHP version.

alexpott credited mikelutz.

alexpott’s picture

Crediting @mikelutz and @tacituseu for their work on #3001920: Investigate PHP 7.3 workarounds which has helped get this (hopefully) green.

alexpott’s picture

Issue summary: View changes
mondrake’s picture

Tested patch in #25 on Travis CI for the Imagemagick module with

Drupal 8.7.x
PHP 7.4.0-dev
PHPUnit 6.5.13

and tests run smoothly https://travis-ci.org/mondrake/imagemagick/jobs/440495985

Without the patch, they were failing https://travis-ci.org/mondrake/imagemagick/jobs/440492343

Setting to RTBC, tentatively. IDNK is there anything left to do here?

alexpott’s picture

+++ b/core/lib/Drupal/Core/Session/SessionManager.php
@@ -218,8 +218,8 @@ public function regenerate($destroy = FALSE, $lifetime = NULL) {
     if ($this->isStarted()) {
       $old_session_id = $this->getId();
+      session_regenerate_id($destroy);
     }
-    session_id(Crypt::randomBytesBase64());

This is the only tricky change because it totally changes how our session IDs are generated. We need a decent CR for this explaining we now obey PHP's session generation in certain circumstances. But also we need to consider whether this is sane or if the disruption caused by #2238561: Use the default PHP session ID instead of generating a custom one is preferable.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Needs review

Let's make it clear in status that this needs more discussion.

DamienMcKenna’s picture

Version: 8.6.x-dev » 8.7.x-dev

Shouldn't this go in 8.7 first and then be backported to 8.6?

alexpott’s picture

Been thinking about this some more I think we can do this without changing how the session ID is regenerated. It might involve an extra write to the DB if the session already exists which I think is rare - anonymous users normally do not have a session - a case that comes to mind with core is after an install but one extra db operation there is hardly a problem.

alexpott’s picture

Version: 8.7.x-dev » 8.6.x-dev

@DamienMcKenna yep this has to go in 8.7 first but it is targeting 8.6.x because PHP 7.3 is out in November way before 8.7.0.

Status: Needs review » Needs work

The last submitted patch, 33: 2989734-2-33.patch, failed testing. View results

alexpott’s picture

Fingers-crossed this should be green.

Status: Needs review » Needs work

The last submitted patch, 36: 2989734-2-36.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
FileSize
869 bytes
8.82 KB

Ho hum. I was wrong. Maybe this one...

catch’s picture

Status: Needs review » Reviewed & tested by the community

Nice find with the session change, that looks a lot less intrusive than both the earlier changes here and the other issue.

alexpott’s picture

+++ b/core/includes/install.core.inc
@@ -1566,6 +1566,8 @@ function install_bootstrap_full() {
+  // Set a value to ensure the session is maintained throughout the install.
+  $session->set('_drupal_installing', TRUE);

@@ -1879,6 +1881,9 @@ function install_finished(&$install_state) {
+  // Clean up the session flag.
+  \Drupal::service('session')->remove('_drupal_installing');

I'd love to understand what is happening with a multi-lingual install that makes this necessary. On one level fixing the session during an install makes heaps of sense but on another that fact this change makes this necessary is worrying. The test that fails without this code is: Drupal\FunctionalTests\Installer\InstallerExistingConfigSyncDirectoryMultilingualTest.

Will try looking into this. But tracking down this stuff in the installer is hard.

andypost’s picture

@alexpott I bet multilingual needs rebuild container and download translation in batch, which in turn needs session

alexpott’s picture

I think I understand it. So with the multi-lingual install we have a proper multi-stage batch process during the install just before logging the user in. When this happens we declare the session obsolete during the regeneration and destroy it instead of saving it. That's not what we should be doing because then \Drupal\Core\Session\SessionManager::migrateStoredSession() has nothing to do. Here's a patch the removes the changes to the installer in favour of ensuring we don't destroy a session during session regeneration.

alexpott’s picture

Note wrt to multi-lingual install and session we've had a very similar issue in the past. See #2108623: Installing via the UI no longer logs in user 1 every time

jibran’s picture

andypost’s picture

@alexpott yes, that explained in #2108623-23: Installing via the UI no longer logs in user 1 every time

+++ b/core/lib/Drupal/Core/TempStore/PrivateTempStore.php
@@ -27,6 +28,7 @@
+  use DependencySerializationTrait;

I guess it needs follow-up to investigate #14

there's something that we can serialize and unserialize in PrivateTempStore that works on 7.2 but not in 7.3

andypost’s picture

catch’s picture

That looks much better.

Committed 39c3361 and pushed to 8.7.x. Thanks!

Looks looks backportable to 8.6.x, however definitely not the day before a release window. So leaving RTBC there.

  • catch committed 39c3361 on 8.7.x
    Issue #2989734 by alexpott, andypost, mikelutz, tacituseu: PHP 7.3...
xjm’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record

Can we get a change record please? Thanks!

alexpott’s picture

Nothing has changed that anyone needs to react to as far as I know.

  • The session changes should be transparent.
  • The serialization trait being used by PrivateTempStore is not an API change
  • Everything else are workarounds for things that have been deprecated in PHP 7.3 or are considered errors so if contrib or custom does this they'll get the same warnings a core got.

Or do we need a change record to say that we support PHP 7.3?

Wim Leers’s picture

Or do we need a change record to say that we support PHP 7.3?

Not sure what we've done in the past (for PHP 7.2 f.e.), but that sure sounds helpful and valuable?

catch’s picture

Status: Needs work » Reviewed & tested by the community

That makes sense to me too, posted one here: https://www.drupal.org/node/3011831

Added a note in the CR to say that people should consult this issue to see what changes core had to make.

Back to RTBC for 8.6.x

  • larowlan committed 5d17da1 on 8.6.x authored by catch
    Issue #2989734 by alexpott, andypost, mikelutz, tacituseu: PHP 7.3...
larowlan’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: -Needs change record

C/p as 5d17da1f31 and pushed to 8.6.x

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

hchonov’s picture

Both in the change record and in the documentation only Drupal 8.7.x is listed as supporting PHP 7.3.
See https://www.drupal.org/docs/8/system-requirements/php-requirements and https://www.drupal.org/node/3011831 .

However the issue has been backported to 8.6x. and is now included in 8.6.4. I've updated the documentation to include the 8.6.4 version. Is it fine to update the CR as well?

hansfn’s picture

@hchonov: Thx for updating the documentation. It was based on the CR. I wasn't aware that this was backported to 8.6.x - which is great news by the way.

mfb’s picture

It seems like we're currently in a state where some services work on PHP 7.3 but some don't - e.g. PrivateTempStore was fixed here, but SharedTempStore was not.

mfb’s picture

klausi’s picture

liquidcms’s picture

deleted.