GlSyncFtp::getFiles()   B
last analyzed

Complexity

Conditions 6
Paths 5

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 17
rs 8.8571
cc 6
eloc 11
nc 5
nop 4
1
<?php
2
3
/**
4
 * Sync local files with ftp server
5
 *
6
 * PHP version 5.4
7
 *
8
 * @category  GLICER
9
 * @package   GlSyncFtp
10
 * @author    Emmanuel ROECKER
11
 * @author    Rym BOUCHAGOUR
12
 * @copyright 2015 GLICER
13
 * @license   MIT
14
 * @link      http://dev.glicer.com/
15
 *
16
 * Created : 22/05/15
17
 * File : GlSyncFtp.php
18
 *
19
 */
20
21
namespace GlSyncFtp;
22
23
use Symfony\Component\Finder\SplFileInfo;
24
use Symfony\Component\Finder\Finder;
25
use phpseclib\Net\SFTP;
26
27
/**
28
 * Class SFTPConnection
29
 * @package GLICER\GetterBundle\Ftp
30
 */
31
class GlSyncFtp
32
{
33
    const DELETE_FILE = 0;
34
    const DELETE_DIR  = 1;
35
    const CREATE_DIR  = 2;
36
    const NEW_FILE    = 3;
37
    const UPDATE_FILE = 4;
38
39
    /**
40
     * @var SFTP
41
     */
42
    private $sftp;
43
44
    /**
45
     * @var string
46
     */
47
    private $server;
48
49
    /**
50
     * @var int
51
     */
52
    private $port;
53
54
    /**
55
     * @var string
56
     */
57
    private $user;
58
59
    /**
60
     * @var string
61
     */
62
    private $password;
63
64
    /**
65
     * @param string $ftpserver
66
     * @param int    $port
67
     * @param string $user
68
     * @param string $password
69
     */
70
    public function __construct($ftpserver, $port, $user, $password)
71
    {
72
        $this->server   = $ftpserver;
73
        $this->port     = $port;
74
        $this->user     = $user;
75
        $this->password = $password;
76
    }
77
78
    public function __destruct()
79
    {
80
        $this->disconnect();
81
    }
82
83
    public function disconnect()
84
    {
85
        if (isset($this->sftp)) {
86
            $this->sftp->disconnect();
87
        }
88
    }
89
90
    /**
91
     * @param string $root
92
     * @param array  $listfiles
93
     * @param array  $listdirs
94
     *
95
     * @throws GlSyncFtpException
96
     */
97
    public function getAllFiles($root, &$listfiles, &$listdirs)
98
    {
99
        $this->login();
100
        $this->getFiles($root, "", $listfiles, $listdirs);
101
    }
102
103
    /**
104
     * @throws GlSyncFtpException
105
     */
106
    private function login()
107
    {
108
        if (isset($this->sftp)) {
109
            return;
110
        }
111
112
        $this->sftp = new SFTP($this->server, $this->port);
113
        if (!$this->sftp->login($this->user, $this->password)) {
114
            throw new GlSyncFtpException('Login Failed');
115
        }
116
    }
117
118
    /**
119
     * @param string $root
120
     * @param string $relative
121
     * @param array  $listfiles
122
     * @param array  $listdirs
123
     */
124
    private function getFiles($root, $relative, &$listfiles, &$listdirs)
125
    {
126
        $files = $this->sftp->rawlist($root . '/' . $relative);
127
        if ($files === false) {
128
            return;
129
        }
130
        foreach ($files as $name => $raw) {
131
            if (($name != '.') && ($name != '..')) {
132
                if ($raw['type'] == NET_SFTP_TYPE_DIRECTORY) {
133
                    $listdirs[$relative . '/' . $name] = $raw;
134
                    $this->getFiles($root, $relative . '/' . $name, $listfiles, $listdirs);
135
                } else {
136
                    $listfiles[$relative . '/' . $name] = $raw;
137
                }
138
            }
139
        }
140
    }
141
142
143
    /**
144
     * sync list of local directories with list of ftp directories
145
     *
146
     * @param array    $list
147
     * @param callable $syncdir = null
148
     * @param callable $syncop  = null
149
     */
150
    public function syncDirectories($list, callable $syncdir = null, callable $syncop = null)
151
    {
152
        foreach ($list as $src => $dst) {
153
            if ($syncdir) {
154
                $syncdir($src, $dst);
155
            }
156
            $this->syncDirectory(
157
                 $src,
158
                     $dst,
159
                     $syncop
160
            );
161
        }
162
    }
163
164
    /**
165
     * delete files unknowns on ftp server
166
     * 
167
     * @param string $src
168
     * @param string $dst
169
     * @param callable|null $syncop
170
     */
171
    private function syncDelete($src, $dst,callable $syncop = null) {
172
        $files = [];
173
        $dirs  = [];
174
        $this->getFiles($dst, "", $files, $dirs);
175
176
        // delete on ftp server, files not present in local directory
177 View Code Duplication
        foreach ($files as $name => $raw) {
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...
178
            if (!file_exists($src . $name)) {
179
                $filepathFtp = $dst . strtr($name, ["\\" => "/"]);
180
                if ($syncop) {
181
                    $syncop(self::DELETE_FILE, $filepathFtp);
182
                }
183
                $this->sftp->delete($filepathFtp);
184
            }
185
        }
186
187
        // delete on ftp server, unknowns directories
188
        $dirs = array_reverse($dirs);
189 View Code Duplication
        foreach ($dirs as $name => $raw) {
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...
190
            if (!file_exists($src . $name)) {
191
                $filepathFtp = $dst . strtr($name, ["\\" => "/"]);
192
                if ($syncop) {
193
                    $syncop(self::DELETE_DIR, $filepathFtp);
194
                }
195
                $this->sftp->rmdir($filepathFtp);
196
            }
197
        }        
198
    }
199
200
201
    /**
202
     * sync local directory with ftp directory
203
     *
204
     * @param string        $src
205
     * @param string        $dst
206
     * @param callable|null $syncop
207
     *
208
     * @throws GlSyncFtpException
209
     */
210
    public function syncDirectory($src, $dst, callable $syncop = null)
211
    {
212
        $this->login();
213
214
        $this->syncDelete($src, $dst, $syncop);
215
        
216
        // create new directories
217
        $finderdir = new Finder();
218
        $finderdir->directories()->ignoreDotFiles(false)->followLinks()->in($src)->notName('.git*');
219
220
        /**
221
         * @var SplFileInfo $dir
222
         */
223
        foreach ($finderdir as $dir) {
224
            $dirpathFtp = $dst . "/" . strtr($dir->getRelativePathname(), ["\\" => "/"]);
225
            $stat       = $this->sftp->stat($dirpathFtp);
226
            if (!$stat) {
227
                if ($syncop) {
228
                    $syncop(self::CREATE_DIR, $dirpathFtp);
229
                }
230
                $this->sftp->mkdir($dirpathFtp, $dir->getRealPath(), SFTP::SOURCE_LOCAL_FILE);
231
                $this->sftp->chmod(0755, $dirpathFtp, $dir->getRealPath());
232
            }
233
        }
234
235
        // copy new files or update if younger
236
        $finderdir = new Finder();
237
        $finderdir->files()->ignoreDotFiles(false)->followLinks()->in($src)->notName('.git*');
238
239
        /**
240
         * @var SplFileInfo $file
241
         */
242
        foreach ($finderdir as $file) {
243
            $filepathFtp = $dst . "/" . strtr($file->getRelativePathname(), ["\\" => "/"]);
244
            $stat        = $this->sftp->stat($filepathFtp);
245
            if (!$stat) {
246
                if ($syncop) {
247
                    $syncop(self::NEW_FILE, $filepathFtp);
248
                }
249
                $this->sftp->put($filepathFtp, $file->getRealPath(), SFTP::SOURCE_LOCAL_FILE);
250
            } else {
251
                $size = $this->sftp->size($filepathFtp);
252
                if (($file->getMTime() > $stat['mtime']) || ($file->getSize() != $size)) {
253
                    if ($syncop) {
254
                        $syncop(self::UPDATE_FILE, $filepathFtp);
255
                    }
256
                    $this->sftp->put($filepathFtp, $file->getRealPath(), SFTP::SOURCE_LOCAL_FILE);
257
                }
258
            }
259
        }
260
    }
261
}
262
263