b. e. hollenbeck
b. e. hollenbeck

Reputation: 6573

PHP exec() and spaces in paths

I'm executing the following in a PHP application:

  $source = '/home/user/file.ext';
  $output_dir = $this->setOutputString();

  chdir('/home/ben/xc/phplib/bgwatcher-2011a/a01/');
  exec('php bin/createjob.php $source $output_dir', $output);

  return $output[0];

The problem is this: I have control over $source, but not $output_dir, which is a legacy Windows filesystem, and there are spaces in the path. An example $output_dir is:

/home/vol1/district id/store id/this_is_the_file.html

When inserting the output string into the exec() function, I have tried both:

addslashes($output_dir) and '"' . $output_dir . '"' to escape the entire output string. In the first case, the path gets concatenated to:

/home/vol1/districtthis_is_the_file.html

... where everything between the first space and the filename gets dropped. In the second case, exec() appears to throw a shoe and doesn't execute properly - unfortunately, the error message is getting lost in the machinery - I can provide it if it's absolutely necessary, but I'm also under time constraints to find a solution.

What's the solution, here? Do I sprintf() the entire string for exec()? I'm very confused as to why addslashes isn't working correctly to escape the spaces, and I assume it has something to do with sanitization with exec(), but I can't find any documentation to back it up.

Update: I've tried escapeshellarg() and preg_replace() without success. Thinking about this further, do I need to double-escape the path? Or escape the path and the command? If the path is being unescaped once by exec(), and once by PHP before it executes the command, does it stand to reason that I need to account for both escapes? Or is that not how it works?

Upvotes: 16

Views: 27243

Answers (7)

astrosixer
astrosixer

Reputation: 121

You can use double quotes and escape character together to work out this.

$fileName = "filename with spaces.pdf";
exec("php bin/createjob.php >\"".$fileName."\" 2> error.log" , $output, $return);

Upvotes: 0

Goce Ribeski
Goce Ribeski

Reputation: 1372

this works for me when using exec() with soffice(LibreOffice):

$file_name = "Some, file name.xlsx";
exec('/usr/bin/soffice --headless --convert-to pdf '."'".$file_name."'".' 2>&1', $output, $r);

Upvotes: 0

Bojangles
Bojangles

Reputation: 101533

From the PHP doc (here),

Returns a string with backslashes before characters that need to be quoted in database queries etc. These characters are single quote ('), double quote ("), backslash () and NUL (the NULL byte).

This won't do anything to the spaces. What you will need to do is use str_replace() to add slashes, like this:

$new_string = str_replace(" ", "\\ ", $old_string);

Upvotes: 10

Demian Brecht
Demian Brecht

Reputation: 21378

According to the PHP docs,

Returns a string with backslashes before characters that need to be quoted in database queries etc. These characters are single quote ('), double quote ("), backslash () and NUL (the NULL byte).

Looks like you'll have to preg_replace the spaces yourself.

Edit:

Even though this is the topic of another discussion, if performance is an issue, then after looking into it a little more, it seems that str_replace is actually quite a bit faster than preg_replace:

The test labeled "str_replace()" was the faster by 0.9053 seconds (it took 10.3% the time.)

The first test took 1.0093 seconds. (preg_replace)

The second test took 0.104 seconds. (str_replace)

Benchmark found here.

Upvotes: 7

mario
mario

Reputation: 145512

You can very well use shell quotes, since that is what all exec commands run through:

exec("php bin/createjob.php '$source' '$output_dir'", $output);

It btw works not just for arguments, but also for the command itself:

exec('"/bin/echo" "one parameter"');

Use escapeshellcmd() anyway.

Upvotes: 3

Kromey
Kromey

Reputation: 1212

I've used exec() with paths with spaces before, on both Windows and Linux hosts, and in both cases quoting the path worked perfectly for me.

That said, if you have no control over the safety of a shell argument, always run it through escapeshellarg() first!

Upvotes: 5

Michael Berkowski
Michael Berkowski

Reputation: 270727

I don't believe addslashes() does anything with spaces. escapeshellarg() might be what you want instead. Docs on escapeshellarg

Upvotes: 12

Related Questions