Completed
Push — master ( b77c5c...4fbeac )
by Jeroen
10s
created

FtpTransporter::putContent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 1
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 2
crap 6
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 Symfony\Component\Finder\Finder;
16
use Webcreate\Conveyor\Event\TransporterEvent;
17
use Webcreate\Conveyor\Event\TransporterEvents;
18
19
class FtpTransporter extends AbstractTransporter
20
{
21
    protected $stream;
22
23 1
    public function __construct(EventDispatcherInterface $dispatcher)
24
    {
25 1
        $this->setDispatcher($dispatcher);
26 1
    }
27
28
    public function connect()
29
    {
30
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_CONNECT, new TransporterEvent($this));
31
32
        $port = $this->port ?: 21;
33
34
        $this->stream = ftp_connect($this->host, $port);
35
        if (false == $this->stream) {
36
            throw new \RuntimeException(sprintf('Could not connect to host %s on port %s', $this->host, $port));
37
        }
38
        ftp_pasv($this->stream, true);
39
    }
40
41
    public function login()
42
    {
43
        $success = ftp_login($this->stream, $this->username, $this->password);
0 ignored issues
show
Unused Code introduced by
$success 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...
44
    }
45
46 1
    public function connectAndLogin()
47
    {
48 1
        $this->connect();
49 1
        $this->login();
50 1
    }
51
52
    public function exists($path)
53
    {
54
        if (!$this->stream) {
55
            $this->connectAndLogin();
56
        }
57
58
        $pwd = ftp_pwd($this->stream);
59
60
        // try to change directory to see if it is an existing directory
61
        $result = @ftp_chdir($this->stream, $path);
62
        if (true === $result) {
63
            ftp_chdir($this->stream, $pwd); // change back to the original directory
64
65
            return true;
66
        } else {
67
            // list the parent directory and check if the file exists
68
            $parent = dirname($path);
69
            $options = '-a'; // list hidden
70
            $result = ftp_rawlist($this->stream, $options . ' ' . $parent);
71
72
            if (false !== $result) {
73
                foreach ($result as $line) {
74
                    if (false !== $pos = strrpos($line, basename($path))) {
75
                        return true;
76
                    }
77
                }
78
            }
79
        }
80
81
        return false;
82
    }
83
84
    public function mkdir($dest)
85
    {
86
        $pwd = dirname($dest);
87
        if (false === $this->exists($pwd)) {
88
            $this->mkdir($pwd);
89
        }
90
91
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_MKDIR, new TransporterEvent($this, $dest));
92
93
        ftp_mkdir($this->stream, $dest);
94
    }
95
96 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...
97
    {
98
        if (!$this->stream) {
99
            $this->connectAndLogin();
100
        }
101
102
        $realDest = $dest;
103
104
        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...
105
            $realDest = tempnam(sys_get_temp_dir(), basename($src));
106
        }
107
108
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_GET, new TransporterEvent($this, array('src' => $src, 'dest' => $dest)));
109
110
        $succes = ftp_get($this->stream, $realDest, $src, FTP_BINARY);
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...
111
112
        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...
113
            $content = file_get_contents($realDest);
114
            unlink($realDest);
115
116
            return $content;
117
        }
118
    }
119
120 1
    public function put($src, $dest)
121
    {
122 1
        if (!$this->stream) {
123 1
            $this->connectAndLogin();
124
        }
125
126 1
        if (false === file_exists($src)) {
127 1
            throw new \InvalidArgumentException(sprintf('Resource \'%s\' does not exist', $src));
128
        }
129
130
        if (is_file($src)) {
131
            $pwd = dirname($dest);
132
            if (false === $this->exists($pwd)) {
133
                $this->mkdir($pwd);
134
            }
135
136
            $file = new \SplFileInfo($src);
137
138
            $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_PUT, new TransporterEvent($this, array('dest' => $dest, 'src' => $file->getPathname())));
139
140
            ftp_put($this->stream, $dest, $file->getPathname(), FTP_BINARY);
141 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...
142
            if (!$this->exists($dest)) {
143
                $this->mkdir($dest);
144
            }
145
146
            $finder = new Finder();
147
            $test = $finder->in($src)->depth('== 0');
148
149
            foreach ($test as $file) {
150
                $this->put(rtrim($src, '/') . '/' . $file->getFilename(), rtrim($dest, '/')  . '/' . $file->getFilename());
151
            }
152
        }
153
    }
154
155
    public function putContent($content, $dest)
156
    {
157
        if (!$this->stream) {
158
            $this->connectAndLogin();
159
        }
160
161
        $this->dispatcher->dispatch(TransporterEvents::TRANSPORTER_PUT_CONTENT, new TransporterEvent($this, array('dest' => $dest, 'content' => $content)));
162
163
        $tempfile = tempnam(sys_get_temp_dir(), 'conveyor');
164
165
        file_put_contents($tempfile, $content);
166
167
        ftp_put($this->stream, $dest, $tempfile, FTP_BINARY);
168
169
        unlink($tempfile);
170
    }
171
172
    /**
173
     * Creates a symlink on the remote server
174
     *
175
     * @param $src
176
     * @param $dest
177
     * @throws \RuntimeException
178
     * @return mixed
179
     */
180
    public function symlink($src, $dest)
181
    {
182
        throw new \RuntimeException('Symlinking not supported');
183
    }
184
185
    /**
186
     * Checks for symlink on the remote server
187
     *
188
     * @param $dest
189
     * @throws \RuntimeException
190
     * @return bool
191
     */
192
    public function isSymlink($dest)
193
    {
194
        throw new \RuntimeException('Symlinking not supported');
195
    }
196
197
    /**
198
     * Copies a file/directory on the remote host
199
     *
200
     * @param  string            $src
201
     * @param  string            $dest
202
     * @param  bool              $recursive
203
     * @throws \RuntimeException
204
     * @return mixed
205
     */
206
    public function copy($src, $dest, $recursive = true)
207
    {
208
        throw new \RuntimeException('Copy (yet) not supported');
209
    }
210
211
    /**
212
     * Removes a file/directory on the remote host
213
     *
214
     * @param  string            $path
215
     * @param  bool              $recursive
216
     * @throws \RuntimeException
217
     * @return mixed
218
     */
219
    public function remove($path, $recursive = true)
220
    {
221
        throw new \RuntimeException('Remove (yet) not supported');
222
    }
223
224
    /**
225
     * Lists files and directories
226
     *
227
     * @todo WARNING: this is untested code!!
228
     *
229
     * @param  string $path
230
     * @return mixed
231
     */
232
    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...
233
    {
234
        if (!$this->stream) {
235
            $this->connectAndLogin();
236
        }
237
238
        $list = ftp_rawlist($this->stream, $path);
239
240
        $retval = array();
241
242
        foreach ($list as $info) {
243
            $item = array();
244
            $chunks = preg_split('/\s+/', $info);
245
246
            list(
247
                $item['rights'],
248
                $item['number'],
249
                $item['user'],
250
                $item['group'],
251
                $item['size'],
252
                $item['month'],
253
                $item['day'],
254
                $item['time']) = $chunks;
255
256
            $item['type'] = $chunks[0]{0} === 'd' ? 'directory' : 'file';
257
258
            array_splice($chunks, 0, 8);
259
            $fileOrDirectory = implode(" ", $chunks);
260
261
            if ('..' === $fileOrDirectory || '.' === $fileOrDirectory) {
262
                continue;
263
            }
264
265
            $retval[$fileOrDirectory] = array(
266
                'type' => $item['type'],
267
                'mtime' => new \DateTime(sprintf('%s %s %s', $item['month'], $item['day'], $item['time'])),
268
            );
269
        }
270
271
        return $retval;
272
    }
273
274
    public function __destruct()
275
    {
276
        if ($this->stream) {
277
            ftp_close($this->stream);
278
        }
279
    }
280
}
281