WelcomeWelcome | FAQFAQ | DownloadsDownloads | WikiWiki

Author Topic: easy web interfaces to command line programs using lighttpd and bash  (Read 5920 times)

Offline donquixote2u

  • WikiUser
  • *
  • Posts: 20
Heres a few ideas for a lightweight way of creating web interfaces to command line actions - no need for the whole apache/php route;

first, install bash, and the lighttpd web server
then start lighttpd using a config like this to enable bash cgi;
Code: [Select]
## usage: sudo lighttpd -f /path/to/this/config/file
server.modules              = ( "mod_cgi", "mod_alias" )
server.document-root        = "/opt/www/"
server.errorlog             = "/home/errors.log"
$HTTP["host"] =~ "^" {
$HTTP["url"] =~ ".sh" {
cgi.assign = ( "" => "/usr/local/bin/bash" ) }
}
static-file.exclude-extensions = (".sh" )

(set the web doc root and error logging to wherever)

I just put my scripts in the web root - they can go else where, look up the lightpd config details for how.

 I also put the .sh suffix on them in case I want to mix in html docs

The trick with bash cgi forms is how to return the html form input with POST (url arguments via GET is messy) - heres a subroutine I found to handle that, which I call into my main script so I can use it elsewhere:

Code: [Select]
#This code for getting code from post data is from http://oinkzwurgl.org/bash_cgi

# (internal) routine to store POST data
function cgi_get_POST_vars()
{
    # check content type
    # FIXME: not sure if we could handle uploads with this..
    [ "${CONTENT_TYPE}" != "application/x-www-form-urlencoded" ] && \
echo "Warning: you should probably use MIME type "\
    "application/x-www-form-urlencoded!" 1>&2
    # save POST variables (only first time this is called)
    [ -z "$QUERY_STRING_POST" \
      -a "$REQUEST_METHOD" = "POST" -a ! -z "$CONTENT_LENGTH" ] && \
read -n $CONTENT_LENGTH QUERY_STRING_POST
    return
}

# (internal) routine to decode urlencoded strings
function cgi_decodevar()
{
    [ $# -ne 1 ] && return
    local v t h
    # replace all + with whitespace and append %%
    t="${1//+/ }%%"
    while [ ${#t} -gt 0 -a "${t}" != "%" ]; do
v="${v}${t%%\%*}" # digest up to the first %
t="${t#*%}"       # remove digested part
# decode if there is anything to decode and if not at end of string
if [ ${#t} -gt 0 -a "${t}" != "%" ]; then
   h=${t:0:2} # save first two chars
   t="${t:2}" # remove these
   v="${v}"`echo -e \\\\x${h}` # convert hex to special char
fi
    done
    # return decoded string
    echo "${v}"
    return
}

# routine to get variables from http requests
# usage: cgi_getvars method varname1 [.. varnameN]
# method is either GET or POST or BOTH
# the magic varible name ALL gets everything
function cgi_getvars()
{
    [ $# -lt 2 ] && return
    local q p k v s
    # get query
    case $1 in
GET)
   [ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
   ;;
POST)
   cgi_get_POST_vars
   [ ! -z "${QUERY_STRING_POST}" ] && q="${QUERY_STRING_POST}&"
   ;;
BOTH)
   [ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
   cgi_get_POST_vars
   [ ! -z "${QUERY_STRING_POST}" ] && q="${q}${QUERY_STRING_POST}&"
   ;;
    esac
    shift
    s=" $* "
    # parse the query data
    while [ ! -z "$q" ]; do
p="${q%%&*}"  # get first part of query string
k="${p%%=*}"  # get the key (variable name) from it
v="${p#*=}"   # get the value from it
q="${q#$p&*}" # strip first part from query string
# decode and evaluate var if requested
[ "$1" = "ALL" -o "${s/ $k /}" != "$s" ] && \
   eval "$k=\"`cgi_decodevar \"$v\"`\""
    done
    return
}

(the subroutine is called cgivars.sh in the main routine, stored in the web root along with the other scripts)

and now for the main form-handling script; as an example heres my web interface for the mpc / mpd music player combo (I'll try to attach a screenshot showing what it looks like)

Code: [Select]
#!/bin/bash
## MUSIC PLAYER WEB INTERFACE
## include handler for receiving form variables via POST
source ./cgivars.sh
echo -e "Content-type: text/html\n\n"
## display form html (closing html is left off at first, added after search key fields added)
cat <<EOF
<html>
<head>
    <title>JUKEBOX MUSIC SELECTION</title>
<style>
div #panel1 { width: 48%; float: left; border: 1px solid; padding: 0px 2px 2px 5px; }
div #panel2 { width: 50%; float: right; border: 1px solid; padding: 0px 2px 2px 5px; }
</style>
</head>
<body bgcolor=#bbbbee >
<div style="font-family: Arial, Helvetica, sans-serif; font-size: medium; ">
   <div>
              <h1> SELECT and PLAY MUSIC</h1>
</div>
   <hr />
<form action="http://${HTTP_HOST}${SCRIPT_NAME}" method="POST">
       <strong > SELECT  </strong>
         Search Tag  <select  name="tag">
<option>Artist</option>
<option>Genre</option>
<option value="Title">Song</option>
  <option value="Album">Type</option>
            </select>
Search Text  <input name="pattern" type="text" />

<input name="submit" type="submit" value="submit" />
<hr />
EOF
## now get form fields from returned form (empty first time thru), process
cgi_getvars BOTH ALL
case "$submit" in
'play')
CMD="mpc toggle";
;;
'shuffle')
CMD="mpc shuffle";
;;
'prev')
CMD="mpc prev";
;;
'next')
CMD="mpc next";
;;
'clear')
CMD="mpc clear";
;;
'submit')
CMD="search";
;;
'add')
CMD='mpc search '${key}' | mpc add'
;;
'reset')
key=""
CMD="";
;;
'voldown')
CMD="volume"
DIR="down";
;;
'volup')
CMD="volume"
DIR="up";
;;
esac
## set up new  search keys and format for next output of screen form
if [ "$pattern" != "" ]; then
    newkeys=${key}" "${tag}" "${pattern}
fi
cat <<EOF
current keys  <input name="key"  type="text"
 size="40" readonly="true" value ="$newkeys"/>
<button name="submit" type="submit" value="add">add</button>
<button name="submit" type="submit" value="reset">reset</button>
<hr>
<strong> PLAY  </strong>
<button name="submit" type="submit" value="shuffle">shuffle</button>
<button name="submit" type="submit" value="prev" alt="back"><<</button>
<button name="submit" type="submit" value="play" alt="play/stop">>|</button>
<button name="submit" type="submit" value="next" alt="next">>></button>
<button name="submit" type="submit" value="voldown" alt="vol -">vol -</button>
<button name="submit" type="submit" value="volup" alt="vol +">vol +</button>
<button name="submit" type="submit" value="clear">clear</button>
</form>
<div id="panel1"><h3>SELECTION</h3>
EOF
## if cmd is volume change, get volume status and adjust
if [ "$CMD" = "volume" ]; then
  VOL=`mpc volume | sed 's/volume://g' | sed 's/\%//g'`
  if [ "$DIR" = "up" ]; then
    if [ "$VOL" -gt "86" ]; then
 VOL=100
    else
 let VOL+=13
    fi
  else ## volume request is "down"
    if [ "$VOL" -lt "15" ]; then
 VOL=0
    else
 let VOL-=15
    fi
  fi
CMD='mpc volume '$VOL
fi  
if [ "$CMD" = "search" ]; then
  CMD='mpc search '$newkeys" | sed 's/$/<br>/g'"
fi
## echo 'CMD: '$CMD
if [ "$CMD" != "" ]; then
  eval $CMD
fi
echo '</div>'
echo '<div id="panel2"><h3>PLAYLIST</h3>'
mpc playlist | sed 's/$/<br>/g'
cat <<EOF
</div></div>
</body>
</html>
EOF

( no comments on my code please, its really a test for you to spot the style errors  ;D ) - I've attached a screenshot below so you can see what the code actually produces.

- as you can see, you can create large chunks of straight html  and output them with "cat", either inline or as separate files.

 thats it!  just call up the page with the normal http://(host)/(script) url and you should be in business - easy, huh?

 
« Last Edit: August 20, 2010, 03:30:00 PM by donquixote2u »