public function ajax() { $apiArgs = isset($_GET["apiArgs"]) ? $_GET["apiArgs"] : array(); if (!$apiArgs) { wp_send_json_error(array("error" => "MISSING_APIARGS")); exit; } if (empty($apiArgs["since_id"]) || !is_numeric($apiArgs["since_id"])) { wp_send_json_error(array("error" => "MISSING_SINCE_ID")); exit; } // $since_id = isset( $_GET["since_id"] ) ? absint($_GET["since_id"]) : null; $logQueryArgs = $apiArgs; $logQuery = new SimpleHistoryLogQuery(); $answer = $logQuery->query($logQueryArgs); // Use our own repsonse array instead of $answer to keep size down $json_data = array(); $numNewRows = isset($answer["total_row_count"]) ? $answer["total_row_count"] : 0; $json_data["num_new_rows"] = $numNewRows; $json_data["num_mysql_queries"] = get_num_queries(); if ($numNewRows) { // We have new rows // Append strings $textRowsFound = sprintf(_n('1 new event', '%d new events', $numNewRows, 'simple-history'), $numNewRows); $json_data["strings"] = array("newRowsFound" => $textRowsFound); } wp_send_json_success($json_data); }
/** * Quick stats above the log * Uses filter "simple_history/history_page/before_gui" to output its contents */ public function output_quick_stats() { global $wpdb; // Get number of events today $logQuery = new SimpleHistoryLogQuery(); $logResults = $logQuery->query(array("posts_per_page" => 1, "date_from" => strtotime("today"))); $total_row_count = (int) $logResults["total_row_count"]; // Get sql query for where to read only loggers current user is allowed to read/view $sql_loggers_in = $this->getLoggersThatUserCanRead(get_current_user_id(), "sql"); // Get number of users today, i.e. events with wp_user as initiator $sql_users_today = sprintf(' SELECT DISTINCT(c.value) AS user_id #h.id, h.logger, h.level, h.initiator, h.date FROM %3$s AS h INNER JOIN %4$s AS c ON c.history_id = h.id AND c.key = "_user_id" WHERE initiator = "wp_user" AND logger IN %1$s AND date > "%2$s" ', $sql_loggers_in, date("Y-m-d H:i", strtotime("today")), $wpdb->prefix . SimpleHistory::DBTABLE, $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS); $cache_key = "quick_stats_users_today_" . md5(serialize($sql_loggers_in)); $cache_group = "simple-history-" . $this->get_cache_incrementor(); $results_users_today = wp_cache_get($cache_key, $cache_group); if (false === $results_users_today) { $results_users_today = $wpdb->get_results($sql_users_today); wp_cache_set($cache_key, $results_users_today, $cache_group); } $count_users_today = sizeof($results_users_today); // Get number of other sources (not wp_user) $sql_other_sources_where = sprintf(' initiator <> "wp_user" AND logger IN %1$s AND date > "%2$s" ', $sql_loggers_in, date("Y-m-d H:i", strtotime("today")), $wpdb->prefix . SimpleHistory::DBTABLE, $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS); $sql_other_sources_where = apply_filters("simple_history/quick_stats_where", $sql_other_sources_where); $sql_other_sources = sprintf(' SELECT DISTINCT(h.initiator) AS initiator FROM %3$s AS h WHERE %5$s ', $sql_loggers_in, date("Y-m-d H:i", strtotime("today")), $wpdb->prefix . SimpleHistory::DBTABLE, $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS, $sql_other_sources_where); // sf_d($sql_other_sources, '$sql_other_sources'); $cache_key = "quick_stats_results_other_sources_today_" . md5(serialize($sql_other_sources)); $results_other_sources_today = wp_cache_get($cache_key, $cache_group); if (false === $results_other_sources_today) { $results_other_sources_today = $wpdb->get_results($sql_other_sources); wp_cache_set($cache_key, $results_other_sources_today, $cache_group); } $count_other_sources = sizeof($results_other_sources_today); //sf_d($logResults, '$logResults'); //sf_d($results_users_today, '$sql_users_today'); //sf_d($results_other_sources_today, '$results_other_sources_today'); ?> <div class="SimpleHistoryQuickStats"> <p> <?php $msg_tmpl = ""; // No results today at all if ($total_row_count == 0) { $msg_tmpl = __("No events today so far.", "simple-history"); } else { /* Type of results x1 event today from 1 user. x1 event today from 1 source. 3 events today from 1 user. x2 events today from 2 users. x2 events today from 1 user and 1 other source. x3 events today from 2 users and 1 other source. x3 events today from 1 user and 2 other sources. x4 events today from 2 users and 2 other sources. */ // A single event existed and was from a user // 1 event today from 1 user. if ($total_row_count == 1 && $count_users_today == 1) { $msg_tmpl .= __('One event today from one user.', "simple-history"); } // A single event existed and was from another source // 1 event today from 1 source. if ($total_row_count == 1 && !$count_users_today) { $msg_tmpl .= __('One event today from one source.', "simple-history"); } // Multiple events from a single user // 3 events today from one user. if ($total_row_count > 1 && $count_users_today == 1 && !$count_other_sources) { $msg_tmpl .= __('%1$d events today from one user.', "simple-history"); } // Multiple events from only users // 2 events today from 2 users. if ($total_row_count > 1 && $count_users_today == $total_row_count) { $msg_tmpl .= __('%1$d events today from %2$d users.', "simple-history"); } // Multiple events from 1 single user and 1 single other source // 2 events today from 1 user and 1 other source. if ($total_row_count && 1 == $count_users_today && 1 == $count_other_sources) { $msg_tmpl .= __('%1$d events today from one user and one other source.', "simple-history"); } // Multiple events from multple users but from only 1 single other source // 3 events today from 2 users and 1 other source. if ($total_row_count > 1 && $count_users_today > 1 && $count_other_sources == 1) { $msg_tmpl .= __('%1$d events today from one user and one other source.', "simple-history"); } // Multiple events from 1 user but from multiple other source // 3 events today from 1 user and 2 other sources. if ($total_row_count > 1 && 1 == $count_users_today && $count_other_sources > 1) { $msg_tmpl .= __('%1$d events today from one user and %3$d other sources.', "simple-history"); } // Multiple events from multiple user and from multiple other sources // 4 events today from 2 users and 2 other sources. if ($total_row_count > 1 && $count_users_today > 1 && $count_other_sources > 1) { $msg_tmpl .= __('%1$s events today from %2$d users and %3$d other sources.', "simple-history"); } } // only show stats if we have something to output if ($msg_tmpl) { printf($msg_tmpl, $logResults["total_row_count"], $count_users_today, $count_other_sources); // Space between texts /* echo " "; // http://playground-root.ep/wp-admin/options-general.php?page=simple_history_settings_menu_slug&selected-tab=stats printf( '<a href="%1$s">View more stats</a>.', add_query_arg("selected-tab", "stats", menu_page_url(SimpleHistory::SETTINGS_MENU_SLUG, 0)) ); */ } ?> </p> </div> <?php }
function test_log_query() { // Add admin user $user_id = $this->factory->user->create(array('role' => 'administrator')); wp_set_current_user($user_id); $args = array("posts_per_page" => 1); $logQuery = new SimpleHistoryLogQuery(); $queryResults = $logQuery->query($args); // The latest row should be the user we create above $this->assertArrayHasKey("total_row_count", $queryResults); $this->assertArrayHasKey("pages_count", $queryResults); $this->assertArrayHasKey("page_current", $queryResults); $this->assertArrayHasKey("page_rows_from", $queryResults); $this->assertArrayHasKey("page_rows_to", $queryResults); $this->assertArrayHasKey("max_id", $queryResults); $this->assertArrayHasKey("min_id", $queryResults); $this->assertArrayHasKey("log_rows_count", $queryResults); $this->assertArrayHasKey("log_rows", $queryResults); $this->assertCount(1, $queryResults["log_rows"]); $this->assertObjectHasAttribute("id", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("logger", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("level", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("date", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("message", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("initiator", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("occasionsID", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("subsequentOccasions", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("rep", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("repeated", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("occasionsIDType", $queryResults["log_rows"][0]); $this->assertObjectHasAttribute("context", $queryResults["log_rows"][0]); }
public function downloadExport() { global $wpdb; $table_name = $wpdb->prefix . SimpleHistory::DBTABLE; $table_name_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS; if (isset($_POST["simple-history-action"]) && $_POST["simple-history-action"] === "export-history") { // Will die if nonce not valid check_admin_referer(__CLASS__ . "-action-export"); $export_format = isset($_POST["format"]) ? $_POST["format"] : "json"; // Disable relative time output in header add_filter("simple_history/header_time_ago_max_time", "__return_zero"); add_filter("simple_history/header_just_now_max_time", "__return_zero"); // Don't use "You" if event is initiated by the same user that does the export add_filter("simple_history/header_initiator_use_you", "__return_false"); $query = new SimpleHistoryLogQuery(); $query_args = array("paged" => 1, "posts_per_page" => 3000); $events = $query->query($query_args); // $events->total_row_count; $pages_count = $events["pages_count"]; $page_current = $events["page_current"]; $fp = fopen('php://output', 'w'); #header("Content-Type: application/octet-stream"); if ("csv" == $export_format) { $filename = "simple-history-export-" . time() . ".csv"; header("Content-Type: text/plain"); header("Content-Disposition: attachment; filename='{$filename}'"); } else { if ("json" == $export_format) { $filename = "simple-history-export-" . time() . ".json"; header("Content-Type: application/json"); header("Content-Disposition: attachment; filename='{$filename}'"); } else { if ("html" == $export_format) { $filename = "simple-history-export-" . time() . ".html"; header("Content-Type: text/html"); #header("Content-Disposition: attachment; filename='{$filename}'"); } } } // Some formats need to output some stuff before the actual loops if ("json" == $export_format) { $json_row = "["; fwrite($fp, $json_row); } else { if ("html" == $export_format) { $html = sprintf(' <!doctype html> <meta charset="utf-8"> <title>Simple History export</title> <ul> '); fwrite($fp, $html); } } // Paginate through all pages and all their rows $row_loop = 0; while ($page_current <= $pages_count + 1) { // if ($page_current > 1) { break; } # To debug/test foreach ($events["log_rows"] as $one_row) { // if ( $row_loop > 10) { break; } # To debug/test set_time_limit(30); if ("csv" == $export_format) { $header_output = strip_tags(html_entity_decode($this->sh->getLogRowHeaderOutput($one_row), ENT_QUOTES, 'UTF-8')); $header_output = trim(preg_replace('/\\s\\s+/', ' ', $header_output)); $message_output = strip_tags(html_entity_decode($this->sh->getLogRowPlainTextOutput($one_row), ENT_QUOTES, 'UTF-8')); fputcsv($fp, array($one_row->date, $one_row->logger, $one_row->level, $one_row->initiator, $one_row->context_message_key, $header_output, $message_output, $one_row->subsequentOccasions)); } else { if ("json" == $export_format) { // If not first loop then add a comma between all json objects if ($row_loop == 0) { $comma = "\n"; } else { $comma = ",\n"; } $json_row = $comma . $this->sh->json_encode($one_row); fwrite($fp, $json_row); } else { if ("html" == $export_format) { $html = sprintf(' <li> <div>%1$s</div> <div>%2$s</div> <div>%3$s</div> </li> ', $this->sh->getLogRowHeaderOutput($one_row), $this->sh->getLogRowPlainTextOutput($one_row), $this->sh->getLogRowDetailsOutput($one_row)); fwrite($fp, $html); } } } $row_loop++; } #echo "<br>memory_get_usage:<br>"; print_r(memory_get_usage()); #echo "<br>memory_get_peak_usage:<br>"; print_r(memory_get_peak_usage()); #echo "<br>fetch next page"; flush(); // Fetch next page // @TODO: must take into consideration that new items can be added while we do the fetch $page_current++; $query_args["paged"] = $page_current; $events = $query->query($query_args); #echo "<br>did fetch next page"; #echo "<br>memory_get_usage:<br>"; print_r(memory_get_usage()); #echo "<br>memory_get_peak_usage:<br>"; print_r(memory_get_peak_usage()); } if ("json" == $export_format) { $json_row = "]"; fwrite($fp, $json_row); } else { if ("html" == $export_format) { $html = sprintf('</ul>'); fwrite($fp, $html); } } fclose($fp); flush(); exit; #echo "<br>done"; } }
/** * Output RSS */ function output_rss() { $rss_secret_option = get_option("simple_history_rss_secret"); $rss_secret_get = isset($_GET["rss_secret"]) ? $_GET["rss_secret"] : ""; if (empty($rss_secret_option) || empty($rss_secret_get)) { die; } $rss_show = true; $rss_show = apply_filters("simple_history/rss_feed_show", $rss_show); if (!$rss_show || !$this->is_rss_enabled()) { wp_die('Nothing here.'); } header("Content-Type: text/xml; charset=utf-8"); echo '<?xml version="1.0" encoding="UTF-8"?>'; $self_link = $this->get_rss_address(); if ($rss_secret_option === $rss_secret_get) { ?> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <channel> <title><![CDATA[<?php printf(__("History for %s", 'simple-history'), get_bloginfo("name")); ?> ]]></title> <description><![CDATA[<?php printf(__("WordPress History for %s", 'simple-history'), get_bloginfo("name")); ?> ]]></description> <link><?php echo get_bloginfo("url"); ?> </link> <atom:link href="<?php echo $self_link; ?> " rel="self" type="application/atom+xml" /> <?php // Override capability check: if you have a valid rss_secret_key you can read it all $action_tag = "simple_history/loggers_user_can_read/can_read_single_logger"; add_action($action_tag, array($this, "on_can_read_single_logger"), 10, 3); // Modify header time output so it does not show relative date or time ago-format // Because we don't know when a user reads the RSS feed, time ago format may be very inaccurate add_action("simple_history/header_just_now_max_time", "__return_zero"); add_action("simple_history/header_time_ago_max_time", "__return_zero"); // Get log rows $args = array("posts_per_page" => 10); $args = apply_filters("simple_history/rss_feed_args", $args); $logQuery = new SimpleHistoryLogQuery(); $queryResults = $logQuery->query($args); // Remove capability override after query is done // remove_action( $action_tag, array($this, "on_can_read_single_logger") ); foreach ($queryResults["log_rows"] as $row) { $header_output = $this->sh->getLogRowHeaderOutput($row); $text_output = $this->sh->getLogRowPlainTextOutput($row); $details_output = $this->sh->getLogRowDetailsOutput($row); // http://cyber.law.harvard.edu/rss/rss.html#ltguidgtSubelementOfLtitemgt //$item_guid = home_url() . "?SimpleHistoryGuid=" . $row->id; $item_guid = esc_url(add_query_arg("SimpleHistoryGuid", $row->id, home_url())); $item_link = esc_url(add_query_arg("SimpleHistoryGuid", $row->id, home_url())); /** * Filter the guid/link URL used in RSS feed. * Link will be esc_url'ed by simple history, so no need to do that in your filter * * @since 2.0.23 * * @param string $item_guid link. * @param array $row */ $item_link = apply_filters("simple_history/rss_item_link", $item_link, $row); $item_link = esc_url($item_link); $item_title = $this->sh->getLogLevelTranslated($row->level) . ": " . wp_kses($text_output, array()); $level_output = sprintf(__('Severity level: %1$s'), $this->sh->getLogLevelTranslated($row->level)); ?> <item> <title><![CDATA[<?php echo $item_title; ?> ]]></title> <description><![CDATA[ <p><?php echo $header_output; ?> </p> <p><?php echo $text_output; ?> </p> <div><?php echo $details_output; ?> </div> <p><?php echo $level_output; ?> </p> <?php $occasions = $row->subsequentOccasions - 1; if ($occasions) { printf(_n('+%1$s occasion', '+%1$s occasions', $occasions, 'simple-history'), $occasions); } ?> ]]></description> <?php // author must be email to validate, but the field is optional, so we skip it /* <author><?php echo $row->initiator ?></author> */ ?> <pubDate><?php echo date("D, d M Y H:i:s", strtotime($row->date)); ?> GMT</pubDate> <guid isPermaLink="false"><![CDATA[<?php echo $item_guid; ?> ]]></guid> <link><![CDATA[<?php echo $item_link; ?> ]]></link> </item> <?php /* [0] => stdClass Object ( [id] => 27324 [logger] => SimplePluginLogger [level] => info [date] => 2014-10-15 06:50:01 [message] => Updated plugin "{plugin_name}" from {plugin_prev_version} to {plugin_version} [type] => [initiator] => wp_user [occasionsID] => 75e8aeab3e43b37f8a458f3744c4995f [subsequentOccasions] => 1 [rep] => 1 [repeated] => 1 [occasionsIDType] => 75e8aeab3e43b37f8a458f3744c4995f [context] => Array ( [plugin_slug] => google-analytics-for-wordpress [plugin_name] => Google Analytics by Yoast [plugin_title] => <a href="https://yoast.com/wordpress/plugins/google-analytics/#utm_source=wordpress&#038;utm_medium=plugin&#038;utm_campaign=wpgaplugin&#038;utm_content=v504">Google Analytics by Yoast</a> [plugin_description] => This plugin makes it simple to add Google Analytics to your WordPress blog, adding lots of features, eg. error page, search result and automatic clickout and download tracking. <cite>By <a href="https://yoast.com/">Team Yoast</a>.</cite> [plugin_author] => <a href="https://yoast.com/">Team Yoast</a> [plugin_version] => 5.0.7 [plugin_url] => https://yoast.com/wordpress/plugins/google-analytics/#utm_source=wordpress&#038;utm_medium=plugin&#038;utm_campaign=wpgaplugin&#038;utm_content=v504 [plugin_update_info_plugin] => google-analytics-for-wordpress/googleanalytics.php [plugin_update_info_package] => https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.5.0.7.zip [plugin_prev_version] => 5.0.6 [_message_key] => plugin_bulk_updated [_user_id] => 1 [_user_login] => admin [_user_email] => par.thernstrom@gmail.com [_server_remote_addr] => ::1 [_server_http_referer] => http://playground-root.ep/wp-admin/update-core.php?action=do-plugin-upgrade ) ) */ } ?> </channel> </rss> <?php } else { // RSS secret was not ok ?> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <channel> <title><?php printf(__("History for %s", 'simple-history'), get_bloginfo("name")); ?> </title> <description><?php printf(__("WordPress History for %s", 'simple-history'), get_bloginfo("name")); ?> </description> <link><?php echo home_url(); ?> </link> <item> <title><?php _e("Wrong RSS secret", 'simple-history'); ?> </title> <description><?php _e("Your RSS secret for Simple History RSS feed is wrong. Please see WordPress settings for current link to the RSS feed.", 'simple-history'); ?> </description> <pubDate><?php echo date("D, d M Y H:i:s", time()); ?> GMT</pubDate> <guid><?php echo home_url() . "?SimpleHistoryGuid=wrong-secret"; ?> </guid> </item> </channel> </rss> <?php } }
}); }); </script> <?php defined('ABSPATH') or exit; echo "<hr>"; echo "<p class='hide-if-no-js'><button class='button js-SimpleHistoryShowsStatsForGeeks'>Show stats for geeks</button></p>"; ?> <div class="SimpleHistory__statsForGeeksInner hide-if-js"> <?php echo "<h4>Rows count</h4>"; $logQuery = new SimpleHistoryLogQuery(); $rows = $logQuery->query(array("posts_per_page" => 1)); // This is the number of rows with occasions taken into consideration $total_accassions_rows_count = $rows["total_row_count"]; // Total number of log rows // Not caring about occasions, this number = all occasions $total_num_rows = $wpdb->get_var("select count(*) FROM {$table_name}"); echo "<ul>"; echo "<li>Total {$total_num_rows} log rows in db.</li>"; echo "<li>Total {$total_accassions_rows_count} rows, when grouped by occasion id.</li>"; echo "</ul>"; echo "<h4>Clear history interval</h4>"; echo "<p>" . $this->sh->get_clear_history_interval() . "</p>"; $sql_table_size = sprintf(' SELECT table_name AS "table_name", round(((data_length + index_length) / 1024 / 1024), 2) "size_in_mb"