New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

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

Comments

@danielbachhuber
Member

danielbachhuber commented Jan 28, 2015

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

This comment has been minimized.

Show comment
Hide comment
@szepeviktor

szepeviktor Feb 12, 2015

Contributor

Does this if prevent this behaviour?

Contributor

szepeviktor commented Feb 12, 2015

Does this if prevent this behaviour?

@nextgenthemes

This comment has been minimized.

Show comment
Hide comment
@nextgenthemes

nextgenthemes Mar 15, 2015

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;
}

nextgenthemes commented Mar 15, 2015

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

This comment has been minimized.

Show comment
Hide comment
@szepeviktor

szepeviktor Mar 15, 2015

Contributor

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

Contributor

szepeviktor commented Mar 15, 2015

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

@nextgenthemes

This comment has been minimized.

Show comment
Hide comment
@nextgenthemes

nextgenthemes Mar 15, 2015

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

nextgenthemes commented Mar 15, 2015

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

@EndemolUK

This comment has been minimized.

Show comment
Hide comment
@EndemolUK

EndemolUK Aug 5, 2015

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.

EndemolUK commented Aug 5, 2015

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

This comment has been minimized.

Show comment
Hide comment
@bloqhead

bloqhead Aug 13, 2015

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

bloqhead commented Aug 13, 2015

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

a7127cff69cab32e5c4723e8446e21c4b7325dc added a commit to a7127cff69cab32e5c4723e8446e21c4b7325dc/wp-cli that referenced this issue Sep 23, 2015

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
@scribu

This comment has been minimized.

Show comment
Hide comment
@scribu

scribu Sep 25, 2015

Member

@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

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

This comment has been minimized.

Show comment
Hide comment
@rmccue

rmccue Sep 25, 2015

Contributor

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.

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

This comment has been minimized.

Show comment
Hide comment
@scribu

scribu Sep 25, 2015

Member

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.

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

This comment has been minimized.

Show comment
Hide comment
@rmccue

rmccue Sep 25, 2015

Contributor

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.

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

This comment has been minimized.

Show comment
Hide comment
@danielbachhuber
Member

danielbachhuber commented Dec 14, 2015

Related #2278

@danyalette

This comment has been minimized.

Show comment
Hide comment
@danyalette

danyalette Jan 20, 2016

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)

danyalette commented Jan 20, 2016

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

This comment has been minimized.

Show comment
Hide comment
@benlk

benlk Jun 6, 2016

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

benlk commented Jun 6, 2016

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

This comment has been minimized.

Show comment
Hide comment
@danielbachhuber

danielbachhuber Jun 6, 2016

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.

Member

danielbachhuber commented Jun 6, 2016

@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

This comment has been minimized.

Show comment
Hide comment
@benlk

benlk 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)

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

This comment has been minimized.

Show comment
Hide comment
@danielbachhuber

danielbachhuber Oct 24, 2016

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.

Member

danielbachhuber commented Oct 24, 2016

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.

@senica

This comment has been minimized.

Show comment
Hide comment
@senica

senica Feb 21, 2017

For those that got here because of the add_filter error, just wrap your add_filters in a if(function_exists('add_filter')){ /* your add_filter functions here */ }
If you don't want to move them to a plugin or some of the other suggested routes.

senica commented Feb 21, 2017

For those that got here because of the add_filter error, just wrap your add_filters in a if(function_exists('add_filter')){ /* your add_filter functions here */ }
If you don't want to move them to a plugin or some of the other suggested routes.

@decadence

This comment has been minimized.

Show comment
Hide comment
@decadence

decadence Aug 8, 2017

It also fails if you have <? open tag in wp-config.php instead of <?php

decadence commented Aug 8, 2017

It also fails if you have <? open tag in wp-config.php instead of <?php

@temujin9

This comment has been minimized.

Show comment
Hide comment
@temujin9

temujin9 Jan 17, 2018

Any chance that add_filter could be defined as a no-op fuction in this context, so that WP CLI can be used without requiring modifications? (EDIT: apparently, no. I'd forgotten that you can't redefine functions in PHP.)

temujin9 commented Jan 17, 2018

Any chance that add_filter could be defined as a no-op fuction in this context, so that WP CLI can be used without requiring modifications? (EDIT: apparently, no. I'd forgotten that you can't redefine functions in PHP.)

@paulschreiber

This comment has been minimized.

Show comment
Hide comment
@paulschreiber

paulschreiber Jan 22, 2018

I hit this because the last two lines in my wp-config weren't the expected:

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

paulschreiber commented Jan 22, 2018

I hit this because the last two lines in my wp-config weren't the expected:

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

zachflauaus added a commit to zachflauaus/mtv-vvv-site that referenced this issue Mar 5, 2018

@nickbreen

This comment has been minimized.

Show comment
Hide comment
@nickbreen

nickbreen Mar 16, 2018

@decadence your comment led me to my fix. I had <?Php rather than <?php at the start of wp-config.php.

The cryptic error message in my case was:

PHP Parse error:  syntax error, unexpected '<', expecting end of file in phar://
/usr/local/share/php/wp-cli.phar/php/WP_CLI/Runner.php(941) : eval()'d code on line 1

Which, of course, implies some PHP file has a syntax error.

nickbreen commented Mar 16, 2018

@decadence your comment led me to my fix. I had <?Php rather than <?php at the start of wp-config.php.

The cryptic error message in my case was:

PHP Parse error:  syntax error, unexpected '<', expecting end of file in phar://
/usr/local/share/php/wp-cli.phar/php/WP_CLI/Runner.php(941) : eval()'d code on line 1

Which, of course, implies some PHP file has a syntax error.

@decadence

This comment has been minimized.

Show comment
Hide comment
@decadence

decadence Mar 16, 2018

@nickbreen glad you solved it

decadence commented Mar 16, 2018

@nickbreen glad you solved it

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