WP-CLI can fail cryptically when parsing custom wp-config.php #1631

Closed
danielbachhuber opened this Issue Jan 28, 2015 · 16 comments

Projects

None yet

9 participants

@danielbachhuber
Member

Starting a new issue as the definitive place to point users who've run into this.

WP-CLI uses a custom version of WordPress's wp-settings.php file. Here's a narrative version of the backstory. Before WP-CLI can load wp-settings-cli.php, it needs to know all of the constants defined in wp-config.php (database connection details and so on).

In a typical WordPress install, wp-config.php has the following at the end of the file:

/* That's all, stop editing! Happy blogging. */

/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');

/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

This is the code that loads WordPress. Because WP-CLI doesn't want WordPress to load yet when it's pulling the constants out of wp-config.php, it uses regex to strip the require_once(ABSPATH . 'wp-settings.php'); statement.

But, if the regex fails for whatever reason, WordPress gets loaded via the normal wp-settings.php statement when wp-config.php is evaluated, and WP-CLI can fail in a variety of cryptic ways.

@szepeviktor
Member

Does this if prevent this behaviour?

@nextgenthemes

Fatal error: Call to undefined function add_filter() in phar:///home/xxxxxx/bin/wp/php/wp-cli.php(23) : eval()'d code on line 92

I am on webfaction if that matters. And I use Q2A WP intergration, so i have the following added to my wp-config.php (start and end)

<?php
/**
 * The base configurations of the WordPress.
 *
 * This file has the following configurations: MySQL settings, Table Prefix,
 * Secret Keys, WordPress Language, and ABSPATH. You can find more information
 * by visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing
 * wp-config.php} Codex page. You can get the MySQL settings from your web host.
 *
 * This file is used by the wp-config.php creation script during the
 * installation. You don't have to use the web site, you can just copy this file
 * to "wp-config.php" and fill in the values.
 *
 * @package WordPress
 */

define('COOKIEPATH', '/');
define('COOKIE_DOMAIN', '.nextgenthemes.com');

--- normal config removed ---

add_filter('allowed_redirect_hosts', 'qa_wordpress_redirect_hosts');
function qa_wordpress_redirect_hosts($content) {
    $content[] = 'community.nextgenthemes.com';
    return $content;
}
@szepeviktor
Member

Try moving add_filter () to a MU plugin. It can be used after WP core is loaded.

@nextgenthemes

@szepeviktor Awesome thanks, I somehow guessed this but did ask b4 thinking of mu-plugins.

@EndemolUK

As a quick and simple fix then the following mod at the end of wp-config.php should always work I think?

Change:

/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

To

if(!function_exists('wp_unregister_GLOBALS'))  {
    /** Sets up WordPress vars and included files. */
    require_once(ABSPATH . 'wp-settings.php');
}

This way if using wp-cli's internal version of wp-settings.php we don't load the site's version, and the regex that wp-cli requires to work is preserved. If just running the site as normal it'll still load too.

I don't see this as a permanent answer to the issue but it works for me.

@bloqhead

@EndemolUK that actually worked for me as well. Thank you!

@a7127cff69cab32e5c4723e8446e21c4b7325dc a7127cff69cab32e5c4723e8446e21c4b7325dc added a commit to a7127cff69cab32e5c4723e8446e21c4b7325dc/wp-cli that referenced this issue Sep 23, 2015
@a7127cff69cab32e5c4723e8446e21c4b7325dc a7127cff69cab32e5c4723e8446e21c4b7325dc Only include definitions and variable declarations
Only include definitions and variable declarations in the wp-config $lines_to_run.  This should resolve problems seen with wp-cli#1631
04be5ac
@scribu
Member
scribu commented Sep 25, 2015

@rmccue shared a great solution:

Instead of hacking the contents of the wp-config.php file and then calling eval() on it, just define ABSPATH to point to an empty wp-settings.php file:

https://github.com/humanmade/Cavalcade-Runner/blob/26054b4a302f2e59972115a5c24916d24873601f/lib/Runner.php#L28-L52

@rmccue
Contributor
rmccue commented Sep 25, 2015

Note: if you need to load WP afterwards, this can break, since WP needs to know the right ABSPATH to load itself, and plugins will also depend on that. I don't think that matters in some places wp-cli loads it, but potentially some it does.

To help with that, you can use a hybrid solution: fork/exec off an instance just to load the config, have it output as JSON, then use that in your main process. The overhead of doing that is reasonably minimal (since you're only loading wp-config, not all of WP), but it does exist.

@scribu
Member
scribu commented Sep 25, 2015

Ah... I think WP-CLI already uses the fake ABSPATH trick when it doesn't need to load the rest of WP.

fork/exec off an instance just to load the config, have it output as JSON, then use that in your main process.

Yeah, I guess you could detect (in a generic way) all the constants and globals that wp-config sets and send them via JSON.

@rmccue
Contributor
rmccue commented Sep 25, 2015

Yeah, I guess you could detect (in a generic way) all the constants and globals that wp-config sets and send them via JSON.

You can basically just use get_defined_vars and get_defined_constants before/after loading for that. Works reasonably well.

@danielbachhuber
Member

Related #2278

@danyalette

if you are using Pantheon and are having this issue (i.e. getting a seemingly random fatal error - à la Fatal error: Cannot redeclare wp_is_mobile() (previously declared in /path/vars.php:126) in phar:///usr/local/bin/wp/php/wp-settings-cli.php on line 271 when you attempt to use the wp cli):
the require statement giving you trouble is in wp-config-local.php, not in wp-config.php .

I simply commented out require_once(ABSPATH . 'wp-settings.php'); in wp-config-local.php (and left it as-is in wp-config.php). This solved my wp-cli problem and doesn't appear (so far) to have any adverse effects (since wp-settings.php does still get loaded in wp-config.php)

@benlk
benlk commented Jun 6, 2016 edited

If it's any use diagnosing this bug, the described behavior does not occur when run with the --debug flag, using Wordpress 4.5.2 and a Wordpress-generated wp-config.php:

vagrant@precise64:/vagrant$ wp --debug
Debug: No readable global config found (0.02s)
Debug: No project config found (0.023s)
Debug: No package autoload found to load. (0.04s)
Debug: ABSPATH defined: /vagrant/ (0.041s)
Debug: Begin WordPress load (0.044s)
Debug: wp-config.php path: /vagrant/wp-config.php (0.045s)
Debug: Loaded WordPress (2.491s)
Debug: Running command: help (2.596s)

and then I pressed q to exit the help list.

Running without --debug::

vagrant@precise64:/vagrant$ wp
PHP Fatal error:  Call to undefined function apply_filters() in /vagrant/wp-includes/load.php on line 315

System information:

vagrant@precise64:/vagrant$ php --version
PHP 5.3.10-1ubuntu3.23 with Suhosin-Patch (cli) (built: May 19 2016 20:38:03) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies

vagrant@precise64:/vagrant$ uname -a
Linux precise64 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
@danielbachhuber
Member

@benlk I think in time you did your before and after, VVV ran svn up on your /vagrant directory. The fatal error you're seeing is from a filter introduced in WP 4.6, so you'll need to run wp cli update --nightly for compatibility.

@benlk
benlk commented Jun 8, 2016

That's not quite what happened, but you're right that that install was using the master branch of https://github.com/wordpress/wordpress. Thanks! I'll downgrade it to 4.5.2.

(https://github.com/INN/deploy-tools has a command fab wp.install, which I ran without the required version number argument, which downloaded the master branch of wordpress instead of failing. I'm not using VVV)

@danielbachhuber
Member

At this point, I think we're going to stick with what we have. The approach of spawning a separate process to read wp-config.php is creative, but I'd be concerned about introducing a breaking change if there was business logic in the config file. While somewhat painful, this is a problem users are capable of fixing on their own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment