index that shows options and setup check
[phancap.git] / src / phancap / Adapter / Cutycapt.php
1 <?php
2 namespace phancap;
3
4 class Adapter_Cutycapt
5 {
6     protected $lockHdl;
7     protected $lockFile = null;
8
9     /**
10      * @return mixed TRUE if all is fine, array with error messages otherwise
11      */
12     public function isAvailable()
13     {
14         $old = error_reporting(error_reporting() & ~E_STRICT);
15         $arErrors = array();
16         if (\System::which('xvfb-run') === false) {
17             $arErrors[] = '"xvfb-run" is not installed';
18         }
19         if (\System::which('cutycapt') === false) {
20             $arErrors[] = '"cutycapt" is not installed';
21         }
22         if (\System::which('convert') === false) {
23             $arErrors[] = '"convert" (imagemagick) is not installed';
24         }
25
26         error_reporting($old);
27         if (count($arErrors)) {
28             return $arErrors;
29         }
30
31         return true;
32     }
33
34     public function render(Image $img, Options $options)
35     {
36         $format = $options->values['sformat'];
37         if ($format == 'jpg') {
38             $format = 'jpeg';
39         }
40
41         $serverNumber = $this->getServerNumber($options);
42         $tmpPath = $img->getPath() . '-tmp';
43         $cmd = 'cutycapt'
44             . ' --url=' . escapeshellarg($options->values['url'])
45             . ' --out-format=' . escapeshellarg($format)
46             . ' --out=' . escapeshellarg($tmpPath)
47             . ' --max-wait=10000'
48             . ' --min-width=' . $options->values['bwidth'];
49         if ($options->values['bheight'] !== null) {
50             $cmd .= ' --min-height=' . $options->values['bheight'];
51         }
52
53         $xvfbcmd = 'xvfb-run'
54             . ' -e /dev/stdout'
55             . ' --server-args="-screen 0, 1024x768x24"'
56             . ' --server-num=' . $serverNumber;
57         Executor::run($xvfbcmd . ' ' . $cmd);
58
59         $this->resize($tmpPath, $img, $options);
60     }
61
62     protected function getServerNumber()
63     {
64         //clean stale lock files
65         $this->cleanup();
66
67         $num = 100;
68         $bFound = false;
69         do {
70             ++$num;
71             $f = $this->config->cacheDir . 'tmp-curlycapt-server-' . $num . '.lock';
72             $this->lockHdl = fopen($f, 'w');
73             if (flock($this->lockHdl, LOCK_EX | LOCK_NB)) {
74                 $this->lockFile = $f;
75                 $bFound = true;
76                 break;
77             } else {
78                 fclose($this->lockHdl);
79             }
80         } while ($num < 200);
81
82         if (!$bFound) {
83             throw new \Exception('Too many requests running');
84         }
85
86         $this->lockFile = $f;
87         return $num;
88     }
89
90     public function cleanup()
91     {
92         if ($this->lockFile !== null && $this->lockHdl) {
93             flock($this->lockHdl, LOCK_UN);
94             unlink($this->lockFile);
95         }
96
97         $lockFiles = glob(
98             $this->config->cacheDir . 'tmp-curlycapt-server-*.lock'
99         );
100
101         $now = time();
102         foreach ($lockFiles as $file) {
103             if ($now - filemtime($file) > 120) {
104                 //delete stale lock file; probably something crashed.
105                 unlink($file);
106             }
107         }
108     }
109
110     protected function resize($tmpPath, $img, $options)
111     {
112         if ($options->values['sformat'] == 'pdf') {
113             //nothing to resize.
114             rename($tmpPath, $img->getPath());
115             return;
116         }
117
118         $crop = '';
119         if ($options->values['smode'] == 'screen') {
120             $crop = ' -crop ' . $options->values['swidth']
121                 . 'x' . $options->values['sheight']
122                 . '+0x0';
123         }
124
125         $convertcmd = 'convert'
126             . ' ' . escapeshellarg($tmpPath)
127             . ' -resize ' . $options->values['swidth']
128             . $crop
129             . ' ' . escapeshellarg($img->getPath());
130         Executor::run($convertcmd);
131         //var_dump($convertcmd);die();
132         unlink($tmpPath);
133     }
134
135     public function setConfig(Config $config)
136     {
137         $this->config = $config;
138     }
139 }
140 ?>