This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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
|
|||||
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
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
![]() |
|||||
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
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
![]() |
|||||
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 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.