1<?php 2namespace Luracast\Restler\Format; 3 4 5use Luracast\Restler\Data\Obj; 6use Luracast\Restler\RestException; 7 8/** 9 * Comma Separated Value Format 10 * 11 * @category Framework 12 * @package Restler 13 * @subpackage format 14 * @author R.Arul Kumaran <arul@luracast.com> 15 * @copyright 2010 Luracast 16 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 17 * @link http://luracast.com/products/restler/ 18 * 19 */ 20class CsvFormat extends Format implements iDecodeStream 21{ 22 23 const MIME = 'text/csv'; 24 const EXTENSION = 'csv'; 25 public static $delimiter = ','; 26 public static $enclosure = '"'; 27 public static $escape = '\\'; 28 public static $haveHeaders = null; 29 30 /** 31 * Encode the given data in the csv format 32 * 33 * @param array $data 34 * resulting data that needs to 35 * be encoded in the given format 36 * @param boolean $humanReadable 37 * set to TRUE when restler 38 * is not running in production mode. Formatter has to 39 * make the encoded output more human readable 40 * 41 * @return string encoded string 42 * 43 * @throws RestException 500 on unsupported data 44 */ 45 public function encode($data, $humanReadable = false) 46 { 47 $char = Obj::$separatorChar; 48 Obj::$separatorChar = false; 49 $data = Obj::toArray($data); 50 Obj::$separatorChar = $char; 51 if (is_array($data) && array_values($data) == $data) { 52 //if indexed array 53 $lines = array(); 54 $row = array_shift($data); 55 if (array_values($row) != $row) { 56 $lines[] = static::putRow(array_keys($row)); 57 } 58 $lines[] = static::putRow(array_values($row)); 59 foreach ($data as $row) { 60 $lines[] = static::putRow(array_values($row)); 61 } 62 return implode(PHP_EOL, $lines) . PHP_EOL; 63 } 64 throw new RestException( 65 500, 66 'Unsupported data for ' . strtoupper(static::EXTENSION) . ' format' 67 ); 68 } 69 70 protected static function putRow($data) 71 { 72 $fp = fopen('php://temp', 'r+'); 73 fputcsv($fp, $data, static::$delimiter, static::$enclosure); 74 rewind($fp); 75 $data = fread($fp, 1048576); 76 fclose($fp); 77 return rtrim($data, PHP_EOL); 78 } 79 80 /** 81 * Decode the given data from the csv format 82 * 83 * @param string $data 84 * data sent from client to 85 * the api in the given format. 86 * 87 * @return array associative array of the parsed data 88 */ 89 public function decode($data) 90 { 91 $decoded = array(); 92 93 if (empty($data)) { 94 return $decoded; 95 } 96 97 $lines = array_filter(explode(PHP_EOL, $data)); 98 99 $keys = false; 100 $row = static::getRow(array_shift($lines)); 101 102 if (is_null(static::$haveHeaders)) { 103 //try to guess with the given data 104 static::$haveHeaders = !count(array_filter($row, 'is_numeric')); 105 } 106 107 static::$haveHeaders ? $keys = $row : $decoded[] = $row; 108 109 while (($row = static::getRow(array_shift($lines), $keys)) !== FALSE) 110 $decoded [] = $row; 111 112 $char = Obj::$separatorChar; 113 Obj::$separatorChar = false; 114 $decoded = Obj::toArray($decoded); 115 Obj::$separatorChar = $char; 116 return $decoded; 117 } 118 119 protected static function getRow($data, $keys = false) 120 { 121 if (empty($data)) { 122 return false; 123 } 124 $line = str_getcsv( 125 $data, 126 static::$delimiter, 127 static::$enclosure, 128 static::$escape 129 ); 130 131 $row = array(); 132 foreach ($line as $key => $value) { 133 if (is_numeric($value)) 134 $value = floatval($value); 135 if ($keys) { 136 if (isset($keys [$key])) 137 $row [$keys [$key]] = $value; 138 } else { 139 $row [$key] = $value; 140 } 141 } 142 if ($keys) { 143 for ($i = count($row); $i < count($keys); $i++) { 144 $row[$keys[$i]] = null; 145 } 146 } 147 return $row; 148 } 149 150 /** 151 * Decode the given data stream 152 * 153 * @param string $stream A stream resource with data 154 * sent from client to the api 155 * in the given format. 156 * 157 * @return array associative array of the parsed data 158 */ 159 public function decodeStream($stream) 160 { 161 $decoded = array(); 162 163 $keys = false; 164 $row = static::getRow(stream_get_line($stream, 0, PHP_EOL)); 165 if (is_null(static::$haveHeaders)) { 166 //try to guess with the given data 167 static::$haveHeaders = !count(array_filter($row, 'is_numeric')); 168 } 169 170 static::$haveHeaders ? $keys = $row : $decoded[] = $row; 171 172 while (($row = static::getRow(stream_get_line($stream, 0, PHP_EOL), $keys)) !== FALSE) 173 $decoded [] = $row; 174 175 $char = Obj::$separatorChar; 176 Obj::$separatorChar = false; 177 $decoded = Obj::toArray($decoded); 178 Obj::$separatorChar = $char; 179 return $decoded; 180 } 181}