source: spip-zone/_plugins_/projection/inc/projection.php @ 58785

Last change on this file since 58785 was 58785, checked in by fil@…, 9 years ago

on commence a dereferencer les liens internes et les modeles img doc et emb

File size: 13.4 KB
Line 
1<?php
2
3# la projection d'un objet c'est le contenu de cet objet au format
4# HTML pour affichage plaisant mais contenant toutes les données
5# pour permettre une recopie
6
7# dans quel répertoire on fait ça… local/projection/
8
9
10function projection($objet, $id_objet) {
11        spip_log("projection $objet:$id_objet", "projection");
12        spip_log($_SERVER['REQUEST_URI'], 'projection'); # verifier qu'on s'execute bien sur le cron
13
14        if ($projection = charger_fonction('projection_'.$objet, 'inc', true)) {
15        spip_log("a $projection", 'projection');
16                $projection($objet, $id_objet);
17        } else {
18                projection_dist($objet, $id_objet);
19        }
20
21        spip_log("a $projection", 'projection');
22}
23
24
25function projection_dist($objet, $id_objet) {
26        spip_log("Je ne sais pas faire la projection de $objet:$id_objet", "projection");
27
28}
29
30function inc_projection_articles_dist($objet, $id_objet) {
31        if (!$dir = projection_dir($objet, $id_objet)) {
32                spip_log('echec', 'projection');
33                return false;
34        }
35
36        # contenu à enregistrer
37        include_spip('abstract_sql');
38        $obj = sql_fetsel('*', table_objet($objet), id_table_objet($objet).'='.$id_objet);
39        # todo : retirer les champs inutiles, ajouter les jointures (auteurs, mots, documents)
40
41        # fichier de projection
42        $type = objet_type($objet); # 'article'
43        $f = $dir.$type.'-'.$id_objet.'.yaml';
44        spip_log($f, 'projection');
45
46        # recuperer la representation complete de l'objet
47        $representation = projection_representation($obj, $type);
48
49        # on l'écrit et zou
50        return ecrire_fichier($f, $representation);
51}
52
53
54
55function projection_dir($objet, $id_objet) {
56        if ($p = sous_repertoire(_DIR_VAR, 'projection')
57        AND $p = sous_repertoire($p,$objet))  # on pourrait organiser par rubrique
58                return $p;
59}
60
61# à noter : json_encode est temporaire, on veut un vrai format
62# avec de belles propriétés
63function projection_representation($obj, $type) {
64        include_spip('inc/yaml');
65
66        // fallback json si yaml absent
67        if (!function_exists('yaml_encode'))
68                return json_encode($obj);
69
70        // eliminer les champs vides ou null ou ayant une valeur par defaut
71        $data = array_filter($obj);
72        if ($data['date_redac'] == '0000-00-00 00:00:00')
73                unset($data['date_redac']);
74        if ($data['statut'] == 'publie')
75                unset($data['statut']);
76
77        // eliminer les champs inutiles
78        foreach (explode(' ',
79        'id_article id_rubrique id_secteur export date_modif lang langue_choisie accepter_forum maj'
80        ) as $i)
81                unset($data[$i]);
82
83        //
84        // ajouter les jointures
85        //
86       
87        # authors
88        if (count($auteurs = sql_allfetsel('nom, bio', 'spip_auteurs a left join spip_auteurs_articles b on a.id_auteur=b.id_auteur', 'b.id_article='.$obj['id_article']))) {
89                $data['authors'] = array_filter(array_map('projection_auteur', $auteurs));
90                if (count($data['authors']) == 1)
91                        $data['authors'] = array_pop($data['authors']);
92        } else
93                $data['error'] .= sql_error();
94
95        # tags
96        if (count($mots = sql_allfetsel('titre, descriptif, texte', 'spip_mots a left join spip_mots_articles b on a.id_mot=b.id_mot', 'b.id_article='.$obj['id_article']))) {
97                $data['tags'] = array_filter(array_map('projection_mot', $mots));
98        } else
99                $data['error'] .= sql_error();
100
101        # documents
102        if (count($docs = sql_allfetsel('titre, descriptif, fichier, a.id_document, vu, mode', 'spip_documents a left join spip_documents_liens b on a.id_document=b.id_document', "b.objet='$type' AND b.id_objet=".$obj['id_article']))) {
103                $data['docs'] = array_filter(array_map('projection_doc', $docs));
104        } else
105                $data['error'] .= sql_error();
106
107        # category
108        if ($rub = sql_allfetsel('titre, descriptif, texte', 'spip_rubriques', "id_rubrique=".$obj['id_rubrique'])) {
109                $data['category'] = projection_rubrique($rub[0]);
110        } else
111                $data['error'] .= sql_error();
112
113
114        ## le texte, c'est l'essentiel mais il ne figure pas dans l'entete
115        unset($data['texte']);
116        ## le chapo et le PS sont du texte,
117        ## ils peuvent contenir des raccourcis <docX>
118        foreach(explode(' ', 'chapo ps') as $i)
119                if (isset($data[$i]))
120                        $data[$i] = projection_texte($data[$i], $data);
121
122        #
123        # Envoyer la representation YAML + content
124        #
125        $rep = "##### projection de l'article $obj[id_article]\n"
126                . "--- # metadata\n"
127                . yaml_encode(array_filter($data))
128                . "--- # content\n";
129
130        $rep .= projection_texte($obj['texte'], $data);
131
132        return $rep;
133}
134
135
136function projection_auteur($auteur) {
137        $auteur = array_filter($auteur);
138        if (count($auteur) == 1
139        AND isset($auteur['nom']))
140                $auteur = $auteur['nom'];
141        return $auteur;
142}
143function projection_mot($mot) {
144        $mot = array_filter($mot);
145        if (count($mot) == 1
146        AND isset($mot['titre']))
147                $mot = $mot['titre'];
148        return $mot;
149}
150function projection_doc($doc) {
151        $doc = array_filter($doc);
152        $conf['url_de_base'] = 'http://rezo.pagekite.net/spip2.1/';
153
154        #'<doc http://…………… copy|nocopy>
155        # conf : copy / nocopy / default: copy|nocopy
156
157        // URL absolue de maniere a pouvoir exporter
158        if (isset($doc['fichier'])
159        AND !preg_match(',://,', $fichier))
160                $doc['fichier'] = url_absolue(_DIR_IMG.$doc['fichier'], $conf['url_de_base']);
161
162        if ($doc['vu'] == 'non') {
163                unset($doc['id_document']);
164                if ($doc['mode'] == 'image')
165                        $doc = array();
166        }
167        unset($doc['vu']);
168        if ($doc['mode'] == 'document') unset($doc['mode']);
169
170        if (count($doc) == 1
171        AND isset($doc['fichier']))
172                $doc = $doc['fichier'];
173        return $doc;
174}
175function projection_rubrique($rub) {
176        $rub = array_filter($rub);
177        if (count($rub) == 1
178        AND isset($rub['titre']))
179                $rub = $rub['titre'];
180        return $rub;
181}
182
183# on va nettoyer un peu le texte notamment les liens !
184# mais c'est très difficile car dn SPIP tout est fait
185# pour exporter du HTML
186## le code ci-dessous casse pas mal de choses dans le texte
187function projection_texte($txt, &$data) {
188        include_spip('inc/texte');
189        $txt = echappe_html($txt, 'P', true);
190        #$txt = expanser_liens($txt /*,$connect */);
191
192        $txt = projection_dereferencer($txt, &$data);
193
194#       $txt = iconv_wordwrap($txt, 80);
195        $txt = echappe_retour($txt, 'P');
196        return $txt;
197}
198
199## dereferencer les liens et modeles
200function projection_dereferencer($texte, $data) {
201        $texte = projection_dereferencer_liens($texte, $data);
202        $texte = projection_dereferencer_modeles($texte, $data);
203        return $texte;
204}
205
206// cf. http://doc.spip.org/@traiter_modeles
207function projection_dereferencer_modeles($texte, &$data, $liens=null) {
208
209        // detecter les modeles (rapide)
210        if (strpos($texte,"<")!==false AND
211          preg_match_all('/<[a-z_-]{3,}\s*[0-9|]+/iS', $texte, $matches, PREG_SET_ORDER)) {
212                foreach ($matches as $match) {
213                        // Recuperer l'appel complet (y compris un eventuel lien)
214                        $a = strpos($texte,$match[0]);
215                        preg_match(_RACCOURCI_MODELE_DEBUT,
216                        substr($texte, $a), $regs);
217                        $regs[]=""; // s'assurer qu'il y a toujours un 5e arg, eventuellement vide
218                        list(,$mod, $type, $id, $params, $fin) = $regs;
219                        if ($fin AND
220                        preg_match('/<a\s[^<>]*>\s*$/i',
221                                        substr($texte, 0, $a), $r)) {
222                                $lien = array(
223                                        'href' => extraire_attribut($r[0],'href'),
224                                        'class' => extraire_attribut($r[0],'class'),
225                                        'mime' => extraire_attribut($r[0],'type')
226                                );
227                                $n = strlen($r[0]);
228                                $a -= $n;
229                                $cherche = $n + strlen($regs[0]);
230                        } else {
231                                $lien = false;
232                                $cherche = strlen($mod);
233                        }
234
235/*
236                                // si un tableau de liens a ete passe, reinjecter le contenu d'origine
237                                // dans les parametres, plutot que les liens echappes
238                                if (!is_null($liens))
239                                        $params = str_replace($liens[0], $liens[1], $params);
240*/
241
242                          $modele = projection_dereferencer_modele($regs[0], $type, $id, $params, $lien, $connect);
243
244/*
245                                // en cas d'echec,
246                                // si l'objet demande a une url,
247                                // creer un petit encadre vers elle
248                                if ($modele === false) {
249                                        if (!$lien)
250                                                $lien = traiter_lien_implicite("$type$id", '', 'tout', $connect);
251                                        if ($lien)
252                                                $modele = '<a href="'
253                                                  .$lien['url']
254                                                  .'" class="spip_modele'
255                                                  . '">'
256                                                  .sinon($lien['titre'], _T('ecrire:info_sans_titre'))
257                                                  ."</a>";
258                                        else {
259                                                $modele = "";
260                                                if (test_espace_prive()) {
261                                                        $modele = entites_html(substr($texte,$a,$cherche));
262                                                        if (!is_null($liens))
263                                                                $modele = "<pre>".str_replace($liens[0], $liens[1], $modele)."</pre>";
264                                                }
265                                        }
266                                }
267*/
268
269                                // le remplacer dans le texte
270                                if ($modele !== false) {
271                                        #$modele = protege_js_modeles($modele);
272                                        $rempl = code_echappement($modele, 'P');
273                                        $texte = substr($texte, 0, $a)
274                                                . $rempl
275                                                . substr($texte, $a+$cherche);
276                                }
277                        }
278                }
279
280        return $texte;
281}
282
283function projection_dereferencer_modele($appel, $type, $id, $params, $lien, $connect) {
284#       $a = func_get_args();
285#       return var_export($a, true);
286        switch($type) {
287                case 'img':
288                case 'doc':
289                case 'emb':
290                        if (is_numeric($id) AND $id>0) {
291                                $url = projection_doc($doc = sql_fetsel('fichier', 'spip_documents', 'id_document='.$id));
292                                $appel = preg_replace("/$id/", "| href=".$url." ", $appel, 1);
293                                # <media|href=xxxxxx|small> ?
294                        }
295                        break;
296        }
297
298        return $appel;
299}
300
301// cf. http://doc.spip.org/@expanser_liens
302define('_RACCOURCI_LIEN', "/\[([^][]*?([[]\w*[]][^][]*)*)->(>?)([^]]*)\]/msS");
303function projection_dereferencer_liens($texte, &$data) {
304        $sources = $inserts = $regs = array();
305        if (preg_match_all(_RACCOURCI_LIEN, $texte, $regs, PREG_SET_ORDER)) {
306                $lien = 'projection_lien'; #charger_fonction('lien', 'inc');
307                foreach ($regs as $k => $reg) {
308
309                        $inserts[$k] = '@@SPIP_ECHAPPE_LIEN_' . $k . '@@';
310                        $sources[$k] = $reg[0];
311                        $texte = str_replace($sources[$k], $inserts[$k], $texte);
312
313                        list($titre, $bulle, $hlang) = traiter_raccourci_lien_atts($reg[1]);
314                        $r = $reg[count($reg)-1];
315                        // la mise en lien automatique est passee par la a tort !
316                        // corrigeons pour eviter d'avoir un <a...> dans un href...
317                        if (strncmp($r,'<a',2)==0){
318                                $href = extraire_attribut($r, 'href');
319                                // remplacons dans la source qui peut etre reinjectee dans les arguments
320                                // d'un modele
321                                $sources[$k] = str_replace($r,$href,$sources[$k]);
322                                // et prenons le href comme la vraie url a linker
323                                $r = $href;
324                        }
325                        $regs[$k] = $lien($reg, $r, $titre, '', $bulle, $hlang, '', $connect);
326                }
327        }
328
329        // on passe a traiter_modeles la liste des liens reperes pour lui permettre
330        // de remettre le texte d'origine dans les parametres du modele
331#       $texte = traiter_modeles($texte, false, false, $connect, array($inserts, $sources));
332#       $texte = corriger_typo($texte);
333        $texte = str_replace($inserts, $regs, $texte);
334        return $texte;
335}
336
337function projection_lien($reg, $lien, $texte='', $class='', $title='', $hlang='', $rel='', $connect='') {
338        if ($match = typer_raccourci($lien)) { 
339                @list($type,,$id,,$args,,$ancre) = $match;
340
341                // Si une langue est demandee sur un raccourci d'article, chercher
342                // la traduction ;
343                // - [{en}->art2] => traduction anglaise de l'article 2, sinon art 2
344                // - [{}->art2] => traduction en langue courante de l'art 2, sinon art 2
345                if ($hlang
346                AND $type == 'article'
347                AND $id_trad = sql_getfetsel('id_trad', 'spip_articles', "id_article=$id")
348                AND $id_dest = sql_getfetsel('id_article', 'spip_articles',
349                        "id_trad=$id_trad  AND statut<>'refuse' AND lang=" . sql_quote($hlang))
350                )
351                        $id = $id_dest;
352
353                # (article, 2) => URL publique de l'article 2
354                $url = generer_url_entite_absolue($id, $type, $args, $ancre, $connect);
355
356                # si le texte est vide aller chercher le titre
357                $lien = calculer_url("$type$id", $texte, 'tout', $connect);
358
359                $titre = strlen($reg[1]) ? $reg[1] : $lien['titre'];
360
361                return "[$titre->$url]";
362        }
363
364        return $reg[0];
365}
366
367## optionnellement, wordwrap (ne vaut pas un sentencewrap)
368## http://fr2.php.net/manual/fr/function.wordwrap.php#106088
369/**
370 * Word wrap
371 *
372 * @param  string  $string
373 * @param  integer $width
374 * @param  string  $break
375 * @param  boolean $cut
376 * @param  string  $charset
377 * @return string
378 */
379function iconv_wordwrap($string, $width = 75, $break = "\n", $cut = false, $charset = 'utf-8')
380{
381    $stringWidth = iconv_strlen($string, $charset);
382    $breakWidth  = iconv_strlen($break, $charset);
383
384    if (strlen($string) === 0) {
385        return '';
386    } elseif ($breakWidth === null) {
387        throw new Zend_Text_Exception('Break string cannot be empty');
388    } elseif ($width === 0 && $cut) {
389        throw new Zend_Text_Exception('Can\'t force cut when width is zero');
390    }
391
392    $result    = '';
393    $lastStart = $lastSpace = 0;
394
395    for ($current = 0; $current < $stringWidth; $current++) {
396        $char = iconv_substr($string, $current, 1, $charset);
397
398        if ($breakWidth === 1) {
399            $possibleBreak = $char;
400        } else {
401            $possibleBreak = iconv_substr($string, $current, $breakWidth, $charset);
402        }
403
404        if ($possibleBreak === $break) {
405            $result    .= iconv_substr($string, $lastStart, $current - $lastStart + $breakWidth, $charset);
406            $current   += $breakWidth - 1;
407            $lastStart  = $lastSpace = $current + 1;
408        } elseif ($char === ' ') {
409            if ($current - $lastStart >= $width) {
410                $result    .= iconv_substr($string, $lastStart, $current - $lastStart, $charset) . $break;
411                $lastStart  = $current + 1;
412            }
413
414            $lastSpace = $current;
415        } elseif ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
416            $result    .= iconv_substr($string, $lastStart, $current - $lastStart, $charset) . $break;
417            $lastStart  = $lastSpace = $current;
418        } elseif ($current - $lastStart >= $width && $lastStart < $lastSpace) {
419            $result    .= iconv_substr($string, $lastStart, $lastSpace - $lastStart, $charset) . $break;
420            $lastStart  = $lastSpace = $lastSpace + 1;
421        }
422    }
423
424    if ($lastStart !== $current) {
425        $result .= iconv_substr($string, $lastStart, $current - $lastStart, $charset);
426    }
427
428    return $result;
429}
430
431
Note: See TracBrowser for help on using the repository browser.