source: spip-zone/_plugins_/iterateurs/iterateur/data.php @ 43305

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

meilleure gestion des CSV, report de http://core.spip.org/projects/export/repository/revisions/16881/

File size: 10.6 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  SPIP, Systeme de publication pour l'internet                           *
5 *                                                                         *
6 *  Copyright (c) 2001-2011                                                *
7 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
8 *                                                                         *
9 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
10 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
11\***************************************************************************/
12
13if (!defined('_ECRIRE_INC_VERSION')) return;
14
15include_spip('iterateur/iterateur');
16
17
18//
19// creer une boucle sur un iterateur DATA
20// annonce au compilo les "champs" disponibles
21//
22function iterateur_DATA_dist($b) {
23        $b->iterateur = 'DATA'; # designe la classe d'iterateur
24        $b->show = array(
25                'field' => array(
26                        'cle' => 'STRING',
27                        'valeur' => 'STRING',
28                        '*' => 'ALL'
29                )
30        );
31        $b->select[] = '.valeur';
32        return $b;
33}
34
35
36/**
37 * IterateurDATA pour iterer sur des donnees
38 */
39class IterateurDATA implements Iterator {
40        /**
41         * tableau de donnees
42         * @var array
43         */
44        protected $tableau = array();
45
46        /**
47         * Conditions de filtrage
48         * ie criteres de selection
49         * @var array
50         */
51        protected $filtre = array();
52
53
54        /**
55         * Cle courante
56         * @var null
57         */
58        protected $cle = null;
59
60        /**
61         * Valeur courante
62         * @var null
63         */
64        protected $valeur = null;
65
66        /**
67         * Constructeur
68         *
69         * @param  $command
70         * @param array $info
71         */
72        public function __construct($command, $info=array()) {
73                $this->type='DATA';
74                $this->command = $command;
75                $this->info = $info;
76
77                $this->select($command);
78        }
79
80        /**
81         * Revenir au depart
82         * @return void
83         */
84        public function rewind() {
85                reset($this->tableau);
86                list($this->cle, $this->valeur) = each($this->tableau);
87        }
88
89        public function exception_des_criteres() {
90                return array('tableau');
91        }
92
93        protected function cache_get($cle) {
94                if (!$cle) return;
95                # utiliser memoization si dispo
96                include_spip('inc/memoization');
97                if (!function_exists('cache_get')) return;
98                return cache_get($cle);
99        }
100
101        protected function cache_set($cle, $ttl) {
102                if (!$cle) return;
103                # utiliser memoization si dispo
104                include_spip('inc/memoization');
105                if (!function_exists('cache_set')) return;
106                return cache_set($cle,
107                        array(
108                                'data' => $this->tableau,
109                                'time' => time(),
110                                'ttl' => $ttl
111                        ),
112                        3600 + $ttl);
113                        # conserver le cache 1h deplus que la validite demandee,
114                        # pour le cas ou le serveur distant ne repond plus
115        }
116
117        protected function select($command) {
118                // les commandes connues pour l'iterateur POUR/DATA
119                // sont : {tableau #ARRAY} ; cle=...; valeur=...
120                // source URL
121                if (isset($this->command['source'])
122                AND isset($this->command['sourcemode'])) {
123
124                        # un peu crado : avant de charger le cache il faut charger
125                        # les class indispensables, sinon PHP ne saura pas gerer
126                        # l'objet en cache ; cf plugins/icalendar
127                        if (isset($this->command['sourcemode']))
128                                charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true);
129
130                        # avons-nous un cache dispo ?
131                        if (is_string($this->command['source']))
132                                $cle = 'datasource_'.md5($this->command['sourcemode'].':'.$this->command['source']);
133                        $cache = $this->cache_get($cle);
134                        if (isset($this->command['datacache']))
135                                $ttl = intval($this->command['datacache']);
136                        if ($cache
137                        AND ($cache['time'] + (isset($ttl) ? $ttl : $cache['ttl'])
138                                > time())
139                        AND !(_request('var_mode') === 'recalcul'
140                                AND include_spip('inc/autoriser')
141                                AND autoriser('recalcul')
142                        )) {
143                                $this->tableau = $cache['data'];
144                        }
145                        else try {
146                                # dommage que ca ne soit pas une option de yql_to_array...
147                                if ($this->command['sourcemode'] == 'yql')
148                                        if (!isset($ttl)) $ttl = 3600;
149
150                                if (isset($this->command['sourcemode'])
151                                AND in_array($this->command['sourcemode'],
152                                        array('table', 'array', 'tableau'))
153                                ) {
154                                        if (is_array($a = $this->command['source'])
155                                        OR (is_string($a)
156                                        AND $a = str_replace('&quot;', '"', $a) # fragile!
157                                        AND is_array($a = @unserialize($a)))
158                                        )
159                                                $this->tableau = $a;
160                                }
161                                else if (preg_match(',^https?://,', $this->command['source'])) {
162                                        include_spip('inc/distant');
163                                        $u = recuperer_page($this->command['source']);
164                                        if (!$u)
165                                                throw new Exception("404");
166                                        if (!isset($ttl)) $ttl = 24*3600;
167                                } else if (@is_readable($this->command['source'])) {
168                                        $u = spip_file_get_contents($this->command['source']);
169                                        if (!isset($ttl)) $ttl = 10;
170                                } else {
171                                        $u = $this->command['source'];
172                                        if (!isset($ttl)) $ttl = 10;
173                                }
174
175                                if (!$this->err
176                                AND $g = charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true)) {
177                                        if (is_array($a = $g($u))) {
178                                                $this->tableau = $a;
179                                        }
180                                }
181
182                                if (!is_array($this->tableau))
183                                        $this->err = true;
184
185                                if (!$this->err AND $ttl>0)
186                                        $this->cache_set($cle, $ttl);
187
188                        }
189                        catch (Exception $e) {
190                                $e = $e->getMessage();
191                                $err = sprintf("[%s, %s] $e",
192                                        $this->command['source'],
193                                        $this->command['sourcemode']);
194                                erreur_squelette(array($err, array()));
195                                $this->err = true;
196                        }
197
198                        # en cas d'erreur, utiliser le cache si encore dispo
199                        if ($this->err
200                        AND $cache) {
201                                $this->tableau = $cache['data'];
202                                $this->err = false;
203                        }
204
205                }
206
207                // Critere {liste X1, X2, X3}
208                if (isset($this->command['liste'])) {
209                        $this->tableau = $this->command['liste'];
210                }
211
212                // Si a ce stade on n'a pas de table, il y a un bug
213                if (!is_array($this->tableau)) {
214                        $this->err = true;
215                        spip_log("erreur datasource ".$this->command['source']);
216                }
217
218
219                // {datapath query.results}
220                // extraire le chemin "query.results" du tableau de donnees
221                if (!$this->err
222                AND is_array($this->command['datapath'])) {
223                        list(,$base) = each($this->command['datapath']);
224                        if (strlen($base = trim($base))) {
225                                $this->tableau = Iterateurs_table_valeur($this->tableau, $base);
226                                if (!is_array($this->tableau)) {
227                                        $this->tableau = array();
228                                        $this->err = true;
229                                        spip_log("datapath '$base' absent");
230                                }
231                        }
232                }
233
234                // tri {par x}
235                if ($this->command['orderby']) {
236                        $sortfunc = '';
237                        foreach($this->command['orderby'] as $tri) {
238                                if (preg_match(',^\.?([/\w]+)( DESC)?$,iS', $tri, $r)) {
239                                        if ($r[1] == 'valeur')
240                                                $tv = '%s';
241                                        else if ($r[1] == 'alea') # {par hasard}
242                                                $tv = 'rand(0,1)';
243                                        else
244                                                $tv = 'Iterateurs_table_valeur(%s, '.var_export($r[1],true).')';
245                                        $sortfunc .= '
246                                        $a = '.sprintf($tv,'$aa').';
247                                        $b = '.sprintf($tv,'$bb').';
248                                        if ($a <> $b)
249                                                return ($a ' . ($r[2] ? '>' : '<').' $b) ? -1 : 1;';
250                                }
251                        }
252
253                        if ($sortfunc) {
254                                uasort($this->tableau, create_function('$aa,$bb',
255                                        $sortfunc.'
256                                        return 0;'
257                                ));
258                        }
259                }
260
261                // grouper les resultats {fusion /x/y/z} ;
262                if ($this->command['groupby']
263                AND strlen($fusion = $this->command['groupby'][0])) {
264                        $vu = array();
265                        foreach($this->tableau as $k => $v) {
266                                $val = Iterateurs_table_valeur($v, $fusion);
267                                if (isset($vu[$val]))
268                                        unset($this->tableau[$k]);
269                                else
270                                        $vu[$val] = true;
271                        }
272                }
273
274                $this->rewind();
275                #var_dump($this->tableau);
276        }
277
278
279        /**
280         * L'iterateur est-il encore valide ?
281         * @return bool
282         */
283        public function valid(){
284                return !is_null($this->cle);
285        }
286
287        /**
288         * Retourner la valeur
289         * @return null
290         */
291        public function current() {
292                return $this->valeur;
293        }
294
295        /**
296         * Retourner la cle
297         * @return null
298         */
299        public function key() {
300                return $this->cle;
301        }
302
303        /**
304         * Passer a la valeur suivante
305         * @return void
306         */
307        public function next(){
308                if ($this->valid())
309                        list($this->cle, $this->valeur) = each($this->tableau);
310        }
311
312        /**
313         * Compter le nombre total de resultats
314         * @return int
315         */
316        public function count() {
317                if (is_null($this->total))
318                        $this->total = count($this->tableau);
319          return $this->total;
320        }
321}
322
323
324function inc_file_to_array_dist($u) {
325        return preg_split('/\r?\n/', $u);
326}
327function inc_plugins_to_array_dist($u) {
328        include_spip('inc/plugin');
329        return liste_chemin_plugin_actifs();
330}
331function inc_xml_to_array_dist($u) {
332        return @ObjectToArray(new SimpleXmlIterator($u));
333}
334function inc_yql_to_array_dist($u) {
335        define('_YQL_ENDPOINT', 'http://query.yahooapis.com/v1/public/yql?&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&q=');
336        $v = recuperer_page($url = _YQL_ENDPOINT.urlencode($u).'&format=json');
337        $w = json_decode($v);
338        if (!$w) {
339                throw new Exception('YQL: r&#233;ponse vide ou mal form&#233;e');
340                return false;
341        }
342        return (array) $w;
343}
344function inc_sql_to_array_dist($u) {
345        # sortir le connecteur de $u
346        preg_match(',^(?:(\w+):)?(.*)$,S', $u, $v);
347        $serveur = (string) $v[1];
348        $req = trim($v[2]);
349        if ($s = sql_query($req, $serveur)) {
350                $r = array();
351                while ($t = sql_fetch($s))
352                        $r[] = $t;
353                return $r;
354        }
355        return false;
356}
357function inc_json_to_array_dist($u) {
358        if (is_array($json = json_decode($u))
359        OR is_object($json))
360                return (array) $json;
361}
362function inc_csv_to_array_dist($u) {
363        include_spip('inc/csv');
364        list($entete,$csv) = analyse_csv($u);
365        array_unshift($csv,$entete);
366
367        include_spip('inc/charsets');
368        foreach ($entete as $k => $v) {
369                $v = strtolower(preg_replace(',\W+,', '_', translitteration($v)));
370                foreach ($csv as &$item)
371                        $item[$v] = &$item[$k];
372        }
373        return $csv;
374}
375function inc_rss_to_array_dist($u) {
376        include_spip('inc/syndic');
377        if (is_array($rss = analyser_backend($u)))
378                $tableau = $rss;
379        return $tableau;
380}
381// atom, alias de rss
382function inc_atom_to_array_dist($u) {
383        $g = charger_fonction('rss_to_array', 'inc');
384        return $g($u);
385}
386// glob : lister des fichiers selon un masque, pour la syntaxe cf php.net/glob
387function inc_glob_to_array_dist($u) {
388        return (array) glob($u,
389                GLOB_MARK | GLOB_NOSORT | GLOB_BRACE
390        );
391}
392// ls : lister des fichiers selon un masque glob
393// et renvoyer aussi leurs donnees php.net/stat
394function inc_ls_to_array_dist($u) {
395        $glob = charger_fonction('glob_to_array', 'inc');
396        $a = $glob($u);
397        foreach ($a as &$v) {
398                $b = (array) @stat($v);
399                foreach ($b as $k => $ignore)
400                        if (is_numeric($k)) unset($b[$k]);
401                $b['file'] = basename($v);
402                $v = array_merge(
403                        pathinfo($v),
404                        $b
405                );
406        }
407        return $a;
408}
409
410function ObjectToArray($object){
411        $xml_array = array();
412        for( $object->rewind(); $object->valid(); $object->next() ) {
413                if(!array_key_exists($object->key(), $xml_array)){
414                        $xml_array[$object->key()] = array();
415                }
416                $vars = get_object_vars($object->current());
417                if (isset($vars['@attributes']))
418                        foreach($vars['@attributes'] as $k => $v)
419                        $xml_array[$object->key()][$k] = $v;
420                if($object->hasChildren()){
421                        $xml_array[$object->key()][] = ObjectToArray(
422                                $object->current());
423                }
424                else{
425                        $xml_array[$object->key()][] = strval($object->current());
426                }
427        }
428        return $xml_array;
429}
430?>
Note: See TracBrowser for help on using the repository browser.