Issues (1182)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/cli/class-wc-cli-report.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Show Reports.
5
 *
6
 * @since    2.5.0
7
 * @package  WooCommerce/CLI
8
 * @category CLI
9
 * @author   WooThemes
10
 */
11
class WC_CLI_Report extends WC_CLI_Command {
12
13
	/**
14
	 * List reports.
15
	 *
16
	 * ## OPTIONS
17
	 *
18
	 * [--format=<format>]
19
	 * : Acceptec values: table, csv, json, count, ids. Default: table.
20
	 *
21
	 * ## EXAMPLES
22
	 *
23
	 *     wp wc report list
24
	 *
25
	 * @subcommand list
26
	 * @since      2.5.0
27
	 */
28
	public function list_( $__, $assoc_args ) {
29
		$reports   = array( 'sales', 'sales/top_sellers' );
30
		$formatter = $this->get_formatter(
31
			array_merge(
32
				array( 'fields' => array_keys( $reports ) ),
33
				$assoc_args
34
			)
35
		);
36
37
		if ( 'ids' === $formatter->format ) {
38
			echo implode( ' ', $reports );
39
		} else {
40
			$formatter->display_item( $reports );
41
		}
42
	}
43
44
	/**
45
	 * View sales report.
46
	 *
47
	 * ## OPTIONS
48
	 *
49
	 * [--field=<field>]
50
	 * : Instead of returning the whole report fields, returns the value of a single fields.
51
	 *
52
	 * [--fields=<fields>]
53
	 * : Get a specific subset of the report's fields.
54
	 *
55
	 * [--format=<format>]
56
	 * : Accepted values: table, json, csv. Default: table.
57
	 *
58
	 * [--period=<period>]
59
	 * : The supported periods are: week, month, last_month, and year. If invalid
60
	 * period is supplied, week is used. If period is not specified, the current
61
	 * day is used.
62
	 *
63
	 * [--date_min]
64
	 * : Return sales for a specific start date. The date need to be in the YYYY-MM-AA format.
65
	 *
66
	 * [--date_max]
67
	 * : Return sales for a specific end date. The dates need to be in the YYYY-MM-AA format.
68
	 *
69
	 * [--limit]
70
	 * : Limit report result. Default: 12.
71
	 *
72
	 * ## AVAILABLE FIELDS
73
	 *
74
	 * These fields are available for get command:
75
	 *
76
	 * * total_sales
77
	 * * average_sales
78
	 * * total_orders
79
	 * * total_items
80
	 * * total_tax
81
	 * * total_shipping
82
	 * * total_discount
83
	 * * totals_grouped_by
84
	 * * totals
85
	 * * total_customers
86
	 *
87
	 * ## EXAMPLES
88
	 *
89
	 *     wp wc report sales
90
	 *
91
	 *     wp wc report sales --period=last_month
92
	 *
93
	 * @since 2.5.0
94
	 */
95
	public function sales( $__, $assoc_args ) {
96
		$reporter = $this->get_reporter( $assoc_args );
97
98
		// new customers
99
		$users_query = new WP_User_Query(
100
			array(
101
				'fields' => array( 'user_registered' ),
102
				'role'   => 'customer',
103
			)
104
		);
105
106
		$customers = $users_query->get_results();
107
108
		foreach ( $customers as $key => $customer ) {
109
			if ( strtotime( $customer->user_registered ) < $reporter->start_date || strtotime( $customer->user_registered ) > $reporter->end_date ) {
110
				unset( $customers[ $key ] );
111
			}
112
		}
113
114
		$total_customers = count( $customers );
115
		$report_data     = $reporter->get_report_data();
116
		$period_totals   = array();
117
118
		// setup period totals by ensuring each period in the interval has data
119
		for ( $i = 0; $i <= $reporter->chart_interval; $i ++ ) {
120
121
			switch ( $reporter->chart_groupby ) {
122
				case 'day' :
123
					$time = date( 'Y-m-d', strtotime( "+{$i} DAY", $reporter->start_date ) );
124
					break;
125
				default :
126
					$time = date( 'Y-m', strtotime( "+{$i} MONTH", $reporter->start_date ) );
127
					break;
128
			}
129
130
			// set the customer signups for each period
131
			$customer_count = 0;
132
			foreach ( $customers as $customer ) {
133
				if ( date( ( 'day' == $reporter->chart_groupby ) ? 'Y-m-d' : 'Y-m', strtotime( $customer->user_registered ) ) == $time ) {
134
					$customer_count++;
135
				}
136
 			}
137
138
			$period_totals[ $time ] = array(
139
				'sales'     => wc_format_decimal( 0.00, 2 ),
140
				'orders'    => 0,
141
				'items'     => 0,
142
				'tax'       => wc_format_decimal( 0.00, 2 ),
143
				'shipping'  => wc_format_decimal( 0.00, 2 ),
144
				'discount'  => wc_format_decimal( 0.00, 2 ),
145
				'customers' => $customer_count,
146
			);
147
		}
148
149
		// add total sales, total order count, total tax and total shipping for each period
150
		foreach ( $report_data->orders as $order ) {
151
			$time = ( 'day' === $reporter->chart_groupby ) ? date( 'Y-m-d', strtotime( $order->post_date ) ) : date( 'Y-m', strtotime( $order->post_date ) );
152
153
			if ( ! isset( $period_totals[ $time ] ) ) {
154
				continue;
155
			}
156
157
			$period_totals[ $time ]['sales']    = wc_format_decimal( $order->total_sales, 2 );
158
			$period_totals[ $time ]['tax']      = wc_format_decimal( $order->total_tax + $order->total_shipping_tax, 2 );
159
			$period_totals[ $time ]['shipping'] = wc_format_decimal( $order->total_shipping, 2 );
160
		}
161
162
		foreach ( $report_data->order_counts as $order ) {
163
			$time = ( 'day' === $reporter->chart_groupby ) ? date( 'Y-m-d', strtotime( $order->post_date ) ) : date( 'Y-m', strtotime( $order->post_date ) );
164
165
			if ( ! isset( $period_totals[ $time ] ) ) {
166
				continue;
167
			}
168
169
			$period_totals[ $time ]['orders']   = (int) $order->count;
170
		}
171
172
		// add total order items for each period
173
		foreach ( $report_data->order_items as $order_item ) {
174
			$time = ( 'day' === $reporter->chart_groupby ) ? date( 'Y-m-d', strtotime( $order_item->post_date ) ) : date( 'Y-m', strtotime( $order_item->post_date ) );
175
176
			if ( ! isset( $period_totals[ $time ] ) ) {
177
				continue;
178
			}
179
180
			$period_totals[ $time ]['items'] = (int) $order_item->order_item_count;
181
		}
182
183
		// add total discount for each period
184
		foreach ( $report_data->coupons as $discount ) {
185
			$time = ( 'day' === $reporter->chart_groupby ) ? date( 'Y-m-d', strtotime( $discount->post_date ) ) : date( 'Y-m', strtotime( $discount->post_date ) );
186
187
			if ( ! isset( $period_totals[ $time ] ) ) {
188
				continue;
189
			}
190
191
			$period_totals[ $time ]['discount'] = wc_format_decimal( $discount->discount_amount, 2 );
192
		}
193
194
		$sales_data  = array(
195
			'total_sales'       => $report_data->total_sales,
196
			'net_sales'         => $report_data->net_sales,
197
			'average_sales'     => $report_data->average_sales,
198
			'total_orders'      => $report_data->total_orders,
199
			'total_items'       => $report_data->total_items,
200
			'total_tax'         => wc_format_decimal( $report_data->total_tax + $report_data->total_shipping_tax, 2 ),
201
			'total_shipping'    => $report_data->total_shipping,
202
			'total_refunds'     => $report_data->total_refunds,
203
			'total_discount'    => $report_data->total_coupons,
204
			'totals_grouped_by' => $reporter->chart_groupby,
205
			'totals'            => $period_totals,
206
			'total_customers'   => $total_customers,
207
		);
208
209
		$sales_data = apply_filters( 'woocommerce_cli_sales_report', $sales_data );
210
211
		if ( empty( $assoc_args['fields'] ) ) {
212
			$assoc_args['fields'] = array_keys( $sales_data );
213
		}
214
215
		$formatter = $this->get_formatter( $assoc_args );
216
		$formatter->display_item( $sales_data );
217
	}
218
219
	/**
220
	 * View report of top sellers.
221
	 *
222
	 * ## OPTIONS
223
	 *
224
	 * [--<field>=<value>]
225
	 * : Filter report based on report property.
226
	 *
227
	 * [--field=<field>]
228
	 * : Prints the value of a single field for each seller.
229
	 *
230
	 * [--fields=<fields>]
231
	 * : Limit the output to specific report fields.
232
	 *
233
	 * [--format=<format>]
234
	 * : Acceptec values: table, csv, json, count, ids. Default: table.
235
	 *
236
	 * [--period=<period>]
237
	 * : The supported periods are: week, month, last_month, and year. If invalid
238
	 * period is supplied, week is used. If period is not specified, the current
239
	 * day is used.
240
	 *
241
	 * [--date_min]
242
	 * : Return sales for a specific start date. The date need to be in the YYYY-MM-AA format.
243
	 *
244
	 * [--date_max]
245
	 * : Return sales for a specific end date. The dates need to be in the YYYY-MM-AA format.
246
	 *
247
	 * [--limit]
248
	 * : Limit report result. Default: 12.
249
	 *
250
	 * ## AVAILABLE FIELDS
251
	 *
252
	 * These fields will be displayed by default for each row:
253
	 *
254
	 * * title
255
	 * * product_id
256
	 * * quantity
257
	 *
258
	 * ## EXAMPLES
259
	 *
260
	 *     wp wc report top_sellers
261
	 *
262
	 *     wp wc report top_sellers --period=last_month
263
	 *
264
	 * @since 2.5.0
265
	 */
266
	public function top_sellers( $__, $assoc_args ) {
267
		$reporter    = $this->get_reporter( $assoc_args );
268
		$top_sellers = $reporter->get_order_report_data( array(
269
			'data' => array(
270
				'_product_id' => array(
271
					'type'            => 'order_item_meta',
272
					'order_item_type' => 'line_item',
273
					'function'        => '',
274
					'name'            => 'product_id'
275
				),
276
				'_qty' => array(
277
					'type'            => 'order_item_meta',
278
					'order_item_type' => 'line_item',
279
					'function'        => 'SUM',
280
					'name'            => 'order_item_qty'
281
				)
282
			),
283
			'order_by'     => 'order_item_qty DESC',
284
			'group_by'     => 'product_id',
285
			'limit'        => isset( $assoc_args['limit'] ) ? absint( $assoc_args['limit'] ) : 12,
286
			'query_type'   => 'get_results',
287
			'filter_range' => true,
288
		) );
289
290
		$top_sellers_data = array();
291 View Code Duplication
		foreach ( $top_sellers as $top_seller ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
292
			$product = wc_get_product( $top_seller->product_id );
293
294
			if ( $product ) {
295
				$top_sellers_data[] = array(
296
					'title'      => $product->get_title(),
297
					'product_id' => $top_seller->product_id,
298
					'quantity'   => $top_seller->order_item_qty,
299
				);
300
			}
301
		}
302
		$top_sellers_data = apply_filters( 'woocommerce_cli_top_sellers_report', $top_sellers_data );
303
304
		$formatter = $this->get_formatter( $assoc_args );
305
		if ( 'ids' === $formatter->format ) {
306
			$query_args['fields'] = 'ids';
307
			echo implode( ' ', wp_list_pluck( $top_sellers_data, 'product_id' ) );
308
		} else {
309
			$formatter->display_items( $top_sellers_data );
310
		}
311
	}
312
313
	/**
314
	 * Setup the report object and parse any date filtering
315
	 *
316
	 * @since  2.5.0
317
	 * @param  array $assoc_args Arguments provided in when invoking the command
318
	 * @return WC_Report_Sales_By_Date
319
	 */
320
	private function get_reporter( $assoc_args ) {
321
322
		include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php' );
323
		include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-report-sales-by-date.php' );
324
325
		$report = new WC_Report_Sales_By_Date();
326
327
		if ( empty( $assoc_args['period'] ) ) {
328
329
			// custom date range
330
			$assoc_args['period'] = 'custom';
331
332 View Code Duplication
			if ( ! empty( $assoc_args['date_min'] ) || ! empty( $assoc_args['date_max'] ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
333
334
				// overwrite _GET to make use of WC_Admin_Report::calculate_current_range() for custom date ranges
335
				$_GET['start_date'] = $this->parse_datetime( $assoc_args['date_min'] );
336
				$_GET['end_date'] = isset( $assoc_args['date_max'] ) ? $this->parse_datetime( $assoc_args['date_max'] ) : null;
337
338
			} else {
339
340
				// default custom range to today
341
				$_GET['start_date'] = $_GET['end_date'] = date( 'Y-m-d', current_time( 'timestamp' ) );
342
			}
343
344
		} else {
345
346
			// ensure period is valid
347
			if ( ! in_array( $assoc_args['period'], array( 'week', 'month', 'last_month', 'year' ) ) ) {
348
				$assoc_args['period'] = 'week';
349
			}
350
351
			// TODO: change WC_Admin_Report class to use "week" instead, as it's more consistent with other periods
352
			// allow "week" for period instead of "7day"
353
			if ( 'week' === $assoc_args['period'] ) {
354
				$assoc_args['period'] = '7day';
355
			}
356
		}
357
358
		$report->calculate_current_range( $assoc_args['period'] );
359
360
		return $report;
361
	}
362
363
	/**
364
	 * Get default format fields that will be used in `list` and `get` subcommands.
365
	 *
366
	 * @since  2.5.0
367
	 * @return string
368
	 */
369
	protected function get_default_format_fields() {
370
		return 'title,product_id,quantity';
371
	}
372
}
373