source: spip-zone/_plugins_/ressource/inc/ressource.php @ 65568

Last change on this file since 65568 was 65568, checked in by brunobergot@…, 8 years ago

version 0.2.0 : ajout d'un pipeline ressource_meta pour permettre à d'autres plugins de se brancher sur la fonction du même nom + passage du numéro de version sur 3 chiffres

File size: 15.2 KB
Line 
1<?php
2
3/*
4 * transforme un raccourci de ressource en un joli html a embed
5 *
6 *
7 */
8
9define('_EXTRAIRE_RESSOURCES', ',' . '<"?(https?://|[\w -]+\.[\w -]+).*>'.',UimsS');
10
11
12function traiter_ressources($r) {
13        if ($ressource = charger_fonction('ressource', 'inc', true))
14                $html = $ressource($r[0]);
15        else
16                $html = htmlspecialchars($r[0]);
17
18        return '<html>'.$html.'</html>';
19}
20
21
22function inc_ressource_dist($r) {
23        // $r contient tout le texte définissant la ressource :
24        // <fichier.rtf option1 option2...>
25
26        // 1. phraser le raccourci
27        $attrs = phraser_tag('<res src='.substr($r,1));
28
29        # debug :)
30        $attrs['debug'] = $r;
31
32        // 2. keywords : right => align=right, etc
33        foreach(array(
34                'right' => 'align',
35                'left' => 'align',
36                'center' => 'align',
37        ) as $k => $v) {
38                if ($attrs[$k] == $k) {
39                        $attrs[$v] = $k;
40                        unset($attrs[$k]);
41                }
42        }
43
44        // 2. constituer les meta-donnees associees a $res[src]
45        $meta = ressource_meta($attrs);
46
47        // 4. traiter les parametres d'image / logo / vignette / resize
48        // supprimera le href si necessaire
49        $image = ressource_image($attrs, $meta);
50
51        $final = array_merge($meta, $attrs);
52
53        // renvoyer le html final
54        $final = array_merge($final, $image);
55
56        $html = embed_ressource($final);
57        return $html;
58}
59
60function ressource_meta($res) {
61        $meta = array();
62
63        // on va beaucoup travailler avec l'attribut src
64        $src = $res['src'];
65
66        // identifier la ressource
67        // s'agit-il d'un fichier decrit dans la mediathèque,
68        // d'un fichier local, d'un oembed, d'un doc distant connu, etc ?
69
70        // ressource fichier.rtf => rtf/fichier.rtf
71        if (preg_match(',^[^/]+\.([^.]+)$,', $src, $r))
72                $fichier = $r[1].'/'.$r[0];
73        else
74                $fichier = $src;
75
76        // determiner temporairement l'extension de la ressource (ca pourra changer
77        // si on en fait une copie locale et qu'elle indique un autre type mime)
78        if (preg_match(',\.(\w+)([?#].*)?$,S', $src, $r)) {
79                $meta['extension'] = strtolower($r[1]);
80
81                if ($meta['extension'] == 'jpeg')
82                        $meta['extension'] = 'jpg';
83        }
84
85        # d'abord fouiller la mediatheque
86        include_spip('base/abstract_sql');
87        if ($s = sql_fetsel('*', 'spip_documents', 'fichier='.sql_quote($fichier))) {
88                $meta = $s;
89                $meta['href'] = get_spip_doc($s['fichier']);
90                $meta['local'] = copie_locale($meta['href'], 'test');
91        }
92        else
93        if (preg_match(',^https?://,', $src)) {
94                $meta['href'] = $src;
95
96                /* pipeline ! */
97                /* exemple : traitement par autoembed */
98                include_spip('autoembed/autoembed');
99                if (function_exists('embed_url')
100                AND $u = embed_url($src)) {
101                        $meta['extract'] = $u;
102                }
103               
104                $meta = pipeline('ressource_meta',
105                        array(
106                                'args' => $res,
107                                'data' => $meta
108                        )
109                );
110               
111                /* chargement distant */
112                if (!isset($meta['html'])) {
113                        include_spip('inc/distant');
114                        if (!$local = copie_locale($src, 'test')
115                        AND !in_array($meta['extension'], array('mp3'))
116                        ) {
117                                include_spip('inc/queue');
118                                queue_add_job('copie_locale', 'copier', array($src), $file = 'inc/distant', $no_duplicate = true, $time=0, $priority=0);
119                        }
120                        if ($local = copie_locale($src, 'test')) {
121                                $meta['local'] = $local;
122                        }
123                }
124
125        }
126        // fichier dans IMG/ ?
127        else if (preg_match(',^[^/]+\.([^.]+)$,', $src, $r)
128        AND $h = _DIR_IMG.$r[1].'/'.$r[0]
129        AND @file_exists($h)
130        ) {
131                $meta['local'] = $h;
132                $meta['href'] = $h;
133        }
134
135        // si on l'a, renseigner ce qu'on peut dire du fichier
136        if (isset($meta['local'])
137        AND @file_exists($meta['local'])) {
138                $meta['extension'] = preg_replace(',^.*\.,', '', $meta['local']);
139                $meta['taille'] = @filesize($meta['local']);
140                if ($r = getimagesize($meta['local'])) {
141                        // donnees brutes du fichier
142                        $meta['width'] = $r[0];
143                        $meta['height'] = $r[1];
144                        $meta['largeur'] = $meta['width'];
145                        $meta['hauteur'] = $meta['height'];
146                }
147
148                if ($meta['extension'] == 'html') {
149                        // choper ce qu'on peut du html
150                        ressource_html($meta);
151                }
152
153                // extraire ses donnees !
154                if (!isset($meta['extract'])
155                AND $u = ressource_extract($meta)) {
156                        $meta['fullextract'] = $u;
157                        $meta['extract'] = propre(couper($u, 500));
158                }
159        }
160
161        // recupere le type mime de la ressource
162        if (isset($meta['extension']))
163                $meta['type_document'] = ressource_mime($meta['extension']);
164
165        return $meta;
166}
167
168// choper les trucs du genre meta opengraph ; meta description etc
169function ressource_html(&$meta) {
170
171        include_spip('fonctionsale');
172        if (function_exists('sale')) {
173                $u = sale(spip_file_get_contents($meta['local']));
174
175                $meta['fullextract'] = $u;
176                $meta['extract'] = propre(couper($u, 500));
177        }
178}
179
180function ressource_mime($e) {
181        global $tables_images, $tables_sequences, $tables_documents, $tables_mime, $mime_alias;
182        include_spip('base/typedoc');
183
184
185        $mime = $tables_mime[$e];
186        if (!$t = $tables_documents[$e]
187        AND !$t = $tables_images[$e]
188        AND !$t = $tables_sequences[$e])
189                $t = $e;
190
191        return $t;
192
193}
194
195/*
196 * recoit une chaine
197 * renvoie un array
198 * les valeurs par defaut sont mappees
199 * inspire de http://w-shadow.com/blog/2009/10/20/how-to-extract-html-tags-and-their-attributes-with-php/
200 */
201function phraser_tag($rr) {
202        $attribute_pattern =
203        '@
204        (
205        (?P<name>\w+)                    # attribute name
206        \s*=\s*
207        (
208            (?P<quote>[\"\'])(?P<value_quoted>.*?)(?P=quote)    # a quoted value
209            |                      # or
210            (?P<value_unquoted>[^\s"\']+?)(?:\s+)          # an unquoted value
211        )
212        |(?P<auto>\w+)
213        )
214        @xsiS';
215
216        // d'abord eliminer le type du tag et l'evntuelle fermeture auto
217        $res = array();
218        $rr = preg_replace(',^<\w+\s+,S', '', $rr);
219        $rr = preg_replace(',\s*/?'.'>$,S', ' ', $rr);
220
221        // ensuite parser le reste des attributs
222        preg_match_all($attribute_pattern, $rr, $z, PREG_SET_ORDER);
223
224        foreach($z as $t) {
225                if (isset($t['auto'])) {
226                        if (is_numeric($t['auto'])) # 200
227                                $res['width'] = $t['auto'];
228                        elseif (preg_match(',^\d+x\d+$,', $t['auto'])) # 200x300
229                                $res['geometry'] = $t['auto'];
230                        else
231                                $res[$t['auto']] = $t['auto'];
232                }
233                elseif (isset($t['value_unquoted'])) {
234                        $res[$t['name']] = $t['value_unquoted'];
235                }
236                elseif (isset($t['value_quoted'])) {
237                        $res[$t['name']] = $t['value_quoted'];
238                }
239        }
240
241        return $res;
242}
243
244function embed_ressource($res) {
245        // si la ressource est un document, renvoyer <doc1>
246        if (isset($res['id_document'])) {
247#               return recuperer_fond('modeles/doc', $res);
248        }
249
250        return
251#               "<pre>".var_export($res,true)."</pre>" .
252                recuperer_fond('modeles/ressource', $res);
253}
254
255/* ici c'est flou… */
256function ressource_image($attrs, $meta) {
257        $image = array();
258
259        // creer une vignette pour le doc ; si une largeur est exigee,
260        // adapter la taille.
261        if ($attrs['largeur'] OR $attrs['hauteur']) {
262                $resize = true;
263        }
264        // size
265        else {
266                if (!$attrs['size']) {
267                        if ($attrs['image']) # ???? c'est quoi ? le mode ?
268                                $attrs['size'] = 'd'; # ??? default
269                        else
270                                $attrs['size'] = 'd'; #
271                }
272                if (in_array($meta['extension'], array('gif', 'png', 'jpg'))) {
273                        $a = image_stdsize($attrs['src'], $attrs['size']);
274                        $resize = true;
275                }
276        }
277
278        // Verifier d'abord si le parametre 'icon' force l'icon
279# todo : icone => icon
280        if ($attrs['icon']) {
281                $f = charger_fonction('vignette','inc');
282                $img = $f($meta['extension'], false);
283                if ($resize)
284                        $a = image_reduire($img, $attrs['largeur'], $attrs['hauteur']);
285                else
286                        $a = '<img src="'.$img.'" />';
287
288        }
289        // methode normale : reduire l'image si possible, sinon icon
290        else {
291                if (!$a) {
292                        $w = sinon($attrs['largeur'],500);
293                        $h = sinon($attrs['hauteur'],700);
294                        $a = vignette_automatique($meta['id_vignette'], $meta,
295                                '' /*url*/, $w, $h, null /* align */);
296                }
297        }
298        $image['logodocument'] = $a;
299
300
301        // experimental : DEST (TODO: parametre à mieux nommer ?)
302        // parametre |dest=800 pour reduire l'image LIEE a 800px max
303        if ($attrs['dest']) {
304                $tmp = image_reduire($meta['local'], $attrs['dest']);
305                if ($tmp = extraire_attribut($tmp, 'src'))
306                        $image['href'] = $tmp;
307        }
308
309        return $image;
310}
311
312
313
314
315# s t m d z b o
316function image_stdsize($img, $s) {
317        include_spip('inc/filtres_images');
318
319        # intercepter les URLs flickr pour choper les jolies reductions
320        if (preg_match(',^(http://farm.*.staticflickr.com/(\d+/[0-9a-z_]+?))(_[zbo])?\.jpg$,', $img, $r)) {
321                if (in_array($s, array('s', 't', 'm', 'z', 'b') )){
322                        $img = $r[1].'_'.$s.'.jpg';
323                        return '<img src="'.$img.'" />';
324                }
325                if (in_array($s, array('d'))) {
326                        $img = $r[1].'.jpg';
327                        return '<img src="'.$img.'" />';
328                }
329        }
330
331
332
333        if (!is_numeric($s)) {
334        switch($s) {
335                case 's':
336                case 'square':
337                        # la c'est dur
338                        $d = 75;
339                        $img = image_passe_partout($img, $d, $d);
340                        $img = image_recadre($img, $d, $d);
341                        break;
342                case 't':
343                case 'thumb':
344                case 'thumbnail':
345                        $a = 100;
346                        break;
347                case 'm':
348                case 'small':
349                        $a = 240;
350                        break;
351                case 'z':
352                case 'medium640':
353                        $a = 640;
354                        break;
355                case 'b':
356                case 'large':
357                        $a = 1024;
358                        break;
359                case 'o':
360                case 'original':
361                        $a = null;
362                        break;
363                case '-':
364                case '':
365                case 'd':
366                case 'default':
367                default:
368                        $a = 500;
369                        break;
370        }
371        }
372
373        if ($a)
374                $img = image_reduire($img, $a);
375        else if (is_numeric($s))
376                $img = image_reduire($img, $s);
377
378        return $img;
379}
380
381
382
383function ressource_extract($meta) {
384        /*
385
386        global $extracteur;
387
388        $extension = $meta['extension'];
389
390        include_spip('extract/'.$extension);
391        if (function_exists($lire = $extracteur[$extension])) {
392                $charset = 'iso-8859-1';
393                $contenu = $lire($meta['local'], $charset);
394                var_dump($lire, $contenu);
395        }
396        */
397
398        switch($meta['extension']) {
399                case 'html':
400                case 'doc':
401                case 'docx':
402                case 'rtf':
403                case 'odt':
404                        $conv = converthtml($meta['local'], $err);
405                        include_spip('fonctionsale');
406                        if (function_exists('sale')) {
407                                $conv = sale($conv);
408                        }
409                        break;
410                default:
411                        break;
412        }
413
414        return $conv;
415}
416
417/**
418* Multiple Curl Handlers
419* @author Jorge Hebrard ( jorge.hebrard@gmail.com )
420**/
421class curlNode{
422    static private $listenerList;
423    private $callback;
424    public function __construct($url){
425        $new =& self::$listenerList[];
426        $new['url'] = $url;
427        $this->callback =& $new;
428    }
429    /**
430    * Callbacks needs 3 parameters: $url, $html (data of the url), and $lag (execution time)
431    **/
432    public function addListener($callback){
433        $this->callback['callback'] = $callback;
434    }
435    /**
436    * curl_setopt() wrapper. Enjoy!
437    **/
438    public function setOpt($key,$value){
439        $this->callback['opt'][$key] = $value;
440    }
441    /**
442    * Request all the created curlNode objects, and invoke associated callbacks.
443    **/
444    static public function request(){
445   
446        //create the multiple cURL handle
447        $mh = curl_multi_init();
448       
449        $running=null;
450       
451        # Setup all curl handles
452        # Loop through each created curlNode object.
453        foreach(self::$listenerList as &$listener){
454            $url = $listener['url'];
455            $current =& $ch[];
456           
457            # Init curl and set default options.
458            # This can be improved by creating
459            $current = curl_init();
460
461            curl_setopt($current, CURLOPT_URL, $url);
462            # Since we don't want to display multiple pages in a single php file, do we?
463            curl_setopt($current, CURLOPT_HEADER, 0);
464            curl_setopt($current, CURLOPT_RETURNTRANSFER, 1);
465           
466            # Set defined options, set through curlNode->setOpt();
467            if (isset($listener['opt'])){
468                foreach($listener['opt'] as $key => $value){
469                    curl_setopt($current, $key, $value);
470                }
471            }
472           
473            curl_multi_add_handle($mh,$current);
474           
475            $listener['handle'] = $current;
476            $listener['start'] = microtime(1);
477        } unset($listener);
478
479        # Main loop execution
480        do {
481            # Exec until there's no more data in this iteration.
482            # This function has a bug, it
483            while(($execrun = curl_multi_exec($mh, $running)) == CURLM_CALL_MULTI_PERFORM);
484            if($execrun != CURLM_OK) break; # This should never happen. Optional line.
485           
486            # Get information about the handle that just finished the work.
487            while($done = curl_multi_info_read($mh)) {
488                # Call the associated listener
489                foreach(self::$listenerList as $listener){
490                    # Strict compare handles.
491                    if ($listener['handle'] === $done['handle']) {
492                        # Get content
493                        $html = curl_multi_getcontent($done['handle']);
494                        # Call the callback.
495                        call_user_func($listener['callback'],
496                        $listener['url'],
497                        $html,(microtime(1)-$listener['start']));
498                        # Remove unnecesary handle (optional, script works without it).
499                        curl_multi_remove_handle($mh, $done['handle']);
500                    }
501                }
502               
503            }
504            # Required, or else we would end up with a endless loop.
505            # Without it, even when the connections are over, this script keeps running.
506            if (!$running) break;
507           
508            # I don't know what these lines do, but they are required for the script to work.
509            while (($res = curl_multi_select($mh)) === 0);
510            if ($res === false) break; # Select error, should never happen.
511        } while (true);
512
513        # Finish out our script ;)
514        curl_multi_close($mh);
515   
516    }
517}
518
519function converthtml($f, $err) {
520        define('_CONVERT_URL', 'http://office.rezo.net/office/v1/?email=fil@rezo.net&key=1223649b375bb98e1b57141f96643cd47a3029c3');
521
522        $signature = md5_file($f);
523
524        // 1. a-t-on le fichier en local
525        $html = sous_repertoire(_DIR_TMP,'converthtml').$signature.'.html';
526        if (file_exists($html))
527                return spip_file_get_contents($html);
528
529        // 2. sinon le chercher sur le serveur office.rezo
530        if (!defined('_CONVERT_URL'))
531                return false;
532
533        $url = parametre_url(_CONVERT_URL, 'signature', $signature, '&');
534
535        include_spip('inc/queue');
536        queue_add_job('convert_html_fetch', 'convert_html_fetch('.$f.')', array($url, $f, $html), $file = 'inc/ressource', $no_duplicate = true, $time=0, $priority=0);
537        #convert_html_fetch($url, $f);
538
539        return '';
540}
541
542function convert_html_fetch($url, $f, $html=null) {
543        if (!$html) return;
544        include_spip('inc/distant');
545        if ($rep = recuperer_page($url)
546        AND $rep = json_decode($rep)
547        AND isset($rep->content)) {
548                ecrire_fichier($html, $rep->content);
549                return;
550        }
551       
552
553        // 3. si 404, l'envoyer au serveur
554        #include_spip('inc/queue');
555        #queue_add_job('convert_html_send', 'convert_html_send('.$f.')', array($url, $f), $file = 'inc/ressource', $no_duplicate = true, $time=0, $priority=0);
556        convert_html_send($url, $f);
557
558}
559
560function convert_html_send($url, $f) {
561        include_spip('inc/filtres');
562        spip_log('curl @'.$f.' '.$url.' ('.taille_en_octets(filesize($f)).')');
563        $data = array('file' => '@'.$f);
564        $ch = curl_init();
565        curl_setopt($ch, CURLOPT_VERBOSE, 1);
566        curl_setopt($ch, CURLOPT_URL, $url);
567        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
568        curl_setopt($ch, CURLOPT_POST, true);
569        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
570        $n = curl_exec($ch);
571        spip_log($n);
572        curl_close($ch);
573}
574
575
576function xconverthtml($f, &$err) {
577
578
579        $k = escapeshellarg($f);
580
581        exec("/usr/bin/textutil -convert html -stdout -noload -nostore $k", $ret, $err);
582
583        if ($err) {
584                spip_log($err);
585        } else {
586                $ret = join($ret, "\n");
587                // les notes de bas de page word sont parfois transformees en truc chelou
588                $ret = str_replace('<span class="Apple-converted-space"> </span>', '~', $ret);
589                return nettoyer_utf8($ret);
590        }
591}
592
593function nettoyer_utf8($t) {
594        if (!preg_match('!\S!u', $t))
595                $t = preg_replace_callback(',&#x([0-9a-f]+);,i', 'utf8_do', utf8_encode(utf8_decode($t)));
596        return $t;
597}
Note: See TracBrowser for help on using the repository browser.