source: spip-zone/_plugins_/step/inc/step.php @ 34251

Last change on this file since 34251 was 34251, checked in by marcimat@…, 10 years ago

Sortons STEP de la steppe...
Ce nom n'est pas définitif. Pour l'instant il signifie «Système de téléchargement de plugins»

Ce plugin a pour vocation de faciliter la recherche, l'installation et la mise à jour de plugins SPIP. Il fonctionne -actuellement- avec SPIP 2.0.10 et PHP5 (pour scandir)

Il n'est pas terminé et est en phase de développement encore.
Aucune mise à jour de sa base de donnée ne sera effectuée avant une version de test (i.e si le plugin se met à planter suite à une mise à jour, il faut le désinstaller et le réactiver).

Ce plugin se veut être (pour l'instant) comme une sorte de "Synaptic" pour SPIP (pour ceux qui connaissent Ubuntu) en un tout petit peu plus convivial.


Lire le fichier TODO pour la liste des taches à réaliser.

File size: 18.8 KB
Line 
1<?php
2
3if (!defined("_ECRIRE_INC_VERSION")) return;
4
5define('_FILE_PLUGIN_CONFIG', "plugin.xml");
6
7
8// ---------------------- LIBS -------------------------------
9
10// Faire la liste des librairies disponibles
11// retourne un array ( nom de la lib => repertoire , ... )
12function step_lister_librairies() {
13        $libs = array();
14        foreach (array_reverse(creer_chemin()) as $d) {
15                if (is_dir($dir = $d.'lib/')
16                AND $t = @opendir($dir)) {
17                        while (($f = readdir($t)) !== false) {
18                                if ($f[0] != '.'
19                                AND is_dir("$dir/$f"))
20                                        $libs[$f] = $dir;
21                        }
22                }
23        }
24        return $libs;
25}
26
27
28
29// retourne un cadre contenant la liste des librairies disponibles dans /lib
30function step_html_liste_librairies_presentes(){
31        // Lister les librairies disponibles
32        $res = "";
33        if ($libs = step_lister_librairies()) {
34                ksort($libs);
35                $res = '<ul>';
36                foreach ($libs as $lib => $rep)
37                        $res .= "<li title='".joli_repertoire($rep)."'>$lib</li>\n";
38                $res .= '</ul>';
39        }
40        return $res;   
41}
42
43
44
45
46// ---------------------- ZONES de PLUGINS -------------------------------
47
48// Met a jour les zones de plugins
49function step_update(){
50
51
52        // proposition d'action :
53        // 1) lister tous les plugins locaux actifs et les afficher
54        // 2) lister tous les plugins locaux inactifs (prefixe different des actifs)
55        //   3) lister les plugins locaux actifs dont une maj existe en local (?)
56        //   4) lister les plugins locaux inactifs plus anciens (?)
57        // 5) lister les plugins distants : comparer a la fois l'etat (stable...) et la version
58        //    et lister 1 prefix par etat (la version la plus recente)
59        // 6) si ce plugin est deja present en local... on propose une mise a jour.
60       
61        // actualiser les plugins locaux
62        step_actualiser_plugins_locaux();
63       
64        // actualiser les plugins distants
65        $res = sql_select(array('id_zone','adresse'),'spip_zones_plugins');
66        while ($r = sql_fetch($res)){
67                step_actualiser_zone($r['adresse']);
68        }
69}
70
71
72
73// Teste la validite d'une url d'une zone de paquets
74function step_verifier_adresse_zone($url){
75        return preg_match(',^https?://[^.]+\.[^.]+.*/.*[^/]$,', $url);
76}
77
78
79
80
81
82// Ajoute une zone de paquets
83// (xml d'une liste de plugin)
84// a la liste des zones de SPIP
85// et ajoute les plugins associes dans la table spip_plugins
86function step_ajouter_zone($url){
87        $url = trim($url);
88
89        // mauvaise adresse
90        if (!step_verifier_adresse_zone($url))
91                return;
92               
93        // adresse deja presente
94        if (sql_countsel('spip_zones_plugins', 'adresse='.sql_quote($url))){
95                return;
96        }
97
98        // lire les donnees d'une zone de plugins
99        $paquets = step_xml_parse_zone($url);
100       
101        if (count($paquets)){
102                // nom et description a definir dans le fichier xml de la source ?
103                $nom = $url;
104                $id_zone = sql_insertq('spip_zones_plugins', array('nom'=>$nom, 'adresse'=>$url, 'nombre_plugins'=>count($paquets)));
105               
106                // ajouter les plugins dans spip_plugins
107                step_maj_liste_plugins($id_zone, $paquets);
108        }
109       
110        return count($paquets);
111}
112
113
114
115
116
117// actualise une zone de plugins
118// $id = adresse zone OU id_zone dans la table spip_zones_plugins
119function step_actualiser_zone($id){
120        $id = trim($id);
121       
122        // pas de zone a cette adresse ?
123        if (!$z = sql_fetsel(array('id_zone', 'adresse'), 'spip_zones_plugins', 'adresse=' . sql_quote($id) . ' OR id_zone='. sql_quote($id)) ){
124                return;
125        }
126       
127        // lire les donnees d'une zone de plugins
128        $paquets = step_xml_parse_zone($z['adresse']);
129       
130        if (count($paquets)){
131                // nom et description a definir dans le fichier xml de la source ?
132                $nom = $url = $z['adresse'];
133                sql_updateq('spip_zones_plugins', array(
134                                'nom'=>$nom, 
135                                'adresse'=>$url, 
136                                'nombre_plugins'=>count($paquets)), 
137                                'id_zone=' . sql_quote($z['id_zone'])
138                );
139               
140                // actualiser les plugins dans spip_plugins
141                step_maj_liste_plugins($z['id_zone'], $paquets);
142        }
143}
144
145
146
147// actualise la liste des plugins locaux presents et installes
148function step_actualiser_plugins_locaux(){
149       
150        if ($plugins = step_liste_plugin_files()) {
151                // connaitre la liste des plugins actuellement actifs
152                $actifs = step_liste_plugin_actifs();
153                $recents = step_liste_plugin_recents();
154
155                include_spip('inc/xml');
156                // recuperer les plugins.xml
157                // et mettre a jour la bdd...
158                // si le plugin n'est pas activable,
159                // on ne l'affiche pas non plus
160                sql_delete('spip_plugins','id_zone=' . sql_quote(0));
161
162                foreach($plugins as $constante=>$liste) {
163                        foreach ($liste as $p) {
164                                step_actualiser_plugin_local($constante, $p, $actifs, $recents);
165                        }               
166                }
167        }
168}
169
170
171function step_actualiser_plugin_local($constante, $p, $actifs, $recents) {
172        $dir = constant($constante);
173        lire_fichier($dir . $p . '/' . _FILE_PLUGIN_CONFIG, $xml);
174        // enlever la balise doctype qui provoque une erreur "balise non fermee" lors du parsage
175        $xml = preg_replace('#<!DOCTYPE[^>]*>#','',$xml);
176        // traduire le xml en php
177        if (is_array($plugin = spip_xml_parse($xml)) and $plugin = $plugin['plugin'][0]){
178                // applatir les champs du plugin (ie les balises <multi> sont des chaines...)
179                if ($insert = step_xml_parse_plugin($plugin)) {
180                        // recuperer les champs sql utiles
181                        if ($insert = step_selectionner_champs_sql_plugin($insert)) {
182                                $insert['id_zone'] = 0;
183                                $insert['present'] = 'oui';
184                                $insert['constante'] = $constante; 
185                                $insert['dossier'] = $p . '/'; 
186                                $prefix = strtoupper($insert['prefixe']);
187                                // flag sur plugin actif et installe
188                                if (is_array($actifs[$prefix])
189                                and ($actifs[$prefix]['dir'] == $p)) {
190                                        $insert['actif'] = 'oui';
191                                        if (step_plugin_est_installe($p))
192                                                $insert['installe'] = 'oui';
193                                }
194                                // flag sur plugin utilise recemment
195                                if (isset($recents[$p]) and $recents[$p]) {
196                                        $insert['recent'] = 1; // si on met la valeur, il sera difficile d'appliquer {recent?}
197                                }
198                                // flag s'il existe une version plus stable ou plus recente
199                                // (seulement si le plugin n'est pas actif)
200                                // et on rend obsolete, inversement, les plugins que l'on perime                                       
201                                if ($res = sql_select(array('id_plugin','version','etatnum'),'spip_plugins',array(
202                                        'id_zone=' . sql_quote(0),
203                                        'prefixe=' . sql_quote($insert['prefixe'])))
204                                AND sql_count($res)) {
205                                        $invalides = array();
206                                        while ($r = sql_fetch($res)) {
207                                                // nota ; idem aux plugs des zones... il faudrait
208                                                // par defaut ne juger que le numero de version, et non l'etat
209                                                // en attandant, si (v3 stable et v4 test) on affiche les 2
210                                               
211                                                // si version <= moi et etat <= moi, on invalide ce plugin
212                                                if (version_compare($r['version'],$insert['version'],'<=') and ($r['etatnum'] <= $insert['etatnum'])) {
213                                                        $invalides[] = $r['id_plugin'];
214                                                }
215                                                if ($insert['actif'] != 'oui') {
216                                                        // s'il existe un plugin en tout point mieux, je m'invalide
217                                                        if ((version_compare($r['version'],$insert['version'],'>') and ($r['etatnum'] >= $insert['etatnum']))
218                                                        or  (version_compare($r['version'],$insert['version'],'>=') and ($r['etatnum'] > $insert['etatnum']))
219                                                        ) {
220                                                                $insert['obsolete'] = 'oui';
221                                                        }
222                                                }
223                                        }
224                                        if ($invalides) {
225                                                sql_updateq('spip_plugins',array('obsolete'=>'oui'), sql_in('id_plugin', $invalides));
226                                        }
227                                }                                                               
228
229                                // on recherche d'eventuelle mises a jour existantes
230                                if ($res = sql_select(array('id_plugin','version','superieur'),'spip_plugins',array(
231                                        'actif=' . sql_quote('non'),
232                                        'id_zone>' . sql_quote(0),
233                                        'prefixe=' . sql_quote($insert['prefixe']),
234                                        'etatnum>=' . sql_quote($insert['etatnum'])))
235                                AND sql_count($res)) {
236                                        $superieurs = array();
237                                        while ($r = sql_fetch($res)) {
238                                                // si version superieure et etat identique ou meilleur,
239                                                // c'est que c'est une mise a jour possible !
240                                                if (version_compare($r['version'],$insert['version'],'>')) {
241                                                        if (!$insert['maj_version'] or version_compare($r['version'], $insert['maj_version'],'>')) {
242                                                                $insert['maj_version'] = $r['version'];
243                                                        }
244                                                }
245                                                if ($r['superieur'] != 'oui') {
246                                                        $superieurs[] = $r['id_plugin'];
247                                                }
248                                        }
249                                        if ($superieurs) {
250                                                sql_updateq('spip_plugins',array('superieur'=>'oui'), sql_in('id_plugin', $superieurs));
251                                        }
252                                }                               
253                               
254                                return sql_insertq('spip_plugins', $insert);   
255                        }
256                }                                       
257        }
258}
259
260
261// supprime une zone de plugins (et sa liste de plugins)
262// $id = adresse zone OU id_zone dans la table spip_zones_plugins
263// ainsi que les entrees associes dans la table spip_plugins
264function step_supprimer_zone($id){
265        $id = trim($id);
266       
267        // pas de zone a cette adresse ?
268        if (!$id_zone = sql_getfetsel('id_zone', 'spip_zones_plugins', 'adresse=' . sql_quote($id) . ' OR id_zone='. sql_quote($id)) ){
269                return;
270        }
271
272        sql_delete('spip_plugins','id_zone='.sql_quote($id_zone));
273        sql_delete('spip_zones_plugins','id_zone='.sql_quote($id_zone));
274        return true;
275}
276
277
278
279// met a jour la liste des plugins d'une zone donnee
280function step_maj_liste_plugins($id_zone, $liste) {
281
282        if ($id_zone and is_array($liste)) {
283                sql_delete('spip_plugins','id_zone=' . sql_quote($id_zone));
284                foreach ($liste as $file=>$p) {
285                        if ($insert = step_selectionner_champs_sql_plugin($p['plugin'])) {
286                                $insert['id_zone'] = $id_zone;
287                                $insert['paquet'] = $file;
288                                // on ajoute le plugin uniquement s'il est nouveau
289                                // ou de version superieure (etat et prefixe identiques)
290
291                                // le jour ou on aura des zones de plugins / etat, on pourra
292                                // rendre obsolete uniquement avec le numero de version
293                                // en attendant lorsque (v3 stable, et v4 test existent, on propose les 2)
294                                if ($res = sql_select(array('id_plugin','id_zone','version'),'spip_plugins',array(
295                                        'etatnum<=' . sql_quote($insert['etatnum']),
296                                        'prefixe=' . sql_quote($insert['prefixe'])))
297                                AND sql_count($res))
298                                {
299                                        $add = false;
300                                        while ($r = sql_fetch($res)) {
301                                                // 2 possibilites :
302                                                // - plus recent : on le met,
303                                                //     + on met un flag sur les locaux... (maj_version)
304                                                //     + on supprime les distants plus vieux
305                                                // - plus ancien : on le met pas...
306                                                if (version_compare($insert['version'], $r['version'],'>')) {
307                                                        $add = true;
308                                                        if ($r['id_zone'] == 0) {
309                                                                sql_updateq('spip_plugins',array('maj_version'=>$insert['version']),'id_plugin='.sql_quote($r['id_plugin']));
310                                                                $insert['superieur'] = 'oui'; // dire que ce plugin est une mise a jour d'un plugin deja actif
311                                                        } else {
312                                                                // il y a un cas qui pose probleme :
313                                                                // - si on ne met pas les plugins aux versions identiques des zones distantes
314                                                                // - si on supprime le paquet local (avec ses fichiers)
315                                                                // - une recherche ne trouvera plus le paquet (vu qu'il ne sera pas dans la bdd)
316                                                                // cela oblige a actualiser les sources de plugins pour recalculer.
317                                                                // on laisse comme cela pour l'instant.
318                                                                sql_delete('spip_plugins','id_plugin='.sql_quote($r['id_plugin']));
319                                                        }
320                                                }
321                                        }
322                                        if ($add) sql_insertq('spip_plugins',$insert);
323                                } else {
324                                        sql_insertq('spip_plugins',$insert);
325                                }
326                        }
327                }
328        } 
329}
330
331
332// passe simplement un '[version;version]'
333function step_verifier_plugin_compatible_version_spip($version){
334        $version_spip = $GLOBALS['spip_version_branche'].".".$GLOBALS['spip_version_code'];
335        return step_plugin_version_compatible($version, $version_spip);
336}
337
338
339
340// Les archives xml sont deja applaties, pas la peine de se compliquer.
341function step_selectionner_champs_sql_plugin($p) {
342
343        // calcul du tableau de dependances
344        // Et on ne propose pas de plugin ne fonctionnant pas
345        // avec notre version de SPIP
346        $dependances = array();
347        if (is_array($p['necessite'])) {
348                foreach ($p['necessite'] as $c=>$n) {
349                        if ($n['id'] == 'SPIP') {
350                                if (!step_verifier_plugin_compatible_version_spip($n['version'])) {
351                                        return false;
352                                }
353                                break;
354                        }
355                        $p['necessite'][$c]['id'] = strtolower($n['id']);
356                }
357                $dependances['necessite'] = $p['necessite'];
358        }
359       
360        if (is_array($p['utilise'])) {
361                foreach ($p['utilise'] as $c=>$n) {
362                        $p['utilise'][$c]['id'] = strtolower($n['id']);
363                }
364                $dependances['utilise'] = $p['utilise'];
365        }
366
367        // etat numerique (pour simplifier la recherche de maj)
368        $num = array('stable'=>4, 'test'=>3, 'dev'=>2, 'experimental'=>1);
369        $etatnum = isset($num[$p['etat']]) ? $num[$p['etat']] : 0;
370        return array(
371                'nom' => $p['nom'],
372                'prefixe' => $p['prefix'],
373                'auteur' => $p['auteur'],
374                'version' => $p['version'],
375                'version_base' => $p['version_base'],
376                'licence' => $p['licence'],
377                'shortdesc' => $p['shortdesc'],
378                'description' => $p['description'],
379                'dependances' => serialize($dependances),
380                'etat' => $p['etat'],
381                'etatnum' => $etatnum,
382                'actif' => 'non',
383                'installe' => 'non',
384                'logo' => $p['icon'],
385                'categorie' => $p['categorie'],
386                'tags' => $p['tags'],
387        );
388}
389
390
391
392// ----------------------- Verifications de versions
393
394// fonction de SPIP inc/plugins
395function step_plugin_version_compatible($intervalle,$version){
396        if (!strlen($intervalle)) return true;
397        if (!preg_match(',^[\[\(]([0-9.a-zRC\s]*)[;]([0-9.a-zRC\s]*)[\]\)]$,',$intervalle,$regs)) return false;
398        $mineure = $regs[1];
399        $majeure = $regs[2];
400        $mineure_inc = $intervalle{0}=="[";
401        $majeure_inc = substr($intervalle,-1)=="]";
402        #var_dump("$mineure_inc-$mineure-$majeure-$majeure_inc");
403        if (strlen($mineure)){
404                if ($mineure_inc AND version_compare($version,$mineure,'<')) return false;
405                if (!$mineure_inc AND version_compare($version,$mineure,'<=')) return false;
406        }
407        if (strlen($majeure)){
408                if ($majeure_inc AND version_compare($version,$majeure,'>')) return false;
409                if (!$majeure_inc AND version_compare($version,$majeure,'>=')) return false;
410        }
411        return true;
412}
413
414
415
416
417
418// ----------------------- Analyses XML ---------------------------------
419
420
421// parse un fichier de source dont l'url est donnee
422// ce fichier est un fichier XML contenant <zone><zone_elt/></zone>
423function step_xml_parse_zone($url){
424        include_spip('inc/xml');
425
426        $arbre = array();
427       
428        include_spip('inc/distant');
429        if (!$xml = recuperer_page($url)) {
430                return false;
431        }
432
433        // enlever la balise doctype qui provoque une erreur "balise non fermee" lors du parsage
434        $xml = preg_replace('#<!DOCTYPE[^>]*>#','',$xml);
435        if (!is_array($arbre = spip_xml_parse($xml)) OR !is_array($arbre = $arbre['archives'][0])){
436                return false;
437        }
438
439        // boucle sur les elements pour creer un tableau array (url_zip => datas)
440        $paquets = array();                     
441        foreach ($arbre as $z=>$c){
442                $c = $c[0];
443                // si plugin et fichier zip, on ajoute le paquet dans la liste
444                if ((is_array($c['plugin'])) AND ($url = $c['file'][0])) {
445                        $paquets[$url] = array(
446                                'plugin' => step_xml_parse_plugin($c['plugin'][0]), 
447                                'file' => $url, 
448                        );
449                }
450        }
451        if (!$paquets) {
452                return false;
453        }
454       
455        return $paquets;
456}
457
458// aplatit plusieurs cles d'un arbre xml dans un tableau
459// effectue un trim() au passage
460function step_xml_aplatit_multiple($array, $arbre){
461        $a = array();
462        // array('uri','archive'=>'zip',...)
463        foreach ($array as $i=>$n){
464                if (is_string($i)) $cle = $i;
465                else $cle = $n;
466                $a[$n] = trim(spip_xml_aplatit($arbre[$cle]));
467        }
468        return $a;     
469}
470
471
472// parse un plugin.xml genere par spip_xml_parse()
473// en un tableau plus facilement utilisable
474// cette fonction doit permettre de mapper des changements
475// de syntaxe entre plugin.xml et step
476function step_xml_parse_plugin($arbre){
477
478        if (!is_array($arbre)) 
479                return false;
480       
481        // on commence par les simples !
482        $plug_arbre = step_xml_aplatit_multiple(
483                                array('nom','icon','auteur','licence','version','version_base','etat','shortdesc','categorie','tags',
484                                'description','lien','options','fonctions','prefix','install'), 
485                                $arbre);
486        $plug_arbre['prefix'] = strtolower($plug_arbre['prefix']);
487       
488        // on continue avec les plus complexes...       
489        // 1) balises avec attributs
490        foreach (array(
491                        'necessite'=>array('necessite', null),
492                        'utilise'=>array('utilise', null),
493                        'chemin'=>array('path', array('dir'=>'')))
494                                as $balise=>$p){
495                $params = $res = array();
496                // recherche de la balise et extraction des attributs
497                if (spip_xml_match_nodes(",^$balise,",$arbre, $res)){
498                        foreach(array_keys($res) as $tag){
499                                list($tag,$att) = spip_xml_decompose_tag($tag);
500                                $params[] = $att;
501                        }
502                } 
503                // valeur par defaut
504                else {
505                        if ($p[1]!==null)
506                                $params[] = $p[1];
507                }
508                $plug_arbre[$p[0]] = $params;           
509        }
510
511        // 2) balises impriquees
512        // (pipeline, boutons, onglets)
513        // on verra plus tard si besoin !
514
515        return $plug_arbre;
516}
517
518
519
520
521
522
523// ------------------- A peu de chose pres dans le core ----------------
524
525
526// retourne le chemin d'une image contenu dans images/
527function step_chemin_image($icone){
528        return find_in_path($icone, _NOM_IMG_PACK);
529}
530
531
532
533// -------------------- Autorisations ----------------------------
534
535// teste si l'on peut ecrire un plugin dans un repertoire donne
536function autoriser_plugins_telecharger($faire, $type, $id, $qui, $opt){
537       
538        if (
539                !_AUTORISER_TELECHARGER_PLUGINS
540                OR !step_verifier_droit_ecriture()
541                OR !autoriser('configurer', $type, $id, $qui, $opt)
542        ) return false;
543       
544        return true;
545}
546
547// verifie que l'on peut ecrire dans le repertoire donne
548function step_verifier_droit_ecriture($dir = _DIR_PLUGINS2){
549        if ($dir)
550                return is_dir($dir) AND is_writable($dir);
551        else 
552                return false;   
553}
554
555
556// ------------------------ Recherche des plugins locaux ------------
557
558// Retourne la liste de tous les plugins d'un repertoire donne
559// ou d'un tableau de repertoires
560// (modif de la fonction de spip 2.1)
561function step_liste_plugin_files($dir_plugins = ""){
562        static $plugin_files=array();
563
564        if (!$dir_plugins) {
565                $dir_plugins = array(
566                        '_DIR_PLUGINS',
567                        '_DIR_EXTENSIONS',
568                );
569                // plugins supp (1 seul dossier)
570                if (defined('_DIR_PLUGINS_SUPP')) {$dir_plugins[] = '_DIR_PLUGINS_SUPP';}
571        }
572       
573        // tableau
574        if (is_array($dir_plugins)) {
575                foreach ($dir_plugins as $dir) {
576                        $plugin_files[$dir] = step_liste_plugin_files($dir);
577                }
578                return $plugin_files;
579        }
580       
581        // solo
582        if (!isset($plugin_files[$dir_plugins])
583        OR count($plugin_files[$dir_plugins]) == 0){
584                $plugin_files[$dir_plugins] = array();
585                foreach (preg_files(constant($dir_plugins), '/plugin[.]xml$') as $plugin) {
586                        $plugin_files[$dir_plugins][] = str_replace(constant($dir_plugins),'',dirname($plugin));
587                }
588                sort($plugin_files[$dir_plugins]);
589        }
590
591        return $plugin_files[$dir_plugins];
592}
593
594
595
596// ----------------------- Connaitre les plugins actifs, recents et desinstallables
597
598
599// de inc/plugins
600function step_liste_plugin_actifs(){
601        $meta_plugin = isset($GLOBALS['meta']['plugin'])?$GLOBALS['meta']['plugin']:'';
602        if (strlen($meta_plugin)>0){
603                if (is_array($t=unserialize($meta_plugin)))
604                        return $t;
605        }
606        return array();
607}
608
609
610// liste des plugins utilises recemment
611function step_liste_plugin_recents(){
612        $meta_plugin = isset($GLOBALS['meta']['plugins_interessants'])?$GLOBALS['meta']['plugins_interessants']:'';
613        if (strlen($meta_plugin)>0){
614                if (is_array($t=unserialize($meta_plugin)))
615                        return $t;
616        }
617        return array();
618}
619
620
621
622function step_plugin_est_installe($plug_path){
623        $plugin_installes = isset($GLOBALS['meta']['plugin_installes'])?unserialize($GLOBALS['meta']['plugin_installes']):array();
624        if (!$plugin_installes) return false;
625        return in_array($plug_path,$plugin_installes);
626}
627
628
629function step_selectionner_maj() {
630        $ids = array();
631        if ($res = sql_select('id_plugin','spip_plugins',array(
632                'maj_version<>' .sql_quote(''),
633                'id_zone='.sql_quote(0),
634                'obsolete='.sql_quote('non')))) {
635                        while ($r = sql_fetch($res)) {
636                                $ids[] = $r['id_plugin'];
637                        }
638        }
639        return $ids;
640}
641
642?>
Note: See TracBrowser for help on using the repository browser.