Completed
Push — master ( e61230...7500e8 )
by Sebastian
04:38
created

AmazonS3v3::upload()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
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
    /**
23
     * Execute the sync.
24
     *
25
     * @see    \phpbu\App\Backup\Sync::sync()
26
     * @param  \phpbu\App\Backup\Target $target
27
     * @param  \phpbu\App\Result        $result
28
     * @throws \phpbu\App\Backup\Sync\Exception
29
     */
30
    public function sync(Target $target, Result $result)
31
    {
32
        $s3 = new S3Client([
33
            'region'  => $this->region,
34
            'version' => '2006-03-01',
35
            'credentials' => [
36
                'key'    => $this->key,
37
                'secret' => $this->secret,
38
            ]
39
        ]);
40
41
        if (!$s3->doesBucketExist($this->bucket)) {
42
            $result->debug('create s3 bucket');
43
            $this->createBucket($s3);
44
        }
45
46
        try {
47
            $this->upload($target, $s3);
48
        } catch (\Exception $e) {
49
            throw new Exception($e->getMessage(), null, $e);
50
        }
51
        $result->debug('upload: done');
52
    }
53
54
    /**
55
     * Create a s3 bucket.
56
     *
57
     * @param \Aws\S3\S3Client $s3
58
     */
59
    private function createBucket(S3Client $s3)
60
    {
61
        $s3->createBucket([
62
            'ACL'                       => $this->acl,
63
            'Bucket'                    => $this->bucket,
64
            'CreateBucketConfiguration' => [
65
                'LocationConstraint' => $this->region,
66
            ]
67
        ]);
68
    }
69
70
    /**
71
     * Upload backup to Amazon S3 bucket.
72
     *
73
     * @param \phpbu\App\Backup\Target $target
74
     * @param \Aws\S3\S3Client         $s3
75
     */
76
    private function upload(Target $target, S3Client $s3)
77
    {
78
        if ($this->useMultiPartUpload($target)) {
79
            $this->uploadMultiPart($target, $s3);
80
        } else {
81
            $this->uploadStream($target, $s3);
82
        }
83
    }
84
85
    /**
86
     * Upload via stream wrapper.
87
     *
88
     * @param  \phpbu\App\Backup\Target $target
89
     * @param  \Aws\S3\S3Client         $s3
90
     * @throws \phpbu\App\Backup\Sync\Exception
91
     */
92
    private function uploadStream(Target $target, S3Client $s3)
93
    {
94
        $s3->registerStreamWrapper();
95
        $source = $this->getFileHandle($target->getPathname(), 'r');
96
        $stream = $this->getFileHandle('s3://' . $this->bucket . '/' . $this->getUploadPath($target), 'w');
97
        while(!feof($source)) {
98
            fwrite($stream, fread($source, 4096));
99
        }
100
        fclose($stream);
101
    }
102
103
    /**
104
     * Upload via multi part.
105
     *
106
     * @param \phpbu\App\Backup\Target $target
107
     * @param \Aws\S3\S3Client         $s3
108
     * @param \Aws\Exception\MultipartUploadException
109
     */
110
    private function uploadMultiPart(Target $target, S3Client $s3)
111
    {
112
        $uploader = new MultipartUploader($s3, $target->getPathname(), [
113
            'bucket' => $this->bucket,
114
            'key'    => $this->getUploadPath($target),
115
        ]);
116
        $uploader->upload();
117
    }
118
119
    /**
120
     * Open stream and validate it.
121
     *
122
     * @param  string $path
123
     * @param  string $mode
124
     * @return resource
125
     * @throws \phpbu\App\Backup\Sync\Exception
126
     */
127
    private function getFileHandle($path, $mode)
128
    {
129
        $handle = fopen($path, $mode);
130
        if (!is_resource($handle)) {
131
            throw new Exception('fopen failed: could not open stream ' . $path);
132
        }
133
        return $handle;
134
    }
135
136
    /**
137
     * Get the s3 upload path
138
     *
139
     * @param \phpbu\App\Backup\Target $target
140
     * @return string
141
     */
142
    public function getUploadPath(Target $target)
143
    {
144
        // remove leading slash
145
        return (substr($this->path, 0, 1) == '/' ? substr($this->path, 1) : $this->path)
146
               . (substr($this->path, -1, 1) == '/' ? '' : '/')
147
               . $target->getFilename();
148
    }
149
}
150