5 * (c) Fil, toggg 2006-2013
9 if (!defined('_ECRIRE_INC_VERSION')) {
13 define('_PREG_CRAYON', ',crayon\b[^<>\'"]+?\b((\w+)-(\w+)-(\w+(?:-\w+)*))\b,');
15 // Compatibilite pour 1.92 : on a besoin de sql_fetch et table_objet_sql
16 if ($GLOBALS['spip_version_code'] < '1.93' and $f = charger_fonction('compat_crayons', 'inc')) {
20 // Autoriser les crayons sur les tables non SPIP ?
21 // Par defaut : oui (pour les admins complets, si autoriser_defaut_dist()) ;
22 // mettre a false en cas de mutualisation par prefixe de table,
23 // sinon on ne peut pas garantir que les sites sont hermetiques
24 if (!defined('_CRAYONS_TABLES_EXTERNES')) {
25 define('_CRAYONS_TABLES_EXTERNES', true);
28 // Autorisations non prevues par le core
29 include_spip('inc/autoriser');
31 include_spip('inc/crayons-json');
33 if (!function_exists('autoriser_meta_modifier_dist')) {
35 * Autorisation d'éditer les configurations dans spip_meta
37 * Les admins complets OK pour certains champs,
38 * Sinon, il faut être webmestre
41 * Attention sur les SPIP < 11515 (avant 04/2008) inc/autoriser
42 * passe seulement intval($id) alors qu'ici la cle est une chaine...
44 * @param string $faire Action demandée
45 * @param string $type Type d'objet sur lequel appliquer l'action
46 * @param int $id Identifiant de l'objet
47 * @param array $qui Description de l'auteur demandant l'autorisation
48 * @param array $opt Options de cette autorisation
49 * @return bool true s'il a le droit, false sinon
51 function autoriser_meta_modifier_dist($faire, $type, $id, $qui, $opt) {
52 // Certaines cles de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})
53 // $id = str_replace('__', '/', $id);
54 if (in_array($id, array('nom_site', 'slogan_site', 'descriptif_site', 'email_webmaster'))) {
55 return autoriser('configurer', null, null, $qui);
57 return autoriser('webmestre', null, null, $qui);
62 // table spip_messages, la c'est tout simplement non (peut mieux faire,
63 // mais c'est a voir dans le core/organiseur ou dans autorite)
64 if (defined('_DIR_PLUGIN_ORGANISEUR')) {
65 include_spip('organiseur_autoriser');
68 if (!function_exists('autoriser_message_modifier_dist')) {
69 function autoriser_message_modifier_dist($faire, $type, $id, $qui, $opt) {
73 //compat 192 documents
74 if ($GLOBALS['spip_version_code'] < '1.93') {
75 if (!function_exists('get_spip_doc')) {
76 function get_spip_doc($fichier) {
78 if (preg_match(',^\w+://,', $fichier)) {
81 // gestion d'erreurs, fichier=''
82 if (!strlen($fichier)) {
87 return (strpos($fichier, _DIR_IMG
) === false) ? _DIR_IMG
. $fichier : $fichier;
92 // Autoriser l'usage des crayons ?
93 function autoriser_crayonner_dist($faire, $type, $id, $qui, $opt) {
94 // Le type pouvant etre une table, verifier les autoriser('modifier')
95 // correspondant ; ils demandent le nom de l'objet: spip_articles => article
96 // ex: spip_articles => 'article'
97 $type = preg_replace(',^spip_(.*?)s?$,', '\1', $type);
98 if (strlen($GLOBALS['table_prefix'])) {
99 $type = preg_replace(',^'.$GLOBALS['table_prefix'].'_(.*?)s?$,', '\1', $type);
102 // Tables non SPIP ? Si elles sont interdites il faut regarder
103 // quelle table on appelle, et verifier si elle est "interne"
104 if (!_CRAYONS_TABLES_EXTERNES
) {
105 include_spip('base/serial');
106 include_spip('base/auxiliaires');
107 include_spip('public/parametrer');
108 if (!isset($GLOBALS['tables_principales']['spip_'.table_objet($type)])
109 and !isset($GLOBALS['tables_auxiliaires']['spip_'.table_objet($type)])) {
114 // Traduire le modele en liste de champs
115 if (isset($opt['modele'])) {
116 $opt['champ'] = $opt['modele'];
119 // Pour un auteur, si le champ est statut ou email, signaler l'option
120 // ad hoc (cf. inc/autoriser)
121 if ($type == 'auteur'
122 and in_array($opt['champ'], array('statut', 'email'))) {
123 $opt[$opt['champ']] = true;
127 autoriser('modifier', $type, $id, $qui, $opt)
131 // Si un logo est demande, on renvoie la date dudit logo (permettra de gerer
132 // un "modifie par ailleurs" si la date a change, rien de plus)
133 function valeur_champ_logo($table, $id, $champ) {
134 $chercher_logo = charger_fonction('chercher_logo', 'inc');
135 $on = $chercher_logo($id, id_table_objet($table), 'on');
136 return $on ?
filemtime($on[0]) : false;
139 // Idem : si un doc est demande, on renvoie la date du doc
140 function valeur_champ_document($table, $id, $champ) {
141 $s = spip_query('SELECT date FROM spip_documents WHERE id_document=' . _q($id));
142 if ($t = sql_fetch($s)) {
147 function valeur_champ_vignette($table, $id, $champ) {
148 $vignette = sql_getfetsel('id_vignette', 'spip_documents', 'id_document=' . intval($id));
149 if (is_numeric($vignette) && ($vignette > 0)) {
150 $date = sql_getfetsel('date', 'spip_documents', 'id_document=' . intval($vignette));
152 return $date ?
$date : false;
154 // cette fonction de revision recoit le fichier upload a passer en logo
155 // en reference : le nom du widget, pour aller chercher d'autres donnees
157 function logo_revision($id, $file, $type, $ref) {
158 $chercher_logo = charger_fonction('chercher_logo', 'inc');
159 $_id_objet = id_table_objet($type);
161 // Chargement d'un nouveau logo ?
163 define('FILE_UPLOAD', true); // message pour crayons_json_export :(
165 if (include_spip('action/editer_logo')
166 and function_exists('logo_modifier')) {
167 logo_modifier($type, $id, 'on', $file['logo']);
170 // supprimer l'ancien logo
171 $on = $chercher_logo($id, $_id_objet, 'on');
176 // ajouter le nouveau
177 include_spip('action/iconifier');
178 action_spip_image_ajouter_dist(type_du_logo($_id_objet) . 'on' . $id, false, false); // beurk
181 // Suppression du logo ?
182 if ($wid = array_pop($ref)
183 and $_POST['content_'.$wid.'_logo_supprimer'] == 'on') {
184 if (include_spip('action/editer_logo')
185 and function_exists('logo_supprimer')) {
186 logo_supprimer($type, $id, 'on');
188 if ($on = $chercher_logo($id, $_id_objet, 'on')) {
196 if (is_array($cfg = @unserialize
($GLOBALS['meta']['crayons']))
197 and $max = intval($cfg['reduire_logo'])) {
198 $on = $chercher_logo($id, $_id_objet, 'on');
199 include_spip('inc/filtres');
200 @copy
($on[0], $temp = _DIR_VAR
. 'tmp' . rand(0, 999) . '.' . $on[3]);
201 $img1 = filtrer('image_reduire', $temp, $max);
202 $img2 = preg_replace(',[?].*,', '', extraire_attribut($img1, 'src'));
203 if (@file_exists
($img2)
204 and $img2 != $temp) {
205 if (include_spip('action/editer_logo')
206 and function_exists('logo_modifier')) {
207 logo_modifier($type, $id, 'on', $img2);
210 $dest = $on[1].$on[2].'.'
211 .preg_replace(',^.*\.(gif|jpg|png)$,', '\1', $img2);
212 @rename
($img2, $dest);
222 // cette fonction de revision recoit le fichier upload a passer en document
223 function document_fichier_revision($id, $data, $type, $ref) {
225 $s = spip_query('SELECT * FROM spip_documents WHERE id_document=' . intval($id));
226 if (!$t = sql_fetch($s)) {
231 // Envoi d'une URL de document distant ?
232 // TODO: verifier l'extension distante, sinon tout explose
234 AND preg_match(',^(https?|ftp)://.+,', $data['fichier'])) {
235 include_spip('inc/modifier');
236 modifier_contenu('document', $id,
237 array('champs' => array('fichier', 'distant')),
238 array('fichier' => $data['fichier'], 'distant' => 'oui')
245 // Chargement d'un nouveau doc ?
246 if ($data['document']) {
247 $arg = $data['document'];
249 * Méthode >= SPIP 3.0
250 * ou SPIP 2.x + Mediathèque
252 if ($ajouter_documents = charger_fonction('ajouter_documents', 'action', true)) {
253 $actifs = $ajouter_documents($id, array($arg), '', 0, $t['mode']);
255 if (is_numeric($x)) {
260 } elseif ($ajouter_documents = charger_fonction('ajouter_documents', 'inc', true)) {
264 check_upload_error($arg['error']);
265 $x = $ajouter_documents($arg['tmp_name'], $arg['name'],
266 'article', 0, 'document', null, $actifs);
267 // $actifs contient l'id_document nouvellement cree
268 // on recopie les donnees interessantes dans l'ancien
269 $extension = ', extension ';
271 if ($GLOBALS['spip_version_code'] < '1.93') {
275 if ($id_new = array_pop($actifs)
276 and $s = spip_query("SELECT fichier, taille, largeur, hauteur $extension, distant FROM spip_documents
277 WHERE id_document="._q($id_new))
278 and $new = sql_fetch($s)) {
279 define('FILE_UPLOAD', true); // message pour crayons_json_export :(
281 // Une vignette doit rester une image
282 if ($t['mode'] == 'vignette'
283 and !in_array($new['extension'], array('jpg', 'gif', 'png'))) {
287 // Maintenant on est bon, on recopie les nouvelles donnees
288 // dans l'ancienne ligne spip_documents
289 include_spip('inc/modifier');
293 # 'champs' inutile a partir de SPIP 11348
294 array('champs' => array_keys($new)),
298 // supprimer l'ancien document (sauf s'il etait distant)
299 if ($t['distant'] != 'oui'
300 and file_exists(get_spip_doc($t['fichier']))) {
301 supprimer_fichier(get_spip_doc($t['fichier']));
304 // Effacer la ligne temporaire de spip_document
305 spip_query('DELETE FROM spip_documents WHERE id_document='.intval($id_new));
307 // oublier id_document temporaire (ca marche chez moi, sinon bof)
308 spip_query('ALTER TABLE spip_documents AUTO_INCREMENT='.intval($id_new));
316 // cette fonction de revision soit supprime la vignette d'un document,
317 // soit recoit le fichier upload a passer ou remplacer la vignette du document
318 function vignette_revision($id, $data, $type, $ref) {
319 $s = sql_fetsel('id_document,id_vignette', 'spip_documents', 'id_document = '.intval($id));
324 include_spip('inc/modifier');
325 include_spip('inc/documents');
326 include_spip('action/editer_document');//pour revision_document
327 // Chargement d'un nouveau doc ?
328 if ($data['vignette']) {
329 define('FILE_UPLOAD', true);
330 if (is_numeric($s['id_vignette']) and ($s['id_vignette'] > 0)) {
331 spip_log('suppression de la vignette');
332 // Suppression du document
333 $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));
334 if (@file_exists
($f = get_spip_doc($vignette))) {
335 spip_log("efface $f");
336 supprimer_fichier($f);
338 sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));
339 sql_delete('spip_documents_liens', 'id_document='.intval($s['id_vignette']));
345 'operation' => 'supprimer_document',
346 'table' => 'spip_documents',
347 'id_objet' => $s['id_vignette']
355 $arg = $data['vignette'];
356 check_upload_error($arg['error']);
357 // Ajout du document comme vignette
360 * Méthode >= SPIP 3.0
361 * ou SPIP 2.x + Mediatheque
363 if ($ajouter_documents = charger_fonction('ajouter_documents', 'action', true)) {
364 $x = $ajouter_documents(null,array($arg),'', 0, 'vignette');
365 $vignette = reset($x);
366 if (intval($vignette)) {
367 document_modifier($id, array('id_vignette'=>$vignette));
368 } elseif ($id_vignette) {
369 document_modifier($id, array('id_vignette'=>$id_vignette));
371 } elseif ($ajouter_documents = charger_fonction('ajouter_documents', 'inc', true)) {
375 // On remet l'id_vignette a 0 si on l'a supprimé
377 revision_document($s['id_document'], array('id_vignette' => 0));
379 $x = $ajouter_documents($arg['tmp_name'], $arg['name'],'','', 'vignette', $id, $actifs);
381 } elseif ($wid = array_pop($ref)
382 and $_POST['content_'.$wid.'_vignette_supprimer'] == 'on') {
383 if (is_numeric($s['id_vignette']) and ($s['id_vignette']>0)) {
384 // Suppression du document
385 $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));
386 if (@file_exists
($f = get_spip_doc($vignette))) {
387 spip_log("efface $f");
388 supprimer_fichier($f);
390 sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));
391 sql_delete('spip_documents_liens', 'id_document = ' . intval($s['id_vignette']));
397 'operation' => 'supprimer_document',
398 'table' => 'spip_documents',
399 'id_objet' => $s['id_vignette']
405 // On remet l'id_vignette a 0
406 revision_document($s['id_document'], array('id_vignette'=>0));
413 function colonne_table($type, $col) {
414 list($distant,$table) = distant_table($type);
416 if (!(($tabref = &crayons_get_table($table, $nom_table))
417 && isset($tabref['field'][$col])
418 && ($brut = $tabref['field'][$col]))) {
421 $ana = explode(' ', $brut);
424 $ret = array('brut' => $brut,
425 'type' => '', 'notnull' => false, 'long' => 0, 'def' => '');
426 foreach ($ana as $mot) {
429 $ret['type'] = ($mot = strtolower($mot));
432 if ($mot[strlen($mot) - 1] == ')') {
433 $pos = strpos($mot, '(');
434 $ret['type'] = strtolower(substr($mot, 0, $pos++
));
435 $vir = explode(',', substr($mot, $pos, -1));
436 if ($ret['type'] == 'enum') {
438 } elseif (count($vir) > 1) {
441 $ret['long'] = $vir[0];
452 switch (strtolower($mot)) {
462 $ret['notnull'] = strtolower($mot) == 'null';
466 $df1 = strpos('"\'', $mot[0]) !== false?
$mot[0] : '';
470 $ret['def'] .= $sep . $mot;
475 if ($df1 == $mot[strlen($mot) - 1]) {
476 $ret['def'] = substr($ret['def'], 1, -1);
488 * Obtient le nom de la table ainsi que sa ou ses clés primaires
490 * @param string $type
491 * Table sur laquelle s'applique le crayon.
492 * Ce type peut contenir le nom d'un connecteur distant tel que `{connect}__{table}`
495 * - false si on ne trouve pas de table ou de table ayant de clé primaire
497 * - - nom de la table sql
498 * - - tableau des noms de clés primaires
500 function crayons_get_table_name_and_primary($type) {
501 static $types = array();
502 if (isset($types[$type])) {
503 return $types[$type];
507 if ($tabref = &crayons_get_table($type, $nom_table)
508 and ($tabid = explode(',', $tabref['key']['PRIMARY KEY']))) {
509 return $types[$type] = array($nom_table, $tabid);
511 spip_log('crayons: table ' . $type . ' inconnue');
512 return $types[$type] = false;
516 function table_where($type, $id, $where_en_tableau = false) {
517 if (!$infos = crayons_get_table_name_and_primary($type)) {
518 return array(false, false);
521 list($nom_table, $tabid) = $infos;
523 if (is_scalar($id)) {
524 $id = explode('-', $id);
526 // sortie tableau pour sql_updateq
527 if ($where_en_tableau) {
529 foreach ($id as $idcol => $idval) {
530 $where[] = '`' . (is_int($idcol) ?
trim($tabid[$idcol]) : $idcol) . '`=' . sql_quote($idval);
532 // sinon sortie texte pour sql_query
535 foreach ($id as $idcol => $idval) {
536 $where .= $and . '`' . (is_int($idcol) ?
trim($tabid[$idcol]) : $idcol) . '`=' . _q($idval);
540 return array($nom_table, $where);
542 // var_dump(colonne_table('forum', 'id_syndic')); die();
544 function valeur_colonne_table_dist($type, $col, $id) {
546 // Table introuvable ou sans clé primaire
547 if (!$infos = crayons_get_table_name_and_primary($type)) {
550 $table = reset($infos);
555 foreach ($col as $champ) {
556 if (function_exists($f = 'valeur_champ_'.$table.'_'.$champ)
557 or function_exists($f = 'valeur_champ_'.$champ)) {
558 $r[$champ] = $f($table, $id, $champ);
559 $col = array_diff($col, array($champ));
565 list($distant, $table) = distant_table($type);
566 list($nom_table, $where) = table_where($type, $id);
569 'SELECT `' . implode($col, '`, `') .
570 '` FROM ' . $nom_table . ' WHERE ' . $where,
572 ) and $t = sql_fetch($s)) {
573 $r = array_merge($r, $t);
581 * Extrait la valeur d'une ou plusieurs colonnes d'une table
583 * @param string $table
584 * Type d'objet de la table (article)
585 * @param string|array $col
586 * Nom de la ou des colonnes (ps)
588 * Identifiant de l'objet
590 * Couples Nom de la colonne => Contenu de la colonne
592 function valeur_colonne_table($table, $col, $id) {
593 if (!is_array($col)) {
597 if (function_exists($f = $table . '_valeur_colonne_table_dist')
598 or function_exists($f = $table.'_valeur_colonne_table')
599 or $f = 'valeur_colonne_table_dist') {
600 return $f($table, $col, $id);
605 * Extrait la valeur d'une configuration en meta
607 * Pour ces données, il n'y a toujours qu'une colonne (valeur),
608 * mais on gère l'enregistrement et la lecture via lire_config ou ecrire_config
609 * dès que l'on demande des sous parties d'une configuration.
611 * On ne retourne alors ici dans 'valeur' que la sous-partie demandée si
614 * @param string $table
615 * Nom de la table (meta)
617 * Nom des colonnes (valeur)
619 * Nom ou clé de configuration (descriptif_site ou demo__truc pour demo/truc)
621 * Couple valeur => Contenu de la configuration
623 function meta_valeur_colonne_table_dist($table, $col, $id) {
624 // Certaines clés de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})
625 $id = str_replace('__', '/', $id);
627 // Éviter de planter les vieux SPIP
628 if (false === strpos($id, '/')) {
629 $config = isset($GLOBALS['meta'][$id]) ?
$GLOBALS['meta'][$id] : '';
630 // SPIP 3 ou Bonux 2 ou CFG
632 include_spip('inc/config');
633 $config = lire_config($id, '');
635 return array('valeur' => $config);
639 function return_log($var) {
640 die(crayons_json_export(array('$erreur'=> var_export($var, true))));
643 function _U($texte, $params = array()) {
644 include_spip('inc/charsets');
645 return unicode2charset(html2unicode(_T($texte, $params)));
649 * Obtenir la configuration des crayons
651 * @note wdgcfg = widget config :-)
654 * Couples : attribut => valeur
657 $php = function_exists('crayons_config') ?
crayons_config() : array();
658 include_spip('inc/meta');
661 $metacrayons = empty($meta['crayons']) ?
array() : unserialize($meta['crayons']);
664 'msgNoChange' => false,
665 'msgAbandon' => false, /* etait: true */
667 'yellow_fade' => false,
668 'clickhide' => false /* etait: true */
669 ) as $cfgi => $def) {
670 $wdgcfg[$cfgi] = isset($php[$cfgi]) ?
$php[$cfgi] :
671 isset($metacrayons[$cfgi]) ?
$metacrayons[$cfgi] : $def;
676 function &crayons_get_table($type, &$nom_table) {
677 list($distant,$table) = distant_table($type);
678 static $return = array();
679 static $noms = array();
680 if (!isset($return[$table])) {
681 $try = array(table_objet_sql($table), 'spip_'.table_objet($table), 'spip_' . $table . 's', $table . 's', 'spip_' . $table, $table);
683 // premiere possibilite (à partir de 1.9.3) : regarder directement la base
684 if (function_exists('sql_showtable')) {
685 foreach ($try as $nom) {
686 if ($q = sql_showtable($nom, !$distant, $distant)) {
687 $noms[$table] = $nom;
688 $return[$table] = $q;
694 // seconde, une heuristique 1.9.2
695 if (!isset($return[$table])) {
696 include_spip('base/serial');
697 include_spip('base/auxiliaires');
698 include_spip('public/parametrer');
699 foreach (array('tables_principales', 'tables_auxiliaires') as $categ) {
700 foreach ($try as $nom) {
701 if (isset($GLOBALS[$categ][$nom])) {
702 $noms[$table] = $nom;
703 $return[$table] = & $GLOBALS[$categ][$nom];
711 $nom_table = $noms[$table];
712 return $return[$table];
715 function distant_table($type) {
716 //separation $type en $distant $table
717 //separateur double underscore "__"
718 strstr($type, '__') ?
list($distant,$table) = explode('__', $type) : list($distant, $table) = array(false, $type);
719 return array($distant,$table);