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 $arValues[$name], $arOption['min'], $arOption['max']
157 } else if (gettype($arOption['type']) == 'array') {
158 $this->values[$name] = $this->validateArray(
159 $arValues[$name], $arOption['type']
161 } else if ($arOption['type'] == 'age') {
162 $this->values[$name] = $this->clamp(
163 static::validateAge($arValues[$name]),
164 $arOption['min'], null,
167 } else if ($arOption['type'] != 'skip') {
168 throw new \InvalidArgumentException(
169 'Unsupported option type: ' . $arOption['type']
172 unset($arValues[$name]);
175 if (count($arValues) > 0) {
176 throw new \InvalidArgumentException(
177 'Unsupported parameter: ' . implode(', ', array_keys($arValues))
181 $this->calcPageSize();
185 * Calculate the browser size and screenshot size from the given options
189 protected function calcPageSize()
191 if ($this->values['swidth'] === null) {
192 $this->values['swidth'] = $this->values['bwidth'];
194 if ($this->values['smode'] == 'page') {
198 if ($this->values['sheight'] !== null) {
199 $this->values['bheight'] = intval(
200 $this->values['bwidth'] / $this->values['swidth']
201 * $this->values['sheight']
203 } else if ($this->values['bheight'] !== null) {
204 $this->values['sheight'] = intval(
205 $this->values['swidth'] / $this->values['bwidth']
206 * $this->values['bheight']
209 //no height set. use 4:3
210 $this->values['sheight'] = $this->values['swidth'] / 4 * 3;
211 $this->values['bheight'] = $this->values['bwidth'] / 4 * 3;
216 * Makes sure a value is between $min and $max (inclusive)
218 * @param integer $value Value to check
219 * @param integer $min Minimum allowed value
220 * @param integer $max Maximum allowed value
221 * @param boolean $silent When silent, invalid values are corrected.
222 * An exception is thrown otherwise.
224 * @return integer Corrected value
225 * @throws \InvalidArgumentException When not silent and value outside range
227 protected function clamp($value, $min, $max, $silent = false)
229 if ($min !== null && $value < $min) {
233 throw new \InvalidArgumentException(
234 'Value must be at least ' . $min
238 if ($max !== null && $value > $max) {
242 throw new \InvalidArgumentException(
243 'Value may be up to ' . $min
251 * Validates an age is numeric. If it is not numeric, it's interpreted as
252 * a ISO 8601 duration specification.
254 * @param string $value Age in seconds
256 * @return integer Age in seconds
257 * @throws \InvalidArgumentException
258 * @link http://en.wikipedia.org/wiki/Iso8601#Durations
260 public static function validateAge($value)
262 if (!is_numeric($value)) {
263 //convert short notation to seconds
264 $value = 'P' . ltrim(strtoupper($value), 'P');
266 $interval = new \DateInterval($value);
267 } catch (\Exception $e) {
268 throw new \InvalidArgumentException(
269 'Invalid age: ' . $value
276 ) + $interval->h * 3600
284 * Check that a given value exists in an array
286 * @param string $value Value to check
287 * @param array $options Array of allowed values
289 * @return string Value
290 * @throws \InvalidArgumentException If the value does not exist in $options
292 protected function validateArray($value, $options)
294 if (array_search($value, $options) === false) {
295 throw new \InvalidArgumentException(
296 'Invalid value ' . $value . '.'
297 . ' Allowed: ' . implode(', ', $options)
304 * Validate that a value is numeric and between $min and $max (inclusive)
306 * @param string $value Value to check
307 * @param integer $min Minimum allowed value
308 * @param integer $max Maximum allowed value
310 * @return integer Value as integer
311 * @throws \InvalidArgumentException When outside range or not numeric
313 protected function validateInt($value, $min, $max)
315 if (!is_numeric($value)) {
316 throw new \InvalidArgumentException(
317 'Value must be a number'
320 $value = (int) $value;
321 return $this->clamp($value, $min, $max);
325 * Validate (and fix) an URL
327 * @param string $url URL
329 * @return string Fixed URL
330 * @throws \InvalidArgumentException
332 protected function validateUrl($url)
334 $parts = parse_url($url);
335 if ($parts === false) {
336 throw new \InvalidArgumentException('Invalid URL');
338 if (!isset($parts['scheme'])) {
339 $url = 'http://' . $url;
340 $parts = parse_url($url);
341 } else if ($parts['scheme'] != 'http' && $parts['scheme'] != 'https') {
342 throw new \InvalidArgumentException('Unsupported protocol');
344 if (!isset($parts['host'])) {
345 throw new \InvalidArgumentException('URL host missing');
351 * Set phancap configuration
353 * @param Config $config Phancap configuration
357 public function setConfig(Config $config)
359 $this->config = $config;
360 $this->options['smaxage']['default'] = $this->config->screenshotMaxAge;
361 $this->options['smaxage']['min'] = $this->config->screenshotMinAge;