AmazonS3v3   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 201
Duplicated Lines 0 %

Test Coverage

Coverage 61.29%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 50
dl 0
loc 201
ccs 38
cts 62
cp 0.6129
rs 10
c 4
b 0
f 0
wmc 18

12 Methods

Rating   Name   Duplication   Size   Complexity  
A uploadMultiPart() 0 4 1
A createCollector() 0 4 1
A createClient() 0 8 1
A createBucket() 0 7 1
A setup() 0 5 1
A upload() 0 6 2
A simulate() 0 5 1
A uploadStream() 0 9 2
A createUploader() 0 5 1
A getUploadPath() 0 3 2
A getFileHandle() 0 7 2
A sync() 0 17 3
1
<?php
2
namespace phpbu\App\Backup\Sync;
3
4
use Aws\S3\MultipartUploader;
5
use Aws\S3\S3Client;
6
use phpbu\App\Backup\Collector;
7
use phpbu\App\Backup\Path;
8
use phpbu\App\Backup\Target;
9
use phpbu\App\Result;
10
11
/**
12
 * Amazon S3 Sync
13
 *
14
 * @package    phpbu
15
 * @subpackage Backup
16
 * @author     Sebastian Feldmann <[email protected]>
17
 * @copyright  Sebastian Feldmann <[email protected]>
18
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
19
 * @link       http://phpbu.de/
20
 * @since      Class available since Release 3.0.0
21
 */
22
class AmazonS3v3 extends AmazonS3
23
{
24
    use Cleanable;
0 ignored issues
show
introduced by
The trait phpbu\App\Backup\Sync\Cleanable requires some properties which are not provided by phpbu\App\Backup\Sync\AmazonS3v3: $type, $options
Loading history...
25
26
    /**
27
     * Amazon S3 client.
28
     *
29
     * @var S3Client;
30
     */
31
    protected $client;
32
33
    /**
34
     * Configure the sync.
35
     *
36
     * @see    \phpbu\App\Backup\Sync::setup()
37
     * @param  array $config
38
     * @throws \phpbu\App\Backup\Sync\Exception
39
     * @throws \phpbu\App\Exception
40
     */
41 12
    public function setup(array $config)
42
    {
43 12
        parent::setup($config);
44
45 7
        $this->setUpCleanable($config);
46 7
    }
47
48
    /**
49
     * Execute the sync.
50
     *
51
     * @see    \phpbu\App\Backup\Sync::sync()
52
     * @param  \phpbu\App\Backup\Target $target
53
     * @param  \phpbu\App\Result        $result
54
     * @throws \phpbu\App\Backup\Sync\Exception
55
     */
56 3
    public function sync(Target $target, Result $result)
57
    {
58 3
        $this->client = $this->createClient();
59
60 3
        if (!$this->client->doesBucketExist($this->bucket)) {
61 2
            $result->debug('create s3 bucket');
62 2
            $this->createBucket($this->client);
63
        }
64
65
        try {
66 3
            $this->upload($target, $this->client);
67 2
            $result->debug('upload: done');
68
69
            // run remote cleanup
70 2
            $this->cleanup($target, $result);
71 1
        } catch (\Exception $e) {
72 1
            throw new Exception($e->getMessage(), null, $e);
73
        }
74 2
    }
75
76
    /**
77
     * Create the AWS client.
78
     *
79
     * @return \Aws\S3\S3Client
80
     */
81
    protected function createClient() : S3Client
82
    {
83
        return new S3Client([
84
            'region'      => $this->region,
85
            'version'     => '2006-03-01',
86
            'credentials' => [
87
                'key'    => $this->key,
88
                'secret' => $this->secret,
89
            ]
90
        ]);
91
    }
92
93
    /**
94
     * Create a multi part s3 file uploader.
95
     *
96
     * @param  \phpbu\App\Backup\Target $target
97
     * @param  \Aws\S3\S3Client         $s3
98
     * @return \Aws\S3\MultipartUploader
99
     */
100
    protected function createUploader(Target $target, S3Client $s3) : MultipartUploader
101
    {
102
        return new MultipartUploader($s3, $target->getPathname(), [
103
            'bucket' => $this->bucket,
104
            'key'    => $this->getUploadPath($target),
105
        ]);
106
    }
107
108
    /**
109
     * Creates collector for Amazon S3
110
     *
111
     * @param  \phpbu\App\Backup\Target $target
112
     * @return \phpbu\App\Backup\Collector
113
     */
114 1
    protected function createCollector(Target $target) : Collector
115
    {
116 1
        $path = new Path($this->pathRaw, $this->time);
117 1
        return new Collector\AmazonS3v3($target, $path, $this->client, $this->bucket);
118
    }
119
120
    /**
121
     * Simulate the sync execution.
122
     *
123
     * @param \phpbu\App\Backup\Target $target
124
     * @param \phpbu\App\Result        $result
125
     */
126 1
    public function simulate(Target $target, Result $result)
127
    {
128 1
        parent::simulate($target, $result);
129
130 1
        $this->simulateRemoteCleanup($target, $result);
131 1
    }
132
133
    /**
134
     * Create a s3 bucket.
135
     *
136
     * @param \Aws\S3\S3Client $s3
137
     */
138 2
    private function createBucket(S3Client $s3)
139
    {
140 2
        $s3->createBucket([
141 2
            'ACL'                       => $this->acl,
142 2
            'Bucket'                    => $this->bucket,
143
            'CreateBucketConfiguration' => [
144 2
                'LocationConstraint' => $this->region,
145
            ]
146
        ]);
147 2
    }
148
149
    /**
150
     * Upload backup to Amazon S3 bucket.
151
     *
152
     * @param  \phpbu\App\Backup\Target $target
153
     * @param  \Aws\S3\S3Client         $s3
154
     * @throws \phpbu\App\Backup\Sync\Exception
155
     * @throws \phpbu\App\Exception
156
     */
157 3
    private function upload(Target $target, S3Client $s3)
158
    {
159 3
        if ($this->useMultiPartUpload($target)) {
160 3
            $this->uploadMultiPart($target, $s3);
161
        } else {
162
            $this->uploadStream($target, $s3);
163
        }
164 2
    }
165
166
    /**
167
     * Upload via stream wrapper.
168
     *
169
     * @param  \phpbu\App\Backup\Target $target
170
     * @param  \Aws\S3\S3Client         $s3
171
     * @throws \phpbu\App\Backup\Sync\Exception
172
     */
173
    private function uploadStream(Target $target, S3Client $s3)
174
    {
175
        $s3->registerStreamWrapper();
176
        $source = $this->getFileHandle($target->getPathname(), 'r');
177
        $stream = $this->getFileHandle('s3://' . $this->bucket . '/' . $this->getUploadPath($target), 'w');
178
        while (!feof($source)) {
179
            fwrite($stream, fread($source, 4096));
180
        }
181
        fclose($stream);
182
    }
183
184
    /**
185
     * Upload via multi part.
186
     *
187
     * @param \phpbu\App\Backup\Target $target
188
     * @param \Aws\S3\S3Client         $s3
189
     * @throws \Aws\Exception\MultipartUploadException
190
     */
191 3
    private function uploadMultiPart(Target $target, S3Client $s3)
192
    {
193 3
        $uploader = $this->createUploader($target, $s3);
194 3
        $uploader->upload();
195 2
    }
196
197
    /**
198
     * Open stream and validate it.
199
     *
200
     * @param  string $path
201
     * @param  string $mode
202
     * @return resource
203
     * @throws \phpbu\App\Backup\Sync\Exception
204
     */
205
    private function getFileHandle($path, $mode)
206
    {
207
        $handle = fopen($path, $mode);
208
        if (!is_resource($handle)) {
209
            throw new Exception('fopen failed: could not open stream ' . $path);
210
        }
211
        return $handle;
212
    }
213
214
    /**
215
     * Get the s3 upload path
216
     *
217
     * @param  \phpbu\App\Backup\Target $target
218
     * @return string
219
     */
220 2
    public function getUploadPath(Target $target)
221
    {
222 2
        return (!empty($this->path) ? $this->path . '/' : '') . $target->getFilename();
223
    }
224
}
225