Rationale
Prevent having to use raw FTP functions, make common use-cases easier.
Functionality
FtpEntry base class
At the moment, an FtpEntry represents a file, and an FtpDir (which extends
FtpEntry) represents a directory. This poses several limitations on what
can be in the FtpEntry class and makes it harder to distinguish them from
each other.
New layout:
abstract class FtpEntry extends Object {
}
class FtpFile extends FtpEntry {
}
class FtpDir extends FtpEntry {
}
FtpEntryList class
class FtpEntryList extends Object implements IteratorAggregate {
/**
* Returns an iterator for use in foreach()
*
* @see php://language.oop5.iterations
* @return php.Iterator
*/
public function getIterator() {
}
/**
* Returns the number of elements in this list.
*
* @return int
*/
public function size() {
}
/**
* Tests if this list has no elements.
*
* @return bool
*/
public function isEmpty() {
}
/**
* Returns all elements in this list as an array.
*
* @return peer.ftp.FtpEntry[] an array of all entries
* @throws peer.SocketException in case of an I/O error
*/
public function asArray() {
}
}
New methods
peer.ftp.FtpConnection:
class FtpConnection extends Object {
/**
* Returns an FtpDir instance representing this connection's
* root directory
*
* @return peer.ftp.FtpDir the instance
* @throws peer.SocketException in case of an I/O error
*/
public function rootDir() {
}
/**
* Sends a raw command to the FTP server and returns the server's
* response (unparsed) as an array of strings.
*
* Accepts a command which will be handled as format-string for
* further arbitrary arguments, e.g.:
*
* $c->sendCommand('CLNT %s', $clientName);
*
* @param string command
* @param string* args
* @return string[] result
* @throws peer.SocketException in case of an I/O error
*/
public function sendCommand($command) {
}
}
peer.ftp.FtpEntry:
abstract class FtpEntry {
/**
* Checks whether this entry exists.
*
* @return bool TRUE if the file exists, FALSE otherwise
* @throws peer.SocketException in case of an I/O error
*/
public function exists() {
}
/**
* Rename this entry
*
* @param string to the new name
* @throws io.IOException if an entry by the new name already exists
* @throws peer.SocketException in case of an I/O error
*/
public function rename($to) {
}
/**
* Change this entry's permissions
*
* @param int to the new permissions
* @throws io.IOException if an entry by the new name already exists
* @throws peer.SocketException in case of an I/O error
*/
public function changePermissions($to) {
}
/**
* Delete this entry
*
* @throws peer.SocketException in case of an I/O error
*/
public abstract function delete();
}
peer.ftp.FtpDir:
class FtpDir extends FtpEntry {
/**
* Returns a list of entries
*
* @return peer.ftp.FtpEntryList
* @throws peer.SocketException in case of an I/O error
*/
public function entries() {
}
/**
* Checks whether a file by the given name exists in this
* directory.
*
* @param string name
* @return bool TRUE if the file exists, FALSE otherwise
* @throws peer.SocketException in case of an I/O error
*/
public function hasFile($name) {
}
/**
* Returns an FtpFile instance representing a file in this
* directory.
*
* @param string name
* @return peer.ftp.FtpFile the instance
* @throws io.FileNotFoundException in case the file was not found
* @throws peer.SocketException in case of an I/O error
*/
public function getFile($name) {
}
/**
* Creates a file in this directory and returns an FtpFile instance
* representing it.
*
* @param string name
* @return peer.ftp.FtpFile the instance
* @throws io.IOException in case the file already exists
* @throws peer.SocketException in case of an I/O error
*/
public function newFile($name) {
}
/**
* Returns an FtpFile instance representing a file in this
* directory.
*
* Note: Same as getFile() but does not throw exceptions if the file
* does not exist but will return an FtpFile in any case.
*
* @param string name
* @return peer.ftp.FtpFile the instance
* @throws peer.SocketException in case of an I/O error
*/
public function file($name) {
}
/**
* Checks whether a subdirectory by the given name exists in this
* directory.
*
* @param string name
* @return bool TRUE if the file exists, FALSE otherwise
* @throws peer.SocketException in case of an I/O error
*/
public function hasDir($name) {
}
/**
* Returns an FtpDir instance representing a subdirectory in this
* directory.
*
* @param string name
* @return peer.ftp.FtpDir the instance
* @throws io.FileNotFoundException in case the file was not found
* @throws peer.SocketException in case of an I/O error
*/
public function getDir($name) {
}
/**
* Creates a subdirectory in this directory and returns an FtpDir
* instance representing it.
*
* @param string name
* @return peer.ftp.FtpDir the created instance
* @throws lang.IllegalStateException in case the directory already exists
* @throws io.IOException in case the directory could not be created
*/
public function newDir($name) {
}
/**
* Returns an FtpDir instance representing a subdirectory in this
* directory.
*
* Note: Same as getDir() but does not throw exceptions if the
* directory does not exist but will create it and thus return an
* FtpDir in any case.
*
* @param string name
* @return peer.ftp.FtpDir the instance
* @throws lang.IllegalStateException in case the directory exists and is a file
* @throws io.IOException in case the directory could not be created
*/
public function dir($name) {
}
}
Examples
Checking for entry existance:
$c= new FtpConnection('ftp://user:pass@example.com');
$c->connect();
if (-1 == ftp_size($c->handle, '/'.$filename)) {
}
if (!($dir= $c->getDir('/'))) {
throw new FileNotFoundException('Dir does not exist');
}
$exists= FALSE;
while ($e= $dir->getEntry()) {
if (!($e instanceof FtpDir) && $e->getName() == $filename) {
$exists= TRUE;
break;
}
}
if (!$c->rootDir()->hasFile($filename)) {
}
Retrieving the root directory:
$c= new FtpConnection('ftp://user:pass@example.com');
$c->connect();
$root= $c->getDir('/');
$root= $c->rootDir();
Exceptions for makeDir():
$c= new FtpConnection('ftp://user:pass@example.com');
$c->connect();
if (FALSE === $c->makeDir(new FtpDir('/admin'))) {
}
$dir= $c->getDir('/admin');
try {
$dir= $c->rootDir()->newDir('admin');
} catch (IllegalStateException $e) {
} catch (IOException $e) {
}
Retrieving a single entry:
$c= new FtpConnection('ftp://user:pass@example.com');
$c->connect();
if (!($dir= $c->getDir('admin'))) {
throw new FileNotFoundException('Admin dir does not exist');
}
$entry= NULL;
while ($e= $dir->getEntry()) {
if (!($e instanceof FtpDir) && $e->getName() == $name) {
$entry= $e;
break;
}
}
if (!$entry) {
throw new FileNotFoundException('File not found');
}
$entry= $c->rootDir()->getDir('admin')->getFile($name);
Downloading entries:
$c= new FtpConnection('ftp://user:pass@example.com');
$c->connect();
try {
$c->get('/'.$filename, $local);
} catch (IOException $e) {
}
try {
$c->rootDir()->getFile($filename)->downloadTo(new FileOutputStream(new File($local)));
} catch (FileNotFoundException $e) {
} catch (SocketException $e) {
} catch (IOException $e) {
}
Uploading entries:
$c= new FtpConnection('ftp://user:pass@example.com');
$c->connect();
try {
$c->put($local, '/'.$filename);
} catch (IOException $e) {
}
try {
$c->rootDir()->file($filename)->uploadFrom(new FileInputStream(new File($local)));
} catch (FileNotFoundException $e) {
} catch (SocketException $e) {
} catch (IOException $e) {
}
Retrieving all entries into an array:
$c= new FtpConnection('ftp://user:pass@example.com');
$c->connect();
$root= $c->getDir('/');
$entries= array();
while ($entry= $root->getEntry()) {
$entries[]= $entry;
}
$entries= $c->rootDir()->entries()->asArray();
Entry iteration:
$c= new FtpConnection('ftp://user:pass@example.com');
$c->connect();
$root= $c->getDir('/');
$entries= array();
while ($entry= $root->getEntry()) {
}
foreach ($c->rootDir()->entries() as $entry) {
}
Security considerations
n/a
Speed impact
n/a
Dependencies
Deprecated methods in peer.ftp.FtpConnection:
public peer.ftp.FtpDir getDir([string $dir= NULL])
public bool setDir(peer.ftp.FtpDir $f)
public bool makeDir(peer.ftp.FtpDir $f)
public bool put(mixed $arg, [string $remote= NULL], [string $mode= 0])
public bool get(string $remote, mixed $arg, [string $mode= 0])
public bool delete(string $remote)
public bool rename(string $src, string $target)
public array quote(string $command)
Related documents
- http://experiments.xp-framework.net/?arena,ftp
The new API
Comments
- friebe, Sun Oct 14 19:26:33 2007
Should the old methods be removed instantly (breaking BC) or should
they be available but deprecated?
- friebe, Mon Oct 15 22:02:46 2007
Decided to add methods from old API as deprecated methods. They will
be removed in a future release!
<EOF>