Search code examples
pythonhtmlimagecherrypy

How to save this file?


So I have come HTML code that lets the user input an image:

<label class="tab-item"> Browse
    <span class="icon icon-more"></span>
    <input type="file" accept="image/*"  name="image_save" value="image_save" onchange="updatePhoto(event);"></input>
</label>

#some more code

<form action="../api/save" method="post">
    <button type="submit" name="image_save" class="btn btn-positive btn-block" href="../api.put" value="image_save">
        Test Save
    </button>
</form>

And in a Python file I have:

@cherrypy.expose
def save(self, image_save=None):
    f = open(image_save)
    f.save("../photos/" + "test" + ".png", "PNG")
    return "Image saved"

However I get the error

IOError: [Errno 2] No such file or directory: u'image_save'"

How would you guys save the image that is given through the HTML code? What type of data is being given as the method argument?


Solution

  • There is a mimimal example at this site which gives this example for a python file upload:

    #!/usr/local/bin/python
    """This demonstrates a minimal http upload cgi.
    This allows a user to upload up to three files at once.
    It is trivial to change the number of files uploaded.
    
    This script has security risks. A user could attempt to fill
    a disk partition with endless uploads. 
    If you have a system open to the public you would obviously want
    to limit the size and number of files written to the disk.
    """
    import cgi
    import cgitb; cgitb.enable()
    import os, sys
    try: # Windows needs stdio set for binary mode.
        import msvcrt
        msvcrt.setmode (0, os.O_BINARY) # stdin  = 0
        msvcrt.setmode (1, os.O_BINARY) # stdout = 1
    except ImportError:
        pass
    
    UPLOAD_DIR = "/tmp"
    
    HTML_TEMPLATE = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html><head><title>File Upload</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    </head><body><h1>File Upload</h1>
    <form action="%(SCRIPT_NAME)s" method="POST" enctype="multipart/form-data">
    File name: <input name="file_1" type="file"><br>
    File name: <input name="file_2" type="file"><br>
    File name: <input name="file_3" type="file"><br>
    <input name="submit" type="submit">
    </form>
    </body>
    </html>"""
    
    def print_html_form ():
        """This prints out the html form. Note that the action is set to
          the name of the script which makes this is a self-posting form.
          In other words, this cgi both displays a form and processes it.
        """
        print "content-type: text/html\n"
        print HTML_TEMPLATE % {'SCRIPT_NAME':os.environ['SCRIPT_NAME']}
    
    def save_uploaded_file (form_field, upload_dir):
        """This saves a file uploaded by an HTML form.
           The form_field is the name of the file input field from the form.
           For example, the following form_field would be "file_1":
               <input name="file_1" type="file">
           The upload_dir is the directory where the file will be written.
           If no file was uploaded or if the field does not exist then
           this does nothing.
        """
        form = cgi.FieldStorage()
        if not form.has_key(form_field): return
        fileitem = form[form_field]
        if not fileitem.file: return
        fout = file (os.path.join(upload_dir, fileitem.filename), 'wb')
        while 1:
            chunk = fileitem.file.read(100000)
            if not chunk: break
            fout.write (chunk)
        fout.close()
    
    save_uploaded_file ("file_1", UPLOAD_DIR)
    save_uploaded_file ("file_2", UPLOAD_DIR)
    save_uploaded_file ("file_3", UPLOAD_DIR)
    
    print_html_form ()
    

    Additional Suggestions

    I would suggest you change the input type to

     <input type="file" name="image_save" accept="image/x-png,image/gif,image/jpeg" />
    

    instead of image/* to limit to png/jpg/gif. MIME type can be checked using php and i would also suggest you add a upload_max_filesize (in php also)

    Finally change the fout line to

     fout = open(pathname, 'wb')
    

    While the file() constructor is an alias for open(), for future and backwards compatibility, open() remains preferred.