www.webdeveloper.com
Results 1 to 15 of 19

Thread: output shell script output via php and web browser - HELP!

Hybrid View

  1. #1
    Join Date
    Aug 2006
    Location
    Michigan
    Posts
    1,046

    output shell script output via php and web browser - HELP!

    Hello Gurus,

    How could I output the shell scripted output with PHP to a web browser?

    The script runs for 2 minutes and prints out several lines during the execution of the script on the command line.

    Need a way to run this with PHP and print the output of the shell script as the script executes instead of all at once when the script has completed execution.

  2. #2
    Join Date
    Mar 2007
    Location
    Las Vegas, NV
    Posts
    45
    I think there might be severeal ways to do this:

    http://us.php.net/manual/en/function.escapeshellcmd.php

    Barrie
    Debian lenny

  3. #3
    Join Date
    Aug 2006
    Location
    Michigan
    Posts
    1,046
    Thanks, I have looked at all the docs for this type of Shell Command Execution. but they all behave the same. first they execute the program then display the output to the screen.

    I'm looking to display the output to the screen as the script executes.

    For example:

    I have a shell test script that I can run on the command line. first it will print the word "Hello", then wait 5 seconds and then print the word "Goodbye".

    // test.sh
    Code:
    echo "hello";
    sleep 5;
    echo "goodbye";
    now using some of the PHP commands like exec() (and others) the script will execute and then display both hello and goodbye with no 5 second pause between the two

    PHP Code:
    $output exec('test.sh');
    echo 
    $output
    is there a way to use PHP to display the output as the shell script is executing?

    so it should display "Hello" first then pause for five seconds and print "Goodbye", NOT execute for 5 seconds and display "Hello Goodbye".

    Is this example clear?

  4. #4
    Join Date
    Aug 2006
    Location
    Michigan
    Posts
    1,046
    Still looking for some help with this, anyone?

  5. #5
    Join Date
    Aug 2004
    Location
    Ankh-Morpork
    Posts
    19,175
    You might be able to do it via AJAX.

    1. Main PHP script uses exec() or whatever to launch shell script as a background process with all output redirected to a file.

    2. JavaScript uses timer loop to call another PHP script that will read the file receiving the shell script's output, and returns it to the page where the JS can display it.
    "Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be."
    ~ Terry Pratchett in Nation

    eBookworm.us

  6. #6
    Join Date
    Mar 2009
    Posts
    4

    not working in browser

    I've tried the shell script code which mentioned in the above , I'm able to run the code in the command line . But in the browser its not displaying anything.Please tell me what may be the problem in executing the shell script via php in the browser.

    Thanks in advance

  7. #7
    Join Date
    Mar 2009
    Posts
    4

    not working in browser when try to open an application like firefox ,gvim etc.,

    In my previous comment i've mentioned that the shell script not executing in the browser via php. But when i'm trying to echo , its working . But when i try to open an application eg. firefox,gvim ,text editor , for some applications its returning the error . for some its displaying a white screen.

    if any one knows the answer, Please help me with some examples.

    Actually my requirement is to open a dreamweaver application thru php. My Server is running in gentoo linux and i've to open the dreamweaver in the windows machine which i'll access thru the rdesktop. If anyone knows the solution , please let me know.
    Last edited by ruby christina; 03-02-2009 at 07:47 AM.

  8. #8
    Join Date
    Aug 2006
    Location
    Michigan
    Posts
    1,046
    This could be a permissions issue with the launching of the programs. as the user that is running the script via web page is usually nobody or apache with limited permissions.

  9. #9
    Join Date
    Mar 2009
    Posts
    4

    getting error

    I've tried the above by changing the user and set full permissions to the user, still i'm getting a blank screen for opening the firefox and for opening gvim in linux the following error i'm getting

    Vim: Error reading input, exiting... Vim: Finished. [?25l[?12l[?25h

    this is my php code
    $output1 = shell_exec('chown ruby batcall.php startapp.sh');
    $output2 = shell_exec('chmod 755 batcall.php startapp.sh');
    //$output2 = shell_exec('ps aux | grep httpd');
    $output4 = shell_exec('sh startapp.sh');
    echo $output;

    startapp.sh
    gvim

    Please tell me what is the solution for this

  10. #10
    Join Date
    Sep 2006
    Location
    Bucharest, RO
    Posts
    940
    ruby_christina: are you trying to open firefox on the server FROM the client? I think you are misunderstanding a few basic client-server issues. If you are simply running "firefox" using exec() or shell_exec() or any similar function in PHP and YOU are browsing from another PC, this will make the SERVER (not your desktop PC) try to open up firefox and, of course, you won't see anything on your PC (you can't run GNOME applications through HTTP :\). Also, the application won't even start work on your server because Apache is running in a different session (disregarding the user) which isn't connected to the XOrg server (the display server) so it can't run visual applications.

    On to Phill's problem. Well, it's a tricky one. I don't think any Ajax solution will work (there's still going to be a PHP script that will write to that file after 5 minutes). As I see it, you have two options:
    1) You create another user session and you get file pointers to its stdout, stdin and stderr and read / write from / to those in an unblocking way. But don't ask me how to do this
    2) You launch the command with an ampersand and you make it dump output to a file. Then you read the file. But, you're going to make a workaround in order to find out when the command has finished executing. For this, you can create a helper script that will output something when the big command finishes. Here's how I've done it:
    Code:
    # helper.sh
    ping -c 4 google.com
    echo "FINISHED"
    PHP Code:
    <?php
    // text/plain so we don't have any html weirdness + new lines are handled right
    header("Content-Type: text/plain");
    // make sure we output everything as soon as it comes in
    ob_implicit_flush(true);
    // run the command
    `./helper.sh > /var/www/work/test/tmp.txt &`;
    $fp fopen("tmp.txt"'r');
    if (!
    $fp) exit;
    // this is the string on which the command will be considered to have finished
    $magic_str "FINISHED";
    $full_str '';
    while ( 
    trim(substr($full_str, -strlen($magic_str)-1)) != $magic_str ) {
       
    $buf fread($fp1024);
       echo 
    $buf;
       
    $full_str .= $buf;
    }
    fclose($fp);
    ?>
    This works (tested), here are a few things to note:
    1) tmp.txt must exist and be readable/writable by Apache. It must exist because otherwise the file might not be yet created when PHP tries to fopen() it which will lead to an error.
    2) helper.sh must be executable (man that slowed me down a bit) by Apache.
    3) Lots of things can go wrong with this. Make sure you don't use it with just any command (you can create your own helper.sh through PHP then run it, if you want to run different commands using the same logic).
    4) Have fun
    Last edited by Znupi; 03-04-2009 at 10:00 AM.

  11. #11
    Join Date
    May 2009
    Posts
    3
    Hey guys, I've wanted to do this in the past but my will power gave out. But this time I was more persistent.

    I tried using the code Znupi posted but I couldn't get it to work.

    However, I went back to php.net and really read over the different manual pages on the system(), passthru(), exec(), shell_exec() functions and backticks operator.

    There is a BIG difference between using the system() or passthru() functions from using any of the others.

    This difference is how the output buffers of the command execution are handled.

    In system() and passthru(), PHP will attempt to flush the buffers after *every* line of output.

    This means that this code:

    PHP Code:
    system("echo \"Starting...\"
    sleep 2
    echo \"Done.\""
    ); 
    will be treated just like this code written in only PHP:

    PHP Code:
    echo "Starting...";
    sleep(2);
    echo 
    "Done."

    As long as you are not using output buffering on your page (ob_start()) then the effect will be exactly what you are looking for since the buffers will be flushed to the browser after each line of command output.

    But of course there is a caveat!

    It doesn't work with executing custom shell scripts! (well - not without a small workaround)

    The workaround is really simple though. Just use file_get_contents("myscript.sh") to turn the shell script contents into a command string. Insert that command string into your system() command and voila! The output buffers are flushed as expected.

    NOTE: One thing I did *not* test was the effect of this process on the working directory for the execution of the shell script commands. However, if your shell script relies on a particular working directory then make sure that the working directory is either set inside the shell script itself or that you do a "cd /custom/dir/here" (change directory) command just prior to where you insert the shell script command string.

    Example: (two files: test.php and test.sh)

    test.php
    PHP Code:
    <?php

    $tmp_file 
    dirname(__FILE__)."/tmp.txt";
    if(!
    is_file($tmp_file)) {
        
    $fp fopen($tmp_file"w+");
        if(
    $fp) {
            
    fclose($fp);
        }
    }
    echo 
    "<pre>";
    $test_script file_get_contents("test.sh");
    system("echo \"Starting...\"
    sleep 2
    echo \"Doing more...\"
    "
    .$test_script."
    echo \"Done.\""
    );
    echo 
    "</pre>";
    test.sh
    Code:
    echo "Running test..."
    
    sleep 1
    
    echo "Almost done..."
    
    sleep 1
    
    echo "Test complete."

    And for those of you (like me) who are using output buffering on the entire page for whatever reason (templates, caching, error handling) - there is still a little more hacking to do. As long as your output is (X)HTML then the following solution will work for fully output buffered pages (ob_start()).

    Separate your system() and passthru() calls into a plain PHP file that just outputs plain text: (obviously make sure that you force some sort of user authentication prior to actually running the commands.php script!)

    commands.php
    PHP Code:
    <?php
    header
    ("Content-type: text/plain");

    $script file_get_contents("script.sh");
    system($script);
    then output HTML containing an iFrame:

    dostuff.htm
    Code:
    <html>
    <head>
    </head>
    <body>
    <iframe src="commands.php" scrolling="auto"></iframe>
    </body>
    </html>
    Good luck!


    ----------------
    michael--at--getsprink--dot--com
    http://getsprink.com/
    http://phpjs.org/
    Last edited by mongoose643; 05-07-2009 at 01:00 AM.

  12. #12
    Join Date
    Aug 2013
    Posts
    1

    Smile thank you

    It worked like a dream !!! Thanks
    Quote Originally Posted by mongoose643 View Post
    hey guys, i've wanted to do this in the past but my will power gave out. But this time i was more persistent.

    I tried using the code znupi posted but i couldn't get it to work.

    However, i went back to php.net and really read over the different manual pages on the system(), passthru(), exec(), shell_exec() functions and backticks operator.

    There is a big difference between using the system() or passthru() functions from using any of the others.

    This difference is how the output buffers of the command execution are handled.

    In system() and passthru(), php will attempt to flush the buffers after *every* line of output.

    This means that this code:

    PHP Code:
    system("echo \"starting...\"
    sleep 2
    echo \"done.\""
    ); 
    will be treated just like this code written in only php:

    PHP Code:
    echo "starting...";
    sleep(2);
    echo 
    "done."

    as long as you are not using output buffering on your page (ob_start()) then the effect will be exactly what you are looking for since the buffers will be flushed to the browser after each line of command output.

    But of course there is a caveat!

    It doesn't work with executing custom shell scripts! (well - not without a small workaround)

    the workaround is really simple though. Just use file_get_contents("myscript.sh") to turn the shell script contents into a command string. Insert that command string into your system() command and voila! The output buffers are flushed as expected.

    Note: One thing i did *not* test was the effect of this process on the working directory for the execution of the shell script commands. However, if your shell script relies on a particular working directory then make sure that the working directory is either set inside the shell script itself or that you do a "cd /custom/dir/here" (change directory) command just prior to where you insert the shell script command string.

    Example: (two files: Test.php and test.sh)

    test.php
    PHP Code:
    <?php

    $tmp_file 
    dirname(__file__)."/tmp.txt";
    if(!
    is_file($tmp_file)) {
        
    $fp fopen($tmp_file"w+");
        if(
    $fp) {
            
    fclose($fp);
        }
    }
    echo 
    "<pre>";
    $test_script file_get_contents("test.sh");
    system("echo \"starting...\"
    sleep 2
    echo \"doing more...\"
    "
    .$test_script."
    echo \"done.\""
    );
    echo 
    "</pre>";
    test.sh
    Code:
    echo "running test..."
    
    sleep 1
    
    echo "almost done..."
    
    sleep 1
    
    echo "test complete."

    and for those of you (like me) who are using output buffering on the entire page for whatever reason (templates, caching, error handling) - there is still a little more hacking to do. As long as your output is (x)html then the following solution will work for fully output buffered pages (ob_start()).

    Separate your system() and passthru() calls into a plain php file that just outputs plain text: (obviously make sure that you force some sort of user authentication prior to actually running the commands.php script!)

    commands.php
    PHP Code:
    <?php
    header
    ("content-type: Text/plain");

    $script file_get_contents("script.sh");
    system($script);
    then output html containing an iframe:

    Dostuff.htm
    Code:
    <html>
    <head>
    </head>
    <body>
    <iframe src="commands.php" scrolling="auto"></iframe>
    </body>
    </html>
    good luck!


    ----------------
    michael--at--getsprink--dot--com
    http://getsprink.com/
    http://phpjs.org/

  13. #13
    Join Date
    May 2009
    Posts
    3

    Talking You're welcome!

    Quote Originally Posted by nipun1229 View Post
    It worked like a dream !!! Thanks
    Wow - I had completely forgotten that I wrote that up and posted those examples. Kind of cool to see someone is able to make good use of it four years after I wrote it. It certainly helps to vindicate the hours of research I spent figuring it all out.

  14. #14
    Join Date
    May 2009
    Posts
    3
    Hello again - I just spent the past hour and a half writing a little iFrame polling script because iFrames are REALLY ugly and they usually end up with scrollbars that you don't want.

    I needed nicely formatted output with no scrollbars.

    Change the iframe code to this:

    Code:
    <iframe id="iframe_source" src="commands.php" style="display: none;" />
    <div id="visual_destination"></div>
    <script>
    // At an interval of 250 milliseconds, update the content of "visual_destination" with the data that is currently loaded in the "iframe_source" element.
    new iFramePoller("iframe_source", "visual_destination", 250);
    </script>

    iframe-poller.js // requires Prototype JS (http://prototypejs.org/)
    Code:
    /**
     * Copyright 2009 Michael White
     * 
     * You may contact me at: michael--at--getsprink--dot--com
     * Website: http://getsprink.com
     * 
     * LICENSE: This code is free for use and modification provided this copyright notice and license remains in tact.
     * This software comes without ANY warranty, expressed or implied. (i.e. - this code may or may not work for you!)
     * 
     * If you do use this code or a modified version of it on a project/website I would like to know! Contact me at the e-mail address listed above.
     * 
     * I do offer paid consultation and assistance services for your JavaScript and PHP needs.
     * 
     * If you would like help implementing or modifying this software for your solution, contact me at michael--at--getsprink--dot--com
     * 
     */
    
    
    // This script is used to poll an iframe on a set interval and update an HTML container element.
    
    // Data is checked each time a content check is made to make sure that the data has actually changed prior to updating the destination element.
    
    // Also, the onload event is listened for on the iFrame and that event triggers the stopPolling() function and no more updates are made after that point.
    
    // It makes sense to set the iframe's display property to "display: none;" so that only the other HTML container element is visible.
    
    // You can configure the interval frequency
    
    var iFramePoller_InstanceStack = {};
    
    var iFramePoller = Class.create({
    	global_config: {
    		trace: false,
    		log: false
    	},
    	source_id: null,
    	dest_id: null,
    	source_el: null,
    	dest_el: null,
    	interval: 250,
    	data_cache: null,
    	poll_timer: null,
    	reference_id: null,
    	initialize: function(iframe_source_id, destination_element_id, interval) {
    		this.source_id = iframe_source_id;
    		this.source_el = $(this.source_id);
    		
    		this.dest_id = destination_element_id;
    		this.dest_el = $(this.dest_id);
    		
    		this.interval = interval ? interval : this.interval;
    		
    		// Generate a random reference ID to persist the scope when using setTimeout
    		this.reference_id = "iFramePoller-instance-id-"+Math.random(30, 1500);
    		
    		this.startPolling();
    		
    		iFramePoller_InstanceStack[this.reference_id] = this;
    	},
    	__trace: function(function_name) {
            if(this.global_config.trace === true) {
                console.log("iFramePoller." + function_name + "()");
            }
        },
        __log: function(message) {
            if(this.global_config.log === true) {
                console.log(message);
            }
        },
        setTimer: function() {
        	// Setup a timer for checking the iFrame content and updating the destination element.
    		this.poll_timer = setTimeout(this.doPoll.bind(this), this.interval);
        },
    	startPolling: function() {
        	this.__trace("startPolling");
    		var ref = this.reference_id;
    		// Setup a listener callback for the onload event of the source iFrame
    		Element.observe(this.source_el, "load", this.stopPolling.bind(this));
    		this.setTimer();
    	},
    	stopPolling: function() {
    		this.__trace("stopPolling");
    		clearTimeout(this.poll_timer);
    		this.updateContent();
    		// Delete the iframe 0.5 seconds after the last content update.
    		setTimeout(this.destroySourceIframe.bind(this), 500);
    	},
    	destroySourceIframe: function() {
    		this.source_el.remove();
    	},
    	doPoll: function() {
    		this.__trace("doPoll");
    		this.updateContent();
    		this.setTimer();
    	},
    	updateContent: function() {
    		this.__trace("updateContent");
    		var doc = null;
    		if(this.source_el.contentDocument) {
                this.__log("Using contentDocument");
                doc = this.source_el.contentDocument;
            }
            /* Bugfixed to work in IE6 */
            else if(iframe.contentWindow.document) {
                this.__log("Using contentWindow.document");
                doc = this.source_el.contentWindow.document;
            }
            else {
                this.__log("Using frame[frame_id].document");
                doc = window.frame[this.source_id].document;
            }
    
            this.dest_el.innerHTML = doc.body.innerHTML;
    	}
    });

  15. #15
    Join Date
    Mar 2007
    Location
    localhost
    Posts
    2,206
    Usually a shell script on a web host will run in the area of the server that is not accessible to the public side of operations, this in many hosts is a security precaution.

    The host I use has this kind of feature set up.

    On the host I use I have a shell script that runs every hour to scrape a file in the webspace thats public, it is on the shell side a simple test to see if the hour is equal to 1/4 of a 12 hour period.

    If not then operations cease.

    If it is then the shell script calls a PHP script that then does the processing of the data, pushes information in to a datafile and database.

    On the public side of things, the public page reads the file and database, no need to call a shell script web side as the process has been automated to write a data file and push data in to a database that is then made publicly available.

    So you might want to set up a shell that is cronjobbed every few minutes that writes or pushes your data via a PHP script.
    Yes, I know I'm about as subtle as being hit by a bus..(\\.\ Aug08)
    Yep... I say it like I see it, even if it is like a baseball bat in the nutz... (\\.\ Aug08)
    I want to leave this world the same way I came into it, Screaming, Incontinent & No memory!
    I laughed that hard I burst my colostomy bag... (\\.\ May03)
    Life for some is like a car accident... Mine is like a motorway pile up...

    Problems with Vista? :: Getting Cryptic wid it. :: The 'C' word! :: Whois?

Thread Information

Users Browsing this Thread

There are currently 5 users browsing this thread. (0 members and 5 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles