--- /dev/null
+/www/imgcache
--- /dev/null
+<?php
+namespace phancap;
+
+class Adapter_Cutycapt
+{
+ public function isAvailable()
+ {
+ //FIXME: setup check for xvfbrun, cutycapt, convert
+ }
+
+ public function render(Image $img, Options $options)
+ {
+ $tmpPath = $img->getPath() . '-tmp';
+ $cmd = 'cutycapt'
+ . ' --url=' . escapeshellarg($options->values['url'])
+ . ' --out-format=' . escapeshellarg($options->values['sformat'])
+ . ' --out=' . escapeshellarg($tmpPath)
+ . ' --max-wait=10000'
+ . ' --min-width=' . $options->values['bwidth'];
+ if ($options->values['bheight'] !== null) {
+ $cmd .= ' --min-height=' . $options->values['bheight'];
+ }
+
+ $xvfbcmd = 'xvfb-run'
+ . ' -e /dev/stdout'
+ . ' --server-args="-screen 0, 1024x768x24"';
+ Executor::run($xvfbcmd . ' ' . $cmd);
+
+ $this->resize($tmpPath, $img, $options);
+ }
+
+ protected function resize($tmpPath, $img, $options)
+ {
+ if ($options->values['sformat'] == 'pdf') {
+ //nothing to resize.
+ rename($tmpPath, $img->getPath());
+ return;
+ }
+
+ $crop = '';
+ if ($options->values['smode'] == 'screen') {
+ $crop = ' -crop ' . $options->values['swidth']
+ . 'x' . $options->values['sheight']
+ . '+0x0';
+ }
+
+ $convertcmd = 'convert'
+ . ' ' . escapeshellarg($tmpPath)
+ . ' -resize ' . $options->values['swidth']
+ . $crop
+ . ' ' . escapeshellarg($img->getPath());
+ Executor::run($convertcmd);
+ //var_dump($convertcmd);die();
+ unlink($tmpPath);
+ }
+}
+?>
--- /dev/null
+<?php
+namespace phancap;
+
+class Config
+{
+ /**
+ * Full file system path to cache directory
+ * @var string
+ */
+ public $cacheDir;
+
+ /**
+ * Full URL to cache directory
+ * @var string
+ */
+ public $cacheDirUrl;
+
+
+ public function __construct()
+ {
+ $this->cacheDir = getcwd() . '/imgcache/';
+ $this->cacheDirUrl = $this->getCurrentUrlDir() . '/imgcache/';
+ }
+
+ public function setupCheck()
+ {
+ if (!is_dir($this->cacheDir)) {
+ throw new \Exception('Cache directory does not exist: ' . $this->cacheDir);
+ }
+ if (!is_writable($this->cacheDir)) {
+ throw new \Exception('Cache directory is not writable: ' . $this->cacheDir);
+ }
+ }
+
+ protected function getCurrentUrl()
+ {
+ if (!isset($_SERVER['REQUEST_SCHEME'])) {
+ $_SERVER['REQUEST_SCHEME'] = 'http';
+ }
+ return $_SERVER['REQUEST_SCHEME'] . '://'
+ . $_SERVER['HTTP_HOST']
+ . preg_replace('/#.*$/', '', $_SERVER['REQUEST_URI']);
+ }
+
+ protected function getCurrentUrlDir()
+ {
+ $url = $this->getCurrentUrl();
+ $url = preg_replace('/\?.*$/', '', $url);
+ if (substr($url, -1) == '/') {
+ return $url;
+ }
+
+ return substr($url, 0, -strlen(basename($url)) - 1);
+ }
+}
+?>
--- /dev/null
+<?php
+namespace phancap;
+
+class Executor
+{
+ public static function run($cmd)
+ {
+ exec($cmd . ' 2>&1', $arOutput, $exitcode);
+ if ($exitcode != 0) {
+ //FIXME: do something with $arOutput
+ echo implode("\n", $arOutput) . "\n";
+ throw new \Exception('Error running cutycapt', $exitcode);
+ }
+ }
+}
+
+?>
--- /dev/null
+<?php
+namespace phancap;
+
+class Image
+{
+ protected $config;
+ public $name;
+
+
+ public function __construct($name)
+ {
+ $this->name = $name;
+ }
+
+ public function getPath()
+ {
+ return $this->config->cacheDir . $this->name;
+ }
+
+ public function getUrl()
+ {
+ return $this->config->cacheDirUrl . $this->name;
+ }
+
+ public function setConfig(Config $config)
+ {
+ $this->config = $config;
+ }
+}
+?>
\ No newline at end of file
'title' => 'Website URL',
'default' => null,
'type' => 'url',
+ 'required' => true,
),
'bwidth' => array(
'title' => 'Browser width',
*/
'swidth' => array(
'title' => 'Screenshot width',
- 'default' => 300,
+ 'default' => null,
'type' => 'int',
'min' => 16,
'max' => 8192,
foreach (static::$options as $name => $arOption) {
$this->values[$name] = $arOption['default'];
if (!isset($arValues[$name])) {
+ if (isset($arOption['required'])) {
+ throw new \InvalidArgumentException(
+ $name . ' parameter missing'
+ );
+ }
continue;
}
+
if ($arOption['type'] == 'url') {
$this->values[$name] = $this->validateUrl($arValues[$name]);
} else if ($arOption['type'] == 'int') {
protected function calcPageSize()
{
+ if ($this->values['swidth'] === null) {
+ $this->values['swidth'] = $this->values['bwidth'];
+ }
if ($this->values['smode'] == 'page') {
return;
}
--- /dev/null
+<?php
+namespace phancap;
+
+class Repository
+{
+ public function setConfig(Config $config)
+ {
+ $this->config = $config;
+ }
+
+ public function getImage(Options $options)
+ {
+ $name = $this->getFilename($options);
+ $img = new Image($name);
+ $img->setConfig($this->config);
+ if (!$this->isAvailable($img)) {
+ $this->render($img, $options);
+ }
+ return $img;
+ }
+
+ public function getFilename(Options $options)
+ {
+ return parse_url($options->values['url'], PHP_URL_HOST)
+ . '-' . md5(\serialize($options->values))
+ . '.' . $options->values['sformat'];
+ }
+
+ public function isAvailable(Image $img)
+ {
+ $path = $img->getPath();
+ if (!file_exists($path)) {
+ return false;
+ }
+ //FIXME: add cache lifetime check
+
+ return true;
+ }
+
+ protected function render(Image $img, Options $options)
+ {
+ $adapter = new Adapter_Cutycapt();
+ $adapter->render($img, $options);
+ }
+}
+?>
/**
* Get a screenshot for a website.
*/
+header('HTTP/1.0 500 Internal Server Error');
+
if (file_exists(__DIR__ . '/../src/phancap/Autoloader.php')) {
include_once __DIR__ . '/../src/phancap/Autoloader.php';
Autoloader::register();
include_once 'phancap/Autoloader.php';
}
+$config = new Config();
+$config->setupCheck();
+
$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();
+ echo $e->getMessage() . "\n";
exit(1);
}
-var_dump($options->values);
+$rep = new Repository();
+$rep->setConfig($config);
+try {
+ $img = $rep->getImage($options);
+ header('HTTP/1.0 302 Found');
+ header('Location: ' . $img->getUrl());
+} catch (\Exception $e) {
+ //FIXME: handle 404s and so properly
+ header('HTTP/1.0 500 Internal Server error');
+ header('Content-type: text/plain');
+ echo $e->getMessage() . "\n";
+ exit(2);
+}
?>