Completed
Push — master ( 1bdda1...381df8 )
by Bjørn
03:02
created

ServeConvertedWebP::serveOriginal()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 2
dl 0
loc 9
ccs 5
cts 7
cp 0.7143
crap 3.2098
rs 10
c 0
b 0
f 0
1
<?php
2
namespace WebPConvert\Serve;
3
4
use ImageMimeTypeGuesser\ImageMimeTypeGuesser;
5
6
use WebPConvert\Convert\Exceptions\ConversionFailedException;
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
        $contentType = ImageMimeTypeGuesser::lenientGuess($source);
75 3
        if (is_null($contentType)) {
76
            throw new ServeFailedException('Rejecting to serve original (mime type cannot be determined)');
77 3
        } elseif ($contentType === false) {
78
            throw new ServeFailedException('Rejecting to serve original (it is not an image)');
79
        } else {
80 3
            ServeFile::serve($source, $contentType, $serveImageOptions);
81
        }
82 3
    }
83
84
    /**
85
     * Serve destination file.
86
     *
87
     * @param   string  $destination                   path to destination file
88
     * @param   array   $serveImageOptions (optional)  options for serving (such as which headers to add)
89
     *       Supported options:
90
     *       - All options supported by ServeFile::serve()
91
     * @return  void
92
     */
93 6
    public static function serveDestination($destination, $serveImageOptions = [])
94
    {
95 6
        ServeFile::serve($destination, 'image/webp', $serveImageOptions);
96 6
    }
97
98
99 2
    public static function warningHandler()
100
    {
101
        // do nothing! - as we do not return anything, the warning is suppressed
102 2
    }
103
104
    /**
105
     * Serve converted webp.
106
     *
107
     * Serve a converted webp. If a file already exists at the destination, that is served (unless it is
108
     * older than the source - in that case a fresh conversion will be made, or the file at the destination
109
     * is larger than the source - in that case the source is served). Some options may alter this logic.
110
     * In case no file exists at the destination, a fresh conversion is made and served.
111
     *
112
     * @param   string  $source              path to source file
113
     * @param   string  $destination         path to destination
114
     * @param   array   $options (optional)  options for serving/converting
115
     *       Supported options:
116
     *       'show-report'     => (boolean)   If true, the decision will always be 'report'
117
     *       'serve-original'  => (boolean)   If true, the decision will be 'source' (unless above option is set)
118
     *       'reconvert     '  => (boolean)   If true, the decision will be 'fresh-conversion' (unless one of the
119
     *                                        above options is set)
120
     *       - All options supported by WebPConvert::convert()
121
     *       - All options supported by ServeFile::serve()
122
     * @param  \WebPConvert\Loggers\BaseLogger $logger (optional)
123
     *
124
     * @throws  \WebPConvert\Exceptions\WebPConvertException  If something went wrong.
125
     * @return  void
126
     */
127 7
    public static function serve($source, $destination, $options = [], $logger = null)
128
    {
129
130 7
        if (empty($source)) {
131
            throw new ServeFailedException('Source argument missing');
132
        }
133 7
        if (empty($destination)) {
134
            throw new ServeFailedException('Destination argument missing');
135
        }
136 7
        if (@!file_exists($source)) {
137
            throw new ServeFailedException('Source file was not found');
138
        }
139
140 7
        $options = self::processOptions($options);
141
142 7
        if ($options['suppress-warnings']) {
143 7
            set_error_handler(
144 7
                array('\\WebPConvert\\Serve\\ServeConvertedWebP', "warningHandler"),
145 7
                E_WARNING | E_USER_WARNING | E_NOTICE | E_USER_NOTICE
146
            );
147
        }
148
149
150
        //$options = array_merge(self::$defaultOptions, $options);
151
152
        // Step 1: Is there a file at the destination? If not, trigger conversion
153
        // However 1: if "show-report" option is set, serve the report instead
154
        // However 2: "reconvert" option should also trigger conversion
155 7
        if ($options['show-report']) {
156 1
            Header::addLogHeader('Showing report', $logger);
157 1
            Report::convertAndReport($source, $destination, $options);
158 1
            return;
159
        }
160
161 6
        if (!@file_exists($destination)) {
162 2
            Header::addLogHeader('Converting (there were no file at destination)', $logger);
163 2
            WebPConvert::convert($source, $destination, $options['convert'], $logger);
164 4
        } elseif ($options['reconvert']) {
165
            Header::addLogHeader('Converting (told to reconvert)', $logger);
166
            WebPConvert::convert($source, $destination, $options['convert'], $logger);
167
        } else {
168
            // Step 2: Is the destination older than the source?
169
            //         If yes, trigger conversion (deleting destination is implicit)
170 4
            $timestampSource = @filemtime($source);
171 4
            $timestampDestination = @filemtime($destination);
172 4
            if (($timestampSource !== false) &&
173 4
                ($timestampDestination !== false) &&
174 4
                ($timestampSource > $timestampDestination)) {
175 1
                    Header::addLogHeader('Converting (destination was older than the source)', $logger);
176 1
                    WebPConvert::convert($source, $destination, $options['convert'], $logger);
177
            }
178
        }
179
180
        // Step 3: Serve the smallest file (destination or source)
181
        // However, first check if 'serve-original' is set
182 6
        if ($options['serve-original']) {
183 1
            Header::addLogHeader('Serving original (told to)', $logger);
184 1
            self::serveOriginal($source, $options['serve-image']);
185
        }
186
187 6
        $filesizeDestination = @filesize($destination);
188 6
        $filesizeSource = @filesize($source);
189 6
        if (($filesizeSource !== false) &&
190 6
            ($filesizeDestination !== false) &&
191 6
            ($filesizeDestination > $filesizeSource)) {
192 1
                Header::addLogHeader('Serving original (it is smaller)', $logger);
193 1
                self::serveOriginal($source, $options['serve-image']);
194
        }
195
196 6
        Header::addLogHeader('Serving converted file', $logger);
197 6
        self::serveDestination($destination, $options['serve-image']);
198 6
    }
199
}
200