Completed
Push — master ( 72cf29...ecec76 )
by Sebastian
03:13
created

AmazonS3v3   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 17.54%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 16
lcom 1
cbo 8
dl 0
loc 179
ccs 10
cts 57
cp 0.1754
rs 10
c 2
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A setup() 0 6 1
B sync() 0 25 3
A createCollector() 0 4 1
A simulate() 0 6 1
A createBucket() 0 10 1
A upload() 0 8 2
A uploadStream() 0 10 2
A uploadMultiPart() 0 8 1
A getFileHandle() 0 8 2
A getUploadPath() 0 4 2
1
<?php
2
namespace phpbu\App\Backup\Sync;
3
4
use Aws\S3\S3Client;
5
use Aws\S3\MultipartUploader;
6
use phpbu\App\Backup\Collector;
7
use phpbu\App\Result;
8
use phpbu\App\Backup\Target;
9
use phpbu\App\Util;
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 Clearable;
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 9
    public function setup(array $config)
42
    {
43 9
        parent::setup($config);
44
45 4
        $this->setUpClearable($config);
46 4
    }
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
    public function sync(Target $target, Result $result)
57
    {
58
        $this->client = new S3Client([
59
            'region'  => $this->region,
60
            'version' => '2006-03-01',
61
            'credentials' => [
62
                'key'    => $this->key,
63
                'secret' => $this->secret,
64
            ]
65
        ]);
66
67
        if (!$this->client->doesBucketExist($this->bucket)) {
68
            $result->debug('create s3 bucket');
69
            $this->createBucket($this->client);
70
        }
71
72
        try {
73
            $this->upload($target, $this->client);
74
        } catch (\Exception $e) {
75
            throw new Exception($e->getMessage(), null, $e);
76
        }
77
        // run remote cleanup
78
        $this->cleanup($target, $result);
79
        $result->debug('upload: done');
80
    }
81
82
    /**
83
     * Creates collector for Amazon S3
84
     *
85
     * @param  \phpbu\App\Backup\Target $target
86
     * @return \phpbu\App\Backup\Collector
87
     */
88
    protected function createCollector(Target $target) : Collector
89
    {
90
        return new Collector\AmazonS3v3($target, $this->client, $this->bucket, $this->pathRaw, $this->time);
91
    }
92
93
    /**
94
     * Simulate the sync execution.
95
     *
96
     * @param \phpbu\App\Backup\Target $target
97
     * @param \phpbu\App\Result        $result
98
     */
99 1
    public function simulate(Target $target, Result $result)
100
    {
101 1
        parent::simulate($target, $result);
102
103 1
        $this->simulateRemoteCleanup($target, $result);
104 1
    }
105
106
    /**
107
     * Create a s3 bucket.
108
     *
109
     * @param \Aws\S3\S3Client $s3
110
     */
111
    private function createBucket(S3Client $s3)
112
    {
113
        $s3->createBucket([
114
            'ACL'                       => $this->acl,
115
            'Bucket'                    => $this->bucket,
116
            'CreateBucketConfiguration' => [
117
                'LocationConstraint' => $this->region,
118
            ]
119
        ]);
120
    }
121
122
    /**
123
     * Upload backup to Amazon S3 bucket.
124
     *
125
     * @param  \phpbu\App\Backup\Target $target
126
     * @param  \Aws\S3\S3Client         $s3
127
     * @throws \phpbu\App\Backup\Sync\Exception
128
     * @throws \phpbu\App\Exception
129
     */
130
    private function upload(Target $target, S3Client $s3)
131
    {
132
        if ($this->useMultiPartUpload($target)) {
133
            $this->uploadMultiPart($target, $s3);
134
        } else {
135
            $this->uploadStream($target, $s3);
136
        }
137
    }
138
139
    /**
140
     * Upload via stream wrapper.
141
     *
142
     * @param  \phpbu\App\Backup\Target $target
143
     * @param  \Aws\S3\S3Client         $s3
144
     * @throws \phpbu\App\Backup\Sync\Exception
145
     */
146
    private function uploadStream(Target $target, S3Client $s3)
147
    {
148
        $s3->registerStreamWrapper();
149
        $source = $this->getFileHandle($target->getPathname(), 'r');
150
        $stream = $this->getFileHandle('s3://' . $this->bucket . '/' . $this->getUploadPath($target), 'w');
151
        while (!feof($source)) {
152
            fwrite($stream, fread($source, 4096));
153
        }
154
        fclose($stream);
155
    }
156
157
    /**
158
     * Upload via multi part.
159
     *
160
     * @param \phpbu\App\Backup\Target $target
161
     * @param \Aws\S3\S3Client         $s3
162
     * @param \Aws\Exception\MultipartUploadException
163
     */
164
    private function uploadMultiPart(Target $target, S3Client $s3)
165
    {
166
        $uploader = new MultipartUploader($s3, $target->getPathname(), [
167
            'bucket' => $this->bucket,
168
            'key'    => $this->getUploadPath($target),
169
        ]);
170
        $uploader->upload();
171
    }
172
173
    /**
174
     * Open stream and validate it.
175
     *
176
     * @param  string $path
177
     * @param  string $mode
178
     * @return resource
179
     * @throws \phpbu\App\Backup\Sync\Exception
180
     */
181
    private function getFileHandle($path, $mode)
182
    {
183
        $handle = fopen($path, $mode);
184
        if (!is_resource($handle)) {
185
            throw new Exception('fopen failed: could not open stream ' . $path);
186
        }
187
        return $handle;
188
    }
189
190
    /**
191
     * Get the s3 upload path
192
     *
193
     * @param \phpbu\App\Backup\Target $target
194
     * @return string
195
     */
196 2
    public function getUploadPath(Target $target)
197
    {
198 2
        return (!empty($this->path) ? $this->path . '/' : '') . $target->getFilename();
199
    }
200
}
201