[PLUGINS] +crayons et enluminures
[ptitvelo/web/www.git] / www / plugins / crayons / inc / crayons.php
1 <?php
2
3 if (!defined("_ECRIRE_INC_VERSION")) return;
4
5 define('_PREG_CRAYON', ',crayon\b[^<>\'"]+?\b((\w+)-(\w+)-(\w+(?:-\w+)*))\b,');
6
7 // Compatibilite pour 1.92 : on a besoin de sql_fetch et table_objet_sql
8 if ($GLOBALS['spip_version_code'] < '1.93' AND $f = charger_fonction('compat_crayons', 'inc'))
9 $f();
10
11 // Autoriser les crayons sur les tables non SPIP ?
12 // Par defaut : oui (pour les admins complets, si autoriser_defaut_dist()) ;
13 // mettre a false en cas de mutualisation par prefixe de table,
14 // sinon on ne peut pas garantir que les sites sont hermetiques
15 define('_CRAYONS_TABLES_EXTERNES', true);
16
17 // Autorisations non prevues par le core
18 include_spip('inc/autoriser');
19
20 include_spip('inc/crayons-json');
21
22
23 if (!function_exists('autoriser_meta_modifier_dist')) {
24 /**
25 * Autorisation d'éditer les configurations dans spip_meta
26 *
27 * Les admins complets OK pour certains champs,
28 * Sinon, il faut être webmestre
29 *
30 * @note
31 * Attention sur les SPIP < 11515 (avant 04/2008) inc/autoriser
32 * passe seulement intval($id) alors qu'ici la cle est une chaine...
33 *
34 * @param string $faire Action demandée
35 * @param string $type Type d'objet sur lequel appliquer l'action
36 * @param int $id Identifiant de l'objet
37 * @param array $qui Description de l'auteur demandant l'autorisation
38 * @param array $opt Options de cette autorisation
39 * @return bool true s'il a le droit, false sinon
40 **/
41 function autoriser_meta_modifier_dist($faire, $type, $id, $qui, $opt) {
42 // Certaines cles de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})
43 // $id = str_replace('__', '/', $id);
44 if (in_array("$id", array(
45 'nom_site', 'slogan_site', 'descriptif_site', 'email_webmaster'
46 )))
47 return autoriser('configurer', null, null, $qui);
48 else
49 return autoriser('webmestre', null, null, $qui);
50 }
51 }
52
53 // table spip_messages, la c'est tout simplement non (peut mieux faire,
54 // mais c'est a voir dans le core/organiseur ou dans autorite)
55 if (defined('_DIR_PLUGIN_ORGANISEUR'))
56 include_spip('organiseur_autoriser');
57 if (!function_exists('autoriser_message_modifier_dist')) {
58 function autoriser_message_modifier_dist($faire, $type, $id, $qui, $opt) {
59 return false;
60 }
61 }
62 //compat 192 documents
63 if ($GLOBALS['spip_version_code'] < '1.93'){
64 if (!function_exists('get_spip_doc')){
65 function get_spip_doc($fichier) {
66 // fichier distant
67 if (preg_match(',^\w+://,', $fichier))
68 return $fichier;
69
70 // gestion d'erreurs, fichier=''
71 if (!strlen($fichier))
72 return false;
73
74 // fichier normal
75 return (strpos($fichier, _DIR_IMG) === false)
76 ? _DIR_IMG . $fichier
77 : $fichier;
78 }
79 }
80 }
81
82 // Autoriser l'usage des crayons ?
83 function autoriser_crayonner_dist($faire, $type, $id, $qui, $opt) {
84 // Le type pouvant etre une table, verifier les autoriser('modifier')
85 // correspondant ; ils demandent le nom de l'objet: spip_articles => article
86 // ex: spip_articles => 'article'
87 $type = preg_replace(',^spip_(.*?)s?$,', '\1', $type);
88 if (strlen($GLOBALS['table_prefix']))
89 $type = preg_replace(',^'.$GLOBALS['table_prefix'].'_(.*?)s?$,', '\1', $type);
90
91 // Tables non SPIP ? Si elles sont interdites il faut regarder
92 // quelle table on appelle, et verifier si elle est "interne"
93 if (!_CRAYONS_TABLES_EXTERNES) {
94 include_spip('base/serial');
95 include_spip('base/auxiliaires');
96 include_spip('public/parametrer');
97 if (!isset($GLOBALS['tables_principales']['spip_'.table_objet($type)])
98 AND !isset($GLOBALS['tables_auxiliaires']['spip_'.table_objet($type)]))
99 return false;
100 }
101
102 // Traduire le modele en liste de champs
103 if (isset($opt['modele']))
104 $opt['champ'] = $opt['modele'];
105
106 // Pour un auteur, si le champ est statut ou email, signaler l'option
107 // ad hoc (cf. inc/autoriser)
108 if ($type == 'auteur'
109 AND in_array($opt['champ'], array('statut', 'email')))
110 $opt[$opt['champ']] = true;
111
112 return (
113 autoriser('modifier', $type, $id, $qui, $opt)
114 );
115 }
116
117 // Si un logo est demande, on renvoie la date dudit logo (permettra de gerer
118 // un "modifie par ailleurs" si la date a change, rien de plus)
119 function valeur_champ_logo($table, $id, $champ) {
120 $chercher_logo = charger_fonction('chercher_logo', 'inc');
121 $on = $chercher_logo($id, id_table_objet($table), 'on');
122 return $on ? filemtime($on[0]) : false;
123 }
124
125 // Idem : si un doc est demande, on renvoie la date du doc
126 function valeur_champ_document($table, $id, $champ) {
127 $s = spip_query("SELECT date FROM spip_documents WHERE id_document="._q($id));
128 if ($t = sql_fetch($s))
129 return $t['date'];
130 }
131
132 function valeur_champ_vignette($table, $id, $champ) {
133 $vignette = sql_getfetsel('id_vignette','spip_documents','id_document='.intval($id));
134 if(is_numeric($vignette) && ($vignette > 0)){
135 $date = sql_getfetsel('date','spip_documents','id_document='.intval($vignette));
136 }
137 return $date ? $date : false;
138 }
139 // cette fonction de revision recoit le fichier upload a passer en logo
140 // en reference : le nom du widget, pour aller chercher d'autres donnees
141 // (ex: supprimer)
142 function logo_revision($id, $file, $type, $ref) {
143
144 $chercher_logo = charger_fonction('chercher_logo', 'inc');
145 $_id_objet = id_table_objet($type);
146
147 // Chargement d'un nouveau logo ?
148 if ($file['logo']) {
149 define('FILE_UPLOAD', true); // message pour crayons_json_export :(
150
151 // supprimer l'ancien logo
152 $on = $chercher_logo($id, $_id_objet, 'on');
153 if ($on) @unlink($on[0]);
154
155 // ajouter le nouveau
156 include_spip('action/iconifier');
157 action_spip_image_ajouter_dist(
158 type_du_logo($_id_objet).'on'.$id, false, false
159 ); // beurk
160 }
161
162 else
163
164 // Suppression du logo ?
165 if ($wid = array_pop($ref)
166 AND $_POST['content_'.$wid.'_logo_supprimer'] == 'on') {
167 if ($on = $chercher_logo($id, $_id_objet, 'on'))
168 @unlink($on[0]);
169 }
170
171
172 // Reduire le logo ?
173 if (is_array($cfg = @unserialize($GLOBALS['meta']['crayons']))
174 AND $max = intval($cfg['reduire_logo'])) {
175 $on = $chercher_logo($id, $_id_objet, 'on');
176 include_spip('inc/filtres');
177 @copy($on[0], $temp = _DIR_VAR.'tmp'.rand(0,999).'.'.$on[3]);
178 $img1 = filtrer('image_reduire', $temp, $max);
179 $img2 = preg_replace(',[?].*,', '', extraire_attribut($img1, 'src'));
180 if (@file_exists($img2)
181 AND $img2 != $temp) {
182 @unlink($on[0]);
183 $dest = $on[1].$on[2].'.'
184 .preg_replace(',^.*\.(gif|jpg|png)$,', '\1', $img2);
185 @rename($img2,$dest);
186 }
187 @unlink($temp);
188 }
189
190 return true;
191 }
192
193
194 // cette fonction de revision recoit le fichier upload a passer en document
195 function document_fichier_revision($id, $data, $type, $ref) {
196
197 $s = spip_query("SELECT * FROM spip_documents WHERE id_document="._q($id));
198 if (!$t = sql_fetch($s))
199 return false;
200
201 /*
202 // Envoi d'une URL de document distant ?
203 // TODO: verifier l'extension distante, sinon tout explose
204 if ($data['fichier']
205 AND preg_match(',^(https?|ftp)://.+,', $data['fichier'])) {
206 include_spip('inc/modifier');
207 modifier_contenu('document', $id,
208 array('champs' => array('fichier', 'distant')),
209 array('fichier' => $data['fichier'], 'distant' => 'oui')
210 );
211 return true;
212 }
213 else
214 */
215
216 // Chargement d'un nouveau doc ?
217 if ($data['document']) {
218
219 $ajouter_documents = charger_fonction('ajouter_documents', 'inc');
220 $arg = $data['document'];
221 check_upload_error($arg['error']);
222 $x = $ajouter_documents($arg['tmp_name'], $arg['name'],
223 'article', 0, 'document', null, $actifs);
224
225 // $actifs contient l'id_document nouvellement cree
226 // on recopie les donnees interessantes dans l'ancien
227 $extension=", extension ";
228 //compat 192
229 if ($GLOBALS['spip_version_code'] < '1.93')
230 $extension="";
231
232 if ($id_new = array_pop($actifs)
233 AND $s = spip_query("SELECT fichier, taille, largeur, hauteur $extension, distant FROM spip_documents
234 WHERE id_document="._q($id_new))
235 AND $new = sql_fetch($s)) {
236 define('FILE_UPLOAD', true); // message pour crayons_json_export :(
237
238 // Une vignette doit rester une image
239 if ($t['mode'] == 'vignette'
240 AND !in_array($new['extension'], array('jpg', 'gif', 'png')))
241 return false;
242
243 // Maintenant on est bon, on recopie les nouvelles donnees
244 // dans l'ancienne ligne spip_documents
245 include_spip('inc/modifier');
246 modifier_contenu('document', $id,
247 # 'champs' inutile a partir de SPIP 11348
248 array('champs' => array_keys($new)),
249 $new);
250
251 // supprimer l'ancien document (sauf s'il etait distant)
252 if ($t['distant'] != 'oui'
253 AND file_exists(get_spip_doc($t['fichier'])))
254 supprimer_fichier(get_spip_doc($t['fichier']));
255
256 // Effacer la ligne temporaire de spip_document
257 spip_query("DELETE FROM spip_documents WHERE id_document="._q($id_new));
258
259 // oublier id_document temporaire (ca marche chez moi, sinon bof)
260 spip_query("ALTER TABLE spip_documents AUTO_INCREMENT="._q($id_new));
261
262 return true;
263 }
264 }
265
266 }
267
268 // cette fonction de revision soit supprime la vignette d'un document,
269 // soit recoit le fichier upload a passer ou remplacer la vignette du document
270 function vignette_revision($id, $data, $type, $ref) {
271 $s = sql_fetsel("*","spip_documents","id_document=".intval($id));
272 if (!is_array($s))
273 return false;
274
275 include_spip('inc/modifier');
276 include_spip('inc/documents');
277 // Chargement d'un nouveau doc ?
278 if ($data['vignette']) {
279 define('FILE_UPLOAD', true);
280 if(is_numeric($s['id_vignette']) && ($s['id_vignette']>0)){
281 spip_log('suppression de la vignette');
282 // Suppression du document
283 $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));
284 if (@file_exists($f = get_spip_doc($vignette))) {
285 spip_log("efface $f");
286 supprimer_fichier($f);
287 }
288 sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));
289 sql_delete('spip_documents_liens', 'id_document='.intval($s['id_vignette']));
290
291 pipeline('post_edition',
292 array(
293 'args' => array(
294 'operation' => 'supprimer_document',
295 'table' => 'spip_documents',
296 'id_objet' => $s['id_vignette']
297 ),
298 'data' => null
299 )
300 );
301
302 // On remet l'id_vignette a 0
303 revision_document($s['id_document'], array('id_vignette'=>0));
304 }
305 // Ajout du document comme vignette
306 $ajouter_documents = charger_fonction('ajouter_documents', 'inc');
307 $arg = $data['vignette'];
308 check_upload_error($arg['error']);
309 $x = $ajouter_documents($arg['tmp_name'], $arg['name'],'','', 'vignette', $id, $actifs);
310 }else
311 // Suppression de la vignette ?
312 if ($wid = array_pop($ref)
313 AND $_POST['content_'.$wid.'_vignette_supprimer'] == 'on') {
314 if(is_numeric($s['id_vignette']) && ($s['id_vignette']>0)){
315 // Suppression du document
316 $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));
317 if (@file_exists($f = get_spip_doc($vignette))) {
318 spip_log("efface $f");
319 supprimer_fichier($f);
320 }
321 sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));
322 sql_delete('spip_documents_liens', 'id_document='.intval($s['id_vignette']));
323
324 pipeline('post_edition',
325 array(
326 'args' => array(
327 'operation' => 'supprimer_document',
328 'table' => 'spip_documents',
329 'id_objet' => $s['id_vignette']
330 ),
331 'data' => null
332 )
333 );
334
335 // On remet l'id_vignette a 0
336 revision_document($s['id_document'], array('id_vignette'=>0));
337 }
338 }
339 return true;
340 }
341
342 function colonne_table($type, $col) {
343 list($distant,$table) = distant_table($type);
344 $nom_table = '';
345 if (!(($tabref = &crayons_get_table($table, $nom_table)) && ($brut = $tabref['field'][$col]))) {
346 return false;
347 }
348 $ana = explode(' ', $brut);
349 $sta = 0;
350 $sep = '';
351 $ret = array('brut' => $brut,
352 'type' => '', 'notnull' => false, 'long' => 0, 'def' => '');
353 foreach ($ana as $mot) {
354 switch ($sta) {
355 case 0: $ret['type'] = ($mot = strtolower($mot));
356 case 1: if ($mot[strlen($mot) - 1] == ')') {
357 $pos = strpos($mot, '(');
358 $ret['type'] = strtolower(substr($mot, 0, $pos++));
359 $vir = explode(',', substr($mot, $pos, -1));
360 if ($ret['type'] == 'enum') {
361 $ret['enum'] = $vir;
362 } elseif (count($vir) > 1) {
363 $ret['long'] = $vir;
364 } else {
365 $ret['long'] = $vir[0];
366 }
367 $sta = 1;
368 continue;
369 }
370 if (!$sta) {
371 $sta = 1;
372 continue;
373 }
374 case 2: switch (strtolower($mot)) {
375 case 'not':
376 $sta = 3;
377 continue;
378 case 'default':
379 $sta = 4;
380 continue;
381 }
382 continue;
383 case 3: $ret['notnull'] = strtolower($mot) == 'null';
384 $sta = 2;
385 continue;
386 case 4: $df1 = strpos('"\'', $mot[0]) !== false? $mot[0] : '';
387 $sta = 5;
388 case 5: $ret['def'] .= $sep . $mot;
389 if (!$df1) {
390 $sta = 2;
391 continue;
392 }
393 if ($df1 == $mot[strlen($mot) - 1]) {
394 $ret['def'] = substr($ret['def'], 1, -1);
395 $sta = 2;
396 }
397 $sep = ' ';
398 continue;
399 }
400 }
401 return $ret;
402 }
403 // var_dump(colonne_table('forum', 'id_syndic')); die();
404
405 function table_where($type, $id, $where_en_tableau = false)
406 {
407 list($distant,$table) = distant_table($type);
408 $nom_table = '';
409 if (!(($tabref = &crayons_get_table($type, $nom_table))
410 && ($tabid = explode(',', $tabref['key']['PRIMARY KEY'])))) {
411 spip_log('crayons: table ' . $table . ' inconnue');
412 return array(false, false);
413 }
414 if (is_scalar($id)) {
415 $id = explode('-', $id);
416 }
417 // sortie tableau pour sql_updateq
418 if ($where_en_tableau) {
419 $where = array();
420 foreach ($id as $idcol => $idval) {
421 $where[] = '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . sql_quote($idval);
422 }
423 // sinon sortie texte pour sql_query
424 } else {
425 $where = $and = '';
426 foreach ($id as $idcol => $idval) {
427 $where .= $and . '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . _q($idval);
428 $and = ' AND ';
429 }
430 }
431 return array($nom_table, $where);
432 }
433 // var_dump(colonne_table('forum', 'id_syndic')); die();
434
435 function valeur_colonne_table_dist($type, $col, $id) {
436 list($distant,$table) = distant_table($type);
437 list($nom_table, $where) = table_where($type, $id);
438
439 if (!$nom_table)
440 return false;
441
442 $r = array();
443
444 // valeurs non SQL
445 foreach ($col as $champ) {
446 if (function_exists($f = 'valeur_champ_'.$table.'_'.$champ) OR function_exists($f = 'valeur_champ_'.$champ)) {
447 $r[$champ] = $f($table, $id, $champ);
448 $col = array_diff($col, array($champ));
449 }
450 }
451
452 // valeurs SQL
453 if (count($col)
454 AND $s = spip_query(
455 'SELECT `' . implode($col, '`, `') .
456 '` FROM ' . $nom_table . ' WHERE ' . $where, $distant)
457 AND $t = sql_fetch($s))
458 $r = array_merge($r, $t);
459
460 return $r;
461 }
462
463 /**
464 * Extrait la valeur d'une ou plusieurs colonnes d'une table
465 *
466 * @param string $table
467 * Type d'objet de la table (article)
468 * @param string|array $col
469 * Nom de la ou des colonnes (ps)
470 * @param string $id
471 * Identifiant de l'objet
472 * @return array
473 * Couples Nom de la colonne => Contenu de la colonne
474 **/
475 function valeur_colonne_table($table, $col, $id) {
476 if (!is_array($col))
477 $col = array($col);
478
479 if (function_exists($f = $table.'_valeur_colonne_table_dist')
480 OR function_exists($f = $table.'_valeur_colonne_table')
481 OR $f = 'valeur_colonne_table_dist')
482 return $f($table, $col, $id);
483 }
484
485 /**
486 * Extrait la valeur d'une configuration en meta
487 *
488 * Pour ces données, il n'y a toujours qu'une colonne (valeur),
489 * mais on gère l'enregistrement et la lecture via lire_config ou ecrire_config
490 * dès que l'on demande des sous parties d'une configuration.
491 *
492 * On ne retourne alors ici dans 'valeur' que la sous-partie demandée si
493 * c'est le cas.
494 *
495 * @param string $table
496 * Nom de la table (meta)
497 * @param array $col
498 * Nom des colonnes (valeur)
499 * @param string $id
500 * Nom ou clé de configuration (descriptif_site ou demo__truc pour demo/truc)
501 * @return array
502 * Couple valeur => Contenu de la configuration
503 **/
504 function meta_valeur_colonne_table_dist($table, $col, $id) {
505 // Certaines clés de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})
506 $id = str_replace('__', '/', $id);
507
508 // Éviter de planter les vieux SPIP
509 if (false === strpos($id, '/')) {
510 $config = isset($GLOBALS['meta'][$id]) ? $GLOBALS['meta'][$id] : '';
511 // SPIP 3 ou Bonux 2 ou CFG
512 } else {
513 include_spip('inc/config');
514 $config = lire_config($id, '');
515 }
516 return array('valeur' => $config);
517 }
518
519
520 function return_log($var) {
521 die(crayons_json_export(array('$erreur'=> var_export($var,true))));
522 }
523
524 function _U($texte, $params=array())
525 {
526 include_spip('inc/charsets');
527 return unicode2charset(html2unicode(_T($texte, $params)));
528 }
529
530 // wdgcfg = widget config :-)
531 function wdgcfg() {
532 $php = function_exists('crayons_config') ? crayons_config() : array();
533 include_spip('inc/meta');
534 lire_metas();
535 global $meta;
536 $metacrayons = empty($meta['crayons']) ? array() : unserialize($meta['crayons']);
537 $wdgcfg = array();
538 foreach (array(
539 'msgNoChange' => false,
540 'msgAbandon' => false, /* etait: true */
541 'filet' => false,
542 'yellow_fade' => false,
543 'clickhide' => false /* etait: true */
544 )
545 as $cfgi => $def) {
546 $wdgcfg[$cfgi] = isset($php[$cfgi]) ? $php[$cfgi] :
547 isset($metacrayons[$cfgi]) ? $metacrayons[$cfgi] : $def;
548 }
549 return $wdgcfg;
550 }
551
552 function &crayons_get_table($type, &$nom_table) {
553 list($distant,$table) = distant_table($type);
554 static $return = array();
555 static $noms = array();
556 if (!isset($return[$table])) {
557 $try = array(table_objet_sql($table), 'spip_'.table_objet($table), 'spip_' . $table . 's', $table . 's', 'spip_' . $table, $table);
558
559 // premiere possibilite (à partir de 1.9.3) : regarder directement la base
560 if (function_exists('sql_showtable')) {
561 foreach ($try as $nom) {
562 if ($q = sql_showtable($nom , !$distant , $distant)) {
563 $noms[$table] = $nom;
564 $return[$table] = $q;
565 break;
566 }
567 }
568 }
569
570 // seconde, une heuristique 1.9.2
571 if (!isset($return[$table])) {
572 include_spip('base/serial');
573 include_spip('base/auxiliaires');
574 include_spip('public/parametrer');
575 foreach(array('tables_principales', 'tables_auxiliaires') as $categ)
576 {
577 foreach ($try as $nom) {
578 if (isset($GLOBALS[$categ][$nom])) {
579 $noms[$table] = $nom;
580 $return[$table] = & $GLOBALS[$categ][$nom];
581 break 2;
582 }
583 }
584 }
585 }
586
587 }
588
589 $nom_table = $noms[$table];
590 return $return[$table];
591 }
592
593 function distant_table($type) {
594 //separation $type en $distant $table
595 //separateur double underscore "__"
596 strstr($type,'__')? list($distant,$table) = explode('__',$type) : list($distant,$table) = array(False,$type);
597 return array($distant,$table);
598 }
599 ?>