Version Description
Download this release
Release Info
Developer | maxchirkov |
Plugin | Simple Login Log |
Version | 0.5 |
Comparing to | |
See all releases |
Code changes from version 0.3 to 0.5
- languages/simple-login-log.pot +151 -0
- readme.txt +48 -7
- simple-login-log.php +401 -104
languages/simple-login-log.pot
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (C) 2010 Simple Login Log
|
2 |
+
# This file is distributed under the same license as the Simple Login Log package.
|
3 |
+
msgid ""
|
4 |
+
msgstr ""
|
5 |
+
"Project-Id-Version: Simple Login Log 0.4\n"
|
6 |
+
"Report-Msgid-Bugs-To: http://wordpress.org/tag/simple-login-log\n"
|
7 |
+
"POT-Creation-Date: 2011-12-02 17:27:38+00:00\n"
|
8 |
+
"MIME-Version: 1.0\n"
|
9 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
+
"Content-Transfer-Encoding: 8bit\n"
|
11 |
+
"PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
|
12 |
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
+
|
15 |
+
#: simple-login-log.php:63 simple-login-log.php:681
|
16 |
+
msgid "Successful"
|
17 |
+
msgstr ""
|
18 |
+
|
19 |
+
#: simple-login-log.php:64 simple-login-log.php:682
|
20 |
+
msgid "Failed"
|
21 |
+
msgstr ""
|
22 |
+
|
23 |
+
#: simple-login-log.php:65
|
24 |
+
msgid "Login"
|
25 |
+
msgstr ""
|
26 |
+
|
27 |
+
#: simple-login-log.php:66
|
28 |
+
msgid "User Agent"
|
29 |
+
msgstr ""
|
30 |
+
|
31 |
+
#: simple-login-log.php:67
|
32 |
+
msgid "Login Redirect"
|
33 |
+
msgstr ""
|
34 |
+
|
35 |
+
#: simple-login-log.php:68
|
36 |
+
msgid "#"
|
37 |
+
msgstr ""
|
38 |
+
|
39 |
+
#: simple-login-log.php:69
|
40 |
+
msgid "User ID"
|
41 |
+
msgstr ""
|
42 |
+
|
43 |
+
#: simple-login-log.php:70
|
44 |
+
msgid "Username"
|
45 |
+
msgstr ""
|
46 |
+
|
47 |
+
#: simple-login-log.php:71
|
48 |
+
msgid "Name"
|
49 |
+
msgstr ""
|
50 |
+
|
51 |
+
#: simple-login-log.php:72
|
52 |
+
msgid "Time"
|
53 |
+
msgstr ""
|
54 |
+
|
55 |
+
#: simple-login-log.php:73
|
56 |
+
msgid "IP Address"
|
57 |
+
msgstr ""
|
58 |
+
|
59 |
+
#: simple-login-log.php:74
|
60 |
+
msgid "Login Result"
|
61 |
+
msgstr ""
|
62 |
+
|
63 |
+
#: simple-login-log.php:75
|
64 |
+
msgid "Data"
|
65 |
+
msgstr ""
|
66 |
+
|
67 |
+
#: simple-login-log.php:112
|
68 |
+
msgid "Records"
|
69 |
+
msgstr ""
|
70 |
+
|
71 |
+
#. #-#-#-#-# plugin.pot (Simple Login Log 0.4) #-#-#-#-#
|
72 |
+
#. Plugin Name of the plugin/theme
|
73 |
+
#: simple-login-log.php:259 simple-login-log.php:268
|
74 |
+
msgid "Simple Login Log"
|
75 |
+
msgstr ""
|
76 |
+
|
77 |
+
#: simple-login-log.php:260
|
78 |
+
msgid "Truncate Log Entries"
|
79 |
+
msgstr ""
|
80 |
+
|
81 |
+
#: simple-login-log.php:261
|
82 |
+
msgid "Log Failed Attempts"
|
83 |
+
msgstr ""
|
84 |
+
|
85 |
+
#: simple-login-log.php:268 simple-login-log.php:386
|
86 |
+
msgid "Login Log"
|
87 |
+
msgstr ""
|
88 |
+
|
89 |
+
#: simple-login-log.php:281
|
90 |
+
msgid "Leave empty or enter 0 if you don't want the log to be truncated."
|
91 |
+
msgstr ""
|
92 |
+
|
93 |
+
#: simple-login-log.php:286
|
94 |
+
msgid ""
|
95 |
+
"Logs failed attempts where user name and password are entered. Will not log "
|
96 |
+
"if at least one of the mentioned fields is empty."
|
97 |
+
msgstr ""
|
98 |
+
|
99 |
+
#: simple-login-log.php:396
|
100 |
+
msgid "Username:"
|
101 |
+
msgstr ""
|
102 |
+
|
103 |
+
#: simple-login-log.php:396
|
104 |
+
msgid "Filter User"
|
105 |
+
msgstr ""
|
106 |
+
|
107 |
+
#: simple-login-log.php:421
|
108 |
+
msgid "Export Log to CSV"
|
109 |
+
msgstr ""
|
110 |
+
|
111 |
+
#: simple-login-log.php:430
|
112 |
+
msgid "Export Current Results to CSV"
|
113 |
+
msgstr ""
|
114 |
+
|
115 |
+
#: simple-login-log.php:460
|
116 |
+
msgid "View All"
|
117 |
+
msgstr ""
|
118 |
+
|
119 |
+
#: simple-login-log.php:461
|
120 |
+
msgid "Filter"
|
121 |
+
msgstr ""
|
122 |
+
|
123 |
+
#: simple-login-log.php:555
|
124 |
+
msgid "Filter log by this name"
|
125 |
+
msgstr ""
|
126 |
+
|
127 |
+
#: simple-login-log.php:680
|
128 |
+
msgid "Login Results"
|
129 |
+
msgstr ""
|
130 |
+
|
131 |
+
#: simple-login-log.php:680
|
132 |
+
msgid "All"
|
133 |
+
msgstr ""
|
134 |
+
|
135 |
+
#. Plugin URI of the plugin/theme
|
136 |
+
msgid "http://simplerealtytheme.com"
|
137 |
+
msgstr ""
|
138 |
+
|
139 |
+
#. Description of the plugin/theme
|
140 |
+
msgid ""
|
141 |
+
"This plugin keeps a log of WordPress user logins. Offers user filtering and "
|
142 |
+
"export features."
|
143 |
+
msgstr ""
|
144 |
+
|
145 |
+
#. Author of the plugin/theme
|
146 |
+
msgid "Max Chirkov"
|
147 |
+
msgstr ""
|
148 |
+
|
149 |
+
#. Author URI of the plugin/theme
|
150 |
+
msgid "http://SimpleRealtyTheme.com"
|
151 |
+
msgstr ""
|
readme.txt
CHANGED
@@ -4,31 +4,35 @@ Donate link: http://www.ibsteam.net/donate
|
|
4 |
Tags: login, log, users
|
5 |
Requires at least: 3.0
|
6 |
Tested up to: 3.3
|
7 |
-
Stable tag: 0.
|
8 |
|
9 |
This plugin keeps a log of WordPress user logins. Offers user and date filtering, and export features.
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
-
Simple log of user logins. Tracks username, time of login, IP address and browser user agent.
|
14 |
|
15 |
-
|
16 |
-
* Author URI: [http://simplerealtytheme.com/](http://simplerealtytheme.com/ "Real Estate Themes & Plugins for WordPress")
|
17 |
-
* Copyright: Released under GNU GENERAL PUBLIC LICENSE
|
18 |
|
19 |
**Features include:**
|
20 |
|
21 |
-
1. ability to filter by username, month and year;
|
22 |
2. export into CSV file;
|
23 |
3. log auto-truncation;
|
24 |
4. option to record failed login attempts.
|
25 |
|
|
|
|
|
|
|
|
|
26 |
== Installation ==
|
27 |
|
28 |
1. Install and activate like any other basic plugin.
|
29 |
2. If you wish to set log trancation or opt-in to record failed login attemtps, go to Settings => General. Scroll down to Simple Login Log.
|
30 |
3. To view login log, go to Users => Login Log. You can export the log to CSV file form the same page.
|
31 |
|
|
|
|
|
32 |
== Screenshots ==
|
33 |
|
34 |
1. Simple Login Log Settings.
|
@@ -36,7 +40,44 @@ Simple log of user logins. Tracks username, time of login, IP address and browse
|
|
36 |
|
37 |
== Changelog ==
|
38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
**Version 0.3**
|
40 |
|
41 |
- Added support for third-party login plugins.
|
42 |
-
- Added option to log Failed Login Attempts.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
Tags: login, log, users
|
5 |
Requires at least: 3.0
|
6 |
Tested up to: 3.3
|
7 |
+
Stable tag: 0.5
|
8 |
|
9 |
This plugin keeps a log of WordPress user logins. Offers user and date filtering, and export features.
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
+
Simple log of user logins. Tracks username, time of login, IP address and browser user agent.
|
14 |
|
15 |
+
[Demo Video](http://screenr.com/kfEs "Demo Video")
|
|
|
|
|
16 |
|
17 |
**Features include:**
|
18 |
|
19 |
+
1. ability to filter by username, successful/failed logins, month and year;
|
20 |
2. export into CSV file;
|
21 |
3. log auto-truncation;
|
22 |
4. option to record failed login attempts.
|
23 |
|
24 |
+
* Author: Max Chirkov
|
25 |
+
* Author URI: [http://simplerealtytheme.com/](http://simplerealtytheme.com/ "Real Estate Themes & Plugins for WordPress")
|
26 |
+
* Copyright: Released under GNU GENERAL PUBLIC LICENSE
|
27 |
+
|
28 |
== Installation ==
|
29 |
|
30 |
1. Install and activate like any other basic plugin.
|
31 |
2. If you wish to set log trancation or opt-in to record failed login attemtps, go to Settings => General. Scroll down to Simple Login Log.
|
32 |
3. To view login log, go to Users => Login Log. You can export the log to CSV file form the same page.
|
33 |
|
34 |
+
Screen Options are available at the top of the Login Log page. Click on the *Secreen Options* tab to expand the options section. You'll be able to change the number of results pre page as well as hide/display table columns.
|
35 |
+
|
36 |
== Screenshots ==
|
37 |
|
38 |
1. Simple Login Log Settings.
|
40 |
|
41 |
== Changelog ==
|
42 |
|
43 |
+
**Version 0.5**
|
44 |
+
|
45 |
+
- Bug fix: in_array() warning for hidden columns not returning an array.
|
46 |
+
|
47 |
+
**Version 0.4**
|
48 |
+
|
49 |
+
- Added option to export filtered log results.
|
50 |
+
- Added Views filters All/Successful/Failed logins.
|
51 |
+
- Added Screen Options: number of items per page, output visibility options for table columns.
|
52 |
+
- Added *sll-output-data* filter, which allows to alter data output in each column of the table.
|
53 |
+
- Added support for localization.
|
54 |
+
|
55 |
**Version 0.3**
|
56 |
|
57 |
- Added support for third-party login plugins.
|
58 |
+
- Added option to log Failed Login Attempts.
|
59 |
+
|
60 |
+
== Other Notes ==
|
61 |
+
|
62 |
+
= Filters =
|
63 |
+
|
64 |
+
** Log Output Within the Table **
|
65 |
+
|
66 |
+
*sll-output-data* - filters table row array where array keys are column names and values is the output
|
67 |
+
For example, we can use this filter to link IP addresses to a geo-location service:
|
68 |
+
`
|
69 |
+
<?php
|
70 |
+
add_filter( 'sll-output-data', 'link_location_by_ip' );
|
71 |
+
function link_location_by_ip($item){
|
72 |
+
|
73 |
+
//$item is a single row for columns with their values
|
74 |
+
|
75 |
+
$item['ip'] = sprintf('<a target="_blank" href="http://infosniper.net/index.php?ip_address=%1$s&map_source=3&two_maps=1&overview_map=1&lang=1&map_type=1&zoom_level=11">%1$s</a>', $item['ip']);
|
76 |
+
return $item;
|
77 |
+
}
|
78 |
+
?>
|
79 |
+
`
|
80 |
+
|
81 |
+
= Translation =
|
82 |
+
|
83 |
+
Currently there are no trunslations available. If you would like to contribute, the POT file is available in the *languages* folder. Translation file name convention is *sll-{locale}.mo*, where {locale} is the locale of your language. Fore example, Russian file name would be *sll-ru_RU.po*.
|
simple-login-log.php
CHANGED
@@ -4,21 +4,22 @@
|
|
4 |
Plugin URI: http://simplerealtytheme.com
|
5 |
Description: This plugin keeps a log of WordPress user logins. Offers user filtering and export features.
|
6 |
Author: Max Chirkov
|
7 |
-
Version: 0.
|
8 |
Author URI: http://SimpleRealtyTheme.com
|
9 |
*/
|
10 |
|
11 |
-
|
12 |
//TODO: add cleanup method on uninstall
|
13 |
|
14 |
if( !class_exists( 'SimpleLoginLog' ) )
|
15 |
{
|
16 |
class SimpleLoginLog {
|
17 |
-
private $
|
|
|
18 |
private $log_duration = null; //days
|
19 |
private $opt_name = 'simple_login_log';
|
20 |
private $opt = false;
|
21 |
-
private $login_success = 1;
|
|
|
22 |
|
23 |
function __construct()
|
24 |
{
|
@@ -26,14 +27,24 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
26 |
$this->table = $wpdb->prefix . $this->table;
|
27 |
$this->opt = get_option($this->opt_name);
|
28 |
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
30 |
{
|
31 |
-
$
|
32 |
-
|
|
|
33 |
|
34 |
|
35 |
add_action( 'admin_menu', array(&$this, 'sll_admin_menu') );
|
36 |
add_action('admin_init', array(&$this, 'settings_api_init') );
|
|
|
|
|
|
|
|
|
37 |
|
38 |
//Init login actions
|
39 |
add_action( 'init', array(&$this, 'init_login_actions') );
|
@@ -43,6 +54,69 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
43 |
|
44 |
//Initialize scheduled events
|
45 |
add_action( 'wp', array(&$this, 'init_scheduled_events') );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
|
48 |
function init_login_actions(){
|
@@ -91,33 +165,102 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
91 |
}
|
92 |
}
|
93 |
|
|
|
|
|
|
|
|
|
94 |
function install()
|
95 |
{
|
96 |
global $wpdb;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
|
98 |
-
$sql = "CREATE TABLE " . $this->table . "
|
99 |
-
(
|
100 |
-
id INT( 11 ) NOT NULL AUTO_INCREMENT ,
|
101 |
-
uid INT( 11 ) NOT NULL ,
|
102 |
-
user_login VARCHAR( 60 ) NOT NULL ,
|
103 |
-
time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL ,
|
104 |
-
ip VARCHAR( 100 ) NOT NULL ,
|
105 |
-
data LONGTEXT NOT NULL ,
|
106 |
-
PRIMARY KEY ( id ) ,
|
107 |
-
INDEX ( uid, ip )
|
108 |
-
);";
|
109 |
-
|
110 |
-
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
111 |
-
dbDelta($sql);
|
112 |
}
|
|
|
113 |
|
114 |
//Initializing Settings
|
115 |
function settings_api_init()
|
116 |
{
|
117 |
-
add_settings_section('simple_login_log', 'Simple Login Log', array(&$this, 'sll_settings'), 'general');
|
118 |
-
add_settings_field('field_log_duration', 'Truncate Log Entries', array(&$this, 'field_log_duration'), 'general', 'simple_login_log');
|
119 |
-
add_settings_field('field_log_failed_attempts', 'Log Failed Attempts', array(&$this, 'field_log_failed_attempts'), 'general', 'simple_login_log');
|
120 |
-
register_setting( 'general', 'simple_login_log' );
|
|
|
121 |
}
|
122 |
|
123 |
function sll_admin_menu()
|
@@ -135,17 +278,18 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
135 |
$duration = (null !== $this->opt['log_duration']) ? $this->opt['log_duration'] : $this->log_duration;
|
136 |
$output = '<input type="text" value="' . $duration . '" name="simple_login_log[log_duration]" size="10" class="code" /> days and older.';
|
137 |
echo $output;
|
138 |
-
echo "<p>Leave empty or enter 0 if you don't want the log to be truncated
|
139 |
}
|
140 |
|
141 |
function field_log_failed_attempts(){
|
142 |
$failed_attempts = ( isset($this->opt['failed_attempts']) ) ? $this->opt['failed_attempts'] : false;
|
143 |
-
echo '<input type="checkbox" name="simple_login_log[failed_attempts]" value="1" ' . checked( $failed_attempts, 1, false ) . ' /> Logs failed attempts where user name and password are entered. Will not log if at least one of the mentioned fields is empty.';
|
144 |
}
|
145 |
|
146 |
function admin_header()
|
147 |
{
|
148 |
-
|
|
|
149 |
return;
|
150 |
|
151 |
echo '<style type="text/css">';
|
@@ -155,8 +299,9 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
155 |
echo '.wp-list-table .column-name { width: 15%; }';
|
156 |
echo '.wp-list-table .column-time { width: 15%; }';
|
157 |
echo '.wp-list-table .column-ip { width: 10%; }';
|
|
|
158 |
echo '.wp-list-table .login-failed { background: #ffd5d1; }';
|
159 |
-
echo '</style>';
|
160 |
}
|
161 |
|
162 |
//Catch messages on successful login
|
@@ -165,14 +310,10 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
165 |
$userdata = get_user_by('login', $user_login);
|
166 |
|
167 |
$uid = ($userdata->ID) ? $userdata->ID : 0;
|
168 |
-
|
169 |
-
//Stop if login form wasn't submitted
|
170 |
-
//if( !$_REQUEST['wp-submit'] )
|
171 |
-
// return;
|
172 |
|
173 |
-
$data['Login'] = ( 1 == $this->login_success ) ? 'Successful' : 'Failed';
|
174 |
-
if ( isset( $_REQUEST['redirect_to'] ) ) { $data['Login Redirect'] = $_REQUEST['redirect_to']; }
|
175 |
-
$data['User Agent'] = $_SERVER['HTTP_USER_AGENT'];
|
176 |
|
177 |
$serialized_data = serialize($data);
|
178 |
|
@@ -181,10 +322,11 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
181 |
'user_login' => $user_login,
|
182 |
'time' => current_time('mysql'),
|
183 |
'ip' => $_SERVER['REMOTE_ADDR'],
|
|
|
184 |
'data' => $serialized_data,
|
185 |
);
|
186 |
|
187 |
-
$format = array('%d', '%s', '%s', '%s', '%s');
|
188 |
|
189 |
$this->save_data($values, $format);
|
190 |
}
|
@@ -195,59 +337,108 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
195 |
$wpdb->insert( $this->table, $values, $format );
|
196 |
}
|
197 |
|
198 |
-
function
|
199 |
-
|
200 |
-
global $wpdb, $ssl_list_table;
|
201 |
-
|
202 |
-
$log_table = new SLL_List_Table;
|
203 |
-
|
204 |
-
$limit = 20;
|
205 |
-
$offset = ( isset($_REQUEST['page']) ) ? 'OFFSET ' . $limit * $_REQUEST['page'] : 0;
|
206 |
-
$where = '';
|
207 |
-
|
208 |
if( isset($_GET['filter']) && '' != $_GET['filter'] )
|
209 |
{
|
210 |
-
$where = "
|
|
|
|
|
|
|
|
|
211 |
}
|
212 |
if( isset($_GET['datefilter']) && '' != $_GET['datefilter'] )
|
213 |
{
|
214 |
$year = substr($_GET['datefilter'], 0, 4);
|
215 |
$month = substr($_GET['datefilter'], -2);
|
216 |
-
$where = "
|
217 |
}
|
218 |
|
219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
$data = $wpdb->get_results($sql, 'ARRAY_A');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
|
222 |
-
$log_table->items = $
|
223 |
-
$log_table->prepare_items();
|
224 |
|
225 |
echo '<div class="wrap srp">';
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
echo '</div>';
|
231 |
-
|
232 |
-
|
|
|
|
|
233 |
echo '<input type="hidden" name="page" value="login_log" />';
|
234 |
-
echo '<
|
235 |
-
|
236 |
-
echo '</form>';
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
|
|
|
|
|
|
|
|
|
|
245 |
}
|
246 |
|
247 |
private function date_filter()
|
248 |
{
|
249 |
global $wpdb;
|
250 |
-
$sql = "SELECT DISTINCT YEAR(time) as year, MONTH(time)as month FROM {$this->table}";
|
251 |
$results = $wpdb->get_results($sql);
|
252 |
|
253 |
if(!$results)
|
@@ -266,24 +457,36 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
266 |
|
267 |
$output = '<form method="get">';
|
268 |
$output .= '<input type="hidden" name="page" value="login_log" />';
|
269 |
-
$output .= '<select name="datefilter"><option value="">View All</option>' . $option . '</select>';
|
270 |
-
$output .= '<input class="button" type="submit" value="Filter" />';
|
271 |
$output .= '</form>';
|
272 |
return $output;
|
273 |
}
|
274 |
|
275 |
-
function export_to_CSV(){
|
276 |
global $wpdb;
|
277 |
|
278 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
$data = $wpdb->get_results($sql, 'ARRAY_A');
|
280 |
|
281 |
if(!$data)
|
282 |
return;
|
283 |
|
|
|
|
|
|
|
284 |
// send response headers to the browser
|
285 |
header( 'Content-Type: text/csv' );
|
286 |
-
header( 'Content-Disposition: attachment;filename=
|
287 |
$fp = fopen('php://output', 'w');
|
288 |
|
289 |
$i = 0;
|
@@ -301,7 +504,7 @@ if( !class_exists( 'SimpleLoginLog' ) )
|
|
301 |
}
|
302 |
|
303 |
fclose($fp);
|
304 |
-
die();
|
305 |
}
|
306 |
|
307 |
}
|
@@ -322,7 +525,7 @@ class SLL_List_Table extends WP_List_Table
|
|
322 |
{
|
323 |
function __construct()
|
324 |
{
|
325 |
-
global $
|
326 |
|
327 |
//Set parent defaults
|
328 |
parent::__construct( array(
|
@@ -330,24 +533,34 @@ class SLL_List_Table extends WP_List_Table
|
|
330 |
'plural' => 'users', //plural name of the listed records
|
331 |
'ajax' => false //does this table support ajax?
|
332 |
) );
|
333 |
-
|
334 |
-
|
|
|
|
|
335 |
|
336 |
function column_default($item, $column_name)
|
337 |
{
|
|
|
338 |
switch($column_name){
|
339 |
case 'id':
|
340 |
case 'uid':
|
341 |
-
case 'time':
|
342 |
case 'ip':
|
343 |
-
return $item[$column_name];
|
344 |
case 'user_login':
|
345 |
-
|
|
|
|
|
|
|
|
|
346 |
case 'name';
|
347 |
$user_info = get_userdata($item['uid']);
|
348 |
return ( is_object($user_info) ) ? $user_info->first_name . " " . $user_info->last_name : false;
|
|
|
|
|
|
|
349 |
case 'data':
|
350 |
-
|
351 |
if(is_array($data))
|
352 |
{
|
353 |
$output = '';
|
@@ -355,28 +568,33 @@ class SLL_List_Table extends WP_List_Table
|
|
355 |
{
|
356 |
$output .= $k .': '. $v .'<br />';
|
357 |
}
|
358 |
-
|
|
|
|
|
|
|
359 |
return '<div class="login-failed">' . $output . '</div>';
|
360 |
}
|
361 |
return $output;
|
362 |
}
|
363 |
break;
|
364 |
default:
|
365 |
-
|
366 |
}
|
367 |
}
|
368 |
|
369 |
function get_columns()
|
370 |
-
{
|
|
|
371 |
$columns = array(
|
372 |
-
'id' => '
|
373 |
-
'uid' => '
|
374 |
-
'user_login' => '
|
375 |
-
'name' => '
|
376 |
-
'time' => '
|
377 |
-
'ip' => '
|
378 |
-
'
|
379 |
-
|
|
|
380 |
return $columns;
|
381 |
}
|
382 |
|
@@ -384,20 +602,98 @@ class SLL_List_Table extends WP_List_Table
|
|
384 |
{
|
385 |
$sortable_columns = array(
|
386 |
//'id' => array('id',true), //doesn't sort correctly
|
387 |
-
'uid'
|
388 |
-
'
|
389 |
-
'
|
|
|
390 |
);
|
391 |
return $sortable_columns;
|
392 |
}
|
393 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
394 |
function prepare_items()
|
395 |
{
|
396 |
-
|
|
|
397 |
/**
|
398 |
* First, lets decide how many records per page to show
|
399 |
-
*/
|
400 |
-
$
|
|
|
401 |
|
402 |
|
403 |
/**
|
@@ -408,7 +704,8 @@ class SLL_List_Table extends WP_List_Table
|
|
408 |
* used to build the value for our _column_headers property.
|
409 |
*/
|
410 |
$columns = $this->get_columns();
|
411 |
-
$
|
|
|
412 |
$sortable = $this->get_sortable_columns();
|
413 |
|
414 |
|
@@ -418,8 +715,7 @@ class SLL_List_Table extends WP_List_Table
|
|
418 |
* 3 other arrays. One for all columns, one for hidden columns, and one
|
419 |
* for sortable columns.
|
420 |
*/
|
421 |
-
$this->_column_headers = array($columns, $hidden, $sortable);
|
422 |
-
|
423 |
|
424 |
/**
|
425 |
* Optional. You can handle your bulk actions however you see fit. In this
|
@@ -508,6 +804,7 @@ class SLL_List_Table extends WP_List_Table
|
|
508 |
'per_page' => $per_page, //WE have to determine how many items to show on a page
|
509 |
'total_pages' => ceil($total_items/$per_page) //WE have to calculate the total number of pages
|
510 |
) );
|
|
|
511 |
}
|
512 |
|
513 |
-
}
|
4 |
Plugin URI: http://simplerealtytheme.com
|
5 |
Description: This plugin keeps a log of WordPress user logins. Offers user filtering and export features.
|
6 |
Author: Max Chirkov
|
7 |
+
Version: 0.5
|
8 |
Author URI: http://SimpleRealtyTheme.com
|
9 |
*/
|
10 |
|
|
|
11 |
//TODO: add cleanup method on uninstall
|
12 |
|
13 |
if( !class_exists( 'SimpleLoginLog' ) )
|
14 |
{
|
15 |
class SimpleLoginLog {
|
16 |
+
private $db_ver = "1.1";
|
17 |
+
public $table = 'simple_login_log';
|
18 |
private $log_duration = null; //days
|
19 |
private $opt_name = 'simple_login_log';
|
20 |
private $opt = false;
|
21 |
+
private $login_success = 1;
|
22 |
+
public $data_labels = array();
|
23 |
|
24 |
function __construct()
|
25 |
{
|
27 |
$this->table = $wpdb->prefix . $this->table;
|
28 |
$this->opt = get_option($this->opt_name);
|
29 |
|
30 |
+
//Get plugin's DB version
|
31 |
+
$this->installed_ver = get_option( "sll_db_ver" );
|
32 |
+
|
33 |
+
//Check if download was initiated
|
34 |
+
$download = @esc_attr( $_GET['download-login-log'] );
|
35 |
+
if($download)
|
36 |
{
|
37 |
+
$where = ( isset($_GET['where']) ) ? $_GET['where'] : false;
|
38 |
+
$this->export_to_CSV($where);
|
39 |
+
}
|
40 |
|
41 |
|
42 |
add_action( 'admin_menu', array(&$this, 'sll_admin_menu') );
|
43 |
add_action('admin_init', array(&$this, 'settings_api_init') );
|
44 |
+
add_action('admin_head', array(&$this, 'screen_options') );
|
45 |
+
|
46 |
+
//check if db needs to be upgraded after plugin update was completed
|
47 |
+
add_action('plugins_loaded', array(&$this, 'update_db_check') );
|
48 |
|
49 |
//Init login actions
|
50 |
add_action( 'init', array(&$this, 'init_login_actions') );
|
54 |
|
55 |
//Initialize scheduled events
|
56 |
add_action( 'wp', array(&$this, 'init_scheduled_events') );
|
57 |
+
|
58 |
+
//Load Locale
|
59 |
+
add_action('init', array(&$this, 'load_locale'), 10 );
|
60 |
+
|
61 |
+
//For translation purposes
|
62 |
+
$this->data_labels = array(
|
63 |
+
'Successful' => __('Successful', 'sll'),
|
64 |
+
'Failed' => __('Failed', 'sll'),
|
65 |
+
'Login' => __('Login', 'sll'),
|
66 |
+
'User Agent' => __('User Agent', 'sll'),
|
67 |
+
'Login Redirect' => __('Login Redirect', 'sll'),
|
68 |
+
'id' => __('#', 'sll'),
|
69 |
+
'uid' => __('User ID', 'sll'),
|
70 |
+
'user_login' => __('Username', 'sll'),
|
71 |
+
'name' => __('Name', 'sll'),
|
72 |
+
'time' => __('Time', 'sll'),
|
73 |
+
'ip' => __('IP Address', 'sll'),
|
74 |
+
'login_result' => __('Login Result', 'sll'),
|
75 |
+
'data' => __('Data', 'sll'),
|
76 |
+
);
|
77 |
+
|
78 |
+
}
|
79 |
+
|
80 |
+
function load_locale() {
|
81 |
+
$locale = get_locale();
|
82 |
+
if( empty( $locale ) )
|
83 |
+
$locale = 'en_US';
|
84 |
+
|
85 |
+
$mofile = dirname( __FILE__ )."/languages/sll-{$locale}.mo";
|
86 |
+
load_textdomain( 'sll', $mofile );
|
87 |
+
}
|
88 |
+
|
89 |
+
function screen_options() {
|
90 |
+
|
91 |
+
//execute only on login_log page, othewise return null
|
92 |
+
$page = ( isset($_GET['page']) ) ? esc_attr($_GET['page']) : false;
|
93 |
+
if( 'login_log' != $page )
|
94 |
+
return;
|
95 |
+
|
96 |
+
$current_screen = get_current_screen();
|
97 |
+
|
98 |
+
//define options
|
99 |
+
$per_page_field = 'per_page';
|
100 |
+
$per_page_option = $current_screen->id . '_' . $per_page_field;
|
101 |
+
|
102 |
+
//Save options that were applied
|
103 |
+
if( isset($_REQUEST['wp_screen_options']) && isset($_REQUEST['wp_screen_options']['value']) )
|
104 |
+
{
|
105 |
+
update_option( $per_page_option, esc_html($_REQUEST['wp_screen_options']['value']) );
|
106 |
+
}
|
107 |
+
|
108 |
+
//prepare options for display
|
109 |
+
|
110 |
+
//if per page option is not set, use default
|
111 |
+
$per_page_val = get_option($per_page_option, 20);
|
112 |
+
$args = array('label' => __('Records', 'sll'), 'default' => $per_page_val );
|
113 |
+
|
114 |
+
//display options
|
115 |
+
add_screen_option($per_page_field, $args);
|
116 |
+
$_per_page = get_option('users_page_login_log_per_page');
|
117 |
+
|
118 |
+
global $_wp_column_headers;
|
119 |
+
$_wp_column_headers[ $current_screen->id ] = SLL_List_Table::get_columns();
|
120 |
}
|
121 |
|
122 |
function init_login_actions(){
|
165 |
}
|
166 |
}
|
167 |
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Runs via plugin activation hook & creates a database
|
171 |
+
*/
|
172 |
function install()
|
173 |
{
|
174 |
global $wpdb;
|
175 |
+
|
176 |
+
if( $this->installed_ver != $this->db_ver )
|
177 |
+
{
|
178 |
+
//if table does't exist, create a new one
|
179 |
+
if( !$wpdb->get_row("SHOW TABLES LIKE '{$this->table}'") ){
|
180 |
+
$sql = "CREATE TABLE " . $this->table . "
|
181 |
+
(
|
182 |
+
id INT( 11 ) NOT NULL AUTO_INCREMENT ,
|
183 |
+
uid INT( 11 ) NOT NULL ,
|
184 |
+
user_login VARCHAR( 60 ) NOT NULL ,
|
185 |
+
time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL ,
|
186 |
+
ip VARCHAR( 100 ) NOT NULL ,
|
187 |
+
login_result VARCHAR (1) ,
|
188 |
+
data LONGTEXT NOT NULL ,
|
189 |
+
PRIMARY KEY ( id ) ,
|
190 |
+
INDEX ( uid, ip, login_result )
|
191 |
+
);";
|
192 |
+
|
193 |
+
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
194 |
+
dbDelta($sql);
|
195 |
+
|
196 |
+
update_option( "sll_db_ver", $this->db_ver );
|
197 |
+
}
|
198 |
+
}
|
199 |
+
|
200 |
+
|
201 |
+
}
|
202 |
+
|
203 |
+
|
204 |
+
/**
|
205 |
+
* Checks if the installed database version is the same as the db version of the current plugin
|
206 |
+
* calles the version specific function if upgrade is required
|
207 |
+
*/
|
208 |
+
function update_db_check() {
|
209 |
+
if ( get_site_option( 'sll_db_ver' ) != $this->db_ver )
|
210 |
+
{
|
211 |
+
switch( $this->db_ver )
|
212 |
+
{
|
213 |
+
case "1.1":
|
214 |
+
$this->db_update_1_1();
|
215 |
+
break;
|
216 |
+
}
|
217 |
+
}
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* DB version specific updates
|
222 |
+
*/
|
223 |
+
function db_update_1_1()
|
224 |
+
{
|
225 |
+
|
226 |
+
/* this version adds a new field "login_result"
|
227 |
+
* check if this field exists
|
228 |
+
*/
|
229 |
+
global $wpdb;
|
230 |
+
|
231 |
+
$sql = "SELECT * FROM {$this->table}";
|
232 |
+
$fields = $wpdb->get_row($sql, 'ARRAY_A');
|
233 |
+
|
234 |
+
if( !$fields ){
|
235 |
+
$this->install();
|
236 |
+
return;
|
237 |
+
}
|
238 |
+
|
239 |
+
$field_names = array_keys( $fields );
|
240 |
+
|
241 |
+
if( !array_search('login_result', $field_names) )
|
242 |
+
{
|
243 |
+
//add the new field since it doesn't exist
|
244 |
+
$sql = "ALTER TABLE {$this->table} ADD COLUMN login_result varchar(1) NOT NULL AFTER ip, ADD INDEX (login_result);";
|
245 |
+
$insert = $wpdb->query( $sql );
|
246 |
+
|
247 |
+
//update version record if it has been updated
|
248 |
+
if( false !== $insert )
|
249 |
+
update_option( "sll_db_ver", $this->db_ver );
|
250 |
+
|
251 |
+
}
|
252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
}
|
254 |
+
|
255 |
|
256 |
//Initializing Settings
|
257 |
function settings_api_init()
|
258 |
{
|
259 |
+
add_settings_section('simple_login_log', __('Simple Login Log', 'sll'), array(&$this, 'sll_settings'), 'general');
|
260 |
+
add_settings_field('field_log_duration', __('Truncate Log Entries', 'sll'), array(&$this, 'field_log_duration'), 'general', 'simple_login_log');
|
261 |
+
add_settings_field('field_log_failed_attempts', __('Log Failed Attempts', 'sll'), array(&$this, 'field_log_failed_attempts'), 'general', 'simple_login_log');
|
262 |
+
register_setting( 'general', 'simple_login_log' );
|
263 |
+
|
264 |
}
|
265 |
|
266 |
function sll_admin_menu()
|
278 |
$duration = (null !== $this->opt['log_duration']) ? $this->opt['log_duration'] : $this->log_duration;
|
279 |
$output = '<input type="text" value="' . $duration . '" name="simple_login_log[log_duration]" size="10" class="code" /> days and older.';
|
280 |
echo $output;
|
281 |
+
echo "<p>" . __("Leave empty or enter 0 if you don't want the log to be truncated.", 'sll') . "</p>";
|
282 |
}
|
283 |
|
284 |
function field_log_failed_attempts(){
|
285 |
$failed_attempts = ( isset($this->opt['failed_attempts']) ) ? $this->opt['failed_attempts'] : false;
|
286 |
+
echo '<input type="checkbox" name="simple_login_log[failed_attempts]" value="1" ' . checked( $failed_attempts, 1, false ) . ' /> ' . __('Logs failed attempts where user name and password are entered. Will not log if at least one of the mentioned fields is empty.', 'sll');
|
287 |
}
|
288 |
|
289 |
function admin_header()
|
290 |
{
|
291 |
+
$page = ( isset($_GET['page']) ) ? esc_attr($_GET['page']) : false;
|
292 |
+
if( 'login_log' != $page )
|
293 |
return;
|
294 |
|
295 |
echo '<style type="text/css">';
|
299 |
echo '.wp-list-table .column-name { width: 15%; }';
|
300 |
echo '.wp-list-table .column-time { width: 15%; }';
|
301 |
echo '.wp-list-table .column-ip { width: 10%; }';
|
302 |
+
echo '.wp-list-table .column-login_result { width: 10%; }';
|
303 |
echo '.wp-list-table .login-failed { background: #ffd5d1; }';
|
304 |
+
echo '</style>';
|
305 |
}
|
306 |
|
307 |
//Catch messages on successful login
|
310 |
$userdata = get_user_by('login', $user_login);
|
311 |
|
312 |
$uid = ($userdata->ID) ? $userdata->ID : 0;
|
|
|
|
|
|
|
|
|
313 |
|
314 |
+
$data[$this->data_labels['Login']] = ( 1 == $this->login_success ) ? $this->data_labels['Successful'] : $this->data_labels['Failed'];
|
315 |
+
if ( isset( $_REQUEST['redirect_to'] ) ) { $data[$this->data_labels['Login Redirect']] = $_REQUEST['redirect_to']; }
|
316 |
+
$data[$this->data_labels['User Agent']] = $_SERVER['HTTP_USER_AGENT'];
|
317 |
|
318 |
$serialized_data = serialize($data);
|
319 |
|
322 |
'user_login' => $user_login,
|
323 |
'time' => current_time('mysql'),
|
324 |
'ip' => $_SERVER['REMOTE_ADDR'],
|
325 |
+
'login_result' => $this->login_success,
|
326 |
'data' => $serialized_data,
|
327 |
);
|
328 |
|
329 |
+
$format = array('%d', '%s', '%s', '%s', '%s', '%s');
|
330 |
|
331 |
$this->save_data($values, $format);
|
332 |
}
|
337 |
$wpdb->insert( $this->table, $values, $format );
|
338 |
}
|
339 |
|
340 |
+
function make_where_query(){
|
341 |
+
$where = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
342 |
if( isset($_GET['filter']) && '' != $_GET['filter'] )
|
343 |
{
|
344 |
+
$where['filter'] = "user_login = '{$_GET['filter']}'";
|
345 |
+
}
|
346 |
+
if( isset($_GET['result']) && '' != $_GET['result'] )
|
347 |
+
{
|
348 |
+
$where['result'] = "login_result = '{$_GET['result']}'";
|
349 |
}
|
350 |
if( isset($_GET['datefilter']) && '' != $_GET['datefilter'] )
|
351 |
{
|
352 |
$year = substr($_GET['datefilter'], 0, 4);
|
353 |
$month = substr($_GET['datefilter'], -2);
|
354 |
+
$where['datefilter'] = "YEAR(time) = {$year} AND MONTH(time) = {$month}";
|
355 |
}
|
356 |
|
357 |
+
return $where;
|
358 |
+
}
|
359 |
+
|
360 |
+
function log_get_data(){
|
361 |
+
global $wpdb;
|
362 |
+
|
363 |
+
$limit = 20;
|
364 |
+
$where = '';
|
365 |
+
|
366 |
+
$where = $this->make_where_query();
|
367 |
+
|
368 |
+
if( is_array($where) && !empty($where) )
|
369 |
+
$where = 'WHERE ' . implode(' AND ', $where);
|
370 |
+
|
371 |
+
$sql = "SELECT * FROM $this->table $where ORDER BY time DESC LIMIT $limit";
|
372 |
$data = $wpdb->get_results($sql, 'ARRAY_A');
|
373 |
+
|
374 |
+
return $data;
|
375 |
+
}
|
376 |
+
|
377 |
+
function log_manager()
|
378 |
+
{
|
379 |
+
|
380 |
+
$log_table = new SLL_List_Table;
|
381 |
|
382 |
+
$log_table->items = $this->log_get_data();
|
383 |
+
$log_table->prepare_items();
|
384 |
|
385 |
echo '<div class="wrap srp">';
|
386 |
+
echo '<h2>' . __('Login Log', 'sll') . '</h2>';
|
387 |
+
echo '<div class="tablenav top">';
|
388 |
+
echo '<div class="alignleft actions">';
|
389 |
+
echo $this->date_filter();
|
390 |
+
echo '</div>';
|
391 |
+
|
392 |
+
$username = ( isset($_GET['filter']) ) ? esc_attr($_GET['filter']) : false;
|
393 |
+
echo '<form method="get" class="alignright">';
|
394 |
+
echo '<p class="search-box">';
|
395 |
+
echo '<input type="hidden" name="page" value="login_log" />';
|
396 |
+
echo '<label>' . __('Username:', 'sll') . ' </label><input type="text" name="filter" class="filter-username" value="' . $username . '" /> <input class="button" type="submit" value="' . __('Filter User', 'sll') . '" />';
|
397 |
+
echo '<br />';
|
398 |
+
echo '</p>';
|
399 |
+
echo '</form>';
|
400 |
+
echo '</div>';
|
401 |
+
echo '<div class="tablenav top">';
|
402 |
+
|
403 |
+
//if log failed attempts is set in the settings, then output views filter
|
404 |
+
if( isset($this->opt['failed_attempts']) ){
|
405 |
+
echo '<div class="alignleft actions">';
|
406 |
+
$log_table->views();
|
407 |
+
echo '</div>';
|
408 |
+
}
|
409 |
+
|
410 |
+
echo '<div class="alignright actions">';
|
411 |
+
$mode = ( isset($_GET['mode']) ) ? esc_attr($_GET['mode']) : false;
|
412 |
+
$log_table->view_switcher($mode);
|
413 |
+
echo '</div>';
|
414 |
echo '</div>';
|
415 |
+
|
416 |
+
$log_table->display();
|
417 |
+
|
418 |
+
echo '<form method="get" id="export-login-log">';
|
419 |
echo '<input type="hidden" name="page" value="login_log" />';
|
420 |
+
echo '<input type="hidden" name="download-login-log" value="true" />';
|
421 |
+
submit_button( __('Export Log to CSV', 'sll'), 'secondary' );
|
422 |
+
echo '</form>';
|
423 |
+
//if filtered results - add export filtered results button
|
424 |
+
if( $where = $this->make_where_query() ){
|
425 |
+
|
426 |
+
echo '<form method="get" id="export-login-log">';
|
427 |
+
echo '<input type="hidden" name="page" value="login_log" />';
|
428 |
+
echo '<input type="hidden" name="download-login-log" value="true" />';
|
429 |
+
echo '<input type="hidden" name="where" value="' . esc_attr(serialize($where)) . '" />';
|
430 |
+
submit_button( __('Export Current Results to CSV', 'sll'), 'secondary' );
|
431 |
+
echo '</form>';
|
432 |
+
|
433 |
+
}
|
434 |
+
|
435 |
+
echo '</div>';
|
436 |
}
|
437 |
|
438 |
private function date_filter()
|
439 |
{
|
440 |
global $wpdb;
|
441 |
+
$sql = "SELECT DISTINCT YEAR(time) as year, MONTH(time)as month FROM {$this->table} ORDER BY YEAR(time), MONTH(time) desc";
|
442 |
$results = $wpdb->get_results($sql);
|
443 |
|
444 |
if(!$results)
|
457 |
|
458 |
$output = '<form method="get">';
|
459 |
$output .= '<input type="hidden" name="page" value="login_log" />';
|
460 |
+
$output .= '<select name="datefilter"><option value="">' . __('View All', 'sll') . '</option>' . $option . '</select>';
|
461 |
+
$output .= '<input class="button" type="submit" value="' . __('Filter', 'sll') . '" />';
|
462 |
$output .= '</form>';
|
463 |
return $output;
|
464 |
}
|
465 |
|
466 |
+
function export_to_CSV($where = false){
|
467 |
global $wpdb;
|
468 |
|
469 |
+
//if $where is set, then contemplate WHERE sql query
|
470 |
+
if( $where ){
|
471 |
+
$where = unserialize($where);
|
472 |
+
|
473 |
+
if( is_array($where) && !empty($where) )
|
474 |
+
$where = ' WHERE ' . implode(' AND ', $where);
|
475 |
+
|
476 |
+
}
|
477 |
+
|
478 |
+
$sql = "SELECT * FROM {$this->table}{$where}";
|
479 |
$data = $wpdb->get_results($sql, 'ARRAY_A');
|
480 |
|
481 |
if(!$data)
|
482 |
return;
|
483 |
|
484 |
+
//date string to suffix the file nanme: month - day - year - hour - minute
|
485 |
+
$suffix = date('n-j-y_H-i');
|
486 |
+
|
487 |
// send response headers to the browser
|
488 |
header( 'Content-Type: text/csv' );
|
489 |
+
header( 'Content-Disposition: attachment;filename=login_log_' . $suffix . '.csv');
|
490 |
$fp = fopen('php://output', 'w');
|
491 |
|
492 |
$i = 0;
|
504 |
}
|
505 |
|
506 |
fclose($fp);
|
507 |
+
die();
|
508 |
}
|
509 |
|
510 |
}
|
525 |
{
|
526 |
function __construct()
|
527 |
{
|
528 |
+
global $sll, $_wp_column_headers;
|
529 |
|
530 |
//Set parent defaults
|
531 |
parent::__construct( array(
|
533 |
'plural' => 'users', //plural name of the listed records
|
534 |
'ajax' => false //does this table support ajax?
|
535 |
) );
|
536 |
+
|
537 |
+
$this->data_labels = $sll->data_labels;
|
538 |
+
|
539 |
+
}
|
540 |
|
541 |
function column_default($item, $column_name)
|
542 |
{
|
543 |
+
$item = apply_filters('sll-output-data', $item);
|
544 |
switch($column_name){
|
545 |
case 'id':
|
546 |
case 'uid':
|
547 |
+
case 'time':
|
548 |
case 'ip':
|
549 |
+
return $item[$column_name];
|
550 |
case 'user_login':
|
551 |
+
//unset existing filter and pagination
|
552 |
+
$args = wp_parse_args( parse_url($_SERVER["REQUEST_URI"], PHP_URL_QUERY) );
|
553 |
+
unset($args['filter']);
|
554 |
+
unset($args['paged']);
|
555 |
+
return "<a href='" . add_query_arg( array('filter' => $item[$column_name]), menu_page_url('login_log', false) ) . "' title='" . __('Filter log by this name', 'sll') . "'>{$item[$column_name]}</a>";
|
556 |
case 'name';
|
557 |
$user_info = get_userdata($item['uid']);
|
558 |
return ( is_object($user_info) ) ? $user_info->first_name . " " . $user_info->last_name : false;
|
559 |
+
case 'login_result':
|
560 |
+
if ( '' == $item[$column_name]) return '';
|
561 |
+
return ( '1' == $item[$column_name] ) ? $this->data_labels['Successful'] : '<div class="login-failed">' . $this->data_labels['Failed'] . '</div>';
|
562 |
case 'data':
|
563 |
+
$data = unserialize($item[$column_name]);
|
564 |
if(is_array($data))
|
565 |
{
|
566 |
$output = '';
|
568 |
{
|
569 |
$output .= $k .': '. $v .'<br />';
|
570 |
}
|
571 |
+
|
572 |
+
$output = ( isset($_GET['mode']) && 'excerpt' == $_GET['mode'] ) ? $output : substr($output, 0, 50) . '...';
|
573 |
+
|
574 |
+
if( isset($data[$this->data_labels['Login']]) && $data[$this->data_labels['Login']] == $this->data_labels['Failed'] ){
|
575 |
return '<div class="login-failed">' . $output . '</div>';
|
576 |
}
|
577 |
return $output;
|
578 |
}
|
579 |
break;
|
580 |
default:
|
581 |
+
return $item[$column_name];
|
582 |
}
|
583 |
}
|
584 |
|
585 |
function get_columns()
|
586 |
+
{
|
587 |
+
global $status;
|
588 |
$columns = array(
|
589 |
+
'id' => $this->data_labels['id'],
|
590 |
+
'uid' => $this->data_labels['uid'],
|
591 |
+
'user_login' => $this->data_labels['user_login'],
|
592 |
+
'name' => $this->data_labels['name'],
|
593 |
+
'time' => $this->data_labels['time'],
|
594 |
+
'ip' => $this->data_labels['ip'],
|
595 |
+
'login_result' => $this->data_labels['login_result'],
|
596 |
+
'data' => $this->data_labels['data'],
|
597 |
+
);
|
598 |
return $columns;
|
599 |
}
|
600 |
|
602 |
{
|
603 |
$sortable_columns = array(
|
604 |
//'id' => array('id',true), //doesn't sort correctly
|
605 |
+
'uid' => array('uid',false),
|
606 |
+
'user_login' => array('user_login', false),
|
607 |
+
'time' => array('time',true),
|
608 |
+
'ip' => array('ip', false),
|
609 |
);
|
610 |
return $sortable_columns;
|
611 |
}
|
612 |
|
613 |
+
function get_views()
|
614 |
+
{
|
615 |
+
//creating class="current" variables
|
616 |
+
if( !isset($_GET['result']) ){
|
617 |
+
$all = 'class="current"';
|
618 |
+
$success = '';
|
619 |
+
$failed = '';
|
620 |
+
}else{
|
621 |
+
$all = '';
|
622 |
+
$success = ( '1' == $_GET['result'] ) ? 'class="current"' : '';
|
623 |
+
$failed = ( '0' == $_GET['result'] ) ? 'class="current"' : '';
|
624 |
+
}
|
625 |
+
|
626 |
+
//get number of successful and failed logins so we can display them in parentheces for each view
|
627 |
+
global $wpdb, $sll;
|
628 |
+
|
629 |
+
//building a WHERE SQL query for each view
|
630 |
+
$where = $sll->make_where_query();
|
631 |
+
//we only need the date filter, everything else need to be unset
|
632 |
+
if( is_array($where) && isset($where['datefilter']) ){
|
633 |
+
$where = array( 'datefilter' => $where['datefilter'] );
|
634 |
+
}else{
|
635 |
+
$where = false;
|
636 |
+
}
|
637 |
+
|
638 |
+
$where3 = $where2 = $where1 = $where;
|
639 |
+
$where2['login_result'] = "login_result = '1'";
|
640 |
+
$where3['login_result'] = "login_result = '0'";
|
641 |
+
|
642 |
+
if(is_array($where1) && !empty($where1)){
|
643 |
+
$where1 = 'WHERE ' . implode(' AND ', $where1);
|
644 |
+
}
|
645 |
+
$where2 = 'WHERE ' . implode(' AND ', $where2);
|
646 |
+
$where3 = 'WHERE ' . implode(' AND ', $where3);
|
647 |
+
|
648 |
+
$sql1 = "SELECT * FROM {$sll->table} {$where1}";
|
649 |
+
$a = $wpdb->query($sql1);
|
650 |
+
$sql2 = "SELECT * FROM {$sll->table} {$where2}";
|
651 |
+
$s = $wpdb->query($sql2);
|
652 |
+
$sql3 = "SELECT * FROM {$sll->table} {$where3}";
|
653 |
+
$f = $wpdb->query($sql3);
|
654 |
+
|
655 |
+
//if date filter is set, adjust views label to reflect the date
|
656 |
+
$date_label = false;
|
657 |
+
if( isset($_GET['datefilter']) && !empty($_GET['datefilter']) ){
|
658 |
+
$year = substr($_GET['datefilter'], 0, 4);
|
659 |
+
$month = substr($_GET['datefilter'], -2);
|
660 |
+
$timestamp = mktime(0, 0, 0, $month, 1, $year);
|
661 |
+
$date_label = date('F', $timestamp) . ' ' . $year . ' ';
|
662 |
+
}
|
663 |
+
|
664 |
+
//get args from the URL
|
665 |
+
$args = wp_parse_args( parse_url($_SERVER["REQUEST_URI"], PHP_URL_QUERY) );
|
666 |
+
//the only arguments we can pass are mode and datefilter
|
667 |
+
$param = false;
|
668 |
+
if( isset($args['mode']) )
|
669 |
+
$param['mode'] = $args['mode'];
|
670 |
+
|
671 |
+
if( isset($args['datefilter']) )
|
672 |
+
$param['datefilter'] = $args['datefilter'];
|
673 |
+
|
674 |
+
//creating base url for the views links
|
675 |
+
$menu_page_url = menu_page_url('login_log', false);
|
676 |
+
( is_array($param) && !empty($param) ) ? $url = add_query_arg( $param, $menu_page_url) : $url = $menu_page_url;
|
677 |
+
|
678 |
+
//definition for views array
|
679 |
+
$views = array(
|
680 |
+
'all' => $date_label . __('Login Results', 'sll') . ': <a ' . $all . ' href="' . $url . '">' . __('All', 'sll') . '</a>' . '(' .$a . ')',
|
681 |
+
'success' => '<a ' . $success . ' href="' . $url . '&result=1">' . __('Successful', 'sll') . '</a> (' . $s . ')',
|
682 |
+
'failed' => '<a ' . $failed . ' href="' . $url . '&result=0">' . __('Failed', 'sll') . '</a>' . '(' . $f . ')',
|
683 |
+
);
|
684 |
+
|
685 |
+
return $views;
|
686 |
+
}
|
687 |
+
|
688 |
function prepare_items()
|
689 |
{
|
690 |
+
$screen = get_current_screen();
|
691 |
+
|
692 |
/**
|
693 |
* First, lets decide how many records per page to show
|
694 |
+
*/
|
695 |
+
$per_page_option = $screen->id . '_per_page';
|
696 |
+
$per_page = get_option($per_page_option, 20);
|
697 |
|
698 |
|
699 |
/**
|
704 |
* used to build the value for our _column_headers property.
|
705 |
*/
|
706 |
$columns = $this->get_columns();
|
707 |
+
$hidden_cols = get_user_option( 'manage' . $screen->id . 'columnshidden' );
|
708 |
+
$hidden = ( $hidden_cols ) ? $hidden_cols : array();
|
709 |
$sortable = $this->get_sortable_columns();
|
710 |
|
711 |
|
715 |
* 3 other arrays. One for all columns, one for hidden columns, and one
|
716 |
* for sortable columns.
|
717 |
*/
|
718 |
+
$this->_column_headers = array($columns, $hidden, $sortable);
|
|
|
719 |
|
720 |
/**
|
721 |
* Optional. You can handle your bulk actions however you see fit. In this
|
804 |
'per_page' => $per_page, //WE have to determine how many items to show on a page
|
805 |
'total_pages' => ceil($total_items/$per_page) //WE have to calculate the total number of pages
|
806 |
) );
|
807 |
+
|
808 |
}
|
809 |
|
810 |
+
}
|