Completed
Push — master ( 17c5b4...da708e )
by Bjørn
03:12
created

ServeFile::processOptions()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 20
nc 4
nop 1
dl 0
loc 30
ccs 21
cts 21
cp 1
crap 3
rs 9.6
c 0
b 0
f 0
1
<?php
2
namespace WebPConvert\Serve;
3
4
//use WebPConvert\Serve\Report;
5
use WebPConvert\Helpers\InputValidator;
6
use WebPConvert\Options\ArrayOption;
7
use WebPConvert\Options\BooleanOption;
8
use WebPConvert\Options\Options;
9
use WebPConvert\Options\StringOption;
10
use WebPConvert\Serve\Header;
11
use WebPConvert\Serve\Exceptions\ServeFailedException;
12
13
/**
14
 * Serve a file (send to standard output)
15
 *
16
 * @package    WebPConvert
17
 * @author     Bjørn Rosell <[email protected]>
18
 * @since      Class available since Release 2.0.0
19
 */
20
class ServeFile
21
{
22
23
    /**
24
     * Process options.
25
     *
26
     * @throws \WebPConvert\Options\Exceptions\InvalidOptionTypeException   If the type of an option is invalid
27
     * @throws \WebPConvert\Options\Exceptions\InvalidOptionValueException  If the value of an option is invalid
28
     * @param array $options
29
     */
30 5
    private static function processOptions($options)
31
    {
32 5
        $options2 = new Options();
33 5
        $options2->addOptions(
34 5
            new ArrayOption('headers', []),
35 5
            new StringOption('cache-control-header', 'public, max-age=31536000')
36
        );
37 5
        foreach ($options as $optionId => $optionValue) {
38 4
            $options2->setOrCreateOption($optionId, $optionValue);
39
        }
40 5
        $options2->check();
41 5
        $options = $options2->getOptions();
42
43
        // headers option
44
        // --------------
45
46 5
        $headerOptions = new Options();
47 5
        $headerOptions->addOptions(
48 5
            new BooleanOption('cache-control', false),
49 5
            new BooleanOption('content-length', true),
50 5
            new BooleanOption('content-type', true),
51 5
            new BooleanOption('expires', false),
52 5
            new BooleanOption('last-modified', true),
53 5
            new BooleanOption('vary-accept', false)
54
        );
55 5
        foreach ($options['headers'] as $optionId => $optionValue) {
56 4
            $headerOptions->setOrCreateOption($optionId, $optionValue);
57
        }
58 5
        $options['headers'] = $headerOptions->getOptions();
59 5
        return $options;
60
    }
61
62
    /**
63
     * Serve existing file.
64
     *
65
     * @param  string  $filename     File to serve (absolute path)
66
     * @param  string  $contentType  Content-type (used to set header).
67
     *                                    Only used when the "set-content-type-header" option is set.
68
     *                                    Set to ie "image/jpeg" for serving jpeg file.
69
     * @param  array   $options      Array of named options (optional).
70
     *       Supported options:
71
     *       'add-vary-accept-header'  => (boolean)   Whether to add *Vary: Accept* header or not. Default: true.
72
     *       'set-content-type-header' => (boolean)   Whether to set *Content-Type* header or not. Default: true.
73
     *       'set-last-modified-header' => (boolean)  Whether to set *Last-Modified* header or not. Default: true.
74
     *       'set-cache-control-header' => (boolean)  Whether to set *Cache-Control* header or not. Default: true.
75
     *       'cache-control-header' => string         Cache control header. Default: "public, max-age=86400"
76
     *
77
     * @throws ServeFailedException  if serving failed
78
     * @return  void
79
     */
80 5
    public static function serve($filename, $contentType, $options = [])
81
    {
82
        // Check mimetype - this also checks that path is secure and file exists
83 5
        InputValidator::checkMimeType($filename, [
84 5
            'image/jpeg',
85
            'image/png',
86
            'image/webp',
87
            'image/gif'
88
        ]);
89
90
        /*
91
        if (!file_exists($filename)) {
92
            Header::addHeader('X-WebP-Convert-Error: Could not read file');
93
            throw new ServeFailedException('Could not read file');
94
        }*/
95
96 5
        $options = self::processOptions($options);
97
98 5
        if ($options['headers']['last-modified']) {
99 4
            Header::setHeader("Last-Modified: " . gmdate("D, d M Y H:i:s", @filemtime($filename)) ." GMT");
100
        }
101
102 5
        if ($options['headers']['content-type']) {
103 4
            Header::setHeader('Content-Type: ' . $contentType);
104
        }
105
106 5
        if ($options['headers']['vary-accept']) {
107 1
            Header::addHeader('Vary: Accept');
108
        }
109
110 5
        if (!empty($options['cache-control-header'])) {
111 5
            if ($options['headers']['cache-control']) {
112 2
                Header::setHeader('Cache-Control: ' . $options['cache-control-header']);
113
            }
114 5
            if ($options['headers']['expires']) {
115
                // Add exprires header too (#126)
116
                // Check string for something like this: max-age:86400
117 1
                if (preg_match('#max-age\\s*=\\s*(\\d*)#', $options['cache-control-header'], $matches)) {
118 1
                    $seconds = $matches[1];
119 1
                    Header::setHeader('Expires: '. gmdate('D, d M Y H:i:s \G\M\T', time() + intval($seconds)));
120
                }
121
            }
122
        }
123
124 5
        if ($options['headers']['content-length']) {
125 4
            Header::setHeader('Content-Length: ' . filesize($filename));
126
        }
127
128 5
        if (@readfile($filename) === false) {
129
            Header::addHeader('X-WebP-Convert-Error: Could not read file');
130
            throw new ServeFailedException('Could not read file');
131
        }
132 5
    }
133
}
134