FTP vs move_uploaded_file()
Moderator: General Moderators
- Buddha443556
- Forum Regular
- Posts: 873
- Joined: Fri Mar 19, 2004 1:51 pm
FTP vs move_uploaded_file()
I'm trying to decide how much trouble to goto for a HTTP file upload. Should I just use move_uploaded_file() or should I move the file using FTP? There are of course many pros and cons to each approach. I have shared accounts on servers running phpsuexec and mod_php. So, file ownership is somewhat of an issue for me. While FTP would solve ownership issues, I find myself concerned about the consequences of the added complexity.
I would like to know which approach my fellow member here use or recommend? Anyone using FTP to move upload files?
Thanks,
Buddha
I would like to know which approach my fellow member here use or recommend? Anyone using FTP to move upload files?
Thanks,
Buddha
Why not use move_uploaded_file() and then chown(), chmod(), and/or chgrp() for the ownership/permissions issues? 
But I feel that there might be a issues if the shared accounts don't naturally have the ability to freely transfer files together.
But I feel that there might be a issues if the shared accounts don't naturally have the ability to freely transfer files together.
- feyd
- Neighborhood Spidermoddy
- Posts: 31559
- Joined: Mon Mar 29, 2004 3:24 pm
- Location: Bothell, Washington, USA
there is a scenario where the php user doesn't have permission to do so, thus needing an alternative, such as FTP. Although, in my experience, FTP would be disabled long before php's user wouldn't have permission to write to it's own locales. There's always storage in the database, but we all know the cons on that baby..
- Buddha443556
- Forum Regular
- Posts: 873
- Joined: Fri Mar 19, 2004 1:51 pm
Yep, it's an issue. chmod() is pretty much the only option usually on shared servers. Which means you wind up with 0777 files and directories owned by nobody.Why not use move_uploaded_file() and then chown(), chmod(), and/or chgrp() for the ownership/permissions issues? Smile
But I feel that there might be a issues if the shared accounts don't naturally have the ability to freely transfer files together.
That's a good point. I checked my reseller accounts and all four of my host have FTP enabled. Now a couple of them I've been with more than a year [one host 4+ years] so I'm thinking FTP might not be a big risk. [At least, not as big as some shared servers.] This also brought to mind that one of my host is heavily firewalled but this usually prevent incoming requests. I should be able to use loopback (127.0.0.1) for the FTP operations. That would also eliminate DNS lookup which is always slow on shared servers too. This might actually work.feyd wrote:Although, in my experience, FTP would be disabled long before php's user wouldn't have permission to write to it's own locales.
Thanks,
Buddha
- Buddha443556
- Forum Regular
- Posts: 873
- Joined: Fri Mar 19, 2004 1:51 pm
- Buddha443556
- Forum Regular
- Posts: 873
- Joined: Fri Mar 19, 2004 1:51 pm
That special IP, 127.0.0.1, that has no hardware associated with it or a physical connection to the network.pilau wrote:What is a loopback?Buddha443556 wrote:Know what I said about loopback ... forget it. Not a good idea on cPanel.
Need to use my domain for the FTP operation even though it's not really going anywhere ... sort of like a loopback.
Quite sometime ago I ran into problems with some PHP installs, the exact problems escape me but there was various file permission problems and FTP seemed like the best solution.
I wrote a filesystem2FTP type class which solved my problems. Not sure if it's of any use as I did very little testing other than for my specific cases but you are free to use it, bits of it or completely ignore it (I've tacked a couple of usage examples on the end, note they are examples only and in no way constitute working secure scripts)...
Example 1....
Example 2....
I wrote a filesystem2FTP type class which solved my problems. Not sure if it's of any use as I did very little testing other than for my specific cases but you are free to use it, bits of it or completely ignore it (I've tacked a couple of usage examples on the end, note they are examples only and in no way constitute working secure scripts)...
Code: Select all
<?php
/******************************************************************************
* filename fs2ftp.cls.php
*
* description performs many common file systems functions via FTP to
* circumvent permissions problems on many PHP installations
*
* project none
*
* author redmonkey
*
* version 0.1
*
* license GPL, the GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html
*
* copyright 2005 redmonkey, all rights reserved
*
* license GPL
*
* notes this is not a FTP class
*
* notes reqiures that PHP's FTP functions are enabled
*
* file history
* ============
* 03/01/2004 v0.1 initial version
*
* notice this program is free software, you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version
*
* notice this program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details
******************************************************************************/
/******************************************************************************
* the predefined constant DIRECTORY_SEPARATOR became available from PHP
* version 4.3.x (I think) so make it available for earlier versions
******************************************************************************/
if (!defined('DIRECTORY_SEPARATOR'))
{
/****************************************************************************
* has PHP_OS always been avilable? perhaps php_uname might be a better option
****************************************************************************/
switch(strtolower(substr(PHP_OS, 0, 3)))
{
case 'win':
define('DIRECTORY_SEPARATOR', '\\');
break;
/**************************************************************************
* blatant assumption that everything else uses '/'
**************************************************************************/
default :
define('DIRECTORY_SEPARATOR', '/');
break;
}
}
class fs2ftp
{
var $ftpserver; // your FTP server (usually localhost)
var $ftpuser; // your FTP username
var $ftppass; // your FTP password
var $ftproot; // full path from root of filesystem to root of your FTP server
var $passive; // set passive mode when connecting
var $conn_id; // connection id returned by ftp_connect
/**
* @return
* @param string _user your logon FTP username
* @param string _pass your FTP password
* @param string _root the full path from the root of the filesystem to the
* root of your FTP server (e.g. if your webserver root
* is /home/user/public_html then your FTP server root
* will most likely be /home/user
* @param string _server location of your FTP server (recommend using 'localhost')
* @param bool _pasv set passive mode on (true) or off (false)
* @desc constructor, initialise class variables and set users
* FTP connection details, this does not connect to the
* FTP server
*/
function fs2ftp($_user, $_pass, $_root, $_server = false, $_pasv = false)
{
if (!$this->ftproot = realpath($_root))
{
trigger_error('Failed to resolve FTP root path ' . $this->ftpserver, E_USER_ERROR);
return false;
}
$this->ftpserver = $_server == false ? 'localhost' : $_server; // FTP server address
$this->ftpuser = $_user; // FTP username
$this->ftppass = $_pass; // FTP password
$this->passive = $_pasv; // set passive mode on (true) off (false)
$this->conn_id = false; // connection id resource handle
}
/**
* @return bool true on success false otherwise
* @desc establish a connection and login to the FTP server
*/
function connect()
{
if ($this->conn_id != false)
{
return true;
}
if (!$this->conn_id = @ftp_connect($this->ftpserver))
{
trigger_error('Failed to connect to ' . $this->ftpserver, E_USER_WARNING);
return false;
}
if (!$this->_login())
{
return false;
}
if ($this->passive == true)
{
if (!$this->set_passive(true))
{
trigger_error('Failed to initialize passive mode', E_USER_WARNING);
return false;
}
}
return true;
}
/**
* @return bool true on success false otherwise
* @desc establish a login to the FTP server
*/
function _login()
{
if (@ftp_login($this->conn_id, $this->ftpuser, $this->ftppass));
{
return true;
}
$this->conn_id = false;
trigger_error('Failed to login to ' . $this->ftpserver . ' with username ' . $this->ftpuser, E_USER_WARNING);
return false;
}
/**
* @return bool true on success false otherwise
* @desc closes the connection to the FTP server
*/
function quit()
{
if (!$this->conn_id || !@ftp_quit($this->conn_id))
{
trigger_error('Connection already closed', E_USER_NOTICE);
return false;
}
$this->conn_id = false;
return true;
}
/**
* @return bool true on success false otherwise
* @param string _dir directory to create
* @desc creates a directory and sets permissions
*/
function mk_dir($_dir, $_mode = null)
{
if (!$this->connect())
{
$error_msg = 'Failed to create directory (' . $_dir . ') FTP server has gone away';
trigger_error($error_msg, E_USER_WARNING);
return false;
}
if (!$parent = realpath(dirname($_dir)))
{
trigger_error('Failed to create directory (' . $_dir . ') parent directory does not exist', E_USER_WARNING);
return false;
}
if (file_exists($parent . DIRECTORY_SEPARATOR . basename($_dir)))
{
$error_msg = 'Failed to create directory (' . $_dir . ') a file ';
$error_msg .= 'or directory with that name already exists';
trigger_error($error_msg, E_USER_WARNING);
return false;
}
$dir = str_replace($this->ftproot, '', $parent . DIRECTORY_SEPARATOR . basename($_dir));
if (!@ftp_mkdir($this->conn_id, $dir))
{
trigger_error('Failed to create directory (' . $_dir . ')', E_USER_WARNING);
return false;
}
if (!is_null($_mode))
{
return $this->ch_mod($_dir, $_mode);
}
return true;
}
/**
* @return bool true on success false otherwise
* @param string _file file to set permissions on
* @desc sets permissions on _file
*/
function ch_mod($_file, $_mode)
{
if (!$this->connect())
{
$error_msg = 'Failed to set permissions on (' . $_file . ') FTP server has gone away';
trigger_error($error_msg, E_USER_WARNING);
return false;
}
if (!$file = realpath($_file))
{
trigger_error('Failed to set permissions on (' . $_file . ') no such file or directory', E_USER_WARNING);
return false;
}
$file = str_replace($this->ftproot, '', $file);
if (!@ftp_site($this->conn_id, 'CHMOD ' . decoct($_mode) . ' ' . $file))
{
trigger_error('Failed to set permissions on (' . $_file . ')', E_USER_WARNING);
return false;
}
return true;
}
/**
* @return bool true on success false otherwise
* @param string _file file to remove
* @desc deletes _file
*/
function rm($_file)
{
if (!$this->connect())
{
$error_msg = 'Failed to delete file (' . $_file . ') FTP server has gone away';
trigger_error($error_msg, E_USER_WARNING);
return false;
}
if (!$file = realpath($_file))
{
trigger_error('Failed to delete file (' . $_file . ') no such file exists', E_USER_WARNING);
return false;
}
$file = str_replace($this->ftproot, '', $file);
if (!@ftp_delete($this->conn_id, $file))
{
trigger_error('Failed to delete file (' . $_file . ')', E_USER_WARNING);
return false;
}
return true;
}
/**
* @return bool true on success false otherwise
* @param string _dir directory to remove
* @desc deletes _dir
*/
function rm_dir($_dir)
{
if (!$this->connect())
{
$error_msg = 'Failed to remove directory (' . $_dir . ') FTP server has gone away';
trigger_error($error_msg, E_USER_WARNING);
return false;
}
if (!$dir = realpath($_dir))
{
trigger_error('Failed to delete directory (' . $_dir . ') no such directory exists', E_USER_WARNING);
return false;
}
$dir = str_replace($this->ftproot, '', $dir);
if (!@ftp_rmdir($this->conn_id, $dir))
{
trigger_error('Failed to remove directory (' . $_dir . ')', E_USER_WARNING);
return false;
}
return true;
}
/**
* @return bool true on success false otherwise
* @param string _source file to copy
* @param string _destination destination including filename of the copied file
* @param int _mode transfer mode (either FTP_BINARY or FTP_ASCII)
* @desc copies the file specied by _source to _destination
*/
function cp($_source, $_destination, $_mode = FTP_BINARY)
{
if (!$this->connect())
{
$error_msg = 'Failed to copy file (' . $_source . ') FTP server has gone away';
trigger_error($error_msg, E_USER_WARNING);
return false;
}
if (!$ddir = realpath(dirname($_destination)))
{
trigger_error('Failed to copy file (' . $_source . ') destination directory does not exist', E_USER_WARNING);
return false;
}
$destination = str_replace($this->ftproot, '', $ddir . DIRECTORY_SEPARATOR . basename($_destination));
if (!@ftp_put($this->conn_id, $destination, $_source, $_mode))
{
trigger_error('Failed to copy file (' . $_source . ')', E_USER_WARNING);
return false;
}
return true;
}
/**
* @return bool true on success false otherwise
* @param string _source file to move
* @param string _destination destination including filename of the moved file
* @param int _mode transfer mode (either FTP_BINARY or FTP_ASCII)
* @desc moves a file specied by _source to _destination
*/
function mv($_source, $_destination)
{
if (!$this->connect())
{
$error_msg = 'Failed to copy file (' . $_source . ') FTP server has gone away';
trigger_error($error_msg, E_USER_WARNING);
return false;
}
if (!$source = realpath($_source))
{
trigger_error('Failed to move (' . $_source . ') source file does not exist', E_USER_WARNING);
return false;
}
if (!$ddir = realpath(dirname($_destination)))
{
trigger_error('Failed to move (' . $_source . ') destination directory does not exist', E_USER_WARNING);
return false;
}
$source = str_replace($this->ftproot, '', $source);
$destination = str_replace($this->ftproot, '', $ddir . DIRECTORY_SEPARATOR . basename($_destination));
if (!@ftp_rename($this->conn_id, $source, $destination))
{
trigger_error('Failed to move (' . $_source . ')', E_USER_WARNING);
return false;
}
return true;
}
/**
* @return bool true on success false otherwise
* @param bool _mode true to turn passive mode on, false for off
* @desc turns passive mode connection on or off
*/
function set_passive($_mode = true)
{
if (!$this->connect())
{
return false;
}
return @ftp_pasv($this->conn_id, $_mode);
}
}
?>Code: Select all
<?php
include('./includes/fs2ftp.cls.php');
$FTP = &new fs2ftp('username', 'password', '/path/to/ftproot');
// making a directory and setting permissions
$FTP->mk_dir('testing', 0777);
// copying a file
$FTP->cp('ftpexample.ex1.php', 'testing/ftpexample.copy.ex1.php');
// create a file in the temp directory then move it
$file = tempnam(null, 'rm_');
$fp = fopen($file, 'wb');
fwrite($fp, 'some text');
fclose($fp);
$FTP->mv($file, 'testfile.txt');
unlink($file);
$FTP->quit();
?>Code: Select all
<?php
//full path to upload directory (no trailing slashes)
$dir = '/full/path/to/upload/directory'; //Change this to the correct dir
//allowed MIME types
$types = array("image/gif","image/jpeg");
if(isset($_POST['submit']))
{
$uploaded = false;
$tmp_name = $_FILES['upload']['tmp_name'];
$new_name = $_FILES['upload']['name'];
//check MIME
if (in_array($_FILES['upload']['type'], $types))
{
//move file from tmp dir to upload directory
if (is_uploaded_file($tmp_name))
{
//Load up filesystem via FTP class
require('./includes/fs2ftp.cls.php');
$FTP = &new fs2ftp('username', 'password', '/path/to/ftproot');
if ($FTP->cp($tmp_name, $dir . '/' . $new_name))
{
$FTP->quit();
$uploaded = true;
}
}
}
if (!$uploaded)
{
// show error
echo "<small>File <strong><em></em></strong> Was Not Uploaded!</small><br />";
$name = $_FILES['upload']['name'];
$type = $_FILES['upload']['type'];
$size = $_FILES['upload']['size'];
$tmp = $_FILES['upload']['name'];
echo "Name: $name<br/ >Type: $typ<br />Size: $size<br />Tmp: $tmp";
}
else
{
echo " was uploaded sucessfully!";
}
}
?>
<form action="upload.php" method="post" enctype="multipart/form-data">
<fieldset>
<legend>Upload Files</legend>
<input type="file" name="upload" />
</fieldset>
<input type="submit" name="submit" value="Upload Files" />
</form>- Buddha443556
- Forum Regular
- Posts: 873
- Joined: Fri Mar 19, 2004 1:51 pm
Thanks redmonkey.
Think I'll play with this a little more first:
Found it in the Manual, seem to be working pretty well on my development server so far. Trying it out on imagejpeg() now. <crossing fingers>
EDIT: Same technique doesn't seem to work on imagejpeg().
Think I'll play with this a little more first:
Code: Select all
move_uploaded_file($_FILES['upload']['tmp_name'], 'ftp://user:password@ftp.server.com/'.$new_filename);EDIT: Same technique doesn't seem to work on imagejpeg().
- Buddha443556
- Forum Regular
- Posts: 873
- Joined: Fri Mar 19, 2004 1:51 pm
I'm doubting the reliability of the FTP wrapper too. At least on Windows anyway. Seems to disconnect from the FTP server before the transfer is complete. Using ftp_fput() seems to be much more reliable solution. Live and learn.redmonkey wrote:Definately a far easier option if it works for you. I had problems with that in the past, quite sometime ago now so may be more reliable now, or perhaps it was my setup/server?
I don't think I've ever had any call to use ftp_fput, I've never had any issues with ftp_put on either Windows, OS X or *nix servers. Having said that, I don't really use it that often.
I've started looking at using cURL for FTP transfers, it's a bit of an ugly library but for the most part it's working OK.
I've started looking at using cURL for FTP transfers, it's a bit of an ugly library but for the most part it's working OK.