Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
VipsCommand
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 7
240
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setIO
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getOutput
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getErrorString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
20
 makeTemp
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 makePageArgument
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * PHP wrapper class for VIPS under MediaWiki
4 *
5 * Copyright © Bryan Tong Minh, 2011
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * http://www.gnu.org/copyleft/gpl.html
21 * @file
22 */
23
24namespace MediaWiki\Extension\VipsScaler;
25
26use LogicException;
27use MediaWiki\Shell\Shell;
28use TempFSFile;
29
30/**
31 * Wrapper class around the vips command, useful to chain multiple commands
32 * with intermediate .v files
33 */
34class VipsCommand {
35
36    /** Flag to indicate that the output file should be a temporary .v file */
37    public const TEMP_OUTPUT = true;
38
39    /** @var string */
40    protected $err;
41
42    /** @var string */
43    protected $output;
44
45    /** @var string */
46    protected $input;
47
48    /** @var bool */
49    protected $removeInput;
50
51    /** @var string */
52    protected $vips;
53
54    /** @var array */
55    protected $args;
56
57    /**
58     * Constructor
59     *
60     * @param string $vips Path to binary
61     * @param array $args Array or arguments
62     */
63    public function __construct( $vips, $args ) {
64        $this->vips = $vips;
65        $this->args = $args;
66    }
67
68    /**
69     * Set the input and output file of this command
70     *
71     * @param string|VipsCommand $input Input file name or an VipsCommand object to use the
72     * output of that command
73     * @param string $output Output file name or extension of the temporary file
74     * @param bool $tempOutput Output to a temporary file
75     */
76    public function setIO( $input, $output, $tempOutput = false ) {
77        if ( $input instanceof VipsCommand ) {
78            $this->input = $input->getOutput();
79            $this->removeInput = true;
80        } else {
81            $this->input = $input;
82            $this->removeInput = false;
83        }
84        if ( $tempOutput ) {
85            $tmpFile = self::makeTemp( $output );
86            $tmpFile->bind( $this );
87            $this->output = $tmpFile->getPath();
88        } else {
89            $this->output = $output;
90        }
91    }
92
93    /**
94     * Returns the output filename
95     * @return string
96     */
97    public function getOutput() {
98        return $this->output;
99    }
100
101    /**
102     * Return the output of the command
103     * @return string
104     */
105    public function getErrorString() {
106        return $this->err;
107    }
108
109    /**
110     * Call the vips binary with varargs and returns the return value.
111     *
112     * @return int Return value
113     */
114    public function execute() {
115        # Build the command line
116        $cmd = [
117            $this->vips,
118            array_shift( $this->args ),
119            $this->input,
120            $this->output
121        ];
122
123        $cmd = array_merge( $cmd, $this->args );
124
125        # Execute
126        $result = Shell::command( $cmd )
127            ->environment( [ 'IM_CONCURRENCY' => '1' ] )
128            ->limits( [ 'filesize' => 409600 ] )
129            ->includeStderr()
130            ->execute();
131
132        $this->err = $result->getStdout();
133        $retval = $result->getExitCode();
134
135        # Cleanup temp file
136        if ( $retval != 0 && file_exists( $this->output ) ) {
137            unlink( $this->output );
138        }
139        if ( $this->removeInput ) {
140            unlink( $this->input );
141        }
142
143        return $retval;
144    }
145
146    /**
147     * Generate a random, non-existent temporary file with a specified
148     * extension.
149     *
150     * @param string $extension Extension
151     * @return TempFSFile
152     */
153    public static function makeTemp( $extension ) {
154        return TempFSFile::factory( 'vips_', $extension );
155    }
156
157    /**
158     * Output syntax for specifying a non-default page.
159     *
160     * This is a little hacky, but im_shrink and shrink have
161     * a different format for specifying page number.
162     *
163     * @param int $page Page number (1-indexed)
164     * @return string String to append to filename
165     */
166    public function makePageArgument( $page ) {
167        $vipsCommand = $this->args[0];
168        $page = intval( $page ) - 1;
169
170        if ( $page === 0 ) {
171            // Default is first page anyways.
172            return '';
173        }
174        if ( substr( $vipsCommand, 0, 2 ) === 'im' ) {
175            // The im_* commands seem to all take the colon format
176            return ':' . $page;
177        }
178        if ( $vipsCommand === 'shrink' ) {
179            return "[page=$page]";
180        }
181        throw new LogicException( "Not sure how to specify page for command $vipsCommand" );
182    }
183
184}