550 likes | 818 Views
CGI Programming. CGI.pm Creating HTML pages with Perl Forms processing A general Web front end for Perl programs. Some of These Slides Were Based on Previous Material by John Grefenstette. Web programming.
E N D
CGI Programming • CGI.pm • Creating HTML pages with Perl • Forms processing • A general Web front end for Perl programs Some of These Slides Were Based on Previous Material by John Grefenstette BINF634 FALL 2013 - CGI PROGRAMMING
Web programming • Many web pages are static text files containing HTML (hypertext markup language) tags that tell the Browser how to display the page Browser(client) Web Server BINF634 FALL 2013 - CGI PROGRAMMING
<HTML> <HEAD> <TITLE>BINF 634. Bioinformatics Programming, Test Data 1</TITLE> </HEAD> <BODY bgcolor="#ffffff"> BINF 634 - Spring 2008 <p> Test data and sample output for Programming Assignment 1: <p> % seqstat.pl test1.fsa > test1.out<br> Input: <a href="test1.fsa">test1.fsa</a><br> Output: <a href="test1.out">test1.out</a><p> % seqstat.pl test2.fsa > test2.out<br> Input: <a href="test2.fsa">test2.fsa</a><br> Output: <a href="test2.out">test2.out</a><p> % seqstat.pl test3.fsa > test3.out<br> Input: <a href="test3.fsa">test3.fsa</a><br> Output: <a href="test3.out">test3.out</a><p> % seqstat.pl H_influenzae.fsa > H_influenzae.out<br> Input: <a href="H_influenzae.fsa">H_influenzae.fsa</a><br> Output: <a href="H_influenzae.out">H_influenzae.out</a><p> </BODY> </HTML> BINF634 FALL 2013 - CGI PROGRAMMING
Browser(client) Web Server Perl program Data Server CGI programming Internet user's machine binf.gmu.edu • Goal: Enable users to access your program over the web • Advantages: • Portable • No need to distribute code • Enable users to access remote databases BINF634 FALL 2013 - CGI PROGRAMMING
CGI programming Idea: • Write Perl programs that create HTML pages dynamically Steps: • Create HTML forms for user input • Get user input from forms • Run algorithm • Create new HTML to display output BINF634 FALL 2013 - CGI PROGRAMMING
CGI programming CGI.pm • Perl module written by Lincoln Stein • Contains subroutines for creating HTML • so you don’t need to remember HTML syntax • Includes forms, and standard widgets • text fields, radio buttons, pull down menus, file uploads, etc. • Documentation: http://perldoc.perl.org/CGI.html http://www.wiley.com/legacy/compbooks/stein/ BINF634 FALL 2013 - CGI PROGRAMMING
Simple cgi program • The web browser can be configured to treat programs in certain directories as CGI scripts • Put CGI scripts in ~/public_html/cgi-bin • Make the script executable: % cd ~/public_html/cgi-bin % chmod 755 hello #!/usr/bin/perl -w # File: hello use strict; use warnings; use CGI qw(:standard); # module to output HTML commands print header; print start_html("My first CGI"); print "Hello, world!"; print end_html; exit; BINF634 FALL 2013 - CGI PROGRAMMING
Debugging CGI Programs • Debugging CGI programs can be tricky • Warnings and fatal error's are sent to system logs • You normally don’t see these system logs • Solutions: • Always check for compilations errors before running in a browser: % perl -c cgi_program • Include CARP module to send fatal errors to browser use CGI::Carp qw/fatalsToBrowser/; BINF634 FALL 2013 - CGI PROGRAMMING
Some formatting #!/usr/bin/perl -w # File: format # declare we want to use the CGI module with standard function set use CGI qw(:standard); # set fatal error message to the browser window use CGI::Carp qw/fatalsToBrowser/; # more elaborate HTML print header; print start_html("Test cgi"); print h1('A Simple Example'); # h1 is a level 1 header (large) print p; # outputs a paragraph break <p> print "Hello, world!", p, "This is a new paragraph.", p; print em("This is italics font."); # em puts text into italics (emphasis) print "This is normal font."; # br outputs a line break <br> print "Notice you you need a br to make a line break", br, "like this.", p; # hr gives a horizontal line across the page <HR> print "hr gives a horizontal rule like this:", br, hr; print "The end."; print end_html; exit; BINF634 FALL 2013 - CGI PROGRAMMING
A Virtual Clock #!/usr/bin/perl # File: time use strict; use warnings; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; my $current_time = localtime; # localtime is a built-in function print header, start_html('A Virtual Clock'), h1('A Virtual Clock'), "The current time is $current_time.", hr, end_html; exit; BINF634 FALL 2013 - CGI PROGRAMMING
#!/usr/bin/perl # File: form use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; print header; print start_html('A Simple Form'); if (not defined param()) { print h1('A Simple Form'); print start_form; print "What's your name? "; print textfield('name'); print p; print "Pick your keywords:"; print p; print checkbox_group(-name=>'words', -values=>['biology','virus','computers','programs','lab'], -defaults=>['computers','lab']); print p; print "What's your favorite color? "; print popup_menu(-name=>'color', -values=>['red','green','blue','yellow']); print p; print submit; print end_form; print hr; } else { my $name = param('name'); my @keywords = param('words'); my $color = param('color'); print "Your name is $name"; print p; print "Your keywords are: @keywords"; print p; print "Your favorite color is $color"; print hr; } print end_html; BINF634 FALL 2013 - CGI PROGRAMMING
How to set up forms • Create form with start_form(); … end_form(); • Populate form with appropriate fields and buttons: print textfield(); print "What's your name? "; print textfield('name'); print checkbox_group(); print checkbox_group( -name=>'words', -values=>['biology','virus','computers','programs','lab'], -defaults=>['computers','lab']); print popup_menu(); print popup_menu(-name=>'color', -values=>['red','green','blue','yellow']); print reset(); # clears the form print submit(); # values sent through params() function BINF634 FALL 2013 - CGI PROGRAMMING
How it works • The name field is the key to access the values filled in or selected by the user • The values of these fields can be retrieved by calling the subroutineparam()with the desired key • When the program is called the first time by accessing its URL,param()returns an undefined value • When the submit button is pressed, the Perl program is run again, but nowparam() returns the values input to the named field in the form BINF634 FALL 2013 - CGI PROGRAMMING
More details • Each type of field and button on forms created through CGI.pm take several parameters: • name • size • label • default values (for menus and buttons) • Read documentation for CGI.pm, here • http://perldoc.perl.org/CGI.html BINF634 FALL 2013 - CGI PROGRAMMING
#!/usr/bin/perl # File: basecounter use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; print header; print start_html('A Base Counter'), h3('A Nucleotide Counter'), start_form, p, "Enter a DNA string in the text box below, and I will count the various bases for you.", p, "DNA string: ", textfield('dna'), p, reset, submit, end_form, hr; if (param()) { # this part is executed after user clicks SUBMIT button my $dna = param('dna'); # analyze the input data my $a = ($dna =~ tr/Aa//); my $t = ($dna =~ tr/Tt//); my $c = ($dna =~ tr/Cc//); my $g = ($dna =~ tr/Gg//); # output results to the HTML page print "The DNA is: $dna", p, "The base counts are: A = $a C = $c G = $g T = $t", p, hr; } print end_html; exit; BINF634 FALL 2013 - CGI PROGRAMMING
Template for CGI program (1) • Use this if you want to create HTML page, then add info when user clicks SUBMIT (like the Nucleotide counter): #!/usr/bin/perl use strict; use warnings; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; print header; print start_html('Title of Web Page'); # put code to set up web page here print start_form; . . . print reset, submit, end_form, hr; if (param()) { # this part is executed after user clicks SUBMIT button } print end_html; exit; BINF634 FALL 2013 - CGI PROGRAMMING
Template for CGI program (2) #!/usr/bin/perl use strict; use warnings; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; print header; print start_html('Title of Web Page'); if (not defined param()) { # this part is executed when the URL is entered into browser print start_form; . . . print reset, submit, end_form, hr; } else { # this part is executed after user clicks SUBMIT button } print end_html; exit; • Use this if you want to create HTML page, then display new page when user clicks SUBMIT (like the Simple Form): BINF634 FALL 2013 - CGI PROGRAMMING
Multipart Forms • Multipart forms allow a file field on the form • Use this to present user with a dialog box to select a local file to upload to the server • The Perl program can then access the uploaded copy of the file BINF634 FALL 2013 - CGI PROGRAMMING
#!/usr/bin/perl # File: basecounter2 use strict; use warnings; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; my $url = "/jsolka/cgi-bin/basecounter2"; print header; print start_html('A Base Counter'), h3('A Nucleotide Counter'), start_multipart_form, p, "Click the button to choose a FASTA file:", br, filefield(-name=>'filename'), p, reset, submit('submit','Submit File'), hr, endform; if (param()) { my $filehandle = upload('filename'); # read whole file into @data array my @data = <$filehandle>; close $filehandle; # discard header line and put rest of file into $dna string shift @data; my $dna = join "", @data; $dna =~ s/\s//g; # analyze the input data my $a = ($dna =~ tr/Aa//); my $t = ($dna =~ tr/Tt//); my $c = ($dna =~ tr/Cc//); my $g = ($dna =~ tr/Gg//); # output results to the HTML page print "The DNA is: $dna", p, "The base counts are: A = $a C = $c G = $g T = $t", p, hr; print address( a({href=>$url},"Click here to submit another file.")); } print end_html; exit; BINF634 FALL 2013 - CGI PROGRAMMING
Wrapper: A Web Interface with CGI • We will design a Web Interface for Perl programs • Key Idea: Separate function (e.g. Perl program) from Interface • Method: • Write standalone Perl program that uses command line arguments • Write a separate Web Interface program (the wrapper) • The Interface • interacts with the user via the web • creates the input files needed • creates the command line args needed • calls the standalone Perl program, puts output in a file • displays the output on the web BINF634 FALL 2013 - CGI PROGRAMMING
Internet user's machine www.binf.gmu.edu Browser(client) Web Interface Input file Perl program Output file CGI programming Issues: • The web interface program is run by user "www", not you • So, the files are created by user "www" • The perl program is run by user "www" One solution: • The web interface script: • will create a directory owned by www • create an input file in this directory • run the perl program to create an output file • read the resulting output file and display it on the web page BINF634 FALL 2013 - CGI PROGRAMMING
#!/usr/bin/perl -T # File: wrapper # Author: Jeff Solka based on earlier version by John Grefenstette # # A simple web interface to the program named in the variable "program" below. # It is assumed that this program takes a single input file # as its command line argument. # use warnings; use strict; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; # edit the following lines as needed: my $path = "/userhomes/faculty/jsolka/binf634"; # path to program directory my $prog = "words.pl"; # the program we want to run my $url = "/jsolka/cgi-bin/wrapper"; # the URL of this script my $dir = "/tmp/CGI-$$"; # working directory $ENV{PATH} = "/bin:/usr/bin"; # makes it OK to run other programs # Create an HTML form with a FILE FIELD: print header; print start_html('A Web Interface'), h3("A Web Interface for $prog"), start_multipart_form, p, "Click the button to choose the input file:", br, filefield('filename'), p, reset, submit('submit','Submit File'), endform; BINF634 FALL 2013 - CGI PROGRAMMING
# This part processes the form after the user clicks on "Submit" if (defined param()) { # get filehandle on file uploaded from internet my $filehandle = upload('filename'); if (not defined $filehandle) { # the user did not enter a file name print p, strong("Please complete file field."), p, address( a({href=>$url}, "Try again.")); exit; } # copy uploaded file to working directory mkdir $dir or die "Can't create directory $dir\n"; chdir $dir or die "Can't change to directory $dir\n"; print hr, p, "Working directory = $dir", p; my $infile = "in"; open FH, ">$infile" or die "Can't open $infile"; while (<$filehandle>) { s/\r//g; # convert end-of-line character to Unix print FH; } close $filehandle; close FH; # display the input file on the web page print hr, p, "Input file = $infile", p; print_file($infile); BINF634 FALL 2013 - CGI PROGRAMMING
# run the program on the input file and save the output my $outfile = "out"; # "$path/$prog" is the full path to the target Perl program my $command = "$path/$prog $infile > $outfile"; # run the given command print hr, p, "Executing: <PRE>$command</PRE>", p; system $command; # display the output on the web page print hr, p, "Output:", p; print_file($outfile); # clean up (comment out when debugging) system "rm -rf $dir"; # provide a link to run the wrapper again print hr, p; print address( a({href=>$url},"Click here to run the program again.")); } print end_html; exit; BINF634 FALL 2013 - CGI PROGRAMMING
sub print_file { my ($file) = @_; if (open(OUTFILE, "$file")) { my @output = <OUTFILE>; close OUTFILE; print "<PRE>"; # preformatted output foreach my $line (@output) { # convert any special HTML characters # change "&" to "&", "<" to "<", ">" to ">" $line = escapeHTML($line); print $line; } print '</PRE>'; # end preformatted output } else { print strong("<font color=red>Sorry, an error has occurred in reading the file \"$file\".</font>"); } } BINF634 FALL 2013 - CGI PROGRAMMING
To Review: • CGI.pm provides subroutines for producing HTML documents dynamically • Put cgi programs in ~/public_html/cgi-bin so that the web server treats them as CGI • Make sure the cgi programs are executable by all Wrapper: • Put standalone perl script in a directory readable by user "www" • Edit the wrapper to point to the perl script BINF634 FALL 2013 - CGI PROGRAMMING
CGI.pm BINF634 FALL 2013 - CGI PROGRAMMING
CGI.pm BINF634 FALL 2013 - CGI PROGRAMMING
CGI.pm BINF634 FALL 2013 - CGI PROGRAMMING
CGI.pm BINF634 FALL 2013 - CGI PROGRAMMING
CGI with Popup Window #!/usr/bin/perl use strict; use warnings; use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser/; print header; print start_html('Popup Window'); if (not defined param()) { print start_multipart_form(-target=>'_new'); print h3("Ask your Question"); print p, "What's your name? ", textfield('name'), p; print reset; print submit; print endform; } else { print h3("And the Answer is..."); print p, "Your name is ", param("name"), p; } print end_html; BINF634 FALL 2013 - CGI PROGRAMMING
Security in CGI Programming(See Ch 23 in Wall) • When accepting data from internet users, you must guard against malicious users -- see Chapter 23 for more details. • Never directly execute commands entered by remote users • take care with "system" commands • Be careful about writing to world-writable files • Our wrapper program makes sure the file do not already exist • Do not assume that uploaded files contain appropriate data • Perl provides some safeguards for CGI programs • Taint mode keeps track of possibly tainted data that has not been checked by the CGI script • To get taint mode: #!/usr/bin/perl -T BINF634 FALL 2013 - CGI PROGRAMMING
Taint Mode (-T) • In a CGI program, all values obtained from user input are considered tainted (dangerous) until untainted (re-written) by the program itself • Tainted values in certain operations, such as system calls, cause an exception in Taint Mode • Example: suppose the user inputs a seed value $seed for a random number generator, and your CGI program contains: #!/usr/bin/perl -T # Taint mode ... my $seed = param('seed'); system "$prog -s $seed > $outfile"; • This will cause an error because the user might have input something like $seed = "123 > xxx; rm -rf *" • So your system call would become: system "$prog -s 123 > xxx; rm -rf * > $outfile"; • This removes ALL FILES and DIRECTORIES!! BINF634 FALL 2013 - CGI PROGRAMMING
Untainting User Supplied data • Always use Taint mode (-T) in CGI program that collect user input • Untaint user-supplied data by checking that they contain the correct kind of data, and rewriting it • For example, this untaints the $seed value: if ($seed =~ /^(\d+)$/) { $seed = $1 } else { $seed = 123 }; • For some variables, you might only allow word characters, hyphens and dots: if ($database =~ /^([-\w.]+)$/) { $database = $1 } else { die "Bad database name: $database\n" }; • It is up to you to decide how to check the information -- Perl does not know what to legal form of the data should be • Be especially careful about user data that might contain quotes (' or ") or file names that contain "/" or "../". BINF634 FALL 2013 - CGI PROGRAMMING