--- /dev/null
+************************************
+phancap - website screenshot service
+************************************
+
+Software to create screenshots and thumbnails of websites via an API.
+
+Self-hosted and written in PHP. Caching included.
+
+
+=======================
+Technical brainstorming
+=======================
+
+Tools to make website screenshots
+=================================
+- `cutycapt <http://cutycapt.sourceforge.net/>`_
+- `khtml2png <http://khtml2png.sourceforge.net/>`_ (outdated)
+- `phantomjs <http://phantomjs.org/>`_
+- `python-webkit2png <https://github.com/AdamN/python-webkit2png/>`_
+- `wkhtmltopdf <http://code.google.com/p/wkhtmltopdf/>`_
+- wkhtmltoimage
+
+
+Possible parameters
+===================
+
+Page request parameters
+-----------------------
+- url
+- bwidth (browser width / resolution)
+- bheight (browser height / resolution)
+- delay (capture X seconds after page loaded)
+- useragent (user agent header string)
+- accepted languages (Accept-Language header)
+- cookie (set cookie data)
+- referer (custom referer header)
+- post data (send POST data as if filled out a form)
+
+Screenshot configuration
+------------------------
+- width (of thumbnail)
+- height (of thumbnail)
+- output format (jpg, png, pdf)
+- mode: screen or page (full page height or screen size only)
+ - page aka fullpage
+- quality (jpeg image quality)
+
+Misc
+----
+- callback URL (to notify when screenshot is ready)
+- sync/async (wait for response or just get a 202 accepted)
+- cache (to force a fresh screenshot with cache=0,
+ otherwise seconds the cache may be old)
+- api key
+- token (md5 hash of query string)
+
+API parameter sources
+---------------------
+- http://api1.thumbalizr.com/
+- http://url2png.com/docs/
+- http://webthumb.bluga.net/apidoc
+- http://www.page2images.com/Create-website-screenshot-online-API
+- http://browshot.com/api/documentation
+
+
+Other website screenshot services
+=================================
+- http://browsershots.org/
+- http://browshot.com/
+- http://ctrlq.org/screenshots/
+- http://grabz.it/
+- http://url2png.com/
+- http://usersnap.com/
+- http://websnapr.com/
+- http://webthumb.bluga.net/
+- http://www.page2images.com/
+- http://www.shrinktheweb.com/
+- http://www.thumbalizr.com/
+- http://www.url2picture.com/
+
+
+Other website screenshot software
+=================================
+- https://github.com/microweber/screen
--- /dev/null
+<?php
+/**
+ * Part of phancap
+ *
+ * PHP version 5
+ *
+ * @category Tools
+ * @package Phancap
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2014 Christian Weiske
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://cweiske.de/phancap.htm
+ */
+namespace phancap;
+
+/**
+ * Class autoloader, PSR-0 compliant.
+ *
+ * @category Tools
+ * @package Phancap
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2014 Christian Weiske
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @version Release: @package_version@
+ * @link http://cweiske.de/phancap.htm
+ */
+class Autoloader
+{
+ /**
+ * Load the given class
+ *
+ * @param string $class Class name
+ *
+ * @return void
+ */
+ public function load($class)
+ {
+ $file = strtr($class, '_\\', '//') . '.php';
+ if (stream_resolve_include_path($file)) {
+ include $file;
+ }
+ }
+
+ /**
+ * Register this autoloader
+ *
+ * @return void
+ */
+ public static function register()
+ {
+ set_include_path(
+ get_include_path() . PATH_SEPARATOR . __DIR__ . '/../'
+ );
+ spl_autoload_register(array(new self(), 'load'));
+ }
+}
+?>
--- /dev/null
+<?php
+namespace phancap;
+
+class Options
+{
+ public static $options = array(
+ /**
+ * Browser settings
+ */
+ 'url' => array(
+ 'title' => 'Website URL',
+ 'default' => null,
+ 'type' => 'url',
+ ),
+ 'bwidth' => array(
+ 'title' => 'Browser width',
+ 'default' => 1024,
+ 'type' => 'int',
+ 'min' => 16,
+ 'max' => 2048,
+ ),
+ 'bheight' => array(
+ 'title' => 'Browser height',
+ 'default' => null,
+ 'type' => 'int',
+ 'min' => 16,
+ 'max' => 8192,
+ ),
+ /**
+ * Screenshot settings
+ */
+ 'swidth' => array(
+ 'title' => 'Screenshot width',
+ 'default' => 300,
+ 'type' => 'int',
+ 'min' => 16,
+ 'max' => 8192,
+ ),
+ 'sheight' => array(
+ 'title' => 'Screenshot height',
+ 'default' => null,
+ 'type' => 'int',
+ 'min' => 16,
+ 'max' => 8192,
+ ),
+ 'sformat' => array(
+ 'title' => 'Screenshot format',
+ 'default' => 'png',
+ 'type' => array('png', 'jpg', 'pdf'),
+ ),
+ 'smode' => array(
+ 'title' => 'Screenshot mode',
+ 'default' => 'screen',
+ 'type' => array('screen', 'page'),
+ ),
+ );
+
+ public $values = array();
+
+
+ /**
+ * Parses an array of options, validates them and writes them into
+ * $this->values.
+ *
+ * @param array $arValues Array of options, e.g. $_GET
+ */
+ public function parse($arValues)
+ {
+ foreach (static::$options as $name => $arOption) {
+ $this->values[$name] = $arOption['default'];
+ if (!isset($arValues[$name])) {
+ continue;
+ }
+ if ($arOption['type'] == 'url') {
+ $this->values[$name] = $this->validateUrl($arValues[$name]);
+ } else if ($arOption['type'] == 'int') {
+ $this->values[$name] = $this->validateInt(
+ $arValues[$name], $arOption['min'], $arOption['max']
+ );
+ } else if (gettype($arOption['type']) == 'array') {
+ $this->values[$name] = $this->validateArray(
+ $arValues[$name], $arOption['type']
+ );
+ } else {
+ throw new \InvalidArgumentException(
+ 'Unsupported option type: ' . $arOption['type']
+ );
+ }
+ unset($arValues[$name]);
+ }
+
+ if (count($arValues) > 0) {
+ throw new \InvalidArgumentException(
+ 'Unsupported parameter: ' . implode(', ', array_keys($arValues))
+ );
+ }
+
+ $this->calcPageSize();
+ }
+
+ protected function calcPageSize()
+ {
+ if ($this->values['smode'] == 'page') {
+ return;
+ }
+
+ if ($this->values['sheight'] !== null) {
+ $this->values['bheight'] = intval(
+ $this->values['bwidth'] / $this->values['swidth']
+ * $this->values['sheight']
+ );
+ } else if ($this->values['bheight'] !== null) {
+ $this->values['sheight'] = intval(
+ $this->values['swidth'] / $this->values['bwidth']
+ * $this->values['bheight']
+ );
+ } else {
+ //no height set. use 4:3
+ $this->values['sheight'] = $this->values['swidth'] / 4 * 3;
+ $this->values['bheight'] = $this->values['bwidth'] / 4 * 3;
+ }
+ }
+
+ protected function validateArray($value, $options)
+ {
+ if (array_search($value, $options) === false) {
+ throw new \InvalidArgumentException(
+ 'Invalid value ' . $value . '.'
+ . ' Allowed: ' . implode(', ', $options)
+ );
+ }
+ return $value;
+ }
+
+ protected function validateInt($value, $min, $max)
+ {
+ if (!is_numeric($value)) {
+ throw new \InvalidArgumentException(
+ 'Value must be a number'
+ );
+ }
+ $value = (int) $value;
+ if ($value < $min) {
+ throw new \InvalidArgumentException(
+ 'Value must be at least ' . $min
+ );
+ }
+ if ($value > $max) {
+ throw new \InvalidArgumentException(
+ 'Value may be up to ' . $min
+ );
+ }
+ return $value;
+ }
+
+ protected function validateUrl($url)
+ {
+ $parts = parse_url($url);
+ if ($parts === false) {
+ throw new \InvalidArgumentException('Invalid URL');
+ }
+ if (!isset($parts['scheme'])) {
+ throw new \InvalidArgumentException('URL scheme missing');
+ }
+ if (!isset($parts['host'])) {
+ throw new \InvalidArgumentException('URL host missing');
+ }
+ return $url;
+ }
+}
+?>
--- /dev/null
+<?php
+namespace phancap;
+/**
+ * Get a screenshot for a website.
+ */
+if (file_exists(__DIR__ . '/../src/phancap/Autoloader.php')) {
+ include_once __DIR__ . '/../src/phancap/Autoloader.php';
+ Autoloader::register();
+} else {
+ include_once 'phancap/Autoloader.php';
+}
+
+$options = new Options();
+try {
+ $options->parse($_GET);
+} catch (\InvalidArgumentException $e) {
+ header('HTTP/1.0 400 Bad Request');
+ header('Content-type: text/plain');
+ echo $e->getMessage();
+ exit(1);
+}
+
+var_dump($options->values);
+?>
--- /dev/null
+<?php
+
+
+?>