0

I'm using Symfony's console component to write some command line tools, one of which uses WP-CLI to set up a WordPress site. Specifically using wp option update I'm running into issues with both JSON and quotes.

For example, running something like:

shell_exec("wp option update blogdescription ''");

Results in literal '' in the database. In fact, any time I use that command, if it's successful, whatever I've tried to set in the database is wrapped in the single quotes.

And then something like this:

$github_updater_args = [
            'github_access_token'=>'',
            'bitbucket_username'=>'username',
            'bitbucket_password'=>'password',
            'all-in-one-seo-populate-keywords'=>'1'
];
$github_updater_args = json_encode($github_updater_args);
var_dump($github_updater_args);
shell_exec("wp option update github_updater '$github_updater_args' --format=json");

The dump results in:

string(200) "{"github_access_token":"","bitbucket_username":"devs@webspecdesign.com","bitbucket_password":"xxxxxxxxx","webspec-design-wordpress-core":"1","all-in-one-seo-populate-keywords":"1","webspec-smtp":"1"}"

Which is valid JSON, but the wp command resulted in the following:

Error: Invalid JSON: '{github_access_token:,bitbucket_username:username,bitbucket_password:password,all-in-one-seo-populate-keywords:1}'

You'll notice the quotes have been stripped out, which I assume is what it's complaining about? Or is that just how it dumps out the error?

Either way, I then decided I would hardcode the JSON, so just:

shell_exec('wp option update github_updater \'{"github_access_token": "", "bitbucket_username": "username", "bitbucket_password": "password"}\' --format=json');

Which gave me the following error:

Error: Too many positional arguments: , bitbucket_username: username, bitbucket_password: password}'

I wager the two issues are related. I thought maybe it was a WP-CLI issue, so I opened an issue there, but it was closed without reaching an answer. The more I stare at it, however, the more I think it might by a Symfony thing. Perhaps I definitely need to use the Process Component rather than shell_exec? Is that what it's designed for?

Update: Tried the Symfony Process Component:

$process = new Process("wp option update blogdescription ''");
$process->run();

Still got my two quotes. So nothing doing there.

luchaninov
  • 6,792
  • 6
  • 60
  • 75
Ethan C
  • 1,408
  • 1
  • 14
  • 26
  • You're basically suffering from the shell equivalent of an sql injection attack. You need to use [escapeshellcmd()](http://php.net/manual/en/function.escapeshellcmd.php) – Marc B Nov 02 '15 at 14:16
  • @MarcB I think this was suggested previously. I tried `shell_exec(escapeshellcmd("wp option update blogdescription 'gal'"));` and the blog's tagline ended up as `'gal'`, quotes and all – Ethan C Nov 02 '15 at 14:23
  • 1
    don't escape the ENTIRE shell command line, just the json. Remember. you're going through at least two parsers: the shell's, and wp's. you need to escape the json so it gets through the shell parser – Marc B Nov 02 '15 at 14:25
  • `shell_exec( "wp option update github_updater '" . escapeshellcmd($github_updater_args) . "' --format=json" );` continues to result in the Invalid JSON error – Ethan C Nov 02 '15 at 14:27

1 Answers1

0

You are looking for escapeshellarg() to escape your json data. escapeshellcmd() is for sanitizing an entire command, not a single argument. Try something like this:

$github_updater_args = [
    'github_access_token'=>'',
    'bitbucket_username'=>'username',
    'bitbucket_password'=>'password',
    'all-in-one-seo-populate-keywords'=>'1'
];
$github_updater_args = json_encode($github_updater_args);
$cmd = sprintf("wp option update github_updater %s --format=json", escapeshellarg($github_updater_args));
shell_exec($cmd);

Edit

There is something missing from your question or there is a bug in the CLI script you are executing. I wrote two quick test php scripts to illustrate that the json escaping works correctly.

test.php

<?php

$github_updater_args = [
    'github_access_token'=>'',
    'bitbucket_username'=>'username',
    'bitbucket_password'=>'password',
    'all-in-one-seo-populate-keywords'=>'1'
];
$github_updater_args = json_encode($github_updater_args);
$cmd = sprintf("php j.php %s", escapeshellarg($github_updater_args));
echo shell_exec($cmd);
echo PHP_EOL;

j.php

<?php

var_dump(json_decode($argv[1]));

output

~$ php test.php
object(stdClass)#1 (4) {
  ["github_access_token"]=>
  string(0) ""
  ["bitbucket_username"]=>
  string(8) "username"
  ["bitbucket_password"]=>
  string(8) "password"
  ["all-in-one-seo-populate-keywords"]=>
  string(1) "1"
}
Josh J
  • 6,813
  • 3
  • 25
  • 47
  • Yeah, I think this was suggested by the WP-CLI guy. Resulted in `Error: Invalid JSON:` with same output as before – Ethan C Nov 02 '15 at 14:50
  • @EthanC check out my edit above. The escaping with `escapeshellarg` (not `escapeshellcmd`) works correctly when given a minimal example. Which shell are you using? – Josh J Nov 02 '15 at 15:24
  • Git Bash. So I went in a directory, created `test.php` and `j.php` and dropped in the contents you've got here. My output was `NULL`? So I dumped out `$argv[1]` and saw the JSON, but with quotes stripped out: `string(129) "{ github_access_token : , bitbucket_username : username , bitbuck et_password : password , all-in-one-seo-populate-keywords : 1 }" ` I'm on a Windows machine, if that matters. – Ethan C Nov 02 '15 at 15:59
  • That is the problem then. Something with git bash and windows together. You may need to escape the double quotes into something like `\{\"arg\":\"value\"\}`. Try it in the standard windows `cmd.exe` and see if you have the same problem. – Josh J Nov 02 '15 at 16:05
  • Same in `cmd.exe`. A coworker on a Mac got the same result in `zsh`. Then he swapped the single-quotes in `test.php` for double-quotes and it worked, but that didn't solve anything for me in Bash nor `cmd` .Hrm. – Ethan C Nov 02 '15 at 16:16
  • A good way to figure out what your shell expects escaped is to try to `echo` some `json` data and add backslashes as needed until you get the right output: `~$ echo {"arg1": ""} {arg1: } ~$ echo {\"arg1\": ""} {"arg1": } ~$ echo {\"arg1\": \"\"} {"arg1": ""}` – Josh J Nov 02 '15 at 16:25
  • Seems to be a Windows/PHP issue - I can get it escaped properly with something like this and then no `escapeshellarg`: `"\"github_access_token\""=>"\"\"",`, but then on the Macintosh, it has too many quotes. I say Windows + PHP because I can take the original shell command, hard-coded, and run it in a `.sh` file and it's fine, but if I wrap that command in backticks and put it in a `.php` file, it strips the quotes. Something is automatically happening. – Ethan C Nov 02 '15 at 16:52
  • Erm. http://superuser.com/questions/238810/problem-with-quotes-around-file-names-in-windows-command-shell – Ethan C Nov 02 '15 at 16:57