Link to home
Start Free TrialLog in
Avatar of dialeradmin
dialeradmin

asked on

Download script error - Help. Filescan, server connection. PHP

Ok, so I thought I had the script completed, but when I tested it, it's not producing the results...

I have this download script that contains a form.  In this form, there is a drop down menu, and a textfield.  The drop down menu contains four different servers.  A user selects the server they wish to connect to, and they enter the filename+extension they wish to download.  When the submit button is clicked, the script should connect to the server that was selected in the drop down, and search for the file that was entered into the textfield.  If it is found, it should allow the user to download the file.  If it is not found, it should echo "File not found."

I have attached the script I have, hoping someone can help me figure out why it is not working.  When I type in an exact filename that is on the server I want to connect to, the result is always a page refresh.  Even if I type in a file that is not on the server.


download.php
========================
<?php
session_start();
include_once('log.php');

if (!isset($_SESSION['logged_in'] ))
{
    header("Location:access_denied.php");
}
require_once('db.php');
$targetServer = $_POST['select'];

// Retrieve the connection information from a database
$query = "SELECT ipAddress, Username, Password FROM serverList WHERE Server_name = '$targetServer' LIMIT 1";
$result = mysql_query($query);

if (mysql_num_rows($result))
{
   $data = mysql_fetch_object($result);

    // set up basic connection
   $conn_id = ftp_connect($data->ipAddress);

   // login with username and password
   $login_result = ftp_login($conn_id, $data->Username, $data->Password);
 
}

function findFile($conn_id, $folder, $filename)
{
        error_reporting(1);
      $results = array();
      $contents = ftp_nlist($conn_id, '.');
      foreach($contents AS $file)
      {
              if($file == '.' || $file == '..')
                  continue;
           if(ftp_chdir($conn_id,$file))
           {
                  $result = findFile($conn_id,$folder.'/'.$file,$filename);
                  if(is_array($result))
                  {
                        foreach($result AS $retval)
                        {
                              $results[] = $retval;
                        }
                  }
                  else if($result !== false)
                  {
                        $results[] = $result;
                  }
                  ftp_cdup($conn_id);
            }
            else
            {
                  if(strcmp($file,$filename)==0)
                  {
                        $results[] = $folder.'/'.$file;
                  }
            }
      }
      if(count($results)>0)
      {
            if(count($results)==1)
                  return $results[0];
            else
                  return $results;
      }
      else
            return false;
}

function download($conn_id, $filelocation)
{
      $tmp_file = substr(md5(time()),0,8);
      $handle = fopen($tmp_file, 'w');
      $filename = array_pop(split('/',$filelocation));
      $ext = array_pop(split('.',$filename));
      if(ftp_fget($conn_id, $handle, $filelocation, FTP_BINARY, 0))
      {
                 $filesize = filesize($tmp_file);
           header('content-disposition: attachment; filename='.$filename);
           header('Content-Type: content='.$ext);
           header('Content-Length: '.$filesize);
           readfile($tmp_file);
               unlink($tmp_file);
           return $filesize;
      }
      else
        {
                 unlink($tmp_file);
           return "Download failed";
        }
}

function connectFindDownload($ftp_server, $ftp_user, $ftp_pass, $filename, $folder = '.')
{
      $conn_id = ftp_connect($ftp_server);
      $login_result = ftp_login($conn_id, $ftp_user, $ftp_pass);
      if(!$login_result)
      {
            return "connection failed";
      }
      else
      {
            ftp_chdir($conn_id,$folder);
            $filelocations = findFile($conn_id, $folder, $filename);
            if($filelocations != false)
            {
                  if(is_array($filelocations))
                  {
                        $filelocations = $filelocations[0];
                  }
                  if($folder != '.')
                        $filelocations = str_replace($folder.'/','',$filelocations);
                  return download($conn_id, $filelocations);
            }
            else
                  return "File not found";
      }
      ftp_close($conn_id);
}

findFile($conn_id, $folder, $filename);
download($conn_id, $filelocation);
connectFindDownload($ftp_server, $ftp_user, $ftp_pass, $filename, $folder = '.');
?>
Avatar of glcummins
glcummins
Flag of United States of America image

>> When I type in an exact filename that is on the server I want to connect to, the result is always a page refresh.

The form that receives the filename is not included in the script you posted above. It sounds like the action= attribute of the form on that page may be incorrect, or there is some Javascript that is interferring with a proper submit.

If you are unable to find the problem easily, can you post the HTML form that receives this information so that we can troubleshoot further?
Avatar of dialeradmin
dialeradmin

ASKER

Yeah, sure.
Here is the form that I am using.  Also, I do have a small snippet of Javascript on the page, but it shouldn't interfere (It's just a small time-out script)...

FORM
===================
<form name="form1" method="post" action="">
                     
              <p align="left"></p>
                      <table width="100%">
                       
                <tr>
                  <td width="30%">&nbsp;</td>
                  <td width="40%" rowspan="6" align="center" valign="top">
                    <div align="center">
                      <table width="75%">
                        <tr>
                         
                        </tr>
                      </table>
                    </div></td>
                          <td width="30%" rowspan="6">&nbsp;</td>
                        </tr>
                        <tr>
                          <td><font color="#FF0000" size="-2" face="Arial, Helvetica, sans-serif">Select
                            Dialer:</font></td>
                        </tr>
                        <tr>
                          <td><select name="select" id="select">
                      <option value="Dialer 1">Dialer 1</option>
                      <option value="Dialer 2">Dialer 2</option>
                      <option value="Dialer 3">Dialer 3</option>
                      <option value="Dialer 4">Dialer 4</option>
                    </select></td>
                        </tr>
                        <tr>
                         
                  <td><font color="#FF0000" size="-2" face="Arial, Helvetica, sans-serif">Filename
                    (<font color="#000000">with</font> <font color="#000000">extension</font>):</font></td>
                        </tr>
                        <tr>
                          <td><input name="filename" type="text" id="filename"></td>
                        </tr>
                        <tr>
                          <td><input type="submit" name="Submit" value="Retrieve file"></td>
                        </tr>
                      </table>
                   </p>
                    </form>
Here's the problem:

<form name="form1" method="post" action="">

You have no action, so nowhere for the form to post. You should change so that your PHP script is the 'action' (target) of the form.
Ok.  I tried that.  I inserted download3.php into action=""...but nothing changed.  Still the same result.
Instead of putting download3.php in action, do I need to put the whole url address to the file?  For example, /directorylocation/download3.php?
Yes, if download3.php is not in the same directory as your HTML document, you will need to specify the path.
Oh.  Well, my HTML is included in the same file as the PHP, FORM, etc...So I'm still confused as why the script is not working properly.
Is there a way to test if a connection is even being made to the server?
 - For example, what could I possibly place throughout my code to go, if statement to if statement, until I found the one that is not working???

Thanks
If the form is simply being refreshed, then your PHP script is never being called. I see nothing in your PHP script that re-calls the form if something fails. You will first need to determine what is wrong with the form before adding troubleshooting lines to the script.

You can take a look at your server logs to see what pages are being requested. Watch the logs as you submit the form, and see what files are being returned to the browser. This will give you a good starting point.

After you have determined that the script is indeed being called, there is a nice troubleshooting method that you can use:

At the top of your script, just after the <?php line, add the following line:

define('DEBUG', 1);

Then, at any point in your script, you can add lines like:

DEBUG and print("Entering first loop.<br />");

The define() statement defines a constant called 'DEBUG' and sets it's value to '1'. Each time you use a 'DEBUG and <whatever>' statement, the PHP interpreter checks to see if DEBUG has a non-zero value. If so, the rest of the statement is executed.

This method is handy when adding troubleshooting lines that you don't want the end user to see. When your application is ready for real life, you simply change the first line to:

define('DEBUG', 0);

Now, none of the 'DEBUG and <whatever>' statements will be executed, because the value of 'DEBUG' is 0. You don't have to worry about removing each of the debugging lines manually. You can still remove them to keep your code clean, but if you happen to miss one, the end user will never see it.
You are not implementing these functions correctly. The only function that needs to be called is "connectFindDownload" which will in turn will log in to the server and call the other 2 as needed.

Here is the correct implementation:

if (mysql_num_rows($result))
{
   $data = mysql_fetch_object($result);
   connectFindDownload($data->ipAddress, $data->Username, $data->Password, $_POST['filename']);
}

Remove these lines:
findFile($conn_id, $folder, $filename);
download($conn_id, $filelocation);
connectFindDownload($ftp_server, $ftp_user, $ftp_pass, $filename, $folder = '.');
By the way, if you limit the function to just the particular folder where the file is likely to be located, you can greatly speed up the performance. Searching an entire server over an ftp connection is something like the very opposite of efficient.
Alright.  I changed that last part where I call the functions.  When I test the script now, here is the error I receive after the submit button is clicked.

"Warning: ftp_connect() [function.ftp-connect]: php_network_getaddresses: getaddrinfo failed: Name or service not known in /opt/lampp/htdocs/dialer/download3.php on line 97

Warning: ftp_login() expects parameter 1 to be resource, boolean given in /opt/lampp/htdocs/dialer/download3.php on line 98"
Ok, are you able to connect to your ftp server by simply typing "ftp://[user]:[pass]@[server]" into your browser?

If yes, then echo the value for $data->ipAddress to make sure you're connecting to the same server you think you're connecting to.

If no, then your problem does not lie in php. Your server simply isn't accepting connections and you should pose your question with the server and network zone experts.
Alright.  I tried connecting to the server through the browser.  I was able to get a connection, but I could only access the main directory it placed me in after I logged in.  I tried typing in different directories I have access to when I connect through an SFTP client, but I was refused access.  I couldn't access any other directory besides the main one.

I guess this is a security feature my server is using, since connecting through a browser uses ftp and not sftp?
This is the first I have heard in this thread that you are using sftp. That is an entirely different protocol as ftp, and the connection method is different. Do you require an sftp connection via your script?
well, the servers i need to connect to via drop-down menu will need to use sftp since I won't be given full privileges unless i log in through sftp...

so, as far as my script, i don't think i require an sftp???  I just figured you could connect the same was as if it was ftp.  I guess not.

I'll post my code again, hoping there is not too much changes that need to take place in order to switch from ftp connection to sftp...

 - Can I still have each server stored in my SQL database with the ipAddress, Username, Password???
Here is what I have now...I connect through database lookup...Should I change something in my database where I have the server information stored???

download.php
======================================
<?php
session_start();
include_once('log.php');

if (!isset($_SESSION['logged_in'] ))
{
    header("Location:access_denied.php");
}
require_once('db.php');
$targetServer = $_POST['select'];

// Retrieve the connection information from a database
$query = "SELECT ipAddress, Username, Password FROM serverList WHERE Server_name = '$targetServer' LIMIT 1";
$result = mysql_query($query);

if (mysql_num_rows($result))
{
   $data = mysql_fetch_object($result);

    // set up basic connection
   $conn_id = ftp_connect($data->ipAddress);

   // login with username and password
   $login_result = ftp_login($conn_id, $data->Username, $data->Password);
 
}

function findFile($conn_id, $folder, $filename)
{
        error_reporting(1);
      $results = array();
      $contents = ftp_nlist($conn_id, '.');
      foreach($contents AS $file)
      {
              if($file == '.' || $file == '..')
                  continue;
           if(ftp_chdir($conn_id,$file))
           {
                  $result = findFile($conn_id,$folder.'/'.$file,$filename);
                  if(is_array($result))
                  {
                        foreach($result AS $retval)
                        {
                              $results[] = $retval;
                        }
                  }
                  else if($result !== false)
                  {
                        $results[] = $result;
                  }
                  ftp_cdup($conn_id);
            }
            else
            {
                  if(strcmp($file,$filename)==0)
                  {
                        $results[] = $folder.'/'.$file;
                  }
            }
      }
      if(count($results)>0)
      {
            if(count($results)==1)
                  return $results[0];
            else
                  return $results;
      }
      else
            return false;
}

function download($conn_id, $filelocation)
{
      $tmp_file = substr(md5(time()),0,8);
      $handle = fopen($tmp_file, 'w');
      $filename = array_pop(split('/',$filelocation));
      $ext = array_pop(split('.',$filename));
      if(ftp_fget($conn_id, $handle, $filelocation, FTP_BINARY, 0))
      {
                 $filesize = filesize($tmp_file);
           header('content-disposition: attachment; filename='.$filename);
           header('Content-Type: content='.$ext);
           header('Content-Length: '.$filesize);
           readfile($tmp_file);
               unlink($tmp_file);
           return $filesize;
      }
      else
        {
                 unlink($tmp_file);
           return "Download failed";
        }
}

function connectFindDownload($ftp_server, $ftp_user, $ftp_pass, $filename, $folder = '.')
{
      $conn_id = ftp_connect($ftp_server);
      $login_result = ftp_login($conn_id, $ftp_user, $ftp_pass);
      if(!$login_result)
      {
            return "connection failed";
      }
      else
      {
            ftp_chdir($conn_id,$folder);
            $filelocations = findFile($conn_id, $folder, $filename);
            if($filelocations != false)
            {
                  if(is_array($filelocations))
                  {
                        $filelocations = $filelocations[0];
                  }
                  if($folder != '.')
                        $filelocations = str_replace($folder.'/','',$filelocations);
                  return download($conn_id, $filelocations);
            }
            else
                  return "File not found";
      }
      ftp_close($conn_id);
}

if (mysql_num_rows($result))
{
   $data = mysql_fetch_object($result);
   connectFindDownload($data->ipAddress, $data->Username, $data->Password, $_POST['filename']);
}
ASKER CERTIFIED SOLUTION
Avatar of MasonWolf
MasonWolf
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I confess I'm out of my depth when it comes to sftp though. My advice may be wildly inaccurate, so if glcummins says to do different, please take his word over mine.
There are a number of dedicated SSH-related functions. Take a look at http://www.php.net/manual/en/function.ssh2-tunnel.php for starters, and then at the ftp-specific function (ssh2-sftp). This will definitely require some additional study on your part to make this connection work.
@glcummins:

Is what he wants to do even possible with php? I don't know and I don't pretend to, but I'm very curious for the sake of my own applications.
Here is an example of how to send a file via SFTP (copied verbatim from ): http://www.php.net/manual/en/function.ssh2-sftp.php

<?php

class SFTPConnection
{
    private $connection;
    private $sftp;

    public function __construct($host, $port=22)
    {
        $this->connection = @ssh2_connect($host, $port);
        if (! $this->connection)
            throw new Exception("Could not connect to $host on port $port.");
    }

    public function login($username, $password)
    {
        if (! @ssh2_auth_password($this->connection, $username, $password))
            throw new Exception("Could not authenticate with username $username " .
                                "and password $password.");

        $this->sftp = @ssh2_sftp($this->connection);
        if (! $this->sftp)
            throw new Exception("Could not initialize SFTP subsystem.");
    }

    public function uploadFile($local_file, $remote_file)
    {
        $sftp = $this->sftp;
        $stream = @fopen("ssh2.sftp://$sftp$remote_file", 'w');

        if (! $stream)
            throw new Exception("Could not open file: $remote_file");

        $data_to_send = @file_get_contents($local_file);
        if ($data_to_send === false)
            throw new Exception("Could not open local file: $local_file.");

        if (@fwrite($stream, $data_to_send) === false)
            throw new Exception("Could not send data from file: $local_file.");

        @fclose($stream);
    }
}

try
{
    $sftp = new SFTPConnection("localhost", 22);
    $sftp->login("username", "password");
    $sftp->uploadFile("/tmp/to_be_sent", "/tmp/to_be_received");
}
catch (Exception $e)
{
    echo $e->getMessage() . "\n";
}
@MasonWolf: Everything is possible in PHP. The only question is how many ways you want to stand on your head to achieve the result. :)
@glcummins,
I looked at the php.net website under the ssh2 functions, and I didn't see anything that looked like scanning a directory. Do you happen to know if the standard ftp file-system navigation functions will work once the sftp connection has been established? If so, then only the connectFindDownload and download functions will need to be modified.
sooooo.......

...couple things...First of all, I was told the connection to my server should use sftp.  so, i'll have to look into the ssh2-sftp functions...

also, and besides the point...i have an upload script that was needing to connect via sftp connection as well...the script you posted a few posts ago that is a send file script...would that work as far as an sftp upload script goes?  What information would I have to change in order to use my database information to connect???  Also, is that script uploading to a certain directory?  

Thanks so far for your help Mason and glscummins!!!
>>the script you posted a few posts ago that is a send file script...would that work as far as an sftp upload script goes

The terms "send file" and "upload"  refer to the same process: moving a file from your server to another server.

>> What information would I have to change in order to use my database information to connect
The information should be identical: server name or address, username, password.

>> is that script uploading to a certain directory
 You specify the directory to which the file will be uploaded. Look at the the following line:

        $stream = @fopen("ssh2.sftp://$sftp$remote_file", 'w');

$sftp will contain the server address, and $remote_file will contain the full destination path of your file.

The script that glcummins posted should work to upload a file, yes. Use the function calls at the bottom of that code to connect, replacing it with your own connection information from the database. Change the code where appropriate to fit your script.
try
{
    $sftp = new SFTPConnection($data->ipAddress, 22);
    $sftp->login($data->user, $data->pass);
    $sftp->uploadFile($_FILES['uploadFile']['tmp_name'], "/uploads/".$_FILES['uploadFile']['name']);
}
catch (Exception $e)
{
    echo $e->getMessage() . "\n";
}
Ok...I understand that I must match the server information with mine.  It's just, since I am using a drop-down menu which contains four different servers...How will I store the $host or $username/$password information into those variables depending on which server is selected from the drop down?  


 - And as for this statement:
$stream = @fopen("ssh2.sftp://$sftp$remote_file", 'w');
 - How will I place a certain server selected from the drop down into $sftp?
As stated above, the variable $sftp contains the server name or IP address. You will simply select the appropriate server name or IP address from your database record, and store that value in $sftp.
Oh...
Is the $this-> grabbing whatever value is selected in the drop down???
"$sftp = $this->sftp;"

- So if I wanted to change where a file was copied to on my server, I could change this statement to say:

$stream = @fopen("ssh2.sftp://$sftp/opt/avaya/pds/xfer/dhc/$remote_file", 'w');
You won't need to touch that particular statement "$stream = @fopen...". Just copy the code in its entirety into your upload script (or into a new file and use "include" or "require") and then use the lines I pasted earlier, changing the values as needed to fit your particular script:

try
{
    $sftp = new SFTPConnection($data->ipAddress, 22);
    $sftp->login($data->Username, $data->Password);
    $sftp->uploadFile($_FILES['uploadFile']['tmp_name'], "/uploads/".$_FILES['uploadFile']['name']);
}
catch (Exception $e)
{
    echo $e->getMessage() . "\n";
}

As for selecting a particular server from the database, just change your query to:

$query = "SELECT ipAddress, Username, Password FROM serverList WHERE Server_name = '$_POST[select]' LIMIT 1";
Ok...So something like this?  sorry if things just aren't clicking...I just started PHP a few weeks ago and it's been hard to soak it all in in such a quick period of time.  Is this code supposed to be seperate with my form?  Or are you talking about incorporating this code into my upload script that I have in my other Open question?  Again, thanks for your help!

upload.php
==================
<?php
session_start();

if (!isset($_SESSION['logged_in'] ))
{
    header("Location: access_denied.php");
}

if ($_SESSION['Level_access'] > 2 )
{
    header('Location: access_denied.php');
}

require_once('db.php');
include_once('log.php');

class SFTPConnection
{
    private $connection;
    private $sftp;

    public function __construct($host, $port=22)
    {
        $this->connection = @ssh2_connect($host, $port);
        if (! $this->connection)
            throw new Exception("Could not connect to $host on port $port.");
    }

    public function login($username, $password)
    {
        if (! @ssh2_auth_password($this->connection, $username, $password))
            throw new Exception("Could not authenticate with username $username " .
                                "and password $password.");

        $this->sftp = @ssh2_sftp($this->connection);
        if (! $this->sftp)
            throw new Exception("Could not initialize SFTP subsystem.");
    }

    public function uploadFile($local_file, $remote_file)
    {
        $sftp = $this->sftp;
        $stream = @fopen("ssh2.sftp://$sftp$remote_file", 'w');

        if (! $stream)
            throw new Exception("Could not open file: $remote_file");

        $data_to_send = @file_get_contents($local_file);
        if ($data_to_send === false)
            throw new Exception("Could not open local file: $local_file.");

        if (@fwrite($stream, $data_to_send) === false)
            throw new Exception("Could not send data from file: $local_file.");

        @fclose($stream);
    }
}

try
{
    $sftp = new SFTPConnection($data->ipAddress, 22);
    $sftp->login($data->Username, $data->Password);
    $sftp->uploadFile($_FILES['uploadFile']['tmp_name'], "/uploads/".$_FILES['uploadFile']['name']);
}
catch (Exception $e)
{
    echo $e->getMessage() . "\n";
}
?>
See my post on your other question