These essentially allow you to use shell script and all your normal system
commands inside a web page to create dynamic web pages, or in other
words, web based GUIs for system/terminal programs.
I wanted a lightweight way of creating dynamic web applications without installing any extra programs.
This method uses only the 'httpd' busybox applet, and BASH.
To use these examples, you'll need to create the folder ~/bin/ and add it to your $PATH:
Code: Select all
mkdir /root/bin
export PATH=/root/bin:$PATH
1. Create the folders /root/www/cgi-bin
2. Save the scripts below as /root/www/cgi-bin/test.sh and ~/www/cgi-bin/upload.sh
3. Run `chmod 755 /root/www/cgi-bin/test.sh` to make it executable and give it the right permissions
4. Run `DOCUMENT_ROOT=/root/www httpd -h /root/www -p 127.0.0.1:8080 -u nobody:nobody`
(Or you could start your web server with this wrapper I made, to get extra security
and automatic folder creation, file ownership/permission handling, etc)
5. Visit http://localhost:8080/ in your browser.
FEATURES OF TEST SCRIPT:
You can add ?foo=bar&stuff=whatever to the URL and these values will be displayed on the page as $GET['foo'], etc ..
You can submit the form on the page and then the form field values will be displayed on the page as $POST['foo'], etc ..
You can upload files - BUT BINARY FILES GET BROKEN IN THE UPLOAD ... Any fixes for that?!
File: test.sh
Code: Select all
#!/bin/bash
#===============================================================================
# Description:
#
# a test script, demonstrating how to parse GET and POST
# variables into associative arrays with BASH, httpd and CGI.
#
# Installation:
#
# chmod 755 this script, and put it in your CGI bin (somewhere
# like '$HOME/www/cgi-bin/test.sh')
#
# Usage:
#
# Run the command `httpd -p 127.0.0.1:8080 -h ~/www` and visit
# the URL 'http://localhost/cgi-bin/test.sh' in a web browser.
#
# Adding a query string to the URL, or submitting the form on
# the page will create $POST and $GET arrays containing the
# key/value pairs of the POST/GET data.
#
#
# More info:
#
# https://stackoverflow.com/questions/3919755/how-to-parse-query-string-from-a-bash-cgi-script
#
#===============================================================================
# Set some vars for later
title="CGI demo"
#===============================================================================
# Parsing GET and POST variables is horrible, let's make it easier.
# Let's put the query string and POST variables in into nice arrays.
# get POST vars (if any), with support for multi-line vars
POST_STRING="$(cat)"
# handling file uploads
if [ "$REQUEST_METHOD" = "POST" ]; then
if [ "$(echo "$CONTENT_TYPE" | grep -m1 'multipart/form-data;')" != "" ];then
if [ "$CONTENT_LENGTH" -gt 0 ]; then
boundary=$(echo -n "$POST_STRING" | head -1 | tr -d '\r\n');
filename=$(echo -n "$POST_STRING" | grep --text --max-count=1 -oP "(?<=filename=\")[^\"]*");
file_content="$(echo -n "$POST_STRING" \
| sed '1,/Content-Type:/d' \
| tail -c +3 \
| head --lines=-1 \
| head --bytes=-4 \
| head -n -4)"
fi
else
# parse $QUERY_STRING
saveIFS=$IFS # save IFS (internal field separator)
IFS='=&' # use '=' and '&' as internal field separators
get_array=($QUERY_STRING) # create an array from $QUERY_STRING
post_array=($POST_STRING) # create an array from $POST_STRING
IFS=$saveIFS # restore IFS to its original state
# Let's create associative array, so we can access the
# query string and POST values like so: $GET['foo'] and $POST['foo']
# The keys will be accessed using an exclamation point ${!array[@]},
# the values are accessed using ${array[@]}, the total number of items
# in the array can be accessed using a hash - ${#array[@]}.
# Declare, is used to set variables, array and attributes.The -a option
# creates indexed arrays, -A creates associative arrays.
# declare the $GET and $POST associative arrays (still empty at this point)
declare -A GET
declare -A POST
# add the key/value pairs to $GET
for ((i=0; i<${#get_array[@]}; i+=2))
do
key=${get_array[i]}
value=${get_array[i+1]}
GET[$key]=$value
done
# add the key/value pairs to $POST
for ((i=0; i<${#post_array[@]}; i+=2))
do
key=${post_array[i]}
value=${post_array[i+1]}
POST[$key]=$value
done
fi
fi
#===============================================================================
# BEGIN OUTPUT
# IMPORTANT - set the content type first, then an empty newline!
echo 'Content-type: text/html; charset=UTF-8'
echo 'Status: 200 OK'
echo ''
echo ''
#===============================================================================
# BEGIN PAGE HTML
echo '<!DOCTYPE html>'
echo '<html>'
echo "<head><title>$title</title></head>"
echo "<body>"
echo "<h1>$title</h1>"
echo "<br>========================================================<br>"
echo "<p>ENV VARS</p>"
echo '<pre>'
uname -a
echo -n 'user = '; whoami
env | sort -u
echo "</pre>"
echo "<br>========================================================<br>"
# if we have a query string, print the relevant vars
if [ "$QUERY_STRING" != '' ];then
echo '<p>$QUERY_STRING:</p>'
echo "<pre>"
echo $QUERY_STRING
echo "</pre>"
echo '<p>$GET[@] array:</p>'
echo "<pre>"
# print the key/value pairs:
for x in "${!GET[@]}"
do
echo '$GET'"[$x] = ${GET[$x]}"
done
echo "</pre>"
else
echo "<p>Add a query string to the URL to see it parsed here.</p>"
fi
echo '<br>========================================================<br>'
# if we have a POST vars, print the relevant vars
if [ "$POST_STRING" != "" ];then
# file uploads
if [ "$(echo "$CONTENT_TYPE" | grep -m1 'multipart/form-data;')" != "" ];then
echo "<br>"
echo "<p>File upload(s):</p>"
echo "<pre>"
echo "boundary: $boundary"
echo "filename: $filename"
echo "file contents:"
echo "</pre>"
echo "<div style=\"background-color:#dfdfdf;\"><pre>${file_content}</pre></div><p>more text..</p>"
else
echo '<p>$POST_STRING:</p>'
echo "<pre>"
echo $POST_STRING
echo "</pre>"
echo '<p>$POST[@] array:</p>'
echo "<pre>"
# print the key/value pairs:
for x in "${!POST[@]}"
do
echo '$POST'"[$x] = ${POST[$x]}"
done
echo "</pre>"
fi
else
echo '<form id="file-form" action="upload.sh" method="post" enctype="multipart/form-data">
Select file to upload:
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload File" name="submit">
</form>'
echo '<br>========================================================<br>'
echo '<p>Enter a month and year then click "Submit" to see the POST variables here.</p>'
echo '<form id="text-form" method="post" action="">'
echo ' <p>Month: <input type="text" name="month" value="" style="width: 90px" /></p>'
echo ' <p>Year: <input type="text" name="year" value="" style="width: 90px" /></p>'
echo ' <input type="submit" value="Submit" />'
echo '</form>'
fi
echo "</body>"
echo "</html>"
echo ""
And upload.sh
Code: Select all
#!/bin/bash
#======================================
# Description:
#
# A dumb script for handling file uploads.. CANNOT handle binary files!
#
# Installation:
#
# chmod 755 this script, and put it in your CGI bin
#
# Usage: POST the file to this script using something like this:
#
# <form action="" method="post" enctype="multipart/form-data">
# <input type="file" name="fileToUpload" id="fileToUpload">
# <input type="submit" value="Upload File" name="submit">
# </form>
#
# Or, use curl to upload files via the terminal:
#
# curl http://localhost:8080/cgi-bin/upload.sh -F "MyFile=@/path/to/a/file"
#
#======================================
# This scripts needs the following env vars:
# DOCUMENT_ROOT # the web server root folder (usually /var/www/)
# REQUEST_METHOD # GET or POST
# CONTENT_TYPE # 'multipart/form-data' or 'application/x-www-form-urlencoded'
# CONTENT_LENGTH # length of POST data
function error500 {
echo 'Content-type: text/html; charset=UTF-8'
echo 'Status: 500 Internal Server Error'
echo ''
echo ''
}
if [ ! -d "${DOCUMENT_ROOT}" ] || \
[ "$REQUEST_METHOD" != "POST" ] || \
[ "$(echo "$CONTENT_TYPE" | grep -m1 'multipart/form-data;')" = "" ] || \
[ "$CONTENT_LENGTH" -eq 0 ]; then
error500
exit 1
fi
#if [ ! -d ${DOCUMENT_ROOT}/downloads/ ]then
mkdir ${DOCUMENT_ROOT}/downloads/ &>/dev/null
chmod 744 ${DOCUMENT_ROOT}/downloads/ &>/dev/null
chown nobody:nobody ${DOCUMENT_ROOT}/downloads/ &>/dev/null
#fi
# all POST vars are received as std input
POST_DATA="$(cat)"
# get the file meta info and contents
boundary=$(echo -n "$POST_DATA" | head -1 | tr -d '\r\n');
filename=$(echo "$POST_DATA" | sed -n '2!d;s/\(.*filename=\"\)\(.*\)\".*$/\2/;p')
file=$(echo "$POST_DATA" | sed -n "1,/$boundary/p" | sed '1,4d;$d')
# save the file
echo "$file" > ${DOCUMENT_ROOT}/downloads/"$filename" || \
{
error500
exit 1
}
chmod 755 ${DOCUMENT_ROOT}/downloads/"$filename"
#--------------------------
# BEGIN OUTPUT
echo 'Content-type: text/html; charset=UTF-8'
echo 'Status: 200 OK'
echo ''
echo ''
echo "File '$filename' uploaded OK"
exit 0