[RESOLVED] File Uploading
Results 1 to 13 of 13

Thread: [RESOLVED] File Uploading

  1. #1
    Member
    Join Date
    Jan 2014
    Location
    Loveland, CO
    Posts
    40

    resolved [RESOLVED] File Uploading

    I'm hoping this is the right place to post this question. If it needs to be moved to the General Help or Coding areas, please move as needed.

    I have a set of users that need to upload large files to our FTP Site. Due to the number of users, I am having them upload as anonymous users and using their e-mail address as their password for tracking purposes. Most of these users are not particularly tech-savvy, so instead of giving them instructions to use the Command Prompt or a separate FTP Client, I wrote up a "quick" web interface for them with html & php. I had to do some mickey-mousing around using .htaccess to allow for the larger file types, but I got the file upload to work; however, once the user clicks the "Upload File" button, if they aren't using Chrome the interface appears to hang-up while the file is uploading to the temporary location (Chrome users get a small black bar at the bottom of the screen that shows the upload progress). I wanted to have the interface put up something to let the users know that their file is being uploaded and that the page isn't hung up or locked up. I did a little search and found some scripts that appeared to do just what I was seeking, but I'm having issues incorporating them into my existing code.

    You guys here at phpbuilder.com were particularly helpful earlier this year when I was trying to re-write some other code for reading incoming e-mails using Zend\Mail, so I'm hoping you'll be able to point me in the right direction here as well.

    This code uploads the file as expected and displays the "Loading..." gif while the temporary file is being uploaded as I wanted. It uses move_uploaded_file instead of ftp_put, but that's not a big deal because i know how to re-write the php to use ftp_put instead. The problem I have with this code is I don't know how to display feedback. For example, if the e-mail field is blank or doesn't contain a valid e-mail, I don't know how to modify this code to stop processing the upload and tell the user to enter a valid e-mail address.

    If I understand this code correctly, in upload.php the variable $result is being used to relay back to index.php that upload.php ran successfully and in index.php in the stopUpload function the variable success is a boolean that directly relates to $result in upload.php. Is that correct? If so, how would I pass back other values to index.php so I could specify other conditions besides just success or failure uploading the file?

    index.php:
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    	<head>
    	   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    	   <title>Web-FTP Upload</title>
    
    	<script language="javascript" type="text/javascript">
    	<!--
    	function startUpload(){
    	      document.getElementById('upload_process').style.visibility = 'visible';
    	      document.getElementById('upload_form').style.visibility = 'hidden';
    	      return true;
    	}
    
    	function stopUpload(success){
    	      var result = '';
    	      if (success == 1){
    		 result = '<span class="msg">The file was uploaded successfully!<\/span><br/><br/>';
    	      }
    	      else {
    		 result = '<span class="emsg">There was an error during file upload!<\/span><br/><br/>';
    	      }
    	      document.getElementById('upload_process').style.visibility = 'hidden';
    	      document.getElementById('upload_form').style.visibility = 'visible';
    	      document.getElementById('upload_result').style.visibility = 'visible';
    	      document.getElementById('upload_result').innerHTML = '<tr id="upload_result" ><td align="center" colspan="2"><p align="center">'+result+'</p></td></tr>';
    
    	      return true;
    	}
    	//-->
    	</script>
    	<style>
    	#upload_process{
    	   visibility:hidden;
    	}
    	#upload_result{
    	   visibility:hidden;
    	}
    	</style>
    	</head>
    
    	<body>
    	<table border="0">
    		<tr><td align="center"><h3>Web-FTP Upload</h3></td></tr>
    		<tr><td>
    			Instructions:
    			<ul>
    			<li>Select the file to be uploaded. </li>
    			<li>Enter your e-mail address. </li>
    			<li>Click "Upload File" </li>
    			</ul>
    		</td></tr>
    		<tr><td align="left">
    			<table border="0">
    				<tr id="upload_form"><td colspan = "2">
    					<form action="upload.php" method="post" enctype="multipart/form-data" target="upload_target" onsubmit="startUpload();" >
    						<tr><td align="right"><label>File:</label></td><td align="left"><input name="myfile" type="file" size="30" /></td></tr>
    						<tr><td align="right"><label>Email:</label></td><td align="left"><input type="email" name="useremail" id="useremail" size = "30" /></td></tr>
    						<tr><td align="center" colspan="2">
    							<input type="submit" name="submitBtn" class="sbtn" value="Upload" />
    							<br />
    							<iframe id="upload_target" name="upload_target" src="#" style="width:0;height:0;border:0px solid #fff;"></iframe>
    						</td></tr>
    					</form>
    				</td></tr>
    				<tr id="upload_result" ><td align="center" colspan="2"><p align="center"></p></td></tr>
    				<tr id="upload_process"><td align="center" colspan="2">Loading...<br/><img src="loader.gif" /></td></tr>
    			</table>
    		</td></tr>
    	</table>
    	</body>
    </html>
    upload.php
    Code:
    <?php
       // Edit upload location here
       $destination_path = getcwd().DIRECTORY_SEPARATOR;
    
       $result = 0;
       
       $target_path = $destination_path . basename( $_FILES['myfile']['name']);
    
       if(@move_uploaded_file($_FILES['myfile']['tmp_name'], $target_path)) {
          $result = 1;
       }
       
       sleep(1);
    ?>
    
    <script language="javascript" type="text/javascript">window.top.window.stopUpload(<?php echo $result; ?>);</script>

  2. #2
    Senior Member
    Join Date
    Jul 2007
    Posts
    3,665
    Quote Originally Posted by mittra View Post
    If I understand this code correctly, in upload.php the variable $result is being used to relay back to index.php that upload.php ran successfully and in index.php in the stopUpload function the variable success is a boolean that directly relates to $result in upload.php. Is that correct?
    Possibly correct, if you use terms in a very lose sense. The important thing is that you understand how it works. If you wish to communicate with others, also using terms in a stricter sense will help a lot to avoid confusion. In short
    - upload.php does not tell index.php anything at all. upload.php never calls index.php
    - The success parameter of stopUpload directly relates to the value of $result in upload.php
    - success is not a boolean in this case - it is an integer
    - You cannot rely on success being of any particular type as far as the function body of stopUpload goes, unless stopUpload cast it as such. The type of success is determined at call time, by the calling code which in this case is output from upload.php.
    PHP Code:
    # int
    echo window.top.stopUpload(1);
    # bool
    echo window.top.stopUpload(true);
    # string
    echo window.top.stopUpload('1'); 

    The form's target attribute is set to "upload_target" which is an iframe. That iframe works pretty much like any ordinary html page, except that it is also part of another enclosing html page. Thus, the posted form is processed by upload.php. The browser will then take any output from upload.php and use it as content for the iframe. In this case, the output is this script element
    Code:
    <script>window.top.window.stopUpload(<?php echo $result; ?>);</script>
    You should remove the type attribute. If it is present it must be a valid content type. "text/javascript" is obsolete, but the type attribute will take this value if not specified. Setting the type to text/javascript is incorrect, while leaving it out will default to this value. Leaving it out is at least no less interoperable.

    You should also remove the language attribute since its possible values have never been standardized. Use type (unless you need a text/javascript type).

    What happens is that the script will run inside the iframe. iframes have their own window object. The top property of a window will refer to the window object of a browser window or browser tab (the top-most browsing context). Therefor, in the topmost browsing context it is always true that
    Code:
    window === window.top;
    And while it is also true and not incorrect to use redundant .window
    Code:
    window.window === window.top.window;
    window === window.top.window;
    it is nonetheless redundant.

    In your topmost browsing context, you have defined the function stopUpload and the iframe may then call it by
    Code:
    window.top.stopUpload();
    just like the topmost browsing context would call it by
    Code:
    window.stopUpload();
    // or better yet, simply
    stopUpload();
    If you have a button of the non-submit variety in your topmost document, and pushing it calls the javascript function stopUpload, you'd probably (hopefully) not state that clicking the button would tell index.php anything. You'd probably state that clicking the button would call stopUpload. The same thing happens as a result of the output from upload.php: stopUpload is called. Nothing is sent to index.php.

    Quote Originally Posted by mittra View Post
    if they aren't using Chrome the interface appears to hang-up while the file is uploading to the temporary location
    iframe uploads and frame uploads are a thing of the past. You are generally better off handling http requests that do not reload the page with ajax. Ajax requests are asynchronous by default, and you should get consistent behaviour across browsers.

    Quote Originally Posted by mittra View Post
    I wanted to have the interface put up something to let the users know that their file is being uploaded and that the page isn't hung up or locked up.
    If you are satisified with giving Everyone but IE9- a progress bar, you can use the progress event for level 2 XHR.

    Quote Originally Posted by mittra View Post
    I did a little search and found some scripts that appeared to do just what I was seeking, but I'm having issues incorporating them into my existing code.
    It's kind of hard to help inside a black box.

    Quote Originally Posted by mittra View Post
    This code uploads the file as expected and displays the "Loading..." gif while the temporary file is being uploaded as I wanted. It uses move_uploaded_file instead of ftp_put, but that's not a big deal because i know how to re-write the php to use ftp_put instead.
    Except that this could lead to another problem. If the progress bar measures progress for the user's upload to your web server and you switch from moving the large file on the same disk (constant time in regards to file size) to an ftp upload (will take time, potentially lots of time) the progress bar may stay at 100% for a long time, which makes the system appear to be frozen.
    One way around this is to continue using move_uploaded_file, then close the http connection before sending the file over ftp. The downside to this is that the user's file will not be immediately available in the new location after the (user's) upload completes.
    The other way around it is to "guess" (possibly by using average speed for the last 10 uploads) at what speed you can deliver the file from web server to ftp server and incorporate this time into the file upload total time and modifying the progress calculation to incoroprate this.

    Quote Originally Posted by mittra View Post
    The problem I have with this code is I don't know how to display feedback. For example, if the e-mail field is blank or doesn't contain a valid e-mail, I don't know how to modify this code to stop processing the upload and tell the user to enter a valid e-mail address.
    This is a two-part problem - one part is handling this gracefully in the brower. The second part is to have your server simply abort on invalid in-data, or in case you wish to play nice with anyone else talking to your api, abort on invalid in-data and provide a meaningful error message.

    The first part is preventing the upload from being allowed unless the user provides the necessary information. Adding the required attribute to all form inputs that are required will make such information required. Adding an onsubmit event to the form (or similar for ajax uploads) and implement javascript validation of whatever data you want to validate and abort unless it is valid takes care of the rest. This way, a regular user will never have to send their very large file to your web server before being told that their email adress is required or invalid.

    The second part is doing the same thing on the web server. First off, any user can circumvent your client-side validation by creating their own http request even if you don't mean for anyone to do so. Secondly, it is possible that you actually want to allow user's to use your server side api outside of your web page.

    Quote Originally Posted by mittra View Post
    how would I pass back other values to index.php so I could specify other conditions besides just success or failure uploading the file?
    Reformulate the question as: how would I pass back other values to stopUpload so I could specify other conditions besides just success or failure uploading the file?
    The answer is then obviously to pass more than only 0 or 1 to stopUpload. One way would be to also send 2, 3 and 4 to stopUpload. But it's probably better to let success take only 0/1 / true/false, and add second parameter which takes an error message, such as "file size too large", "invalid email address" etc. And such a function could still be called both directly from javascript code BEFORE sending the request to the server, as well as after (in case your form was bypassed or some server side error occurred).

    Quote Originally Posted by mittra View Post
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    Stop coding for yesterdays web and start following ]the current specification
    Quote Originally Posted by The html 5 standards
    The DOCTYPE legacy string should not be used unless the document is generated from a system that cannot output the shorter string.
    Moreover, XHTML 1.0 Transitional does not even seem to be a permitted obsolete doctype.

  3. #3
    Pedantic Curmudgeon Weedpacket's Avatar
    Join Date
    Aug 2002
    Location
    General Systems Vehicle "Thrilled To Be Here"
    Posts
    21,905
    THERE IS AS YET INSUFFICIENT DATA FOR A MEANINGFUL ANSWER
    FAQs! FAQs! FAQs! Most forums have them!
    Search - Debugging 101 - Collected Solutions - General Guidelines - Getting help at all

  4. #4
    Member
    Join Date
    Jan 2014
    Location
    Loveland, CO
    Posts
    40
    Holy cow! That is a ton of extremely useful information! Way more than I was looking for, but certainly appreciated. I will modify my scripts to take into account these recommendations. Very helpful indeed.

  5. #5
    Settled 4 red convertible dalecosp's Avatar
    Join Date
    Jul 2002
    Location
    Accelerating Windows at 9.81 m/s....
    Posts
    7,722
    Quote Originally Posted by mittra View Post
    Holy cow! That is a ton of extremely useful information! Way more than I was looking for, but certainly appreciated. I will modify my scripts to take into account these recommendations. Very helpful indeed.
    Welcome to PHPBuilder!
    /!!\ mysql_ is deprecated --- don't use it! Tell your hosting company you will switch if they don't upgrade! /!!!\ ereg() is deprecated --- don't use it!

    dalecosp "God doesn't play dice." --- Einstein "Perl is hardly a paragon of beautiful syntax." --- Weedpacket

    Getting Help at All --- Collected Solutions to Common Problems --- Debugging 101 --- Unanswered Posts --- OMBE: Office Machines, Business Equipment

  6. #6
    Member
    Join Date
    Jan 2014
    Location
    Loveland, CO
    Posts
    40
    Okay. So let's start from scratch.

    Here's my index.html and ftp_upload.php file that is called by clicking the submit button. I have made a few minor modifications to the ftp_upload.php file based on your recommendations above here (namely the part of ftp_upload.php that was checking to see if the email field was populated).

    This is the barebones version of the index.html file that does not put up the "Loading..." gif and unless you're using Chrome appears to hang if you are uploading a large file. It also doesn't display the results below the form, but as a second page generated by ftp_upload.php.

    Index.html:
    HTML Code:
    <html>
    	<head>
    		<title>Web-FTP File Upload</title>
    	</head>
    	<body>
    	<div align="center">
    		<table border="1">
    			<tr><td align="center">
    				<h3>Web-FTP File Upload</h3>
    			</td></tr>
    			<tr><td>
    				Instructions:
    				<ul>
    					<li>Select the file to be uploaded. </li>
    					<li>Enter your e-mail address. </li>
    					<li>Click "Upload File" </li>
    				</ul>
    			</td></tr>
    			<tr><td>
    				<table>
    					<form id="upload" name="upload" method="post" action="ftp_upload.php" enctype="multipart/form-data">
    						<tr><td align="right"><label for="file">File:</label></td><td align="left"><input type="file" name="userfile" id="userfile" size="30" required /></td></tr>
    						<tr><td align="right"><label for="email">E-mail:</label></td><td align="left"><input type="email" name="useremail" id="useremail" size="30" required /></td></tr>
    				</table>
    			</td></tr>
    			<tr><td align="center">
    						<button type="submit" id="submit" name="submit" >Upload File</button>
    					</form>
    			</td></tr>
    			<tr><td>
    				<p><div class="result"></div></p>
    			</td></tr>
    		</table>
    	</div>
    	</body>
    </html>
    ftp_upload.php
    PHP Code:
    <?php

        ini_set
    ("session.gc_maxlifetime","10800");

        function 
    test_input($data) {
           
    $data trim($data);
           
    $data stripslashes($data);
           
    $data htmlspecialchars($data);
           return 
    $data;
        }

        function 
    cut_string_using_last($character$string$side$keep_character=true) {
            
    $offset = ($keep_character 0);
            
    $whole_length strlen($string);
            
    $right_length = (strlen(strrchr($string$character)) - 1);
            
    $left_length = ($whole_length $right_length 1);
            switch(
    $side) {
                case 
    'left':
                    
    $piece substr($string0, ($left_length $offset));
                    break;
                case 
    'right':
                    
    $start = (- ($right_length $offset));
                    
    $piece substr($string$start);
                    break;
                default:
                    
    $piece false;
                    break;
            }
            return(
    $piece);
        }

       
    // Configuration - Your Options
        
    $allowed_filetypes = array('.gif','.jpg','.jpeg','.png','.tif','.tiff','.bmp','.zip','.pdf','.mp3','.mdb','.allow'); // These will be the types of file that will pass the validation.
        
    $max_filesize 1073741824// Maximum filesize in BYTES (currently 1GB).
        
    $upload_path '/usr/home/kurtsorensen/public_ftp/kurtsorensen/incoming/'// The place the files will be uploaded to.
        
    $tmp_name $_FILES['userfile']['tmp_name'];
        
    $filename $_FILES['userfile']['name']; // Get the name of the file (including file extension).
        
    $ext cut_string_using_last('.'$filename'right'true); // Get the extension from the file name.

        
    $ftp_server 'ftp.inflectionnetwork.com';
        
    $ftp_user_name 'anonymous';
        
    $ftp_user_pass $_POST['useremail'];

       
    // Check if the filetype is allowed, if not DIE and inform the user.
       
    if(!in_array($ext,$allowed_filetypes))
          die(
    'The file you attempted to upload is not allowed (' .$ext' is not allowed. Please contact the systm administrator for assitance.)');

       
    // Now check the filesize, if it is too large then DIE and inform the user.
       
    if(filesize($_FILES['userfile']['tmp_name']) > $max_filesize)
          die(
    'The file you attempted to upload is too large (' .filesize($_FILES['userfile']['tmp_name']). ' > ' .$max_filesize').');


        
    //Check that the email address entered fits standard email format
        
    $email test_input($_POST['useremail']);
        
    // check if e-mail address is well-formed
        
    if (!filter_var($emailFILTER_VALIDATE_EMAIL)) {
            
    $emailErr 'Invalid email format! <br />Please try again.';
            echo 
    $emailErr;
            die;
        }

        
    // set up a connection or die
        
    $conn_id ftp_connect($ftp_server) or die('Couldn\'t connect to ' $ftp_server ' <br />Please try again.');

        
    // Open a session to an external ftp site
        
    $login_result ftp_login($conn_id$ftp_user_name$ftp_user_pass);

        
    // Check open
        
    if ((!$conn_id) || (!$login_result)) {
            echo 
    'FTP-Connect failed! <br />Please try again.';
            die;
        } else {
            echo 
    'Connected to InflectionNetwork FTP as ' $ftp_user_pass '<br />';
        }

        
    // try to change the directory to incoming
        
    if (!ftp_chdir($conn_id'incoming')) {
            echo 
    'Couldn\'t change directory. <br />';
            
    ftp_close($conn_id);
            die;
        }

        
    // turn on passive mode transfers
        
    ftp_pasv($conn_idtrue) ;
        
    set_time_limit(0);

        
    // Upload the file to your specified path and modify the file name if it exists.

        
    $newfilename '';
        
    $fulldest $upload_path.$filename;
        for (
    $i=1file_exists($fulldest); $i++) {
            if (
    $i == 1)
                
    $newfilename substr($filename0strlen($filename)-strlen($ext)).'['.$i.']'.$ext;
            else
                
    $newfilename substr($filename0strlen($filename)-strlen($ext)).substr_replace('['.($i-1).']''['.$i.']'0).$ext;

            
    $fulldest $upload_path.$newfilename;
        }

        if (
    $newfilename)
            
    $filename $newfilename;


        if (
    ftp_put($conn_id$filename$tmp_nameFTP_BINARY))
            echo 
    '"' .$filename '" was successfully uploaded. <br />View the FTP File Directory <a href="ftp://ftp.inflectionnetwork.com/incoming" title="FTP Fileview">here</a>'// It worked.
        
    else
            echo 
    'There was an error during the file upload. Please try again.'// It failed :(.

        // close the connection
        
    ftp_close($conn_id);

     
    ?>
    I have in my cadre of scripts a password generator script that creates a random password based on several user defined parameters and it displays the results on the same page. I can utilize that code (jQuery/AJAX) for this interface, but I don't know how to pass the $_FILES array from index.html to ftp_upload.php. I guess that's the best place to start.

    How do I pass the $_FILES array from index.html to ftp_upload.php using AJAX?

  7. #7
    Senior Member
    Join Date
    Jul 2007
    Posts
    3,665
    Assuming a button with id="upload-button"
    Code:
    $(document).ready(function (e) {
        // add event handler for click on upload button
        $('#upload-button').on('click', function (e) {
            // FormData object includes files in upload
            var fd = new FormData(e.target.form);
            $.ajax({
                url : '/ftp_upload.php',
                type : 'post',
                /* According to my own notes, "contentType has to be false or the boundary attribute will be overwritten".
                 * I don't know when I researched this or if it still holds true. Either verify by trial or check the jQuery docs
                 */
                contentType : false,
                processData : false,
                cache : false,
                /* Include the FormData object as post data */
                data : fd
            }).done(function (data, text, jqxhr) {
                console.log('done');
            }).fail(function (jqxjr, text, error) {
    
            });
        });
    });
    When I wrote my original reply, I forgot that FormData was not supported by IE before version 10. If you need support for IE9-, you will still have to use iframe fallback. Or stick with the original iframe approach.

    You could also use code that deals with this problem for you. There are ready to use jQuery plugins that handle it. So unless you are interested in learning to do it all by yourself, perhaps you should look into using something like [url=http://blueimp.github.io/jQuery-File-Upload/basic.html]. If you look at the html source of that page, you'll find a usage example at lines 128-150, minor adjustments needed. Moreover, these already deal with the progress bar for the client to server upload.

  8. #8
    Member
    Join Date
    Jan 2014
    Location
    Loveland, CO
    Posts
    40

    Question

    So that's the .html side of things. Cool. Now how does the .php side "pick-up" the $_FILES array of data? I'm probably not asking that correctly. Here's what I mean:

    In my password generator, the .html side passes the data like this:

    HTML Code:
    <script type="text/javascript">
    	$(document).ready(function() {
    		$("form#genpass").submit(function() {
    		var minInput     = $('#minInput').attr('value');
    		var maxInput     = $('#maxInput').attr('value');
    		var symInput     = $('#symInput').attr('value');
    		var imgInput	 = $('#imgInput').attr('checked');
    			$.ajax({
    				type: "POST",
    				url: "genpass.php",
    				data: "minInput="+ minInput +"&maxInput="+ maxInput +"&symInput="+ symInput +"&imgInput="+ imgInput,
    				success: function(data){
    								$('div.result').fadeIn();
    								$('.result').html(data);
    				}
    			});
    			return false;
    		});
    	});
    </script>
    minInput is the minimum number of characters that should be used for the password.
    maxInput is the maximum number of characters that should be used for the password.
    symInput is the number of special characters to be included in the password.
    imgInput is a check box that indicates that the gnerator should generate an image of the password to be used to send users the password via email so I'm not sending passwords as plain text through unencrypted email.

    Here's the html part of the page with the form and submit button:

    HTML Code:
    <tr><td>
    	<table>
    		<form id="genpass" method="post" action="">
    			<tr><td align="right">Min:&nbsp;</td><td align="left"><input type="text" name="minInput" id="minInput" size="2" value="8"></td></tr>
    			<tr><td align="right">Max:&nbsp;</td><td align="left"><input type="text" name="maxInput" id="maxInput" size="2" value="16"></td></tr>
    			<tr><td align="right">Sym:&nbsp;</td><td align="left"><input type="text" name="symInput" id="symInput" size="2" value="0"></td></tr>
    	</table>
    </td></tr>
    <tr><td align="center">
    			<input type="submit" value="Generate Password">
    			<br>
    			<input type="checkbox" name="imgInput" id="imgInput" >Generate Image&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</input>
    		</form>
    </td></tr>
    <tr><td align="center" height="60px">
    	<p><div class="result"></div></p>
    </td></tr>
    Then on the .php side of things in genpass.php:

    PHP Code:
    <?php
        
    function passwdGen($minLen 8$maxLen 16$maxSym 0)
        {
            
    $symbolCount 0;
            for (
    $i 0$i rand($minLen$maxLen); $i++)
            {
                do
                {
                    
    $char rand(33126);
                    
    $symbolCount += $isSymbol = (!in_array($charrange(4857)) && !in_array($charrange(6590)) && !in_array($charrange(97122)));
                    if (
    $symbolCount <= $maxSym || !$isSymbol)
                    {
                        break;
                    }
                }
                while (
    true);
                
    $passwd sprintf('%s%c', isset($passwd) ? $passwd NULL$char);
            }
            return 
    $passwd;
        }

        
    $minLen $_POST['minInput'];
        
    $maxLen $_POST['maxInput'];
        
    $maxSym $_POST['symInput'];
        
    $genImg $_POST['imgInput'];

        
    $passwd passwdGen($minLen$maxLen$maxSym);

        echo 
    "<p>".$passwd."</p>";

        if (
    $genImg == "checked") {
            require_once(
    'imggen.php');

            echo 
    "<p><img src='".IntToImg($passwd)."' alt='".$passwd."'></img></p>";
            echo 
    '<p>'.(shortURL($passwd)).'</p>';

        }

    ?>
    You can see where the $_POST data is "picked up" by the php and assigned to variables there.

    My question then is if I use the code you presented, can the php script just get the $_FILES array of data similarly?

    I'm a self-taught programmer and have learned mostly through forums like this, using reference manuals and Frankensteining other code snippets I pick up here and there, so if I'm not asking the question properly, please forgive me. Hopefully, I'm getting across my intent.

    Thank you for your patience.

  9. #9
    Senior Member
    Join Date
    Jul 2007
    Posts
    3,665
    Quote Originally Posted by mittra View Post
    You can see where the $_POST data is "picked up" by the php and assigned to variables there.

    My question then is if I use the code you presented, can the php script just get the $_FILES array of data similarly?
    Yes. PHP automatically populates $_GET, $_POST and $_FILES given requests where it makes sense to do so. The PHP manual entry for $_FILES has this to say
    An associative array of items uploaded to the current script via the HTTP POST method.

  10. #10
    Member
    Join Date
    Jan 2014
    Location
    Loveland, CO
    Posts
    40
    Dag-nab-it! I have totally confused myself and somewhere along the line screwed things up....

    I've modified my html again to fit a number of the recommendations you guys made here and now it isn't working. It appears to work, but doesn't. >

    Here's the HTML:

    HTML Code:
    <!DOCTYPE html>
    	<head>
    		<title>Web-FTP File Upload</title>
    		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
    		<script>
    
    			$(document).ready(function() {
    				$('form#upload_form').submit(function() {
    					var formdata = new FormData(target.form);
    					$.ajax({
    						type: 'POST',
    						url: 'ftp_upload.php',
    						data: formdata,
    						processData: false,
    						contentType: false,
    						success: function(data){
    							$('div.result').fadeIn();
    							$('.result').html(data);
    						}
    					});
    				return false;
    				});
    			});
    		</script>
    	</head>
    	<body>
    	<div align='center'>
    		<table border='1'>
    			<tr><td align='center'>
    				<h3>Web-FTP File Upload</h3>
    			</td></tr>
    			<tr><td>
    				Instructions:
    				<ul>
    					<li>Enter your e-mail address. </li>
    					<li>Select the file to be uploaded. </li>
    					<li>Click "Upload File" </li>
    				</ul>
    			</td></tr>
    			<tr><td>
    				<table>
    					<form name='upload_form' id='upload_form' action='' method='POST' enctype='multipart/form-data'>
    						<tr><td align='right'><label for='email'>E-mail:</label></td><td align='left'><input type='email' name='userEmail' id='userEmail' size='30' placeholder='Enter your email address here.' required /></td></tr>
    						<tr><td align='right'><label for='file'>File:</label></td><td align='left'><input type='file' name='userFile' id='userFile' size='30' placeholder='Select a file to upload.' required /></td></tr>
    				</table>
    			</td></tr>
    			<tr><td align='center'>
    						<button type='submit' id='submitBtn'>Upload File</button>
    					</form>
    			</td></tr>
    			<tr><td align='center' height='60px'>
    				<p><div id='result'></div></p>
    			</td></tr>
    		</table>
    	</div>
    	</body>
    </html>
    and here's the php:
    PHP Code:
    <?php

        ini_set
    ("session.gc_maxlifetime","10800");

        function 
    test_input($data) {
           
    $data trim($data);
           
    $data stripslashes($data);
           
    $data htmlspecialchars($data);
           return 
    $data;
        }

        function 
    cut_string_using_last($character$string$side$keep_character=true) {
            
    $offset = ($keep_character 0);
            
    $whole_length strlen($string);
            
    $right_length = (strlen(strrchr($string$character)) - 1);
            
    $left_length = ($whole_length $right_length 1);
            switch(
    $side) {
                case 
    'left':
                    
    $piece substr($string0, ($left_length $offset));
                    break;
                case 
    'right':
                    
    $start = (- ($right_length $offset));
                    
    $piece substr($string$start);
                    break;
                default:
                    
    $piece false;
                    break;
            }
            return(
    $piece);
        }

       
    // Configuration - Your Options
        
    $allowed_fileExts = array('.gif','.jpg','.jpeg','.png','.tif','.tiff','.bmp','.zip','.pdf','.mdb','.allow'); // These will be the types of file that will pass the validation.
        
    $allowed_fileTypes = array('image/*','application/x-zip-compressed','application/pdf','application/msaccess');
        
    $max_fileSize 1073741824// Maximum filesize in BYTES (currently 1GB).
        
    $upload_path '/usr/home/kurtsorensen/public_ftp/kurtsorensen/incoming/'// The place the files will be uploaded to.
        
    $tmp_name $_FILES['userFile']['tmp_name'];
        
    $fileName $_FILES['userFile']['name']; // Get the name of the file (including file extension).
        
    $ext cut_string_using_last('.'$fileName'right'true); // Get the extension from the file name.
        
    $fileType $_FILES['userFile']['type'];

        
    $ftp_server 'ftp.inflectionnetwork.com';
        
    $ftp_user_name 'anonymous';
        
    $ftp_user_pass $_POST['userEmail'];

        
    print_r ($_FILES['userFile']);
        echo 
    '<br />';

       
    // Check if the filetype is allowed, if not DIE and inform the user.
       
    if(!in_array($ext,$allowed_fileExts))
          die(
    'The file you attempted to upload is not allowed (' .$ext' is not allowed. Please contact the system administrator for assitance.)');

       
    // Now check the filesize, if it is too large then DIE and inform the user.
       
    if(filesize($_FILES['userFile']['tmp_name']) > $max_fileSize)
          die(
    'The file you attempted to upload is too large (' .filesize($_FILES['userFile']['tmp_name']). ' > ' .$max_fileSize').');


        
    //Check that the email address entered fits standard email format
        
    $email test_input($_POST['userEmail']);
        
    // check if e-mail address is well-formed
        
    if (!filter_var($emailFILTER_VALIDATE_EMAIL)) {
            
    $emailErr 'Invalid email format! <br />Please try again.';
            echo 
    $emailErr;
            die;
        }

        
    // set up a connection or die
        
    $conn_id ftp_connect($ftp_server) or die('Couldn\'t connect to ' $ftp_server ' <br />Please try again.');

        
    // Open a session to an external ftp site
        
    $login_result ftp_login($conn_id$ftp_user_name$ftp_user_pass);

        
    // Check open
        
    if ((!$conn_id) || (!$login_result)) {
            echo 
    'FTP-Connect failed! <br />Please try again.';
            die;
        } else {
            echo 
    'Connected to InflectionNetwork FTP as ' $ftp_user_pass '<br />';
        }

        
    // try to change the directory to incoming
        
    if (!ftp_chdir($conn_id'incoming')) {
            echo 
    'Couldn\'t change directory. <br />';
            
    ftp_close($conn_id);
            die;
        }

        
    // turn on passive mode transfers
        
    ftp_pasv($conn_idtrue) ;
        
    set_time_limit(0);

        
    // Upload the file to your specified path and modify the file name if it exists.

        
    $newFileName '';
        
    $fullDest $upload_path.$fileName;
        for (
    $i=1file_exists($fullDest); $i++) {
            if (
    $i == 1)
                
    $newFileName substr($fileName0strlen($fileName)-strlen($ext)).'['.$i.']'.$ext;
            else
                
    $newFileName substr($fileName0strlen($fileName)-strlen($ext)).substr_replace('['.($i-1).']''['.$i.']'0).$ext;

            
    $fullDest $upload_path.$newFileName;
        }

        if (
    $newFileName)
            
    $fileName $newFileName;


        if (
    ftp_put($conn_id$fileName$tmp_nameFTP_BINARY))
            echo 
    '"' .$fileName '" was successfully uploaded. <br />View the FTP File Directory <a href="ftp://ftp.inflectionnetwork.com/incoming" title="FTP Fileview">here</a>'// It worked.
        
    else
            echo 
    'There was an error during the file upload. <br/>Please try again.'// It failed :(.

        // close the connection
        
    ftp_close($conn_id);

     
    ?>
    As it is now, it appears to pass the necessary data from the HTML to the PHP and does not go to a new page, but the file doesn't actually upload and the feedback doesn't appear in the results <div> as expected. And it still doesn't include the "Loading..." gif. If I put "ftp_upload.php" in the form action, it processes everything fine and uploads the file, but the results are on a new page.

    I have this sense I've overlooked something simple, but I have been staring at this for the past few days and have no idea what I'm missing.

  11. #11
    Member
    Join Date
    Jan 2014
    Location
    Loveland, CO
    Posts
    40
    Interesting. I went back to my password generator program and replaced
    Code:
    var minInput     = $('#minInput').attr('value');
    var maxInput     = $('#maxInput').attr('value');
    var symInput     = $('#symInput').attr('value');
    var imgInput	 = $('#imgInput').attr('checked');
    and
    Code:
    $.ajax({
    	type: "POST",
    	url: "genpass.php",
    	data: "minInput="+ minInput +"&maxInput="+ maxInput +"&symInput="+ symInput +"&imgInput="+ imgInput,
    	success: function(data){
    		$('div.result').fadeIn();
    		$('.result').html(data);
    	}
    });
    with
    Code:
    var formData = new FormData();
    and
    Code:
    $.ajax({
    	type: "POST",
    	url: "genpass.php",
    	data: formData,
    	success: function(data){
    		$('div.result').fadeIn();
    		$('.result').html(data);
    	}
    });
    and now it doesn't work either. There's something about how FormData() collects/passes the info along that seems to cause some malfunction in the code that isn't obvious.

  12. #12
    Member
    Join Date
    Jan 2014
    Location
    Loveland, CO
    Posts
    40

    Found a solution

    So in trying to determine how FormData() passed the form information to the php file for processing differently, I found a complete AJAX solution for my web FTP interface.

    Thank you all for trying to assist me in getting this figured out. I'm posting the html here in hopes that it will help someone else in the future. I've added a feature to my php that it will now also send m an e-mail every time a new file is uploaded.

    HTML Code:
    <!doctype html>
    <html>
    	<head>
    	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    	<title>Web-FTP File Upload</title>
    	<script type="text/javascript">
    
    		"use strict";
    
    		/*\
    		|*|
    		|*|  :: XMLHttpRequest.prototype.sendAsBinary() Polyfill ::
    		|*|
    		|*|  https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#sendAsBinary()
    		\*/
    
    		if (!XMLHttpRequest.prototype.sendAsBinary) {
    		  XMLHttpRequest.prototype.sendAsBinary = function(sData) {
    			var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
    			for (var nIdx = 0; nIdx < nBytes; nIdx++) {
    			  ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
    			}
    			/* send as ArrayBufferView...: */
    			this.send(ui8Data);
    			/* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */
    		  };
    		}
    
    		/*\
    		|*|
    		|*|  :: AJAX Form Submit Framework ::
    		|*|
    		|*|  https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
    		|*|
    		|*|  This framework is released under the GNU Public License, version 3 or later.
    		|*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
    		|*|
    		|*|  Syntax:
    		|*|
    		|*|   AJAXSubmit(HTMLFormElement);
    		\*/
    
    		var AJAXSubmit = (function () {
    
    		  function ajaxSuccess () {
    			/* console.log("AJAXSubmit - Success!"); */
    			/*alert(this.responseText);*/
    			document.getElementById('upload_process').style.visibility = 'hidden';
    			document.getElementById('result').style.visibility = 'visible';
    			document.getElementById('result').innerHTML = this.responseText;
    		  }
    
    		  function submitData (oData) {
    			/* the AJAX request... */
    			var oAjaxReq = new XMLHttpRequest();
    			oAjaxReq.submittedData = oData;
    			oAjaxReq.onload = ajaxSuccess;
    			/* method is POST */
    			oAjaxReq.open("post", oData.receiver, true);
    			/* enctype is multipart/form-data */
    			var sBoundary = "---------------------------" + Date.now().toString(16);
    			oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary);
    			oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" + oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n");
    		  }
    
    		  function processStatus (oData) {
    			document.getElementById('upload_process').style.visibility = 'visible';
    			document.getElementById('result').style.visibility = 'hidden';
    			if (oData.status > 0) { return; }
    			/* the form is now totally serialized! do something before sending it to the server... */
    			/* doSomething(oData); */
    			/* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */
    			submitData (oData);
    		  }
    
    		  function pushSegment (oFREvt) {
    			this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
    			this.owner.status--;
    			processStatus(this.owner);
    		  }
    
    		  function plainEscape (sText) {
    			/* how should I treat a text/plain form encoding? what characters are not allowed? this is what I suppose...: */
    			/* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */
    			return sText.replace(/[\s\=\\]/g, "\\$&");
    		  }
    
    		  function SubmitRequest (oTarget) {
    			var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post";
    			/* console.log("AJAXSubmit - Serializing form..."); */
    			this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded";
    			this.technique = bIsPost ? this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0;
    			this.receiver = oTarget.action;
    			this.status = 0;
    			this.segments = [];
    			var fFilter = this.technique === 2 ? plainEscape : escape;
    			for (var nItem = 0; nItem < oTarget.elements.length; nItem++) {
    			  oField = oTarget.elements[nItem];
    			  if (!oField.hasAttribute("name")) { continue; }
    			  sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT";
    			  if (sFieldType === "FILE" && oField.files.length > 0) {
    				  /* enctype is multipart/form-data */
    				  for (nFile = 0; nFile < oField.files.length; nFile++) {
    					oFile = oField.files[nFile];
    					oSegmReq = new FileReader();
    					/* (custom properties:) */
    					oSegmReq.segmentIdx = this.segments.length;
    					oSegmReq.owner = this;
    					/* (end of custom properties) */
    					oSegmReq.onload = pushSegment;
    					this.segments.push("Content-Disposition: form-data; name=\"" + oField.name + "\"; filename=\""+ oFile.name + "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n");
    					this.status++;
    					oSegmReq.readAsBinaryString(oFile);
    				  }
    			  } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
    					/* field type is not FILE or is FILE but is empty */
    					this.segments.push(
    					this.technique === 3 ? /* enctype is multipart/form-data */
    						"Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n"
    					: /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */
    						fFilter(oField.name) + "=" + fFilter(oField.value)
    					);
    			  }
    			}
    			processStatus(this);
    		  }
    
    			return function (oFormElement) {
    				if (!oFormElement.action) { return; }
    				new SubmitRequest(oFormElement);
    			};
    
    		})();
    
    	</script>
    	<style>
    		#upload_process{
    		   visibility:hidden;
    		}
    		#upload_result{
    		   visibility:hidden;
    		}
    	</style>
    	</head>
    	<body>
    		<div>
    			<h3 align='center'>Web-FTP File Upload</h3>
    			<p>
    				Instructions:
    				<ul>
    					<li>Enter your e-mail address. </li>
    					<li>Select the file to be uploaded. </li>
    					<li>Click "Upload File" </li>
    				</ul>
    			</p>
    			<form action='ftp_upload.php' method='POST' enctype='multipart/form-data' onsubmit="AJAXSubmit(this); return false;">
    				<fieldset>
    					<p align='center'>
    						<table border = '0'>
    							<tr><td align='right'>
    								<label for='email'>E-mail:</label>
    							</td><td align='left'>
    								<input type='email' name='userEmail' id='userEmail' size='30' placeholder='Enter your email address here.' />
    							</td></tr>
    							<tr><td align='right'>
    								<label for='file'>File:</label>
    							</td><td align='left'>
    								<input type='file' name='userFile' id='userFile' size='30' placeholder='Select a file to upload.' />
    							</td></tr>
    							<tr><td align='center' colspan='2'>
    								<input type='submit' value='Upload File' align='center' />
    							</td></tr>
    						</table>
    					</p>
    				</fieldset>
    			</form>
    			<p align='center' >
    				<div id='upload_process'>
    				<div id='result' align='center'></div>
    					<p align='center'>
    						Processing and Uploading File. Please wait... <br />
    						<img src="loader.gif" />
    					</p>
    				</div>
    			</p>
    		</div>
    	</body>
    </html>
    Again, thank you for your help and I hope this helps others.

  13. #13
    Senior Member
    Join Date
    Jul 2007
    Posts
    3,665
    I've been busy elsewhere and havn't had time to answer before. Glad you got everything to work eventually. Just thought I'd reply to post #6 above to let you know where you went wrong in case you are interested.


    Quote Originally Posted by mittra View Post
    Okay. So let's start from scratch.
    Index.html:
    HTML Code:
    <html>
    	<head>
    		<title>Web-FTP File Upload</title>
    	</head>
    	<body>
    	<div align="center">
    		<table border="1">
    			<tr><td align="center">
    				<h3>Web-FTP File Upload</h3>
    			</td></tr>
    			<tr><td>
    				Instructions:
    				<ul>
    					<li>Select the file to be uploaded. </li>
    					<li>Enter your e-mail address. </li>
    					<li>Click "Upload File" </li>
    				</ul>
    			</td></tr>
    			<tr><td>
    				<table>
    					<form id="upload" name="upload" method="post" action="ftp_upload.php" enctype="multipart/form-data">
    						<tr><td align="right"><label for="file">File:</label></td><td align="left"><input type="file" name="userfile" id="userfile" size="30" required /></td></tr>
    						<tr><td align="right"><label for="email">E-mail:</label></td><td align="left"><input type="email" name="useremail" id="useremail" size="30" required /></td></tr>
    				</table>
    			</td></tr>
    			<tr><td align="center">
    						<button type="submit" id="submit" name="submit" >Upload File</button>
    					</form>
    			</td></tr>
    			<tr><td>
    				<p><div class="result"></div></p>
    			</td></tr>
    		</table>
    	</div>
    	</body>
    </html>
    1. Your html code is invalid. Due to mismatching opening and closing tags you may end up with an empty form element (element forcibly closed by browser).
    These are probably both acceptable.
    HTML Code:
    <!-- 1. -->
    <form>
      <table>
        <tr><td></td></tr>
        <tr><td></td></tr>
      </table>
    </form>
    
    <!-- 2. -->
    <table>
      <tr><td></td></tr>
      <tr><td>
        <form>
        </form>
      </td></tr>
    </table>
    The HTML 5 docs will let you know what structure is allowed, see 4.10 forms, which states
    Contexts in which this element can be used:
    Where flow content is expected.

    Content model:
    Flow content, but with no form element descendants.
    The first part tells you that you can put a form element where flow content is allowed. The second tells you the form element may contain flow content (except nested forms). Section 3.2.4.1.2 Flow content tells you which elements are considered flow content

    2. You are not passing a form to the FormData constructor.
    The event handler is added to the form's submit event, which means that inside the event handler, e.target is the form, while e.target.form is undefined. e.target.form is what you'd use if you had an event handler listening for events on a form element, such as a click event on a form button.

    3. Your submit event handler does not call event.preventDefault, which means the form will be submitted in the usual manner.
    If your event handler also sends the form data, you will actually send the same data twice.

    Javascript code changes to deal with 2. and 3.
    Code:
    $('#form').on('submit', function(e) {
        // The constructor argument has to be a valid form element.
        // I.e. e.target, rather than e.target.form
        var formdata = new FormData(e.target);
        
        // This prevents default behaviour (i.e. regular form post)
        e.preventDefault();
    
        // rest of code here…

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •