Completed
Push — master ( 934cdf...8f45fc )
by Johnny
01:43
created

Ftp::__destruct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 6
ccs 0
cts 6
cp 0
rs 9.4286
cc 2
eloc 3
nc 2
nop 0
crap 6
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 $host     = '';
19
    protected $username = '';
20
    protected $password = '';
21
    protected $filename = '';
22
    protected $port     = 21;
23
24
    protected $timeout  = 90;
25
    protected $handle   = null;
26
27
    /**
28
     * You might think just connect to the ftp server from the constructor
29
     * but psr-4 dictates that autoloadable classes MUST NOT...
30
     *
31
     * Quote:
32
     * Autoloader implementations MUST NOT throw exceptions, MUST NOT raise errors of any level, and SHOULD NOT return a value.
33
     *
34
     * So we need to use authenticate() after we construct.
35
     *
36
     * @param string $host
37
     * @param string $username
38
     * @param string $password
39
     * @param string $filename
40
     * @param int $port
41
     * @param int $timeout
42
     */
43
    public function __construct($host = "", $username = "", $password = "", $filename = "", $port = 21, $timeout = 90)
44
    {
45
        $this->host     = $host;
46
        $this->username = $username;
47
        $this->password = $password;
48
        $this->filename = $filename;
49
        $this->timeout  = $timeout;
50
        $this->port     = $port;
51
    }
52
53
    /**
54
     * We should be so nice to terminate the construction of we are done.
55
     */
56
    public function __destruct()
57
    {
58
        if ($this->handle) {
59
            ftp_close($this->handle);
60
        }
61
    }
62
63
    /**
64
     * Authenticate to the ftp server.
65
     *
66
     * @return bool
67
     */
68
    public function authenticate()
69
    {
70
71
        set_error_handler(
72
            function () {
73
            }
74
        );
75
76
        $this->handle  = ftp_connect($this->host, $this->port, $this->timeout);
77
        $authenticated = ftp_login($this->handle, $this->username, $this->password);
78
79
        restore_error_handler();
80
81
        if ($this->handle === false) {
82
            throw new Exception\RuntimeException('Could not connect to host: '.$this->host);
83
        }
84
85
        if ($authenticated === false) {
86
            throw new Exception\RuntimeException('Could not authenticate to: '.$this->host);
87
        }
88
        return true;
89
    }
90
91
    /**
92
     * Read the previous scan results from the file system.
93
     *
94
     * @return array
95
     */
96
    public function read()
97
    {
98
        if ($this->handle === false)
99
            return false;
100
101
        $stream = fopen('php://memory', 'w');
102
103
        if (!$stream)
104
            return false;
105
106
        $data   = '';
107
        if ($ret = ftp_nb_fget($this->handle, $stream, $this->filename, self::FTP_MODE_ASCII)) {
108
            while ($ret === FTP_MOREDATA) {
109
                rewind($stream);
110
                $data .=  stream_get_contents($stream);
111
                $ret = ftp_nb_continue($this->handle);
112
            }
113
            if ($ret != FTP_FINISHED) {
114
               return false;
115
            } else {
116
                $data = Yaml::parse($data);
117
                return Report\Report::fromArray($data);
118
            }
119
        }
120
        return false;
121
    }
122
123
    /**
124
     * Write the report to the filesystem so we can reuse it
125
     * at a later stace when we invoke Redbox\Scan\ScanService's scan() method.
126
     *
127
     * @param Report\Report|null $report
128
     * @return bool
129
     */
130
    public function write(Report\Report $report = null)
131
    {
132
        if ($this->handle === false)
133
            return false;
134
135
        if ($report) {
136
137
            $stream = fopen('php://memory', 'w+');
138
            if (!$stream) return false;
139
            $data = $report->toArray();
140
            $data = Yaml::dump($data, 99);
141
142
            fwrite($stream, $data);
143
            rewind($stream);
144
145
            if (ftp_fput($this->handle, $this->filename, $stream, self::FTP_MODE_ASCII)) {
146
                return true;
147
            } else {
148
                return false;
149
            }
150
        }
151
        return false;
152
    }
153
}