X-Git-Url: https://git.cweiske.de/phancap.git/blobdiff_plain/9a568c09ae8cef2f0222e82dc93ed122615c2590..4e0f274a5a874799690a1688d3e9bea46a0c9b67:/src/phancap/Adapter/Cutycapt.php diff --git a/src/phancap/Adapter/Cutycapt.php b/src/phancap/Adapter/Cutycapt.php index 173a86c..19657c8 100644 --- a/src/phancap/Adapter/Cutycapt.php +++ b/src/phancap/Adapter/Cutycapt.php @@ -1,19 +1,91 @@ + * @copyright 2014 Christian Weiske + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 + * @link http://cweiske.de/phancap.htm + */ namespace phancap; +/** + * Screenshot rendering using the "cutycapt" command line tool. + * + * @category Tools + * @package Adapter_Cutycapt + * @author Christian Weiske + * @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 Adapter_Cutycapt { + /** + * Lock file handle + * @var resourece + */ + protected $lockHdl; + + /** + * Lock file path + * @var string + */ + protected $lockFile = null; + + /** + * Check if all dependencies are available. + * + * @return mixed TRUE if all is fine, array with error messages otherwise + */ public function isAvailable() { - //FIXME: setup check for xvfbrun, cutycapt, convert + $old = error_reporting(error_reporting() & ~E_STRICT); + $arErrors = array(); + if (\System::which('xvfb-run') === false) { + $arErrors[] = '"xvfb-run" is not installed'; + } + if (\System::which('cutycapt') === false) { + $arErrors[] = '"cutycapt" is not installed'; + } + if (\System::which('convert') === false) { + $arErrors[] = '"convert" (imagemagick) is not installed'; + } + + error_reporting($old); + if (count($arErrors)) { + return $arErrors; + } + + return true; } + /** + * Render a website screenshot + * + * @param Image $img Image configuration + * @param Options $options Screenshot configuration + * + * @return void + * @throws \Exception When something fails + */ public function render(Image $img, Options $options) { + $format = $options->values['sformat']; + if ($format == 'jpg') { + $format = 'jpeg'; + } + + $serverNumber = $this->getServerNumber($options); $tmpPath = $img->getPath() . '-tmp'; $cmd = 'cutycapt' . ' --url=' . escapeshellarg($options->values['url']) - . ' --out-format=' . escapeshellarg($options->values['sformat']) + . ' --out-format=' . escapeshellarg($format) . ' --out=' . escapeshellarg($tmpPath) . ' --max-wait=10000' . ' --min-width=' . $options->values['bwidth']; @@ -23,13 +95,86 @@ class Adapter_Cutycapt $xvfbcmd = 'xvfb-run' . ' -e /dev/stdout' - . ' --server-args="-screen 0, 1024x768x24"'; + . ' --server-args="-screen 0, 1024x768x24"' + . ' --server-num=' . $serverNumber; Executor::run($xvfbcmd . ' ' . $cmd); $this->resize($tmpPath, $img, $options); } - protected function resize($tmpPath, $img, $options) + /** + * Get a free X server number. + * + * Each xvfb-run process needs its own free server number. + * Needed for multiple parallel requests. + * + * @return integer Server number + */ + protected function getServerNumber() + { + //clean stale lock files + $this->cleanup(); + + $num = 100; + $bFound = false; + do { + ++$num; + $f = $this->config->cacheDir . 'tmp-curlycapt-server-' . $num . '.lock'; + $this->lockHdl = fopen($f, 'w'); + if (flock($this->lockHdl, LOCK_EX | LOCK_NB)) { + $this->lockFile = $f; + $bFound = true; + break; + } else { + fclose($this->lockHdl); + } + } while ($num < 200); + + if (!$bFound) { + throw new \Exception('Too many requests running'); + } + + $this->lockFile = $f; + return $num; + } + + /** + * Unlock lock file and clean up old lock files + * + * @return void + */ + public function cleanup() + { + if ($this->lockFile !== null && $this->lockHdl) { + flock($this->lockHdl, LOCK_UN); + unlink($this->lockFile); + } + + $lockFiles = glob( + $this->config->cacheDir . 'tmp-curlycapt-server-*.lock' + ); + + $now = time(); + foreach ($lockFiles as $file) { + if ($now - filemtime($file) > 120) { + //delete stale lock file; probably something crashed. + unlink($file); + } + } + } + + /** + * Convert an image to the given size. + * + * Target file is the path of $img. + * + * @param string $tmpPath Path of image to be scaled. + * @param Image $img Image configuration + * @param Options $options Screenshot configuration + * + * @return void + */ + protected function resize($tmpPath, Image $img, Options $options) { if ($options->values['sformat'] == 'pdf') { //nothing to resize. @@ -53,5 +198,17 @@ class Adapter_Cutycapt //var_dump($convertcmd);die(); unlink($tmpPath); } + + /** + * Set phancap configuration + * + * @param Config $config Phancap configuration + * + * @return void + */ + public function setConfig(Config $config) + { + $this->config = $config; + } } ?>