1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19

20
/**
21
 * Stores an object on S3
22
 *
23
 * @package phing.tasks.ext
24
 * @author  Andrei Serdeliuc <andrei@serdeliuc.ro>
25
 */
26
class S3PutTask extends S3
27
{
28
    /**
29
     * File we're trying to upload
30
     *
31
     * (default value: null)
32
     *
33
     * @var string
34
     */
35
    protected $source = null;
36

37
    /**
38
     * Content we're trying to upload
39
     *
40
     * The user can specify either a file to upload or just a bit of content
41
     *
42
     * (default value: null)
43
     *
44
     * @var mixed
45
     */
46
    protected $content = null;
47

48
    /**
49
     * Collection of filesets
50
     * Used for uploading multiple files
51
     *
52
     * (default value: array())
53
     *
54
     * @var array
55
     */
56
    protected $filesets = [];
57

58
    /**
59
     * Whether to try to create buckets or not
60
     *
61
     * (default value: false)
62
     *
63
     * @var bool
64
     */
65
    protected $createBuckets = false;
66

67
    /**
68
     * File ACL
69
     * Use to set the permission to the uploaded files
70
     *
71
     * (default value: 'private')
72
     *
73
     * @var string
74
     */
75
    protected $acl = 'private';
76

77
    /**
78
     * File content type
79
     * Use this to set the content type of your static files
80
     * Set contentType to "auto" if you want to autodetect the content type based on the source file extension
81
     *
82
     * (default value: 'binary/octet-stream')
83
     *
84
     * @var string
85
     */
86
    protected $contentType = 'binary/octet-stream';
87

88
    /**
89
     * Object maxage (in seconds).
90
     *
91
     * @var int
92
     */
93
    protected $maxage = null;
94

95
    /**
96
     * Content is gzipped.
97
     *
98
     * @var boolean
99
     */
100
    protected $gzipped = false;
101

102
    /**
103
     * Extension content type mapper
104
     *
105
     * @var array
106
     */
107
    protected $extensionContentTypeMapper = [
108
        'js' => 'application/x-javascript',
109
        'css' => 'text/css',
110
        'html' => 'text/html',
111
        'gif' => 'image/gif',
112
        'png' => 'image/png',
113
        'jpg' => 'image/jpeg',
114
        'jpeg' => 'image/jpeg',
115
        'txt' => 'text/plain'
116
    ];
117

118
    /**
119
     * Whether filenames contain paths
120
     *
121
     * (default value: false)
122
     *
123
     * @var bool
124
     */
125
    protected $fileNameOnly = false;
126
    private $object;
127

128
    /**
129
     * @param string $source
130
     *
131
     * @throws BuildException if $source is not readable
132
     */
133 0
    public function setSource($source)
134
    {
135 0
        if (!is_readable($source)) {
136 0
            throw new BuildException('Source is not readable: ' . $source);
137
        }
138

139 0
        $this->source = $source;
140
    }
141

142
    /**
143
     * @return string
144
     *
145
     * @throws BuildException if source is null
146
     */
147 0
    public function getSource()
148
    {
149 0
        if ($this->content !== null) {
150 0
            $tempFile = tempnam($this->getProject()->getProperty('php.tmpdir'), 's3_put_');
151

152 0
            file_put_contents($tempFile, $this->content);
153 0
            $this->source = $tempFile;
154
        }
155

156 0
        if ($this->source === null) {
157 0
            throw new BuildException('Source is not set');
158
        }
159

160 0
        return $this->source;
161
    }
162

163
    /**
164
     * @param string $content
165
     *
166
     * @throws BuildException if $content is a empty string
167
     */
168 0
    public function setContent($content)
169
    {
170 0
        if (empty($content) || !is_string($content)) {
171 0
            throw new BuildException('Content must be a non-empty string');
172
        }
173

174 0
        $this->content = $content;
175
    }
176

177
    /**
178
     * @return string
179
     *
180
     * @throws BuildException if content is null
181
     */
182 0
    public function getContent()
183
    {
184 0
        if ($this->content === null) {
185 0
            throw new BuildException('Content is not set');
186
        }
187

188 0
        return $this->content;
189
    }
190

191
    /**
192
     * @param string $object
193
     *
194
     * @throws BuildException
195
     */
196 0
    public function setObject($object)
197
    {
198 0
        if (empty($object) || !is_string($object)) {
199 0
            throw new BuildException('Object must be a non-empty string');
200
        }
201

202 0
        $this->object = $object;
203
    }
204

205
    /**
206
     * @return string
207
     *
208
     * @throws \BuildException
209
     */
210 0
    public function getObject()
211
    {
212 0
        if ($this->object === null) {
213 0
            throw new BuildException('Object is not set');
214
        }
215

216 0
        return $this->object;
217
    }
218

219
    /**
220
     * @param $permission
221
     * @throws BuildException
222
     */
223 0
    public function setAcl($permission)
224
    {
225 0
        $valid_acl = ['private', 'public-read', 'public-read-write', 'authenticated-read'];
226 0
        if (empty($permission) || !is_string($permission) || !in_array($permission, $valid_acl)) {
227 0
            throw new BuildException('Object must be one of the following values: ' . implode('|', $valid_acl));
228
        }
229 0
        $this->acl = $permission;
230
    }
231

232
    /**
233
     * @return string
234
     */
235 0
    public function getAcl()
236
    {
237 0
        return $this->acl;
238
    }
239

240
    /**
241
     * @param string $contentType
242
     */
243 0
    public function setContentType($contentType)
244
    {
245 0
        $this->contentType = $contentType;
246
    }
247

248
    /**
249
     * @return string
250
     * @throws BuildException
251
     */
252 0
    public function getContentType()
253
    {
254 0
        if ($this->contentType === 'auto') {
255 0
            $ext = strtolower(substr(strrchr($this->getSource(), '.'), 1));
256 0
            return $this->extensionContentTypeMapper[$ext] ?? 'binary/octet-stream';
257
        }
258

259 0
        return $this->contentType;
260
    }
261

262 0
    public function setCreateBuckets(bool $createBuckets)
263
    {
264 0
        $this->createBuckets = $createBuckets;
265
    }
266

267
    /**
268
     * @return bool
269
     */
270 0
    public function getCreateBuckets()
271
    {
272 0
        return $this->createBuckets;
273
    }
274

275
    /**
276
     * Set seconds in max-age, null value exclude max-age setup.
277
     *
278
     * @param int $seconds
279
     */
280 0
    public function setMaxage($seconds)
281
    {
282 0
        $this->maxage = $seconds;
283
    }
284

285
    /**
286
     * Get seconds in max-age or null.
287
     *
288
     * @return int Number of seconds in maxage or null.
289
     */
290 0
    public function getMaxage()
291
    {
292 0
        return $this->maxage;
293
    }
294

295
    /**
296
     * Set if content is gzipped.
297
     *
298
     * @param boolean $gzipped
299
     */
300 0
    public function setGzip($gzipped)
301
    {
302 0
        $this->gzipped = $gzipped;
303
    }
304

305
    /**
306
     * Return if content is gzipped.
307
     *
308
     * @return boolean Indicate if content is gzipped.
309
     */
310 0
    public function getGzip()
311
    {
312 0
        return $this->gzipped;
313
    }
314

315
    /**
316
     * Generate HTTPHEader array sent to S3.
317
     *
318
     * @return array HttpHeader to set in S3 Object.
319
     */
320 0
    protected function getHttpHeaders()
321
    {
322 0
        $headers = [];
323 0
        if (null !== $this->maxage) {
324 0
            $headers['Cache-Control'] = 'max-age=' . $this->maxage;
325
        }
326 0
        if ($this->gzipped) {
327 0
            $headers['Content-Encoding'] = 'gzip';
328
        }
329

330 0
        return $headers;
331
    }
332

333 0
    public function setFileNameOnly(bool $fileNameOnly)
334
    {
335 0
        $this->fileNameOnly = $fileNameOnly;
336
    }
337

338
    /**
339
     * creator for _filesets
340
     *
341
     * @return FileSet
342
     */
343 0
    public function createFileset()
344
    {
345 0
        $num = array_push($this->filesets, new FileSet());
346

347 0
        return $this->filesets[$num - 1];
348
    }
349

350
    /**
351
     * getter for _filesets
352
     *
353
     * @return array
354
     */
355 0
    public function getFilesets()
356
    {
357 0
        return $this->filesets;
358
    }
359

360
    /**
361
     * Determines what we're going to store in the object
362
     *
363
     * If _content has been set, this will get stored,
364
     * otherwise, we read from _source
365
     *
366
     * @return string
367
     *
368
     * @throws BuildException
369
     */
370 0
    public function getObjectData()
371
    {
372 0
        $source = $this->getSource();
373

374 0
        if (!is_file($source)) {
375 0
            throw new BuildException('Currently only files can be used as source');
376
        }
377

378 0
        return $source;
379
    }
380

381
    /**
382
     * Store the object on S3
383
     *
384
     * @throws BuildException
385
     * @return void
386
     */
387 0
    public function execute()
388
    {
389 0
        if (!$this->isBucketAvailable()) {
390 0
            if (!$this->getCreateBuckets()) {
391 0
                throw new BuildException('Bucket doesn\'t exist and createBuckets not specified');
392
            }
393

394 0
            if (!$this->createBucket()) {
395 0
                throw new BuildException('Bucket cannot be created');
396
            }
397
        }
398

399
        // Filesets take precedence
400 0
        if (!empty($this->filesets)) {
401 0
            $objects = [];
402

403 0
            foreach ($this->filesets as $fs) {
404 0
                if (!($fs instanceof FileSet)) {
405 0
                    continue;
406
                }
407

408 0
                $ds = $fs->getDirectoryScanner($this->getProject());
409 0
                $objects = array_merge($objects, $ds->getIncludedFiles());
410
            }
411

412 0
            $fromDir = $fs->getDir($this->getProject())->getAbsolutePath();
413

414 0
            if ($this->fileNameOnly) {
415 0
                foreach ($objects as $object) {
416 0
                    $this->source = $object;
417 0
                    $this->saveObject(basename($object), $fromDir . DIRECTORY_SEPARATOR . $object);
418
                }
419
            } else {
420 0
                foreach ($objects as $object) {
421 0
                    $this->source = $object;
422 0
                    $this->saveObject(
423 0
                        str_replace('\\', '/', $object),
424 0
                        $fromDir . DIRECTORY_SEPARATOR . $object
425
                    );
426
                }
427
            }
428

429 0
            return;
430
        }
431

432 0
        $this->saveObject($this->getObject(), $this->getSource());
433
    }
434

435
    /**
436
     * @param string $key
437
     * @param string $sourceFile
438
     * @throws \BuildException
439
     */
440 0
    protected function saveObject($key, $sourceFile)
441
    {
442 0
        $client = $this->getClientInstance();
443 0
        $client->putObject(
444
            [
445 0
                'Bucket' => $this->getBucket(),
446 0
                'Key' => $key,
447 0
                'SourceFile' => $sourceFile
448
            ]
449
        );
450
    }
451
}

Read our documentation on viewing source code .

Loading