#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2003
    Location
    Canada
    Posts
    185
    Rep Power
    0

    My first CGI PROGRAM.


    I would like to know how to refactor this code so it works better and more effiecently. It is a hack, as it is my first cgi project - ever. Please be gentle.
    The problems i am having are 1) if a user enters a invalid email address it still gives the error message however it also still writes to the file
    2)Every time an item is written to the file, part of the previous information is overwritten by whitespace. This seems to be incremental by a value incremented by at least 2 on each line:
    for example if the file was accessed x times.
    first time:abcdefghiklmno
    second time:abcdefghik
    third:abcdefghijk
    and so on

    this is my code so far. again please be gentle. I'm pretty much finished- i think:
    Code:
    #c_parser.py
    #import appropiate modules
    
    import cgi
    import time
    import cgitb; cgitb.enable()
    form = cgi.FieldStorage()
    print "Content-type: text/html"
    print
    
    open = 0
    
    
    #get form information
        
    try:
        
        name = form["name"].value
        if name.isalpha():
            name = name.lower()
        else:
            print "Enter a valid name"
            
        exp = form["Experience"].value
        level = form["Level"].value
        product = form["Product"].value
        
        area_code = form["area_code"].value
        if area_code.isalpha():
            print "Enter a valid area code"
            
        phone_prefix = form["p_prefix"].value
        if phone_prefix.isalpha():
            print "Enter a valid Phone Prefix"
            
        phone_suffix = form["p_suffix"].value
        if phone_suffix.isalpha():
            print "Enter a valid Phone Suffix"
            
        email = form["email"].value
        if "@" not in email:
            print "Enter a valid email"
    
        phone = area_code + "-" + phone_prefix + "-"+ phone_suffix
    
    except Exception, e:
        print "please input your", e
    
    else:
    
        try:
            open+=1
            f = file(r"C:\Program Files\Abyss Web Server\htdocs\log.txt", "r+")
            length = len(f.read())
            f.seek(length+open)
            f.write("\n")"""with newline some values of preceeding line still truncated"""
            f.write(time.asctime())
            f.close()
            print "info written to file now"
    
        except Exception, e:
            print e
    "In theory, there is no difference between theory and practice.
    But, in practice, there is."

  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2003
    Location
    Canada
    Posts
    185
    Rep Power
    0
    wow my code is excellent? gee thanks:
    "In theory, there is no difference between theory and practice.
    But, in practice, there is."

  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Feb 2004
    Location
    London, England
    Posts
    1,585
    Rep Power
    1373
    I missed this post first time around.

    First a comment on efficiency in CGI scripts: don't worry about it. In a CGI program like this the bulk of the time is going to be spent loading Python, loading the script, and compiling it to bytecodes. Unless you have a loop in you script that is doing heavy processing then nothing you can do to the code will make any noticeable difference. If execution time is an issue for you then look into one of the alternatives to CGI where Python is running full time so does not need to be loaded: mod_python, mod_cgi, FastCGI, WebWare, Zope etc.

    Now down to the code:

    1)
    Code:
        if name.isalpha():
            name = name.lower()
    Don't bother with the isalpha test - name = name.lower() is all you need, since it will make all alpha characters lowercase and leave the rest. The test for isalpha will return False if any character in the string is non-alpha, including spaces. So "John Doe" will not be made lowercase since it will fail the test.

    2)
    Code:
        if area_code.isalpha():
            print "Enter a valid area code"
    I presume by area code that you mean Zip code? The UK and many other countries have an alphanumeric area code, e.g. "AB12 CD34", so your test will exclude those from outside of america. It will also accept as valid any string that has any non-alpha characters (e.g. '$%&**'), as well the empty string. If you want to check that a string only contains 0-9 then use str.isdigit().

    3) ditto for all the phone number tests. But also see my rant on checking phone numbers here.

    4)
    Code:
    except Exception, e:
        print "please input your", e
    What will be in the exception object e? Why do you assume it will be a string saying what is missing?

    5)
    Code:
            open+=1
            f = file(r"C:\Program Files\Abyss Web Server\htdocs\log.txt", "r+")
            length = len(f.read())
            f.seek(length+open)
    open is intialised to 0 at the start of the script, so will always be set to 1 at this point. What is it supposed to represent?
    You are also reading in the entire file just to seek to the end - I take back what I said about not needing to optimise. You can seek directly to the end of the file with f.seek(0,2). You can also open the file for appending in which case the seek to the end happens automatically.

    6) It looks like you are writing to the log file that the server is using. THIS IS VERY DANGEROUS. The server may be be in the process of writing to the file, in which case the call to write() may fail, or the server may write to the file between your seek and your write statements, which will result in information getting overwritten. It sounds from your description that this may be what is happening. Create your own log file and write to that.

    7)
    Code:
        try:
        ...
        except Exception, e:
            print e
    you have enabled cgitb to display any exceptions in a nice HTML friendly way, but then you catch all exceptions and display the same information in plain text. Remove the last try/except block and let cgitb do its work.

    Finally a note on good practice: if you separate out the CGI part and put the data handling into a separate function then you can easily test the code either interactively or with unittest. e.g.

    Code:
    def checkAndSaveFormData(name, exp, area_code, phone_prefix,...):
       ...
    
    if __name__ == '__main__':
      name = cgi.form['name'].value
      exp = cgi.form['exp'].value
      ...
      checkAndSaveFormData(name, exp,...)

    Dave - The Developers' Coach
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2003
    Location
    Canada
    Posts
    185
    Rep Power
    0
    Thank you for you reply Coach. I've sinced refactored my code and found more efficient ways to code it.
    Thank you very much for you helpful suggestions and your time. you can be sure i wasn't trying to write to the log file, and i've found the pythonic way of appending to a file with the append mode . If does its job very well.
    here is my code for anyone who would like to see a decent cgi script in python, add your own content accordingly
    Code:
    #c_parser.py
    """ while 1:
            get form input
            handle form validity
            break
        process form"""
        
    #import appropiate modules
    
    import cgi, sys,time
    import cgitb; cgitb.enable()
    
    form = cgi.FieldStorage()
    print "Content-type: text/html"
    print
    
    def Alert():
        print  """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/transitional">
    
    <html>
    <head>
    <link rel="stylesheet" type="text/css" href="styles.css" />
    </head>
    <title>title goes here</title>
    <body>
    
    
    <h1>HEADLINES</h1>
    <P/>
    <h4>just a blurb</h4>
    <table cellpadding = 4 cellspacing=0 width=100%>
    <tr> 
    <th><a href ="about.htm">About Us</a> 
    <th><a href ="solutions.htm">Solutions</a>
    <th><a href ="contact.htm">Contact</a>
    <th><a href ="index.htm">Home</a>
    <th><a href ="eform.htm">E-Forms</a>
    </tr></table><ul/><hr/><p/>
    <center/>
    </body>
    </html>"""
        return 
    
    
    def End_page():
        print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/transitional">
    
    <html>
    <head>
    <link rel="stylesheet" type="text/css" href="styles.css" />
    </head>
    <title>TITLE</title>
    <body>
    
    
    <h1>HEADLINES HERE</h1>
    <p/>
    <h4>other blurbs</h4>
    <table cellpadding = 4 cellspacing=0 width=100%>
    
    <tr> 
    <th><a href ="about.htm">About Us</a> 
    <th><a href ="solutions.htm">Solutions</a>
    <th><a href ="contact.htm">Contact</a>
    <th><a href ="index.htm">Home</a>
    </tr></table><ul/><hr/><p/>
    <center/>Your information has been processed.</p>
    <input type = "button" value ="RETURN TO HOME"  onClick = "window.location = ' index.htm' ">
    </body>
    </html>
    </h1>
    """ 
        return
    
    
    def ProcessInfo():
        """processes client info however possible to just maybe  refactor and use the csv module,or picke, or shelve"""
        try:
            f=open(r"C:\Program Files\Abyss Web Server\htdocs\clients.txt", "a")
            f.write(time.asctime())
            f.write("\n")
            f.write(info)
            f.write("\n\n")
        finally:
             f.close()
        return 
    
    
    #get form information
    while 1:
        """form.getvalue("key") much less forgiving since it will not raise an exception and return none if nothing in field"""
        name=form.getvalue("name","name_none")
        l_name=form.getvalue("l_name","lname_none")
        exp=form.getvalue("Experience","exp_none")
        level=form.getvalue("Level","level_none")
        product=form.getvalue("Product","product_none")
        area_code = form.getvalue("area_code","area_none")
        phone_prefix = form.getvalue("p_prefix","prefix_none")
        phone_suffix = form.getvalue("p_suffix","suffix_none")
        email = form.getvalue("email","email_none")
    
    
        #TEST INPUT
        if name.lower() == "name_none" or l_name.lower() == "lname_none":
            Alert()
            print "<h2>Please Enter a valid name</h2>"
        
        elif exp=="exp_none":
            Alert()
            print "<h2>Please enter your experience level</h2>"
        elif level=="level_none":
            Alert()
            print "<h2>Please enter your level of work</h2>"
        elif product== "product_none":
            Alert()
            print "<h2>Please enter the product or service you have experience with</h2>"
        elif area_code=="area_none":
            Alert()
            print "<h2>Enter your area code</h2>"
        elif area_code.isalpha():
            Alert()
            print "<h2>Enter a valid area code</h2>"
        elif phone_prefix=="prefix_none":
            Alert()
            print "<h2>Enter your phone prefix</h2>"
        elif phone_prefix.isalpha():
            Alert()
            print "<h2>Enter a valid phone prefix</h2>"
        elif phone_suffix.isalpha():
            Alert()
            print "<h2>Enter a valid phone suffix</h2>"
        elif phone_suffix=="suffix_none":
            Alert()
            print "<h2>Enter a phone sufffix</h2>"
        elif "@" not in email:
            Alert()
            print "<h2>Enter a valid email address</h2>"
        else:
            phone = area_code + "-" + phone_prefix + "-" + phone_suffix
            info = name +"  "+ l_name + "  " + exp + "  "+level+" " +product+" "+phone+" "+email
            
            ProcessInfo()
            End_page()
        break
    Also a nice plug: for those of you looking for a webserver to practice your cgi programming in python or other scripting. I highly suggest The Abyss webserver. I didn't build it so i'm not spamming, but it is amazing piece of work. Its tiny, and effiecient and is constantly being upgraded. available for windows and linux. So if you don't need an industrial size webserver like apache check it out. The more ppl using it the better it will become. I'm honestly very impressed with this piece of software. Even use it to host your own sites on your comp. Unbelievable especially when you combine the power of python. Thats my two cents, my ten cents is free.
    "In theory, there is no difference between theory and practice.
    But, in practice, there is."


IMN logo majestic logo threadwatch logo seochat tools logo