Overview

Packages

  • CodeIgniter
    • Libraries
    • Rest
  • None

Classes

  • Example
  • Format
  • Key
  • REST_Controller
  • Rest_server
  • Welcome
  • Overview
  • Package
  • Class
  1: <?php
  2: 
  3: defined('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:  */
 12: class 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: }
532: 
API documentation generated by ApiGen