SftpTransporter   D
last analyzed

Complexity

Total Complexity 81

Size/Duplication

Total Lines 444
Duplicated Lines 16.44 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 33.98%

Importance

Changes 0
Metric Value
wmc 81
lcom 1
cbo 4
dl 73
loc 444
ccs 70
cts 206
cp 0.3398
rs 4.8717
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 2
A setOptions() 0 12 4
A connect() 0 12 3
C login() 0 63 12
A connectAndLogin() 0 9 2
B exists() 0 28 5
A mkdir() 0 18 4
B get() 23 23 4
D put() 25 43 9
B putContent() 13 24 5
A symlink() 3 21 4
A isSymlink() 0 10 2
B copy() 6 27 6
B remove() 0 22 5
B exec() 3 26 4
C ls() 0 27 7
A isConnected() 0 4 1
A __destruct() 0 6 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like SftpTransporter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SftpTransporter, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the Conveyor package.
5
 *
6
 * (c) Jeroen Fiege <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webcreate\Conveyor\Transporter;
13
14
use phpseclib\Crypt\RSA;
15
use phpseclib\Net\SFTP as PhpseclibSFTP;
16
use phpseclib\System\SSH\Agent;
17
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
18
use Symfony\Component\Finder\Finder;
19
use Webcreate\Conveyor\Event\TransporterEvent;
20
use Webcreate\Conveyor\Event\TransporterEvents;
21
use Webcreate\Conveyor\IO\IOInterface;
22
use Webcreate\Conveyor\Transporter\Ftp\Sftp;
23
24
/**
25
 * @todo refactor the injection of the IOInterface to a event-based solution?
26
 */
27
class SftpTransporter extends AbstractTransporter implements SshCapableTransporterInterface
0 ignored issues
show
Complexity introduced by
This class has a complexity of 81 which exceeds the configured maximum of 50.

The class complexity is the sum of the complexity of all methods. A very high value is usually an indication that your class does not follow the single reponsibility principle and does more than one job.

Some resources for further reading:

You can also find more detailed suggestions for refactoring in the “Code” section of your repository.

Loading history...
Complexity introduced by
The class SftpTransporter has a coupling between objects value of 15. Consider to reduce the number of dependencies under 13.
Loading history...
28
{
29
    /**
30
     * @var null|Ftp\Sftp|PhpseclibSFTP
31
     */
32
    protected $sftp;
33
    protected $io;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
34
    protected $keyPassword;
35
36 7
    public function __construct(EventDispatcherInterface $dispatcher, $sftp = null, IOInterface $io)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
Coding Style introduced by
Parameters which have default values should be placed at the end.

If you place a parameter with a default value before a parameter with a default value, the default value of the first parameter will never be used as it will always need to be passed anyway:

// $a must always be passed; it's default value is never used.
function someFunction($a = 5, $b) { }
Loading history...
37
    {
38 7
        parent::__construct($dispatcher);
39
40 7
        if (null === $sftp) {
41
            $sftp = new Sftp();
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $sftp. This often makes code more readable.
Loading history...
42
        }
43 7
        $this->sftp = $sftp;
44 7
        $this->io = $io;
45 7
    }
46
47
    public function setOptions(array $options)
48
    {
49
        // if the host, username or password changes, we should disconnect
50
        if ($this->host !== $options['host']
51
            || $this->username !== $options['user']
52
            || $this->password !== $options['pass']
53
        ) {
54
            $this->sftp->disconnect();
0 ignored issues
show
Bug introduced by
The method disconnect() does not exist on Webcreate\Conveyor\Transporter\Ftp\Sftp. Did you maybe mean connect()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
55
        }
56
57
        parent::setOptions($options);
58
    }
59
60
    public function connect()
61
    {
62
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_CONNECT, new TransporterEvent($this));
63
64
        $port = $this->port ?: 22;
65
66
        $success = $this->sftp->connect($this->host, $port);
67
68
        if (false === $success) {
69
            throw new \RuntimeException(sprintf('Could not connect to host %s on port %s', $this->host, $port));
70
        }
71
    }
72
73
    /**
74
     * @return bool
75
     */
76
    public function login()
0 ignored issues
show
Coding Style introduced by
login uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
77
    {
78
        $password = $this->password;
79
        $username = $this->username;
80
81
        // try to login using ssh key
82
        if (null === $password) {
83
            try {
84
                // try with agent (suppress stupid phpseclib warnings/errors)
85
                $agent = @new Agent();
86
            } catch (\Exception $e) {
87
                $agent = null;
88
            }
89
90
            if ($success = $this->sftp->login($username, $agent)) {
0 ignored issues
show
Documentation Bug introduced by
The method login does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
91
                return true;
92
            }
93
94
            // try with key manually
95
            $identityFilePath = $_SERVER['HOME'] . '/.ssh/id_rsa';
96
            if (!is_file($identityFilePath)) {
97
                $this->io->write(sprintf('Public key file not found in %s', $identityFilePath));
98
99
                return false;
100
            }
101
102
            $identityFile = file_get_contents($identityFilePath);
103
            $key          = new RSA();
104
            $loaded       = $key->loadKey($identityFile);
105
106
            // first try without keypass
107
            if (!$loaded || false === $success = $this->sftp->login($username, $key)) {
0 ignored issues
show
Documentation Bug introduced by
The method login does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
108
                $attempts = 3;
109
110
                // now N attempts to load the identity file
111
                while ($attempts--) {
112
                    // retry with password
113
                    $this->keyPassword = $this->keyPassword ?: $this->io->askAndHideAnswer(sprintf('Enter passphrase for %s: ', $identityFilePath));
114
                    $key->setPassword($this->keyPassword);
115
                    $loaded = $key->loadKey($identityFile);
116
117
                    if (!$loaded) {
118
                        if ($attempts > 0) {
119
                            $this->keyPassword = null;
120
121
                            $this->io->write('Permission denied, please try again.');
122
                        }
123
                    } else {
124
                        if (false === $success = $this->sftp->login($username, $key)) {
0 ignored issues
show
Documentation Bug introduced by
The method login does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
125
                            $this->io->write(sprintf('%s@%s: Permission denied (publickey)', $this->username, $this->host));
126
                        }
127
128
                        return $success;
129
                    }
130
                }
131
            }
132
133
            return $success;
134
        }
135
136
        // login with given password
137
        return $this->sftp->login($username, $password);
0 ignored issues
show
Documentation Bug introduced by
The method login does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
138
    }
139
140
    public function connectAndLogin()
141
    {
142
        $this->connect();
143
        $success = $this->login();
144
145
        if (false === $success) {
146
            throw new \Exception(sprintf('Unable to login to %s', $this->host));
147
        }
148
    }
149
150 2
    public function exists($path)
151
    {
152 2
        if (false === $this->isConnected()) {
153
            $this->connectAndLogin();
154
        }
155
156 2
        $pwd = $this->sftp->pwd();
0 ignored issues
show
Documentation Bug introduced by
The method pwd does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
157
158
        // try to change directory to see if it is an existing directory
159 2
        $result = $this->sftp->chdir($path);
0 ignored issues
show
Documentation Bug introduced by
The method chdir does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
160 2
        if (true === $result) {
161 2
            $result = $this->sftp->chdir($pwd); // change back to the original directory
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Documentation Bug introduced by
The method chdir does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
162
163 2
            return true;
164
        } else {
165
            // list the parent directory and check if the file exists
166
            $parent = dirname($path);
167
            $result = $this->sftp->nlist($parent);
0 ignored issues
show
Documentation Bug introduced by
The method nlist does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
168
169
            if (false !== $result) {
170
                if (in_array(basename($path), $result)) {
171
                    return true;
172
                }
173
            }
174
        }
175
176
        return false;
177
    }
178
179 1
    public function mkdir($dest)
180
    {
181 1
        if (false === $this->isConnected()) {
182
            $this->connectAndLogin();
183
        }
184
185 1
        $pwd = dirname($dest);
186 1
        if (false === $this->exists($pwd)) {
187
            $this->mkdir($pwd);
188
        }
189
190 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_MKDIR, new TransporterEvent($this, $dest));
191
192 1
        $success = $this->sftp->mkdir($dest);
0 ignored issues
show
Documentation Bug introduced by
The method mkdir does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
193 1
        if (false === $success) {
194
            throw new \RuntimeException('Something went wrong: ' . "\n" . implode("\n", $this->sftp->getSFTPErrors()));
0 ignored issues
show
Documentation Bug introduced by
The method getSFTPErrors does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
195
        }
196 1
    }
197
198 1 View Code Duplication
    public function get($src, $dest = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
199
    {
200 1
        if (false === $this->isConnected()) {
201
            $this->connectAndLogin();
202
        }
203
204 1
        $realDest = $dest;
205
206 1
        if (null == $dest) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $dest of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
207
            $realDest = tempnam(sys_get_temp_dir(), basename($src));
208
        }
209
210 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_GET, new TransporterEvent($this, array('src' => $src, 'dest' => $dest)));
211
212 1
        $succes = $this->sftp->get($src, $realDest);
0 ignored issues
show
Unused Code introduced by
$succes is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Documentation Bug introduced by
The method get does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
213
214 1
        if (null == $dest) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $dest of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
215
            $content = file_get_contents($realDest);
216
            unlink($realDest);
217
218
            return $content;
219
        }
220 1
    }
221
222 1
    public function put($src, $dest)
223
    {
224 1
        if (false === $this->isConnected()) {
225
            $this->connectAndLogin();
226
        }
227
228 1
        if (false === file_exists($src)) {
229 1
            throw new \InvalidArgumentException(sprintf('Resource \'%s\' does not exist', $src));
230
        }
231
232
        if (is_file($src)) {
233
            $file = new \SplFileInfo($src);
234
235
            $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_PUT, new TransporterEvent($this, array('dest' => $dest, 'src' => $file->getPathname())));
236
237
            $success = $this->sftp->put($dest, $file->getPathname(), PhpseclibSFTP::SOURCE_LOCAL_FILE);
0 ignored issues
show
Documentation Bug introduced by
The method put does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
238
239 View Code Duplication
            if (!$success) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
                // maybe the parent directory doesnt exist; try to create it and try again
241
                $pwd = dirname($dest);
242
                if (false === $this->exists($pwd)) {
243
                    $this->mkdir($pwd);
244
245
                    // retry try to put
246
                    $success = $this->sftp->put($dest, $file->getPathname(), PhpseclibSFTP::SOURCE_LOCAL_FILE);
0 ignored issues
show
Documentation Bug introduced by
The method put does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
247
                    if (!$success) {
248
                        throw new \RuntimeException('Something went wrong: ' . "\n" . implode("\n", $this->sftp->getSFTPErrors()));
0 ignored issues
show
Documentation Bug introduced by
The method getSFTPErrors does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
249
                    }
250
                }
251
            }
252 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
253
            if (!$this->exists($dest)) {
254
                $this->mkdir($dest);
255
            }
256
257
            $finder = new Finder();
258
            $test = $finder->in($src)->depth('== 0');
259
260
            foreach ($test as $file) {
261
                $this->put(rtrim($src, '/') . '/' . $file->getFilename(), rtrim($dest, '/')  . '/' . $file->getFilename());
262
            }
263
        }
264
    }
265
266 1
    public function putContent($content, $dest)
267
    {
268 1
        if (false === $this->isConnected()) {
269
            $this->connectAndLogin();
270
        }
271
272 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_PUT_CONTENT, new TransporterEvent($this, array('dest' => $dest, 'content' => $content)));
273
274 1
        $success = $this->sftp->put($dest, $content, PhpseclibSFTP::SOURCE_STRING);
0 ignored issues
show
Documentation Bug introduced by
The method put does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
275
276 1 View Code Duplication
        if (!$success) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
277
            // maybe the parent directory doesnt exist; try to create it and try again
278 1
            $pwd = dirname($dest);
279 1
            if (false === $this->exists($pwd)) {
280
                $this->mkdir($pwd);
281
282
                // retry try to put
283
                $success = $this->sftp->put($dest, $content, PhpseclibSFTP::SOURCE_STRING);
0 ignored issues
show
Documentation Bug introduced by
The method put does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
284
                if (!$success) {
285
                    throw new \RuntimeException('Something went wrong: ' . "\n" . implode("\n", $this->sftp->getSFTPErrors()));
0 ignored issues
show
Documentation Bug introduced by
The method getSFTPErrors does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
286
                }
287
            }
288
        }
289 1
    }
290
291
    /**
292
     * Creates a symlink on the remote server
293
     *
294
     * @param $src
295
     * @param $dest
296
     * @throws \RuntimeException
297
     * @return mixed
298
     */
299 1
    public function symlink($src, $dest)
300
    {
301 1
        if (false === $this->isConnected()) {
302
            $this->connectAndLogin();
303
        }
304 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_SYMLINK, new TransporterEvent($this, array('dest' => $dest, 'src' => $src)));
305
306
        // make src an absolute path
307 1
        if (0 !== strpos($src, '/')) {
308 1
            $src = $this->sftp->pwd() . '/' . $src;
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $src. This often makes code more readable.
Loading history...
Documentation Bug introduced by
The method pwd does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
309
        }
310
311
        // strip end slashes
312 1
        $src  = rtrim($src, '/');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $src. This often makes code more readable.
Loading history...
313 1
        $dest = rtrim($dest, '/');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $dest. This often makes code more readable.
Loading history...
314
315 1
        $success = $this->sftp->exec(sprintf("ln -s -T -f %s %s", escapeshellarg($src), escapeshellarg($dest)));
0 ignored issues
show
Documentation Bug introduced by
The method exec does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
316 1 View Code Duplication
        if (false === $success) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
317
            throw new \RuntimeException('Something went wrong: ' . "\n" . implode("\n", (array) $this->sftp->getErrors()));
318
        }
319 1
    }
320
321
    /**
322
     * Checks for symlink on the remote server
323
     *
324
     * @param $dest
325
     * @return bool
326
     */
327
    public function isSymlink($dest)
328
    {
329
        if (false === $this->isConnected()) {
330
            $this->connectAndLogin();
331
        }
332
333
        $lstat = $this->sftp->lstat($dest);
0 ignored issues
show
Documentation Bug introduced by
The method lstat does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
334
335
        return ($lstat['type'] === 3);
336
    }
337
338
    /**
339
     * Copies a file/directory on the remote host
340
     *
341
     * @param  string            $src
342
     * @param  string            $dest
343
     * @param  bool              $recursive
344
     * @throws \RuntimeException
345
     * @return mixed
346
     */
347 1
    public function copy($src, $dest, $recursive = true)
348
    {
349 1
        if (false === $this->isConnected()) {
350
            $this->connectAndLogin();
351
        }
352
353 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_COPY, new TransporterEvent($this, array('dest' => $dest, 'src' => $src)));
354
355 1
        $recursiveFlag = ($recursive ? 'r' : '');
356
357
        // adjust for symlink
358
        // we want to copy the contents of the symlink (dereference it), but keep links in subfolders
359 1
        $lstat = $this->sftp->lstat($src);
0 ignored issues
show
Documentation Bug introduced by
The method lstat does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
360 1
        if ($lstat['type'] === 3) {
361
            $result = $this->sftp->exec(sprintf("readlink -f %s", escapeshellarg($src)));
0 ignored issues
show
Documentation Bug introduced by
The method exec does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
362 View Code Duplication
            if (false === $result) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
363
                throw new \RuntimeException('Something went wrong: ' . "\n" . implode("\n", (array) $this->sftp->getErrors()));
364
            }
365
366
            $src = trim($result);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $src. This often makes code more readable.
Loading history...
367
        }
368
369 1
        $success = $this->sftp->exec(sprintf("cp -{$recursiveFlag}f %s %s", escapeshellarg($src), escapeshellarg($dest)));
0 ignored issues
show
Documentation Bug introduced by
The method exec does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
370 1 View Code Duplication
        if (false === $success) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
            throw new \RuntimeException('Something went wrong: ' . "\n" . implode("\n", (array) $this->sftp->getErrors()));
372
        }
373 1
    }
374
375 1
    public function remove($path, $recursive = true)
376
    {
377 1
        if (false === $this->isConnected()) {
378
            $this->connectAndLogin();
379
        }
380
381 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_REMOVE, new TransporterEvent($this, array('path' => $path)));
382
383 1
        $recursiveFlag = ($recursive ? 'r' : '');
384
385 1
        $success = $this->sftp->exec(sprintf("rm -{$recursiveFlag}f %s", escapeshellarg($path)));
0 ignored issues
show
Documentation Bug introduced by
The method exec does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
386
387 1
        if (false === $success) {
388
            $errors = (array) $this->sftp->getErrors();
389
390
            throw new \RuntimeException('Something went wrong: ' . "\n" . implode("\n", $errors));
391
        }
392
        // ieuww, Net_Ssh doesn't return false, but does put errors in the getStdError()
393 1
        elseif ($error = $this->sftp->getStdError()) {
0 ignored issues
show
Documentation Bug introduced by
The method getStdError does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
394
            throw new \RuntimeException('Something went wrong: ' . "\n" . $error);
395
        }
396 1
    }
397
398
    public function exec($command, $callback = null)
399
    {
400
        if (false === $this->isConnected()) {
401
            $this->connectAndLogin();
402
        }
403
404
//        $this->sftp->enablePTY();
405
406
        $success = $this->sftp->exec($command, $callback);
0 ignored issues
show
Documentation Bug introduced by
The method exec does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
407
408
//        $data = $this->sftp->read();
409
//        if (is_callable($callback)) {
410
//            $callback($data);
411
//        }
412
413 View Code Duplication
        if (false === $success) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
414
            throw new \RuntimeException('Something went wrong: ' . "\n" . implode("\n", (array) $this->sftp->getErrors()));
415
        }
416
417
        $status = $this->sftp->getExitStatus();
0 ignored issues
show
Documentation Bug introduced by
The method getExitStatus does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
418
        if ($status === false) {
419
            $status = -1;
420
        }
421
422
        return $status;
423
    }
424
425
    /**
426
     * Lists files and directories
427
     *
428
     * @param  string $path
429
     * @return mixed
430
     */
431
    public function ls($path)
0 ignored issues
show
Coding Style introduced by
This method's name is shorter than the configured minimum length of 3 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
432
    {
433
        if (false === $this->isConnected()) {
434
            $this->connectAndLogin();
435
        }
436
437
        $list = $this->sftp->rawlist($path);
0 ignored issues
show
Documentation Bug introduced by
The method rawlist does not exist on object<Webcreate\Conveyor\Transporter\Ftp\Sftp>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
438
439
        $retval = array();
440
441
        if (false === $list) {
442
            return $retval;
443
        }
444
445
        foreach ($list as $fileOrDirectory => $info) {
446
            if ('..' === $fileOrDirectory || '.' === $fileOrDirectory) {
447
                continue;
448
            }
449
450
            $retval[$fileOrDirectory] = array(
451
                'type' => (2 == $info['type'] ? 'directory' : 'file'), // @todo improve
452
                'mtime' => new \DateTime('@' . $info['mtime'])
453
            );
454
        }
455
456
        return $retval;
457
    }
458
459 7
    protected function isConnected()
460
    {
461 7
        return $this->sftp->isConnected();
462
    }
463
464
    public function __destruct()
465
    {
466
        if ($this->sftp) {
467
            $this->sftp->disconnect();
0 ignored issues
show
Bug introduced by
The method disconnect() does not exist on Webcreate\Conveyor\Transporter\Ftp\Sftp. Did you maybe mean connect()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
468
        }
469
    }
470
}
471