source: lliurex-jocomunico/trunk/fuentes/lliurex-jocomunico.install/var/lib/application/libraries/Format.php @ 5728

Last change on this file since 5728 was 5728, checked in by joamuran, 3 years ago

Added zero-installed and updated jocomunico

  • Property svn:executable set to *
File size: 14.9 KB
Line 
1<?php
2
3defined('BASEPATH') OR exit('No direct script access allowed');
4
5/**
6 * Format class
7 * Help convert between various formats such as XML, JSON, CSV, etc.
8 *
9 * @author    Phil Sturgeon, Chris Kacerguis, @softwarespot
10 * @license   http://www.dbad-license.org/
11 */
12class Format {
13
14    /**
15     * Array output format
16     */
17    const ARRAY_FORMAT = 'array';
18
19    /**
20     * Comma Separated Value (CSV) output format
21     */
22    const CSV_FORMAT = 'csv';
23
24    /**
25     * Json output format
26     */
27    const JSON_FORMAT = 'json';
28
29    /**
30     * HTML output format
31     */
32    const HTML_FORMAT = 'html';
33
34    /**
35     * PHP output format
36     */
37    const PHP_FORMAT = 'php';
38
39    /**
40     * Serialized output format
41     */
42    const SERIALIZED_FORMAT = 'serialized';
43
44    /**
45     * XML output format
46     */
47    const XML_FORMAT = 'xml';
48
49    /**
50     * Default format of this class
51     */
52    const DEFAULT_FORMAT = self::JSON_FORMAT; // Couldn't be DEFAULT, as this is a keyword
53
54    /**
55     * CodeIgniter instance
56     *
57     * @var object
58     */
59    private $_CI;
60
61    /**
62     * Data to parse
63     *
64     * @var mixed
65     */
66    protected $_data = [];
67
68    /**
69     * Type to convert from
70     *
71     * @var string
72     */
73    protected $_from_type = NULL;
74
75    /**
76     * DO NOT CALL THIS DIRECTLY, USE factory()
77     *
78     * @param NULL $data
79     * @param NULL $from_type
80     * @throws Exception
81     */
82
83    public function __construct($data = NULL, $from_type = NULL)
84    {
85        // Get the CodeIgniter reference
86        $this->_CI = &get_instance();
87
88        // Load the inflector helper
89        $this->_CI->load->helper('inflector');
90
91        // If the provided data is already formatted we should probably convert it to an array
92        if ($from_type !== NULL)
93        {
94            if (method_exists($this, '_from_' . $from_type))
95            {
96                $data = call_user_func([$this, '_from_' . $from_type], $data);
97            }
98            else
99            {
100                throw new Exception('Format class does not support conversion from "' . $from_type . '".');
101            }
102        }
103
104        // Set the member variable to the data passed
105        $this->_data = $data;
106    }
107
108    /**
109     * Create an instance of the format class
110     * e.g: echo $this->format->factory(['foo' => 'bar'])->to_csv();
111     *
112     * @param mixed $data Data to convert/parse
113     * @param string $from_type Type to convert from e.g. json, csv, html
114     *
115     * @return object Instance of the format class
116     */
117    public function factory($data, $from_type = NULL)
118    {
119        // $class = __CLASS__;
120        // return new $class();
121
122        return new static($data, $from_type);
123    }
124
125    // FORMATTING OUTPUT ---------------------------------------------------------
126
127    /**
128     * Format data as an array
129     *
130     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
131     * to the constructor
132     * @return array Data parsed as an array; otherwise, an empty array
133     */
134    public function to_array($data = NULL)
135    {
136        // If no data is passed as a parameter, then use the data passed
137        // via the constructor
138        if ($data === NULL && func_num_args() === 0)
139        {
140            $data = $this->_data;
141        }
142
143        // Cast as an array if not already
144        if (is_array($data) === FALSE)
145        {
146            $data = (array) $data;
147        }
148
149        $array = [];
150        foreach ((array) $data as $key => $value)
151        {
152            if (is_object($value) === TRUE || is_array($value) === TRUE)
153            {
154                $array[$key] = $this->to_array($value);
155            }
156            else
157            {
158                $array[$key] = $value;
159            }
160        }
161
162        return $array;
163    }
164
165    /**
166     * Format data as XML
167     *
168     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
169     * to the constructor
170     * @param NULL $structure
171     * @param string $basenode
172     * @return mixed
173     */
174    public function to_xml($data = NULL, $structure = NULL, $basenode = 'xml')
175    {
176        if ($data === NULL && func_num_args() === 0)
177        {
178            $data = $this->_data;
179        }
180
181        // turn off compatibility mode as simple xml throws a wobbly if you don't.
182        if (ini_get('zend.ze1_compatibility_mode') == 1)
183        {
184            ini_set('zend.ze1_compatibility_mode', 0);
185        }
186
187        if ($structure === NULL)
188        {
189            $structure = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$basenode />");
190        }
191
192        // Force it to be something useful
193        if (is_array($data) === FALSE && is_object($data) === FALSE)
194        {
195            $data = (array) $data;
196        }
197
198        foreach ($data as $key => $value)
199        {
200
201            //change false/true to 0/1
202            if (is_bool($value))
203            {
204                $value = (int) $value;
205            }
206
207            // no numeric keys in our xml please!
208            if (is_numeric($key))
209            {
210                // make string key...
211                $key = (singular($basenode) != $basenode) ? singular($basenode) : 'item';
212            }
213
214            // replace anything not alpha numeric
215            $key = preg_replace('/[^a-z_\-0-9]/i', '', $key);
216
217            if ($key === '_attributes' && (is_array($value) || is_object($value)))
218            {
219                $attributes = $value;
220                if (is_object($attributes))
221                {
222                    $attributes = get_object_vars($attributes);
223                }
224
225                foreach ($attributes as $attribute_name => $attribute_value)
226                {
227                    $structure->addAttribute($attribute_name, $attribute_value);
228                }
229            }
230            // if there is another array found recursively call this function
231            elseif (is_array($value) || is_object($value))
232            {
233                $node = $structure->addChild($key);
234
235                // recursive call.
236                $this->to_xml($value, $node, $key);
237            }
238            else
239            {
240                // add single node.
241                $value = htmlspecialchars(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8');
242
243                $structure->addChild($key, $value);
244            }
245        }
246
247        return $structure->asXML();
248    }
249
250    /**
251     * Format data as HTML
252     *
253     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
254     * to the constructor
255     * @return mixed
256     */
257    public function to_html($data = NULL)
258    {
259        // If no data is passed as a parameter, then use the data passed
260        // via the constructor
261        if ($data === NULL && func_num_args() === 0)
262        {
263            $data = $this->_data;
264        }
265
266        // Cast as an array if not already
267        if (is_array($data) === FALSE)
268        {
269            $data = (array) $data;
270        }
271
272        // Check if it's a multi-dimensional array
273        if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE))
274        {
275            // Multi-dimensional array
276            $headings = array_keys($data[0]);
277        }
278        else
279        {
280            // Single array
281            $headings = array_keys($data);
282            $data = [$data];
283        }
284
285        // Load the table library
286        $this->_CI->load->library('table');
287
288        $this->_CI->table->set_heading($headings);
289
290        foreach ($data as $row)
291        {
292            // Suppressing the "array to string conversion" notice
293            // Keep the "evil" @ here
294            $row = @array_map('strval', $row);
295
296            $this->_CI->table->add_row($row);
297        }
298
299        return $this->_CI->table->generate();
300    }
301
302    /**
303     * @link http://www.metashock.de/2014/02/create-csv-file-in-memory-php/
304     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
305     * to the constructor
306     * @param string $delimiter The optional delimiter parameter sets the field
307     * delimiter (one character only). NULL will use the default value (,)
308     * @param string $enclosure The optional enclosure parameter sets the field
309     * enclosure (one character only). NULL will use the default value (")
310     * @return string A csv string
311     */
312    public function to_csv($data = NULL, $delimiter = ',', $enclosure = '"')
313    {
314        // Use a threshold of 1 MB (1024 * 1024)
315        $handle = fopen('php://temp/maxmemory:1048576', 'w');
316        if ($handle === FALSE)
317        {
318            return NULL;
319        }
320
321        // If no data is passed as a parameter, then use the data passed
322        // via the constructor
323        if ($data === NULL && func_num_args() === 0)
324        {
325            $data = $this->_data;
326        }
327
328        // If NULL, then set as the default delimiter
329        if ($delimiter === NULL)
330        {
331            $delimiter = ',';
332        }
333
334        // If NULL, then set as the default enclosure
335        if ($enclosure === NULL)
336        {
337            $enclosure = '"';
338        }
339
340        // Cast as an array if not already
341        if (is_array($data) === FALSE)
342        {
343            $data = (array) $data;
344        }
345
346        // Check if it's a multi-dimensional array
347        if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE))
348        {
349            // Multi-dimensional array
350            $headings = array_keys($data[0]);
351        }
352        else
353        {
354            // Single array
355            $headings = array_keys($data);
356            $data = [$data];
357        }
358
359        // Apply the headings
360        fputcsv($handle, $headings, $delimiter, $enclosure);
361
362        foreach ($data as $record)
363        {
364            // If the record is not an array, then break. This is because the 2nd param of
365            // fputcsv() should be an array
366            if (is_array($record) === FALSE)
367            {
368                break;
369            }
370
371            // Suppressing the "array to string conversion" notice.
372            // Keep the "evil" @ here.
373            $record = @ array_map('strval', $record);
374
375            // Returns the length of the string written or FALSE
376            fputcsv($handle, $record, $delimiter, $enclosure);
377        }
378
379        // Reset the file pointer
380        rewind($handle);
381
382        // Retrieve the csv contents
383        $csv = stream_get_contents($handle);
384
385        // Close the handle
386        fclose($handle);
387
388        return $csv;
389    }
390
391    /**
392     * Encode data as json
393     *
394     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
395     * to the constructor
396     * @return string Json representation of a value
397     */
398    public function to_json($data = NULL)
399    {
400        // If no data is passed as a parameter, then use the data passed
401        // via the constructor
402        if ($data === NULL && func_num_args() === 0)
403        {
404            $data = $this->_data;
405        }
406
407        // Get the callback parameter (if set)
408        $callback = $this->_CI->input->get('callback');
409
410        if (empty($callback) === TRUE)
411        {
412            return json_encode($data);
413        }
414
415        // We only honour a jsonp callback which are valid javascript identifiers
416        elseif (preg_match('/^[a-z_\$][a-z0-9\$_]*(\.[a-z_\$][a-z0-9\$_]*)*$/i', $callback))
417        {
418            // Return the data as encoded json with a callback
419            return $callback . '(' . json_encode($data) . ');';
420        }
421
422        // An invalid jsonp callback function provided.
423        // Though I don't believe this should be hardcoded here
424        $data['warning'] = 'INVALID JSONP CALLBACK: ' . $callback;
425
426        return json_encode($data);
427    }
428
429    /**
430     * Encode data as a serialized array
431     *
432     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
433     * to the constructor
434     * @return string Serialized data
435     */
436    public function to_serialized($data = NULL)
437    {
438        // If no data is passed as a parameter, then use the data passed
439        // via the constructor
440        if ($data === NULL && func_num_args() === 0)
441        {
442            $data = $this->_data;
443        }
444
445        return serialize($data);
446    }
447
448    /**
449     * Format data using a PHP structure
450     *
451     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
452     * to the constructor
453     * @return mixed String representation of a variable
454     */
455    public function to_php($data = NULL)
456    {
457        // If no data is passed as a parameter, then use the data passed
458        // via the constructor
459        if ($data === NULL && func_num_args() === 0)
460        {
461            $data = $this->_data;
462        }
463
464        return var_export($data, TRUE);
465    }
466
467    // INTERNAL FUNCTIONS
468
469    /**
470     * @param $data XML string
471     * @return SimpleXMLElement XML element object; otherwise, empty array
472     */
473    protected function _from_xml($data)
474    {
475        return $data ? (array) simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA) : [];
476    }
477
478    /**
479     * @param string $data CSV string
480     * @param string $delimiter The optional delimiter parameter sets the field
481     * delimiter (one character only). NULL will use the default value (,)
482     * @param string $enclosure The optional enclosure parameter sets the field
483     * enclosure (one character only). NULL will use the default value (")
484     * @return array A multi-dimensional array with the outer array being the number of rows
485     * and the inner arrays the individual fields
486     */
487    protected function _from_csv($data, $delimiter = ',', $enclosure = '"')
488    {
489        // If NULL, then set as the default delimiter
490        if ($delimiter === NULL)
491        {
492            $delimiter = ',';
493        }
494
495        // If NULL, then set as the default enclosure
496        if ($enclosure === NULL)
497        {
498            $enclosure = '"';
499        }
500
501        return str_getcsv($data, $delimiter, $enclosure);
502    }
503
504    /**
505     * @param $data Encoded json string
506     * @return mixed Decoded json string with leading and trailing whitespace removed
507     */
508    protected function _from_json($data)
509    {
510        return json_decode(trim($data));
511    }
512
513    /**
514     * @param string Data to unserialized
515     * @return mixed Unserialized data
516     */
517    protected function _from_serialize($data)
518    {
519        return unserialize(trim($data));
520    }
521
522    /**
523     * @param $data Data to trim leading and trailing whitespace
524     * @return string Data with leading and trailing whitespace removed
525     */
526    protected function _from_php($data)
527    {
528        return trim($data);
529    }
530
531}
Note: See TracBrowser for help on using the repository browser.