Simple History - Version 2.40.0

Version Description

(March 2021) =

  • Changed: IP address is now also shown when a user successfully logs in. Previously the IP address was only shown for failed login attempts. Note that the IP address/es of all events are always logged and can be seen in the "context data" table that is displayed when you click the date and time of an event. #233.

  • Added: If multiple IP addresses are detected, for example when a website is running behind a proxy or similar, all IP addresses are now shown for failed and sucessful logins.

  • Added: Filter simple_history/row_header_output/display_ip_address that can be used to control when the IP address/es should be visible in the main log. By default sucessful and failed logins are shown.

  • Added: Show message when failing to get IP address due to for example ad blocker. IPInfo.io is for example blocked in the EasyList filter list that for example Chrome extension uBlock Origin uses.

  • Added: Filter simple_history/row_header_output/template that controls the output of the header row in the main event log.

Download this release

Release Info

Developer eskapism
Plugin Icon 128x128 Simple History
Version 2.40.0
Comparing to
See all releases

Code changes from version 2.39.0 to 2.40.0

composer.json CHANGED
@@ -10,7 +10,8 @@
10
  "homepage": "http://simple-history.com/",
11
  "minimum-stability": "dev",
12
  "require-dev": {
13
- "squizlabs/php_codesniffer": "^3.5"
 
14
  },
15
  "require": {
16
  "php": ">=5.2.0"
10
  "homepage": "http://simple-history.com/",
11
  "minimum-stability": "dev",
12
  "require-dev": {
13
+ "squizlabs/php_codesniffer": "^3.5",
14
+ "phpunit/phpunit": "^7"
15
  },
16
  "require": {
17
  "php": ">=5.2.0"
composer.lock CHANGED
@@ -4,9 +4,1518 @@
4
  "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
  "This file is @generated automatically"
6
  ],
7
- "content-hash": "2b65e6c117e9f812e13934ba2a32be21",
8
  "packages": [],
9
  "packages-dev": [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  {
11
  "name": "squizlabs/php_codesniffer",
12
  "version": "dev-master",
@@ -57,6 +1566,195 @@
57
  "standards"
58
  ],
59
  "time": "2020-05-21T06:41:29+00:00"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
  ],
62
  "aliases": [],
@@ -68,5 +1766,5 @@
68
  "php": ">=5.2.0"
69
  },
70
  "platform-dev": [],
71
- "plugin-api-version": "1.1.0"
72
  }
4
  "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
  "This file is @generated automatically"
6
  ],
7
+ "content-hash": "3eb8f2dd7c7507bb8a21f6bb503f457f",
8
  "packages": [],
9
  "packages-dev": [
10
+ {
11
+ "name": "doctrine/instantiator",
12
+ "version": "1.5.x-dev",
13
+ "source": {
14
+ "type": "git",
15
+ "url": "https://github.com/doctrine/instantiator.git",
16
+ "reference": "6410c4b8352cb64218641457cef64997e6b784fb"
17
+ },
18
+ "dist": {
19
+ "type": "zip",
20
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/6410c4b8352cb64218641457cef64997e6b784fb",
21
+ "reference": "6410c4b8352cb64218641457cef64997e6b784fb",
22
+ "shasum": ""
23
+ },
24
+ "require": {
25
+ "php": "^7.1 || ^8.0"
26
+ },
27
+ "require-dev": {
28
+ "doctrine/coding-standard": "^8.0",
29
+ "ext-pdo": "*",
30
+ "ext-phar": "*",
31
+ "phpbench/phpbench": "^0.13 || 1.0.0-alpha2",
32
+ "phpstan/phpstan": "^0.12",
33
+ "phpstan/phpstan-phpunit": "^0.12",
34
+ "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
35
+ },
36
+ "type": "library",
37
+ "autoload": {
38
+ "psr-4": {
39
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
40
+ }
41
+ },
42
+ "notification-url": "https://packagist.org/downloads/",
43
+ "license": [
44
+ "MIT"
45
+ ],
46
+ "authors": [
47
+ {
48
+ "name": "Marco Pivetta",
49
+ "email": "ocramius@gmail.com",
50
+ "homepage": "https://ocramius.github.io/"
51
+ }
52
+ ],
53
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
54
+ "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
55
+ "keywords": [
56
+ "constructor",
57
+ "instantiate"
58
+ ],
59
+ "support": {
60
+ "issues": "https://github.com/doctrine/instantiator/issues",
61
+ "source": "https://github.com/doctrine/instantiator/tree/1.4.x"
62
+ },
63
+ "funding": [
64
+ {
65
+ "url": "https://www.doctrine-project.org/sponsorship.html",
66
+ "type": "custom"
67
+ },
68
+ {
69
+ "url": "https://www.patreon.com/phpdoctrine",
70
+ "type": "patreon"
71
+ },
72
+ {
73
+ "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
74
+ "type": "tidelift"
75
+ }
76
+ ],
77
+ "time": "2020-11-10T19:05:51+00:00"
78
+ },
79
+ {
80
+ "name": "myclabs/deep-copy",
81
+ "version": "1.x-dev",
82
+ "source": {
83
+ "type": "git",
84
+ "url": "https://github.com/myclabs/DeepCopy.git",
85
+ "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220"
86
+ },
87
+ "dist": {
88
+ "type": "zip",
89
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220",
90
+ "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220",
91
+ "shasum": ""
92
+ },
93
+ "require": {
94
+ "php": "^7.1 || ^8.0"
95
+ },
96
+ "replace": {
97
+ "myclabs/deep-copy": "self.version"
98
+ },
99
+ "require-dev": {
100
+ "doctrine/collections": "^1.0",
101
+ "doctrine/common": "^2.6",
102
+ "phpunit/phpunit": "^7.1"
103
+ },
104
+ "default-branch": true,
105
+ "type": "library",
106
+ "autoload": {
107
+ "psr-4": {
108
+ "DeepCopy\\": "src/DeepCopy/"
109
+ },
110
+ "files": [
111
+ "src/DeepCopy/deep_copy.php"
112
+ ]
113
+ },
114
+ "notification-url": "https://packagist.org/downloads/",
115
+ "license": [
116
+ "MIT"
117
+ ],
118
+ "description": "Create deep copies (clones) of your objects",
119
+ "keywords": [
120
+ "clone",
121
+ "copy",
122
+ "duplicate",
123
+ "object",
124
+ "object graph"
125
+ ],
126
+ "support": {
127
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
128
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2"
129
+ },
130
+ "funding": [
131
+ {
132
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
133
+ "type": "tidelift"
134
+ }
135
+ ],
136
+ "time": "2020-11-13T09:40:50+00:00"
137
+ },
138
+ {
139
+ "name": "phar-io/manifest",
140
+ "version": "1.0.3",
141
+ "source": {
142
+ "type": "git",
143
+ "url": "https://github.com/phar-io/manifest.git",
144
+ "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
145
+ },
146
+ "dist": {
147
+ "type": "zip",
148
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
149
+ "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
150
+ "shasum": ""
151
+ },
152
+ "require": {
153
+ "ext-dom": "*",
154
+ "ext-phar": "*",
155
+ "phar-io/version": "^2.0",
156
+ "php": "^5.6 || ^7.0"
157
+ },
158
+ "type": "library",
159
+ "extra": {
160
+ "branch-alias": {
161
+ "dev-master": "1.0.x-dev"
162
+ }
163
+ },
164
+ "autoload": {
165
+ "classmap": [
166
+ "src/"
167
+ ]
168
+ },
169
+ "notification-url": "https://packagist.org/downloads/",
170
+ "license": [
171
+ "BSD-3-Clause"
172
+ ],
173
+ "authors": [
174
+ {
175
+ "name": "Arne Blankerts",
176
+ "email": "arne@blankerts.de",
177
+ "role": "Developer"
178
+ },
179
+ {
180
+ "name": "Sebastian Heuer",
181
+ "email": "sebastian@phpeople.de",
182
+ "role": "Developer"
183
+ },
184
+ {
185
+ "name": "Sebastian Bergmann",
186
+ "email": "sebastian@phpunit.de",
187
+ "role": "Developer"
188
+ }
189
+ ],
190
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
191
+ "support": {
192
+ "issues": "https://github.com/phar-io/manifest/issues",
193
+ "source": "https://github.com/phar-io/manifest/tree/master"
194
+ },
195
+ "time": "2018-07-08T19:23:20+00:00"
196
+ },
197
+ {
198
+ "name": "phar-io/version",
199
+ "version": "2.0.1",
200
+ "source": {
201
+ "type": "git",
202
+ "url": "https://github.com/phar-io/version.git",
203
+ "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
204
+ },
205
+ "dist": {
206
+ "type": "zip",
207
+ "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
208
+ "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
209
+ "shasum": ""
210
+ },
211
+ "require": {
212
+ "php": "^5.6 || ^7.0"
213
+ },
214
+ "type": "library",
215
+ "autoload": {
216
+ "classmap": [
217
+ "src/"
218
+ ]
219
+ },
220
+ "notification-url": "https://packagist.org/downloads/",
221
+ "license": [
222
+ "BSD-3-Clause"
223
+ ],
224
+ "authors": [
225
+ {
226
+ "name": "Arne Blankerts",
227
+ "email": "arne@blankerts.de",
228
+ "role": "Developer"
229
+ },
230
+ {
231
+ "name": "Sebastian Heuer",
232
+ "email": "sebastian@phpeople.de",
233
+ "role": "Developer"
234
+ },
235
+ {
236
+ "name": "Sebastian Bergmann",
237
+ "email": "sebastian@phpunit.de",
238
+ "role": "Developer"
239
+ }
240
+ ],
241
+ "description": "Library for handling version information and constraints",
242
+ "support": {
243
+ "issues": "https://github.com/phar-io/version/issues",
244
+ "source": "https://github.com/phar-io/version/tree/master"
245
+ },
246
+ "time": "2018-07-08T19:19:57+00:00"
247
+ },
248
+ {
249
+ "name": "phpdocumentor/reflection-common",
250
+ "version": "dev-master",
251
+ "source": {
252
+ "type": "git",
253
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
254
+ "reference": "cf8df60735d98fd18070b7cab0019ba0831e219c"
255
+ },
256
+ "dist": {
257
+ "type": "zip",
258
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/cf8df60735d98fd18070b7cab0019ba0831e219c",
259
+ "reference": "cf8df60735d98fd18070b7cab0019ba0831e219c",
260
+ "shasum": ""
261
+ },
262
+ "require": {
263
+ "php": ">=7.1"
264
+ },
265
+ "default-branch": true,
266
+ "type": "library",
267
+ "extra": {
268
+ "branch-alias": {
269
+ "dev-master": "2.x-dev"
270
+ }
271
+ },
272
+ "autoload": {
273
+ "psr-4": {
274
+ "phpDocumentor\\Reflection\\": "src/"
275
+ }
276
+ },
277
+ "notification-url": "https://packagist.org/downloads/",
278
+ "license": [
279
+ "MIT"
280
+ ],
281
+ "authors": [
282
+ {
283
+ "name": "Jaap van Otterdijk",
284
+ "email": "opensource@ijaap.nl"
285
+ }
286
+ ],
287
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
288
+ "homepage": "http://www.phpdoc.org",
289
+ "keywords": [
290
+ "FQSEN",
291
+ "phpDocumentor",
292
+ "phpdoc",
293
+ "reflection",
294
+ "static analysis"
295
+ ],
296
+ "support": {
297
+ "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
298
+ "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master"
299
+ },
300
+ "time": "2020-06-19T17:42:03+00:00"
301
+ },
302
+ {
303
+ "name": "phpdocumentor/reflection-docblock",
304
+ "version": "dev-master",
305
+ "source": {
306
+ "type": "git",
307
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
308
+ "reference": "e3324ecbde7319b0bbcf0fd7ca4af19469c38da9"
309
+ },
310
+ "dist": {
311
+ "type": "zip",
312
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e3324ecbde7319b0bbcf0fd7ca4af19469c38da9",
313
+ "reference": "e3324ecbde7319b0bbcf0fd7ca4af19469c38da9",
314
+ "shasum": ""
315
+ },
316
+ "require": {
317
+ "ext-filter": "*",
318
+ "php": "^7.2 || ^8.0",
319
+ "phpdocumentor/reflection-common": "^2.2",
320
+ "phpdocumentor/type-resolver": "^1.3",
321
+ "webmozart/assert": "^1.9.1"
322
+ },
323
+ "require-dev": {
324
+ "mockery/mockery": "~1.3.2"
325
+ },
326
+ "default-branch": true,
327
+ "type": "library",
328
+ "extra": {
329
+ "branch-alias": {
330
+ "dev-master": "5.x-dev"
331
+ }
332
+ },
333
+ "autoload": {
334
+ "psr-4": {
335
+ "phpDocumentor\\Reflection\\": "src"
336
+ }
337
+ },
338
+ "notification-url": "https://packagist.org/downloads/",
339
+ "license": [
340
+ "MIT"
341
+ ],
342
+ "authors": [
343
+ {
344
+ "name": "Mike van Riel",
345
+ "email": "me@mikevanriel.com"
346
+ },
347
+ {
348
+ "name": "Jaap van Otterdijk",
349
+ "email": "account@ijaap.nl"
350
+ }
351
+ ],
352
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
353
+ "support": {
354
+ "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
355
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master"
356
+ },
357
+ "time": "2020-11-18T14:27:38+00:00"
358
+ },
359
+ {
360
+ "name": "phpdocumentor/type-resolver",
361
+ "version": "1.x-dev",
362
+ "source": {
363
+ "type": "git",
364
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
365
+ "reference": "6759f2268deb9f329812679e9dcb2d0083b2a30b"
366
+ },
367
+ "dist": {
368
+ "type": "zip",
369
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6759f2268deb9f329812679e9dcb2d0083b2a30b",
370
+ "reference": "6759f2268deb9f329812679e9dcb2d0083b2a30b",
371
+ "shasum": ""
372
+ },
373
+ "require": {
374
+ "php": "^7.2 || ^8.0",
375
+ "phpdocumentor/reflection-common": "^2.0"
376
+ },
377
+ "require-dev": {
378
+ "ext-tokenizer": "*"
379
+ },
380
+ "default-branch": true,
381
+ "type": "library",
382
+ "extra": {
383
+ "branch-alias": {
384
+ "dev-1.x": "1.x-dev"
385
+ }
386
+ },
387
+ "autoload": {
388
+ "psr-4": {
389
+ "phpDocumentor\\Reflection\\": "src"
390
+ }
391
+ },
392
+ "notification-url": "https://packagist.org/downloads/",
393
+ "license": [
394
+ "MIT"
395
+ ],
396
+ "authors": [
397
+ {
398
+ "name": "Mike van Riel",
399
+ "email": "me@mikevanriel.com"
400
+ }
401
+ ],
402
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
403
+ "support": {
404
+ "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
405
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.x"
406
+ },
407
+ "time": "2021-02-02T21:09:27+00:00"
408
+ },
409
+ {
410
+ "name": "phpspec/prophecy",
411
+ "version": "1.12.2",
412
+ "source": {
413
+ "type": "git",
414
+ "url": "https://github.com/phpspec/prophecy.git",
415
+ "reference": "245710e971a030f42e08f4912863805570f23d39"
416
+ },
417
+ "dist": {
418
+ "type": "zip",
419
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39",
420
+ "reference": "245710e971a030f42e08f4912863805570f23d39",
421
+ "shasum": ""
422
+ },
423
+ "require": {
424
+ "doctrine/instantiator": "^1.2",
425
+ "php": "^7.2 || ~8.0, <8.1",
426
+ "phpdocumentor/reflection-docblock": "^5.2",
427
+ "sebastian/comparator": "^3.0 || ^4.0",
428
+ "sebastian/recursion-context": "^3.0 || ^4.0"
429
+ },
430
+ "require-dev": {
431
+ "phpspec/phpspec": "^6.0",
432
+ "phpunit/phpunit": "^8.0 || ^9.0"
433
+ },
434
+ "type": "library",
435
+ "extra": {
436
+ "branch-alias": {
437
+ "dev-master": "1.11.x-dev"
438
+ }
439
+ },
440
+ "autoload": {
441
+ "psr-4": {
442
+ "Prophecy\\": "src/Prophecy"
443
+ }
444
+ },
445
+ "notification-url": "https://packagist.org/downloads/",
446
+ "license": [
447
+ "MIT"
448
+ ],
449
+ "authors": [
450
+ {
451
+ "name": "Konstantin Kudryashov",
452
+ "email": "ever.zet@gmail.com",
453
+ "homepage": "http://everzet.com"
454
+ },
455
+ {
456
+ "name": "Marcello Duarte",
457
+ "email": "marcello.duarte@gmail.com"
458
+ }
459
+ ],
460
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
461
+ "homepage": "https://github.com/phpspec/prophecy",
462
+ "keywords": [
463
+ "Double",
464
+ "Dummy",
465
+ "fake",
466
+ "mock",
467
+ "spy",
468
+ "stub"
469
+ ],
470
+ "support": {
471
+ "issues": "https://github.com/phpspec/prophecy/issues",
472
+ "source": "https://github.com/phpspec/prophecy/tree/1.12.2"
473
+ },
474
+ "time": "2020-12-19T10:15:11+00:00"
475
+ },
476
+ {
477
+ "name": "phpunit/php-code-coverage",
478
+ "version": "6.1.4",
479
+ "source": {
480
+ "type": "git",
481
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
482
+ "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d"
483
+ },
484
+ "dist": {
485
+ "type": "zip",
486
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
487
+ "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
488
+ "shasum": ""
489
+ },
490
+ "require": {
491
+ "ext-dom": "*",
492
+ "ext-xmlwriter": "*",
493
+ "php": "^7.1",
494
+ "phpunit/php-file-iterator": "^2.0",
495
+ "phpunit/php-text-template": "^1.2.1",
496
+ "phpunit/php-token-stream": "^3.0",
497
+ "sebastian/code-unit-reverse-lookup": "^1.0.1",
498
+ "sebastian/environment": "^3.1 || ^4.0",
499
+ "sebastian/version": "^2.0.1",
500
+ "theseer/tokenizer": "^1.1"
501
+ },
502
+ "require-dev": {
503
+ "phpunit/phpunit": "^7.0"
504
+ },
505
+ "suggest": {
506
+ "ext-xdebug": "^2.6.0"
507
+ },
508
+ "type": "library",
509
+ "extra": {
510
+ "branch-alias": {
511
+ "dev-master": "6.1-dev"
512
+ }
513
+ },
514
+ "autoload": {
515
+ "classmap": [
516
+ "src/"
517
+ ]
518
+ },
519
+ "notification-url": "https://packagist.org/downloads/",
520
+ "license": [
521
+ "BSD-3-Clause"
522
+ ],
523
+ "authors": [
524
+ {
525
+ "name": "Sebastian Bergmann",
526
+ "email": "sebastian@phpunit.de",
527
+ "role": "lead"
528
+ }
529
+ ],
530
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
531
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
532
+ "keywords": [
533
+ "coverage",
534
+ "testing",
535
+ "xunit"
536
+ ],
537
+ "support": {
538
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
539
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/master"
540
+ },
541
+ "time": "2018-10-31T16:06:48+00:00"
542
+ },
543
+ {
544
+ "name": "phpunit/php-file-iterator",
545
+ "version": "2.0.x-dev",
546
+ "source": {
547
+ "type": "git",
548
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
549
+ "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357"
550
+ },
551
+ "dist": {
552
+ "type": "zip",
553
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4b49fb70f067272b659ef0174ff9ca40fdaa6357",
554
+ "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357",
555
+ "shasum": ""
556
+ },
557
+ "require": {
558
+ "php": ">=7.1"
559
+ },
560
+ "require-dev": {
561
+ "phpunit/phpunit": "^8.5"
562
+ },
563
+ "type": "library",
564
+ "extra": {
565
+ "branch-alias": {
566
+ "dev-master": "2.0.x-dev"
567
+ }
568
+ },
569
+ "autoload": {
570
+ "classmap": [
571
+ "src/"
572
+ ]
573
+ },
574
+ "notification-url": "https://packagist.org/downloads/",
575
+ "license": [
576
+ "BSD-3-Clause"
577
+ ],
578
+ "authors": [
579
+ {
580
+ "name": "Sebastian Bergmann",
581
+ "email": "sebastian@phpunit.de",
582
+ "role": "lead"
583
+ }
584
+ ],
585
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
586
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
587
+ "keywords": [
588
+ "filesystem",
589
+ "iterator"
590
+ ],
591
+ "support": {
592
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
593
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0"
594
+ },
595
+ "funding": [
596
+ {
597
+ "url": "https://github.com/sebastianbergmann",
598
+ "type": "github"
599
+ }
600
+ ],
601
+ "time": "2020-11-30T08:25:21+00:00"
602
+ },
603
+ {
604
+ "name": "phpunit/php-text-template",
605
+ "version": "1.2.1",
606
+ "source": {
607
+ "type": "git",
608
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
609
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
610
+ },
611
+ "dist": {
612
+ "type": "zip",
613
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
614
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
615
+ "shasum": ""
616
+ },
617
+ "require": {
618
+ "php": ">=5.3.3"
619
+ },
620
+ "type": "library",
621
+ "autoload": {
622
+ "classmap": [
623
+ "src/"
624
+ ]
625
+ },
626
+ "notification-url": "https://packagist.org/downloads/",
627
+ "license": [
628
+ "BSD-3-Clause"
629
+ ],
630
+ "authors": [
631
+ {
632
+ "name": "Sebastian Bergmann",
633
+ "email": "sebastian@phpunit.de",
634
+ "role": "lead"
635
+ }
636
+ ],
637
+ "description": "Simple template engine.",
638
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
639
+ "keywords": [
640
+ "template"
641
+ ],
642
+ "support": {
643
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
644
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
645
+ },
646
+ "time": "2015-06-21T13:50:34+00:00"
647
+ },
648
+ {
649
+ "name": "phpunit/php-timer",
650
+ "version": "2.1.x-dev",
651
+ "source": {
652
+ "type": "git",
653
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
654
+ "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662"
655
+ },
656
+ "dist": {
657
+ "type": "zip",
658
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662",
659
+ "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662",
660
+ "shasum": ""
661
+ },
662
+ "require": {
663
+ "php": ">=7.1"
664
+ },
665
+ "require-dev": {
666
+ "phpunit/phpunit": "^8.5"
667
+ },
668
+ "type": "library",
669
+ "extra": {
670
+ "branch-alias": {
671
+ "dev-master": "2.1-dev"
672
+ }
673
+ },
674
+ "autoload": {
675
+ "classmap": [
676
+ "src/"
677
+ ]
678
+ },
679
+ "notification-url": "https://packagist.org/downloads/",
680
+ "license": [
681
+ "BSD-3-Clause"
682
+ ],
683
+ "authors": [
684
+ {
685
+ "name": "Sebastian Bergmann",
686
+ "email": "sebastian@phpunit.de",
687
+ "role": "lead"
688
+ }
689
+ ],
690
+ "description": "Utility class for timing",
691
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
692
+ "keywords": [
693
+ "timer"
694
+ ],
695
+ "support": {
696
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
697
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1"
698
+ },
699
+ "funding": [
700
+ {
701
+ "url": "https://github.com/sebastianbergmann",
702
+ "type": "github"
703
+ }
704
+ ],
705
+ "time": "2020-11-30T08:20:02+00:00"
706
+ },
707
+ {
708
+ "name": "phpunit/php-token-stream",
709
+ "version": "3.1.x-dev",
710
+ "source": {
711
+ "type": "git",
712
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
713
+ "reference": "472b687829041c24b25f475e14c2f38a09edf1c2"
714
+ },
715
+ "dist": {
716
+ "type": "zip",
717
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/472b687829041c24b25f475e14c2f38a09edf1c2",
718
+ "reference": "472b687829041c24b25f475e14c2f38a09edf1c2",
719
+ "shasum": ""
720
+ },
721
+ "require": {
722
+ "ext-tokenizer": "*",
723
+ "php": ">=7.1"
724
+ },
725
+ "require-dev": {
726
+ "phpunit/phpunit": "^7.0"
727
+ },
728
+ "type": "library",
729
+ "extra": {
730
+ "branch-alias": {
731
+ "dev-master": "3.1-dev"
732
+ }
733
+ },
734
+ "autoload": {
735
+ "classmap": [
736
+ "src/"
737
+ ]
738
+ },
739
+ "notification-url": "https://packagist.org/downloads/",
740
+ "license": [
741
+ "BSD-3-Clause"
742
+ ],
743
+ "authors": [
744
+ {
745
+ "name": "Sebastian Bergmann",
746
+ "email": "sebastian@phpunit.de"
747
+ }
748
+ ],
749
+ "description": "Wrapper around PHP's tokenizer extension.",
750
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
751
+ "keywords": [
752
+ "tokenizer"
753
+ ],
754
+ "support": {
755
+ "issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
756
+ "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1"
757
+ },
758
+ "funding": [
759
+ {
760
+ "url": "https://github.com/sebastianbergmann",
761
+ "type": "github"
762
+ }
763
+ ],
764
+ "abandoned": true,
765
+ "time": "2020-11-30T08:38:46+00:00"
766
+ },
767
+ {
768
+ "name": "phpunit/phpunit",
769
+ "version": "7.5.20",
770
+ "source": {
771
+ "type": "git",
772
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
773
+ "reference": "9467db479d1b0487c99733bb1e7944d32deded2c"
774
+ },
775
+ "dist": {
776
+ "type": "zip",
777
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c",
778
+ "reference": "9467db479d1b0487c99733bb1e7944d32deded2c",
779
+ "shasum": ""
780
+ },
781
+ "require": {
782
+ "doctrine/instantiator": "^1.1",
783
+ "ext-dom": "*",
784
+ "ext-json": "*",
785
+ "ext-libxml": "*",
786
+ "ext-mbstring": "*",
787
+ "ext-xml": "*",
788
+ "myclabs/deep-copy": "^1.7",
789
+ "phar-io/manifest": "^1.0.2",
790
+ "phar-io/version": "^2.0",
791
+ "php": "^7.1",
792
+ "phpspec/prophecy": "^1.7",
793
+ "phpunit/php-code-coverage": "^6.0.7",
794
+ "phpunit/php-file-iterator": "^2.0.1",
795
+ "phpunit/php-text-template": "^1.2.1",
796
+ "phpunit/php-timer": "^2.1",
797
+ "sebastian/comparator": "^3.0",
798
+ "sebastian/diff": "^3.0",
799
+ "sebastian/environment": "^4.0",
800
+ "sebastian/exporter": "^3.1",
801
+ "sebastian/global-state": "^2.0",
802
+ "sebastian/object-enumerator": "^3.0.3",
803
+ "sebastian/resource-operations": "^2.0",
804
+ "sebastian/version": "^2.0.1"
805
+ },
806
+ "conflict": {
807
+ "phpunit/phpunit-mock-objects": "*"
808
+ },
809
+ "require-dev": {
810
+ "ext-pdo": "*"
811
+ },
812
+ "suggest": {
813
+ "ext-soap": "*",
814
+ "ext-xdebug": "*",
815
+ "phpunit/php-invoker": "^2.0"
816
+ },
817
+ "bin": [
818
+ "phpunit"
819
+ ],
820
+ "type": "library",
821
+ "extra": {
822
+ "branch-alias": {
823
+ "dev-master": "7.5-dev"
824
+ }
825
+ },
826
+ "autoload": {
827
+ "classmap": [
828
+ "src/"
829
+ ]
830
+ },
831
+ "notification-url": "https://packagist.org/downloads/",
832
+ "license": [
833
+ "BSD-3-Clause"
834
+ ],
835
+ "authors": [
836
+ {
837
+ "name": "Sebastian Bergmann",
838
+ "email": "sebastian@phpunit.de",
839
+ "role": "lead"
840
+ }
841
+ ],
842
+ "description": "The PHP Unit Testing framework.",
843
+ "homepage": "https://phpunit.de/",
844
+ "keywords": [
845
+ "phpunit",
846
+ "testing",
847
+ "xunit"
848
+ ],
849
+ "support": {
850
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
851
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/7.5.20"
852
+ },
853
+ "time": "2020-01-08T08:45:45+00:00"
854
+ },
855
+ {
856
+ "name": "sebastian/code-unit-reverse-lookup",
857
+ "version": "1.0.x-dev",
858
+ "source": {
859
+ "type": "git",
860
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
861
+ "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619"
862
+ },
863
+ "dist": {
864
+ "type": "zip",
865
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619",
866
+ "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619",
867
+ "shasum": ""
868
+ },
869
+ "require": {
870
+ "php": ">=5.6"
871
+ },
872
+ "require-dev": {
873
+ "phpunit/phpunit": "^8.5"
874
+ },
875
+ "type": "library",
876
+ "extra": {
877
+ "branch-alias": {
878
+ "dev-master": "1.0.x-dev"
879
+ }
880
+ },
881
+ "autoload": {
882
+ "classmap": [
883
+ "src/"
884
+ ]
885
+ },
886
+ "notification-url": "https://packagist.org/downloads/",
887
+ "license": [
888
+ "BSD-3-Clause"
889
+ ],
890
+ "authors": [
891
+ {
892
+ "name": "Sebastian Bergmann",
893
+ "email": "sebastian@phpunit.de"
894
+ }
895
+ ],
896
+ "description": "Looks up which function or method a line of code belongs to",
897
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
898
+ "support": {
899
+ "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
900
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0"
901
+ },
902
+ "funding": [
903
+ {
904
+ "url": "https://github.com/sebastianbergmann",
905
+ "type": "github"
906
+ }
907
+ ],
908
+ "time": "2020-11-30T08:15:22+00:00"
909
+ },
910
+ {
911
+ "name": "sebastian/comparator",
912
+ "version": "3.0.x-dev",
913
+ "source": {
914
+ "type": "git",
915
+ "url": "https://github.com/sebastianbergmann/comparator.git",
916
+ "reference": "1071dfcef776a57013124ff35e1fc41ccd294758"
917
+ },
918
+ "dist": {
919
+ "type": "zip",
920
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758",
921
+ "reference": "1071dfcef776a57013124ff35e1fc41ccd294758",
922
+ "shasum": ""
923
+ },
924
+ "require": {
925
+ "php": ">=7.1",
926
+ "sebastian/diff": "^3.0",
927
+ "sebastian/exporter": "^3.1"
928
+ },
929
+ "require-dev": {
930
+ "phpunit/phpunit": "^8.5"
931
+ },
932
+ "type": "library",
933
+ "extra": {
934
+ "branch-alias": {
935
+ "dev-master": "3.0-dev"
936
+ }
937
+ },
938
+ "autoload": {
939
+ "classmap": [
940
+ "src/"
941
+ ]
942
+ },
943
+ "notification-url": "https://packagist.org/downloads/",
944
+ "license": [
945
+ "BSD-3-Clause"
946
+ ],
947
+ "authors": [
948
+ {
949
+ "name": "Sebastian Bergmann",
950
+ "email": "sebastian@phpunit.de"
951
+ },
952
+ {
953
+ "name": "Jeff Welch",
954
+ "email": "whatthejeff@gmail.com"
955
+ },
956
+ {
957
+ "name": "Volker Dusch",
958
+ "email": "github@wallbash.com"
959
+ },
960
+ {
961
+ "name": "Bernhard Schussek",
962
+ "email": "bschussek@2bepublished.at"
963
+ }
964
+ ],
965
+ "description": "Provides the functionality to compare PHP values for equality",
966
+ "homepage": "https://github.com/sebastianbergmann/comparator",
967
+ "keywords": [
968
+ "comparator",
969
+ "compare",
970
+ "equality"
971
+ ],
972
+ "support": {
973
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
974
+ "source": "https://github.com/sebastianbergmann/comparator/tree/3.0"
975
+ },
976
+ "funding": [
977
+ {
978
+ "url": "https://github.com/sebastianbergmann",
979
+ "type": "github"
980
+ }
981
+ ],
982
+ "time": "2020-11-30T08:04:30+00:00"
983
+ },
984
+ {
985
+ "name": "sebastian/diff",
986
+ "version": "3.0.x-dev",
987
+ "source": {
988
+ "type": "git",
989
+ "url": "https://github.com/sebastianbergmann/diff.git",
990
+ "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211"
991
+ },
992
+ "dist": {
993
+ "type": "zip",
994
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211",
995
+ "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211",
996
+ "shasum": ""
997
+ },
998
+ "require": {
999
+ "php": ">=7.1"
1000
+ },
1001
+ "require-dev": {
1002
+ "phpunit/phpunit": "^7.5 || ^8.0",
1003
+ "symfony/process": "^2 || ^3.3 || ^4"
1004
+ },
1005
+ "type": "library",
1006
+ "extra": {
1007
+ "branch-alias": {
1008
+ "dev-master": "3.0-dev"
1009
+ }
1010
+ },
1011
+ "autoload": {
1012
+ "classmap": [
1013
+ "src/"
1014
+ ]
1015
+ },
1016
+ "notification-url": "https://packagist.org/downloads/",
1017
+ "license": [
1018
+ "BSD-3-Clause"
1019
+ ],
1020
+ "authors": [
1021
+ {
1022
+ "name": "Sebastian Bergmann",
1023
+ "email": "sebastian@phpunit.de"
1024
+ },
1025
+ {
1026
+ "name": "Kore Nordmann",
1027
+ "email": "mail@kore-nordmann.de"
1028
+ }
1029
+ ],
1030
+ "description": "Diff implementation",
1031
+ "homepage": "https://github.com/sebastianbergmann/diff",
1032
+ "keywords": [
1033
+ "diff",
1034
+ "udiff",
1035
+ "unidiff",
1036
+ "unified diff"
1037
+ ],
1038
+ "support": {
1039
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
1040
+ "source": "https://github.com/sebastianbergmann/diff/tree/3.0"
1041
+ },
1042
+ "funding": [
1043
+ {
1044
+ "url": "https://github.com/sebastianbergmann",
1045
+ "type": "github"
1046
+ }
1047
+ ],
1048
+ "time": "2020-11-30T07:59:04+00:00"
1049
+ },
1050
+ {
1051
+ "name": "sebastian/environment",
1052
+ "version": "4.2.x-dev",
1053
+ "source": {
1054
+ "type": "git",
1055
+ "url": "https://github.com/sebastianbergmann/environment.git",
1056
+ "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0"
1057
+ },
1058
+ "dist": {
1059
+ "type": "zip",
1060
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0",
1061
+ "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0",
1062
+ "shasum": ""
1063
+ },
1064
+ "require": {
1065
+ "php": ">=7.1"
1066
+ },
1067
+ "require-dev": {
1068
+ "phpunit/phpunit": "^7.5"
1069
+ },
1070
+ "suggest": {
1071
+ "ext-posix": "*"
1072
+ },
1073
+ "type": "library",
1074
+ "extra": {
1075
+ "branch-alias": {
1076
+ "dev-master": "4.2-dev"
1077
+ }
1078
+ },
1079
+ "autoload": {
1080
+ "classmap": [
1081
+ "src/"
1082
+ ]
1083
+ },
1084
+ "notification-url": "https://packagist.org/downloads/",
1085
+ "license": [
1086
+ "BSD-3-Clause"
1087
+ ],
1088
+ "authors": [
1089
+ {
1090
+ "name": "Sebastian Bergmann",
1091
+ "email": "sebastian@phpunit.de"
1092
+ }
1093
+ ],
1094
+ "description": "Provides functionality to handle HHVM/PHP environments",
1095
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
1096
+ "keywords": [
1097
+ "Xdebug",
1098
+ "environment",
1099
+ "hhvm"
1100
+ ],
1101
+ "support": {
1102
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
1103
+ "source": "https://github.com/sebastianbergmann/environment/tree/4.2"
1104
+ },
1105
+ "funding": [
1106
+ {
1107
+ "url": "https://github.com/sebastianbergmann",
1108
+ "type": "github"
1109
+ }
1110
+ ],
1111
+ "time": "2020-11-30T07:53:42+00:00"
1112
+ },
1113
+ {
1114
+ "name": "sebastian/exporter",
1115
+ "version": "3.1.x-dev",
1116
+ "source": {
1117
+ "type": "git",
1118
+ "url": "https://github.com/sebastianbergmann/exporter.git",
1119
+ "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e"
1120
+ },
1121
+ "dist": {
1122
+ "type": "zip",
1123
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/6b853149eab67d4da22291d36f5b0631c0fd856e",
1124
+ "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e",
1125
+ "shasum": ""
1126
+ },
1127
+ "require": {
1128
+ "php": ">=7.0",
1129
+ "sebastian/recursion-context": "^3.0"
1130
+ },
1131
+ "require-dev": {
1132
+ "ext-mbstring": "*",
1133
+ "phpunit/phpunit": "^6.0"
1134
+ },
1135
+ "type": "library",
1136
+ "extra": {
1137
+ "branch-alias": {
1138
+ "dev-master": "3.1.x-dev"
1139
+ }
1140
+ },
1141
+ "autoload": {
1142
+ "classmap": [
1143
+ "src/"
1144
+ ]
1145
+ },
1146
+ "notification-url": "https://packagist.org/downloads/",
1147
+ "license": [
1148
+ "BSD-3-Clause"
1149
+ ],
1150
+ "authors": [
1151
+ {
1152
+ "name": "Sebastian Bergmann",
1153
+ "email": "sebastian@phpunit.de"
1154
+ },
1155
+ {
1156
+ "name": "Jeff Welch",
1157
+ "email": "whatthejeff@gmail.com"
1158
+ },
1159
+ {
1160
+ "name": "Volker Dusch",
1161
+ "email": "github@wallbash.com"
1162
+ },
1163
+ {
1164
+ "name": "Adam Harvey",
1165
+ "email": "aharvey@php.net"
1166
+ },
1167
+ {
1168
+ "name": "Bernhard Schussek",
1169
+ "email": "bschussek@gmail.com"
1170
+ }
1171
+ ],
1172
+ "description": "Provides the functionality to export PHP variables for visualization",
1173
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
1174
+ "keywords": [
1175
+ "export",
1176
+ "exporter"
1177
+ ],
1178
+ "support": {
1179
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
1180
+ "source": "https://github.com/sebastianbergmann/exporter/tree/3.1"
1181
+ },
1182
+ "funding": [
1183
+ {
1184
+ "url": "https://github.com/sebastianbergmann",
1185
+ "type": "github"
1186
+ }
1187
+ ],
1188
+ "time": "2020-11-30T07:47:53+00:00"
1189
+ },
1190
+ {
1191
+ "name": "sebastian/global-state",
1192
+ "version": "2.0.0",
1193
+ "source": {
1194
+ "type": "git",
1195
+ "url": "https://github.com/sebastianbergmann/global-state.git",
1196
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
1197
+ },
1198
+ "dist": {
1199
+ "type": "zip",
1200
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
1201
+ "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
1202
+ "shasum": ""
1203
+ },
1204
+ "require": {
1205
+ "php": "^7.0"
1206
+ },
1207
+ "require-dev": {
1208
+ "phpunit/phpunit": "^6.0"
1209
+ },
1210
+ "suggest": {
1211
+ "ext-uopz": "*"
1212
+ },
1213
+ "type": "library",
1214
+ "extra": {
1215
+ "branch-alias": {
1216
+ "dev-master": "2.0-dev"
1217
+ }
1218
+ },
1219
+ "autoload": {
1220
+ "classmap": [
1221
+ "src/"
1222
+ ]
1223
+ },
1224
+ "notification-url": "https://packagist.org/downloads/",
1225
+ "license": [
1226
+ "BSD-3-Clause"
1227
+ ],
1228
+ "authors": [
1229
+ {
1230
+ "name": "Sebastian Bergmann",
1231
+ "email": "sebastian@phpunit.de"
1232
+ }
1233
+ ],
1234
+ "description": "Snapshotting of global state",
1235
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
1236
+ "keywords": [
1237
+ "global state"
1238
+ ],
1239
+ "support": {
1240
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
1241
+ "source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0"
1242
+ },
1243
+ "time": "2017-04-27T15:39:26+00:00"
1244
+ },
1245
+ {
1246
+ "name": "sebastian/object-enumerator",
1247
+ "version": "3.0.x-dev",
1248
+ "source": {
1249
+ "type": "git",
1250
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1251
+ "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2"
1252
+ },
1253
+ "dist": {
1254
+ "type": "zip",
1255
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
1256
+ "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
1257
+ "shasum": ""
1258
+ },
1259
+ "require": {
1260
+ "php": ">=7.0",
1261
+ "sebastian/object-reflector": "^1.1.1",
1262
+ "sebastian/recursion-context": "^3.0"
1263
+ },
1264
+ "require-dev": {
1265
+ "phpunit/phpunit": "^6.0"
1266
+ },
1267
+ "type": "library",
1268
+ "extra": {
1269
+ "branch-alias": {
1270
+ "dev-master": "3.0.x-dev"
1271
+ }
1272
+ },
1273
+ "autoload": {
1274
+ "classmap": [
1275
+ "src/"
1276
+ ]
1277
+ },
1278
+ "notification-url": "https://packagist.org/downloads/",
1279
+ "license": [
1280
+ "BSD-3-Clause"
1281
+ ],
1282
+ "authors": [
1283
+ {
1284
+ "name": "Sebastian Bergmann",
1285
+ "email": "sebastian@phpunit.de"
1286
+ }
1287
+ ],
1288
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1289
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1290
+ "support": {
1291
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
1292
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0"
1293
+ },
1294
+ "funding": [
1295
+ {
1296
+ "url": "https://github.com/sebastianbergmann",
1297
+ "type": "github"
1298
+ }
1299
+ ],
1300
+ "time": "2020-11-30T07:40:27+00:00"
1301
+ },
1302
+ {
1303
+ "name": "sebastian/object-reflector",
1304
+ "version": "1.1.x-dev",
1305
+ "source": {
1306
+ "type": "git",
1307
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
1308
+ "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d"
1309
+ },
1310
+ "dist": {
1311
+ "type": "zip",
1312
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
1313
+ "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
1314
+ "shasum": ""
1315
+ },
1316
+ "require": {
1317
+ "php": ">=7.0"
1318
+ },
1319
+ "require-dev": {
1320
+ "phpunit/phpunit": "^6.0"
1321
+ },
1322
+ "type": "library",
1323
+ "extra": {
1324
+ "branch-alias": {
1325
+ "dev-master": "1.1-dev"
1326
+ }
1327
+ },
1328
+ "autoload": {
1329
+ "classmap": [
1330
+ "src/"
1331
+ ]
1332
+ },
1333
+ "notification-url": "https://packagist.org/downloads/",
1334
+ "license": [
1335
+ "BSD-3-Clause"
1336
+ ],
1337
+ "authors": [
1338
+ {
1339
+ "name": "Sebastian Bergmann",
1340
+ "email": "sebastian@phpunit.de"
1341
+ }
1342
+ ],
1343
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
1344
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1345
+ "support": {
1346
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
1347
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1"
1348
+ },
1349
+ "funding": [
1350
+ {
1351
+ "url": "https://github.com/sebastianbergmann",
1352
+ "type": "github"
1353
+ }
1354
+ ],
1355
+ "time": "2020-11-30T07:37:18+00:00"
1356
+ },
1357
+ {
1358
+ "name": "sebastian/recursion-context",
1359
+ "version": "3.0.x-dev",
1360
+ "source": {
1361
+ "type": "git",
1362
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
1363
+ "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb"
1364
+ },
1365
+ "dist": {
1366
+ "type": "zip",
1367
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb",
1368
+ "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb",
1369
+ "shasum": ""
1370
+ },
1371
+ "require": {
1372
+ "php": ">=7.0"
1373
+ },
1374
+ "require-dev": {
1375
+ "phpunit/phpunit": "^6.0"
1376
+ },
1377
+ "type": "library",
1378
+ "extra": {
1379
+ "branch-alias": {
1380
+ "dev-master": "3.0.x-dev"
1381
+ }
1382
+ },
1383
+ "autoload": {
1384
+ "classmap": [
1385
+ "src/"
1386
+ ]
1387
+ },
1388
+ "notification-url": "https://packagist.org/downloads/",
1389
+ "license": [
1390
+ "BSD-3-Clause"
1391
+ ],
1392
+ "authors": [
1393
+ {
1394
+ "name": "Sebastian Bergmann",
1395
+ "email": "sebastian@phpunit.de"
1396
+ },
1397
+ {
1398
+ "name": "Jeff Welch",
1399
+ "email": "whatthejeff@gmail.com"
1400
+ },
1401
+ {
1402
+ "name": "Adam Harvey",
1403
+ "email": "aharvey@php.net"
1404
+ }
1405
+ ],
1406
+ "description": "Provides functionality to recursively process PHP variables",
1407
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1408
+ "support": {
1409
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
1410
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0"
1411
+ },
1412
+ "funding": [
1413
+ {
1414
+ "url": "https://github.com/sebastianbergmann",
1415
+ "type": "github"
1416
+ }
1417
+ ],
1418
+ "time": "2020-11-30T07:34:24+00:00"
1419
+ },
1420
+ {
1421
+ "name": "sebastian/resource-operations",
1422
+ "version": "2.0.x-dev",
1423
+ "source": {
1424
+ "type": "git",
1425
+ "url": "https://github.com/sebastianbergmann/resource-operations.git",
1426
+ "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3"
1427
+ },
1428
+ "dist": {
1429
+ "type": "zip",
1430
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3",
1431
+ "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3",
1432
+ "shasum": ""
1433
+ },
1434
+ "require": {
1435
+ "php": ">=7.1"
1436
+ },
1437
+ "type": "library",
1438
+ "extra": {
1439
+ "branch-alias": {
1440
+ "dev-master": "2.0-dev"
1441
+ }
1442
+ },
1443
+ "autoload": {
1444
+ "classmap": [
1445
+ "src/"
1446
+ ]
1447
+ },
1448
+ "notification-url": "https://packagist.org/downloads/",
1449
+ "license": [
1450
+ "BSD-3-Clause"
1451
+ ],
1452
+ "authors": [
1453
+ {
1454
+ "name": "Sebastian Bergmann",
1455
+ "email": "sebastian@phpunit.de"
1456
+ }
1457
+ ],
1458
+ "description": "Provides a list of PHP built-in functions that operate on resources",
1459
+ "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
1460
+ "support": {
1461
+ "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
1462
+ "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0"
1463
+ },
1464
+ "funding": [
1465
+ {
1466
+ "url": "https://github.com/sebastianbergmann",
1467
+ "type": "github"
1468
+ }
1469
+ ],
1470
+ "time": "2020-11-30T07:30:19+00:00"
1471
+ },
1472
+ {
1473
+ "name": "sebastian/version",
1474
+ "version": "2.0.1",
1475
+ "source": {
1476
+ "type": "git",
1477
+ "url": "https://github.com/sebastianbergmann/version.git",
1478
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
1479
+ },
1480
+ "dist": {
1481
+ "type": "zip",
1482
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
1483
+ "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
1484
+ "shasum": ""
1485
+ },
1486
+ "require": {
1487
+ "php": ">=5.6"
1488
+ },
1489
+ "type": "library",
1490
+ "extra": {
1491
+ "branch-alias": {
1492
+ "dev-master": "2.0.x-dev"
1493
+ }
1494
+ },
1495
+ "autoload": {
1496
+ "classmap": [
1497
+ "src/"
1498
+ ]
1499
+ },
1500
+ "notification-url": "https://packagist.org/downloads/",
1501
+ "license": [
1502
+ "BSD-3-Clause"
1503
+ ],
1504
+ "authors": [
1505
+ {
1506
+ "name": "Sebastian Bergmann",
1507
+ "email": "sebastian@phpunit.de",
1508
+ "role": "lead"
1509
+ }
1510
+ ],
1511
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1512
+ "homepage": "https://github.com/sebastianbergmann/version",
1513
+ "support": {
1514
+ "issues": "https://github.com/sebastianbergmann/version/issues",
1515
+ "source": "https://github.com/sebastianbergmann/version/tree/master"
1516
+ },
1517
+ "time": "2016-10-03T07:35:21+00:00"
1518
+ },
1519
  {
1520
  "name": "squizlabs/php_codesniffer",
1521
  "version": "dev-master",
1566
  "standards"
1567
  ],
1568
  "time": "2020-05-21T06:41:29+00:00"
1569
+ },
1570
+ {
1571
+ "name": "symfony/polyfill-ctype",
1572
+ "version": "dev-main",
1573
+ "source": {
1574
+ "type": "git",
1575
+ "url": "https://github.com/symfony/polyfill-ctype.git",
1576
+ "reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
1577
+ },
1578
+ "dist": {
1579
+ "type": "zip",
1580
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
1581
+ "reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
1582
+ "shasum": ""
1583
+ },
1584
+ "require": {
1585
+ "php": ">=7.1"
1586
+ },
1587
+ "suggest": {
1588
+ "ext-ctype": "For best performance"
1589
+ },
1590
+ "default-branch": true,
1591
+ "type": "library",
1592
+ "extra": {
1593
+ "branch-alias": {
1594
+ "dev-main": "1.22-dev"
1595
+ },
1596
+ "thanks": {
1597
+ "name": "symfony/polyfill",
1598
+ "url": "https://github.com/symfony/polyfill"
1599
+ }
1600
+ },
1601
+ "autoload": {
1602
+ "psr-4": {
1603
+ "Symfony\\Polyfill\\Ctype\\": ""
1604
+ },
1605
+ "files": [
1606
+ "bootstrap.php"
1607
+ ]
1608
+ },
1609
+ "notification-url": "https://packagist.org/downloads/",
1610
+ "license": [
1611
+ "MIT"
1612
+ ],
1613
+ "authors": [
1614
+ {
1615
+ "name": "Gert de Pagter",
1616
+ "email": "BackEndTea@gmail.com"
1617
+ },
1618
+ {
1619
+ "name": "Symfony Community",
1620
+ "homepage": "https://symfony.com/contributors"
1621
+ }
1622
+ ],
1623
+ "description": "Symfony polyfill for ctype functions",
1624
+ "homepage": "https://symfony.com",
1625
+ "keywords": [
1626
+ "compatibility",
1627
+ "ctype",
1628
+ "polyfill",
1629
+ "portable"
1630
+ ],
1631
+ "support": {
1632
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.0"
1633
+ },
1634
+ "funding": [
1635
+ {
1636
+ "url": "https://symfony.com/sponsor",
1637
+ "type": "custom"
1638
+ },
1639
+ {
1640
+ "url": "https://github.com/fabpot",
1641
+ "type": "github"
1642
+ },
1643
+ {
1644
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1645
+ "type": "tidelift"
1646
+ }
1647
+ ],
1648
+ "time": "2021-01-07T16:49:33+00:00"
1649
+ },
1650
+ {
1651
+ "name": "theseer/tokenizer",
1652
+ "version": "1.2.0",
1653
+ "source": {
1654
+ "type": "git",
1655
+ "url": "https://github.com/theseer/tokenizer.git",
1656
+ "reference": "75a63c33a8577608444246075ea0af0d052e452a"
1657
+ },
1658
+ "dist": {
1659
+ "type": "zip",
1660
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a",
1661
+ "reference": "75a63c33a8577608444246075ea0af0d052e452a",
1662
+ "shasum": ""
1663
+ },
1664
+ "require": {
1665
+ "ext-dom": "*",
1666
+ "ext-tokenizer": "*",
1667
+ "ext-xmlwriter": "*",
1668
+ "php": "^7.2 || ^8.0"
1669
+ },
1670
+ "type": "library",
1671
+ "autoload": {
1672
+ "classmap": [
1673
+ "src/"
1674
+ ]
1675
+ },
1676
+ "notification-url": "https://packagist.org/downloads/",
1677
+ "license": [
1678
+ "BSD-3-Clause"
1679
+ ],
1680
+ "authors": [
1681
+ {
1682
+ "name": "Arne Blankerts",
1683
+ "email": "arne@blankerts.de",
1684
+ "role": "Developer"
1685
+ }
1686
+ ],
1687
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
1688
+ "support": {
1689
+ "issues": "https://github.com/theseer/tokenizer/issues",
1690
+ "source": "https://github.com/theseer/tokenizer/tree/master"
1691
+ },
1692
+ "funding": [
1693
+ {
1694
+ "url": "https://github.com/theseer",
1695
+ "type": "github"
1696
+ }
1697
+ ],
1698
+ "time": "2020-07-12T23:59:07+00:00"
1699
+ },
1700
+ {
1701
+ "name": "webmozart/assert",
1702
+ "version": "dev-master",
1703
+ "source": {
1704
+ "type": "git",
1705
+ "url": "https://github.com/webmozarts/assert.git",
1706
+ "reference": "9c89b265ccc4092d58e66d72af5d343ee77a41ae"
1707
+ },
1708
+ "dist": {
1709
+ "type": "zip",
1710
+ "url": "https://api.github.com/repos/webmozarts/assert/zipball/9c89b265ccc4092d58e66d72af5d343ee77a41ae",
1711
+ "reference": "9c89b265ccc4092d58e66d72af5d343ee77a41ae",
1712
+ "shasum": ""
1713
+ },
1714
+ "require": {
1715
+ "php": "^7.2 || ^8.0",
1716
+ "symfony/polyfill-ctype": "^1.8"
1717
+ },
1718
+ "conflict": {
1719
+ "phpstan/phpstan": "<0.12.20",
1720
+ "vimeo/psalm": "<3.9.1"
1721
+ },
1722
+ "require-dev": {
1723
+ "phpunit/phpunit": "^8.5.13"
1724
+ },
1725
+ "default-branch": true,
1726
+ "type": "library",
1727
+ "extra": {
1728
+ "branch-alias": {
1729
+ "dev-master": "1.10-dev"
1730
+ }
1731
+ },
1732
+ "autoload": {
1733
+ "psr-4": {
1734
+ "Webmozart\\Assert\\": "src/"
1735
+ }
1736
+ },
1737
+ "notification-url": "https://packagist.org/downloads/",
1738
+ "license": [
1739
+ "MIT"
1740
+ ],
1741
+ "authors": [
1742
+ {
1743
+ "name": "Bernhard Schussek",
1744
+ "email": "bschussek@gmail.com"
1745
+ }
1746
+ ],
1747
+ "description": "Assertions to validate method input/output with nice error messages.",
1748
+ "keywords": [
1749
+ "assert",
1750
+ "check",
1751
+ "validate"
1752
+ ],
1753
+ "support": {
1754
+ "issues": "https://github.com/webmozarts/assert/issues",
1755
+ "source": "https://github.com/webmozarts/assert/tree/master"
1756
+ },
1757
+ "time": "2021-01-18T12:52:36+00:00"
1758
  }
1759
  ],
1760
  "aliases": [],
1766
  "php": ">=5.2.0"
1767
  },
1768
  "platform-dev": [],
1769
+ "plugin-api-version": "2.0.0"
1770
  }
dropins/SimpleHistoryIpInfoDropin.css CHANGED
@@ -1,11 +1,3 @@
1
- .SimpleHistoryLogitem__anonUserWithIp {
2
- }
3
-
4
- .SimpleHistoryLogitem__anonUserWithIp__theIp:hover {
5
- /* cursor: pointer;
6
- text-decoration: underline;*/
7
- }
8
-
9
  .SimpleHistoryIpInfoDropin__popup {
10
  position: absolute;
11
  visibility: hidden;
@@ -36,15 +28,6 @@
36
  transition: visibility 0, opacity 0.25s 0s;
37
  }
38
 
39
- .SimpleHistoryIpInfoDropin__popupArrow {
40
- /*width: 40px;
41
- height: 40px;
42
- font-size: 40px;
43
- position: absolute;
44
- top: -25px;
45
- left: 0;*/
46
- }
47
-
48
  .SimpleHistoryIpInfoDropin__popupArrow {
49
  position: absolute;
50
  background: #fff;
@@ -83,9 +66,6 @@
83
  border-collapse: collapse;
84
  }
85
 
86
- .SimpleHistoryIpInfoDropin__ipInfoTable tr {
87
- }
88
-
89
  .SimpleHistoryIpInfoDropin__ipInfoTable th,
90
  .SimpleHistoryIpInfoDropin__ipInfoTable td {
91
  vertical-align: top;
 
 
 
 
 
 
 
 
1
  .SimpleHistoryIpInfoDropin__popup {
2
  position: absolute;
3
  visibility: hidden;
28
  transition: visibility 0, opacity 0.25s 0s;
29
  }
30
 
 
 
 
 
 
 
 
 
 
31
  .SimpleHistoryIpInfoDropin__popupArrow {
32
  position: absolute;
33
  background: #fff;
66
  border-collapse: collapse;
67
  }
68
 
 
 
 
69
  .SimpleHistoryIpInfoDropin__ipInfoTable th,
70
  .SimpleHistoryIpInfoDropin__ipInfoTable td {
71
  vertical-align: top;
dropins/SimpleHistoryIpInfoDropin.js CHANGED
@@ -1,132 +1,115 @@
1
-
2
- (function($) {
3
-
4
- var $logItems = $(".SimpleHistoryLogitems");
5
- var $popup = $(".SimpleHistoryIpInfoDropin__popup");
6
- var $popupContent = $popup.find(".SimpleHistoryIpInfoDropin__popupContent");
7
-
8
- var templateLoading = wp.template("simple-history-ipinfodropin-popup-loading");
9
- var templateLoaded = wp.template("simple-history-ipinfodropin-popup-loaded");
10
-
11
- // Click on link with IP-number
12
- $logItems.on("click", ".SimpleHistoryLogitem__anonUserWithIp__theIp", function(e) {
13
-
14
- var $elm = $(this);
15
- var ipAddress = $elm.closest(".SimpleHistoryLogitem").data("ipAddress");
16
-
17
- if (! ipAddress) {
18
- return;
19
- }
20
-
21
- // since 24 sept 2016 ipinfo supports ssl/https for all users, so we can enable ipinfo for all
22
- // https://twitter.com/ipinfoio/status/779374440417103872
23
- showPopup($elm);
24
-
25
- return lookupIpAddress(ipAddress);
26
-
27
-
28
- /*
29
- // If we are on a HTTPS site we cant use ipinfo because lookups over https require pro account
30
- // Fallback to plain link
31
- var isHTTPS = document.location.protocol == "https:";
32
-
33
- if (isHTTPS) {
34
-
35
- return true;
36
-
37
- } else {
38
-
39
- showPopup($elm);
40
-
41
- return lookupIpAddress(ipAddress);
42
- }
43
- */
44
-
45
- });
46
-
47
- // Close popup
48
- $popup.on("click", ".SimpleHistoryIpInfoDropin__popupCloseButton", hidePopup);
49
- $(window).on("click", maybeHidePopup);
50
- $(window).on("keyup", maybeHidePopup);
51
- $(document).on("SimpleHistory:logReloadStart", hidePopup);
52
-
53
- // Position and then show popup.
54
- // Content is not added yet
55
- function showPopup($elm) {
56
-
57
- var offset = $elm.offset();
58
-
59
- $popup.css({
60
- //top: offset.top + $elm.outerHeight(),
61
- top: offset.top,
62
- left: offset.left
63
- });
64
-
65
- $popupContent.html(templateLoading());
66
-
67
- $popup.addClass("is-visible");
68
-
69
- }
70
-
71
- function hidePopup(e) {
72
-
73
- $popup.removeClass("is-visible");
74
-
75
- }
76
-
77
- function maybeHidePopup(e) {
78
-
79
- // Make sure variable and properties exist before trying to work on them
80
- if (!e || !e.target) {
81
- return;
82
- }
83
-
84
- var $target = (e.target);
85
-
86
- // Don't hide if click inside popup
87
- if ($.contains($popup.get(0), $target) ) {
88
- return true;
89
- }
90
-
91
- // If initiated by keyboard but not esc, then don't close
92
- if (e.originalEvent && e.originalEvent.type == "keyup" && e.originalEvent.keyCode && e.originalEvent.keyCode != 27) {
93
- return;
94
- }
95
-
96
- // Else it should be ok to hide
97
- hidePopup();
98
-
99
- }
100
-
101
- // Init request to lookup address
102
- function lookupIpAddress(ipAddress) {
103
-
104
- //try {
105
-
106
- var ajax = $.get("https://ipinfo.io/" + ipAddress, onIpAddressLookupResponse, "jsonp");
107
-
108
- // If the ajax call fail, for example because of blocked connections using adblocker-similar software
109
- // err_blocked_by_client
110
- // ajax.fail(onIpAddressLookupResponseError);
111
- // I don't manage to get this to work, I can't find any way to detect err_blocked_by_client
112
-
113
- return false;
114
- //}
115
-
116
- //catch (error) {
117
- // console.log("error", error);
118
- //}
119
-
120
- }
121
-
122
- // Function called when ip adress lookup succeeded
123
- function onIpAddressLookupResponse(d) {
124
-
125
- $popupContent.html(templateLoaded(d));
126
-
127
- }
128
-
129
- /*
130
  function onIpAddressLookupResponseError(d) {
131
 
132
  console.log("onIpAddressLookupResponseError", d);
@@ -134,5 +117,4 @@
134
 
135
  }
136
  */
137
-
138
  })(jQuery);
1
+ (function ($) {
2
+ var $logItems = $(".SimpleHistoryLogitems");
3
+ var $popup = $(".SimpleHistoryIpInfoDropin__popup");
4
+ var $popupContent = $popup.find(".SimpleHistoryIpInfoDropin__popupContent");
5
+
6
+ var templateLoading = wp.template(
7
+ "simple-history-ipinfodropin-popup-loading"
8
+ );
9
+ var templateLoaded = wp.template("simple-history-ipinfodropin-popup-loaded");
10
+ var templateError = wp.template("simple-history-ipinfodropin-popup-error");
11
+
12
+ // Click on link with IP-number
13
+ $logItems.on(
14
+ "click",
15
+ ".SimpleHistoryLogitem__anonUserWithIp__theIp",
16
+ function (e) {
17
+ var $elm = $(this);
18
+ var ipAddress = $elm.closest(".SimpleHistoryLogitem").data("ipAddress");
19
+
20
+ if (!ipAddress) {
21
+ return;
22
+ }
23
+
24
+ // since 24 sept 2016 ipinfo supports ssl/https for all users, so we can enable ipinfo for all
25
+ // https://twitter.com/ipinfoio/status/779374440417103872
26
+ showPopup($elm);
27
+
28
+ return lookupIpAddress(ipAddress);
29
+ }
30
+ );
31
+
32
+ // Close popup
33
+ $popup.on("click", ".SimpleHistoryIpInfoDropin__popupCloseButton", hidePopup);
34
+ $(window).on("click", maybeHidePopup);
35
+ $(window).on("keyup", maybeHidePopup);
36
+ $(document).on("SimpleHistory:logReloadStart", hidePopup);
37
+
38
+ // Position and then show popup.
39
+ // Content is not added yet
40
+ function showPopup($elm) {
41
+ var offset = $elm.offset();
42
+
43
+ $popup.css({
44
+ //top: offset.top + $elm.outerHeight(),
45
+ top: offset.top,
46
+ left: offset.left,
47
+ });
48
+
49
+ $popupContent.html(templateLoading());
50
+
51
+ $popup.addClass("is-visible");
52
+ }
53
+
54
+ function hidePopup(e) {
55
+ $popup.removeClass("is-visible");
56
+ }
57
+
58
+ function maybeHidePopup(e) {
59
+ // Make sure variable and properties exist before trying to work on them
60
+ if (!e || !e.target) {
61
+ return;
62
+ }
63
+
64
+ var $target = e.target;
65
+
66
+ // Don't hide if click inside popup
67
+ if ($.contains($popup.get(0), $target)) {
68
+ return true;
69
+ }
70
+
71
+ // If initiated by keyboard but not esc, then don't close
72
+ if (
73
+ e.originalEvent &&
74
+ e.originalEvent.type == "keyup" &&
75
+ e.originalEvent.keyCode &&
76
+ e.originalEvent.keyCode != 27
77
+ ) {
78
+ return;
79
+ }
80
+
81
+ // Else it should be ok to hide
82
+ hidePopup();
83
+ }
84
+
85
+ // Init request to lookup address
86
+ function lookupIpAddress(ipAddress) {
87
+ var ajax = $.get(
88
+ "https://ipinfo.io/" + ipAddress,
89
+ onIpAddressLookupResponse,
90
+ "jsonp"
91
+ ).fail(function (jqXHR, textStatus, errorThrown) {
92
+ // Some error occured, for example "net::ERR_BLOCKED_BY_CLIENT"
93
+ // when ad blocker uBlock blocks
94
+ // ipinfo.io using EasyPrivacy filter
95
+ console.log("fail", jqXHR, textStatus, errorThrown);
96
+ onIpAddressLookupResponseFail();
97
+ });
98
+
99
+ return false;
100
+ }
101
+
102
+ // Function called when ip adress lookup succeeded.
103
+ function onIpAddressLookupResponse(d) {
104
+ $popupContent.html(templateLoaded(d));
105
+ }
106
+
107
+ // Function called when ip adress lookup failed.
108
+ function onIpAddressLookupResponseFail(d) {
109
+ $popupContent.html(templateError(d));
110
+ }
111
+
112
+ /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  function onIpAddressLookupResponseError(d) {
114
 
115
  console.log("onIpAddressLookupResponseError", d);
117
 
118
  }
119
  */
 
120
  })(jQuery);
dropins/SimpleHistoryIpInfoDropin.php CHANGED
@@ -20,6 +20,43 @@ class SimpleHistoryIpInfoDropin
20
 
21
  add_action('simple_history/enqueue_admin_scripts', array( $this, 'enqueue_admin_scripts' ));
22
  add_action('simple_history/admin_footer', array( $this, 'add_js_template' ));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
 
25
  public function enqueue_admin_scripts()
@@ -43,7 +80,11 @@ class SimpleHistoryIpInfoDropin
43
  </div>
44
 
45
  <script type="text/html" id="tmpl-simple-history-ipinfodropin-popup-loading">
46
- <!-- <p>Getting IP info ...</p> -->
 
 
 
 
47
  </script>
48
 
49
  <script type="text/html" id="tmpl-simple-history-ipinfodropin-popup-loaded">
20
 
21
  add_action('simple_history/enqueue_admin_scripts', array( $this, 'enqueue_admin_scripts' ));
22
  add_action('simple_history/admin_footer', array( $this, 'add_js_template' ));
23
+
24
+ add_filter(
25
+ 'simple_history/row_header_output/display_ip_address',
26
+ [ $this, 'row_header_display_ip_address_filter'],
27
+ 10,
28
+ 2
29
+ );
30
+ }
31
+
32
+ /**
33
+ * Display IP Addressses for login related messages.
34
+ *
35
+ * @param bool $bool
36
+ * @param object $row
37
+ * @return bool
38
+ */
39
+ public function row_header_display_ip_address_filter($bool, $row)
40
+ {
41
+ // Bail if log row in not from our logger.
42
+ if ('SimpleUserLogger' !== $row->logger) {
43
+ return $bool;
44
+ }
45
+
46
+ // Message keys to show IP Addresses for.
47
+ $arr_keys_to_log = [
48
+ 'user_logged_in',
49
+ 'user_login_failed',
50
+ 'user_unknown_login_failed',
51
+ 'user_unknown_logged_in',
52
+ ];
53
+
54
+ // Bail if not correct message key.
55
+ if (!in_array($row->context_message_key, $arr_keys_to_log)) {
56
+ return $bool;
57
+ }
58
+
59
+ return true;
60
  }
61
 
62
  public function enqueue_admin_scripts()
80
  </div>
81
 
82
  <script type="text/html" id="tmpl-simple-history-ipinfodropin-popup-loading">
83
+ <p><?php _ex('Getting IP info ...', 'IP Info Dropin', 'simple-history'); ?></p>
84
+ </script>
85
+
86
+ <script type="text/html" id="tmpl-simple-history-ipinfodropin-popup-error">
87
+ <p><?php _ex('Could not get info about IP address.', 'IP Info Dropin', 'simple-history'); ?></p>
88
  </script>
89
 
90
  <script type="text/html" id="tmpl-simple-history-ipinfodropin-popup-loaded">
inc/SimpleHistory.php CHANGED
@@ -2272,12 +2272,13 @@ Because Simple History was only recently installed, this feed does not display m
2272
  }
2273
 
2274
  /**
2275
- * Return header output for a log row
 
2276
  * Uses the getLogRowHeaderOutput of the logger that logged the row
2277
- * with fallback to SimpleLogger if logger is not available
2278
  *
2279
  * Loggers are discouraged to override this in the loggers,
2280
- * because the output should be the same for all items in the gui
2281
  *
2282
  * @param object $row
2283
  * @return string
@@ -2361,7 +2362,8 @@ Because Simple History was only recently installed, this feed does not display m
2361
  }
2362
 
2363
  /**
2364
- * Returns the HTML output for a log row, to be used in the GUI/Activity Feed
 
2365
  *
2366
  * @param object $oneLogRow SimpleHistoryLogQuery array with data from SimpleHistoryLogQuery
2367
  * @return string
@@ -2369,7 +2371,7 @@ Because Simple History was only recently installed, this feed does not display m
2369
  public function getLogRowHTMLOutput($oneLogRow, $args)
2370
  {
2371
  $defaults = [
2372
- 'type' => 'overview', // or "single" to include more stuff
2373
  ];
2374
 
2375
  $args = wp_parse_args($args, $defaults);
@@ -2409,12 +2411,13 @@ Because Simple History was only recently installed, this feed does not display m
2409
  $occasions_html .= '</div>';
2410
  }
2411
 
2412
- // Add data atributes to log row, so plugins can do stuff
2413
  $data_attrs = '';
2414
  $data_attrs .= sprintf(' data-row-id="%1$d" ', $oneLogRow->id);
2415
  $data_attrs .= sprintf(' data-occasions-count="%1$d" ', $occasions_count);
2416
  $data_attrs .= sprintf(' data-occasions-id="%1$s" ', esc_attr($oneLogRow->occasionsID));
2417
 
 
2418
  if (isset($oneLogRow->context['_server_remote_addr'])) {
2419
  $data_attrs .= sprintf(' data-ip-address="%1$s" ', esc_attr($oneLogRow->context['_server_remote_addr']));
2420
  }
@@ -2422,10 +2425,12 @@ Because Simple History was only recently installed, this feed does not display m
2422
  $arr_found_additional_ip_headers = $this->instantiatedLoggers['SimpleLogger'][
2423
  'instance'
2424
  ]->get_event_ip_number_headers($oneLogRow);
 
2425
  if ($arr_found_additional_ip_headers) {
2426
  $data_attrs .= sprintf(' data-ip-address-multiple="1" ');
2427
  }
2428
 
 
2429
  $data_attrs .= sprintf(' data-logger="%1$s" ', esc_attr($oneLogRow->logger));
2430
  $data_attrs .= sprintf(' data-level="%1$s" ', esc_attr($oneLogRow->level));
2431
  $data_attrs .= sprintf(' data-date="%1$s" ', esc_attr($oneLogRow->date));
@@ -2435,7 +2440,8 @@ Because Simple History was only recently installed, this feed does not display m
2435
  $data_attrs .= sprintf(' data-initiator-user-id="%1$d" ', $oneLogRow->context['_user_id']);
2436
  }
2437
 
2438
- // If type is single then include more details
 
2439
  $more_details_html = '';
2440
  if ($args['type'] == 'single') {
2441
  $more_details_html = apply_filters(
2272
  }
2273
 
2274
  /**
2275
+ * Return header output for a log row.
2276
+ *
2277
  * Uses the getLogRowHeaderOutput of the logger that logged the row
2278
+ * with fallback to SimpleLogger if logger is not available.
2279
  *
2280
  * Loggers are discouraged to override this in the loggers,
2281
+ * because the output should be the same for all items in the GUI.
2282
  *
2283
  * @param object $row
2284
  * @return string
2362
  }
2363
 
2364
  /**
2365
+ * Returns the HTML output for a log row, to be used in the GUI/Activity Feed.
2366
+ * This includes HTML for the header, the sender image, and the details.
2367
  *
2368
  * @param object $oneLogRow SimpleHistoryLogQuery array with data from SimpleHistoryLogQuery
2369
  * @return string
2371
  public function getLogRowHTMLOutput($oneLogRow, $args)
2372
  {
2373
  $defaults = [
2374
+ 'type' => 'overview', // or "single" to include more stuff (used in for example modal details window)
2375
  ];
2376
 
2377
  $args = wp_parse_args($args, $defaults);
2411
  $occasions_html .= '</div>';
2412
  }
2413
 
2414
+ // Add data attributes to log row, so plugins can do stuff.
2415
  $data_attrs = '';
2416
  $data_attrs .= sprintf(' data-row-id="%1$d" ', $oneLogRow->id);
2417
  $data_attrs .= sprintf(' data-occasions-count="%1$d" ', $occasions_count);
2418
  $data_attrs .= sprintf(' data-occasions-id="%1$s" ', esc_attr($oneLogRow->occasionsID));
2419
 
2420
+ // Add data attributes for remote address and other ip number headers.
2421
  if (isset($oneLogRow->context['_server_remote_addr'])) {
2422
  $data_attrs .= sprintf(' data-ip-address="%1$s" ', esc_attr($oneLogRow->context['_server_remote_addr']));
2423
  }
2425
  $arr_found_additional_ip_headers = $this->instantiatedLoggers['SimpleLogger'][
2426
  'instance'
2427
  ]->get_event_ip_number_headers($oneLogRow);
2428
+
2429
  if ($arr_found_additional_ip_headers) {
2430
  $data_attrs .= sprintf(' data-ip-address-multiple="1" ');
2431
  }
2432
 
2433
+ // Add data attributes info for common things like logger, level, data, initiation.
2434
  $data_attrs .= sprintf(' data-logger="%1$s" ', esc_attr($oneLogRow->logger));
2435
  $data_attrs .= sprintf(' data-level="%1$s" ', esc_attr($oneLogRow->level));
2436
  $data_attrs .= sprintf(' data-date="%1$s" ', esc_attr($oneLogRow->date));
2440
  $data_attrs .= sprintf(' data-initiator-user-id="%1$d" ', $oneLogRow->context['_user_id']);
2441
  }
2442
 
2443
+ // If type is single then include more details.
2444
+ // This is typically shown in the modal window when clickin the event date and time.
2445
  $more_details_html = '';
2446
  if ($args['type'] == 'single') {
2447
  $more_details_html = apply_filters(
index.php CHANGED
@@ -6,7 +6,7 @@
6
  * Text Domain: simple-history
7
  * Domain Path: /languages
8
  * Description: Plugin that logs various things that occur in WordPress and then presents those events in a very nice GUI.
9
- * Version: 2.39.0
10
  * Author: Pär Thernström
11
  * Author URI: http://simple-history.com/
12
  * License: GPL2
@@ -45,7 +45,7 @@ if ($ok_php_version && $ok_wp_version) {
45
  * @TODO: make activation multi site aware, as in https://github.com/scribu/wp-proper-network-activation
46
  * register_activation_hook( trailingslashit(WP_PLUGIN_DIR) . trailingslashit( plugin_basename(__DIR__) ) . "index.php" , array("SimpleHistory", "on_plugin_activate" ) );
47
  */
48
- define('SIMPLE_HISTORY_VERSION', '2.39.0');
49
  define('SIMPLE_HISTORY_PATH', plugin_dir_path(__FILE__));
50
  define('SIMPLE_HISTORY_BASENAME', plugin_basename(__FILE__));
51
  define('SIMPLE_HISTORY_DIR_URL', plugin_dir_url(__FILE__));
6
  * Text Domain: simple-history
7
  * Domain Path: /languages
8
  * Description: Plugin that logs various things that occur in WordPress and then presents those events in a very nice GUI.
9
+ * Version: 2.40.0
10
  * Author: Pär Thernström
11
  * Author URI: http://simple-history.com/
12
  * License: GPL2
45
  * @TODO: make activation multi site aware, as in https://github.com/scribu/wp-proper-network-activation
46
  * register_activation_hook( trailingslashit(WP_PLUGIN_DIR) . trailingslashit( plugin_basename(__DIR__) ) . "index.php" , array("SimpleHistory", "on_plugin_activate" ) );
47
  */
48
+ define('SIMPLE_HISTORY_VERSION', '2.40.0');
49
  define('SIMPLE_HISTORY_PATH', plugin_dir_path(__FILE__));
50
  define('SIMPLE_HISTORY_BASENAME', plugin_basename(__FILE__));
51
  define('SIMPLE_HISTORY_DIR_URL', plugin_dir_url(__FILE__));
loggers/SimpleLogger.php CHANGED
@@ -184,34 +184,16 @@ class SimpleLogger
184
  }
185
 
186
  // Interpolate replacement values into the message and return
187
- /*
188
- if ( ! is_string( $message )) {
189
- echo "message:";
190
- var_dump($message);exit;
191
- }
192
- //*/
193
- /*
194
- if ( ! is_string( $replace )) {
195
- echo "replace: \n";
196
- var_dump($replace);
197
- }
198
- // */
199
-
200
  return strtr($message, $replace);
201
  }
202
 
203
  /**
204
- * Returns header output for a log row
205
- * Format should be common for all log rows and should be like:
206
- * Username (user role) · Date
207
- *
208
  * @return string HTML
209
  */
210
- public function getLogRowHeaderOutput($row)
211
  {
212
- // HTML for initiator
213
  $initiator_html = '';
214
-
215
  $initiator = $row->initiator;
216
  $context = $row->context;
217
 
@@ -239,7 +221,6 @@ class SimpleLogger
239
 
240
  // get user role, as done in user-edit.php
241
  $wp_roles = $GLOBALS['wp_roles'];
242
- $all_roles = (array) $wp_roles->roles;
243
  $user_roles = array_intersect(
244
  array_values((array) $user->roles),
245
  array_keys((array) $wp_roles->roles)
@@ -249,12 +230,12 @@ class SimpleLogger
249
  $user_display_name = $user->display_name;
250
 
251
  /*
252
- * If user who logged this is the currently logged in user
253
- * skip name and email and use just "You"
254
- *
255
- * @param bool If you should be used
256
- * @since 2.1
257
- */
258
  $use_you = apply_filters(
259
  'simple_history/header_initiator_use_you',
260
  true
@@ -262,17 +243,17 @@ class SimpleLogger
262
 
263
  if ($use_you && $is_current_user) {
264
  $tmpl_initiator_html = '
265
- <a href="%6$s" class="SimpleHistoryLogitem__headerUserProfileLink">
266
- <strong class="SimpleHistoryLogitem__inlineDivided">%5$s</strong>
267
- </a>
268
- ';
269
  } else {
270
  $tmpl_initiator_html = '
271
- <a href="%6$s" class="SimpleHistoryLogitem__headerUserProfileLink">
272
- <strong class="SimpleHistoryLogitem__inlineDivided">%3$s</strong>
273
- <span class="SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__headerEmail">%2$s</span>
274
- </a>
275
- ';
276
  }
277
 
278
  /**
@@ -325,66 +306,21 @@ class SimpleLogger
325
  case 'web_user':
326
  /*
327
  Note: server_remote_addr may not show visiting/attacking ip, if server is behind...stuff..
328
- Can be behind varnish cashe, or browser can for example use compression in chrome mobile
329
  then the real ip is behind _server_http_x_forwarded_for_0 or similar
330
  _server_remote_addr 66.249.81.222
331
  _server_http_x_forwarded_for_0 5.35.187.212
332
  */
333
 
334
- // Check if additional IP addresses are stored, from http_x_forwarded_for and so on
335
  $arr_found_additional_ip_headers = $this->get_event_ip_number_headers(
336
  $row
337
  );
338
 
339
- if (empty($context['_server_remote_addr'])) {
340
- $initiator_html .=
341
- "<strong class='SimpleHistoryLogitem__inlineDivided'>" .
342
- __('Anonymous web user', 'simple-history') .
343
- '</strong> ';
344
- } else {
345
- $initiator_html .=
346
- "<strong class='SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__anonUserWithIp'>";
347
-
348
- // if ( sizeof( $arr_found_additional_ip_headers ) ) {
349
- // $iplookup_link = sprintf('https://ipinfo.io/%1$s', esc_attr($context["_server_remote_addr"]));
350
- // $ip_numbers_joined = wp_sprintf_l('%l', array("_server_remote_addr" => $context["_server_remote_addr"]) + $arr_found_additional_ip_headers);
351
- /*
352
- $initiator_html .= sprintf(
353
- __('Anonymous user with multiple IP addresses detected: %1$s', "simple-history"),
354
- "<a target='_blank' href={$iplookup_link} class='SimpleHistoryLogitem__anonUserWithIp__theIp'>" . esc_html( $ip_numbers_joined ) . "</a>"
355
- );*/
356
-
357
- /*
358
- print_r($arr_found_additional_ip_headers);
359
- Array
360
- (
361
- [_server_http_x_forwarded_for_0] => 5.35.187.212
362
- [_server_http_x_forwarded_for_1] => 83.251.97.21
363
- )
364
- */
365
-
366
- // } else {
367
- // single ip address
368
- $iplookup_link = sprintf(
369
- 'https://ipinfo.io/%1$s',
370
- esc_attr($context['_server_remote_addr'])
371
- );
372
-
373
- $initiator_html .= sprintf(
374
- __('Anonymous user from %1$s', 'simple-history'),
375
- "<a target='_blank' href={$iplookup_link} class='SimpleHistoryLogitem__anonUserWithIp__theIp'>" .
376
- esc_html($context['_server_remote_addr']) .
377
- '</a>'
378
- );
379
-
380
- // } // multiple ip
381
- $initiator_html .= '</strong> ';
382
-
383
- // $initiator_html .= "<strong>" . __("<br><br>Unknown user from {$context["_server_remote_addr"]}") . "</strong>";
384
- // $initiator_html .= "<strong>" . __("<br><br>{$context["_server_remote_addr"]}") . "</strong>";
385
- // $initiator_html .= "<strong>" . __("<br><br>User from IP {$context["_server_remote_addr"]}") . "</strong>";
386
- // $initiator_html .= "<strong>" . __("<br><br>Non-logged in user from IP {$context["_server_remote_addr"]}") . "</strong>";
387
- } // End if().
388
 
389
  break;
390
 
@@ -425,6 +361,11 @@ class SimpleLogger
425
  $row
426
  );
427
 
 
 
 
 
 
428
  // HTML for date
429
  // Date (should...) always exist
430
  // http://developers.whatwg.org/text-level-semantics.html#the-time-element
@@ -562,6 +503,11 @@ class SimpleLogger
562
  $row
563
  );
564
 
 
 
 
 
 
565
  // Logger "via" info in header, i.e. output some extra
566
  // info next to the time to make it more clear what plugin etc.
567
  // that "caused" this event
@@ -575,33 +521,182 @@ class SimpleLogger
575
  $via_html .= '</span>';
576
  }
577
 
578
- // Loglevel
579
- // SimpleHistoryLogitem--loglevel-warning
580
- /*
581
- $level_html = sprintf(
582
- '<span class="SimpleHistoryLogitem--logleveltag SimpleHistoryLogitem--logleveltag-%1$s">%1$s</span>',
583
- $row->level
584
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
585
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586
 
587
- // Glue together final result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
588
  $template = '
589
  %1$s
590
  %2$s
591
  %3$s
 
592
  ';
593
- // if ( ! $initiator_html ) {
594
- // $template = '%2$s';
595
- // }
 
 
 
 
 
 
 
 
 
 
 
 
 
596
  $html = sprintf(
597
  $template,
598
  $initiator_html, // 1
599
  $date_html, // 2
600
- $via_html // 3
 
601
  );
602
 
603
  /**
604
- * Filter generated html for the log row header
605
  *
606
  * @since 2.0
607
  *
@@ -633,8 +728,8 @@ class SimpleLogger
633
  {
634
  $message = $row->message;
635
  $message_key = isset($row->context['_message_key'])
636
- ? $row->context['_message_key']
637
- : null;
638
 
639
  // Message is translated here, but translation must be added in
640
  // plain text before
@@ -694,8 +789,8 @@ class SimpleLogger
694
  // wp_user = wordpress uses, but user may have been deleted since log entry was added
695
  case 'wp_user':
696
  $user_id = isset($row->context['_user_id'])
697
- ? $row->context['_user_id']
698
- : null;
699
 
700
  if ($user_id > 0 && ($user = get_user_by('id', $user_id))) {
701
  // Sender was user
@@ -1125,8 +1220,8 @@ class SimpleLogger
1125
  * @since 2.nn
1126
  */
1127
  $message_key = isset($context['_message_key'])
1128
- ? $context['_message_key']
1129
- : null;
1130
  $do_log = apply_filters(
1131
  "simple_history/log/do_log/{$this->slug}/{$message_key}",
1132
  true
@@ -1137,14 +1232,14 @@ class SimpleLogger
1137
 
1138
  // Check if $message is a translated message, and if so then fetch original
1139
  $sh_latest_translations =
1140
- $this->simpleHistory->gettextLatestTranslations;
1141
 
1142
  if (!empty($sh_latest_translations)) {
1143
  if (isset($sh_latest_translations[$message])) {
1144
  // Translation of this phrase was found, so use original phrase instead of translated one
1145
  // Store textdomain since it's required to translate
1146
  $context['_gettext_domain'] =
1147
- $sh_latest_translations[$message]['domain'];
1148
 
1149
  // These are good to keep when debugging
1150
  // $context["_gettext_org_message"] = $sh_latest_translations[$message]["text"];
@@ -1211,10 +1306,10 @@ class SimpleLogger
1211
  $db_table = apply_filters('simple_history/db_table', $db_table);
1212
 
1213
  $data = array(
1214
- 'logger' => $this->slug,
1215
- 'level' => $level,
1216
- 'date' => $localtime,
1217
- 'message' => $message
1218
  );
1219
 
1220
  // Allow date to be overriden.
@@ -1230,8 +1325,8 @@ class SimpleLogger
1230
  // Minimize risk of similar loggers logging same messages and such and resulting in same occasions id
1231
  // by always adding logger slug.
1232
  $occasions_data = array(
1233
- '_occasionsID' => $context['_occasionsID'],
1234
- '_loggerSlug' => $this->slug
1235
  );
1236
  $occasions_id = md5(json_encode($occasions_data));
1237
  unset($context['_occasionsID']);
@@ -1303,8 +1398,8 @@ class SimpleLogger
1303
 
1304
  // Detect REST calls and append to context, if not already there.
1305
  $isRestApiRequest =
1306
- (defined('REST_API_REQUEST') && REST_API_REQUEST) ||
1307
- (defined('REST_REQUEST') && REST_REQUEST);
1308
  if ($isRestApiRequest) {
1309
  $context['_rest_api_request'] = true;
1310
  }
@@ -1333,7 +1428,7 @@ class SimpleLogger
1333
  $history_inserted_id = $wpdb->insert_id;
1334
 
1335
  $db_table_contexts =
1336
- $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
1337
 
1338
  /**
1339
  * Filter table name for contexts.
@@ -1370,8 +1465,8 @@ class SimpleLogger
1370
  // Add remote addr to context.
1371
  if (!isset($context['_server_remote_addr'])) {
1372
  $remote_addr = empty($_SERVER['REMOTE_ADDR'])
1373
- ? ''
1374
- : wp_unslash($_SERVER['REMOTE_ADDR']);
1375
 
1376
  /**
1377
  * Filter to control if ip addresses should be anonymized or not.
@@ -1427,7 +1522,7 @@ class SimpleLogger
1427
  }
1428
 
1429
  $context[
1430
- "_server_{$key_lower}_{$ip_loop_num}"
1431
  ] = $ip;
1432
  }
1433
 
@@ -1515,9 +1610,9 @@ class SimpleLogger
1515
  }
1516
 
1517
  $data = array(
1518
- 'history_id' => $history_id,
1519
- 'key' => $key,
1520
- 'value' => $value
1521
  );
1522
 
1523
  $wpdb->insert($db_table_contexts, $data);
@@ -1534,12 +1629,12 @@ class SimpleLogger
1534
  public function get_ip_number_header_keys()
1535
  {
1536
  $arr = array(
1537
- 'HTTP_CLIENT_IP',
1538
- 'HTTP_X_FORWARDED_FOR',
1539
- 'HTTP_X_FORWARDED',
1540
- 'HTTP_X_CLUSTER_CLIENT_IP',
1541
- 'HTTP_FORWARDED_FOR',
1542
- 'HTTP_FORWARDED'
1543
  );
1544
 
1545
  return $arr;
@@ -1593,8 +1688,8 @@ class SimpleLogger
1593
  $ip,
1594
  FILTER_VALIDATE_IP,
1595
  FILTER_FLAG_IPV4 |
1596
- FILTER_FLAG_NO_PRIV_RANGE |
1597
- FILTER_FLAG_NO_RES_RANGE
1598
  ) === false
1599
  ) {
1600
  return false;
184
  }
185
 
186
  // Interpolate replacement values into the message and return
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  return strtr($message, $replace);
188
  }
189
 
190
  /**
191
+ * @param object $row
 
 
 
192
  * @return string HTML
193
  */
194
+ public function getLogRowHeaderInitiatorOutput($row)
195
  {
 
196
  $initiator_html = '';
 
197
  $initiator = $row->initiator;
198
  $context = $row->context;
199
 
221
 
222
  // get user role, as done in user-edit.php
223
  $wp_roles = $GLOBALS['wp_roles'];
 
224
  $user_roles = array_intersect(
225
  array_values((array) $user->roles),
226
  array_keys((array) $wp_roles->roles)
230
  $user_display_name = $user->display_name;
231
 
232
  /*
233
+ * If user who logged this is the currently logged in user
234
+ * skip name and email and use just "You"
235
+ *
236
+ * @param bool If you should be used
237
+ * @since 2.1
238
+ */
239
  $use_you = apply_filters(
240
  'simple_history/header_initiator_use_you',
241
  true
243
 
244
  if ($use_you && $is_current_user) {
245
  $tmpl_initiator_html = '
246
+ <a href="%6$s" class="SimpleHistoryLogitem__headerUserProfileLink">
247
+ <strong class="SimpleHistoryLogitem__inlineDivided">%5$s</strong>
248
+ </a>
249
+ ';
250
  } else {
251
  $tmpl_initiator_html = '
252
+ <a href="%6$s" class="SimpleHistoryLogitem__headerUserProfileLink">
253
+ <strong class="SimpleHistoryLogitem__inlineDivided">%3$s</strong>
254
+ <span class="SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__headerEmail">%2$s</span>
255
+ </a>
256
+ ';
257
  }
258
 
259
  /**
306
  case 'web_user':
307
  /*
308
  Note: server_remote_addr may not show visiting/attacking ip, if server is behind...stuff..
309
+ Can be behind varnish cache, or browser can for example use compression in chrome mobile
310
  then the real ip is behind _server_http_x_forwarded_for_0 or similar
311
  _server_remote_addr 66.249.81.222
312
  _server_http_x_forwarded_for_0 5.35.187.212
313
  */
314
 
315
+ // Check if additional IP addresses are stored, from http_x_forwarded_for and so on.
316
  $arr_found_additional_ip_headers = $this->get_event_ip_number_headers(
317
  $row
318
  );
319
 
320
+ $initiator_html .=
321
+ "<strong class='SimpleHistoryLogitem__inlineDivided'>" .
322
+ __('Anonymous web user', 'simple-history') .
323
+ '</strong> ';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
  break;
326
 
361
  $row
362
  );
363
 
364
+ return $initiator_html;
365
+ }
366
+
367
+ public function getLogRowHeaderDateOutput($row)
368
+ {
369
  // HTML for date
370
  // Date (should...) always exist
371
  // http://developers.whatwg.org/text-level-semantics.html#the-time-element
503
  $row
504
  );
505
 
506
+ return $date_html;
507
+ }
508
+
509
+ public function getLogRowHeaderUsingPluginOutput($row)
510
+ {
511
  // Logger "via" info in header, i.e. output some extra
512
  // info next to the time to make it more clear what plugin etc.
513
  // that "caused" this event
521
  $via_html .= '</span>';
522
  }
523
 
524
+ return $via_html;
525
+ }
526
+
527
+ /**
528
+ * Context for IP Addresses can contain multiple entries.
529
+ *
530
+ * - "_server_remote_addr" with value for example "172.17.0.0" is the main entry.
531
+ * It usually contains the IP address of the visitor.
532
+ *
533
+ * - Then zero or one or multiple entries can exist if web server is for example behind proxy.
534
+ * Entries that can exist are the one with keys is get_ip_number_header_keys(),
535
+ * Also each key can exist multiple times.
536
+ * Final key name will be like "_server_http_x_forwarded_for_0", "_server_http_x_forwarded_for_1" and so on.
537
+ *
538
+ * @param mixed $row
539
+ * @return string
540
+ */
541
+ public function getLogRowHeaderIPAddressOutput($row)
542
+ {
543
+
544
+ /**
545
+ * Filter if IP Address should be added to header row.
546
+ *
547
+ * @since 2.x
548
+ *
549
+ * @param bool True to show IP address, false to hide it. Defaults to false.
550
+ * @param object $row Row data
551
  */
552
+ $show_ip_address = apply_filters(
553
+ 'simple_history/row_header_output/display_ip_address',
554
+ false,
555
+ $row
556
+ );
557
+
558
+ if (!$show_ip_address) {
559
+ return '';
560
+ }
561
+
562
+ $context = $row->context;
563
+ $html = "<span class='SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__anonUserWithIp'>";
564
+
565
+ $arr_ip_addresses = [];
566
+
567
+ // Look for additional ip addresses.
568
+ $arr_found_additional_ip_headers = $this->get_event_ip_number_headers($row);
569
+
570
+ $arr_ip_addresses = array_merge(
571
+ // Remote addr always exists.
572
+ ['_server_remote_addr' => $context['_server_remote_addr']],
573
+ $arr_found_additional_ip_headers
574
+ );
575
+
576
+ // if ( sizeof( $arr_found_additional_ip_headers ) ) {
577
+ // $iplookup_link = sprintf('https://ipinfo.io/%1$s', esc_attr($context["_server_remote_addr"]));
578
+ // $ip_numbers_joined = wp_sprintf_l('%l', array("_server_remote_addr" => $context["_server_remote_addr"]) + $arr_found_additional_ip_headers);
579
+ /*
580
+ $html .= sprintf(
581
+ __('Anonymous user with multiple IP addresses detected: %1$s', "simple-history"),
582
+ "<a target='_blank' href={$iplookup_link} class='SimpleHistoryLogitem__anonUserWithIp__theIp'>" . esc_html( $ip_numbers_joined ) . "</a>"
583
+ );*/
584
+
585
+ /*
586
+ print_r($arr_found_additional_ip_headers);
587
+ Array
588
+ (
589
+ [_server_http_x_forwarded_for_0] => 5.35.187.212
590
+ [_server_http_x_forwarded_for_1] => 83.251.97.21
591
+ )
592
+ */
593
+
594
+ // } else {
595
+
596
+ $first_ip_address = reset($arr_ip_addresses);
597
+
598
+ // Output single or plural text.
599
+ if (sizeof($arr_ip_addresses) === 1) {
600
+ // Single ip address
601
+ $iplookup_link = sprintf(
602
+ 'https://ipinfo.io/%1$s',
603
+ esc_attr($first_ip_address)
604
+ );
605
 
606
+ $html .= sprintf(
607
+ __('IP Address %1$s', 'simple-history'),
608
+ "<a target='_blank' href='{$iplookup_link}' class='SimpleHistoryLogitem__anonUserWithIp__theIp'>" .
609
+ esc_html($first_ip_address) .
610
+ '</a>'
611
+ );
612
+ } elseif (sizeof($arr_ip_addresses) > 1) {
613
+ $ip_addresses_html = '';
614
+
615
+ foreach ($arr_ip_addresses as $ip_address_header => $ip_address) {
616
+ $iplookup_link = sprintf(
617
+ 'https://ipinfo.io/%1$s',
618
+ esc_attr($ip_address)
619
+ );
620
+
621
+ $ip_addresses_html .= sprintf(
622
+ '<a target="_blank" href="%3$s" class="SimpleHistoryLogitem__anonUserWithIp__theIp">%1$s</a>, ',
623
+ esc_html($ip_address), // 1
624
+ esc_html($ip_address_header), // 2
625
+ $iplookup_link // 3
626
+ );
627
+ }
628
+
629
+ // Remove trailing comma.
630
+ $ip_addresses_html = rtrim($ip_addresses_html, ', ');
631
+
632
+ $html .= sprintf(
633
+ __('IP Addresses %1$s', 'simple-history'),
634
+ $ip_addresses_html
635
+ );
636
+ }
637
+
638
+ // } // multiple ip
639
+ $html .= '</span> ';
640
+
641
+ // $initiator_html .= "<strong>" . __("<br><br>Unknown user from {$context["_server_remote_addr"]}") . "</strong>";
642
+ // $initiator_html .= "<strong>" . __("<br><br>{$context["_server_remote_addr"]}") . "</strong>";
643
+ // $initiator_html .= "<strong>" . __("<br><br>User from IP {$context["_server_remote_addr"]}") . "</strong>";
644
+ // $initiator_html .= "<strong>" . __("<br><br>Non-logged in user from IP {$context["_server_remote_addr"]}") . "</strong>";
645
+ // } // End if().
646
+ return $html;
647
+ }
648
+
649
+ /**
650
+ * Returns header output for a log row.
651
+ *
652
+ * Format should be common for all log rows and should be like:
653
+ * Username (user role) · Date · IP Address · Via plugin abc
654
+ * I.e.:
655
+ * Initiator * Date/time * IP Address * Via logger
656
+ *
657
+ * @param object $row Row data
658
+ * @return string HTML
659
+ */
660
+ public function getLogRowHeaderOutput($row)
661
+ {
662
+ $initiator_html = $this->getLogRowHeaderInitiatorOutput($row);
663
+ $date_html = $this->getLogRowHeaderDateOutput($row);
664
+ $via_html = $this->getLogRowHeaderUsingPluginOutput($row);
665
+ $ip_address_html = $this->getLogRowHeaderIPAddressOutput($row);
666
+
667
+ // Template to combine header parts.
668
  $template = '
669
  %1$s
670
  %2$s
671
  %3$s
672
+ %4$s
673
  ';
674
+
675
+ /**
676
+ * Filter template used to glue together markup the log row header.
677
+ *
678
+ * @since 2.0
679
+ *
680
+ * @param string $template
681
+ * @param object $row Log row
682
+ */
683
+ $template = apply_filters(
684
+ 'simple_history/row_header_output/template',
685
+ $template,
686
+ $row
687
+ );
688
+
689
+ // Glue together final result.
690
  $html = sprintf(
691
  $template,
692
  $initiator_html, // 1
693
  $date_html, // 2
694
+ $via_html, // 3
695
+ $ip_address_html // 4
696
  );
697
 
698
  /**
699
+ * Filter generated html for the log row header.
700
  *
701
  * @since 2.0
702
  *
728
  {
729
  $message = $row->message;
730
  $message_key = isset($row->context['_message_key'])
731
+ ? $row->context['_message_key']
732
+ : null;
733
 
734
  // Message is translated here, but translation must be added in
735
  // plain text before
789
  // wp_user = wordpress uses, but user may have been deleted since log entry was added
790
  case 'wp_user':
791
  $user_id = isset($row->context['_user_id'])
792
+ ? $row->context['_user_id']
793
+ : null;
794
 
795
  if ($user_id > 0 && ($user = get_user_by('id', $user_id))) {
796
  // Sender was user
1220
  * @since 2.nn
1221
  */
1222
  $message_key = isset($context['_message_key'])
1223
+ ? $context['_message_key']
1224
+ : null;
1225
  $do_log = apply_filters(
1226
  "simple_history/log/do_log/{$this->slug}/{$message_key}",
1227
  true
1232
 
1233
  // Check if $message is a translated message, and if so then fetch original
1234
  $sh_latest_translations =
1235
+ $this->simpleHistory->gettextLatestTranslations;
1236
 
1237
  if (!empty($sh_latest_translations)) {
1238
  if (isset($sh_latest_translations[$message])) {
1239
  // Translation of this phrase was found, so use original phrase instead of translated one
1240
  // Store textdomain since it's required to translate
1241
  $context['_gettext_domain'] =
1242
+ $sh_latest_translations[$message]['domain'];
1243
 
1244
  // These are good to keep when debugging
1245
  // $context["_gettext_org_message"] = $sh_latest_translations[$message]["text"];
1306
  $db_table = apply_filters('simple_history/db_table', $db_table);
1307
 
1308
  $data = array(
1309
+ 'logger' => $this->slug,
1310
+ 'level' => $level,
1311
+ 'date' => $localtime,
1312
+ 'message' => $message
1313
  );
1314
 
1315
  // Allow date to be overriden.
1325
  // Minimize risk of similar loggers logging same messages and such and resulting in same occasions id
1326
  // by always adding logger slug.
1327
  $occasions_data = array(
1328
+ '_occasionsID' => $context['_occasionsID'],
1329
+ '_loggerSlug' => $this->slug
1330
  );
1331
  $occasions_id = md5(json_encode($occasions_data));
1332
  unset($context['_occasionsID']);
1398
 
1399
  // Detect REST calls and append to context, if not already there.
1400
  $isRestApiRequest =
1401
+ (defined('REST_API_REQUEST') && REST_API_REQUEST) ||
1402
+ (defined('REST_REQUEST') && REST_REQUEST);
1403
  if ($isRestApiRequest) {
1404
  $context['_rest_api_request'] = true;
1405
  }
1428
  $history_inserted_id = $wpdb->insert_id;
1429
 
1430
  $db_table_contexts =
1431
+ $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
1432
 
1433
  /**
1434
  * Filter table name for contexts.
1465
  // Add remote addr to context.
1466
  if (!isset($context['_server_remote_addr'])) {
1467
  $remote_addr = empty($_SERVER['REMOTE_ADDR'])
1468
+ ? ''
1469
+ : wp_unslash($_SERVER['REMOTE_ADDR']);
1470
 
1471
  /**
1472
  * Filter to control if ip addresses should be anonymized or not.
1522
  }
1523
 
1524
  $context[
1525
+ "_server_{$key_lower}_{$ip_loop_num}"
1526
  ] = $ip;
1527
  }
1528
 
1610
  }
1611
 
1612
  $data = array(
1613
+ 'history_id' => $history_id,
1614
+ 'key' => $key,
1615
+ 'value' => $value
1616
  );
1617
 
1618
  $wpdb->insert($db_table_contexts, $data);
1629
  public function get_ip_number_header_keys()
1630
  {
1631
  $arr = array(
1632
+ 'HTTP_CLIENT_IP',
1633
+ 'HTTP_X_FORWARDED_FOR',
1634
+ 'HTTP_X_FORWARDED',
1635
+ 'HTTP_X_CLUSTER_CLIENT_IP',
1636
+ 'HTTP_FORWARDED_FOR',
1637
+ 'HTTP_FORWARDED'
1638
  );
1639
 
1640
  return $arr;
1688
  $ip,
1689
  FILTER_VALIDATE_IP,
1690
  FILTER_FLAG_IPV4 |
1691
+ FILTER_FLAG_NO_PRIV_RANGE |
1692
+ FILTER_FLAG_NO_RES_RANGE
1693
  ) === false
1694
  ) {
1695
  return false;
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: history, log, changes, changelog, audit, audit log, event log, user tracki
5
  Requires at least: 5.2
6
  Tested up to: 5.6
7
  Requires PHP: 5.6
8
- Stable tag: 2.39.0
9
 
10
  View changes made by users within WordPress. See who created a page, uploaded an attachment or approved an comment, and more.
11
 
@@ -50,7 +50,7 @@ Out of the box Simple History has support for:
50
  By default Simple History comes with built in support for the following plugins:
51
 
52
  **Jetpack**<br>
53
- The [Jetpack plugin](https://wordpress.org/plugins/jetpack/) is a plugin from Automattic (the creators of WordPress) that lets you supercharge your website by adding a lot of extra functions.
54
  In Simple History you will see what Jetpack modules that are activated and deactivated.
55
  (The creator of Simple History recommends this plugin and its [brute force attack protection](https://jetpack.com/features/security/brute-force-attack-protection/) functions btw. It's a really good way to block unwanted login attempts from malicious botnets and distributed attacks.
56
 
@@ -193,6 +193,20 @@ Events in the log are stored for 60 days by default. Events older than this will
193
 
194
  == Changelog ==
195
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  = 2.39.0 (January 2021) =
197
 
198
  - Added: Logging of events that a user performs via the [WP Crontrol](https://wordpress.org/plugins/wp-crontrol/) plugin (requires WP Crontrol version 1.9.0 or later). Simple History will log when cron events are added, edited, deleted, and manually ran, and when cron schedules are added and deleted. Props https://github.com/johnbillion.
5
  Requires at least: 5.2
6
  Tested up to: 5.6
7
  Requires PHP: 5.6
8
+ Stable tag: 2.40.0
9
 
10
  View changes made by users within WordPress. See who created a page, uploaded an attachment or approved an comment, and more.
11
 
50
  By default Simple History comes with built in support for the following plugins:
51
 
52
  **Jetpack**<br>
53
+ The [Jetpack plugin](https://wordpress.org/plugins/jetpack/) is a plugin from Automattic (the company behind the WordPress.com service) that lets you supercharge your website by adding a lot of extra functions.
54
  In Simple History you will see what Jetpack modules that are activated and deactivated.
55
  (The creator of Simple History recommends this plugin and its [brute force attack protection](https://jetpack.com/features/security/brute-force-attack-protection/) functions btw. It's a really good way to block unwanted login attempts from malicious botnets and distributed attacks.
56
 
193
 
194
  == Changelog ==
195
 
196
+ = 2.40.0 (March 2021) =
197
+
198
+ - Changed: IP address is now also shown when a user successfully logs in.
199
+ Previously the IP address was only shown for failed login attempts. Note that the IP address/es of all events are always logged and can be seen in the "context data" table that is displayed when you click the date and time of an event.
200
+ [#233](https://github.com/bonny/WordPress-Simple-History/issues/233).
201
+
202
+ - Added: If multiple IP addresses are detected, for example when a website is running behind a proxy or similar, all IP addresses are now shown for failed and sucessful logins.
203
+
204
+ - Added: Filter `simple_history/row_header_output/display_ip_address` that can be used to control when the IP address/es should be visible in the main log. By default sucessful and failed logins are shown.
205
+
206
+ - Added: Show message when failing to get IP address due to for example ad blocker. IPInfo.io is for example blocked in the EasyList filter list that for example [Chrome extension uBlock Origin](https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm) uses.
207
+
208
+ - Added: Filter `simple_history/row_header_output/template` that controls the output of the header row in the main event log.
209
+
210
  = 2.39.0 (January 2021) =
211
 
212
  - Added: Logging of events that a user performs via the [WP Crontrol](https://wordpress.org/plugins/wp-crontrol/) plugin (requires WP Crontrol version 1.9.0 or later). Simple History will log when cron events are added, edited, deleted, and manually ran, and when cron schedules are added and deleted. Props https://github.com/johnbillion.