GetPaid_Anonymization_Logs::get_total_logs()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
/**
3
 * GetPaid Anonymization Logs Admin
4
 *
5
 * @package GetPaid
6
 * @subpackage Admin
7
 * @since 2.8.22
8
 */
9
10
defined( 'ABSPATH' ) || exit;
11
12
/**
13
 * GetPaid_Anonymization_Logs Class
14
 */
15
class GetPaid_Anonymization_Logs {
16
17
    /**
18
     * Anonymization logs page
19
     */
20
    public function display_logs() {
21
        // Check user capabilities
22
        if ( ! current_user_can( 'manage_options' ) ) {
23
            return;
24
        }
25
26
        // Get current page number
27
        $page = isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1;
28
        $per_page = 20;
29
30
        // Fetch logs
31
        $logs = $this->get_logs( $page, $per_page );
32
        $total_logs = $this->get_total_logs();
33
34
        // Prepare pagination
35
        $pagination = paginate_links(
36
            array(
0 ignored issues
show
Security Variable Injection introduced by
array('base' => add_quer...e), 'current' => $page) can contain request data and is used in variable name context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri in wordpress/wp-includes/functions.php on line 1132
  1. Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri
    in wordpress/wp-includes/functions.php on line 1132
  2. $uri . '?' is assigned to $base
    in wordpress/wp-includes/functions.php on line 1165
  3. $protocol . $base . $ret . $frag is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1191
  4. Data is passed through rtrim(), and rtrim($ret, '?') is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1192
  5. Data is passed through str_replace(), and str_replace('?#', '#', $ret) is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1193
  6. $ret is returned
    in wordpress/wp-includes/functions.php on line 1194
  2. Path: Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri in wordpress/wp-includes/functions.php on line 1138
  1. Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri
    in wordpress/wp-includes/functions.php on line 1138
  2. $uri . '?' is assigned to $base
    in wordpress/wp-includes/functions.php on line 1165
  3. $protocol . $base . $ret . $frag is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1191
  4. Data is passed through rtrim(), and rtrim($ret, '?') is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1192
  5. Data is passed through str_replace(), and str_replace('?#', '#', $ret) is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1193
  6. $ret is returned
    in wordpress/wp-includes/functions.php on line 1194

Used in variable context

  1. paginate_links() is called
    in includes/admin/class-getpaid-anonymization-logs.php on line 36
  2. Enters via parameter $args
    in wordpress/wp-includes/general-template.php on line 4469
  3. wp_parse_args() is called
    in wordpress/wp-includes/general-template.php on line 4506
  4. Enters via parameter $args
    in wordpress/wp-includes/functions.php on line 4821
  5. wp_parse_str() is called
    in wordpress/wp-includes/functions.php on line 4827
  6. Enters via parameter $input_string
    in wordpress/wp-includes/formatting.php on line 5148
  7. parse_str() is called
    in wordpress/wp-includes/formatting.php on line 5149

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
37
				'base'      => add_query_arg( 'paged', '%#%' ),
38
				'format'    => '',
39
				'prev_text' => __( '&laquo;', 'invoicing' ),
40
				'next_text' => __( '&raquo;', 'invoicing' ),
41
				'total'     => ceil( $total_logs / $per_page ),
42
				'current'   => $page,
43
            )
44
        );
45
46
        ?>
47
        <div class="wrap getpaid-anonymization-logs">
48
            <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
49
            <div class="tablenav top">
50
                <div class="alignleft actions">
51
                    <form method="get">
52
                        <input type="hidden" name="page" value="wpinv-anonymization-logs">
53
                        <label for="filter-by-date" class="screen-reader-text"><?php _e( 'Filter by date', 'invoicing' ); ?></label>
54
                        <select name="m" id="filter-by-date">
55
                            <option value="0"><?php _e( 'All dates', 'invoicing' ); ?></option>
56
                            <?php
57
                            $months = $this->get_log_months();
58
                            foreach ( $months as $month ) {
59
                                $selected = ( isset( $_GET['m'] ) && $_GET['m'] == $month->month ) ? ' selected="selected"' : '';
60
                                echo '<option value="' . esc_attr( $month->month ) . '"' . $selected . '>' . esc_html( $month->month_name . ' ' . $month->year ) . '</option>';
61
                            }
62
                            ?>
63
                        </select>
64
                        <?php submit_button( __( 'Filter', 'invoicing' ), '', 'filter_action', false ); ?>
65
                    </form>
66
                </div>
67
            </div>
68
            <table class="wp-list-table widefat fixed striped">
69
                <thead>
70
                    <tr>
71
                        <th><?php _e( 'Log ID', 'invoicing' ); ?></th>
72
                        <th><?php _e( 'User', 'invoicing' ); ?></th>
73
                        <th><?php _e( 'Action', 'invoicing' ); ?></th>
74
                        <th><?php _e( 'Date', 'invoicing' ); ?></th>
75
                        <th><?php _e( 'Details', 'invoicing' ); ?></th>
76
                    </tr>
77
                </thead>
78
                <tbody>
79
                    <?php if ( empty( $logs ) ) : ?>
80
                        <tr>
81
                            <td colspan="5"><?php _e( 'No anonymization logs found.', 'invoicing' ); ?></td>
82
                        </tr>
83
                    <?php else : ?>
84
                        <?php
85
                        foreach ( $logs as $log ) :
86
                            $additional_info = json_decode( $log->additional_info, true );
87
                        ?>
88
                            <tr>
89
                                <td><?php echo esc_html( $log->log_id ); ?></td>
90
                                <td>
91
                                    <?php
92
                                    $user_edit_link = get_edit_user_link( $log->user_id );
93
                                    if ( $user_edit_link ) {
94
                                        echo '<a href="' . esc_url( $user_edit_link ) . '">' . esc_html( $log->user_id ) . '</a>';
95
                                    } else {
96
                                        echo esc_html( $log->user_id );
97
                                    }
98
                                    ?>
99
                                </td>
100
                                <td><?php echo esc_html( ucfirst( $log->action ) ); ?></td>
101
                                <td><?php echo esc_html( get_date_from_gmt( $log->timestamp, 'F j, Y g:i a' ) ); ?></td>
102
                                <td>
103
                                    <button class="button-link toggle-details" type="button" aria-expanded="false">
104
                                        <span class="screen-reader-text"><?php _e( 'Show more details', 'invoicing' ); ?></span>
105
                                        <span class="dashicons dashicons-arrow-down-alt2"></span>
106
                                    </button>
107
                                </td>
108
                            </tr>
109
                            <tr class="log-details" style="display:none;">
110
                                <td colspan="5">
111
                                    <div class="log-details-content">
112
                                        <table class="widefat fixed">
113
                                            <tbody>
114
                                                <tr>
115
                                                    <th><?php _e( 'Data Type', 'invoicing' ); ?></th>
116
                                                    <td><?php echo esc_html( $log->data_type ); ?></td>
117
                                                </tr>
118
                                                <?php if ( is_array( $additional_info ) ) : ?>
119
                                                    <tr>
120
                                                        <th><?php _e( 'Additional Information', 'invoicing' ); ?></th>
121
                                                        <td>
122
                                                            <table class="widefat fixed">
123
                                                                <tbody>
124
                                                                    <?php foreach ( $additional_info as $key => $value ) : ?>
125
                                                                        <tr>
126
                                                                            <th><?php echo esc_html( $key ); ?></th>
127
                                                                            <td><?php echo esc_html( $value ); ?></td>
128
                                                                        </tr>
129
                                                                    <?php endforeach; ?>
130
                                                                </tbody>
131
                                                            </table>
132
                                                        </td>
133
                                                    </tr>
134
                                                <?php endif; ?>
135
                                            </tbody>
136
                                        </table>
137
                                    </div>
138
                                </td>
139
                            </tr>
140
                        <?php endforeach; ?>
141
                    <?php endif; ?>
142
                </tbody>
143
            </table>
144
            <?php if ( $pagination ) : ?>
145
                <div class="tablenav bottom">
146
                    <div class="tablenav-pages">
147
                        <?php echo $pagination; ?>
0 ignored issues
show
Bug introduced by
Are you sure $pagination of type string|string[] can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

147
                        <?php echo /** @scrutinizer ignore-type */ $pagination; ?>
Loading history...
Security Cross-Site Scripting introduced by
$pagination can contain request data and is used in output context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri in wordpress/wp-includes/functions.php on line 1132
  1. Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri
    in wordpress/wp-includes/functions.php on line 1132
  2. $uri . '?' is assigned to $base
    in wordpress/wp-includes/functions.php on line 1165
  3. $protocol . $base . $ret . $frag is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1191
  4. Data is passed through rtrim(), and rtrim($ret, '?') is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1192
  5. Data is passed through str_replace(), and str_replace('?#', '#', $ret) is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1193
  6. $ret is returned
    in wordpress/wp-includes/functions.php on line 1194
  7. Data is passed through paginate_links(), and paginate_links(array('base' => add_query_arg('paged', '%#%'), 'format' => '', 'prev_text' => __('&laquo;', 'invoicing'), 'next_text' => __('&raquo;', 'invoicing'), 'total' => ceil($total_logs / $per_page), 'current' => $page)) is assigned to $pagination
    in includes/admin/class-getpaid-anonymization-logs.php on line 35
  2. Path: Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri in wordpress/wp-includes/functions.php on line 1138
  1. Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri
    in wordpress/wp-includes/functions.php on line 1138
  2. $uri . '?' is assigned to $base
    in wordpress/wp-includes/functions.php on line 1165
  3. $protocol . $base . $ret . $frag is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1191
  4. Data is passed through rtrim(), and rtrim($ret, '?') is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1192
  5. Data is passed through str_replace(), and str_replace('?#', '#', $ret) is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1193
  6. $ret is returned
    in wordpress/wp-includes/functions.php on line 1194
  7. Data is passed through paginate_links(), and paginate_links(array('base' => add_query_arg('paged', '%#%'), 'format' => '', 'prev_text' => __('&laquo;', 'invoicing'), 'next_text' => __('&raquo;', 'invoicing'), 'total' => ceil($total_logs / $per_page), 'current' => $page)) is assigned to $pagination
    in includes/admin/class-getpaid-anonymization-logs.php on line 35

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
148
                    </div>
149
                </div>
150
            <?php endif; ?>
151
        </div>
152
        <?php
153
    }
154
155
    /**
156
     * Get logs from the database
157
     *
158
     * @param int $page Current page number
159
     * @param int $per_page Number of logs per page
160
     * @return array
161
     */
162
    private function get_logs( $page, $per_page ) {
163
        global $wpdb;
164
        $table_name = $wpdb->prefix . 'getpaid_anonymization_logs';
165
        $offset = ( $page - 1 ) * $per_page;
166
167
        $query = $wpdb->prepare(
168
            "SELECT * FROM $table_name ORDER BY timestamp DESC LIMIT %d OFFSET %d",
169
            $per_page,
170
            $offset
171
        );
172
173
        return $wpdb->get_results( $query );
174
    }
175
176
    /**
177
     * Get total number of logs
178
     *
179
     * @return int
180
     */
181
    private function get_total_logs() {
182
        global $wpdb;
183
        $table_name = $wpdb->prefix . 'getpaid_anonymization_logs';
184
        return $wpdb->get_var( "SELECT COUNT(*) FROM $table_name" );
185
    }
186
187
    /**
188
     * Get log months for filtering
189
     *
190
     * @return array
191
     */
192
    private function get_log_months() {
193
        global $wpdb;
194
        $table_name = $wpdb->prefix . 'getpaid_anonymization_logs';
195
196
        $months = $wpdb->get_results(
197
            "SELECT DISTINCT YEAR(timestamp) AS year, MONTH(timestamp) AS month, 
198
            DATE_FORMAT(timestamp, '%M') AS month_name, 
199
            DATE_FORMAT(timestamp, '%Y%m') AS month
200
            FROM $table_name
201
            ORDER BY year DESC, month DESC"
202
        );
203
204
        return $months;
205
    }
206
}