craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.28k stars 635 forks source link

[4.x]: "/runtime doesn't exist or isn't writable by PHP. Please fix that." after DDEV-based 3->4 upgrade #14177

Closed proimage closed 9 months ago

proimage commented 9 months ago

What happened?

Description

I'm trying to upgrade a client's Craft 3.x site to 4.x, first locally using DDEV. Once I complete the upgrade process according to the Upgrade docs, if I try to go to either the frontend or backend of the local site, I get a barebones/unstyled error: "/runtime doesn't exist or isn't writable by PHP. Please fix that.": image

I've checked the permissions of storage/runtime/ as seen here: image

(All the directories shown there are owned by [myName] [myName])

There were some odd messages after the supposedly-successful migration process:

image

Not sure if those have anything to do with anything.

Steps to reproduce

  1. Be me
  2. Upgrade my client's site in a local DDEV environment

Expected behavior

I'd expect to be able to access the site and/or CP.

Actual behavior

I get the above error message instead.

Craft CMS version

4.5.3.0 (was 3.9.10)

PHP version

8.1

Operating system and version

Windows 11 + WSL2 + DDEV

Database type and version

MariaDB 10.4

Image driver and version

No response

Installed plugins and versions

Name                            Handle                  Package Name                              Version          Installed  Enabled
------------------------------  ----------------------  ----------------------------------------  ---------------  ---------  -------
Button Box                      buttonbox               verbb/buttonbox                           4.2.2            Yes        Yes    
Cloudflare                      cloudflare              putyourlightson/craft-cloudflare          2.0.2            Yes        Yes    
Contact Form                    contact-form            craftcms/contact-form                     3.0.1            Yes        Yes    
Contact Form Honeypot           contact-form-honeypot   craftcms/contact-form-honeypot            2.0.0            Yes        Yes    
Control Panel CSS               cp-css                  doublesecretagency/craft-cpcss            2.6.0            Yes        Yes    
Digital Download                digital-download        doublesecretagency/craft-digitaldownload  2.2.1            Yes        Yes    
DigitalOcean Spaces Filesystem  dospaces                vaersaagod/dospaces                       2.0.0            Yes        Yes    
Element API                     element-api             craftcms/element-api                      3.0.1.1          Yes        Yes    
Feed Me                         feed-me                 craftcms/feed-me                          5.3.0            Yes        Yes    
Field Manager                   field-manager           verbb/field-manager                       3.0.8            Yes        Yes    
Freeform                        freeform                solspace/craft-freeform                   4.1.13           Yes        Yes    
Guest Entries                   guest-entries           craftcms/guest-entries                    3.0.1            Yes        Yes    
Image Base64                    craft-twig-imagebase64  kisonay/craft-twig-imagebase64            1.1.1            Yes        Yes    
Inventory                       inventory               doublesecretagency/craft-inventory        3.1.1            Yes        Yes    
Lab Reports                     labreports              masugadesign/labreports                   2.0.3            Yes        Yes    
Mix                             mix                     misterbk/mix                              1.6.0            Yes        Yes    
Neo                             neo                     spicyweb/craft-neo                        4.0.2            Yes        Yes    
oEmbed                          oembed                  wrav/oembed                               3.0.7            Yes        Yes    
Postmark                        postmark                craftcms/postmark                         3.0.0            Yes        Yes    
Redactor                        redactor                craftcms/redactor                         3.0.4            Yes        Yes    
Redactor Custom Styles          redactor-custom-styles  carlcs/craft-redactorcustomstyles         4.0.3            Yes        Yes    
Retour                          retour                  nystudio107/craft-retour                  4.1.14           Yes        Yes    
Scout                           scout                   studioespresso/craft-scout                3.3.2            Yes        Yes    
SEO                             seo                     ether/seo                                 4.2.1            Yes        Yes    
Sprout Email                    sprout-email            barrelstrength/sprout-email               4.44.444-beta.4  Yes        Yes    
Super Table                     super-table             verbb/super-table                         3.0.12           Yes        Yes    
Typed link field                typedlinkfield          sebastianlenz/linkfield                   2.1.5            Yes        Yes    
brandonkelly commented 9 months ago

It looks like your CRAFT_BASE_PATH PHP constant is set to an empty string (or not set at all), so paths that are supposed to be relative to it (like [CRAFT_BASE_PATH]/runtime) are becoming absolute server paths (/runtime).

By default on new Craft projects, CRAFT_BASE_PATH is defined in bootstrap.php like this.

proimage commented 9 months ago

Ok, that wasn't the (full) solution itself, but it set me on the right path. I'll document it here for future reference:

There's no bootstrap.php file in the project at all. Shouldn't there be some mention of bootstrap.php on the Upgrade from 3.x -> 4.x page? Seems kinda important to me...

In any case, I created that file, ensured it has 755 permissions, but it didn't make any difference. Then I looked into the web/index.php and saw it already has all the code that bootstrap.php should have:

<?php
/**
 * Craft web bootstrap file
 */

// Set path constants
define('CRAFT_BASE_PATH', dirname(__DIR__));
define('CRAFT_VENDOR_PATH', CRAFT_BASE_PATH.'/vendor');

// Load Composer's autoloader
require_once CRAFT_VENDOR_PATH.'/autoload.php';

// Load dotenv?
if (file_exists(CRAFT_BASE_PATH.'/.env')) {
    (new Dotenv\Dotenv(CRAFT_BASE_PATH))->load();
}

define('CRAFT_STORAGE_PATH', getenv('STORAGE_PATH'));

// Load and run Craft
define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
$app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/web.php';
$app->run();

So now I'm unsure which file should have which code; obviously the above web/index.php isn't referencing the newly-created bootstrap.php.

When I also update the web/index.php file according to its counterpart in the starter project, I get this PHP error:

Fatal error: Uncaught Error: Call to undefined method Dotenv\Dotenv::createUnsafeMutable() in /var/www/html/bootstrap.php:17 Stack trace: #0 /var/www/html/web/index.php(7): require() #1 {main} thrown in /var/www/html/bootstrap.php on line 17

That led me to noticing that the version number in composer.json for vlucas/phpdotenv didn't get updated from 2.4.0, which is mentioned in the upgrade doc as an optional step. So again referencing the starter project, I updated the version to 5.4.0 and ran ddev composer update. It installed or upgraded a dozen or so packages, and then ended with this:

image

Basically, for every one of these commands...

@php craft install/check && php craft clear-caches/compiled-classes --interactive=0 || exit 0
@php craft install/check && php craft clear-caches/compiled-templates --interactive=0 || exit 0
@php craft install/check && php craft clear-caches/data --interactive=0 || exit 0
@php craft install/check && php craft clear-caches/temp-files --interactive=0 || exit 0
@php craft install/check && php craft invalidate-tags/all --interactive=0 || return 0
@php craft install/check && php craft up --interactive=0 || exit 0

...it spit out this pair of errors:

PHP Fatal error:  Uncaught TypeError: Dotenv\Dotenv::__construct(): Argument #1 ($store) must be of type Dotenv\Store\StoreInterface, string given, called in /var/www/html/craft on line 16 and defined in /var/www/html/vendor/vlucas/phpdotenv/src/Dotenv.php:60
Stack trace:
#0 /var/www/html/craft(16): Dotenv\Dotenv->__construct('/var/www/html')
#1 {main}
  thrown in /var/www/html/vendor/vlucas/phpdotenv/src/Dotenv.php on line 60

Fatal error: Uncaught TypeError: Dotenv\Dotenv::__construct(): Argument #1 ($store) must be of type Dotenv\Store\StoreInterface, string given, called in /var/www/html/craft on line 16 and defined in /var/www/html/vendor/vlucas/phpdotenv/src/Dotenv.php:60
Stack trace:
#0 /var/www/html/craft(16): Dotenv\Dotenv->__construct('/var/www/html')
#1 {main}
  thrown in /var/www/html/vendor/vlucas/phpdotenv/src/Dotenv.php on line 60

That said, the site is now functional (🥳), however subsequent runs of both ddev composer install and ddev composer update end with that same array errors, and as you might expect, ddev craft up fails after the first one of those errors.

brandonkelly commented 9 months ago

Glad you got it sorted!

There's no bootstrap.php file in the project at all. Shouldn't there be some mention of bootstrap.php on the Upgrade from 3.x -> 4.x page? Seems kinda important to me...

We added bootstrap.php around Craft 3.4, and it’s completely up to you whether you want to keep your project’s file structure up-to-date with changes we make in the starter project—everything outside of vendor/ is your code to do what you want with.

However we do have a section under “Optional Steps” in the Craft 4 upgrade guide, nudging you to check the starter project and maybe update your project based on it.

The Dotenv errors you’re getting are because you’re using an older version of vlucas/phpdotenv than the one that ships with the starter project by default now. (The starter project currently uses ^5.4.0.)

proimage commented 9 months ago

The Dotenv errors you’re getting are because you’re using an older version of vlucas/phpdotenv than the one that ships with the starter project by default now. (The starter project currently uses ^5.4.0.)

I think perhaps you missed the part (I know, I give too much information sometimes, sorry) where I got those errors after updating Dotenv to 5.4.0...?

i-just commented 9 months ago

The code to initialise Dotenv has changed since version 2.4.0. In your response yesterday, you have:

// Load dotenv?
if (file_exists(CRAFT_BASE_PATH.'/.env')) {
    (new Dotenv\Dotenv(CRAFT_BASE_PATH))->load();
}

With version 5.4.0 you need to change that to https://github.com/craftcms/craft/blob/main/bootstrap.php#L13-L18.

You can always check your code against the bootstrap.php, craft and web/index.php files from the starter project that Brandon mentioned. Also, here’s a similar thread that references v3, but the info should still be helpful for v4.

I hope this helps!

proimage commented 9 months ago

...ahh, I had missed that the extensionless /craft file* is a PHP file! It needed updating, and that fixed the issue. Thanks!

* Why is it extensionless, anyway?

i-just commented 9 months ago

Glad you got it sorted! You can read about the craft file and other files and folders here: https://craftcms.com/docs/4.x/directory-structure.html#craft

ezawadzki commented 9 months ago

phpdotenv to 5.5.0 and this code helps me a lot, with php 8.2 and Craft 4.7.1 :

if (class_exists(Dotenv\Dotenv::class)) {
    Dotenv\Dotenv::createUnsafeMutable(CRAFT_BASE_PATH)->safeLoad();
}