Passed
Push — master ( 5cb744...41c0c2 )
by Bjørn
01:36 queued 11s
created

ServeConvertedWebP   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 160
Duplicated Lines 0 %

Test Coverage

Coverage 96.88%

Importance

Changes 9
Bugs 1 Features 1
Metric Value
eloc 59
c 9
b 1
f 1
dl 0
loc 160
ccs 62
cts 64
cp 0.9688
rs 10
wmc 19

5 Methods

Rating   Name   Duplication   Size   Complexity  
A serveOriginal() 0 10 3
A serveDestination() 0 4 1
A processOptions() 0 16 2
A warningHandler() 0 2 1
C serve() 0 62 12
1
<?php
2
namespace WebPConvert\Serve;
3
4
use WebPConvert\Convert\Exceptions\ConversionFailedException;
5
use WebPConvert\Helpers\InputValidator;
6
use WebPConvert\Helpers\MimeType;
7
use WebPConvert\Serve\Exceptions\ServeFailedException;
8
use WebPConvert\Serve\Header;
9
use WebPConvert\Serve\Report;
10
use WebPConvert\Serve\ServeFile;
11
use WebPConvert\Options\ArrayOption;
12
use WebPConvert\Options\BooleanOption;
13
use WebPConvert\Options\Options;
14
use WebPConvert\Options\SensitiveArrayOption;
15
use WebPConvert\Options\Exceptions\InvalidOptionTypeException;
16
use WebPConvert\Options\Exceptions\InvalidOptionValueException;
17
use WebPConvert\WebPConvert;
18
19
/**
20
 * Serve a converted webp image.
21
 *
22
 * The webp that is served might end up being one of these:
23
 * - a fresh convertion
24
 * - the destionation
25
 * - the original
26
 *
27
 * Exactly which is a decision based upon options, file sizes and file modification dates
28
 * (see the serve method of this class for details)
29
 *
30
 * @package    WebPConvert
31
 * @author     Bjørn Rosell <[email protected]>
32
 * @since      Class available since Release 2.0.0
33
 */
34
class ServeConvertedWebP
35
{
36
37
    /**
38
     * Process options.
39
     *
40
     * @throws \WebPConvert\Options\Exceptions\InvalidOptionTypeException   If the type of an option is invalid
41
     * @throws \WebPConvert\Options\Exceptions\InvalidOptionValueException  If the value of an option is invalid
42
     * @param array $options
43
     */
44 7
    private static function processOptions($options)
45
    {
46 7
        $options2 = new Options();
47 7
        $options2->addOptions(
48 7
            new BooleanOption('reconvert', false),
49 7
            new BooleanOption('serve-original', false),
50 7
            new BooleanOption('show-report', false),
51 7
            new BooleanOption('suppress-warnings', true),
52 7
            new ArrayOption('serve-image', []),
53 7
            new SensitiveArrayOption('convert', [])
54
        );
55 7
        foreach ($options as $optionId => $optionValue) {
56 7
            $options2->setOrCreateOption($optionId, $optionValue);
57
        }
58 7
        $options2->check();
59 7
        return $options2->getOptions();
60
    }
61
62
    /**
63
     * Serve original file (source).
64
     *
65
     * @param   string  $source                        path to source file
66
     * @param   array   $serveImageOptions (optional)  options for serving an image
67
     *                  Supported options:
68
     *                  - All options supported by ServeFile::serve()
69
     * @throws  ServeFailedException  if source is not an image or mime type cannot be determined
70
     * @return  void
71
     */
72 3
    public static function serveOriginal($source, $serveImageOptions = [])
73
    {
74 3
        InputValidator::checkSource($source);
75 3
        $contentType = MimeType::getMimeTypeDetectionResult($source);
76 3
        if (is_null($contentType)) {
77
            throw new ServeFailedException('Rejecting to serve original (mime type cannot be determined)');
78 3
        } elseif ($contentType === false) {
79
            throw new ServeFailedException('Rejecting to serve original (it is not an image)');
80
        } else {
81 3
            ServeFile::serve($source, $contentType, $serveImageOptions);
82
        }
83 3
    }
84
85
    /**
86
     * Serve destination file.
87
     *
88
     * TODO: SHould this really be public?
89
     *
90
     * @param   string  $destination                   path to destination file
91
     * @param   array   $serveImageOptions (optional)  options for serving (such as which headers to add)
92
     *       Supported options:
93
     *       - All options supported by ServeFile::serve()
94
     * @return  void
95
     */
96 6
    public static function serveDestination($destination, $serveImageOptions = [])
97
    {
98 6
        InputValidator::checkDestination($destination);
99 6
        ServeFile::serve($destination, 'image/webp', $serveImageOptions);
100 6
    }
101
102
103 8
    public static function warningHandler()
104
    {
105
        // do nothing! - as we do not return anything, the warning is suppressed
106 8
    }
107
108
    /**
109
     * Serve converted webp.
110
     *
111
     * Serve a converted webp. If a file already exists at the destination, that is served (unless it is
112
     * older than the source - in that case a fresh conversion will be made, or the file at the destination
113
     * is larger than the source - in that case the source is served). Some options may alter this logic.
114
     * In case no file exists at the destination, a fresh conversion is made and served.
115
     *
116
     * @param   string  $source              path to source file
117
     * @param   string  $destination         path to destination
118
     * @param   array   $options (optional)  options for serving/converting
119
     *       Supported options:
120
     *       'show-report'     => (boolean)   If true, the decision will always be 'report'
121
     *       'serve-original'  => (boolean)   If true, the decision will be 'source' (unless above option is set)
122
     *       'reconvert     '  => (boolean)   If true, the decision will be 'fresh-conversion' (unless one of the
123
     *                                        above options is set)
124
     *       - All options supported by WebPConvert::convert()
125
     *       - All options supported by ServeFile::serve()
126
     * @param  \WebPConvert\Loggers\BaseLogger $serveLogger (optional)
127
     * @param  \WebPConvert\Loggers\BaseLogger $convertLogger (optional)
128
     *
129
     * @throws  \WebPConvert\Exceptions\WebPConvertException  If something went wrong.
130
     * @return  void
131
     */
132 7
    public static function serve($source, $destination, $options = [], $serveLogger = null, $convertLogger = null)
133
    {
134 7
        InputValidator::checkSourceAndDestination($source, $destination);
135
136 7
        $options = self::processOptions($options);
137
138 7
        if ($options['suppress-warnings']) {
139 7
            set_error_handler(
140 7
                array('\\WebPConvert\\Serve\\ServeConvertedWebP', "warningHandler"),
141 7
                E_WARNING | E_USER_WARNING | E_NOTICE | E_USER_NOTICE
142
            );
143
        }
144
145
146
        //$options = array_merge(self::$defaultOptions, $options);
147
148
        // Step 1: Is there a file at the destination? If not, trigger conversion
149
        // However 1: if "show-report" option is set, serve the report instead
150
        // However 2: "reconvert" option should also trigger conversion
151 7
        if ($options['show-report']) {
152 1
            Header::addLogHeader('Showing report', $serveLogger);
153 1
            Report::convertAndReport($source, $destination, $options);
154 1
            return;
155
        }
156
157 6
        if (!@file_exists($destination)) {
158 1
            Header::addLogHeader('Converting (there were no file at destination)', $serveLogger);
159 1
            WebPConvert::convert($source, $destination, $options['convert'], $convertLogger);
160 5
        } elseif ($options['reconvert']) {
161 1
            Header::addLogHeader('Converting (told to reconvert)', $serveLogger);
162 1
            WebPConvert::convert($source, $destination, $options['convert'], $convertLogger);
163
        } else {
164
            // Step 2: Is the destination older than the source?
165
            //         If yes, trigger conversion (deleting destination is implicit)
166 4
            $timestampSource = @filemtime($source);
167 4
            $timestampDestination = @filemtime($destination);
168 4
            if (($timestampSource !== false) &&
169 4
                ($timestampDestination !== false) &&
170 4
                ($timestampSource > $timestampDestination)) {
171 1
                    Header::addLogHeader('Converting (destination was older than the source)', $serveLogger);
172 1
                    WebPConvert::convert($source, $destination, $options['convert'], $convertLogger);
173
            }
174
        }
175
176
        // Step 3: Serve the smallest file (destination or source)
177
        // However, first check if 'serve-original' is set
178 6
        if ($options['serve-original']) {
179 1
            Header::addLogHeader('Serving original (told to)', $serveLogger);
180 1
            self::serveOriginal($source, $options['serve-image']);
181
        }
182
183 6
        $filesizeDestination = @filesize($destination);
184 6
        $filesizeSource = @filesize($source);
185 6
        if (($filesizeSource !== false) &&
186 6
            ($filesizeDestination !== false) &&
187 6
            ($filesizeDestination > $filesizeSource)) {
188 1
                Header::addLogHeader('Serving original (it is smaller)', $serveLogger);
189 1
                self::serveOriginal($source, $options['serve-image']);
190
        }
191
192 6
        Header::addLogHeader('Serving converted file', $serveLogger);
193 6
        self::serveDestination($destination, $options['serve-image']);
194 6
    }
195
}
196