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 ($arOption['type'] == 'url') {
148 $this->values[$name] = $this->validateUrl($arValues[$name]);
149 } else if ($arOption['type'] == 'int') {
150 $this->values[$name] = $this->validateInt(
151 $arValues[$name], $arOption['min'], $arOption['max']
153 } else if (gettype($arOption['type']) == 'array') {
154 $this->values[$name] = $this->validateArray(
155 $arValues[$name], $arOption['type']
157 } else if ($arOption['type'] == 'age') {
158 $this->values[$name] = $this->clamp(
159 static::validateAge($arValues[$name]),
160 $arOption['min'], null,
163 } else if ($arOption['type'] != 'skip') {
164 throw new \InvalidArgumentException(
165 'Unsupported option type: ' . $arOption['type']
168 unset($arValues[$name]);
171 if (count($arValues) > 0) {
172 throw new \InvalidArgumentException(
173 'Unsupported parameter: ' . implode(', ', array_keys($arValues))
177 $this->calcPageSize();
181 * Calculate the browser size and screenshot size from the given options
185 protected function calcPageSize()
187 if ($this->values['swidth'] === null) {
188 $this->values['swidth'] = $this->values['bwidth'];
190 if ($this->values['smode'] == 'page') {
194 if ($this->values['sheight'] !== null) {
195 $this->values['bheight'] = intval(
196 $this->values['bwidth'] / $this->values['swidth']
197 * $this->values['sheight']
199 } else if ($this->values['bheight'] !== null) {
200 $this->values['sheight'] = intval(
201 $this->values['swidth'] / $this->values['bwidth']
202 * $this->values['bheight']
205 //no height set. use 4:3
206 $this->values['sheight'] = $this->values['swidth'] / 4 * 3;
207 $this->values['bheight'] = $this->values['bwidth'] / 4 * 3;
212 * Makes sure a value is between $min and $max (inclusive)
214 * @param integer $value Value to check
215 * @param integer $min Minimum allowed value
216 * @param integer $max Maximum allowed value
217 * @param boolean $silent When silent, invalid values are corrected.
218 * An exception is thrown otherwise.
220 * @return integer Corrected value
221 * @throws \InvalidArgumentException When not silent and value outside range
223 protected function clamp($value, $min, $max, $silent = false)
225 if ($min !== null && $value < $min) {
229 throw new \InvalidArgumentException(
230 'Value must be at least ' . $min
234 if ($max !== null && $value > $max) {
238 throw new \InvalidArgumentException(
239 'Value may be up to ' . $min
247 * Validates an age is numeric. If it is not numeric, it's interpreted as
248 * a ISO 8601 duration specification.
250 * @param string $value Age in seconds
252 * @return integer Age in seconds
253 * @throws \InvalidArgumentException
254 * @link http://en.wikipedia.org/wiki/Iso8601#Durations
256 public static function validateAge($value)
258 if (!is_numeric($value)) {
259 //convert short notation to seconds
260 $value = 'P' . ltrim(strtoupper($value), 'P');
262 $interval = new \DateInterval($value);
263 } catch (\Exception $e) {
264 throw new \InvalidArgumentException(
265 'Invalid age: ' . $value
272 ) + $interval->h * 3600
280 * Check that a given value exists in an array
282 * @param string $value Value to check
283 * @param array $options Array of allowed values
285 * @return string Value
286 * @throws \InvalidArgumentException If the value does not exist in $options
288 protected function validateArray($value, $options)
290 if (array_search($value, $options) === false) {
291 throw new \InvalidArgumentException(
292 'Invalid value ' . $value . '.'
293 . ' Allowed: ' . implode(', ', $options)
300 * Validate that a value is numeric and between $min and $max (inclusive)
302 * @param string $value Value to check
303 * @param integer $min Minimum allowed value
304 * @param integer $max Maximum allowed value
306 * @return integer Value as integer
307 * @throws \InvalidArgumentException When outside range or not numeric
309 protected function validateInt($value, $min, $max)
311 if (!is_numeric($value)) {
312 throw new \InvalidArgumentException(
313 'Value must be a number'
316 $value = (int) $value;
317 return $this->clamp($value, $min, $max);
321 * Validate (and fix) an URL
323 * @param string $url URL
325 * @return string Fixed URL
326 * @throws \InvalidArgumentException
328 protected function validateUrl($url)
330 $parts = parse_url($url);
331 if ($parts === false) {
332 throw new \InvalidArgumentException('Invalid URL');
334 if (!isset($parts['scheme'])) {
335 $url = 'http://' . $url;
336 $parts = parse_url($url);
337 } else if ($parts['scheme'] != 'http' && $parts['scheme'] != 'https') {
338 throw new \InvalidArgumentException('Unsupported protocol');
340 if (!isset($parts['host'])) {
341 throw new \InvalidArgumentException('URL host missing');
347 * Set phancap configuration
349 * @param Config $config Phancap configuration
353 public function setConfig(Config $config)
355 $this->config = $config;
356 $this->options['smaxage']['default'] = $this->config->screenshotMaxAge;
357 $this->options['smaxage']['min'] = $this->config->screenshotMinAge;