PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 2.1.4
Visualizer – Tables & Charts Manager with Built-in AI Generator v2.1.4
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
← All changes | classes/Visualizer/Source/Csv.php +34 -94 4.0.62.1.4 View file →
@@ -46,10 +46,10 @@
46 46 *
47 47 * @access public
48 48 * @param string $filename The path to the file.
49 49 */
50 - public function __construct( $filename = '' ) {
51 - $this->_filename = trim( (string) $filename );
50 + public function __construct( $filename = null ) {
51 + $this->_filename = trim( $filename );
52 52 }
53 53
54 54 /**
55 55 * Fetches series information.
@@ -61,49 +61,33 @@
61 61 */
62 62 private function _fetchSeries( &$handle ) {
63 63 // read column titles
64 64 $labels = fgetcsv( $handle, 0, VISUALIZER_CSV_DELIMITER, VISUALIZER_CSV_ENCLOSURE );
65 - $types = null;
65 + $labels = array_map( 'utf8_encode', $labels );
66 + // read series types
67 + $types = fgetcsv( $handle, 0, VISUALIZER_CSV_DELIMITER, VISUALIZER_CSV_ENCLOSURE );
66 68
67 - if ( false !== strpos( $this->_filename, 'tqx=out:csv' ) ) {
68 - $attributes = $this->_fetchSeriesForGoogleQueryLanguage( $labels );
69 - if ( ! $attributes['abort'] ) {
70 - $labels = $attributes['labels'];
71 - $types = $attributes['types'];
72 - }
73 - }
74 -
75 - if ( is_null( $types ) ) {
76 - // read series types
77 - $types = fgetcsv( $handle, 0, VISUALIZER_CSV_DELIMITER, VISUALIZER_CSV_ENCLOSURE );
78 - }
79 -
80 - if ( ! is_array( $labels ) || ! is_array( $types ) ) {
81 - $this->_error = esc_html__( 'File should have a heading row (1st row) and a data type row (2nd row). Please try again.', 'visualizer' );
82 - return false;
83 - }
84 -
85 - $labels = array_filter( $labels );
86 - $types = array_filter( $types );
87 -
88 69 if ( ! $labels || ! $types ) {
89 - $this->_error = esc_html__( 'File should have a heading row (1st row) and a data type row (2nd row). Please try again.', 'visualizer' );
90 70 return false;
91 71 }
92 72
73 + // if no types were setup, re read labels and empty types array
93 74 $types = array_map( 'trim', $types );
94 75 if ( ! self::_validateTypes( $types ) ) {
95 - $this->_error = esc_html__( 'Invalid data types detected in the data type row (2nd row). Please try again.', 'visualizer' );
96 - return false;
76 + // re open the file
77 + fclose( $handle );
78 + $handle = $this->_get_file_handle();
79 +
80 + // re read the labels and empty types array
81 + $labels = fgetcsv( $handle, 0, VISUALIZER_CSV_DELIMITER, VISUALIZER_CSV_ENCLOSURE );
82 + $labels = array_map( 'utf8_encode', $labels );
83 + $types = array();
97 84 }
98 85
99 86 for ( $i = 0, $len = count( $labels ); $i < $len; $i++ ) {
100 - $default_type = $i === 0 ? 'string' : 'number';
101 -
102 - $labels[ $i ] = $this->toUTF8( $labels[ $i ] );
103 -
87 + $default_type = $i == 0 ? 'string' : 'number';
104 88 $this->_series[] = array(
105 - 'label' => sanitize_text_field( wp_strip_all_tags( $labels[ $i ] ) ),
89 + 'label' => $labels[ $i ],
106 90 'type' => isset( $types[ $i ] ) ? $types[ $i ] : $default_type,
107 91 );
108 92 }
109 93
@@ -116,13 +100,18 @@
116 100 * @since 1.4.2
117 101 *
118 102 * @access protected
119 103 * @param string $filename Optional file name to get handle. If omitted, $_filename is used.
120 - * @return resource|false File handle resource on success, otherwise FALSE.
104 + * @return resource File handle resource on success, otherwise FALSE.
121 105 */
122 106 protected function _get_file_handle( $filename = false ) {
107 + // set line endings auto detect mode
108 + ini_set( 'auto_detect_line_endings', true );
123 109 // open file and return handle
124 - return fopen( $filename ? $filename : $this->_filename, 'rb' );
110 + $fc = iconv( 'ISO-8859-1', 'utf-8', file_get_contents( $filename ? $filename : $this->_filename ) );
111 + $tmp = tempnam( sys_get_temp_dir(), rand() );
112 + file_put_contents( $tmp, $fc );
113 + return fopen( $tmp, 'rb' );
125 114 }
126 115
127 116 /**
128 117 * Fetches information from source, parses it and builds series and data arrays.
@@ -134,37 +123,29 @@
134 123 */
135 124 public function fetch() {
136 125 // if filename is empty return false
137 126 if ( empty( $this->_filename ) ) {
138 - $this->_error = esc_html__( 'No file provided. Please try again.', 'visualizer' );
139 127 return false;
140 128 }
141 129
142 130 // read file and fill arrays
143 131 $handle = $this->_get_file_handle();
144 - if ( ! $handle ) {
145 - if ( empty( $this->_error ) ) {
146 - $this->_error = esc_html__( 'The file could not be opened. Please try again.', 'visualizer' );
132 + if ( $handle ) {
133 + // fetch series
134 + if ( ! $this->_fetchSeries( $handle ) ) {
135 + return false;
147 136 }
148 - return false;
149 - }
150 137
151 - // fetch series
152 - if ( ! $this->_fetchSeries( $handle ) ) {
138 + // fetch data
139 + while ( ( $data = fgetcsv( $handle, 0, VISUALIZER_CSV_DELIMITER, VISUALIZER_CSV_ENCLOSURE ) ) !== false ) {
140 +
141 + $this->_data[] = $this->_normalizeData( $data );
142 + }
143 +
144 + // close file handle
153 145 fclose( $handle );
154 - return false;
155 146 }
156 147
157 - // fetch data
158 - $data = fgetcsv( $handle, 0, VISUALIZER_CSV_DELIMITER, VISUALIZER_CSV_ENCLOSURE );
159 - while ( $data !== false ) {
160 - $this->_data[] = $this->_normalizeData( $data );
161 - $data = fgetcsv( $handle, 0, VISUALIZER_CSV_DELIMITER, VISUALIZER_CSV_ENCLOSURE );
162 - }
163 -
164 - // close file handle
165 - fclose( $handle );
166 -
167 148 return true;
168 149 }
169 150
170 151 /**
@@ -178,46 +159,5 @@
178 159 public function getSourceName() {
179 160 return __CLASS__;
180 161 }
181 162
182 - /**
183 - * Adds support for QueryLanguage https://developers.google.com/chart/interactive/docs/querylanguage
184 - * where the user can provide something like /gviz/tq?tq=select%20A%2C%20B%20&tqx=out:csv after the URL of the raw spreadsheet
185 - * to get the subset of data specified by the query
186 - * this will conflate the heading and the type into one value viz. for heading XXX and type string, the value will become "XXX string"
187 - * so we need to split them apart logically
188 - * also the $types variable now contains the first row because the header and the type got conflated
189 - */
190 - private function _fetchSeriesForGoogleQueryLanguage( $labels, $types = array() ) {
191 - $new_labels = array();
192 - $new_types = array();
193 - $abort = false;
194 - foreach ( $labels as $label ) {
195 - // get the index of the last space
196 - $index = strrpos( $label, ' ' );
197 - if ( $index === false ) {
198 - // no space here? something has gone wrong; abort the entire process.
199 - $abort = true;
200 - break;
201 - }
202 - $type = trim( substr( $label, $index + 1 ) );
203 - if ( ! self::_validateTypes( array( $type ) ) ) {
204 - // some other data type? abort the entire process.
205 - $abort = true;
206 - break;
207 - }
208 - $label = substr( $label, 0, $index );
209 - $new_labels[] = $label;
210 - $new_types[] = $type;
211 - }
212 - if ( ! $abort ) {
213 - $labels = $new_labels;
214 - $types = $new_types;
215 - }
216 -
217 - return array(
218 - 'abort' => $abort,
219 - 'labels' => $labels,
220 - 'types' => $types,
221 - );
222 - }
223 163 }