123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- <?php
- /**
- * An FTP transfer wrapper using the Osinet FiniteStateMachine
- *
- * @copyright (c) 2007-2012 Ouest Systèmes Informatiques
- * @author Frédéric G. MARAND
- * @license Licensed under the CeCILL 2.0
- */
- namespace Osinet\FiniteStateMachine;
- /**
- * Save current reporting level while we set it
- */
- $_ftpEr = error_reporting(E_ALL | E_STRICT);
- /**
- * Class implements a finite-state-machine-based FTP client with *very* limited
- * functionality, but that can display progress information states, namely:
- * - 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 FtpClient extends Machine {
- /**
- * remote properties
- */
- private $fRemoteFile;
- private $fRemoteHost;
- private $fRemotePass;
- private $fRemoteUser;
- private $fRemoteWd;
- /**
- * local properties
- */
- private $fLocalWd;
- private $fLocalFile;
- private $fLocalFp; // file pointer to local file, used in get/put/continue
- /**
- * FTP properties
- */
- private $fFtpCallback; // name of callback function for progress information
- private $fFtpGoal; // bytes to be transferred
- private $fFtpConnection; // connection
- /**
- * @return void
- */
- public function __construct($values = array()) {
- if (!isset($values['source'])) {
- throw \Exception('Unspecified machine description.');
- }
- $this->loadFsm($values['source']);
- // print_r($this->fTransitions);
- parent::__construct();
- // print_r($this);die();
- }
- /**
- * Initialize parameters from an array
- *
- * @todo should really check names and values.
- *
- * @param array $params
- *
- * @return Result
- */
- public function setParameters($params) {
- $r = new \ReflectionClass(get_class($this));
- $dp = $r->getDefaultProperties();
- foreach ($params as $name => $value) {
- $field_name = "f$name";
- if (array_key_exists($field_name, $dp)) {
- $this->$field_name = $value;
- }
- else {
- echo "Skipping invalid parameter $name.\n";
- }
- }
- $ret = $this->applyEvent('CheckParameters');
- return $ret;
- }
- /**
- * ============ utility functions ============
- */
- /**
- * format a boolean value as a string
- *
- * @param boolean $val
- * @return string
- */
- static function stringFromBoolean($val)
- {
- return $val ? 'true' : 'false';
- }
- /**
- * Enter description here...
- *
- * @param unknown_type $status
- * @return unknown
- */
- static function stringFromFtp($status)
- {
- switch ($status)
- {
- case FTP_FINISHED: $ret = 'FTP_FINISHED'; break;
- case FTP_MOREDATA: $ret = 'FTP_MOREDATA'; break;
- case FTP_FAILED: $ret = 'FTP_MOREDATA'; break;
- default: $ret = 'FTP_INVALID_STATUS'; break;
- }
- return $ret;
- }
- /**
- * ============ event handlers ============
- */
- /**
- * implement change remote directory
- * @return string (boolean)
- */
- protected function eventChdir()
- {
- $ret = ftp_chdir($this->fFtpConnection, $this->fRemoteWd);
- return self::stringFromBoolean($ret);
- }
- /**
- * does the instance have all necessary info for a FTP transfer ?
- *
- * @return string (boolean)
- */
- public function eventCheckParameters()
- {
- $ret = isset($this->fRemoteHost)
- && isset($this->fRemoteUser)
- && isset($this->fRemotePass)
- && isset($this->fRemoteWd)
- && isset($this->fRemoteFile)
- && isset($this->fLocalWd)
- && isset($this->fLocalFile)
- && isset($this->fFtpCallback)
- ;
- $ret = self::stringFromBoolean($ret);
- // echo func_name() . ", ret = $ret\n";
- return $ret;
- }
- /**
- * implementation of Close event
- *
- * @return string (boolean)
- */
- protected function eventClose()
- {
- $ret = 'true';
- // echo "Trying to close socket...";
- if (is_resource($this->fFtpConnection))
- {
- try
- {
- // echo "Trying to close connection...";
- ftp_close($this->fFtpConnection);
- // echo "Done.";
- }
- catch (Exception $e)
- {
- print_r($e);
- $ret = 'false';
- }
- }
- // echo "Socket closed\n";
- return $ret;
- }
- /**
- * implementation of Connect event
- *
- * @return string (boolean)
- */
- protected function eventConnect()
- {
- // echo func_name() . "\n";
- $this->fFtpConnection = ftp_connect($this->fRemoteHost); // default port, default timeout
- $ret = is_resource($this->fFtpConnection);
- return self::stringFromBoolean($ret);
- }
- /**
- * implementation of continue
- * @return string FTP_FINISHED | FTP_MOREDATA | FTP_FAILED
- */
- protected function eventContinue()
- {
- // echo func_name();
- if ($this->fFtpCallback)
- {
- call_user_func($this->fFtpCallback, $this, 'pre');
- }
- $ret = ftp_nb_continue($this->fFtpConnection);
- if ($ret == FTP_FINISHED)
- {
- fclose($this->fLocalFp);
- }
- if ($this->fFtpCallback)
- call_user_func($this->fFtpCallback, $this, 'post');
- $ret = self::stringFromFtp($ret);
- return $ret;
- }
- /**
- * implementation of get
- *
- * @return string FTP_FINISHED | FTP_MOREDATA | FTP_FAILED
- * @throws Exception fail creating local file
- */
- protected function eventGet()
- {
- // echo func_name() . "\n";
- $this->fLocalFp = fopen($this->fLocalFile, "wb");
- if (!is_resource($this->fLocalFp))
- {
- $ret = self::stringFromFtp(FTP_FAILED);
- // throw new Exception(func_name() . ": could not create local file $this->fLocalFile");
- return $ret;
- }
- $this->fFtpGoal = ftp_size($this->fFtpConnection, $this->fRemoteFile);
- $ret = ftp_nb_fget($this->fFtpConnection, $this->fLocalFp,
- $this->fRemoteFile, FTP_BINARY);
- if ($ret == FTP_FINISHED)
- {
- fclose($this->fLocalFp);
- }
- call_user_func($this->fFtpCallback, $this, 'post');
- // echo func_name() . " => $ret\n"; flush();
- return self::stringFromFtp($ret);
- }
- /**
- * implementation of login
- * @return string (boolean)
- */
- protected function eventLogin()
- {
- // echo func_name() . "\n";
- $ret = ftp_login($this->fFtpConnection, $this->fRemoteUser, $this->fRemotePass);
- return self::stringFromBoolean($ret);
- }
- /**
- * handler must be implemented, but does nothing
- * @return void
- */
- protected function eventProgress()
- {
- return; // the FSM needs nothing for this
- }
- /**
- * close connection if it hasn't been done, to prevent connection
- * lingering on the server if avoidable
- * @return void
- */
- public function __destruct()
- {
- // echo func_name() . PHP_EOL;
- if ($this->isEventAllowed('Close'))
- {
- $this->applyEvent('Close');
- }
- if(is_resource($this->fLocalFp))
- try
- {
- echo "Trying to close file...";
- fclose($this->fLocalFp);
- echo "Done\n";
- }
- catch (Exception $e)
- {
- print_r($e);
- }
- // echo "End of " . func_name() . "\n";
- }
- /**
- * Make sure name can be resolved
- * ignore hosts that don't resolve in DNS or hosts file
- *
- * @param string $host
- * @return boolean
- */
- public function isHostValid($host = null)
- {
- $ret = is_array(gethostbynamel($host));
- return $ret;
- }
- /**
- * If a transfer is under way, return the progress percentile, otherwise 0.0
- *
- * @return float
- */
- public function getProgress()
- {
- if ((!$this->fState == 'active') || (!is_resource($this->fLocalFp)))
- {
- $ret = 0.0;
- }
- else
- {
- $pos = ftell($this->fLocalFp);
- $ret = $pos / $this->fFtpGoal;
- }
- return $ret;
- }
- }
- /**
- * Restore previous reporting level
- */
- error_reporting($_ftpEr);
|