1<?php
2/**
3 * snap helper : Affiche un lien sous forme de miniature.
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Etienne M. <emauvaisfr@yahoo.fr>
7 */
8
9// based on http://wiki.splitbrain.org/plugin:tutorial
10
11// must be run within Dokuwiki
12if (!defined('DOKU_INC')) die();
13
14if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
15require_once(DOKU_PLUGIN . 'syntax.php');
16
17/**
18 * All DokuWiki plugins to extend the parser/rendering mechanism
19 * need to inherit from this class
20 */
21class helper_plugin_snap extends DokuWiki_Syntax_Plugin {
22
23        //Parametres ///////////////////////////////
24        //Chemin vers votre Dokuwiki (voir le constructeur ci-dessous)
25        //Path to your Dokuwiki (see constructor below)
26        var $defaultWiki=false;
27
28        //Taille de l'ecran du navigateur
29        //Browser screen size
30        var $screenx=1280;
31        var $screeny=1024;
32
33        //Proportions largeur/hauteur de l'image de la capture
34        //Proportions width/height of the snap
35        var $imFactor=1.333333333333333333333; //4/3
36
37        //Taille de l'image par defaut
38        //Default image size
39        var $defLarg=200;
40        var $defHaut=150;
41
42        //Taille maximale autorisee pour l'image
43        //Max allowed image size
44        var $maxLarg=400;
45        var $maxHaut=300;
46
47        //Serveur de capture (voir le parametrage de server.sh)
48        //Snap server (see server.sh parameters)
49        var $snapServer="localhost";
50        var $snapPorts="8888 8889 8890 8891 8892";
51        var $snapTimeout=5;            //Secondes
52        var $tryTimeout=3;             //Secondes
53
54        //Utiliser le cache ?
55        //Use cache?
56        var $checkCache=true;
57
58        //Autres variables
59        var $outputPath=false;
60        var $imagePath=false;
61        var $titrePage=false;
62        var $snapTime=false;
63        var $snapTimeFormatted=false;
64        var $fromCache=false;
65        var $succeed=false;
66        var $target=false;
67        var $selectedPort=false;
68        var $snapLog=false;
69        var $timeout=false;
70        var $snapDuration=false;
71        var $snapTotalDuration=false;
72        var $tries=false;
73        var $url=false;
74        var $width=false;
75        var $height=false;
76        ////////////////////////////////////////////
77
78
79    function getInfo() {
80        return array(
81        'author'  => 'Etienne M.',
82        'email'   => 'emauvaisfr@yahoo.fr',
83        'date'    => @file_get_contents(DOKU_PLUGIN.'snap/VERSION'),
84        'name'    => 'snap Helper',
85        'desc'    => html_entity_decode($this->getLang('snap_description')),
86        'url'     => 'http://www.dokuwiki.org/plugin:snap'
87        );
88    }
89
90
91    function getMethods(){
92      $result = array();
93      $result[] = array(
94        'name'   => 'getSnap',
95        'desc'   => $this->lang('snap_getSnap'),
96        'params' => array(
97          'url to snap (page id or full url starting with http://)' => 'string',
98          'width' => 'integer',
99          'height' => 'integer',
100          'checkCache' => 'boolean')
101      );
102      return $result;
103    }
104
105
106    //Constructor
107    function helper_plugin_snap() {
108      global $conf;
109
110      //Chemin vers votre Dokuwiki
111      //Path to your Dokuwiki
112      $this->defaultWiki=DOKU_URL."doku.php?id=";
113
114      $this->outputPath=realpath($conf['datadir']).'/../snap/';
115      if (!file_exists($this->outputPath.".")) mkdir($this->outputPath);
116    }
117
118
119    function getSnap($param, $larg, $haut, $checkCache=NULL) {
120      global $conf;
121
122      $this->imagePath=false;
123      $this->titrePage=false;
124      $this->snapTime=false;
125      $this->snapTimeFormatted=false;
126      $this->fromCache=false;
127      $this->succeed=false;
128      $this->target=false;
129      $this->selectedPort=false;
130      $this->snapLog=false;
131      $this->timeout=false;
132      $this->snapDuration=false;
133      $this->snapTotalDuration=false;
134      $this->tries=false;
135      $this->url=false;
136      $this->width=false;
137      $this->height=false;
138
139      if ($checkCache === NULL) $checkCache=$this->checkCache;
140
141      if (!preg_match('/^.*?:\/\//',$param)) {
142        $this->url=$this->defaultWiki.$param;
143
144        //Il vous faut appliquer cette astuce pour utiliser cette adresse avec authentification: http://www.dokuwiki.org/tips:phashlogin
145        //You have to apply this tip to use this url with authentication: http://www.dokuwiki.org/tips:phashlogin
146        $url=$this->defaultWiki.$param."&u=".urlencode($_SESSION[DOKU_COOKIE]['auth']['user'])."&phash=".urlencode($_SESSION[DOKU_COOKIE]['auth']['pass']);
147
148        //Si vos pages sont en libre acc�s sans authentification, vous pouvez utiliser cette adresse � la place
149        //If your pages are fully readable without authentication, you can use this adresse instead
150        //$url=$this->defaultWiki.$param;
151
152        //Ne pas utiliser la ligne ci-dessous � moins d'�tre vraiment s�r
153        //(les mots de passe des utilisateurs sera utilis� en clair !!!)
154        //Do not use the line below unless you are really sure
155        //(the clear users password will be used!!!)
156        //$url=$this->defaultWiki.$param."&u=".urlencode($_SESSION[DOKU_COOKIE]['auth']['user'])."&p=".PMA_blowfish_decrypt(urlencode($_SESSION[DOKU_COOKIE]['auth']['pass'], auth_cookiesalt());
157
158        $pagelist = plugin_load('helper', 'pagelist');
159        if (!$pagelist) {
160          $titrePage=explode(":",$param);
161          $titrePage=$titrePage[sizeof($titrePage)-1];
162          $titrePage=str_replace('_',' ',$titrePage);
163        }
164        else {
165          $pagelist->page['id']=$param;
166          $pagelist->page['exists'] = 1;
167          $pagelist->_meta=NULL;
168          $titrePage = $pagelist->_getMeta('title');
169          if (!$titrePage) $titrePage = str_replace('_', ' ', noNS($param));
170          $titrePage = hsc($titrePage);
171        }
172      }
173      else {
174        $this->url=$param;
175        $url=$param;
176        $titrePage="";
177      }
178
179      if (!$larg && !$haut) {
180        $larg=$this->defLarg;
181        $haut=$this->defHaut;
182      }
183      else if (!$larg) $larg=round($haut*$this->imFactor,0);
184      else if (!$haut) $haut=round($larg/$this->imFactor,0);
185
186      if ($larg>$this->maxLarg) $larg=$this->maxLarg;
187      if ($haut>$this->maxHaut) $haut=$this->maxHaut;
188
189      $this->width=$larg;
190      $this->height=$haut;
191
192      if ($url==$param) $image="web_".rawurlencode($param);
193      else $image=$param;
194      $image.="_".$larg."x".$haut.".jpg";
195      $imagePath=$this->outputPath.$image;
196      if (file_exists($imagePath)) list($imLarg, $imHaut, $imType, $imAttr) = getimagesize($imagePath);
197
198      //Si l'image n'existe pas ou qu'elle est trop vieille ou qu'on demande une taille differente de celle existante
199      //on la capture
200      if (!$checkCache ||
201          !file_exists($imagePath) ||
202          ((time()-filemtime($imagePath))>$conf['cachetime']) ||
203          $imLarg != $larg ||
204          $imHaut != $haut) {
205
206        $totalStart=time();
207        $try=0;
208
209        //Build the ports list
210        $ports=explode(" ",$this->snapPorts);
211
212        while (!$fp && $try<$this->tryTimeout) {
213          //Pause d'un quart de seconde si on est en retry
214          if ($try) usleep(250000);
215          error_log("SNAP: $image try #$try");
216          $this->selectedPort=$ports[array_rand($ports)];
217          $fp = fsockopen($this->snapServer, $this->selectedPort, $errno, $errstr, 30);
218          $try++;
219        }
220        if (!$fp) {
221          error_log("SNAP: $image aborting");
222          $this->tries=$try;
223          $this->width=false;
224          $this->height=false;
225          return false;
226        } else {
227          error_log("SNAP: $image launch snap");
228          $start=time();
229          fwrite($fp, "$url $imagePath $this->screenx $this->screeny ".($this->snapTimeout*1000)." $larg $haut\n");
230          while (!feof($fp)) $this->snapLog.=fgets($fp, 128);
231            fclose($fp);
232          }
233          $this->snapDuration=time()-$start;
234          $this->snapTotalDuration=time()-$totalStart;
235          $this->tries=$try;
236        }
237        else {
238          error_log("SNAP: $image found in cache");
239          $this->fromCache=true;
240        }
241
242        //Remove password from snapLog
243        $this->snapLog=preg_replace_callback("/&phash=(.*)/",
244                                               create_function('',
245                                                 'return "&phash=******";'
246                                             ),
247                                             $this->snapLog);
248        $this->snapLog=preg_replace_callback("/&p=(.*)/",
249                                               create_function('',
250                                                 'return "&p=******";'
251                                             ),
252                                             $this->snapLog);
253
254        //timeout occurs during snap? (even if true, the snap image may be ok)
255        if (preg_match("/html2image error: time out/i",$this->snapLog)) $this->timeout=true;
256
257        //timeout occurs during snap? (even if true, the snap image may be ok)
258        if (preg_match("/html2image error: time out/i",$this->snapLog)) $this->timeout=true;
259
260        if (!file_exists($imagePath)) {
261          error_log("SNAP: $image not found after snap");
262          return false;
263        }
264
265        error_log("SNAP: $image available");
266        $this->snapTime=filemtime($imagePath);
267        $this->snapTimeFormatted=strftime($conf['dformat'],$this->snapTime);
268
269        if ($url==$param) {
270          if ($conf['target']['extern']) $this->target="target=\"".$conf['target']['extern']."\"";
271        }
272        else {
273          if ($conf['target']['wiki']) $this->target="target=\"".$conf['target']['wiki']."\"";
274        }
275
276        $this->imagePath=$imagePath;
277        $this->titrePage=$titrePage;
278        $this->succeed=true;
279
280        return array($this->imagePath, $this->titrePage, $this->target);
281    }
282}
283?>
284