php__phplib/apps/ftp/u_ftp.php
Frederic G. MARAND 7d0f0d44ea Restructured file layout to incorporate a PSR0 version of Class_Grapher.
- new OSInet/Class_Grapher directory
- moved misc.php and other miscellaneous PHP files to misc/
- split the PSR0 autoloader from misc.php to psr0.php
- moved BackgroundApplication to FSM directory
- moved FSM samples and docs to FSM help directory
- new "apps" directory for the demo source
- new Class_Grapher demo app
- moved the files of the FSM FTP demo app to "apps". Likely broken.
2012-05-02 23:29:47 +02:00

401 lines
9.2 KiB
PHP

<?php
/**
* An FTP transfer wrapper using asynchronous transfer
* (c) 2006 Ouest Systèmes Informatiques (OSI)
* Licensed under the CeCILL 2.0 license
*
* $Id: u_ftp.php,v 1.3 2007-04-28 20:03:40 marand Exp $
*
* @todo redo to take advantage of the new FSM 1.2 features to reduce the code
*/
require_once('u_fsm.php');
/**
* Class implements a finite-state-machine-based
* FTP client with *very* limited functionality,
* but that can display progress information
* states are:
* - init: not yet set up
* - offline: no link established
* - online: client connected to server
* - live: client connected and logged in
* - active: a data transfer operation is under way
* - unsafe: something failed, disconnect can happen out of our control
*/
class ftp_client extends fsm {
private $f_host;
private $f_user;
private $f_pass;
private $f_pwd;
private $f_file;
private $f_localwd;
private $f_localfile;
private $f_fp; // file pointer to local file, used in get/put/continue
private $f_goal; // bytes to be transferred
private $f_conn; // connection
private $f_callback; // name of callback function for progress information
/**
* @param string $url
* @return void
*/
public function __construct(string $url = null) {
if ($url)
$this->set_url($url);
$this->fTransitions = array(
'init' => array(
'check_params' => array(
true => 'offline',
false => 'init',
),
'set_progress' => array(
true => 'offline',
false => 'offline',
),
),
'offline' => array(
'check_params' => array(
true => 'offline',
false => 'init',
),
'connect' => array
(
true => 'online',
false => 'unsafe',
),
'set_progress' => array(
true => 'offline',
false => 'offline',
),
),
'online' => array(
'close' => array(
true => 'offline',
false => 'unsafe',
),
'login' => array(
true => 'live',
false => 'unsafe',
),
),
'live' => array(
'close' => array(
true => 'offline',
false => 'unsafe',
),
'chdir' => array(
true => 'live',
false => 'unsafe',
),
'get' => array(
FTP_FINISHED => 'live',
FTP_FAILED => 'unsafe',
FTP_MOREDATA => 'active',
),
'put' => array(
FTP_FINISHED => 'live',
FTP_FAILED => 'unsafe',
FTP_MOREDATA => 'active',
),
),
'active' => array(
'close' => array(
true => 'offline',
false => 'unsafe',
),
'continue' => array(
FTP_FINISHED => 'live',
FTP_FAILED => 'unsafe',
FTP_MOREDATA => 'active',
),
),
'unsafe' => array(),
/**
* no transition allowed
* Even retrying connect would not be safe
* Must destruct
*/
);
parent::__construct();
}
/**
* close connection if it hasn't been done, to prevent connection
* lingering on the server if avoidable
* @return void
*/
public function __destruct() {
if ($this->is_event_allowed('close'))
$this->f_close();
if (is_resource($this->f_fp)) {
try {
fclose($this->f_fp);
}
catch (Exception $e) {
print_r($e);
}
}
}
/**
* setter for f_host. Make sur name can be resolved
*
* @param string $host
* @return ftp_client
*/
public function set_host($host = null) {
/**
* ignore hosts that don't resolve in DNS
*/
if (is_array(gethostbynamel($host)))
$this->f_host = $host;
else
throw new Exception(func_name() . ": cannot resolve host name \"$host\"");
$this->applyEvent('check_params');
return $this;
}
/**
* setter for f_user
*
* @param string $user
* @return ftp_client
*/
public function set_user($user = 'anonymous') {
$this->f_user = $user;
$this->applyEvent('check_params');
return $this;
}
/**
* setter for f_pass
*
* @param string $pass
* @return ftp_client
*/
public function set_pass($pass = null) {
$this->f_pass = $pass;
$this->applyEvent('check_params');
return $this;
}
/**
* callback is invoked at the end of get, put
* and before and after continue
*
* @param string $callback
*/
public function set_callback($callback) {
if ($callback && !function_exists($callback))
throw new Exception(func_name() . ": cannot use undefined function $callback as callback");
else
$this->f_callback = $callback;
/**
* this setter does not cause a state change, so no call to applyEvent
*/
return $this;
}
/**
* implement change remote directory
* @return boolean
*/
protected function f_chdir() {
$ret = ftp_chdir($this->f_conn, $this->f_pwd);
return $ret;
}
/**
* change remote directory
*
* @param string $pwd
* @return boolean
*/
public function chdir($pwd = null) {
$this->f_pwd = $pwd;
$ret = $this->applyEvent('chdir');
return $ret;
}
/**
* setter for f_file
*
* @param string $file
* @return ftp_client
*/
public function set_file($file = null) {
$this->f_file = $file;
if (!isset($this->f_localfile))
$this->f_localfile = $file;
$this->applyEvent('check_params');
return $this;
}
/**
* setter for f_localfile
*
* @param string $file
* @return ftp_client
*/
public function set_localfile($file = null) {
$this->f_localfile = $file;
$this->applyEvent('check_params');
return $this;
}
/**
* does the instance have all necessary info for a FTP transfer ?
*
* @return boolean
*/
protected function f_check_params() {
$ret = isset($this->f_host)
&& isset($this->f_user)
&& isset($this->f_pass)
&& isset($this->f_file)
&& isset($this->f_localfile)
;
// echo func_name() . ", ret = " . ($ret ? 'TRUE' : 'FALSE') . PHP_EOL;
return $ret;
}
/**
* implementation of connect
*
* @return boolean
*/
protected function f_connect() {
// echo func_name() . "\n";
$this->f_conn = ftp_connect($this->f_host); // default port, default timeout
$ret = is_resource($this->f_conn);
return $ret;
}
/**
* implementation of close
* @return boolean
*/
protected function f_close() {
// echo func_name() . "\n";
$ret = ftp_close($this->f_conn);
return $ret;
}
/**
* implementation of login
* @return boolean
*/
protected function f_login() {
// echo func_name() . "\n";
$ret = ftp_login($this->f_conn, $this->f_user, $this->f_pass);
return $ret;
}
/**
* implementation of get
*
* @return int FTP_FINISHED | FTP_MOREDATA | FTP_FAILED
*/
protected function f_get() {
// echo func_name() . "\n";
$this->f_fp = fopen($this->f_localfile, "wb");
if (!is_resource($this->f_fp)) {
$ret = FTP_FAILED;
throw new Exception(func_name() . ": could not create local file $this->f_file");
}
$this->f_goal = ftp_size($this->f_conn, $this->f_file);
$ret = ftp_nb_fget($this->f_conn, $this->f_fp, $this->f_file, FTP_BINARY);
if ($ret == FTP_FINISHED)
fclose($this->f_fp);
call_user_func($this->f_callback, $this, 'post');
return $ret;
}
/**
* implementation of continue
* @return int FTP_FINISHED | FTP_MOREDATA | FTP_FAILED
*/
protected function f_continue() {
if ($this->f_callback)
call_user_func($this->f_callback, $this, 'pre');
$ret = ftp_nb_continue($this->f_conn);
if ($ret == FTP_FINISHED)
fclose($this->f_fp);
if ($this->f_callback)
call_user_func($this->f_callback, $this, 'post');
return $ret;
}
/**
* interface to connect
* @return void
*/
public function connect() {
// echo func_name() . "\n";
return $this->applyEvent('connect');
}
/**
* interface to login
*
* @return boolean
*/
public function login() {
// echo func_name() . "\n";
return $this->applyEvent('login');
}
/**
* interface to close
*
* @return boolean
*/
public function close() {
// echo func_name() . "\n";
return $this->applyEvent('close');
}
/**
* get a file using previously defined parameters
* @return int FTP_FAILED | FTP_MOREDATA | FTP_FINISHED
*/
public function get() {
// echo func_name() . "\n";
return $this->applyEvent('get');
}
/**
* continue a current transfer
*
* @param string $callback name of function to be called before and after
* @return int FTP_FINISHED | FTP_MOREDATA | FTP_FAILED
*/
// continue is a php reserved word
public function cont() {
// echo func_name() . "\n";
$ret = $this->applyEvent('continue');
$ret = $ret->fsmState;
return $ret;
}
public function get_progress() {
if ((!$this->fState == 'active') || (!is_resource($this->f_fp)))
$ret = 0;
else {
$pos = ftell($this->f_fp);
$ret = $pos / $this->f_goal;
}
return $ret;
}
/* missing: put*/
}