Completed
Pull Request — master (#140)
by
unknown
05:09
created

AmazonS3v3::upload()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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