I am migrating a set of php scripts from Window 2003 / PHP 5.2 to Windows 2012 R2 / PHP 5.6.7
In the scripts exec commands are used, for example to copy files. Commands could look like this:
exec ('copy "C:\ftp\suppliername\upload\*.*" c:\somefolder\ >> output.log');
You could argue that there are better ways to copy files, but I rather wouldn't like to rebuild these scripts right now.
The problem I have is that when there are no files to copy, the error "The system cannot find the file specified." is now shown, while this wan't the case on the old server.
If you just execute the copy command on the command line, the output looks like this:
The system cannot find the file specified.
0 file(s) copied.
This is the same as what gets written to output.log
So apparently the "0 file(s) copied" is getting suppressed somewhere, but not the error.
So my question is, how do I get rid of the error on the commandline? I thought it would be some configuration in php.ini, but after comparing the php.ini from the old and the new server, I couldn't find any essential differences.
I've tried a few things to suppress the error, but with no success:
Adding a # to the exec command
Adding ob_start() and ob_end_clean() before and after the command
Edit: please do not flag as a duplicate. I did see that question before asking my question. the answers given there do not solve my issue. The main question is, why was it working before, you would think that it should still be possible to get it working the same way without modifications to the scripts.
Try adding "2>&1" to your command.
exec ('copy "C:\ftp\suppliername\upload\*.*" c:\somefolder\ >> output.log 2>&1');
This should redirect the error output to output.log
I suppose that this string is being printed to stderr.
You could try to replace your STDERR as described in the post https://stackoverflow.com/a/3823015/146003.
The essential part of the post consists of the lines:
fclose(STDERR);
(...)
$STDERR = fopen('error.log', 'wb');
You can then get rid of error.log. Although I didn't try, you could try to open NIL (see https://stackoverflow.com/a/313115/146003)
First of all, you are redirecting the output of the copy command to a text file, so it will not be ouput to console.
Do this way instead:
exec ('copy "C:\ftp\suppliername\upload\*.*" c:\somefolder\', $output);
var_dump ($output);
Related
In Python, we can add the command line log to a file instead of the console using this command:
python script.py >> mylogfile.txt
How can I do it using PHP? I've tried
php script.php >> mylogfile.txt
but it doesn't work.
I use Windows 10.
I finally found the answer. It's based on the article PHP on the Command Line – Part 1 Article
I first used php script.php > mylog.txt which returns some of the log text to the console, so I thought it's not writing to the log, but it does. I wanted php script.php > mylog.txt 2>&1 which will add any log to the file.
The article says it doesn't work in Windows, but I use Windows 10 and it works.
The error messages are mixed with the normal output as before. But by
piping the output from the script, I can split the errors from the
normal output:
php outwitherrors.php 2> errors.log
This time, you’ll only see these messages:
Opening file foobar.log Job finished
But, if you look into the directory in which you ran the script, a new file called errors.log will have been created, containing the error
message. The number 2 is the command line handle used to identify
standard error. Note that 1 is handle for standard output, while 0 is the handle for standard error. Using the > symbol from the command line, you can direct output to a particular location.
Although this may not seem very exciting, it’s a very handy tool for
system administration. A simple application, running some script from
cron, would be the following:
php outwitherrors.php >> transaction.log 2>> errors.log
Using ‘>>‘, I tell the terminal to append new messages to the existing
log (rather than overwrite it). The normal operational messages are
now logged to file transaction.log, which I might peruse once a month, just to check that everything’s OK. Meanwhile, any errors that need a quicker response end up in file errors.log, which some other cron job might email me on a daily basis (or more frequently) as required.
There’s one difference between the Unix and Windows command lines,
when it comes to piping output, of which you should be aware. On Unix,
you can merge the standard output and standard error streams to a single destination,
for example:
php outwitherrors.php > everything.log 2>&1
It reroutes standard error to standard output, meaning that both get
written to log file everything.log.
I have tried to use exec() with 'whoami' to check if it works and I got the result of
nt authority\system
Now I need to run a .exe file with parameters from php via exec() function.
I tried this in command prompt and it actually runs the program with given parameters. This is the example command.
NOTE the exe file gets 3 inputs (folder, file_name, report_file_nmae)
> ..\..\some_file.exe folder="C:\path_to_folder" param=1.xml report=2.xml
But when I run this command from php file:
exec('..\..\some_file.exe folder="C:\path_to_folder" param=1.xml report=2.xml');
nothing is happening. This is the first time I am using exec() function, so I am not familiar with its details. What is wrong?
I tried using:
\\ instead of \
escapeshellarg() on the directory
added "" around directory folder names
No luck
Addendum:
echo exec($command) // echos < .... why?
or
exec($command, $output);
print_r($output); // Array()
I even changed the permission on the file to full control to all users.
If I call the program from command prompt, I can see the icon appearing next to clock for a second.
But the same call from php will not even call the program.
Edit
Even exec('notepad.exe'); is not working. Something has to be done with php configurations maybe?
I already said that I was new to exec() function. After doing some more digging, I came upon 2>&1 which needs to be added at the end of command in exec().
Thanks #mattosmat for pointing it out in the comments too. I did not try this at once because you said it is a Linux command, I am on Windows.
So, what I have discovered, the command is actually executing in the back-end. That is why I could not see it actually running, which I was expecting to happen.
For all of you, who had similar problem, my advise is to use that command. It will point out all the errors and also tell you info/details about execution.
exec('some_command 2>&1', $output);
print_r($output); // to see the response to your command
Thanks for all the help guys, I appreciate it ;)
You might also try giving the full path to the binary you're trying to run. That solved my problem when trying to use ImageMagick.
I have a question regarding running a shell command via PHP. My goal is to successfully run compass compile [project] via PHP. I have tried the following:
echo system('compass compile [project]', $s); // prints [31m[0m
echo $s; // prints 1
echo passthru('compass compile [project]', $p); // prints [31m[0m
echo $p; // prints 1
echo shell_exec('compass compile [project]'); // prints [31m[0m
echo exec('compass compile [project]', $e, $ee);
print_r($e); // Array ( [0] => [31m[0m )
echo $ee; // prints 1
I even tried running a shell command to an executable file that contained compass compile test and I still got the same results as the trials above.
My questions
What does [31m[0m mean? Does this represent binary data? Do these represent bash colors as search engines suggest?
As far as I know, the output should be the following:
For kicks, I tried to execute via system(/usr/local/bin/compass compile [project]); and I got the same result. I double checked my path so I know I can execute these commands as expected. Here is the output from echo $PATH:
/usr/lib/lightdm/lightdm:
/usr/local/sbin:
/usr/local/bin:
/usr/sbin:
/usr/bin:
/sbin:/bin:
/usr/games:
/usr/local/games:
/var/lib/gems/1.9.1/bin
Is there a way to compile compass projects using PHP?
I've seen a similar error before.
Typically it is due to the things being output in the bash startup scripts. For example, I had an echo in one of my bash startups that jacked up a lot of scripts till I realized what was causing the problem.
Or, perhaps the user (www-data ?) doesn't actually have a home dir and appropriate startup scripts in place?
You can try this to get a non interactive shell:
exec("/bin/bash -c \"compass compile [project]\"", $e, $ee);
print_r($e);
echo $ee;
If you still have issues, try redirecting the output to a tmp file, an checking it:
exec("/bin/bash -c \"compass compile [project] > /tmp/compass.compile.output\"", $e, $ee);
print_r($e);
echo $ee;
See also: What's the difference between .bashrc, .bash_profile, and .environment?
The issue was fixed by using sass --compass and redirecting the stderr to stdout via echo shell_exec("sass --compass [project] 2>&1");
It was a pretty long and arduous process figuring this out since it's been awhile since I've dabbled in command line programs. Remember that error streams and output streams might be on different outputs. The easiest way to test this is to shovel the output into a file via:
# do this once with a good file and once with a file that will give errors
sass --poll style.scss > output.txt
If output.txt is empty then the error output is on the stderr stream such as the case above. We can correct this by redirecting the stderr to the srdout. For example:
sass --poll > output.txt 2>&1
#shows results
cat output.txt
I created a simple PHP script that redirects the output from one textarea to the other. The code can be found here.
First guess would be a permissions issue. Odds are the user account running PHP (unless you're running this from the command line, I'm guessing that this is the user that the httpd apache daemon is running under) doesn't have the permissions to do what you're asking. The errors are extremely unhelpful, however.
From what I can tell, it looks like an attempt to have the error show up in red on the command line. My guess is that there are hidden (or somehow never printed out) characters in-between the codes. Check out some of your apache and/or PHP error logs to see if anything helpful is showing up there that never made it into the PHP variable. Or, for kicks, try copy and pasting the output with the bash colors into a basic text editor and first delete each character from the beginning one by one... see if anything magically appears. If that doesn't work, try the same in reverse, backspacing from the end. Either way, there's an error occurring, so important that it must show in bold red letters to you, it's just not getting to you.
If it does in fact turn out to be a permissions issue, and it's one you can't remedy through permissions wrangling, you could create an intermediary file that your Apache user has permissions to write to, and your cron user has permissions to read from. Instead of running the code directly from PHP, put it in the file, then run a cron on a frequent basis looking for anything in that file, CHECKING IT FOR VALIDITY, and then running it through the compiler and removing it from the file.
It'd be ugly, but sometimes pretty things don't work.
You guessed it right it is colors but the way it is defined is not right. For more information regarding using colors in console please refer to this document. Also, for compiling SCSS via compass you can use shell_exec command in linux. For more information regarding shell_exec please refer to this document. Let us know how it goes.
In a previous post, I was trying to update the encoding for a download file from php. One of the suggestions was to run the unix2dos command before sending the file to the user. This works great when I run the command on the linux box, but when I try and run the command from php I get nothing. Here is what I tried:
$cmd = "unix2dos -n $fullPath $downloadFile";
echo exec($cmd, $out, $retVal);
This displays nothing to the screen, $retVal is 0, and $out is an empty string.
echo system($cmd, $retVal);
This displays nothing to the screen, $retVal is 0.
echo shell_exec($cmd);
This displays nothing to the screen.
I have also tried escaping the command and it parameters like:
$cmd = escapeshellcmd($cmd);
and
$cmd = "unix2dos ". escapeshellarg("-n \"$fullPath\" \"$downloadFile\"");
Please let me know if you see something that I am doing wrong.
Thanks!
Edit: Here is some info that may be helpful.
unix2dos version: 2.2 (1995.03.31)
php version 5.2.9
Running in apache 2 on in Redhat Enterprise Linux 4
Have you considered a pure PHP solution?
<?php
$unixfile = file_get_content('/location/of/file/');
$dosfile= str_replace("\n", "\r\n", $unixfile );
file_put_contents('/location/of/file/', $dosfile);
?>
Something like that should do it, although untested :)
Shadi
See which user the PHP exec command is running as:
<?php system('whoami'); ?>
If this command fails then you likely do not have permission to use exec() or system(), so check your INI files. But be sure to check the correct ones! On Debian systems there are separate Apache and CLI INI files stored at /etc/php5/apache/php.ini and /etc/php5/cli/php.ini respectively. Sorry I do not know the locations for RedHat.
If the whoami command succeeds, make sure that the unix2dos command can be run by the user that is shown, and that the same user is allowed to make changes to the files in question by using chmod or chown.
Are you using the full path to unix2dos? Perhaps the executable is in your path for your shell but not in the path that PHP is using.
My implementation of unix2dos produces no output. If the return value is 0 then the command succeeded and your file has been updated.
The only other thing I see is the -n option which my version doesn't seem to have. You should probably check your man page to see what options it supports
unix2dos does not display the file it converts. Therefor you must display it yourself. A very basic way to do it could be :
$cmd = "unix2dos -n $fullPath $downloadFile";
echo exec($cmd, $out, $retVal);
include "$fullPath."/".$downloadFile;
Using include is pretty dirty but quick and easy. A cleaner way would be to use fopen and read the file then display it.
You'd better create a function that enclose all the operation : conversion + display so you'll have everything at hands.
But, If I were you, I'd prefer to not use exec at all and use FileIterator with a trim on every line so you will not have to care about the carriage return nor deal with a hazardous shell binding.
Not sure about your exact problem, but debugging suggestion:
Try first setting $cmd to ls. See if that works. Then try using /bin/ls (use the full path.)
If those don't work, then there might be a problem with your PHP configuration - there might be a safemode parameter or something which disallows the use of exec(), shell_exec(), or system() functions.
I got the source code from here.
http://www.sfr-fresh.com/linux/misc/unix2dos-2.2.src.tar.gz
I compiled it and then ran the tool. This was my output:
rascher#danish:~/unix2dos$ ./a.out -n 1.txt 2.txt
unix2dos: converting file 1.txt to file 2.txt in DOS format ...
I think the problem is this: the program writes all of its output to stderr, rather than stdout. If you look at the source code, you can see "fprintf(stderr, ...)"
As far as I know, PHP will only read the part of your program's output that is sent to STDOUT. So to overcome this, it seems like you have to redirect the output of your program (unix2dos uses stderr) to stdout. To do this, try something like:
$cmd = "unix2dos -n $fullPath $downloadFile 2>&1"
The "2>" means "redirect stderr" and "&1" means "to stdout".
In either case, I would imagine that the file was converting properly, but since you weren't getting any of the expected output, you thought it was failing. Before making the change, check on the output file to see if it is in DOS or UNIX format.
This is driving me crazy. I'm trying to execute a command line statement on a windows box for my PHP web app. It's running on windows XP, IIS5.1. The web app is running fine, but I cannot get #exec() to work with a specific contactenated variable. My command construction looks like this:
$cmd = ($config->svn." cat ".$this->repConfig->svnParams().quote($path).' -r '.$rev.' > '.quote($filename));
This command does not work as is above, when it generates the following string:
svn --non-interactive --config-dir /tmp cat "file:///c:/temp/test/acccount/dbo_sproctest.sql" -r 1 > "C:\Inetpub\sites\websvn\temp\wsv5B45.tmp"
If I copy/paste this to my own command line, it works fine.
If I hard code that very same path instead of adding it with the variable, it works! I've tried with and without quotes around the file name. I've tried with and without quotes around the entire command. I've tried other directories. I've tried passing an output paramter to exec(), and it comes back empty (Array () ). I've tried redirecting the output of the error stream of the command to a file, and that error output file never gets created.
The only thing I can possibly concieve of is that exec() is failing silently. What on earth am I doing wrong here? If I hard code the file path, using the same dir structure and filename, it works fine. If I don't, it doesn't.
Maybe the slashes () in the file path aren't being escaped properly, but when I do it manually with single quotes they are not considered escape sequences??
UPDATE:
I took the # off of exec, and still not seeing any errors.
I gave the full path to SVN, still no luck. It should be noted that the command worked fine before with the non-full path SVN so long as I manually specify the file destination for cat.
Update 2: RE: Kieth
I'm calling exec by trying both:
exec($cmd);
or
exec($cmd, $out);
My php.ini already had safe_mode = 0.
I added error_reporting(E_ALL); and didn't see anything new
If I echo (or print_r) my exec call, I am not actually seing anything
If I echo (or print_r) my exec call when included an output var, I get an empty arr
Update 3
I tried both escapeshellcmd and escapeshellarg to no avail (good idea though).
I should add that the file is being created through invoking
tempnam("temp", "wbsn");
The fact that it works just fine if I manually specify the string instead of letting it be generated by tempname seems to suggests that the source of the problem, but I can't figure out how. I did a comparison of the manual string with the one generated, and it came back as a match.
#exec will always fail silently, because # is PHP's error suppression operator.
Not sure if this will help you since you're on Windows and I'm on Linux, but I ran into this same problem of silent errors from PHP exec(). I figured out that the command I was attempting to issue (nconvert) sends its error messages to the standard error stream, not standard out. So I added
2>&1
at the end of the command line to redirect my error back to the standard stream. Then I could see that nconvert was giving me a permission denied error.
It could be that the PATH isn't the same from your php script vs your user account. Try removing the # and see if it's trying to throw an error.
In addition, you may want to try putting the full filesystem path to the SVN executable.
Well, if removing # isn't working, try including this at the start of the piece of code you're running:
error_reporting(E_ALL);
That'll turn on full error reporting, just in case you have it turned down or disabled in your php.ini file.
I don't suppose you could show us how exactly you're calling exec()? Could you also check to make sure you're not accidentally running the script in safe mode? Are you echoing out what exec() is returning, and if so, what is it returning?
I'm not a big fan of adding another response, but if I just edit my previous response, you may not see it.
PHP has some special escaping commands for shell scripts: escapeshellcmd and escapeshellarg.
I think you should be able to use escapeshellcmd around your entire $cmd, but I'm not sure.
Have you tried echo exec("dir") or something simple to see if exec() is working at all?
I don't know what going on, but I at least have a workaround.
This works:
$tmp = tempnam("./", "wbsn");
$filename = dirname($tmp).'\\temp\\'.basename($tmp);
This, however, does not, but I would have expected it to generate the same path (diff file name since it's a new tempnam()).
$tmp = tempnam("temp", "wbsn");
Also, this does not work, which I also would expect to generate the same thing:
$tmp = tempnam("temp", "wbsn");
$filename = dirname($tmp).'\\'.basename($tmp);
All 3 of these solutions appear to generate the same file paths, but only the first one actually works when used in my exec. I have no clue why it does not.
Visual inspection (echo) of all 3 of these appear to generate the same paths (with the exception of filenames differing, of course). A string comparison of dirname() of each of these 3 shows as a match. I have no clue what the deal is, but the first one is a workaround.
A very useful trick when debugging shell exec problems is to place an "echo" at the beginning of the command. Make sure that you can view the standard output somewhere.
This will let you examine the command for any obvious problems. Perhaps it has a wildcard that is expanding unexpectedly, or perhaps the shell quoting is not exactly right. The echo will let you see this, and you can cut and paste the echoed command into another shell to see if it is working properly.
My advice will be to switch from WIN, IIS to linux, but as alternative you can try this:
function exec_alt($cmd) {
exec($cmd, $output);
if (!$output) {
/**
* FIXME: for some reason exec() returns empty output array #mine,'s machine.
* Somehow proc_open() approach (below) works, but doesn't work at
* test machines - same empty output with both pipes and temporary
* files (not we bypass shell wrapper). So use it as a fallback.
*/
$output = array();
$handle = proc_open($cmd, array(1 => array('pipe', 'w')), $pipes, null, null, array('bypass_shell' => true));
if (is_resource($handle)) {
$output = explode("\n", stream_get_contents($pipes[1]));
fclose($pipes[1]);
proc_close($handle);
}
}
return $output; }