first work on option parsing
authorChristian Weiske <cweiske@cweiske.de>
Sun, 30 Mar 2014 12:01:34 +0000 (14:01 +0200)
committerChristian Weiske <cweiske@cweiske.de>
Sun, 30 Mar 2014 12:01:34 +0000 (14:01 +0200)
README.rst [new file with mode: 0644]
src/phancap/Autoloader.php [new file with mode: 0644]
src/phancap/Options.php [new file with mode: 0644]
www/get.php [new file with mode: 0644]
www/index.php [new file with mode: 0644]

diff --git a/README.rst b/README.rst
new file mode 100644 (file)
index 0000000..606ed74
--- /dev/null
@@ -0,0 +1,84 @@
+************************************
+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
diff --git a/src/phancap/Autoloader.php b/src/phancap/Autoloader.php
new file mode 100644 (file)
index 0000000..fed2928
--- /dev/null
@@ -0,0 +1,57 @@
+<?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'));
+    }
+}
+?>
diff --git a/src/phancap/Options.php b/src/phancap/Options.php
new file mode 100644 (file)
index 0000000..b5c96d9
--- /dev/null
@@ -0,0 +1,171 @@
+<?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;
+    }
+}
+?>
diff --git a/www/get.php b/www/get.php
new file mode 100644 (file)
index 0000000..5212e99
--- /dev/null
@@ -0,0 +1,24 @@
+<?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);
+?>
diff --git a/www/index.php b/www/index.php
new file mode 100644 (file)
index 0000000..6eff33c
--- /dev/null
@@ -0,0 +1,4 @@
+<?php
+
+
+?>