PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.85
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.85
5.5.85 5.5.84 5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 All 161 releases
← All changes | WPDataAccess/API/WPDA_Apps.php +130 -14 5.5.81 → 5.5.85 View file →
@@ -280,9 +280,13 @@
280 280 'map' => array(
281 281 'required' => false,
282 282 'type' => 'string',
283 283 'description' => __( 'Map settings - JSON string', 'wp-data-access' ),
284 - 'sanitize_callback' => 'wp_kses_post',
284 + 'sanitize_callback' => function ( $param ) {
285 + $sanitized_settings = $this->sanitize_settings( json_decode( (string) $param, true ) );
286 + // Save sanitized JSON as string
287 + return json_encode( $sanitized_settings );
288 + },
285 289 'validate_callback' => 'rest_validate_request_arg',
286 290 ),
287 291 'chart' => array(
288 292 'required' => false,
@@ -514,8 +518,15 @@
514 518 'permission_callback' => '__return_true',
515 519 'args' => array(
516 520 'dbs_source' => $this->get_param( 'dbs' ),
517 521 'dbs_destination' => $this->get_param( 'dbs' ),
522 + 'appDbId' => array(
523 + 'required' => false,
524 + 'type' => 'integer',
525 + 'description' => __( 'App Id', 'wp-data-access' ),
526 + 'sanitize_callback' => 'absint',
527 + 'validate_callback' => 'rest_validate_request_arg',
528 + ),
518 529 ),
519 530 ) );
520 531 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/lang/get', array(
521 532 'methods' => array('POST'),
@@ -1013,8 +1024,27 @@
1013 1024 }
1014 1025 }
1015 1026 }
1016 1027 }
1028 + if ( isset( $settings['columns'] ) && is_array( $settings['columns'] ) && '1' !== $rel_tab ) {
1029 + $queryable_columns = array();
1030 + if ( isset( $settings['table']['columns'] ) && is_array( $settings['table']['columns'] ) ) {
1031 + foreach ( $settings['table']['columns'] as $column ) {
1032 + if ( isset( $column['queryable'] ) && $column['queryable'] ) {
1033 + $queryable_columns[] = $column['columnName'];
1034 + }
1035 + }
1036 + }
1037 + $app_columns = array();
1038 + foreach ( $settings['columns'] as $column ) {
1039 + if ( isset( $column['columnName'], $column['isSelected'] ) && $column['isSelected'] ) {
1040 + $app_columns[$column['columnName']] = in_array( $column['columnName'], $queryable_columns );
1041 + }
1042 + }
1043 + if ( 0 < count( $app_columns ) ) {
1044 + $col = $app_columns;
1045 + }
1046 + }
1017 1047 $table_api = new WPDA_Table();
1018 1048 return $table_api->select(
1019 1049 $dbs,
1020 1050 $tbl,
@@ -1066,8 +1096,9 @@
1066 1096 return array_map( function ( $value ) {
1067 1097 if ( true === $value['isSelected'] ) {
1068 1098 return $value['columnName'];
1069 1099 }
1100 + return null;
1070 1101 }, $columns );
1071 1102 }
1072 1103
1073 1104 public function app_get( $request ) {
@@ -1452,8 +1483,68 @@
1452 1483 $renamed = 0;
1453 1484 $debug_mode = 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG );
1454 1485 $debug = array();
1455 1486 $errors = array();
1487 + if ( $request->get_param( 'appDbId' ) ) {
1488 + // Update app only
1489 + $appDbId = $request->get_param( 'appDbId' );
1490 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- plugin table
1491 + $sql = $wpdb->prepare( "update `{$wpdb->prefix}wpda_app_container` set `cnt_dbs` = %s where `cnt_dbs` = %s and app_id = %d", array($dbs_destination, $dbs_source, $appDbId) );
1492 + $result = $wpdb->query( $sql );
1493 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1494 + $renamed += $result;
1495 + if ( $debug_mode ) {
1496 + $debug[] = array(
1497 + 'sql' => $sql,
1498 + 'result' => $result,
1499 + );
1500 + }
1501 + if ( '' !== $wpdb->last_error ) {
1502 + $errors[] = array(
1503 + 'sql' => $sql,
1504 + 'error' => $wpdb->last_error,
1505 + );
1506 + }
1507 + $sql_content = array("update `{$wpdb->prefix}wpda_app_container` set `cnt_table` = replace(`cnt_table`, '\"dbs\":\"%1s\"', '\"dbs\":\"%1s\"') where `cnt_table` like '%\"dbs\":\"%1s\"%' and app_id = %d", "update `{$wpdb->prefix}wpda_app_container` set `cnt_form` = replace(`cnt_form`, '\"dbs\":\"%1s\"', '\"dbs\":\"%1s\"') where `cnt_form` like '%\"dbs\":\"%1s\"%' and app_id = %d");
1508 + foreach ( $sql_content as $sql ) {
1509 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- plugin table
1510 + $result = $wpdb->query( $wpdb->prepare( $sql, array(
1511 + $dbs_source,
1512 + $dbs_destination,
1513 + $dbs_source,
1514 + $appDbId
1515 + ) ) );
1516 + $renamed += $result;
1517 + if ( $debug_mode ) {
1518 + $debug[] = array(
1519 + 'sql' => $sql,
1520 + 'result' => $result,
1521 + );
1522 + }
1523 + if ( '' !== $wpdb->last_error ) {
1524 + $errors[] = array(
1525 + 'sql' => $sql,
1526 + 'error' => $wpdb->last_error,
1527 + );
1528 + }
1529 + }
1530 + $context = array();
1531 + if ( $debug_mode ) {
1532 + $context['debug'] = $debug;
1533 + }
1534 + if ( 0 < count( $errors ) ) {
1535 + $context['errors'] = $errors;
1536 + return new \WP_Error('error', 'Failed renaming database', array(
1537 + 'status' => 401,
1538 + 'context' => $context,
1539 + ));
1540 + }
1541 + return $this->WPDA_Rest_Response( sprintf(
1542 + /* translators: %s = number of database substitutions */
1543 + __( 'Successfully renamed %s database occurrences', 'wp-data-access' ),
1544 + $renamed
1545 + ), null, $context );
1546 + }
1456 1547 // Rename all occurrences in repository tables and apps
1457 1548 $sqls = array(
1458 1549 "update `{$wpdb->prefix}wpda_publisher` set `pub_schema_name` = %s where `pub_schema_name` = %s",
1459 1550 "update `{$wpdb->prefix}wpda_project_page` set `page_schema_name` = %s where `page_schema_name` = %s",
@@ -1550,14 +1641,23 @@
1550 1641 ));
1551 1642 }
1552 1643 $suppress = $wpdadb->suppress_errors( true );
1553 1644 $chart_data = $wpdadb->get_results( $query, 'ARRAY_A' );
1645 + // Add an * before each label to support numeric labels
1646 + $chart_data_converted = array();
1647 + foreach ( $chart_data as $data ) {
1648 + $row = array();
1649 + foreach ( $data as $key => $value ) {
1650 + $row['*' . $key] = $value;
1651 + }
1652 + $chart_data_converted[] = $row;
1653 + }
1554 1654 $wpdadb->get_results( "create temporary table `wpda_chart_data_types` as {$query}", 'ARRAY_A' );
1555 1655 $explain = $wpdadb->get_results( "desc `wpda_chart_data_types`", 'ARRAY_A' );
1556 1656 $wpdadb->get_results( "drop temporary table `wpda_chart_data_types`", 'ARRAY_A' );
1557 1657 $wpdadb->suppress_errors( $suppress );
1558 1658 return array(
1559 - 'data' => $chart_data,
1659 + 'data' => $chart_data_converted,
1560 1660 'explain' => $explain,
1561 1661 );
1562 1662 } else {
1563 1663 return new \WP_Error('error', $msg, array(
@@ -2038,8 +2138,9 @@
2038 2138 $app_id_details = array_map( function ( $e ) {
2039 2139 if ( isset( $e['app_id_detail'] ) ) {
2040 2140 return $e['app_id_detail'];
2041 2141 }
2142 + return null;
2042 2143 }, $apps );
2043 2144 $app_titles = array();
2044 2145 foreach ( $app_id_details as $app_id_detail ) {
2045 2146 $app_detail = WPDA_App_Model::get_by_id( $app_id_detail );
@@ -2084,8 +2185,9 @@
2084 2185 'time_format' => get_option( 'time_format' ),
2085 2186 'scroll_offset' => WPDA::get_option( WPDA::OPTION_APPS_SCROLL_OFFSET ),
2086 2187 'upload' => @ini_get( 'upload_max_filesize' ),
2087 2188 'uploadBytes' => $this->uploadToBytes( @ini_get( 'upload_max_filesize' ) ),
2189 + 'locale' => get_locale(),
2088 2190 ];
2089 2191 return $settings;
2090 2192 }
2091 2193
@@ -2189,8 +2291,17 @@
2189 2291 return $this->get_app_container_meta( $app_id, $container );
2190 2292 }
2191 2293 }
2192 2294
2295 + private function escapeUnicodeForExport( $str ) {
2296 + if ( empty( $str ) ) {
2297 + return $str;
2298 + }
2299 + return preg_replace_callback( '/\\\\(u[0-9a-fA-F]{4})/', function ( $matches ) {
2300 + return '\\\\' . $matches[1];
2301 + }, $str );
2302 + }
2303 +
2193 2304 private function do_app_export_app( $app_id, $main_app_id ) {
2194 2305 global $wpdb;
2195 2306 $quotes = function ( $value ) {
2196 2307 return str_replace( array(
@@ -2200,9 +2311,10 @@
2200 2311 "\\t",
2201 2312 "\\\\n",
2202 2313 "\\n",
2203 2314 "\\r\\n",
2204 - "\\r"
2315 + "\\r",
2316 + "\\d"
2205 2317 ), array(
2206 2318 "''",
2207 2319 '\\\\"',
2208 2320 "\\\\\\t",
@@ -2209,9 +2321,10 @@
2209 2321 "\\\\t",
2210 2322 "\\\\\\n",
2211 2323 "\\\\n",
2212 2324 "\\\\r\\\\n",
2213 - "\\\\r"
2325 + "\\\\r",
2326 + "\\\\\\\\\\d"
2214 2327 ), $value );
2215 2328 };
2216 2329 $app = WPDA_App_Model::get_by_id( $app_id );
2217 2330 $app_settings = ( null === $app[0]['app_settings'] ? 'null' : "{$quotes( $app[0]['app_settings'] )}" );
@@ -2258,8 +2371,11 @@
2258 2371 // Replace default WordPress database with conversion string
2259 2372 $cnt_dbs = ( $wpdb->dbname === $container['cnt_dbs'] ? '{wp_schema}' : "{$quotes( $container['cnt_dbs'] )}" );
2260 2373 $cnt_table = str_replace( "\"dbs\":\"{$wpdb->dbname}\"", "\"dbs\":\"{wp_schema}\"", $cnt_table );
2261 2374 $cnt_form = str_replace( "\"dbs\":\"{$wpdb->dbname}\"", "\"dbs\":\"{wp_schema}\"", $cnt_form );
2375 + // Replace Unicode characters
2376 + $cnt_table = $this->escapeUnicodeForExport( $cnt_table );
2377 + $cnt_form = $this->escapeUnicodeForExport( $cnt_form );
2262 2378 // phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed
2263 2379 $containers_sql .= <<<SQL
2264 2380 # Import app container
2265 2381 insert into `{wp_prefix}wpda_app_container`
@@ -2568,8 +2684,9 @@
2568 2684 ) {
2569 2685 // Process $search_custom > URL parameters
2570 2686 global $wpdb;
2571 2687 $replacements = array();
2688 + $nonce = bin2hex( random_bytes( 8 ) );
2572 2689 foreach ( self::METHODS as $method ) {
2573 2690 $offset = 0;
2574 2691 $search = $method . '[';
2575 2692 // Get filter
@@ -2599,9 +2716,9 @@
2599 2716 $arg_value = sanitize_text_field( wp_unslash( $search_custom['post'][$arg_name] ) );
2600 2717 }
2601 2718 }
2602 2719 // Handle POST args
2603 - $placeholder = '###URL_PLACEHOLDER_' . md5( $filter ) . '###';
2720 + $placeholder = '###URL_PLACEHOLDER_' . $nonce . '_' . md5( $filter ) . '###';
2604 2721 $where = str_replace( $filter, $placeholder, $where );
2605 2722 // Handle REQUEST args
2606 2723 if ( $arg_value !== null ) {
2607 2724 $replacements[$placeholder] = $wpdb->prepare( '%s', $arg_value );
@@ -2624,9 +2741,9 @@
2624 2741 if ( count( $filter_field_name_array ) === count( $filter_field_value_array ) ) {
2625 2742 // Add filter to where clause.
2626 2743 for ($i = 0; $i < count( $filter_field_name_array ); $i++) {
2627 2744 $where .= ( '' === $where ? '' : ' and ' );
2628 - $placeholder = '###SHORTCODE_PARAM_' . md5( $filter_field_name_array[$i] ) . '###';
2745 + $placeholder = '###SHORTCODE_PARAM_' . $nonce . '_' . md5( $filter_field_name_array[$i] ) . '###';
2629 2746 $where .= ' `' . $filter_field_name_array[$i] . '` like ' . $placeholder;
2630 2747 $replacements[$placeholder] = $wpdb->prepare( '%s', $filter_field_value_array[$i] );
2631 2748 }
2632 2749 }
@@ -2635,9 +2752,9 @@
2635 2752 if ( is_array( $shortcode_params ) ) {
2636 2753 foreach ( $shortcode_params as $column_name => $column_value ) {
2637 2754 $occurences = substr_count( strtolower( $where ), strtolower( "shortcodeParam['{$column_name}']" ) );
2638 2755 if ( 0 < $occurences ) {
2639 - $placeholder = '###SHORTCODE_PARAM_' . md5( $column_name ) . '###';
2756 + $placeholder = '###SHORTCODE_PARAM_' . $nonce . '_' . md5( $column_name ) . '###';
2640 2757 $where = str_ireplace( "shortcodeParam['{$column_name}']", $placeholder, $where );
2641 2758 $replacements[$placeholder] = $wpdb->prepare( '%s', sanitize_text_field( $column_value ) );
2642 2759 }
2643 2760 }
@@ -2657,16 +2774,15 @@
2657 2774 }
2658 2775 // Substitute all dynamic parameters
2659 2776 if ( is_array( $dynamic_params ) && 0 < count( $dynamic_params ) ) {
2660 2777 foreach ( $dynamic_params as $column_name => $column_value ) {
2661 - $placeholder = '###DYNAMIC_PARAM_' . md5( $column_name ) . '###';
2662 - $where = str_ireplace( "{:{$column_name}}", $placeholder, $where );
2663 - $replacements[$placeholder] = $wpdb->prepare( '%s', $column_value );
2778 + if ( stripos( $where, "{:{$column_name}}" ) !== false ) {
2779 + $placeholder = '###DYNAMIC_PARAM_' . $nonce . '_' . md5( $column_name ) . '###';
2780 + $where = str_ireplace( "{:{$column_name}}", $placeholder, $where );
2781 + $replacements[$placeholder] = $wpdb->prepare( '%s', $column_value );
2782 + }
2664 2783 }
2665 2784 }
2666 - foreach ( $replacements as $placeholder => $value ) {
2667 - $where = str_replace( $placeholder, $value, $where );
2668 - }
2669 - return $where;
2785 + return strtr( $where, $replacements );
2670 2786 }
2671 2787
2672 2788 }