PluginProbe
MainWP Key Maker / 0.2
MainWP Key Maker v0.2
trunk 0.1 0.2 1.0 1.1 1.2 1.3
mainwp-key-maker / mainwp-key-maker.php

mainwp-key-maker.php in MainWP Key Maker 0.2, at mainwp-key-maker.php

618 lines 19.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: MainWP Key Maker
4 Plugin URI: https://mainwp.com/
5 Description: Easily convert a form into a "key" to use with the MainWP Bulk Settings Manager Extension
6 Author: MainWP
7 Author URI: https://mainwp.com
8 Version: 0.2
9 */
10
11 // If we made redirection in this session
12 $mainwp_key_maker_is_redirect = false;
13 // Store current user session id
14 $mainwp_key_maker_session_id = "";
15
16
17 if ( ! function_exists( "mainwp_key_maker_get_session_id" ) ) {
18 /**
19 * Get current user session id
20 */
21 function mainwp_key_maker_get_session_id() {
22 global $mainwp_key_maker_session_id;
23
24 // We use global so this happen only once
25 if ( defined( "AUTH_COOKIE" ) && isset( $_COOKIE[ AUTH_COOKIE ] ) && empty( $mainwp_key_maker_session_id ) ) {
26 // Different users can share one account - so use session id
27 $cookie_elements = explode( '|', $_COOKIE[ AUTH_COOKIE ] );
28 if ( isset( $cookie_elements[2] ) ) {
29 $mainwp_key_maker_session_id = substr( (string) $cookie_elements[2], 0, 30 );
30 }
31 }
32 }
33 }
34
35
36 if ( ! function_exists( "mainwp_key_maker_store_request" ) ) {
37 /**
38 * Store $_GET/$_POST inside transient for further use
39 */
40 function mainwp_key_maker_store_request() {
41 global $mainwp_key_maker_session_id, $mainwp_key_maker_is_redirect;
42
43 mainwp_key_maker_get_session_id();
44
45 // Only for logged
46 if ( ! empty( $mainwp_key_maker_session_id ) ) {
47 // Skip heartbleeed WordPress action
48 if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'heartbeat' && isset( $_REQUEST['screen_id'] ) ) {
49 return;
50 }
51
52 $previous_data = get_transient( 'mainwp_eir_' . $mainwp_key_maker_session_id );
53 if ( $previous_data === false ) {
54 $previous_data = array();
55 }
56
57 $datas = array();
58
59 // Store values in transient so we have access to them in next page
60 $datas['post'] = $_POST;
61 $datas['get'] = $_GET;
62 $datas['url'] = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
63 $datas['time'] = time();
64
65 $previous_data[] = $datas;
66
67 set_transient( 'mainwp_eir_' . $mainwp_key_maker_session_id, $previous_data, 90 );
68 $mainwp_key_maker_is_redirect = true;
69 }
70 }
71 }
72
73 // We add additional functionality to wp_redirect and wp_verify_nonce for administrators
74 if ( ! function_exists( 'wp_redirect' ) ) :
75
76 /**
77 * Redirects to another page.
78 * Additionally, stores $_GET, $_POST and url in transient
79 *
80 * @since 1.5.1
81 *
82 * @global bool $is_IIS
83 *
84 * @param string $location The path to redirect to.
85 * @param int $status Status code to use.
86 *
87 * @return bool False if $location is not provided, true otherwise.
88 */
89 function wp_redirect( $location, $status = 302 ) {
90 global $is_IIS;
91
92 /**
93 * Filter the redirect location.
94 *
95 * @since 2.1.0
96 *
97 * @param string $location The path to redirect to.
98 * @param int $status Status code to use.
99 */
100 $location = apply_filters( 'wp_redirect', $location, $status );
101
102 /**
103 * Filter the redirect status code.
104 *
105 * @since 2.3.0
106 *
107 * @param int $status Status code to use.
108 * @param string $location The path to redirect to.
109 */
110 $status = apply_filters( 'wp_redirect_status', $status, $location );
111
112 if ( ! $location ) {
113 return false;
114 }
115
116 $location = wp_sanitize_redirect( $location );
117
118 if ( ! $is_IIS && PHP_SAPI != 'cgi-fcgi' ) {
119 status_header( $status );
120 } // This causes problems on IIS and some FastCGI setups
121
122 mainwp_key_maker_store_request();
123
124 header( "Location: $location", true, $status );
125
126 return true;
127 }
128 endif;
129
130 if ( ! function_exists( 'wp_verify_nonce' ) ) :
131 /**
132 * Verify that correct nonce was used with time limit.
133 * Additionally stores name of nonce action in transient
134 *
135 * The user is given an amount of time to use the token, so therefore, since the
136 * UID and $action remain the same, the independent variable is the time.
137 *
138 * @since 2.0.3
139 *
140 * @param string $nonce Nonce that was used in the form to verify
141 * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
142 *
143 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
144 * 0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
145 */
146 function wp_verify_nonce( $nonce, $action = - 1 ) {
147 global $mainwp_key_maker_session_id;
148
149 if ( ! empty( $mainwp_key_maker_session_id ) ) {
150 $key_maker = get_transient( 'mainwp_ein_' . $mainwp_key_maker_session_id );
151 if ( $key_maker === false ) {
152 $key_maker = array();
153 }
154
155 $key_maker[ trim( $nonce ) ] = $action;
156 set_transient( 'mainwp_ein_' . $mainwp_key_maker_session_id, $key_maker );
157 }
158
159 $nonce = (string) $nonce;
160 $user = wp_get_current_user();
161 $uid = (int) $user->ID;
162 if ( ! $uid ) {
163 /**
164 * Filter whether the user who generated the nonce is logged out.
165 *
166 * @since 3.5.0
167 *
168 * @param int $uid ID of the nonce-owning user.
169 * @param string $action The nonce action.
170 */
171 $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
172 }
173
174 if ( empty( $nonce ) ) {
175 return false;
176 }
177
178 $token = wp_get_session_token();
179 $i = wp_nonce_tick();
180
181 // Nonce generated 0-12 hours ago
182 $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), - 12, 10 );
183 if ( hash_equals( $expected, $nonce ) ) {
184 return 1;
185 }
186
187 // Nonce generated 12-24 hours ago
188 $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), - 12, 10 );
189 if ( hash_equals( $expected, $nonce ) ) {
190 return 2;
191 }
192
193 // Invalid nonce
194 return false;
195 }
196 endif;
197
198 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
199 // We want to support ajax calls also
200 mainwp_key_maker_store_request();
201 }
202
203 class MainWP_Key_Maker {
204
205 public function __construct() {
206 add_action( 'init', array( $this, 'init' ) );
207 }
208
209 public function init() {
210 mainwp_key_maker_get_session_id();
211
212 if ( ! current_user_can( 'manage_options' ) || ! is_admin() ) {
213 return;
214 }
215
216 global $mainwp_key_maker_is_redirect;
217
218 // Display redirect data on next page
219 if ( $mainwp_key_maker_is_redirect ) {
220 return;
221 }
222
223 // Skip Ajax
224 if ( defined( 'XMLRPC_REQUEST' ) || defined( 'DOING_AJAX' ) || defined( 'IFRAME_REQUEST' ) ) {
225 return;
226 }
227
228 // Don't process if fatal error
229 $error = error_get_last();
230 if ( ! empty( $error ) && ( $error['type'] & ( E_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR ) ) ) {
231 return;
232 }
233
234 add_action( 'wp_before_admin_bar_render', array( $this, 'bar_render' ), 999 );
235 add_action( 'admin_footer', array( $this, 'toolbar' ), 999 );
236 }
237
238 /**
239 * Render Key Maker button inside admin bar
240 * Display content using thickbox popup
241 */
242 public function bar_render() {
243 global $wp_admin_bar;
244
245 wp_register_script( 'mainwp-key-maker-colorbox', plugins_url( '/js/jquery.colorbox-min.js', __FILE__ ), array( 'jquery' ) );
246 wp_enqueue_script( 'mainwp-key-maker-colorbox' );
247
248 wp_register_script( 'mainwp-key-maker-zeroclipboard', plugins_url( '/js/ZeroClipboard.min.js', __FILE__ ), array( 'jquery' ) );
249 wp_enqueue_script( 'mainwp-key-maker-zeroclipboard' );
250
251 wp_register_style( 'mainwp-key-maker-colorbox', plugins_url( '/css/colorbox.css', __FILE__ ) );
252 wp_enqueue_style( 'mainwp-key-maker-colorbox' );
253
254 $args = array(
255 'id' => 'mainwp-key-maker-adminbar-node',
256 'title' => __( 'MainWP Key Maker', 'mainwp-key-maker' ),
257 'href' => '#mainwp-key-maker-box'
258 );
259
260 $wp_admin_bar->add_node( $args );
261 ?>
262 <style>
263 #wp-admin-bar-mainwp-key-maker {
264 cursor: pointer;
265 }
266 .mainwp-km-info {
267 margin-top: 1em;
268 padding: .6em;
269 border-left: 4px Solid #7fb100;
270 box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
271 -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
272 }
273 </style>
274 <script>
275 jQuery(function () {
276 var client = new ZeroClipboard(jQuery(".mainwp-key-maker-textarea"));
277
278 client.on('ready', function (event) {
279 client.on("copy", function (event) {
280 event.clipboardData.setData("text/plain", event.target.innerHTML);
281 });
282
283 client.on('aftercopy', function (event) {
284 jQuery("#" + event.target.id + "-button").val('<?php _e('Copied to Clipboard!', 'mainwp-key-maker'); ?>');
285 jQuery("#" + event.target.id + "-button").removeClass('button-primary');
286 setInterval(function () {
287 jQuery("#" + event.target.id + "-button").val('<?php _e('Copy to Clipboard', 'mainwp-key-maker'); ?>');
288 jQuery("#" + event.target.id + "-button").addClass('button-primary');
289 }, 3000);
290 });
291 });
292
293 var client2 = new ZeroClipboard(jQuery(".mainwp-key-maker-copy-button"));
294
295 client2.on('ready', function (event) {
296 client2.on('aftercopy', function (event) {
297 event.target.value = '<?php _e('Copied to Clipboard!', 'mainwp-key-maker'); ?>';
298 event.target.classList.remove('button-primary');
299 setInterval(function () {
300 event.target.value = '<?php _e('Copy to Clipboard', 'mainwp-key-maker'); ?>';
301 event.target.classList.add('button-primary');
302 }, 3000);
303 });
304 });
305
306 jQuery("#wp-admin-bar-mainwp-key-maker-adminbar-node a").colorbox({inline: true, width: "1230px"});
307
308 jQuery(".mainwp-key-maker-debug-a").on("click", function () {
309 jQuery("#mainwp-key-maker-debug-" + jQuery(this).attr("ids")).toggle();
310 });
311 });
312 </script>
313
314 <?php
315 }
316
317 /**
318 * Display content for admin bar button
319 */
320 public function toolbar() {
321 global $mainwp_key_maker_session_id;
322
323 // Do we have anything to display?
324 $is_any_info = false;
325 $is_there_pre_request = false;
326 ?>
327 <div style="display:none;">
328 <div id="mainwp-key-maker-box">
329 <span style="float: right;">
330 <a href="https://mainwp.com" target="_blank" title="MainWP"><img style="height: 40px; margin-right: 15px;" src="<?php echo plugins_url('images/logo.png', __FILE__); ?>" alt="MainWP" /></a>
331 </span>
332 <h1><?php _e( 'MainWP Key Maker', 'mainwp-key-maker'); ?></h1>
333 <div style="clear: both;"></div>
334 <?php
335
336 $nonce = get_transient( 'mainwp_ein_' . $mainwp_key_maker_session_id );
337
338 if ( $nonce === false ) {
339 $nonce = array();
340 }
341
342 $previous_datas = get_transient( 'mainwp_eir_' . $mainwp_key_maker_session_id );
343
344 if ( $previous_datas !== false ) {
345 delete_transient( 'mainwp_ein_' . $mainwp_key_maker_session_id );
346 delete_transient( 'mainwp_eir_' . $mainwp_key_maker_session_id );
347 foreach ( $previous_datas as $previous_counter => $previous_data ):
348 if ( ( isset( $previous_data['post'] ) && ! empty( $previous_data['post'] ) ) || ( isset( $previous_data['get'] ) && ! empty( $previous_data['get'] ) ) ):
349 $is_any_info = true;
350 $is_there_pre_request = true;
351 ?>
352 <div style="padding-bottom: 1em; margin-bottom: 1px Solid #000;">
353 <?php
354 if ( $is_there_pre_request ):
355 ?>
356 <div class="mainwp-km-info">
357 <em><?php _e('The "Verify Form Fields and Values" button allows you to tell if the Key will contain the information you want.', 'mainwp-key-maker'); ?></em><br/>
358 <em><?php _e('If it does not, you may need to submit the form in order for the Key Maker to be able to correctly gather the form fields and values.', 'mainwp-key-maker'); ?></em>
359 </div>
360 <?php
361 endif;
362 ?>
363 <p>
364 <h2 style="margin-bottom: .3em;"><?php _e( 'Post-submission Request', 'mainwp-key-maker' ); ?></h2>
365 <em>( <?php echo date_i18n( "d-m-Y H:i:s", $previous_data['time'] ); ?> )</em>
366 <?php echo( isset( $previous_data['url'] ) ? esc_html( $previous_data['url'] ) : __( 'Unknown url', 'mainwp-key-maker' ) ); ?>
367 <span style="float: right; margin-right: 1.5em;">
368 <a href="#"
369 class="mainwp-key-maker-debug-a button"
370 style="text-decoration: none;"
371 ids="<?php echo esc_attr( $previous_counter ); ?>"><?php _e( 'Verify Form Fields and Values', 'mainwp-key-maker' ); ?>
372 </a>
373 <input type="submit"
374 id="mainwp-key-maker-textarea-previous-<?php echo esc_attr( $previous_counter ); ?>-button"
375 data-clipboard-target="mainwp-key-maker-textarea-previous-<?php echo esc_attr( $previous_counter ); ?>"
376 class="mainwp-key-maker-copy-button button button-primary"
377 value="<?php _e( 'Copy to Clipboard', 'mainwp-key-maker' ); ?>">
378 </span>
379 </p>
380 <div id="mainwp-key-maker-debug-<?php echo esc_attr( $previous_counter ); ?>"
381 style="display:none; width: 1170px !important; margin-bottom: 1em;"
382 class="postbox">
383 <div class="inside">
384 <pre><?php echo $this->custom_print_r( $previous_data, $nonce ); ?></pre>
385 </div>
386 </div>
387
388 <textarea rows="12"
389 cols="90"
390 style="width: 1170px;"
391 class="mainwp-key-maker-textarea"
392 id="mainwp-key-maker-textarea-previous-<?php echo esc_attr( $previous_counter ); ?>"
393 readonly><?php echo esc_textarea( $this->parse_data( $previous_data, $nonce ) ); ?></textarea>
394 </div>
395 <?php
396 endif;
397 endforeach;
398
399
400 }
401
402 $current_data = array();
403 $current_data['post'] = $_POST;
404 $current_data['get'] = $_GET;
405 $current_data['url'] = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
406 $current_data['time'] = time();
407 ?>
408 <div style="padding-bottom: 1em; margin-bottom: 1px Solid #000;">
409 <?php
410 if (!empty($current_data['post']) || !empty($current_data['get'])):
411 $is_any_info = true;
412 ?>
413 <?php
414 if ( ! $is_there_pre_request ):
415 ?>
416 <div class="mainwp-km-info">
417 <em><?php _e('The "Verify Form Fields and Values" button allows you to tell if the Key will contain the information you want.', 'mainwp-key-maker'); ?></em><br/>
418 <em><?php _e('If it does not, you may need to submit the form in order for the Key Maker to be able to correctly gather the form fields and values.', 'mainwp-key-maker'); ?></em>
419 </div>
420 <?php
421 endif;
422 ?>
423 <p>
424 <h2 style="margin-bottom: .3em;"><?php _e('Pre-submission Request', 'mainwp-key-maker'); ?></h2>
425 <em>( <?php echo date_i18n("d-m-Y H:i:s", $current_data['time']); ?> )</em>
426 <?php echo esc_html($current_data['url']); ?>
427 <span style="float: right; margin-right: 1.5em;">
428 <a
429 href="#"
430 class="mainwp-key-maker-debug-a button"
431 ids="current"
432 style="text-decoration: none;"><?php _e('Verify Form Fields and Values', 'mainwp-key-maker'); ?>
433 </a>
434 <input type="submit"
435 id="mainwp-key-maker-textarea-button"
436 data-clipboard-target="mainwp-key-maker-textarea"
437 class="mainwp-key-maker-copy-button button button-primary"
438 value="<?php _e('Copy to clipboard', 'mainwp-key-maker'); ?>">
439 </span>
440 </p>
441
442 <div id="mainwp-key-maker-debug-current"
443 style="display:none; width: 1170px !important; margin-bottom: 1em;"
444 class="postbox">
445 <div class="inside">
446 <pre><?php echo $this->custom_print_r($current_data, $nonce); ?></pre>
447 </div>
448 </div>
449
450
451 <textarea rows="12"
452 cols="90"
453 style="width: 1170px;"
454 class="mainwp-key-maker-textarea"
455 id="mainwp-key-maker-textarea"
456 readonly><?php echo esc_textarea($this->parse_data($current_data, $nonce)); ?></textarea>
457 <?php
458 endif;
459
460 if ( ! $is_any_info ):
461 ?>
462 <div class="mainwp-km-info"><?php _e( 'No form detected. You may have to submit the form before Key Maker is able to find the form and make the Key.', 'mainwp-key-maker' ); ?></div>
463 <?php
464 endif;
465 ?>
466 </div>
467 </div>
468 </div>
469 <?php
470 }
471
472 /**
473 * @param $data
474 * @param $nonce
475 *
476 * Print $_GET and $_POST using print_r with XSS protection
477 *
478 * @return string
479 */
480 public function custom_print_r( $data, $nonce ) {
481 return esc_html( print_r( $this->check_nonces( $data, $nonce ), true ) );
482 }
483
484 /**
485 * @param $data
486 * @param $nonce
487 *
488 * Recursive check if in array, nonce field exist
489 *
490 * @return array
491 */
492 public function check_nonces( $data, $nonce ) {
493 $new = array();
494 foreach ( $data as $key => $val ) {
495 if ( is_array( $val ) ) {
496 $new[ $key ] = $this->check_nonces( $val, $nonce );
497 } else {
498 $val = trim( $val );
499 if ( isset( $nonce[ $val ] ) ) {
500 $new[ $key ] = __( 'NONCE FIELD', 'mainwp-key-maker' ) . ' - ' . $nonce[ $val ];
501 } else {
502 $new[ $key ] = $val;
503 }
504 }
505 }
506
507 return $new;
508 }
509
510 /**
511 * @param $data
512 * @param $nonce
513 *
514 * Parse datas in format readable for Skeleton Key
515 *
516 * @return string
517 */
518 public function parse_data( $data, $nonce ) {
519 $out = array();
520 if ( isset( $data['post'] ) ) {
521 foreach ( $this->flatten_array( $data['post'] ) as $key => $val ) {
522 $array = array();
523 $val = trim( $val );
524
525 if ( isset( $nonce[ $val ] ) ) {
526 $array['field_type'] = 'nonce_field';
527 $array['nonce_field_name'] = $nonce[ $val ];
528 $array['nonce_field_arg'] = $key;
529 } else {
530 if ( strpos( $val, "\n" ) !== false || strpos( $val, "\r" ) !== false ) {
531 $array['field_type'] = 'textarea_field';
532 $array['textarea_field_description'] = $val;
533 $array['textarea_field_name'] = $key;
534 $array['textarea_field_value'] = $val;
535 $array['textarea_field_type'] = 'post';
536 } else {
537 $array['field_type'] = 'text_field';
538 $array['text_field_description'] = $val;
539 $array['text_field_name'] = $key;
540 $array['text_field_value'] = $val;
541 $array['text_field_type'] = 'post';
542 }
543 }
544
545 $out[] = http_build_query( $array );
546 }
547 }
548
549 if ( isset( $data['get'] ) ) {
550 foreach ( $this->flatten_array( $data['get'] ) as $key => $val ) {
551 $array = array();
552 $val = trim( $val );
553
554 if ( isset( $nonce[ $val ] ) ) {
555 $array['field_type'] = 'nonce_field';
556 $array['nonce_field_name'] = $nonce[ $val ];
557 $array['nonce_field_arg'] = $key;
558 } else {
559 $array['field_type'] = 'text_field';
560 $array['text_field_description'] = $val;
561 $array['text_field_name'] = $key;
562 $array['text_field_value'] = $val;
563 $array['text_field_type'] = 'get';
564 }
565
566 $out[] = http_build_query( $array );
567 }
568 }
569
570 $url = "";
571 if ( isset( $data['url'] ) ) {
572 $url = parse_url( $data['url'] );
573 $url = ( isset( $url['path'] ) ? $url['path'] : '' ) . ( isset( $url['query'] ) ? '?' . $url['query'] : '' );
574 }
575
576 $array = array();
577 $array['field_type'] = 'settings_field';
578 $array['settings_field_name'] = __( 'Imported', 'mainwp-key-maker' ) . ' ' . current_time( "d-m-Y H:i:s" );
579 $array['settings_field_url'] = $url;
580
581 $content = http_build_query( $array ) . '&' . implode( '&', $out );
582 $hash = sha1( $content );
583
584 $return = "-----BEGIN BULK SETTINGS MANAGER KEY-----\r\n";
585 $return .= base64_encode( $hash . '|' . $content );
586 $return .= "\r\n-----END BULK SETTINGS MANAGER KEY-----\r\n";
587
588 return $return;
589 }
590
591 /**
592 * @param $array
593 * @param string $previous
594 *
595 * Convert multidimensional array into single dimensional array
596 * Something like http[like][array][structure]
597 *
598 * @return array
599 */
600 public function flatten_array( $array, $previous = "" ) {
601 $out = array();
602 foreach ( $array as $key => $val ) {
603 if ( is_array( $val ) ) {
604 $out = array_merge( $this->flatten_array( $val, ( $previous == "" ? $key : $previous . '[' . $key . ']' ) ), $out );
605 } else {
606 if ( $previous == "" ) {
607 $out[ $key ] = $val;
608 } else {
609 $out[ $previous . '[' . $key . ']' ] = $val;
610 }
611 }
612 }
613
614 return $out;
615 }
616 }
617
618 $mainWP = new MainWP_Key_Maker();