| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 | <?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->f_transitions = 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->apply_event('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->apply_event('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->apply_event('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 apply_event     */    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->apply_event('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->apply_event('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->apply_event('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->apply_event('connect');    }  /**   * interface to login   *   * @return boolean   */  public function login()    {    // echo func_name() . "\n";    return $this->apply_event('login');    }  /**   * interface to close   *   * @return boolean   */  public function close()    {    // echo func_name() . "\n";    return $this->apply_event('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->apply_event('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   */  public function cont() // continue is a php reserved word    {    // echo func_name() . "\n";    $ret = $this->apply_event('continue');    $ret = $ret->fsm_state;    return $ret;    }  public function get_progress()    {    if ((!$this->f_state == 'active') || (!is_resource($this->f_fp)))      $ret = 0;    else      {      $pos = ftell($this->f_fp);      $ret = $pos / $this->f_goal;      }    return $ret;    }  /* missing: put*/  }
 |