Completed
Push — master ( 6fad86...9aa46f )
by Johnny
01:50
created

Ftp::setTransferMode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
namespace Redbox\Scan\Adapter;
3
use Redbox\Scan\Exception;
4
use Redbox\Scan\Report;
5
use Symfony\Component\Yaml\Yaml;
6
7
/**
8
 * Read and write files from a given ftp location.
9
 * see examples/ftp.php for a demonstration.
10
 *
11
 * @package Redbox\Scan\Adapter
12
 */
13
class Ftp implements AdapterInterface
14
{
15
    const FTP_MODE_ASCII  = FTP_ASCII;
16
    const FTP_MODE_BINARY = FTP_BINARY;
17
18
    protected $transfer_mode = self::FTP_MODE_ASCII;
19
    protected $host          = '';
20
    protected $username      = '';
21
    protected $password      = '';
22
    protected $filename      = '';
23
    protected $port          = 21;
24
25
    protected $timeout       = 90;
26
    protected $handle        = null;
27
28
    /**
29
     * You might think just connect to the ftp server from the constructor
30
     * but psr-4 dictates that autoloadable classes MUST NOT...
31
     *
32
     * Quote:
33
     * Autoloader implementations MUST NOT throw exceptions, MUST NOT raise errors of any level, and SHOULD NOT return a value.
34
     *
35
     * So we need to use authenticate() after we construct.
36
     *
37
     * @param string $host
38
     * @param string $username
39
     * @param string $password
40
     * @param string $filename
41
     * @param int $port
42
     * @param int $timeout
43
     */
44
    public function __construct($host = "", $username = "", $password = "", $filename = "", $port = 21, $timeout = 90)
45
    {
46
        $this->host     = $host;
47
        $this->username = $username;
48
        $this->password = $password;
49
        $this->filename = $filename;
50
        $this->timeout  = $timeout;
51
        $this->port     = $port;
52
    }
53
54
    /**
55
     * Set the connection transfer mode to FTP_MODE_ASCII or FTP_MODE_BINARY.
56
     *
57
     * @param $transfer_mode
58
     */
59
    public function setTransferMode($transfer_mode)
60
    {
61
        $this->transfer_mode = $transfer_mode;
62
    }
63
64
    /**
65
     * Return the current TransferMode.
66
     *
67
     * @return int
68
     */
69
    public function getTransferMode()
70
    {
71
        return $this->transfer_mode;
72
    }
73
74
    /**
75
     * Set passive mode on or off. Please not that you can
76
     * only use this mode after you have authenticated the user.
77
     *
78
     * @param bool $status
79
     * @return mixed
80
     */
81
    public function setPassiveMode(bool $status)
82
    {
83
        return @ftp_pasv($this->handle, $status);
84
    }
85
86
    /**
87
     * Disable passive mode and switch to active mode.
88
     */
89
    public function setActiveMode()
90
    {
91
        return $this->setPassiveMode(false);
92
    }
93
94
    /**
95
     * We should be so nice to terminate the construction of we are done.
96
     */
97
    public function __destruct()
98
    {
99
        if ($this->handle) {
100
            ftp_close($this->handle);
101
        }
102
    }
103
104
    /**
105
     * Authenticate to the ftp server.
106
     *
107
     * @return bool
108
     */
109
    public function authenticate()
110
    {
111
112
        set_error_handler(
113
            function () {
114
            }
115
        );
116
117
        $this->handle  = ftp_connect($this->host, $this->port, $this->timeout);
118
        $result        = ftp_login($this->handle, $this->username, $this->password);
119
120
        restore_error_handler();
121
122
        if ($this->handle === false) {
123
            throw new Exception\RuntimeException('Could not connect to host: '.$this->host);
124
        }
125
126
        if ($result === false) {
127
            throw new Exception\RuntimeException('Could not authenticate to: '.$this->host);
128
        }
129
130
        return $result;
131
    }
132
133
    /**
134
     * Read the previous scan results from the file system.
135
     *
136
     * @return array
137
     */
138
    public function read()
139
    {
140
        if (!$this->handle)
141
            return false;
142
143
        $stream = fopen('php://memory', 'w');
144
145
        if (!$stream)
146
            return false;
147
148
        $data   = '';
149
        if ($ret = ftp_nb_fget($this->handle, $stream, $this->filename, $this->transfer_mode)) {
150
            while ($ret === FTP_MOREDATA) {
151
                rewind($stream);
152
                $data .=  stream_get_contents($stream);
153
                $ret = ftp_nb_continue($this->handle);
154
            }
155
            if ($ret != FTP_FINISHED) {
156
               return false;
157
            } else {
158
                $data = (array)Yaml::parse($data);
159
                return Report\Report::fromArray($data);
160
            }
161
        }
162
        return false;
163
    }
164
165
    /**
166
     * Write the report to the filesystem so we can reuse it
167
     * at a later stace when we invoke Redbox\Scan\ScanService's scan() method.
168
     *
169
     * @param Report\Report|null $report
170
     * @return bool
171
     */
172
    public function write(Report\Report $report = null)
173
    {
174
        if (!$this->handle)
175
            return false;
176
177
        if ($report) {
178
179
            $stream = fopen('php://memory', 'w+');
180
            if (!$stream) return false;
181
            $data = $report->toArray();
182
            $data = Yaml::dump($data, 99);
183
184
            fwrite($stream, $data);
185
            rewind($stream);
186
187
            if (ftp_fput($this->handle, $this->filename, $stream, $this->transfer_mode)) {
188
                return true;
189
            }
190
        }
191
        return false;
192
    }
193
}