PHP and shell_exec return value

All,

I'm 100% certain that the following code should return an error, however $res appears to be null.

$res = shell_exec($this->cmd);

According to php.net documentation, the return value is the result of the command and should appear in $res.  $this->cmd looks like the following:

          $this->cmd = "mysqldump -Q -u $this->dbUser -p$this->dbPass $this->dbName";
            
          $this->cmd .= ($this->zip==="bz2") ?
                  " | bzip2 > $this->dest". '/' ."$fname"  :
                  " | gzip > $this->dest".'/'."$fname";

Thanks for any ideas... this should only not come back with any results for a successful dump.
LVL 3
stevefNYCAsked:
Who is Participating?
 
tkalchevConnect With a Mentor Commented:
Adding  "2>&1" at the end of the command should show you the actual error.  Your problem here is that you are using a complex command, which uses pipes and redirects the output to a file. Actually you are executing 2 commands, first is

mysqldump -Q -uUSERNAME -pPASSWORD DATABASENAME

second is

gzip > FILENAME  (I will assume that you use GZIP to simplify the explanation )


When you pipe the commands as you did the complete output from the first command is sent to the STDIN of the second one.
When you add 2>&1 at the end of the command line you get the following :

mysqldump -Q -uUSERNAME -pPASSWORD DATABASENAME | gzip > FILENAME 2>&1

the following is happened :
1. The first command is executed
2. The contents of everything printed on the 1st's command STDOUT is send to the STDIN of the second command
3. If something (the error message in your case) is sent to the STDERR, it is displayed on the system's STDERR and won't be catched by your shell_exec, as it catches only STDOUT
4. The STDOUT of the second command is redirected to FILENAME
5. The STDERR of the second command is redirected to its STDOUT

This situation won't help you, because you need the STDERR of the first command, not the senond's
So, let's modify it a little bit :

mysqldump -Q -uUSERNAME -pPASSWORD DATABASENAME 2>&1 | gzip > FILENAME

what is changed here :

1. The first command is executed
2. The contents of everything printed on the 1st's command STDOUT is send to the STDIN of the second command
3. If something (the error message in your case) is sent to the STDERR, it is also redirected to the STDOUT, actually to the second command's STDIN
4. The STDOUT of the second command is redirected to FILENAME

Now you have the error message gzipped in the FILENAME, you can check it if you run  zcat FILENAME ... Also not exactly what you have expected.

One possible solution for your case is to play a little bit with the I/O redirection, you can for example issue a command line like this :

exec 6>&1 2>&1 1>/tmp/output; mysqldump  -uUSER -pPASSWORD DATABASENAME ; exec 1>&6 6>&-; if [ -s /tmp/output ]; then cat /tmp/output | gzip > FILENAME; rm -f /tmp/output; fi

What it does :

1. exec 6>&1 2>&1 1>/tmp/output : redirects the STDERR to STDOUT and then STDOUT to a file /tmp/output
2. mysqldump  -uUSER -pPASSWORD DATABASENAME  : it just runs your 1st command
3. exec 1>&6 6>&-   : restores the STDOUT and closes descriptor 6
4. if [ -s /tmp/output ]; then cat /tmp/output | gzip > FILENAME; rm -f /tmp/output; fi   : if the file /tmp/output exists and is not empty it is being gzipped to a file FILENAME and then deleted


Hope it will help you
0
 
nizsmoDeveloperCommented:
hi steve,

try and print out $this->cmd and is it the command you are expecting? when you actually use shell to execute the command does it return anything?
0
 
Terry WoodsIT GuruCommented:
Don't you just want two equal signs for this command, rather than 3?:
($this->zip==="bz2")
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
stevefNYCAuthor Commented:
Hey nizsmo,

Yes I've tried that.  I copy/pasted the command from my debug console where I spit it out to make sure the syntax is right... I should be getting an error back:

sf:tmp sf$ mysqldump -Q -u root -pthisisnotmypass foobar | bzip2 > /tmp/builder/foobar.sql.bz2
-bash: /tmp/builder/foobar sql.bz2: No such file or directory
mysqldump: Got error: 2002: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) when trying to connect

I'm intentionally creating that error on the server-side... I just want the return value to pick it up... (just giving a heads up for those who come into this thread and try to start fixing my mysqldump error... it's intentional.)
0
 
Terry WoodsIT GuruCommented:
I suspect also that:
                  " | bzip2 > $this->dest". '/' ."$fname"  :
                  " | gzip > $this->dest".'/'."$fname";

may need curly brackets added, like this:
                  " | bzip2 > {$this->dest}". '/' ."$fname"  :
                  " | gzip > {$this->dest}".'/'."$fname";

though I'm not 100% sure
0
 
stevefNYCAuthor Commented:
TerryAtOpus,

The identity operator works fine in this scenario. I'm making sure that the type in this case matches as well.
0
 
nizsmoDeveloperCommented:
how about simplifying the command and trying it? its not hard to produce an error :)
as you can see here:
http://www.php.net/shell_exec

the return value is indeed the return message, maybe give the example on that webpage a try?
0
 
stevefNYCAuthor Commented:
Works fine when I try the 'ls -ltr' example. Still not returning anything for my mysqldump invocation though
0
 
nizsmoDeveloperCommented:
oh? maybe then it will only capture successful command outputs and not error outputs? just a thought.
0
 
stevefNYCAuthor Commented:
Well, according to php.net the following reads in a user comment:

``ALSO, note that shell_exec() does not grab STDERR, so use "2>&1" to redirect it to STDOUT and catch it.''

I've modified my code to read           

$this->cmd .= ($this->zip==="bz2") ?
                  " | bzip2 > $this->dest". '/' ."$fname 2>&1"  :
                  " | gzip > $this->dest".'/'."$fname 2>&1";

Still no go though.

0
 
Terry WoodsIT GuruCommented:
The following worked for me:
  $cmd = "mjysqldump -Q -u 2>&1";
  $result = shell_exec($cmd);
  echo "Result: '$result'";

Outputs:
Result: 'sh: line 1: mjysqldump: command not found '
0
 
Terry WoodsIT GuruCommented:
Not sure how likely it is that you're running a different shell from what's normal, but different shells use different syntax to redirect the STDERR. How about trying copying and pasting my example, and see what you get?
0
 
stevefNYCAuthor Commented:
I'm just using good ol' bash, Terry.

foo:~ sf$ echo $SHELL
/bin/bash
foo:~ sf$ bash --version
GNU bash, version 3.2.17(1)-release (i386-apple-darwin9.0)
Copyright (C) 2005 Free Software Foundation, Inc.
0
 
stevefNYCAuthor Commented:
Beautiful and concise answer. Thank you kindly.  

Until you responded, I just ended up splitting the commands into two, avoiding any file redirection...
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.