PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.7
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.7
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 3.10.4 All 148 releases
visualizer / classes / Visualizer / Source / Csv.php

Csv.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 4.0.7, at classes/Visualizer/Source/Csv.php

224 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // +----------------------------------------------------------------------+
4 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
5 // +----------------------------------------------------------------------+
6 // | This program is free software; you can redistribute it and/or modify |
7 // | it under the terms of the GNU General Public License, version 2, as |
8 // | published by the Free Software Foundation. |
9 // | |
10 // | This program is distributed in the hope that it will be useful, |
11 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 // | GNU General Public License for more details. |
14 // | |
15 // | You should have received a copy of the GNU General Public License |
16 // | along with this program; if not, write to the Free Software |
17 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
18 // | MA 02110-1301 USA |
19 // +----------------------------------------------------------------------+
20 // | Author: Eugene Manuilov <eugene@manuilov.org> |
21 // +----------------------------------------------------------------------+
22 /**
23 * Source manager for local CSV files.
24 *
25 * @category Visualizer
26 * @package Source
27 *
28 * @since 1.0.0
29 */
30 class Visualizer_Source_Csv extends Visualizer_Source {
31
32 /**
33 * The path to the file with data.
34 *
35 * @since 1.0.0
36 *
37 * @access protected
38 * @var string
39 */
40 protected $_filename;
41
42 /**
43 * Constructor.
44 *
45 * @since 1.0.0
46 *
47 * @access public
48 * @param string $filename The path to the file.
49 */
50 public function __construct( $filename = '' ) {
51 $this->_filename = trim( (string) $filename );
52 }
53
54 /**
55 * Fetches series information.
56 *
57 * @since 1.0.0
58 *
59 * @access private
60 * @param resource $handle The file handle resource.
61 */
62 private function _fetchSeries( &$handle ) {
63 // read column titles
64 $labels = fgetcsv( $handle, 0, VISUALIZER_CSV_DELIMITER, VISUALIZER_CSV_ENCLOSURE );
65 $types = null;
66
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 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 return false;
91 }
92
93 $types = array_map( 'trim', $types );
94 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;
97 }
98
99 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
104 $this->_series[] = array(
105 'label' => sanitize_text_field( wp_strip_all_tags( $labels[ $i ] ) ),
106 'type' => isset( $types[ $i ] ) ? $types[ $i ] : $default_type,
107 );
108 }
109
110 return true;
111 }
112
113 /**
114 * Returns file handle to fetch data from.
115 *
116 * @since 1.4.2
117 *
118 * @access protected
119 * @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.
121 */
122 protected function _get_file_handle( $filename = false ) {
123 // open file and return handle
124 return fopen( $filename ? $filename : $this->_filename, 'rb' );
125 }
126
127 /**
128 * Fetches information from source, parses it and builds series and data arrays.
129 *
130 * @since 1.0.0
131 *
132 * @access public
133 * @return boolean TRUE on success, otherwise FALSE.
134 */
135 public function fetch() {
136 // if filename is empty return false
137 if ( empty( $this->_filename ) ) {
138 $this->_error = esc_html__( 'No file provided. Please try again.', 'visualizer' );
139 return false;
140 }
141
142 // read file and fill arrays
143 $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' );
147 }
148 return false;
149 }
150
151 // fetch series
152 if ( ! $this->_fetchSeries( $handle ) ) {
153 fclose( $handle );
154 return false;
155 }
156
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 return true;
168 }
169
170 /**
171 * Returns source name.
172 *
173 * @since 1.0.0
174 *
175 * @access public
176 * @return string The name of source.
177 */
178 public function getSourceName() {
179 return __CLASS__;
180 }
181
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 }
224