ScpTransporter   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 267
Duplicated Lines 44.94 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 46.81%

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 3
dl 120
loc 267
ccs 44
cts 94
cp 0.4681
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A exists() 13 13 2
A mkdir() 0 18 3
B get() 23 23 4
A put() 21 21 4
A putContent() 20 20 2
A symlink() 11 11 2
A isSymlink() 11 11 2
A copy() 0 13 3
A remove() 13 13 3
A exec() 8 8 2
A ls() 0 4 1

How to fix   Duplicated Code   

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:

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 Symfony\Component\EventDispatcher\EventDispatcherInterface;
15
use Webcreate\Conveyor\Event\TransporterEvent;
16
use Webcreate\Conveyor\Event\TransporterEvents;
17
use Webcreate\Util\Cli;
18
19
class ScpTransporter extends AbstractTransporter implements SshCapableTransporterInterface
20
{
21
    protected $cli;
22
    protected $_exists = array();
23
24 6
    public function __construct(EventDispatcherInterface $dispatcher, Cli $cli)
25
    {
26 6
        parent::__construct($dispatcher);
27
28 6
        $this->cli = $cli;
29 6
    }
30
31
    /**
32
     * Checks if a file or directory exists on the remote server
33
     *
34
     * @param  string $path remote source path
35
     * @return bool   true when the resource exists, false otherwise
36
     */
37 View Code Duplication
    public function exists($path)
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...
38
    {
39
        if (false === isset($this->_exists[$path])) {
40
            $remoteCommand = sprintf("test -e %s", $path);
41
            $commandline   = sprintf("ssh %s@%s \"%s\"", $this->getUser(), $this->getHost(), $remoteCommand);
42
43
            $exitCode = $this->cli->execute($commandline);
44
45
            $this->_exists[$path] = (0 === $exitCode);
46
        }
47
48
        return $this->_exists[$path];
49
    }
50
51
    /**
52
     * Create a directory on the remote server
53
     *
54
     * @param  string            $dest remote path
55
     * @throws \RuntimeException
56
     */
57
    public function mkdir($dest)
58
    {
59
        $pwd = dirname($dest);
60
        if (false === $this->exists($pwd)) {
61
            $this->mkdir($pwd);
62
        }
63
64
        $remoteCommand = sprintf("mkdir '%s'", $dest);
65
        $commandline   = sprintf("ssh %s@%s \"%s\"", $this->getUser(), $this->getHost(), $remoteCommand);
66
67
        $this->_exists[$dest] = true;
68
69
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_MKDIR, new TransporterEvent($this, $dest));
70
71
        if ($this->cli->execute($commandline)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
72
            throw new \RuntimeException($this->cli->getErrorOutput());
73
        }
74
    }
75
76
    /**
77
     * Retrieve file or directory from remote server
78
     *
79
     * @param  string            $src  remote source path
80
     * @param  string            $dest (optional) local destination path
81
     * @throws \RuntimeException
82
     * @return string
83
     */
84 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...
85
    {
86 1
        $realDest = $dest;
87
88 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...
89
            $realDest = tempnam(sys_get_temp_dir(), basename($src));
90
        }
91
92 1
        $commandline = sprintf("scp %s@%s:%s \"%s\"", $this->getUser(), $this->getHost(), $src, $realDest);
93
94 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_GET, new TransporterEvent($this, array('src' => $src, 'dest' => $dest)));
95
96 1
        if ($this->cli->execute($commandline)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
97
            throw new \RuntimeException($this->cli->getErrorOutput());
98
        }
99
100 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...
101
            $content = file_get_contents($realDest);
102
            unlink($realDest);
103
104
            return $content;
105
        }
106 1
    }
107
108
    /**
109
     * Upload a file or directory to remote server
110
     *
111
     * @param  string                    $src  local source path
112
     * @param  string                    $dest remote destination path
113
     * @throws \RuntimeException
114
     * @throws \InvalidArgumentException
115
     */
116 1 View Code Duplication
    public function put($src, $dest)
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...
117
    {
118 1
        if (false === file_exists($src)) {
119 1
            throw new \InvalidArgumentException(sprintf('Resource \'%s\' does not exist', $src));
120
        }
121
122
        $pwd = dirname($dest);
123
        if (false === $this->exists($pwd)) {
124
            $this->mkdir($pwd);
125
        }
126
127
        $commandline = sprintf("scp \"%s\" '%s@%s:%s'", $src, $this->getUser(), $this->getHost(), $dest);
128
129
        $this->_exists[$dest] = true;
130
131
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_PUT, new TransporterEvent($this, array('dest' => $dest, 'src' => $src)));
132
133
        if ($this->cli->execute($commandline)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
134
            throw new \RuntimeException($this->cli->getErrorOutput());
135
        }
136
    }
137
138
    /**
139
     * Upload a string to remote server
140
     *
141
     * @param  string            $content content
142
     * @param  string            $dest    remote destination path
143
     * @throws \RuntimeException
144
     */
145 1 View Code Duplication
    public function putContent($content, $dest)
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...
146
    {
147 1
        $temp_file = tempnam(sys_get_temp_dir(), 'rsync' . time());
148
149 1
        file_put_contents($temp_file, $content);
150
151 1
        $commandline = sprintf("scp \"%s\" '%s@%s:%s'", $temp_file, $this->getUser(), $this->getHost(), $dest);
152
153 1
        $this->_exists[$dest] = true;
154
155 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_PUT_CONTENT, new TransporterEvent($this, array('dest' => $dest, 'src' => $temp_file, 'content' => $content)));
156
157 1
        if ($this->cli->execute($commandline)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
158
            @unlink($temp_file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
159
160
            throw new \RuntimeException($this->cli->getErrorOutput());
161
        }
162
163 1
        @unlink($temp_file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
164 1
    }
165
166
    /**
167
     * Creates a symlink on the remote server
168
     *
169
     * @param $src
170
     * @param $dest
171
     * @throws \RuntimeException
172
     * @return mixed
173
     */
174 1 View Code Duplication
    public function symlink($src, $dest)
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...
175
    {
176 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_SYMLINK, new TransporterEvent($this, array('dest' => $dest, 'src' => $src)));
177
178 1
        $remoteCommand = sprintf("ln -s %s %s", $src, $dest);
179 1
        $commandline   = sprintf("ssh %s@%s \"%s\"", $this->getUser(), $this->getHost(), $remoteCommand);
180
181 1
        if ($this->cli->execute($commandline)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
182
            throw new \RuntimeException($this->cli->getErrorOutput());
183
        }
184 1
    }
185
186
    /**
187
     * Checks for symlink on the remote server
188
     *
189
     * @param $dest
190
     * @return bool
191
     */
192 View Code Duplication
    public function isSymlink($dest)
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...
193
    {
194
        $remoteCommand = sprintf("readlink %s", $dest);
195
        $commandline   = sprintf("ssh %s@%s \"%s\"", $this->getUser(), $this->getHost(), $remoteCommand);
196
197
        if ($this->cli->execute($commandline)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
198
            return false;
199
        }
200
201
        return ('' !== trim($this->cli->getOutput()));
202
    }
203
204
    /**
205
     * Copies a file/directory on the remote host
206
     *
207
     * @param  string            $src
208
     * @param  string            $dest
209
     * @param  bool              $recursive
210
     * @throws \RuntimeException
211
     * @return mixed
212
     */
213 1
    public function copy($src, $dest, $recursive = true)
214
    {
215 1
        $recursiveFlag = ($recursive ? 'r' : '');
216
217 1
        $remoteCommand = sprintf("cp -{$recursiveFlag}f %s %s", $src, $dest);
218 1
        $commandline   = sprintf("ssh %s@%s \"%s\"", $this->getUser(), $this->getHost(), $remoteCommand);
219
220 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_COPY, new TransporterEvent($this, array('dest' => $dest, 'src' => $src)));
221
222 1
        if ($this->cli->execute($commandline)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
223
            throw new \RuntimeException($this->cli->getErrorOutput());
224
        }
225 1
    }
226
227
    /**
228
     * Removes a file/directory on the remote host
229
     *
230
     * @param  string            $path
231
     * @param  bool              $recursive
232
     * @throws \RuntimeException
233
     * @return mixed
234
     */
235 1 View Code Duplication
    public function remove($path, $recursive = true)
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...
236
    {
237 1
        $recursiveFlag = ($recursive ? 'r' : '');
238
239 1
        $remoteCommand = sprintf("rm -{$recursiveFlag}f %s", $path);
240 1
        $commandline   = sprintf("ssh %s@%s \"%s\"", $this->getUser(), $this->getHost(), $remoteCommand);
241
242 1
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_REMOVE, new TransporterEvent($this, array('path' => $path)));
243
244 1
        if ($this->cli->execute($commandline)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
245
            throw new \RuntimeException($this->cli->getErrorOutput());
246
        }
247 1
    }
248
249
    /**
250
     * @todo this is just a simple implementation which should be improved
251
     *
252
     * @param $command
253
     * @param  null              $callback
254
     * @throws \RuntimeException
255
     */
256 View Code Duplication
    public function exec($command, $callback = 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...
257
    {
258
        $commandline = sprintf("ssh %s@%s \"%s\"", $this->getUser(), $this->getHost(), $command);
259
260
        if ($this->cli->execute($commandline, $callback)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cli->execute($commandline, $callback) of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
261
            throw new \RuntimeException($this->cli->getErrorOutput());
262
        }
263
    }
264
265
    /**
266
     * Lists files and directories
267
     *
268
     * returns an array with the following format:
269
     *
270
     * array(
271
     *   'filename' => array(
272
     *     'type' => 'directory', // or 'file'
273
     *     'mtime' => new \DateTime(),
274
     *   ),
275
     * );
276
     *
277
     * @param  string            $path
278
     * @throws \RuntimeException
279
     * @return array
280
     */
281
    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...
282
    {
283
        throw new \RuntimeException('Listing of files and directories is not supported (yet)');
284
    }
285
}
286