[PLUGINS] ~maj Crayons
[lhc/web/www.git] / www / plugins / crayons / inc / crayons.php
index ed40b6e..7bcf64d 100644 (file)
-<?php\r
-/**\r
- * Crayons \r
- * plugin for spip \r
- * (c) Fil, toggg 2006-2013\r
- * licence GPL\r
- */\r
-\r
-if (!defined("_ECRIRE_INC_VERSION")) return;\r
-\r
-define('_PREG_CRAYON', ',crayon\b[^<>\'"]+?\b((\w+)-(\w+)-(\w+(?:-\w+)*))\b,');\r
-\r
-// Compatibilite pour 1.92 : on a besoin de sql_fetch et table_objet_sql\r
-if ($GLOBALS['spip_version_code'] < '1.93' AND $f = charger_fonction('compat_crayons', 'inc'))\r
-       $f();\r
-\r
-// Autoriser les crayons sur les tables non SPIP ?\r
-// Par defaut : oui (pour les admins complets, si autoriser_defaut_dist()) ;\r
-// mettre a false en cas de mutualisation par prefixe de table,\r
-// sinon on ne peut pas garantir que les sites sont hermetiques\r
-if(!defined('_CRAYONS_TABLES_EXTERNES'))\r
-       define('_CRAYONS_TABLES_EXTERNES', true);\r
-\r
-// Autorisations non prevues par le core\r
-include_spip('inc/autoriser');\r
-\r
-include_spip('inc/crayons-json');\r
-\r
-if (!function_exists('autoriser_meta_modifier_dist')) {\r
-/**\r
- * Autorisation d'éditer les configurations dans spip_meta\r
- *\r
- * Les admins complets OK pour certains champs,\r
- * Sinon, il faut être webmestre\r
- *\r
- * @note\r
- *  Attention sur les SPIP < 11515 (avant 04/2008) inc/autoriser\r
- *  passe seulement intval($id) alors qu'ici la cle est une chaine...\r
- *\r
- * @param  string $faire Action demandée\r
- * @param  string $type  Type d'objet sur lequel appliquer l'action\r
- * @param  int    $id    Identifiant de l'objet\r
- * @param  array  $qui   Description de l'auteur demandant l'autorisation\r
- * @param  array  $opt   Options de cette autorisation\r
- * @return bool          true s'il a le droit, false sinon\r
-**/\r
-function autoriser_meta_modifier_dist($faire, $type, $id, $qui, $opt) {\r
-       // Certaines cles de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})\r
-       // $id = str_replace('__', '/', $id);\r
-       if (in_array("$id", array(\r
-               'nom_site', 'slogan_site', 'descriptif_site', 'email_webmaster'\r
-       )))\r
-               return autoriser('configurer', null, null, $qui);\r
-       else\r
-               return autoriser('webmestre', null, null, $qui);\r
-}\r
-}\r
-\r
-// table spip_messages, la c'est tout simplement non (peut mieux faire,\r
-// mais c'est a voir dans le core/organiseur ou dans autorite)\r
-if (defined('_DIR_PLUGIN_ORGANISEUR'))\r
-       include_spip('organiseur_autoriser');\r
-if (!function_exists('autoriser_message_modifier_dist')) {\r
-       function autoriser_message_modifier_dist($faire, $type, $id, $qui, $opt) {\r
-               return false;\r
-       }\r
-}\r
-//compat 192 documents\r
-if ($GLOBALS['spip_version_code'] < '1.93'){\r
-       if (!function_exists('get_spip_doc')){\r
-               function get_spip_doc($fichier) {\r
-                       // fichier distant\r
-                       if (preg_match(',^\w+://,', $fichier))\r
-                                       return $fichier;\r
-\r
-                       // gestion d'erreurs, fichier=''\r
-                       if (!strlen($fichier))\r
-                                       return false;\r
-\r
-                       // fichier normal\r
-                       return (strpos($fichier, _DIR_IMG) === false)\r
-                       ? _DIR_IMG . $fichier\r
-                       : $fichier;\r
-               }\r
-       }\r
-}\r
-\r
-// Autoriser l'usage des crayons ?\r
-function autoriser_crayonner_dist($faire, $type, $id, $qui, $opt) {\r
-       // Le type pouvant etre une table, verifier les autoriser('modifier')\r
-       // correspondant ; ils demandent le nom de l'objet: spip_articles => article\r
-       // ex: spip_articles => 'article'\r
-       $type = preg_replace(',^spip_(.*?)s?$,', '\1', $type);\r
-       if (strlen($GLOBALS['table_prefix']))\r
-               $type = preg_replace(',^'.$GLOBALS['table_prefix'].'_(.*?)s?$,', '\1', $type);\r
-\r
-       // Tables non SPIP ? Si elles sont interdites il faut regarder\r
-       // quelle table on appelle, et verifier si elle est "interne"\r
-       if (!_CRAYONS_TABLES_EXTERNES) {\r
-               include_spip('base/serial');\r
-               include_spip('base/auxiliaires');\r
-               include_spip('public/parametrer');\r
-               if (!isset($GLOBALS['tables_principales']['spip_'.table_objet($type)])\r
-               AND !isset($GLOBALS['tables_auxiliaires']['spip_'.table_objet($type)]))\r
-                       return false;\r
-       }\r
-\r
-       // Traduire le modele en liste de champs\r
-       if (isset($opt['modele']))\r
-               $opt['champ'] = $opt['modele'];\r
-\r
-       // Pour un auteur, si le champ est statut ou email, signaler l'option\r
-       // ad hoc (cf. inc/autoriser)\r
-       if ($type == 'auteur'\r
-       AND in_array($opt['champ'], array('statut', 'email')))\r
-               $opt[$opt['champ']] = true;\r
-\r
-       return (\r
-                autoriser('modifier', $type, $id, $qui, $opt)\r
-       );\r
-}\r
-\r
-// Si un logo est demande, on renvoie la date dudit logo (permettra de gerer\r
-// un "modifie par ailleurs" si la date a change, rien de plus)\r
-function valeur_champ_logo($table, $id, $champ) {\r
-       $chercher_logo = charger_fonction('chercher_logo', 'inc');\r
-       $on = $chercher_logo($id, id_table_objet($table), 'on');\r
-       return $on ? filemtime($on[0]) : false;\r
-}\r
-\r
-// Idem : si un doc est demande, on renvoie la date du doc\r
-function valeur_champ_document($table, $id, $champ) {\r
-       $s = spip_query("SELECT date FROM spip_documents WHERE id_document="._q($id));\r
-       if ($t = sql_fetch($s))\r
-               return $t['date'];\r
-}\r
-\r
-function valeur_champ_vignette($table, $id, $champ) {\r
-       $vignette = sql_getfetsel('id_vignette','spip_documents','id_document='.intval($id));\r
-       if(is_numeric($vignette) && ($vignette > 0)){\r
-               $date = sql_getfetsel('date','spip_documents','id_document='.intval($vignette));\r
-       }\r
-       return $date ? $date : false;\r
-}\r
-// cette fonction de revision recoit le fichier upload a passer en logo\r
-// en reference : le nom du widget, pour aller chercher d'autres donnees\r
-// (ex: supprimer)\r
-function logo_revision($id, $file, $type, $ref) {\r
-       $chercher_logo = charger_fonction('chercher_logo', 'inc');\r
-       $_id_objet = id_table_objet($type);\r
-\r
-       // Chargement d'un nouveau logo ?\r
-       if ($file['logo']) {\r
-               define('FILE_UPLOAD', true); // message pour crayons_json_export :(\r
-\r
-               // supprimer l'ancien logo\r
-               $on = $chercher_logo($id, $_id_objet, 'on');\r
-               if ($on) @unlink($on[0]);\r
-\r
-               // ajouter le nouveau\r
-               include_spip('action/iconifier');\r
-               action_spip_image_ajouter_dist(\r
-                       type_du_logo($_id_objet).'on'.$id, false, false\r
-               ); // beurk\r
-       }\r
-\r
-       else\r
-\r
-       // Suppression du logo ?\r
-       if ($wid = array_pop($ref)\r
-       AND $_POST['content_'.$wid.'_logo_supprimer'] == 'on') {\r
-               if ($on = $chercher_logo($id, $_id_objet, 'on'))\r
-                       @unlink($on[0]);\r
-       }\r
-\r
-       // Reduire le logo ?\r
-       if (is_array($cfg = @unserialize($GLOBALS['meta']['crayons']))\r
-       AND $max = intval($cfg['reduire_logo'])) {\r
-               $on = $chercher_logo($id, $_id_objet, 'on');\r
-               include_spip('inc/filtres');\r
-               @copy($on[0], $temp = _DIR_VAR.'tmp'.rand(0,999).'.'.$on[3]);\r
-               $img1 = filtrer('image_reduire', $temp, $max);\r
-               $img2 = preg_replace(',[?].*,', '', extraire_attribut($img1, 'src'));\r
-               if (@file_exists($img2)\r
-               AND $img2 !=  $temp) {\r
-                       @unlink($on[0]);\r
-                       $dest = $on[1].$on[2].'.'\r
-                               .preg_replace(',^.*\.(gif|jpg|png)$,', '\1', $img2);\r
-                       @rename($img2,$dest);\r
-               }\r
-               @unlink($temp);\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-\r
-// cette fonction de revision recoit le fichier upload a passer en document\r
-function document_fichier_revision($id, $data, $type, $ref) {\r
-\r
-       $s = spip_query("SELECT * FROM spip_documents WHERE id_document=".intval($id));\r
-       if (!$t = sql_fetch($s))\r
-               return false;\r
-\r
-       /*\r
-       // Envoi d'une URL de document distant ?\r
-       // TODO: verifier l'extension distante, sinon tout explose\r
-       if ($data['fichier']\r
-       AND preg_match(',^(https?|ftp)://.+,', $data['fichier'])) {\r
-               include_spip('inc/modifier');\r
-               modifier_contenu('document', $id,\r
-                       array('champs' => array('fichier', 'distant')),\r
-                       array('fichier' => $data['fichier'], 'distant' => 'oui')\r
-               );\r
-               return true;\r
-       }\r
-       else\r
-       */\r
-\r
-       // Chargement d'un nouveau doc ?\r
-       if ($data['document']) {\r
-\r
-               $arg = $data['document'];\r
-               \r
-               /** \r
-                * Méthode >= SPIP 3.0 \r
-                * ou SPIP 2.x + Mediathèque\r
-                */ \r
-               if($ajouter_documents = charger_fonction('ajouter_documents','action',true)){ \r
-                       $actifs = $ajouter_documents($id,array($arg),'', 0,$t['mode']);\r
-                       $x = reset($actifs);\r
-                       if(is_numeric($x))\r
-                               return true;\r
-                       else\r
-                               return false;\r
-               }\r
-               /**\r
-                * Méthode SPIP < 3.0\r
-                */\r
-               else if($ajouter_documents = charger_fonction('ajouter_documents','inc',true)){ \r
-                       check_upload_error($arg['error']);\r
-                       $x = $ajouter_documents($arg['tmp_name'], $arg['name'],\r
-                                       'article', 0, 'document', null, $actifs);\r
-                       // $actifs contient l'id_document nouvellement cree\r
-                       // on recopie les donnees interessantes dans l'ancien\r
-                       $extension=", extension ";\r
-                       //compat 192\r
-                       if ($GLOBALS['spip_version_code'] < '1.93')\r
-                               $extension="";\r
-\r
-                       if ($id_new = array_pop($actifs)\r
-                       AND $s = spip_query("SELECT fichier, taille, largeur, hauteur $extension, distant FROM spip_documents\r
-                               WHERE id_document="._q($id_new))\r
-                       AND $new = sql_fetch($s)) {\r
-                               define('FILE_UPLOAD', true); // message pour crayons_json_export :(\r
-\r
-                               // Une vignette doit rester une image\r
-                               if ($t['mode'] == 'vignette'\r
-                               AND !in_array($new['extension'], array('jpg', 'gif', 'png')))\r
-                                       return false;\r
-\r
-                               // Maintenant on est bon, on recopie les nouvelles donnees\r
-                               // dans l'ancienne ligne spip_documents\r
-                               include_spip('inc/modifier');\r
-                               modifier_contenu('document', $id,\r
-                                       # 'champs' inutile a partir de SPIP 11348\r
-                                       array('champs' => array_keys($new)),\r
-                                       $new);\r
-\r
-                               // supprimer l'ancien document (sauf s'il etait distant)\r
-                               if ($t['distant'] != 'oui'\r
-                               AND file_exists(get_spip_doc($t['fichier'])))\r
-                                       supprimer_fichier(get_spip_doc($t['fichier']));\r
-\r
-                               // Effacer la ligne temporaire de spip_document\r
-                               spip_query("DELETE FROM spip_documents WHERE id_document="._q($id_new));\r
-\r
-                               // oublier id_document temporaire (ca marche chez moi, sinon bof)\r
-                               spip_query("ALTER TABLE spip_documents AUTO_INCREMENT="._q($id_new));\r
-\r
-                               return true;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-// cette fonction de revision soit supprime la vignette d'un document,\r
-// soit recoit le fichier upload a passer ou remplacer la vignette du document\r
-function vignette_revision($id, $data, $type, $ref) {\r
-       $s = sql_fetsel("id_document,id_vignette","spip_documents","id_document=".intval($id));\r
-       if (!is_array($s))\r
-               return false;\r
-\r
-       include_spip('inc/modifier');\r
-       include_spip('inc/documents');\r
-       include_spip('action/editer_document');//pour revision_document\r
-       // Chargement d'un nouveau doc ?\r
-       if ($data['vignette']) {\r
-               define('FILE_UPLOAD', true);\r
-               if(is_numeric($s['id_vignette']) && ($s['id_vignette']>0)){\r
-                       spip_log('suppression de la vignette');\r
-                       // Suppression du document\r
-                       $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));\r
-                       if (@file_exists($f = get_spip_doc($vignette))) { \r
-                               spip_log("efface $f"); \r
-                               supprimer_fichier($f); \r
-                       }\r
-                       sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));\r
-                       sql_delete('spip_documents_liens', 'id_document='.intval($s['id_vignette']));\r
-\r
-                       pipeline('post_edition',\r
-                               array(\r
-                                       'args' => array(\r
-                                               'operation' => 'supprimer_document',\r
-                                               'table' => 'spip_documents',\r
-                                               'id_objet' => $s['id_vignette']\r
-                                       ),\r
-                                       'data' => null\r
-                               )\r
-                       );\r
-                       $id_vignette = 0;\r
-               }\r
-\r
-               $arg = $data['vignette'];\r
-               check_upload_error($arg['error']);\r
-               // Ajout du document comme vignette\r
-\r
-               /**\r
-                * Méthode >= SPIP 3.0 \r
-                * ou SPIP 2.x + Mediatheque\r
-                */\r
-               if($ajouter_documents = charger_fonction('ajouter_documents','action',true)){\r
-                       $x = $ajouter_documents(null,array($arg),'', 0, 'vignette');\r
-                       $vignette = reset($x);\r
-                       if(intval($vignette))\r
-                               document_modifier($id, array('id_vignette'=>$vignette));\r
-                       else if($id_vignette)\r
-                               document_modifier($id, array('id_vignette'=>$id_vignette));\r
-               }\r
-               /**\r
-                * Méthode < SPIP 3.0\r
-                */\r
-               else if($ajouter_documents = charger_fonction('ajouter_documents','inc',true)){\r
-                       // On remet l'id_vignette a 0 si on l'a supprimé\r
-                       if($id_vignette) revision_document($s['id_document'], array('id_vignette'=>0));\r
-                       $x = $ajouter_documents($arg['tmp_name'], $arg['name'],'','', 'vignette', $id, $actifs);\r
-               }\r
-               \r
-       }else\r
-               // Suppression de la vignette ?\r
-               if ($wid = array_pop($ref)\r
-                       AND $_POST['content_'.$wid.'_vignette_supprimer'] == 'on') {\r
-                       if(is_numeric($s['id_vignette']) && ($s['id_vignette']>0)){\r
-                               // Suppression du document\r
-                               $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));\r
-                               if (@file_exists($f = get_spip_doc($vignette))) { \r
-                                       spip_log("efface $f"); \r
-                                       supprimer_fichier($f); \r
-                               }\r
-                               sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));\r
-                               sql_delete('spip_documents_liens',  'id_document='.intval($s['id_vignette']));\r
-\r
-                               pipeline('post_edition',\r
-                                       array(\r
-                                               'args' => array(\r
-                                                       'operation' => 'supprimer_document',\r
-                                                       'table' => 'spip_documents',\r
-                                                       'id_objet' => $s['id_vignette']\r
-                                               ),\r
-                                               'data' => null\r
-                                       )\r
-                               );\r
-\r
-                               // On remet l'id_vignette a 0\r
-                               revision_document($s['id_document'], array('id_vignette'=>0));\r
-                       }\r
-               }\r
-       return true;\r
-}\r
-\r
-\r
-function colonne_table($type, $col) {\r
-       list($distant,$table) = distant_table($type);\r
-       $nom_table = '';\r
-       if (!(($tabref = &crayons_get_table($table, $nom_table))\r
-               && isset($tabref['field'][$col])\r
-               && ($brut = $tabref['field'][$col]))) {\r
-                       return false;\r
-       }\r
-       $ana = explode(' ', $brut);\r
-       $sta = 0;\r
-       $sep = '';\r
-       $ret = array('brut' => $brut,\r
-               'type' => '', 'notnull' => false, 'long' => 0, 'def' => '');\r
-       foreach ($ana as $mot) {\r
-               switch ($sta) {\r
-                       case 0: $ret['type'] = ($mot = strtolower($mot));\r
-                       case 1: if ($mot[strlen($mot) - 1] == ')') {\r
-                                       $pos = strpos($mot, '(');\r
-                                       $ret['type'] = strtolower(substr($mot, 0, $pos++));\r
-                                       $vir = explode(',', substr($mot, $pos, -1));\r
-                                       if ($ret['type'] == 'enum') {\r
-                                               $ret['enum'] = $vir;\r
-                                       } elseif (count($vir) > 1) {\r
-                                               $ret['long'] = $vir;\r
-                                       } else {\r
-                                               $ret['long'] = $vir[0];\r
-                                       }\r
-                                       $sta = 1;\r
-                                       continue;\r
-                               }\r
-                               if (!$sta) {\r
-                                       $sta = 1;\r
-                                       continue;\r
-                               }\r
-                       case 2: switch (strtolower($mot)) {\r
-                               case 'not':\r
-                                       $sta = 3;\r
-                                       continue;\r
-                               case 'default':\r
-                                       $sta = 4;\r
-                                       continue;\r
-                               }\r
-                               continue;\r
-                       case 3:         $ret['notnull'] = strtolower($mot) == 'null';\r
-                               $sta = 2;\r
-                               continue;\r
-                       case 4: $df1 = strpos('"\'', $mot[0]) !== false? $mot[0] : '';\r
-                               $sta = 5;\r
-                       case 5: $ret['def'] .= $sep . $mot;\r
-                               if (!$df1) {\r
-                                       $sta = 2;\r
-                                       continue;\r
-                               }\r
-                               if ($df1 == $mot[strlen($mot) - 1]) {\r
-                                       $ret['def'] = substr($ret['def'], 1, -1);\r
-                                       $sta = 2;\r
-                               }\r
-                               $sep = ' ';\r
-                               continue;\r
-               }\r
-       }\r
-       return $ret;\r
-}\r
-\r
-\r
-/**\r
- * Obtient le nom de la table ainsi que sa ou ses clés primaires\r
- *\r
- * @param string $type\r
- *     Table sur laquelle s'applique le crayon.\r
- *     Ce type peut contenir le nom d'un connecteur distant tel que `{connect}__{table}`\r
- *\r
- * @return array|bool\r
- *     - false si on ne trouve pas de table ou de table ayant de clé primaire\r
- *     - liste :\r
- *     - - nom de la table sql\r
- *     - - tableau des noms de clés primaires\r
-**/\r
-function crayons_get_table_name_and_primary($type) {\r
-       static $types = array();\r
-       if (isset($types[$type])) {\r
-               return $types[$type];\r
-       }\r
-\r
-       $nom_table = '';\r
-       if ($tabref = &crayons_get_table($type, $nom_table)\r
-         and ($tabid = explode(',', $tabref['key']['PRIMARY KEY'])))\r
-       {\r
-               return $types[$type] = array($nom_table, $tabid);\r
-       }\r
-       spip_log('crayons: table ' . $type . ' inconnue');\r
-       return $types[$type] = false;\r
-}\r
-\r
-\r
-function table_where($type, $id, $where_en_tableau = false) {\r
-\r
-\r
-       if (!$infos = crayons_get_table_name_and_primary($type)) {\r
-               return array(false, false);\r
-       }\r
-\r
-       list($nom_table, $tabid) = $infos;\r
-\r
-\r
-       if (is_scalar($id))\r
-               $id = explode('-', $id);\r
-       // sortie tableau pour sql_updateq\r
-       if ($where_en_tableau) {\r
-               $where = array();\r
-               foreach ($id as $idcol => $idval) {\r
-                       $where[] = '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . sql_quote($idval);\r
-               }\r
-       // sinon sortie texte pour sql_query\r
-       } else {\r
-\r
-               $where = $and = '';\r
-               foreach ($id as $idcol => $idval) {\r
-                       $where .= $and . '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . _q($idval);\r
-                       $and = ' AND ';\r
-               }\r
-       }\r
-       return array($nom_table, $where);\r
-}\r
-//     var_dump(colonne_table('forum', 'id_syndic')); die();\r
-\r
-function valeur_colonne_table_dist($type, $col, $id) {\r
-\r
-       // Table introuvable ou sans clé primaire\r
-       if (!$infos = crayons_get_table_name_and_primary($type)) {\r
-               return false;\r
-       }\r
-       $table = reset($infos);\r
-\r
-       $r = array();\r
-\r
-       // valeurs non SQL\r
-       foreach ($col as $champ) {\r
-               if (function_exists($f = 'valeur_champ_'.$table.'_'.$champ) OR function_exists($f = 'valeur_champ_'.$champ)) {\r
-                       $r[$champ] = $f($table, $id, $champ);\r
-                       $col = array_diff($col, array($champ));\r
-               }\r
-       }\r
-\r
-       // valeurs SQL\r
-       if (count($col)) {\r
-               list($distant, $table)   = distant_table($type);\r
-               list($nom_table, $where) = table_where($type, $id);\r
-\r
-               if ($s = spip_query(\r
-                               'SELECT `' . implode($col, '`, `') .\r
-                               '` FROM ' . $nom_table . ' WHERE ' . $where, $distant)\r
-                       AND $t = sql_fetch($s)){\r
-                               $r = array_merge($r, $t);\r
-               }\r
-       }\r
-\r
-       return $r;\r
-}\r
-\r
-/**\r
- * Extrait la valeur d'une ou plusieurs colonnes d'une table\r
- *\r
- * @param string $table\r
- *   Type d'objet de la table (article)\r
- * @param string|array $col\r
- *   Nom de la ou des colonnes (ps)\r
- * @param string $id\r
- *   Identifiant de l'objet\r
- * @return array\r
- *   Couples Nom de la colonne => Contenu de la colonne\r
-**/\r
-function valeur_colonne_table($table, $col, $id) {\r
-       if (!is_array($col))\r
-               $col = array($col);\r
-\r
-       if (function_exists($f = $table.'_valeur_colonne_table_dist')\r
-       OR function_exists($f = $table.'_valeur_colonne_table')\r
-       OR $f = 'valeur_colonne_table_dist')\r
-               return $f($table, $col, $id);\r
-}\r
-\r
-/**\r
- * Extrait la valeur d'une configuration en meta\r
- *\r
- * Pour ces données, il n'y a toujours qu'une colonne (valeur),\r
- * mais on gère l'enregistrement et la lecture via lire_config ou ecrire_config\r
- * dès que l'on demande des sous parties d'une configuration.\r
- *\r
- * On ne retourne alors ici dans 'valeur' que la sous-partie demandée si\r
- * c'est le cas.\r
- *\r
- * @param string $table\r
- *   Nom de la table (meta)\r
- * @param array $col\r
- *   Nom des colonnes (valeur)\r
- * @param string $id\r
- *   Nom ou clé de configuration (descriptif_site ou demo__truc pour demo/truc)\r
- * @return array\r
- *   Couple valeur => Contenu de la configuration\r
-**/\r
-function meta_valeur_colonne_table_dist($table, $col, $id) {\r
-       // Certaines clés de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})\r
-       $id = str_replace('__', '/', $id);\r
-\r
-       // Éviter de planter les vieux SPIP\r
-       if (false === strpos($id, '/')) {\r
-               $config = isset($GLOBALS['meta'][$id]) ? $GLOBALS['meta'][$id] : '';\r
-       // SPIP 3 ou Bonux 2 ou CFG\r
-       } else {\r
-               include_spip('inc/config');\r
-               $config =  lire_config($id, '');\r
-       }\r
-       return array('valeur' => $config);\r
-}\r
-\r
-\r
-function return_log($var) {\r
-       die(crayons_json_export(array('$erreur'=> var_export($var,true))));\r
-}\r
-\r
-function _U($texte, $params=array()) {\r
-       include_spip('inc/charsets');\r
-       return unicode2charset(html2unicode(_T($texte, $params)));\r
-}\r
-\r
-/**\r
- * Obtenir la configuration des crayons\r
- *\r
- * @note wdgcfg = widget config :-)\r
- * \r
- * @return array\r
- *     Couples : attribut => valeur\r
-**/\r
-function wdgcfg() {\r
-       $php = function_exists('crayons_config') ? crayons_config() : array();\r
-       include_spip('inc/meta');\r
-       lire_metas();\r
-       global $meta;\r
-       $metacrayons = empty($meta['crayons']) ? array() : unserialize($meta['crayons']);\r
-       $wdgcfg = array();\r
-       foreach (array(\r
-               'msgNoChange' => false,\r
-               'msgAbandon' => false,  /* etait: true */\r
-               'filet' => false,\r
-               'yellow_fade' => false,\r
-               'clickhide' => false /* etait: true */\r
-       )\r
-       as $cfgi => $def) {\r
-               $wdgcfg[$cfgi] = isset($php[$cfgi]) ? $php[$cfgi] :\r
-                       isset($metacrayons[$cfgi]) ? $metacrayons[$cfgi] : $def;\r
-       }\r
-       return $wdgcfg;\r
-}\r
-\r
-function &crayons_get_table($type, &$nom_table) {\r
-       list($distant,$table) = distant_table($type);\r
-       static $return = array();\r
-       static $noms = array();\r
-       if (!isset($return[$table])) {\r
-               $try = array(table_objet_sql($table), 'spip_'.table_objet($table), 'spip_' . $table . 's', $table . 's', 'spip_' . $table, $table);\r
-\r
-               // premiere possibilite (à partir de 1.9.3) : regarder directement la base\r
-               if (function_exists('sql_showtable')) {\r
-                       foreach ($try as $nom) {\r
-                               if ($q = sql_showtable($nom , !$distant , $distant)) {\r
-                                       $noms[$table] = $nom;\r
-                                       $return[$table] = $q;\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               // seconde, une heuristique 1.9.2\r
-               if (!isset($return[$table])) {\r
-                       include_spip('base/serial');\r
-                       include_spip('base/auxiliaires');\r
-                       include_spip('public/parametrer');\r
-                       foreach(array('tables_principales', 'tables_auxiliaires') as $categ) {\r
-                               foreach ($try as $nom) {\r
-                                       if (isset($GLOBALS[$categ][$nom])) {\r
-                                               $noms[$table] = $nom;\r
-                                               $return[$table] = & $GLOBALS[$categ][$nom];\r
-                                               break 2;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       $nom_table = $noms[$table];\r
-       return $return[$table];\r
-}\r
-\r
-function distant_table($type) {\r
-       //separation $type en $distant $table\r
-       //separateur double underscore "__"\r
-       strstr($type,'__')? list($distant,$table) = explode('__',$type) : list($distant,$table) = array(False,$type);\r
-       return array($distant,$table);\r
-}\r
-?>\r
+<?php
+/**
+ * Crayons
+ * plugin for spip
+ * (c) Fil, toggg 2006-2013
+ * licence GPL
+ */
+
+if (!defined('_ECRIRE_INC_VERSION')) {
+       return;
+}
+
+define('_PREG_CRAYON', ',crayon\b[^<>\'"]+?\b((\w+)-(\w+)-(\w+(?:-\w+)*))\b,');
+
+// Compatibilite pour 1.92 : on a besoin de sql_fetch et table_objet_sql
+if ($GLOBALS['spip_version_code'] < '1.93' and $f = charger_fonction('compat_crayons', 'inc')) {
+       $f();
+}
+
+// Autoriser les crayons sur les tables non SPIP ?
+// Par defaut : oui (pour les admins complets, si autoriser_defaut_dist()) ;
+// mettre a false en cas de mutualisation par prefixe de table,
+// sinon on ne peut pas garantir que les sites sont hermetiques
+if (!defined('_CRAYONS_TABLES_EXTERNES')) {
+       define('_CRAYONS_TABLES_EXTERNES', true);
+}
+
+// Autorisations non prevues par le core
+include_spip('inc/autoriser');
+
+include_spip('inc/crayons-json');
+
+if (!function_exists('autoriser_meta_modifier_dist')) {
+/**
+ * Autorisation d'éditer les configurations dans spip_meta
+ *
+ * Les admins complets OK pour certains champs,
+ * Sinon, il faut être webmestre
+ *
+ * @note
+ *  Attention sur les SPIP < 11515 (avant 04/2008) inc/autoriser
+ *  passe seulement intval($id) alors qu'ici la cle est une chaine...
+ *
+ * @param  string $faire Action demandée
+ * @param  string $type  Type d'objet sur lequel appliquer l'action
+ * @param  int    $id    Identifiant de l'objet
+ * @param  array  $qui   Description de l'auteur demandant l'autorisation
+ * @param  array  $opt   Options de cette autorisation
+ * @return bool          true s'il a le droit, false sinon
+**/
+function autoriser_meta_modifier_dist($faire, $type, $id, $qui, $opt) {
+       // Certaines cles de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})
+       // $id = str_replace('__', '/', $id);
+       if (in_array($id, array('nom_site', 'slogan_site', 'descriptif_site', 'email_webmaster'))) {
+               return autoriser('configurer', null, null, $qui);
+       } else {
+               return autoriser('webmestre', null, null, $qui);
+       }
+}
+}
+
+// table spip_messages, la c'est tout simplement non (peut mieux faire,
+// mais c'est a voir dans le core/organiseur ou dans autorite)
+if (defined('_DIR_PLUGIN_ORGANISEUR')) {
+       include_spip('organiseur_autoriser');
+}
+
+if (!function_exists('autoriser_message_modifier_dist')) {
+       function autoriser_message_modifier_dist($faire, $type, $id, $qui, $opt) {
+               return false;
+       }
+}
+//compat 192 documents
+if ($GLOBALS['spip_version_code'] < '1.93') {
+       if (!function_exists('get_spip_doc')) {
+               function get_spip_doc($fichier) {
+                       // fichier distant
+                       if (preg_match(',^\w+://,', $fichier)) {
+                               return $fichier;
+                       }
+                       // gestion d'erreurs, fichier=''
+                       if (!strlen($fichier)) {
+                               return false;
+                       }
+
+                       // fichier normal
+                       return (strpos($fichier, _DIR_IMG) === false) ? _DIR_IMG . $fichier : $fichier;
+               }
+       }
+}
+
+// Autoriser l'usage des crayons ?
+function autoriser_crayonner_dist($faire, $type, $id, $qui, $opt) {
+       // Le type pouvant etre une table, verifier les autoriser('modifier')
+       // correspondant ; ils demandent le nom de l'objet: spip_articles => article
+       // ex: spip_articles => 'article'
+       $type = preg_replace(',^spip_(.*?)s?$,', '\1', $type);
+       if (strlen($GLOBALS['table_prefix'])) {
+               $type = preg_replace(',^'.$GLOBALS['table_prefix'].'_(.*?)s?$,', '\1', $type);
+       }
+
+       // Tables non SPIP ? Si elles sont interdites il faut regarder
+       // quelle table on appelle, et verifier si elle est "interne"
+       if (!_CRAYONS_TABLES_EXTERNES) {
+               include_spip('base/serial');
+               include_spip('base/auxiliaires');
+               include_spip('public/parametrer');
+               if (!isset($GLOBALS['tables_principales']['spip_'.table_objet($type)])
+                       and !isset($GLOBALS['tables_auxiliaires']['spip_'.table_objet($type)])) {
+                       return false;
+               }
+       }
+
+       // Traduire le modele en liste de champs
+       if (isset($opt['modele'])) {
+               $opt['champ'] = $opt['modele'];
+       }
+
+       // Pour un auteur, si le champ est statut ou email, signaler l'option
+       // ad hoc (cf. inc/autoriser)
+       if ($type == 'auteur'
+               and in_array($opt['champ'], array('statut', 'email'))) {
+               $opt[$opt['champ']] = true;
+       }
+
+       return (
+                autoriser('modifier', $type, $id, $qui, $opt)
+       );
+}
+
+// Si un logo est demande, on renvoie la date dudit logo (permettra de gerer
+// un "modifie par ailleurs" si la date a change, rien de plus)
+function valeur_champ_logo($table, $id, $champ) {
+       $chercher_logo = charger_fonction('chercher_logo', 'inc');
+       $on = $chercher_logo($id, id_table_objet($table), 'on');
+       return $on ? filemtime($on[0]) : false;
+}
+
+// Idem : si un doc est demande, on renvoie la date du doc
+function valeur_champ_document($table, $id, $champ) {
+       $s = spip_query('SELECT date FROM spip_documents WHERE id_document=' . _q($id));
+       if ($t = sql_fetch($s)) {
+               return $t['date'];
+       }
+}
+
+function valeur_champ_vignette($table, $id, $champ) {
+       $vignette = sql_getfetsel('id_vignette', 'spip_documents', 'id_document=' . intval($id));
+       if (is_numeric($vignette) && ($vignette > 0)) {
+               $date = sql_getfetsel('date', 'spip_documents', 'id_document=' . intval($vignette));
+       }
+       return $date ? $date : false;
+}
+// cette fonction de revision recoit le fichier upload a passer en logo
+// en reference : le nom du widget, pour aller chercher d'autres donnees
+// (ex: supprimer)
+function logo_revision($id, $file, $type, $ref) {
+       $chercher_logo = charger_fonction('chercher_logo', 'inc');
+       $_id_objet = id_table_objet($type);
+
+       // Chargement d'un nouveau logo ?
+       if ($file['logo']) {
+               define('FILE_UPLOAD', true); // message pour crayons_json_export :(
+
+               if (include_spip('action/editer_logo')
+                       and function_exists('logo_modifier')) {
+                       logo_modifier($type, $id, 'on', $file['logo']);
+               } else {
+                       // compat SPIP < 3.1
+                       // supprimer l'ancien logo
+                       $on = $chercher_logo($id, $_id_objet, 'on');
+                       if ($on) {
+                               @unlink($on[0]);
+                       }
+
+                       // ajouter le nouveau
+                       include_spip('action/iconifier');
+                       action_spip_image_ajouter_dist(type_du_logo($_id_objet) . 'on' . $id, false, false); // beurk
+               }
+       } else {
+               // Suppression du logo ?
+               if ($wid = array_pop($ref)
+                       and $_POST['content_'.$wid.'_logo_supprimer'] == 'on') {
+                       if (include_spip('action/editer_logo')
+                               and function_exists('logo_supprimer')) {
+                               logo_supprimer($type, $id, 'on');
+                       } else {
+                               if ($on = $chercher_logo($id, $_id_objet, 'on')) {
+                                       @unlink($on[0]);
+                               }
+                       }
+               }
+       }
+
+       // Reduire le logo ?
+       if (is_array($cfg = @unserialize($GLOBALS['meta']['crayons']))
+               and $max = intval($cfg['reduire_logo'])) {
+               $on = $chercher_logo($id, $_id_objet, 'on');
+               include_spip('inc/filtres');
+               @copy($on[0], $temp = _DIR_VAR . 'tmp' . rand(0, 999) . '.' . $on[3]);
+               $img1 = filtrer('image_reduire', $temp, $max);
+               $img2 = preg_replace(',[?].*,', '', extraire_attribut($img1, 'src'));
+               if (@file_exists($img2)
+                       and $img2 !=  $temp) {
+                       if (include_spip('action/editer_logo')
+                               and function_exists('logo_modifier')) {
+                               logo_modifier($type, $id, 'on', $img2);
+                       } else {
+                               @unlink($on[0]);
+                               $dest = $on[1].$on[2].'.'
+                                       .preg_replace(',^.*\.(gif|jpg|png)$,', '\1', $img2);
+                               @rename($img2, $dest);
+                       }
+               }
+               @unlink($temp);
+       }
+
+       return true;
+}
+
+
+// cette fonction de revision recoit le fichier upload a passer en document
+function document_fichier_revision($id, $data, $type, $ref) {
+
+       $s = spip_query('SELECT * FROM spip_documents WHERE id_document=' . intval($id));
+       if (!$t = sql_fetch($s)) {
+               return false;
+       }
+
+       /*
+       // Envoi d'une URL de document distant ?
+       // TODO: verifier l'extension distante, sinon tout explose
+       if ($data['fichier']
+       AND preg_match(',^(https?|ftp)://.+,', $data['fichier'])) {
+               include_spip('inc/modifier');
+               modifier_contenu('document', $id,
+                       array('champs' => array('fichier', 'distant')),
+                       array('fichier' => $data['fichier'], 'distant' => 'oui')
+               );
+               return true;
+       }
+       else
+       */
+
+       // Chargement d'un nouveau doc ?
+       if ($data['document']) {
+               $arg = $data['document'];
+               /**
+                * Méthode >= SPIP 3.0
+                * ou SPIP 2.x + Mediathèque
+                */
+               if ($ajouter_documents = charger_fonction('ajouter_documents', 'action', true)) {
+                       $actifs = $ajouter_documents($id, array($arg), '', 0, $t['mode']);
+                       $x = reset($actifs);
+                       if (is_numeric($x)) {
+                               return true;
+                       } else {
+                               return false;
+                       }
+               } elseif ($ajouter_documents = charger_fonction('ajouter_documents', 'inc', true)) {
+                       /**
+                        * Méthode SPIP < 3.0
+                        */
+                       check_upload_error($arg['error']);
+                       $x = $ajouter_documents($arg['tmp_name'], $arg['name'],
+                                       'article', 0, 'document', null, $actifs);
+                       // $actifs contient l'id_document nouvellement cree
+                       // on recopie les donnees interessantes dans l'ancien
+                        $extension = ', extension ';
+                       //compat 192
+                       if ($GLOBALS['spip_version_code'] < '1.93') {
+                               $extension = '';
+                       }
+
+                       if ($id_new = array_pop($actifs)
+                               and $s = spip_query("SELECT fichier, taille, largeur, hauteur $extension, distant FROM spip_documents
+                               WHERE id_document="._q($id_new))
+                               and $new = sql_fetch($s)) {
+                               define('FILE_UPLOAD', true); // message pour crayons_json_export :(
+
+                               // Une vignette doit rester une image
+                               if ($t['mode'] == 'vignette'
+                                       and !in_array($new['extension'], array('jpg', 'gif', 'png'))) {
+                                       return false;
+                               }
+
+                               // Maintenant on est bon, on recopie les nouvelles donnees
+                               // dans l'ancienne ligne spip_documents
+                               include_spip('inc/modifier');
+                               modifier_contenu(
+                                       'document',
+                                       $id,
+                                       # 'champs' inutile a partir de SPIP 11348
+                                       array('champs' => array_keys($new)),
+                                       $new
+                               );
+
+                               // supprimer l'ancien document (sauf s'il etait distant)
+                               if ($t['distant'] != 'oui'
+                                       and file_exists(get_spip_doc($t['fichier']))) {
+                                       supprimer_fichier(get_spip_doc($t['fichier']));
+                               }
+
+                               // Effacer la ligne temporaire de spip_document
+                               spip_query('DELETE FROM spip_documents WHERE id_document='.intval($id_new));
+
+                               // oublier id_document temporaire (ca marche chez moi, sinon bof)
+                               spip_query('ALTER TABLE spip_documents AUTO_INCREMENT='.intval($id_new));
+
+                               return true;
+                       }
+               }
+       }
+}
+
+// cette fonction de revision soit supprime la vignette d'un document,
+// soit recoit le fichier upload a passer ou remplacer la vignette du document
+function vignette_revision($id, $data, $type, $ref) {
+       $s = sql_fetsel('id_document,id_vignette', 'spip_documents', 'id_document = '.intval($id));
+       if (!is_array($s)) {
+               return false;
+       }
+
+       include_spip('inc/modifier');
+       include_spip('inc/documents');
+       include_spip('action/editer_document');//pour revision_document
+       // Chargement d'un nouveau doc ?
+       if ($data['vignette']) {
+               define('FILE_UPLOAD', true);
+               if (is_numeric($s['id_vignette']) and ($s['id_vignette'] > 0)) {
+                       spip_log('suppression de la vignette');
+                       // Suppression du document
+                       $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));
+                       if (@file_exists($f = get_spip_doc($vignette))) {
+                               spip_log("efface $f");
+                               supprimer_fichier($f);
+                       }
+                       sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));
+                       sql_delete('spip_documents_liens', 'id_document='.intval($s['id_vignette']));
+
+                       pipeline(
+                               'post_edition',
+                               array(
+                                       'args' => array(
+                                               'operation' => 'supprimer_document',
+                                               'table' => 'spip_documents',
+                                               'id_objet' => $s['id_vignette']
+                                       ),
+                                       'data' => null
+                               )
+                       );
+                       $id_vignette = 0;
+               }
+
+               $arg = $data['vignette'];
+               check_upload_error($arg['error']);
+               // Ajout du document comme vignette
+
+               /**
+                * Méthode >= SPIP 3.0
+                * ou SPIP 2.x + Mediatheque
+                */
+               if ($ajouter_documents = charger_fonction('ajouter_documents', 'action', true)) {
+                       $x = $ajouter_documents(null,array($arg),'', 0, 'vignette');
+                       $vignette = reset($x);
+                       if (intval($vignette)) {
+                               document_modifier($id, array('id_vignette'=>$vignette));
+                       } elseif ($id_vignette) {
+                               document_modifier($id, array('id_vignette'=>$id_vignette));
+                       }
+               } elseif ($ajouter_documents = charger_fonction('ajouter_documents', 'inc', true)) {
+                       /**
+                        * Méthode < SPIP 3.0
+                        */
+                       // On remet l'id_vignette a 0 si on l'a supprimé
+                       if ($id_vignette) {
+                               revision_document($s['id_document'], array('id_vignette' => 0));
+                       }
+                       $x = $ajouter_documents($arg['tmp_name'], $arg['name'],'','', 'vignette', $id, $actifs);
+               }
+       } elseif ($wid = array_pop($ref)
+               and $_POST['content_'.$wid.'_vignette_supprimer'] == 'on') {
+               if (is_numeric($s['id_vignette']) and ($s['id_vignette']>0)) {
+                       // Suppression du document
+                       $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));
+                       if (@file_exists($f = get_spip_doc($vignette))) {
+                               spip_log("efface $f");
+                               supprimer_fichier($f);
+                       }
+                       sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));
+                       sql_delete('spip_documents_liens', 'id_document = ' . intval($s['id_vignette']));
+
+                       pipeline(
+                               'post_edition',
+                               array(
+                                       'args' => array(
+                                               'operation' => 'supprimer_document',
+                                               'table' => 'spip_documents',
+                                               'id_objet' => $s['id_vignette']
+                                       ),
+                                       'data' => null
+                               )
+                       );
+
+                       // On remet l'id_vignette a 0
+                       revision_document($s['id_document'], array('id_vignette'=>0));
+               }
+       }
+       return true;
+}
+
+
+function colonne_table($type, $col) {
+       list($distant,$table) = distant_table($type);
+       $nom_table = '';
+       if (!(($tabref = &crayons_get_table($table, $nom_table))
+               && isset($tabref['field'][$col])
+               && ($brut = $tabref['field'][$col]))) {
+                       return false;
+       }
+       $ana = explode(' ', $brut);
+       $sta = 0;
+       $sep = '';
+       $ret = array('brut' => $brut,
+               'type' => '', 'notnull' => false, 'long' => 0, 'def' => '');
+       foreach ($ana as $mot) {
+               switch ($sta) {
+                       case 0:
+                               $ret['type'] = ($mot = strtolower($mot));
+                               continue;
+                       case 1:
+                               if ($mot[strlen($mot) - 1] == ')') {
+                                       $pos = strpos($mot, '(');
+                                       $ret['type'] = strtolower(substr($mot, 0, $pos++));
+                                       $vir = explode(',', substr($mot, $pos, -1));
+                                       if ($ret['type'] == 'enum') {
+                                               $ret['enum'] = $vir;
+                                       } elseif (count($vir) > 1) {
+                                               $ret['long'] = $vir;
+                                       } else {
+                                               $ret['long'] = $vir[0];
+                                       }
+                                       $sta = 1;
+                                       continue;
+                               }
+                               if (!$sta) {
+                                       $sta = 1;
+                                       continue;
+                               }
+                               continue;
+                       case 2:
+                               switch (strtolower($mot)) {
+                                       case 'not':
+                                               $sta = 3;
+                                               continue;
+                                       case 'default':
+                                               $sta = 4;
+                                               continue;
+                               }
+                               continue;
+                       case 3:
+                               $ret['notnull'] = strtolower($mot) == 'null';
+                               $sta = 2;
+                               continue;
+                       case 4:
+                               $df1 = strpos('"\'', $mot[0]) !== false? $mot[0] : '';
+                               $sta = 5;
+                               continue;
+                       case 5:
+                               $ret['def'] .= $sep . $mot;
+                               if (!$df1) {
+                                       $sta = 2;
+                                       continue;
+                               }
+                               if ($df1 == $mot[strlen($mot) - 1]) {
+                                       $ret['def'] = substr($ret['def'], 1, -1);
+                                       $sta = 2;
+                               }
+                               $sep = ' ';
+                               continue;
+               }
+       }
+       return $ret;
+}
+
+
+/**
+ * Obtient le nom de la table ainsi que sa ou ses clés primaires
+ *
+ * @param string $type
+ *     Table sur laquelle s'applique le crayon.
+ *     Ce type peut contenir le nom d'un connecteur distant tel que `{connect}__{table}`
+ *
+ * @return array|bool
+ *     - false si on ne trouve pas de table ou de table ayant de clé primaire
+ *     - liste :
+ *     - - nom de la table sql
+ *     - - tableau des noms de clés primaires
+**/
+function crayons_get_table_name_and_primary($type) {
+       static $types = array();
+       if (isset($types[$type])) {
+               return $types[$type];
+       }
+
+       $nom_table = '';
+       if ($tabref = &crayons_get_table($type, $nom_table)
+               and ($tabid = explode(',', $tabref['key']['PRIMARY KEY']))) {
+               return $types[$type] = array($nom_table, $tabid);
+       }
+       spip_log('crayons: table ' . $type . ' inconnue');
+       return $types[$type] = false;
+}
+
+
+function table_where($type, $id, $where_en_tableau = false) {
+       if (!$infos = crayons_get_table_name_and_primary($type)) {
+               return array(false, false);
+       }
+
+       list($nom_table, $tabid) = $infos;
+
+       if (is_scalar($id)) {
+               $id = explode('-', $id);
+       }
+       // sortie tableau pour sql_updateq
+       if ($where_en_tableau) {
+               $where = array();
+               foreach ($id as $idcol => $idval) {
+                       $where[] = '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . sql_quote($idval);
+               }
+       // sinon sortie texte pour sql_query
+       } else {
+               $where = $and = '';
+               foreach ($id as $idcol => $idval) {
+                       $where .= $and . '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . _q($idval);
+                       $and = ' AND ';
+               }
+       }
+       return array($nom_table, $where);
+}
+//     var_dump(colonne_table('forum', 'id_syndic')); die();
+
+function valeur_colonne_table_dist($type, $col, $id) {
+
+       // Table introuvable ou sans clé primaire
+       if (!$infos = crayons_get_table_name_and_primary($type)) {
+               return false;
+       }
+       $table = reset($infos);
+
+       $r = array();
+
+       // valeurs non SQL
+       foreach ($col as $champ) {
+               if (function_exists($f = 'valeur_champ_'.$table.'_'.$champ)
+                       or function_exists($f = 'valeur_champ_'.$champ)) {
+                       $r[$champ] = $f($table, $id, $champ);
+                       $col = array_diff($col, array($champ));
+               }
+       }
+
+       // valeurs SQL
+       if (count($col)) {
+               list($distant, $table)   = distant_table($type);
+               list($nom_table, $where) = table_where($type, $id);
+
+               if ($s = spip_query(
+                       'SELECT `' . implode($col, '`, `') .
+                       '` FROM ' . $nom_table . ' WHERE ' . $where,
+                       $distant
+               ) and $t = sql_fetch($s)) {
+                               $r = array_merge($r, $t);
+               }
+       }
+
+       return $r;
+}
+
+/**
+ * Extrait la valeur d'une ou plusieurs colonnes d'une table
+ *
+ * @param string $table
+ *   Type d'objet de la table (article)
+ * @param string|array $col
+ *   Nom de la ou des colonnes (ps)
+ * @param string $id
+ *   Identifiant de l'objet
+ * @return array
+ *   Couples Nom de la colonne => Contenu de la colonne
+**/
+function valeur_colonne_table($table, $col, $id) {
+       if (!is_array($col)) {
+               $col = array($col);
+       }
+
+       if (function_exists($f = $table . '_valeur_colonne_table_dist')
+               or function_exists($f = $table.'_valeur_colonne_table')
+               or $f = 'valeur_colonne_table_dist') {
+               return $f($table, $col, $id);
+       }
+}
+
+/**
+ * Extrait la valeur d'une configuration en meta
+ *
+ * Pour ces données, il n'y a toujours qu'une colonne (valeur),
+ * mais on gère l'enregistrement et la lecture via lire_config ou ecrire_config
+ * dès que l'on demande des sous parties d'une configuration.
+ *
+ * On ne retourne alors ici dans 'valeur' que la sous-partie demandée si
+ * c'est le cas.
+ *
+ * @param string $table
+ *   Nom de la table (meta)
+ * @param array $col
+ *   Nom des colonnes (valeur)
+ * @param string $id
+ *   Nom ou clé de configuration (descriptif_site ou demo__truc pour demo/truc)
+ * @return array
+ *   Couple valeur => Contenu de la configuration
+**/
+function meta_valeur_colonne_table_dist($table, $col, $id) {
+       // Certaines clés de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})
+       $id = str_replace('__', '/', $id);
+
+       // Éviter de planter les vieux SPIP
+       if (false === strpos($id, '/')) {
+               $config = isset($GLOBALS['meta'][$id]) ? $GLOBALS['meta'][$id] : '';
+       // SPIP 3 ou Bonux 2 ou CFG
+       } else {
+               include_spip('inc/config');
+               $config =  lire_config($id, '');
+       }
+       return array('valeur' => $config);
+}
+
+
+function return_log($var) {
+       die(crayons_json_export(array('$erreur'=> var_export($var, true))));
+}
+
+function _U($texte, $params = array()) {
+       include_spip('inc/charsets');
+       return unicode2charset(html2unicode(_T($texte, $params)));
+}
+
+/**
+ * Obtenir la configuration des crayons
+ *
+ * @note wdgcfg = widget config :-)
+ *
+ * @return array
+ *     Couples : attribut => valeur
+**/
+function wdgcfg() {
+       $php = function_exists('crayons_config') ? crayons_config() : array();
+       include_spip('inc/meta');
+       lire_metas();
+       global $meta;
+       $metacrayons = empty($meta['crayons']) ? array() : unserialize($meta['crayons']);
+       $wdgcfg = array();
+       foreach (array(
+               'msgNoChange' => false,
+               'msgAbandon' => false,  /* etait: true */
+               'filet' => false,
+               'yellow_fade' => false,
+               'clickhide' => false /* etait: true */
+       ) as $cfgi => $def) {
+               $wdgcfg[$cfgi] = isset($php[$cfgi]) ? $php[$cfgi] :
+                       isset($metacrayons[$cfgi]) ? $metacrayons[$cfgi] : $def;
+       }
+       return $wdgcfg;
+}
+
+function &crayons_get_table($type, &$nom_table) {
+       list($distant,$table) = distant_table($type);
+       static $return = array();
+       static $noms = array();
+       if (!isset($return[$table])) {
+               $try = array(table_objet_sql($table), 'spip_'.table_objet($table), 'spip_' . $table . 's', $table . 's', 'spip_' . $table, $table);
+
+               // premiere possibilite (à partir de 1.9.3) : regarder directement la base
+               if (function_exists('sql_showtable')) {
+                       foreach ($try as $nom) {
+                               if ($q = sql_showtable($nom, !$distant, $distant)) {
+                                       $noms[$table] = $nom;
+                                       $return[$table] = $q;
+                                       break;
+                               }
+                       }
+               }
+
+               // seconde, une heuristique 1.9.2
+               if (!isset($return[$table])) {
+                       include_spip('base/serial');
+                       include_spip('base/auxiliaires');
+                       include_spip('public/parametrer');
+                       foreach (array('tables_principales', 'tables_auxiliaires') as $categ) {
+                               foreach ($try as $nom) {
+                                       if (isset($GLOBALS[$categ][$nom])) {
+                                               $noms[$table] = $nom;
+                                               $return[$table] = & $GLOBALS[$categ][$nom];
+                                               break 2;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       $nom_table = $noms[$table];
+       return $return[$table];
+}
+
+function distant_table($type) {
+       //separation $type en $distant $table
+       //separateur double underscore "__"
+       strstr($type, '__') ? list($distant,$table) = explode('__', $type) : list($distant, $table) = array(false, $type);
+       return array($distant,$table);
+}