You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							531 lines
						
					
					
						
							14 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							531 lines
						
					
					
						
							14 KiB
						
					
					
				
								<?php
							 | 
						|
								
							 | 
						|
								defined('BASEPATH') OR exit('No direct script access allowed');
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Format class
							 | 
						|
								 * Help convert between various formats such as XML, JSON, CSV, etc.
							 | 
						|
								 *
							 | 
						|
								 * @author    Phil Sturgeon, Chris Kacerguis, @softwarespot
							 | 
						|
								 * @license   http://www.dbad-license.org/
							 | 
						|
								 */
							 | 
						|
								class Format {
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Array output format
							 | 
						|
								     */
							 | 
						|
								    const ARRAY_FORMAT = 'array';
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Comma Separated Value (CSV) output format
							 | 
						|
								     */
							 | 
						|
								    const CSV_FORMAT = 'csv';
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Json output format
							 | 
						|
								     */
							 | 
						|
								    const JSON_FORMAT = 'json';
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * HTML output format
							 | 
						|
								     */
							 | 
						|
								    const HTML_FORMAT = 'html';
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * PHP output format
							 | 
						|
								     */
							 | 
						|
								    const PHP_FORMAT = 'php';
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Serialized output format
							 | 
						|
								     */
							 | 
						|
								    const SERIALIZED_FORMAT = 'serialized';
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * XML output format
							 | 
						|
								     */
							 | 
						|
								    const XML_FORMAT = 'xml';
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Default format of this class
							 | 
						|
								     */
							 | 
						|
								    const DEFAULT_FORMAT = self::JSON_FORMAT; // Couldn't be DEFAULT, as this is a keyword
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * CodeIgniter instance
							 | 
						|
								     *
							 | 
						|
								     * @var object
							 | 
						|
								     */
							 | 
						|
								    private $_CI;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Data to parse
							 | 
						|
								     *
							 | 
						|
								     * @var mixed
							 | 
						|
								     */
							 | 
						|
								    protected $_data = [];
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Type to convert from
							 | 
						|
								     *
							 | 
						|
								     * @var string
							 | 
						|
								     */
							 | 
						|
								    protected $_from_type = NULL;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * DO NOT CALL THIS DIRECTLY, USE factory()
							 | 
						|
								     *
							 | 
						|
								     * @param NULL $data
							 | 
						|
								     * @param NULL $from_type
							 | 
						|
								     * @throws Exception
							 | 
						|
								     */
							 | 
						|
								
							 | 
						|
								    public function __construct($data = NULL, $from_type = NULL)
							 | 
						|
								    {
							 | 
						|
								        // Get the CodeIgniter reference
							 | 
						|
								        $this->_CI = &get_instance();
							 | 
						|
								
							 | 
						|
								        // Load the inflector helper
							 | 
						|
								        $this->_CI->load->helper('inflector');
							 | 
						|
								
							 | 
						|
								        // If the provided data is already formatted we should probably convert it to an array
							 | 
						|
								        if ($from_type !== NULL)
							 | 
						|
								        {
							 | 
						|
								            if (method_exists($this, '_from_' . $from_type))
							 | 
						|
								            {
							 | 
						|
								                $data = call_user_func([$this, '_from_' . $from_type], $data);
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                throw new Exception('Format class does not support conversion from "' . $from_type . '".');
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Set the member variable to the data passed
							 | 
						|
								        $this->_data = $data;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Create an instance of the format class
							 | 
						|
								     * e.g: echo $this->format->factory(['foo' => 'bar'])->to_csv();
							 | 
						|
								     *
							 | 
						|
								     * @param mixed $data Data to convert/parse
							 | 
						|
								     * @param string $from_type Type to convert from e.g. json, csv, html
							 | 
						|
								     *
							 | 
						|
								     * @return object Instance of the format class
							 | 
						|
								     */
							 | 
						|
								    public function factory($data, $from_type = NULL)
							 | 
						|
								    {
							 | 
						|
								        // $class = __CLASS__;
							 | 
						|
								        // return new $class();
							 | 
						|
								
							 | 
						|
								        return new static($data, $from_type);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // FORMATTING OUTPUT ---------------------------------------------------------
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Format data as an array
							 | 
						|
								     *
							 | 
						|
								     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
							 | 
						|
								     * to the constructor
							 | 
						|
								     * @return array Data parsed as an array; otherwise, an empty array
							 | 
						|
								     */
							 | 
						|
								    public function to_array($data = NULL)
							 | 
						|
								    {
							 | 
						|
								        // If no data is passed as a parameter, then use the data passed
							 | 
						|
								        // via the constructor
							 | 
						|
								        if ($data === NULL && func_num_args() === 0)
							 | 
						|
								        {
							 | 
						|
								            $data = $this->_data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Cast as an array if not already
							 | 
						|
								        if (is_array($data) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $data = (array) $data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $array = [];
							 | 
						|
								        foreach ((array) $data as $key => $value)
							 | 
						|
								        {
							 | 
						|
								            if (is_object($value) === TRUE || is_array($value) === TRUE)
							 | 
						|
								            {
							 | 
						|
								                $array[$key] = $this->to_array($value);
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                $array[$key] = $value;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $array;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Format data as XML
							 | 
						|
								     *
							 | 
						|
								     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
							 | 
						|
								     * to the constructor
							 | 
						|
								     * @param NULL $structure
							 | 
						|
								     * @param string $basenode
							 | 
						|
								     * @return mixed
							 | 
						|
								     */
							 | 
						|
								    public function to_xml($data = NULL, $structure = NULL, $basenode = 'xml')
							 | 
						|
								    {
							 | 
						|
								        if ($data === NULL && func_num_args() === 0)
							 | 
						|
								        {
							 | 
						|
								            $data = $this->_data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // turn off compatibility mode as simple xml throws a wobbly if you don't.
							 | 
						|
								        if (ini_get('zend.ze1_compatibility_mode') == 1)
							 | 
						|
								        {
							 | 
						|
								            ini_set('zend.ze1_compatibility_mode', 0);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($structure === NULL)
							 | 
						|
								        {
							 | 
						|
								            $structure = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$basenode />");
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Force it to be something useful
							 | 
						|
								        if (is_array($data) === FALSE && is_object($data) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $data = (array) $data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        foreach ($data as $key => $value)
							 | 
						|
								        {
							 | 
						|
								
							 | 
						|
								            //change false/true to 0/1
							 | 
						|
								            if (is_bool($value))
							 | 
						|
								            {
							 | 
						|
								                $value = (int) $value;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // no numeric keys in our xml please!
							 | 
						|
								            if (is_numeric($key))
							 | 
						|
								            {
							 | 
						|
								                // make string key...
							 | 
						|
								                $key = (singular($basenode) != $basenode) ? singular($basenode) : 'item';
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // replace anything not alpha numeric
							 | 
						|
								            $key = preg_replace('/[^a-z_\-0-9]/i', '', $key);
							 | 
						|
								
							 | 
						|
								            if ($key === '_attributes' && (is_array($value) || is_object($value)))
							 | 
						|
								            {
							 | 
						|
								                $attributes = $value;
							 | 
						|
								                if (is_object($attributes))
							 | 
						|
								                {
							 | 
						|
								                    $attributes = get_object_vars($attributes);
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                foreach ($attributes as $attribute_name => $attribute_value)
							 | 
						|
								                {
							 | 
						|
								                    $structure->addAttribute($attribute_name, $attribute_value);
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            // if there is another array found recursively call this function
							 | 
						|
								            elseif (is_array($value) || is_object($value))
							 | 
						|
								            {
							 | 
						|
								                $node = $structure->addChild($key);
							 | 
						|
								
							 | 
						|
								                // recursive call.
							 | 
						|
								                $this->to_xml($value, $node, $key);
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                // add single node.
							 | 
						|
								                $value = htmlspecialchars(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8');
							 | 
						|
								
							 | 
						|
								                $structure->addChild($key, $value);
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $structure->asXML();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Format data as HTML
							 | 
						|
								     *
							 | 
						|
								     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
							 | 
						|
								     * to the constructor
							 | 
						|
								     * @return mixed
							 | 
						|
								     */
							 | 
						|
								    public function to_html($data = NULL)
							 | 
						|
								    {
							 | 
						|
								        // If no data is passed as a parameter, then use the data passed
							 | 
						|
								        // via the constructor
							 | 
						|
								        if ($data === NULL && func_num_args() === 0)
							 | 
						|
								        {
							 | 
						|
								            $data = $this->_data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Cast as an array if not already
							 | 
						|
								        if (is_array($data) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $data = (array) $data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Check if it's a multi-dimensional array
							 | 
						|
								        if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE))
							 | 
						|
								        {
							 | 
						|
								            // Multi-dimensional array
							 | 
						|
								            $headings = array_keys($data[0]);
							 | 
						|
								        }
							 | 
						|
								        else
							 | 
						|
								        {
							 | 
						|
								            // Single array
							 | 
						|
								            $headings = array_keys($data);
							 | 
						|
								            $data = [$data];
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Load the table library
							 | 
						|
								        $this->_CI->load->library('table');
							 | 
						|
								
							 | 
						|
								        $this->_CI->table->set_heading($headings);
							 | 
						|
								
							 | 
						|
								        foreach ($data as $row)
							 | 
						|
								        {
							 | 
						|
								            // Suppressing the "array to string conversion" notice
							 | 
						|
								            // Keep the "evil" @ here
							 | 
						|
								            $row = @array_map('strval', $row);
							 | 
						|
								
							 | 
						|
								            $this->_CI->table->add_row($row);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $this->_CI->table->generate();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @link http://www.metashock.de/2014/02/create-csv-file-in-memory-php/
							 | 
						|
								     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
							 | 
						|
								     * to the constructor
							 | 
						|
								     * @param string $delimiter The optional delimiter parameter sets the field
							 | 
						|
								     * delimiter (one character only). NULL will use the default value (,)
							 | 
						|
								     * @param string $enclosure The optional enclosure parameter sets the field
							 | 
						|
								     * enclosure (one character only). NULL will use the default value (")
							 | 
						|
								     * @return string A csv string
							 | 
						|
								     */
							 | 
						|
								    public function to_csv($data = NULL, $delimiter = ',', $enclosure = '"')
							 | 
						|
								    {
							 | 
						|
								        // Use a threshold of 1 MB (1024 * 1024)
							 | 
						|
								        $handle = fopen('php://temp/maxmemory:1048576', 'w');
							 | 
						|
								        if ($handle === FALSE)
							 | 
						|
								        {
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // If no data is passed as a parameter, then use the data passed
							 | 
						|
								        // via the constructor
							 | 
						|
								        if ($data === NULL && func_num_args() === 0)
							 | 
						|
								        {
							 | 
						|
								            $data = $this->_data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // If NULL, then set as the default delimiter
							 | 
						|
								        if ($delimiter === NULL)
							 | 
						|
								        {
							 | 
						|
								            $delimiter = ',';
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // If NULL, then set as the default enclosure
							 | 
						|
								        if ($enclosure === NULL)
							 | 
						|
								        {
							 | 
						|
								            $enclosure = '"';
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Cast as an array if not already
							 | 
						|
								        if (is_array($data) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $data = (array) $data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Check if it's a multi-dimensional array
							 | 
						|
								        if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE))
							 | 
						|
								        {
							 | 
						|
								            // Multi-dimensional array
							 | 
						|
								            $headings = array_keys($data[0]);
							 | 
						|
								        }
							 | 
						|
								        else
							 | 
						|
								        {
							 | 
						|
								            // Single array
							 | 
						|
								            $headings = array_keys($data);
							 | 
						|
								            $data = [$data];
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Apply the headings
							 | 
						|
								        fputcsv($handle, $headings, $delimiter, $enclosure);
							 | 
						|
								
							 | 
						|
								        foreach ($data as $record)
							 | 
						|
								        {
							 | 
						|
								            // If the record is not an array, then break. This is because the 2nd param of
							 | 
						|
								            // fputcsv() should be an array
							 | 
						|
								            if (is_array($record) === FALSE)
							 | 
						|
								            {
							 | 
						|
								                break;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Suppressing the "array to string conversion" notice.
							 | 
						|
								            // Keep the "evil" @ here.
							 | 
						|
								            $record = @ array_map('strval', $record);
							 | 
						|
								
							 | 
						|
								            // Returns the length of the string written or FALSE
							 | 
						|
								            fputcsv($handle, $record, $delimiter, $enclosure);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Reset the file pointer
							 | 
						|
								        rewind($handle);
							 | 
						|
								
							 | 
						|
								        // Retrieve the csv contents
							 | 
						|
								        $csv = stream_get_contents($handle);
							 | 
						|
								
							 | 
						|
								        // Close the handle
							 | 
						|
								        fclose($handle);
							 | 
						|
								
							 | 
						|
								        return $csv;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Encode data as json
							 | 
						|
								     *
							 | 
						|
								     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
							 | 
						|
								     * to the constructor
							 | 
						|
								     * @return string Json representation of a value
							 | 
						|
								     */
							 | 
						|
								    public function to_json($data = NULL)
							 | 
						|
								    {
							 | 
						|
								        // If no data is passed as a parameter, then use the data passed
							 | 
						|
								        // via the constructor
							 | 
						|
								        if ($data === NULL && func_num_args() === 0)
							 | 
						|
								        {
							 | 
						|
								            $data = $this->_data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Get the callback parameter (if set)
							 | 
						|
								        $callback = $this->_CI->input->get('callback');
							 | 
						|
								
							 | 
						|
								        if (empty($callback) === TRUE)
							 | 
						|
								        {
							 | 
						|
								            return json_encode($data, JSON_UNESCAPED_UNICODE| JSON_UNESCAPED_SLASHES);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // We only honour a jsonp callback which are valid javascript identifiers
							 | 
						|
								        elseif (preg_match('/^[a-z_\$][a-z0-9\$_]*(\.[a-z_\$][a-z0-9\$_]*)*$/i', $callback))
							 | 
						|
								        {
							 | 
						|
								            // Return the data as encoded json with a callback
							 | 
						|
								            return $callback . '(' . json_encode($data) . ');';
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // An invalid jsonp callback function provided.
							 | 
						|
								        // Though I don't believe this should be hardcoded here
							 | 
						|
								        $data['warning'] = 'INVALID JSONP CALLBACK: ' . $callback;
							 | 
						|
								
							 | 
						|
								        return json_encode($data);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Encode data as a serialized array
							 | 
						|
								     *
							 | 
						|
								     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
							 | 
						|
								     * to the constructor
							 | 
						|
								     * @return string Serialized data
							 | 
						|
								     */
							 | 
						|
								    public function to_serialized($data = NULL)
							 | 
						|
								    {
							 | 
						|
								        // If no data is passed as a parameter, then use the data passed
							 | 
						|
								        // via the constructor
							 | 
						|
								        if ($data === NULL && func_num_args() === 0)
							 | 
						|
								        {
							 | 
						|
								            $data = $this->_data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return serialize($data);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Format data using a PHP structure
							 | 
						|
								     *
							 | 
						|
								     * @param mixed|NULL $data Optional data to pass, so as to override the data passed
							 | 
						|
								     * to the constructor
							 | 
						|
								     * @return mixed String representation of a variable
							 | 
						|
								     */
							 | 
						|
								    public function to_php($data = NULL)
							 | 
						|
								    {
							 | 
						|
								        // If no data is passed as a parameter, then use the data passed
							 | 
						|
								        // via the constructor
							 | 
						|
								        if ($data === NULL && func_num_args() === 0)
							 | 
						|
								        {
							 | 
						|
								            $data = $this->_data;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return var_export($data, TRUE);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // INTERNAL FUNCTIONS
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @param $data XML string
							 | 
						|
								     * @return SimpleXMLElement XML element object; otherwise, empty array
							 | 
						|
								     */
							 | 
						|
								    protected function _from_xml($data)
							 | 
						|
								    {
							 | 
						|
								        return $data ? (array) simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA) : [];
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @param string $data CSV string
							 | 
						|
								     * @param string $delimiter The optional delimiter parameter sets the field
							 | 
						|
								     * delimiter (one character only). NULL will use the default value (,)
							 | 
						|
								     * @param string $enclosure The optional enclosure parameter sets the field
							 | 
						|
								     * enclosure (one character only). NULL will use the default value (")
							 | 
						|
								     * @return array A multi-dimensional array with the outer array being the number of rows
							 | 
						|
								     * and the inner arrays the individual fields
							 | 
						|
								     */
							 | 
						|
								    protected function _from_csv($data, $delimiter = ',', $enclosure = '"')
							 | 
						|
								    {
							 | 
						|
								        // If NULL, then set as the default delimiter
							 | 
						|
								        if ($delimiter === NULL)
							 | 
						|
								        {
							 | 
						|
								            $delimiter = ',';
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // If NULL, then set as the default enclosure
							 | 
						|
								        if ($enclosure === NULL)
							 | 
						|
								        {
							 | 
						|
								            $enclosure = '"';
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return str_getcsv($data, $delimiter, $enclosure);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @param $data Encoded json string
							 | 
						|
								     * @return mixed Decoded json string with leading and trailing whitespace removed
							 | 
						|
								     */
							 | 
						|
								    protected function _from_json($data)
							 | 
						|
								    {
							 | 
						|
								        return json_decode(trim($data));
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @param string Data to unserialized
							 | 
						|
								     * @return mixed Unserialized data
							 | 
						|
								     */
							 | 
						|
								    protected function _from_serialize($data)
							 | 
						|
								    {
							 | 
						|
								        return unserialize(trim($data));
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @param $data Data to trim leading and trailing whitespace
							 | 
						|
								     * @return string Data with leading and trailing whitespace removed
							 | 
						|
								     */
							 | 
						|
								    protected function _from_php($data)
							 | 
						|
								    {
							 | 
						|
								        return trim($data);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								}
							 |