9 * @author Christian Weiske <cweiske@cweiske.de>
10 * @copyright 2014 Christian Weiske
11 * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
12 * @link http://cweiske.de/phancap.htm
17 * Options a user can give to the API
21 * @author Christian Weiske <cweiske@cweiske.de>
22 * @copyright 2014 Christian Weiske
23 * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
24 * @version Release: @package_version@
25 * @link http://cweiske.de/phancap.htm
30 * Available options and their configuration
34 public $options = array(
39 'title' => 'Website URL',
45 'title' => 'Browser width',
52 'title' => 'Browser height',
62 'title' => 'Screenshot width',
69 'title' => 'Screenshot height',
76 'title' => 'Screenshot format',
78 'type' => array('png', 'jpg', 'pdf'),
81 'title' => 'Screenshot mode',
82 'default' => 'screen',
83 'type' => array('screen', 'page'),
86 'title' => 'Maximum age for a screenshot',
94 'atimestamp' => array(
95 'title' => 'Timestamp the request has been generated',
100 'title' => 'Access token (user name)',
104 'asignature' => array(
105 'title' => 'Access signature',
112 * Actual values we use after parsing the GET parameters
116 public $values = array();
125 * Parses an array of options, validates them and writes them into
128 * @param array $arValues Array of options, e.g. $_GET
131 * @throws \InvalidArgumentException When required parameters are missing
132 * or parameter values are invalid.
134 public function parse($arValues)
136 foreach ($this->options as $name => $arOption) {
137 $this->values[$name] = $arOption['default'];
138 if (!isset($arValues[$name])) {
139 if (isset($arOption['required'])) {
140 throw new \InvalidArgumentException(
141 $name . ' parameter missing'
147 if ($arValues[$name] === ''
148 && !isset($arOption['required'])
150 //allow empty value; default value will be used
151 } else if ($arOption['type'] == 'url') {
152 $this->values[$name] = $this->validateUrl($arValues[$name]);
153 } else if ($arOption['type'] == 'int') {
154 $this->values[$name] = $this->validateInt(
155 $name, $arValues[$name],
156 $arOption['min'], $arOption['max']
158 } else if (gettype($arOption['type']) == 'array') {
159 $this->values[$name] = $this->validateArray(
160 $name, $arValues[$name], $arOption['type']
162 } else if ($arOption['type'] == 'age') {
163 $this->values[$name] = $this->clamp(
164 static::validateAge($arValues[$name]),
165 $arOption['min'], null,
168 } else if ($arOption['type'] != 'skip') {
169 throw new \InvalidArgumentException(
170 'Unsupported option type: ' . $arOption['type']
173 unset($arValues[$name]);
176 if (count($arValues) > 0) {
177 throw new \InvalidArgumentException(
178 'Unsupported parameter: ' . implode(', ', array_keys($arValues))
182 $this->calcPageSize();
186 * Calculate the browser size and screenshot size from the given options
190 protected function calcPageSize()
192 if ($this->values['swidth'] === null) {
193 $this->values['swidth'] = $this->values['bwidth'];
195 if ($this->values['smode'] == 'page') {
199 if ($this->values['sheight'] !== null) {
200 $this->values['bheight'] = intval(
201 $this->values['bwidth'] / $this->values['swidth']
202 * $this->values['sheight']
204 } else if ($this->values['bheight'] !== null) {
205 $this->values['sheight'] = intval(
206 $this->values['swidth'] / $this->values['bwidth']
207 * $this->values['bheight']
210 //no height set. use 4:3
211 $this->values['sheight'] = $this->values['swidth'] / 4 * 3;
212 $this->values['bheight'] = $this->values['bwidth'] / 4 * 3;
217 * Makes sure a value is between $min and $max (inclusive)
219 * @param integer $value Value to check
220 * @param integer $min Minimum allowed value
221 * @param integer $max Maximum allowed value
222 * @param boolean $silent When silent, invalid values are corrected.
223 * An exception is thrown otherwise.
225 * @return integer Corrected value
226 * @throws \InvalidArgumentException When not silent and value outside range
228 protected function clamp($value, $min, $max, $silent = false)
230 if ($min !== null && $value < $min) {
234 throw new \InvalidArgumentException(
235 'Value must be at least ' . $min
239 if ($max !== null && $value > $max) {
243 throw new \InvalidArgumentException(
244 'Value may be up to ' . $min
252 * Validates an age is numeric. If it is not numeric, it's interpreted as
253 * a ISO 8601 duration specification.
255 * @param string $value Age in seconds
257 * @return integer Age in seconds
258 * @throws \InvalidArgumentException
259 * @link http://en.wikipedia.org/wiki/Iso8601#Durations
261 public static function validateAge($value)
263 if (!is_numeric($value)) {
264 //convert short notation to seconds
265 $value = 'P' . ltrim(strtoupper($value), 'P');
267 $interval = new \DateInterval($value);
268 } catch (\Exception $e) {
269 throw new \InvalidArgumentException(
270 'Invalid age: ' . $value
277 ) + $interval->h * 3600
285 * Check that a given value exists in an array
287 * @param string $name Variable name
288 * @param string $value Value to check
289 * @param array $options Array of allowed values
291 * @return string Value
292 * @throws \InvalidArgumentException If the value does not exist in $options
294 protected function validateArray($name, $value, $options)
296 if (array_search($value, $options) === false) {
297 throw new \InvalidArgumentException(
298 'Invalid value ' . $value . ' for ' . $name . '.'
299 . ' Allowed: ' . implode(', ', $options)
306 * Validate that a value is numeric and between $min and $max (inclusive)
308 * @param string $name Variable name
309 * @param string $value Value to check
310 * @param integer $min Minimum allowed value
311 * @param integer $max Maximum allowed value
313 * @return integer Value as integer
314 * @throws \InvalidArgumentException When outside range or not numeric
316 protected function validateInt($name, $value, $min, $max)
318 if (!is_numeric($value)) {
319 throw new \InvalidArgumentException(
320 $name . ' value must be a number'
323 $value = (int) $value;
324 return $this->clamp($value, $min, $max);
328 * Validate (and fix) an URL
330 * @param string $url URL
332 * @return string Fixed URL
333 * @throws \InvalidArgumentException
335 protected function validateUrl($url)
338 throw new \InvalidArgumentException('URL is empty');
340 $parts = parse_url($url);
341 if ($parts === false) {
342 throw new \InvalidArgumentException('Invalid URL');
344 if (!isset($parts['scheme'])) {
345 $url = 'http://' . $url;
346 $parts = parse_url($url);
347 } else if ($parts['scheme'] != 'http' && $parts['scheme'] != 'https') {
348 throw new \InvalidArgumentException('Unsupported protocol');
350 if (!isset($parts['host'])) {
351 throw new \InvalidArgumentException('URL host missing');
357 * Set phancap configuration
359 * @param Config $config Phancap configuration
363 public function setConfig(Config $config)
365 $this->config = $config;
366 $this->options['smaxage']['default'] = $this->config->screenshotMaxAge;
367 $this->options['smaxage']['min'] = $this->config->screenshotMinAge;