123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- <?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*/
- }
|