PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.8
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.8
2.12.8 2.12.7 2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 All 98 releases
← All changes | inc/admin-ajax.php +100 -4 2.7.0 → 2.12.8 View file →
@@ -37,8 +37,10 @@
37 37 add_action( 'wp_ajax_sureforms_recommended_plugin_activate', [ $this, 'required_plugin_activate' ] );
38 38 add_action( 'wp_ajax_sureforms_recommended_plugin_install', 'wp_ajax_install_plugin' );
39 39 add_action( 'wp_ajax_sureforms_integration', [ $this, 'generate_data_for_suretriggers_integration' ] );
40 40 add_action( 'wp_ajax_srfm_download_export', [ $this, 'download_export_file' ] );
41 + add_action( 'wp_ajax_srfm_download_logs', [ $this, 'download_client_log' ] );
42 + add_action( 'wp_ajax_srfm_clear_logs', [ $this, 'clear_client_log' ] );
41 43
42 44 add_filter( SRFM_SLUG . '_admin_filter', [ $this, 'localize_script_integration' ] );
43 45 }
44 46
@@ -183,9 +185,9 @@
183 185 }
184 186
185 187 // Translators: %s: Form ID.
186 188 $form_name = ! empty( $form->post_title ) ? $form->post_title : sprintf( __( 'SureForms id: %s', 'sureforms' ), $form_id );
187 - $api_url = apply_filters( 'suretriggers_get_iframe_url', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL );
189 + $api_url = apply_filters( 'suretriggers_get_iframe_url', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- SureTriggers' own filter; the name must match SureTriggers exactly to integrate.
188 190
189 191 // This is the format of data required by SureTriggers for adding iframe in target id.
190 192 $body = [
191 193 'client_id' => 'SureForms',
@@ -425,9 +427,17 @@
425 427 if ( 'csv' === $file_info['extension'] ) {
426 428 $content_type = 'text/csv';
427 429 } elseif ( 'zip' === $file_info['extension'] ) {
428 430 $content_type = 'application/zip';
429 - $filename = 'SureForms Entries.zip';
431 + /**
432 + * Filter the user-facing filename used when serving an exported ZIP archive.
433 + *
434 + * @since 2.9.0
435 + *
436 + * @param string $filename Default ZIP filename.
437 + * @param array<string,mixed> $file_info pathinfo() result for the file being served.
438 + */
439 + $filename = (string) apply_filters( 'srfm_export_zip_filename', 'SureForms Entries.zip', $file_info );
430 440 }
431 441 }
432 442
433 443 // Set headers for download.
@@ -442,12 +452,98 @@
442 452 ob_end_clean();
443 453 }
444 454
445 455 // Output the file.
446 - readfile( $filepath ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile -- Need direct file output for download.
456 + readfile( $filepath ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile, WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Direct file output is required to stream the download.
447 457
448 458 // Clean up the temporary file.
449 - unlink( $filepath );
459 + wp_delete_file( $filepath );
450 460
451 461 exit;
452 462 }
463 + /**
464 + * Stream the client debug log to an administrator.
465 + *
466 + * Takes no filename parameter. There is exactly one log file and the server
467 + * derives its path, which removes the path-traversal question entirely rather
468 + * than guarding against it -- and keeps the unguessable file name, which is
469 + * what actually protects the log on nginx, out of the page.
470 + *
471 + * @since 2.12.6
472 + * @return void
473 + */
474 + public function download_client_log() {
475 + $this->verify_log_request();
476 +
477 + $path = Client_Logger::get_log_path( false );
478 + $has_log = '' !== $path && file_exists( $path );
479 +
480 + // The buttons are always offered while logging is on, so downloading before
481 + // anything has failed is a normal thing to do. Hand back an explanatory file
482 + // rather than a wp_die() screen -- an empty log is the good outcome.
483 + if ( ! $has_log ) {
484 + header( 'Content-Type: text/plain; charset=utf-8' );
485 + header( 'X-Content-Type-Options: nosniff' );
486 + header( 'Content-Disposition: attachment; filename="sureforms-debug-log.txt"' );
487 +
488 + if ( ob_get_level() ) {
489 + ob_end_clean();
490 + }
491 +
492 + echo esc_html__( 'No form submission failures have been recorded.', 'sureforms' );
493 + exit;
494 + }
495 +
496 + $size = filesize( $path );
497 +
498 + header( 'Content-Type: text/plain; charset=utf-8' );
499 + header( 'X-Content-Type-Options: nosniff' );
500 + header( 'Content-Disposition: attachment; filename="sureforms-debug-log.txt"' );
501 +
502 + if ( is_int( $size ) ) {
503 + header( 'Content-Length: ' . $size );
504 + }
505 +
506 + header( 'Cache-Control: private, max-age=0, must-revalidate' );
507 +
508 + if ( ob_get_level() ) {
509 + ob_end_clean();
510 + }
511 +
512 + readfile( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile, WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Direct file output is required to stream the download.
513 + exit;
514 + }
515 +
516 + /**
517 + * Delete the client debug log.
518 + *
519 + * @since 2.12.6
520 + * @return void
521 + */
522 + public function clear_client_log() {
523 + $this->verify_log_request();
524 +
525 + Client_Logger::clear();
526 +
527 + wp_send_json_success();
528 + }
529 +
530 + /**
531 + * Capability and nonce gate shared by both log actions.
532 + *
533 + * Capability first, ahead of the nonce, matching the ordering of the sibling
534 + * handlers in this class.
535 + *
536 + * @since 2.12.6
537 + * @return void
538 + */
539 + private function verify_log_request() {
540 + if ( ! Helper::current_user_can() ) {
541 + wp_die( esc_html__( 'You do not have permission to access this file.', 'sureforms' ) );
542 + }
543 +
544 + if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'srfm_client_logs' ) ) {
545 + wp_die( esc_html__( 'Security check failed.', 'sureforms' ) );
546 + }
547 + }
548 +
453 549 }