Completed
Push — master ( e4380d...bbc130 )
by Mike
07:56
created

WC_Tax_Rate_Importer::import_start()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 7
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 9
rs 9.6666
1
<?php
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 18 and the first side effect is on line 3.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
if ( ! class_exists( 'WP_Importer' ) ) {
7
	return;
8
}
9
10
/**
11
 * Tax Rates importer - import tax rates and local tax rates into WooCommerce.
12
 *
13
 * @author      WooThemes
14
 * @category    Admin
15
 * @package     WooCommerce/Admin/Importers
16
 * @version     2.3.0
17
 */
18
class WC_Tax_Rate_Importer extends WP_Importer {
19
20
	/**
21
	 * The current file id.
22
	 *
23
	 * @var int
24
	 */
25
	public $id;
26
27
	/**
28
	 * The current file url.
29
	 *
30
	 * @var string
31
	 */
32
	public $file_url;
33
34
	/**
35
	 * The current import page.
36
	 *
37
	 * @var string
38
	 */
39
	public $import_page;
40
41
	/**
42
	 * The current delimiter.
43
	 *
44
	 * @var string
45
	 */
46
	public $delimiter;
47
48
	/**
49
	 * Constructor.
50
	 */
51
	public function __construct() {
52
		$this->import_page = 'woocommerce_tax_rate_csv';
53
		$this->delimiter   = empty( $_POST['delimiter'] ) ? ',' : wc_clean( $_POST['delimiter'] );
0 ignored issues
show
Documentation Bug introduced by
It seems like empty($_POST['delimiter'...an($_POST['delimiter']) can also be of type array. However, the property $delimiter is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
54
	}
55
56
	/**
57
	 * Registered callback function for the WordPress Importer.
58
	 *
59
	 * Manages the three separate stages of the CSV import process.
60
	 */
61
	public function dispatch() {
62
63
		$this->header();
64
65
		$step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step'];
66
67
		switch ( $step ) {
68
69
			case 0:
70
				$this->greet();
71
				break;
72
73
			case 1:
74
				check_admin_referer( 'import-upload' );
75
76
				if ( $this->handle_upload() ) {
77
78
					if ( $this->id ) {
79
						$file = get_attached_file( $this->id );
80
					} else {
81
						$file = ABSPATH . $this->file_url;
82
					}
83
84
					add_filter( 'http_request_timeout', array( $this, 'bump_request_timeout' ) );
85
86
					$this->import( $file );
87
				}
88
				break;
89
		}
90
91
		$this->footer();
92
	}
93
94
	/**
95
	 * Import is starting.
96
	 */
97
	private function import_start() {
98
		if ( function_exists( 'gc_enable' ) ) {
99
			gc_enable();
100
		}
101
		wc_set_time_limit( 0 );
102
		@ob_flush();
103
		@flush();
104
		@ini_set( 'auto_detect_line_endings', '1' );
105
	}
106
107
	/**
108
	 * UTF-8 encode the data if `$enc` value isn't UTF-8.
109
	 *
110
	 * @param mixed $data
111
	 * @param string $enc
112
	 * @return string
113
	 */
114
	public function format_data_from_csv( $data, $enc ) {
115
		return ( $enc == 'UTF-8' ) ? $data : utf8_encode( $data );
116
	}
117
118
	/**
119
	 * Import the file if it exists and is valid.
120
	 *
121
	 * @param mixed $file
122
	 */
123
	public function import( $file ) {
124
		if ( ! is_file( $file ) ) {
125
			$this->import_error( __( 'The file does not exist, please try again.', 'woocommerce' ) );
126
		}
127
128
		$this->import_start();
129
130
		$loop = 0;
131
132
		if ( ( $handle = fopen( $file, "r" ) ) !== false ) {
133
134
			$header = fgetcsv( $handle, 0, $this->delimiter );
135
136
			if ( 10 === sizeof( $header ) ) {
137
138
				while ( ( $row = fgetcsv( $handle, 0, $this->delimiter ) ) !== false ) {
139
140
					list( $country, $state, $postcode, $city, $rate, $name, $priority, $compound, $shipping, $class ) = $row;
141
142
					$tax_rate = array(
143
						'tax_rate_country'  => $country,
144
						'tax_rate_state'    => $state,
145
						'tax_rate'          => $rate,
146
						'tax_rate_name'     => $name,
147
						'tax_rate_priority' => $priority,
148
						'tax_rate_compound' => $compound ? 1 : 0,
149
						'tax_rate_shipping' => $shipping ? 1 : 0,
150
						'tax_rate_order'    => $loop ++,
151
						'tax_rate_class'    => $class
152
					);
153
154
					$tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate );
155
					WC_Tax::_update_tax_rate_postcodes( $tax_rate_id, wc_clean( $postcode ) );
1 ignored issue
show
Bug introduced by
It seems like wc_clean($postcode) targeting wc_clean() can also be of type array; however, WC_Tax::_update_tax_rate_postcodes() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
156
					WC_Tax::_update_tax_rate_cities( $tax_rate_id, wc_clean( $city ) );
1 ignored issue
show
Bug introduced by
It seems like wc_clean($city) targeting wc_clean() can also be of type array; however, WC_Tax::_update_tax_rate_cities() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
157
				}
158
159
			} else {
160
				$this->import_error( __( 'The CSV is invalid.', 'woocommerce' ) );
161
			}
162
163
			fclose( $handle );
164
		}
165
166
		// Show Result
167
		echo '<div class="updated settings-error"><p>
168
			' . sprintf( __( 'Import complete - imported <strong>%s</strong> tax rates.', 'woocommerce' ), $loop ) . '
169
		</p></div>';
170
171
		$this->import_end();
172
	}
173
174
	/**
175
	 * Performs post-import cleanup of files and the cache.
176
	 */
177
	public function import_end() {
178
		echo '<p>' . __( 'All done!', 'woocommerce' ) . ' <a href="' . admin_url('admin.php?page=wc-settings&tab=tax') . '">' . __( 'View Tax Rates', 'woocommerce' ) . '</a>' . '</p>';
179
180
		do_action( 'import_end' );
181
	}
182
183
	/**
184
	 * Handles the CSV upload and initial parsing of the file to prepare for.
185
	 * displaying author import options.
186
	 *
187
	 * @return bool False if error uploading or invalid file, true otherwise
188
	 */
189
	public function handle_upload() {
190
		if ( empty( $_POST['file_url'] ) ) {
191
192
			$file = wp_import_handle_upload();
193
194
			if ( isset( $file['error'] ) ) {
195
				$this->import_error( $file['error'] );
196
			}
197
198
			$this->id = absint( $file['id'] );
199
200
		} elseif ( file_exists( ABSPATH . $_POST['file_url'] ) ) {
201
			$this->file_url = esc_attr( $_POST['file_url'] );
202
		} else {
203
			$this->import_error();
204
		}
205
206
		return true;
207
	}
208
209
	/**
210
	 * Output header html.
211
	 */
212
	public function header() {
213
		echo '<div class="wrap"><div class="icon32 icon32-woocommerce-importer" id="icon-woocommerce"><br></div>';
214
		echo '<h1>' . __( 'Import Tax Rates', 'woocommerce' ) . '</h1>';
215
	}
216
217
	/**
218
	 * Output footer html.
219
	 */
220
	public function footer() {
221
		echo '</div>';
222
	}
223
224
	/**
225
	 * Output information about the uploading process.
226
	 */
227
	public function greet() {
228
229
		echo '<div class="narrow">';
230
		echo '<p>' . __( 'Hi there! Upload a CSV file containing tax rates to import the contents into your shop. Choose a .csv file to upload, then click "Upload file and import".', 'woocommerce' ).'</p>';
231
232
		echo '<p>' . sprintf( __( 'Tax rates need to be defined with columns in a specific order (10 columns). <a href="%s">Click here to download a sample</a>.', 'woocommerce' ), WC()->plugin_url() . '/dummy-data/sample_tax_rates.csv' ) . '</p>';
233
234
		$action = 'admin.php?import=woocommerce_tax_rate_csv&step=1';
235
236
		$bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
237
		$size = size_format( $bytes );
238
		$upload_dir = wp_upload_dir();
239
		if ( ! empty( $upload_dir['error'] ) ) :
240
			?><div class="error"><p><?php _e( 'Before you can upload your import file, you will need to fix the following error:', 'woocommerce' ); ?></p>
241
			<p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php
242
		else :
243
			?>
244
			<form enctype="multipart/form-data" id="import-upload-form" method="post" action="<?php echo esc_attr(wp_nonce_url($action, 'import-upload')); ?>">
245
				<table class="form-table">
246
					<tbody>
247
						<tr>
248
							<th>
249
								<label for="upload"><?php _e( 'Choose a file from your computer:', 'woocommerce' ); ?></label>
250
							</th>
251
							<td>
252
								<input type="file" id="upload" name="import" size="25" />
253
								<input type="hidden" name="action" value="save" />
254
								<input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
255
								<small><?php printf( __('Maximum size: %s', 'woocommerce' ), $size ); ?></small>
256
							</td>
257
						</tr>
258
						<tr>
259
							<th>
260
								<label for="file_url"><?php _e( 'OR enter path to file:', 'woocommerce' ); ?></label>
261
							</th>
262
							<td>
263
								<?php echo ' ' . ABSPATH . ' '; ?><input type="text" id="file_url" name="file_url" size="25" />
264
							</td>
265
						</tr>
266
						<tr>
267
							<th><label><?php _e( 'Delimiter', 'woocommerce' ); ?></label><br/></th>
268
							<td><input type="text" name="delimiter" placeholder="," size="2" /></td>
269
						</tr>
270
					</tbody>
271
				</table>
272
				<p class="submit">
273
					<input type="submit" class="button" value="<?php esc_attr_e( 'Upload file and import', 'woocommerce' ); ?>" />
274
				</p>
275
			</form>
276
			<?php
277
		endif;
278
279
		echo '</div>';
280
	}
281
282
	/**
283
	 * Show import error and quit.
284
	 * @param  string $message
285
	 */
286
	private function import_error( $message = '' ) {
287
		echo '<p><strong>' . __( 'Sorry, there has been an error.', 'woocommerce' ) . '</strong><br />';
288
		if ( $message ) {
289
			echo esc_html( $message );
290
		}
291
		echo '</p>';
292
		$this->footer();
293
		die();
294
	}
295
296
	/**
297
	 * Added to http_request_timeout filter to force timeout at 60 seconds during import.
298
	 *
299
	 * @param  int $val
300
	 * @return int 60
301
	 */
302
	public function bump_request_timeout( $val ) {
303
		return 60;
304
	}
305
}
306