GetPaid_Graph_Downloader::prepare_handler()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Contains the class that downloads a single report.
4
 *
5
 *
6
 */
7
8
defined( 'ABSPATH' ) || exit;
9
10
/**
11
 * GetPaid_Graph_Downloader Class.
12
 */
13
class GetPaid_Graph_Downloader {
14
15
	/**
16
	 * @var GetPaid_Reports_Report
17
	 */
18
	public $handler;
19
20
	/**
21
	 * Class constructor.
22
	 *
23
	 */
24
	public function __construct() {
25
		$this->handler = new GetPaid_Reports_Report();
26
	}
27
28
	/**
29
	 * Prepares the datastore handler.
30
	 *
31
	 * @return GetPaid_Reports_Report_Items|GetPaid_Reports_Report_Gateways|GetPaid_Reports_Report_Discounts
32
	 */
33
	public function prepare_handler( $graph ) {
34
35
		if ( empty( $this->handler->views[ $graph ] ) ) {
36
			wp_die( esc_html__( 'Invalid Graph', 'invoicing' ), 400 );
37
		}
38
39
		return new $this->handler->views[ $graph ]['class']();
40
41
	}
42
43
	/**
44
	 * Prepares the output stream.
45
	 *
46
	 * @return resource
47
	 */
48
	public function prepare_output() {
49
50
		$output  = fopen( 'php://output', 'w' );
51
52
		if ( false === $output ) {
53
			wp_die( esc_html__( 'Unsupported server', 'invoicing' ), 500 );
54
		}
55
56
		return $output;
57
	}
58
59
	/**
60
	 * Prepares the file type.
61
	 *
62
	 * @return string
63
	 */
64
	public function prepare_file_type( $graph ) {
65
66
		$file_type = empty( $_REQUEST['file_type'] ) ? 'csv' : sanitize_text_field( $_REQUEST['file_type'] );
67
		$file_name = wpinv_sanitize_key( "getpaid-$graph-" . current_time( 'Y-m-d' ) );
68
69
		header( "Content-Type:application/$file_type" );
70
		header( "Content-Disposition:attachment;filename=$file_name.$file_type" );
71
72
		return $file_type;
73
	}
74
75
	/**
76
	 * Handles the actual download.
77
	 *
78
	 */
79
	public function download( $graph ) {
80
		global $wpdb;
81
82
		$handler   = $this->prepare_handler( $graph );
83
		$stream    = $this->prepare_output();
84
		$stats     = $wpdb->get_results( $handler->get_sql( $handler->get_range() ) );
85
		$headers   = array( $handler->field, 'total', 'total_raw' );
86
		$file_type = $this->prepare_file_type( $graph );
87
88
		if ( 'csv' == $file_type ) {
89
			$this->download_csv( $stats, $stream, $headers );
90
		} elseif ( 'xml' == $file_type ) {
91
			$this->download_xml( $stats, $stream, $headers );
92
		} else {
93
			$this->download_json( $stats, $stream, $headers );
94
		}
95
96
		fclose( $stream );
97
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
98
	}
99
100
	/**
101
	 * Downloads graph as csv
102
	 *
103
	 * @param array $stats The stats being downloaded.
104
	 * @param resource $stream The stream to output to.
105
	 * @param array $headers The fields to stream.
106
	 * @since       1.0.19
107
	 */
108
	public function download_csv( $stats, $stream, $headers ) {
109
110
		// Output the csv column headers.
111
		fputcsv( $stream, $headers );
112
113
		// Loop through
114
		foreach ( $stats as $stat ) {
115
			$row  = array_values( $this->prepare_row( $stat, $headers ) );
116
			$row  = array_map( 'maybe_serialize', $row );
117
			fputcsv( $stream, $row );
118
		}
119
120
	}
121
122
	/**
123
	 * Downloads graph as json
124
	 *
125
	 * @param array $stats The stats being downloaded.
126
	 * @param resource $stream The stream to output to.
127
	 * @param array $headers The fields to stream.
128
	 * @since       1.0.19
129
	 */
130
	public function download_json( $stats, $stream, $headers ) {
131
132
		$prepared = array();
133
134
		// Loop through
135
		foreach ( $stats as $stat ) {
136
			$prepared[] = $this->prepare_row( $stat, $headers );
137
		}
138
139
		fwrite( $stream, wp_json_encode( $prepared ) );
0 ignored issues
show
Bug introduced by
It seems like wp_json_encode($prepared) can also be of type false; however, parameter $data of fwrite() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
		fwrite( $stream, /** @scrutinizer ignore-type */ wp_json_encode( $prepared ) );
Loading history...
140
141
	}
142
143
	/**
144
	 * Downloads graph as xml
145
	 *
146
	 * @param array $stats The stats being downloaded.
147
	 * @param resource $stream The stream to output to.
148
	 * @param array $headers The fields to stream.
149
	 * @since       1.0.19
150
	 */
151
	public function download_xml( $stats, $stream, $headers ) {
152
153
		$prepared = array();
154
155
		// Loop through
156
		foreach ( $stats as $stat ) {
157
			$prepared[] = $this->prepare_row( $stat, $headers );
158
		}
159
160
		$xml = new SimpleXMLElement( '<?xml version="1.0"?><data></data>' );
161
		$this->convert_array_xml( $prepared, $xml );
162
163
		fwrite( $stream, $xml->asXML() );
0 ignored issues
show
Bug introduced by
It seems like $xml->asXML() can also be of type true; however, parameter $data of fwrite() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

163
		fwrite( $stream, /** @scrutinizer ignore-type */ $xml->asXML() );
Loading history...
164
165
	}
166
167
	/**
168
	 * Converts stats array to xml
169
	 *
170
	 * @access      public
171
	 * @since      1.0.19
172
	 */
173
	public function convert_array_xml( $data, $xml ) {
174
175
		// Loop through
176
		foreach ( $data as $key => $value ) {
177
178
			$key = preg_replace( '/[^A-Za-z0-9_\-]/', '', $key );
179
180
			if ( is_array( $value ) ) {
181
182
				if ( is_numeric( $key ) ) {
183
					$key = 'item' . $key; //dealing with <0/>..<n/> issues
184
				}
185
186
				$subnode = $xml->addChild( $key );
187
				$this->convert_array_xml( $value, $subnode );
188
189
			} else {
190
				$xml->addChild( $key, $value ?  htmlspecialchars( $value ) : $value );
191
			}
192
}
193
194
	}
195
196
	/**
197
	 * Prepares a single row for download.
198
	 *
199
	 * @param stdClass|array $row The row to prepare..
200
	 * @param array $fields The fields to stream.
201
	 * @since       1.0.19
202
	 * @return array
203
	 */
204
	public function prepare_row( $row, $fields ) {
205
206
		$prepared = array();
207
		$row      = (array) $row;
208
209
		foreach ( $fields as $field ) {
210
211
			if ( $field === 'total' ) {
212
				$prepared[ $field ] = html_entity_decode( strip_tags( wpinv_price( $row['total'] ) ), ENT_QUOTES );
213
				continue;
214
			}
215
216
			if ( $field === 'total_raw' ) {
217
				$prepared[ $field ] = wpinv_round_amount( wpinv_sanitize_amount( $row['total'] ) );
218
				continue;
219
			}
220
221
			$prepared[ $field ] = strip_tags( $row[ $field ] );
222
223
		}
224
225
		return $prepared;
226
	}
227
228
229
}
230