Hello Everyone,

I need your help, can you please tell me how to create a text field for file upload with HTML ?

I presently have this code in my form for file upload to the webserver;
<input name="userfile" type="file" size="50">, this allows someone to browse file from their computer to upload a file. How ever this is not what I want.

What I want is a form field that allows me to preset a file that can be uploaded to the server.

So far this is what I have got <input name="userfile" type="file" size="50" value="a.html"> adding value="a.html" to the field. But it's not working.

Can you guys please help me out? thanks in advance.

Recommended Answers

All 17 Replies

I'm not sure this is still possible, since modern browsers works in a sandbox, separated from the system, so you cannot execute or copy a local file directly from a remote script.

Thanks for your response Cereal, not really copying from local per say. The file is already on a web server "Server1" I'm trying to dispatch the file from "Server1" to "Server2" using that method. Surely there should be a way to achieve this.

Hi Angle90.
From your statements I guess what you are trying to do is to have a default file sent to the server even if the user doesn't include any in their form submission. If that's the case, then it's just a matter of including a conditional statement in the form processing script so that if the file field in the submitted data is null, then a default file is attached instead and sent on to "server2".

Oh, ok. In this case you don't have to use $_FILES, since it's not an upload action, but a download from a remote server. So you don't need a file input field, use text field:

<input type="text" name="link" value="http://remote.dev/a.html" readonly />

In addition from your script you should check if:

  • link is valid and allowed
  • if the remote file is available
  • and then you download it

Keep in mind that, even by placing readonly attribute to the field, the client can change the value of the form or try to submit a custom request by itself, by using cURL and submit whatever, so you should also:

  • add a CSRF check;
  • create a download queue list, to avoid multiple concurrent downloads;
  • create a whitelist and check if the source server is allowed;
  • get the header of the file and from there: 1. check the sizes of the file from the header response; 2. check the mime type of the file you are going to download;
  • check the downloaded file (size and mime type) again;
  • save the file inside a directory in which PHP is not executed.

Some info:
http://www.daniweb.com/web-development/php/threads/449496/my-site-was-hacked-by-c99-shell/
http://www.daniweb.com/web-development/php/threads/426854/how-to-create-an-image-downloader

Bye!

Where is the php script executing from? Server1 or Server2?

Thanks again guys, Cereal, trying your method throws me an error, but i believe that you have an idea of what I'm trying to achieve. So I thought I should post the codes here. I have two major files here "index.php" and "step-1-upload.php".

The codes recide in "server1" which is mine, so if you access index.php from a remote area, you will be asked to enter your server FTP details, then you click on the "Start Installation" button.

The imput would be processed by "step-1-upload.php" The idea is to dispatch a preset file "a.html" from "Server1" as stated in "index.php" into a requesting FTP account public_html/ folder.

But at the moment, I'm not getting it right at all. The codes only work if the requesting visitor is uploading from their computer. I really need your help here guys thanks in advance.

Here are the codes for index.php

<?php 

<form action="step-1-upload.php" method="POST" enctype="multipart/form-data">
<table align="center">
<tr>
<td align="left">
Server:
</td>
<td>
<input size="50" type="text" name="server" value="">
</td>
</tr>
<tr>
<td align="left">
Username:
</td>
<td>
<input size="50" type="text" name="user"  value="">
</td>
</tr>
<tr>
<td align="left">
Password:
</td>
<td>
<input size="50" type="text" name="password" value="" >
</td>
</tr>
<tr>
<td align="left">
Path on the server:
</td>
<td>
<input size="50" type="text" name="pathserver" value="public_html/" readonly>
</td>
</tr>
<tr>
<td align="left">
Select your file to upload:
</td>
<td>
<input name="userfile" type="file" size="50" value="a.html">
</td>
</tr>
<tr>
<td align="left" colspan="2" height="1">
</td>
</tr>
<tr>
<td align="left">
</td>
<td>
<input type="submit" name="submit" value="Start Installation" />
</td>
</tr>
</table>
</form>

?>

And here are the codes for step-1-upload.php

<?
if(!isset($_POST["submit"])){?>

<form action="upload.php" method="POST" enctype="multipart/form-data">
<table align="center">
<tr>
<td align="right">
Server:
</td>
<td>
<input size="50" type="text" name="server" value="">
</td>
</tr>
<tr>
<td align="right">
Username:
</td>
<td>
<input size="50" type="text" name="user"  value="">
</td>
</tr>
<tr>
<td align="right">
Password:
</td>
<td>
<input size="50" type="text" name="password" value="" >
</td>
</tr>
<tr>
<td align="right">
Path on the server:
</td>
<td>
<input size="50" type="text" name="pathserver" >
</td>
</tr>
<tr>
<td align="right">
Select your file to upload:
</td>
<td>
<input name="userfile" type="file" size="50">
</td>
</tr>
</table>
<table align="center">
<tr>
<td align="center">
<input type="submit" name="submit" value="Upload image" />
</td>
</tr>

</table>
</form>
<?}
else 
{

    set_time_limit(300);//for setting 

$paths=$_POST['pathserver'];

$filep=$_FILES['userfile']['tmp_name'];

$ftp_server=$_POST['server'];

$ftp_user_name=$_POST['user'];

$ftp_user_pass=$_POST['password'];

$name=$_FILES['userfile']['name'];



// set up a connection to ftp server
$conn_id = ftp_connect($ftp_server);

// login with username and password
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);

// check connection and login result
if ((!$conn_id) || (!$login_result)) {
       echo "FTP connection has encountered an error!";
       echo "Attempted to connect to $ftp_server for user $ftp_user_name....";
       exit;
   } else {
       echo "Connected to $ftp_server, for user $ftp_user_name".".....";
   }

// upload the file to the path specified
$upload = ftp_put($conn_id, $paths.'/'.$name, $filep, FTP_BINARY);

// check the upload status
if (!$upload) {
       echo "FTP upload has encountered an error!";
   } else {
       echo "Uploaded file with name $name to $ftp_server ";
   }

// close the FTP connection
ftp_close($conn_id);    

}

?>

Which errors you get? As suggested by c-tech you can use a conditional statement to submit the default value and use the form to only display the file name. Also, change your form to deal with strings and not with uploads, for example this:

<input name="userfile" type="file" size="50" value="a.html">

should be:

<input name="userfile" type="text" size="50" value="a.html">

since there are no uploads from the browser client to Server1, $_FILES will be empty, you don't need it because the script gets the file name from the $_POST array, for example:

# $filep=$_FILES['userfile']['tmp_name']; # remove this line
$file = pathinfo(parse_url($_POST['userfile'],PHP_URL_PATH),PATHINFO_BASENAME);
$path = '/local/path/';

if(file_exists($path.$file))
{
    $filep = $file;
}
else
{
    $filep = 'a.html';
}

Anyway, be more specific about the errors, so we can try to help you, bye!

At c-tech, that sounds like a great idea thanks for that tip. However, i'm a complete novice when it comes to PHP so I will really appreaciate your help putting these together.

Cereal I really appreciate your help, can you please double check this ? below are the errors I'm getting following the guidelines above. Thank yous in advance.

[26-Apr-2013 18:29:59] PHP Warning:  ftp_put() [<a href='function.ftp-put'>function.ftp-put</a>]: Filename cannot be empty in /home/user/public_html/test-folder/project/step-1-upload.php on line 90

[26-Apr-2013 18:57:49] PHP Parse error:  syntax error, unexpected '<' in /home/user/public_html/test-folder/project/index.php on line 3
[26-Apr-2013 18:57:58] PHP Parse error:  syntax error, unexpected '<' in /home/user/public_html/test-folder/tools/project/index.php on line 3

[26-Apr-2013 19:41:49] PHP Warning:  ftp_put() [<a href='function.ftp-put'>function.ftp-put</a>]: Can't open that file: Is a directory in /home/user/public_html/test-folder/project/step-1-upload.php on line 55

Ok, the second and third errors are related to the index.php file, you don't need the <?php and ?> since it's plain html, so your index page becomes something like:

<!DOCTYPE html>
<html>
    <head>
        <title>ftp test</title>
    </head>
    <body>
        <h2 align="center">FTP form</h2>
        <form action="step-1-upload.php" method="POST">
            <table align="center">
                <tr>
                    <td align="left">
                        Server:
                    </td>
                    <td>
                        <input size="50" type="text" name="server" value="" />
                    </td>
                </tr>
                <tr>
                    <td align="left">
                        Port:
                    </td>
                    <td>
                        <input size="50" type="text" name="port" value="21" />
                    </td>
                </tr>
                <tr>
                    <td align="left">
                        Username:
                    </td>
                    <td>
                        <input size="50" type="text" name="user"  value="" />
                    </td>
                </tr>
                <tr>
                    <td align="left">
                        Password:
                    </td>
                    <td>
                        <input size="50" type="text" name="password" value="" />
                    </td>
                </tr>
                <tr>
                    <td align="left">
                        Path on the server:
                    </td>
                    <td>
                        <input size="50" type="text" name="pathserver" value="public_html/" readonly />
                    </td>
                </tr>
                <tr>
                    <td align="left">
                        Select your file to upload:
                    </td>
                    <td>
                        <input name="userfile" type="text" size="50" value="a.html" />
                    </td>
                </tr>
                <tr>
                    <td align="left" colspan="2" height="1">
                    </td>
                </tr>
                <tr>
                    <td align="left">
                    </td>
                    <td>
                        <input type="submit" name="submit" value="Start Installation" />
                    </td>
                </tr>
            </table>
        </form>
    </body>
</html>

The other two errors are occuring because the paths are not defined, in my previous example I was checking if the file existed, but when setting $filep I wasn't adding the local path, probably this caused your error, anyway here's a working version:

<?php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    # variables for local server
    $local_path = $_SERVER['DOCUMENT_ROOT'].'/ftp/'; # change this to match yours
    $filename = pathinfo(parse_url($_POST['userfile'],PHP_URL_PATH),PATHINFO_BASENAME);

    # ftp credentials and remote path
    $ftp_user_name = $_POST['user'];
    $ftp_user_pass = $_POST['password'];
    $ftp_server = $_POST['server'];
    $ftp_port = in_array(intval($_POST['port']),array(0,1)) ? 21:intval($_POST['port']); # default port 21
    $remote_path = rtrim($_POST['pathserver'],'/');

    if(file_exists($local_path.$filename))
    {
        $local_file = $local_path.$filename;
    }
    else
    {
        $local_file = $local_path.'a.html';
    }

    // set up a connection to ftp server
    $conn_id = ftp_connect($ftp_server,$ftp_port);

    // login with username and password
    $login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);

    if ((!$conn_id) || (!$login_result))
    {
       echo "FTP connection has encountered an error!";
       echo "Attempted to connect to $ftp_server for user $ftp_user_name....";
       exit;
    } else {
       echo "Connected to $ftp_server, for user $ftp_user_name".".....";
    }
    // upload the file to the path specified
    $upload = ftp_put($conn_id, $remote_path.'/'.$filename, $local_file, FTP_BINARY);

    // check the upload status
    if (!$upload) {
       echo "FTP upload has encountered an error!";
    } else {
       echo "Uploaded file with name $filename to $ftp_server ";
    }

    // close the FTP connection
    ftp_close($conn_id);    
}
else
{
    # die('Access denied!');
    # or redirect to the form page
    header('Location: index.php');
}
?>

I added a port field to the form so the script can connect to an ftp server listening on different ports than 21. By changing $local_path to match your local path, in which you have a.html file, the script should work without any problems.

By the way the errors are occurring in two different directories:

/test-folder/project/ for step-1-upload.php file
/test-folder/tools/project/ for index.php file

So maybe one of the two files is interacting with a previous version(?) Try to setup everything into a new directory and let us know the results, bye.

Hello Cereal, thanks a million. It works perfect and I hope someone else will find this useful as well.

How would i go about attaching more than one files ? Looking at the PHP code above in line 21, I changed this to the following in order to attach multiple files, but it didn't work. How can I achieve this ? I would also like to give you a credit/reference in this project. Thanks ever so much.

$local_file = $local_path.'a.html';
$local_file = $local_path.'b.html';
$local_file = $local_path.'c.html';
$local_file = $local_path.'d.html';
$local_file = $local_path.'e.html';

In order to work you have to create an array and then loop it into single ftp_put() calls, so change the form so you can send an array of files, i.e. by changing the name attribute of the input field userfile:

<tr>
    <td align="left" valign="top">
        Select your file to upload:
    </td>
    <td>
        <input name="userfile[]" type="text" size="50" value="a.html" /><br />
        <input name="userfile[]" type="text" size="50" value="b.html" /><br />
        <input name="userfile[]" type="text" size="50" value="c.html" />
    </td>
</tr>

And change the script:

<?php
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    # verify the files
    function checkfiles($path,$files,$default_files)
    {
        $result = array();

        if(count(array_filter($files)) == 0)
        {
            # default array of files, loaded in case $_POST['userfile'] is empty
            $files = $default_files;
        }

        foreach($files as $file)
        {
            $file = pathinfo(parse_url($file,PHP_URL_PATH),PATHINFO_BASENAME);
            if(file_exists($path.$file) && is_file($path.$file))
            {
                $result[] = $file;
            }
            else
            {
                echo "<p>file $file not found!</p>";
            }
        }
        return $result;
    }

    # default array of files
    $default_files = array('a.html','b.html','c.html','d.html','e.html');

    # variables for local server
    $local_path = $_SERVER['DOCUMENT_ROOT'].'/ftp/'; # change this to match yours
    $local_files = checkfiles($local_path,$_POST['userfile'],$default_files);

    if(count($local_files) == 0)
    {
        echo '<p>Error, files not founded!</p>';
        exit;
    }

    # ftp credentials and remote path
    $ftp_user_name = $_POST['user'];
    $ftp_user_pass = $_POST['password'];
    $ftp_server = $_POST['server'];
    $ftp_port = in_array(intval($_POST['port']),array(0,1)) ? 21:intval($_POST['port']); # default port 21
    $remote_path = rtrim($_POST['pathserver'],'/');

    // set up a connection to ftp server
    $conn_id = ftp_connect($ftp_server,$ftp_port);

    // login with username and password
    $login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);

    if ((!$conn_id) || (!$login_result))
    {
       echo "<p>FTP connection has encountered an error!</p>";
       echo "<p>Attempted to connect to $ftp_server for user $ftp_user_name....</p>";
       exit;
    } else {
       echo "<p>Connected to $ftp_server, for user $ftp_user_name".".....</p>";
    }

    // upload the file to the path specified
    foreach($local_files as $local_file)
    {
        $upload = ftp_put($conn_id, $remote_path.'/'.$local_file, $local_path . $local_file, FTP_BINARY);

        // check the upload status
        if (!$upload) {
           echo "<p>FTP upload has encountered an error with file $local_file!</p>";
        } else {
           echo "<p>Uploaded file with name $local_file to $ftp_server</p>";
        }
    }

    // close the FTP connection
    ftp_close($conn_id);    
}
else
{
    # die('Access denied!');
    # or header to redirect to referer
    header('Location: index.php');
}

Anyway, I'm still not sure if the form can set the files to upload or if you want to upload a predefined group of files, no matter what is sent by the user. In any case I changed the script to deal with both situations, for example if you want to upload only the default group of files, add an empty array as second argument of checkfiles, so change this line (35):

$local_files = checkfiles($local_path,$_POST['userfile'],$default_files);

To:

$local_files = checkfiles($local_path,array(),$default_files);

The empty array will automatically load the $default_files.

I can't thank you enough Cereal. Great help I'll PM you in a sec, thanks a million.

It's all working perfecly now, after installation completes, I like to auto redirect after FTP connection closed or a redirection triggered after the user clicked on a link.

I tried the following but it won't work;

  //  auto redirect or on link clicked 
  echo '<a href="another-file.php">Go back to the main page</a>.';

And I also tried this, with no luck

//  auto redirect or on link clicked 
      echo '<a href="http://$ftp_server">Go back to the main page</a>.';
Member Avatar for diafol

Use

header("Location: $url");

after your ftp script.

You're welcome. What happens? The link is not displayed?

By placing it right after the ftp_close() it should work:

ftp_close($conn_id);
echo '<p><a href="another-file.php">Go back to the main page</a></p>';

To perform an automatic redirect, after displaying the output of the operation you can add a meta tag to the page. To simplify you can add an array to the top of the script $output = array(); and change all the echo statements to $output[] = 'message goes here'; and then print the output at the end.

Otherwise you can save $output to $_SESSION, redirect with header() to the form page and display the results.

Oh it did work after clearing Cache. Instead of this ; echo '<p><a href="another-file.php">Go back to the main page</a></p>';

I want something like this; echo '<p><a href="http://the-url-to-server-2.dns">Go back to the main page</a></p>';

The header("Location: $url"); does not work, please let me explain.

This is what it's all about, a remotely downloadable zipped file and a few php files on "Server1" which is mine. To download the zipped files one has to enter an FTP details "Server2". On successful FTP connection, "Server1" will dispatch the downloadable files to the requesting "Server2". Thanks to Cereal, this stage has been successful.

The next challenge if possible is to either remotely from "Server1" extract the downloaded zipped file at "Server2" (since it seems impossible to create a server-side self extracting zip) or attach a set of PHP files from the onset that can be manually launched to load unzip.php.

To get the ball rolling I have attached an unzip.php file with this code <?php system('unzip html.zip'); ?> however I need a way to remotely trigger it on "Server2" or automatically create a complete url to it based on the submitted server credentials.

After unzip.php completes, I want to be able to run files from the unzipped folder/ (either remotely or via a link).

And finally if successfully processed in "Server2", I want to remotely delete the uploaded zipped and other files that had been remotely downloaded. Thank you all and have a wonderful weekend.

I'm glad you solved.

In addition you cannot perform a self extraction and you cannot perform a command like system('unzip html.zip'); from an ftp shell, nor from ftp_exec() because is chained to the FTP server interface, but you can change your approach:

  1. you first send a file (pong.php) to retrieve information of the remote system (Server2)
  2. basing on the received information you use a new ftp connection to send an archive to Server2, which can be for example: archive.zip or archive.php.gz
  3. use the newe retrieved informations to send a curl request to pong.php file so it can perform the extraction of the files

For the zip files you can use ZipArchive which is based on zip extension, for gz you need zlib library which is needed also by ZipArchive. While a zip can contain many files, gz can compress only single files, but you can use base64_encode() to convert file contents to strings, save them as an array inside a single file (archive.php.gz) and then perform an extraction.

Bye!

Sorry to bump but I forgot to mention that pong.php after been uploaded to Server2 should be queried from Server1 with an HTTP request, you can use it as RESTful service, so in your local form you have to ask not only for FTP path but also an HTTP link, something like: http://server2.tld/public_html/ so your application can perform: http://server2.tld/public_html/pong.php?request=info and use the answer for the other steps. An example flow could be this:

step 1

page1: form to insert FTP credentials
ftp_script: send pong.php to Server2 and redirect to page2

step 2

page2: retrieve information from Server2/pong.php
page2: use info to create options for the installation process, i.e. select which file to send
ftp_script: send archive.(zip|php.gz) to Server2 and redirect to page3

step 3

page3: retrieve info from Server2/pong.php and get md5 digest from local file
page3: check if local and remote digest are equal then write appropriate form: if false back to step 2 else go to next step
curl_script: curl request to Server2/pong.php to execute the extraction and output results to step4

step 4

page4: output final results and create actions to execute remote code

An example of pong.php:

<?php

    $output = array();

    if($_SERVER['REQUEST_METHOD'] == 'GET')
    {
        $action = isset($_GET['request']) ? $_GET['request']:false;
        switch($action)
        {
            case 'info':
                $output['version'] = PHP_VERSION;
                $output['os'] = PHP_OS;
                $output['zlib'] = extension_loaded('zlib') ? 'true':'false';
                $output['zip'] = class_exists('ZipArchive') ? 'true':'false';
                $output['writable'] = is_writable(getcwd()) ? 'true':'false';
                $output['document_root'] = $_SERVER['DOCUMENT_ROOT'];
                $output['files'] = glob('*',GLOB_MARK);
                $output['free_space'] = disk_free_space(getcwd());
            break;
            case 'digest':
                # get digest
                $file = pathinfo(parse_url($_GET['file'],PHP_URL_PATH),PATHINFO_BASENAME);

                if(file_exists($file) && is_file($file))
                {
                    $output['digest'] = md5_file($file);
                }
                else
                {
                    $output['error'] = 'file does not exists';
                }
            break;
            default:
                $output['request'] = 'arguments: info | digest';
                $output['file'] = 'argument: filename; request=digest is required';
        }
    }

    if($_SERVER['REQUEST_METHOD'] == 'POST')
    {
        # unzip
        function uncompress_gz($gzfile,$file)
        {
            $gzfp = gzopen($gzfile, "rb");
            $fp = fopen($file, "w");

            while ($string = gzread($gzfp, 4096))
            {
                fwrite($fp, $string, strlen($string));
            }
            fclose($fp);
            gzclose($gzfp);

            return true;
        }

        # create files from strings
        function writefiles($filename,$string)
        {
            $fp = fopen($filename,"w");
            $contents = base64_decode($string);
            fwrite($fp,$contents);
            fclose($fp);
            return true;
        }

        $file = pathinfo(parse_url($_POST['file'],PHP_URL_PATH));
        $type = $_POST['type'];
        $md5s = $_POST['digest'];

        if(file_exists($file['basename']) && md5_file($file['basename']) == $md5s && is_file($file['basename']))
        {
            switch($type)
            {
                case 'zip':
                    # zip
                    $output['method'] = 'zip';
                    $zip = new ZipArchive;
                    if ($zip->open($file['basename']) === TRUE) {
                        $zip->extractTo('.');
                        $zip->close();
                        $output['extraction'] = 'true';
                        $output['operation'] = 'accomplished';
                    } else {
                        $output['extraction'] = 'false';
                        $output['operation'] = 'not completed';
                    }
                break;
                case 'gz':
                    # uncompress
                    $output['method'] = 'gz';
                    uncompress_gz($file['basename'],$file['filename']);

                    # loop array to create the file
                    require 'archive.php';

                    foreach($archive as $filename => $string)
                    {
                        writefiles($filename,$string);
                    }
                    $output['extraction'] = 'true';
                    $output['operation'] = 'accomplished';
                break;
                default:
                    $output['extraction'] = 'false';
                    $output['operation'] = 'not completed';
            }
        }
        else
        {
            $output['error'] = 'the file does not exist or the checksum is wrong';
        }
        $output['files'] = glob('*',GLOB_MARK);
    }

    header('Content-Type: application/json');
    echo json_encode($output);

?>

An example of usage:

GET

http://server2.tld/public_html/pong.php?request=info
http://server2.tld/public_html/pong.php?request=digest&file=archive.php.gz

POST
// POST step3 of the previous flow: extract files
<form method="post" action="http://server2.tld/public_html/pong.php">
    <input type="text" name="file" value="archive.php.gz" /><br />
    <input type="text" name="type" value="gz" /><br />
    <input type="text" name="digest" value="<php echo md5_file('archive.php.gz');" /><br />
    <input type="submit" name="submit value="submit" />
</form>

And instead of doing a direct request you can perform a curl request from a local script and output results. Remember this is test code, is not good for production systems:

  1. do not include file_get_contents(), eval() or similar in pong.php to avoid arbitrary downloads and execution of code;
  2. filter data and create a system which checks for failed attemps to login, so to block brute force attacks to remote server from your application.

An example of archive.php:

<?php

    $archive = array(
        'file1.php' => 'PD9waHAgZWNobyAiaGVsbG8gd29ybGQiOyA/Pg==',
        'file2.php' => 'PD9waHAgZWNobyAidGVzdCBhcHBsaWNhdGlvbiI7ID8+',
        'file3.php' => 'PD9waHAgZWNobyAiaW5zdGFsbGF0aW9uIGNvbXBsZXRlZCI7ID8+'
    );

?>

Run gzip archive.php to get archive.php.gz. From this point it should be easy to create new cases in the switch statements to perform read, write, delete actions. I hope is clear and useful enough for you, bye!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.