1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace RedirectionIO\Client\Wordpress; |
4
|
|
|
|
5
|
|
|
use RedirectionIO\Client\Sdk\Client; |
6
|
|
|
use RedirectionIO\Client\Sdk\Command\MatchWithResponseCommand; |
7
|
|
|
use RedirectionIO\Client\Sdk\Exception\AgentNotFoundException; |
8
|
|
|
use RedirectionIO\Client\Sdk\HttpMessage\Request; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* RedirectionIOSettingsPage class. |
12
|
|
|
* |
13
|
|
|
* This class is used to create a new page in the admin area |
14
|
|
|
* dedicated to redirection.io. It lets you configuring the plugin as you like. |
15
|
|
|
*/ |
16
|
|
|
class RedirectionIOSettingsPage |
17
|
|
|
{ |
18
|
|
|
private $overrider; |
19
|
|
|
|
20
|
|
|
public function __construct() |
21
|
|
|
{ |
22
|
|
|
$this->overrider = new WPCoreFunctionsOverrider(); |
23
|
|
|
|
24
|
|
|
add_action('init', [$this, 'setTranslations']); |
|
|
|
|
25
|
|
|
add_action('admin_menu', [$this, 'setUp']); |
26
|
|
|
add_action('admin_init', [$this, 'registerSettings']); |
27
|
|
|
add_action('admin_enqueue_scripts', [$this, 'registerAssets']); |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
public function setUp() |
31
|
|
|
{ |
32
|
|
|
add_options_page('redirection.io', 'redirection.io', 'manage_options', 'redirectionio', [$this, 'outputContent']); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
public function setTranslations() |
36
|
|
|
{ |
37
|
|
|
load_plugin_textdomain('redirectionio', false, \dirname(plugin_basename(__FILE__)) . '/../languages'); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
public function outputContent() |
41
|
|
|
{ |
42
|
|
|
if (!current_user_can('manage_options')) { |
43
|
|
|
wp_die(__('You do not have sufficient permissions to access this page.')); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
$title = 'redirection.io'; |
47
|
|
|
$intro = |
48
|
|
|
'<p>' . |
49
|
|
|
__('redirection.io let you track HTTP errors and setup useful HTTP redirections.', 'redirectionio') . |
50
|
|
|
'</p><p>' . |
51
|
|
|
sprintf(__('This plugin works in combination with <a href="%s">redirection.io</a> |
52
|
|
|
and need an installed and configured agent on your server. |
53
|
|
|
</br> |
54
|
|
|
Before using it, please make sure that you have :', 'redirectionio'), esc_url('//redirection.io')) . |
55
|
|
|
'<ul>' . |
56
|
|
|
'<li>' . sprintf(__('created a redirection.io account <a href="">here</a>', 'redirectionio'), esc_url('//redirection.io')) . '</li>' . |
57
|
|
|
'<li>' . sprintf(__('followed the <a href="">installation guide</a> to setup a redirection.io agent on your server', 'redirectionio'), esc_url('//redirection.io')) . '</li>' . |
58
|
|
|
'</ul>' . |
59
|
|
|
'</p><p>' . |
60
|
|
|
__('Drop us an email to [email protected] if you need help or have any question.', 'redirectionio') . |
61
|
|
|
'</p><p>' . |
62
|
|
|
__('Note: in most cases, you only have one agent, so you only need to configure one connection.', 'redirectionio') . |
63
|
|
|
'</p>' |
64
|
|
|
; |
65
|
|
|
$confirm = __('Are you sure ?', 'redirectionio'); |
66
|
|
|
|
67
|
|
|
echo ' |
68
|
|
|
<div class="wrap" id="redirectionio"> |
69
|
|
|
<h1>' . $title . '</h1> |
70
|
|
|
<div>' . $intro . '</div> |
71
|
|
|
<form method="post" action="options.php"> |
72
|
|
|
'; |
73
|
|
|
|
74
|
|
|
settings_fields('redirectionio-group'); |
75
|
|
|
$this->overrider->doSettingsSections('redirectionio'); |
76
|
|
|
|
77
|
|
|
submit_button(); |
78
|
|
|
|
79
|
|
|
echo ' |
80
|
|
|
</form></div> |
81
|
|
|
<script> |
82
|
|
|
var confirmStr = \'' . $confirm . '\'; |
83
|
|
|
</script> |
84
|
|
|
'; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
public function registerSettings() |
88
|
|
|
{ |
89
|
|
|
register_setting( |
90
|
|
|
'redirectionio-group', |
91
|
|
|
'redirectionio', |
92
|
|
|
[$this, 'sanitizeInput'] |
93
|
|
|
); |
94
|
|
|
|
95
|
|
|
$options = get_option('redirectionio'); |
|
|
|
|
96
|
|
|
|
97
|
|
|
// Add projectKey |
98
|
|
|
add_settings_section( |
99
|
|
|
'redirectionio-section-project-key', |
100
|
|
|
__('Project key', 'redirectionio'), |
101
|
|
|
[$this, 'printSection'], |
102
|
|
|
'redirectionio' |
103
|
|
|
); |
104
|
|
|
|
105
|
|
|
add_settings_field( |
106
|
|
|
'redirectionio-input-project-key', |
107
|
|
|
__('Project key', 'redirectionio'), |
108
|
|
|
[$this, 'printProjectKeyField'], |
109
|
|
|
'redirectionio', |
110
|
|
|
'redirectionio-section-project-key', |
111
|
|
|
$options['projectKey'] |
112
|
|
|
); |
113
|
|
|
|
114
|
|
|
// Add connections |
115
|
|
|
foreach ($options['connections'] as $i => $option) { |
116
|
|
|
add_settings_section( |
117
|
|
|
'redirectionio-section-' . $i, |
118
|
|
|
sprintf(__('Connection #%s', 'redirectionio'), $i + 1), |
119
|
|
|
[$this, 'printSection'], |
120
|
|
|
'redirectionio' |
121
|
|
|
); |
122
|
|
|
|
123
|
|
|
foreach ($option as $key => $value) { |
124
|
|
|
switch ($key) { |
125
|
|
|
case 'name': |
126
|
|
|
$title = __('Name', 'redirectionio'); |
127
|
|
|
$required = false; |
128
|
|
|
$description = __('[Optional] If you have multiple connections, you may find useful to name them for better readability.', 'redirectionio'); |
129
|
|
|
$placeholder = __('my-connection', 'redirectionio'); |
130
|
|
|
break; |
131
|
|
|
case 'remote_socket': |
132
|
|
|
$title = __('Agent address', 'redirectionio'); |
133
|
|
|
$required = true; |
134
|
|
|
$description = __('[Required] Insert here your agent address. Internet Domain socket (AF_INET) and Unix Domain socket (AF_UNIX) are supported.<br/> Examples: tcp://192.168.1.1:20301, tcp://agent.my-website.com:10301, unix:///var/run/my-agent.sock', 'redirectionio'); |
135
|
|
|
$placeholder = 'tcp://192.168.1.1:20301'; |
136
|
|
|
break; |
137
|
|
|
default: |
138
|
|
|
$title = 'unknown'; |
139
|
|
|
$required = false; |
140
|
|
|
$description = ''; |
141
|
|
|
$placeholder = ''; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
add_settings_field( |
145
|
|
|
$i . '_' . $key, |
146
|
|
|
$title . ($required ? '*' : ''), |
147
|
|
|
[$this, 'printConnectionField'], |
148
|
|
|
'redirectionio', |
149
|
|
|
'redirectionio-section-' . $i, |
150
|
|
|
[ |
151
|
|
|
'id' => $i, |
152
|
|
|
'type' => $key, |
153
|
|
|
'value' => $value, |
154
|
|
|
'placeholder' => $placeholder, |
155
|
|
|
'description' => $description, |
156
|
|
|
] |
157
|
|
|
); |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
// Add doNotRedirectAdmin |
162
|
|
|
add_settings_section( |
163
|
|
|
'redirectionio-section-do-not-redirect-admin', |
164
|
|
|
__('Disable redirections for admin area', 'redirectionio'), |
165
|
|
|
[$this, 'printSection'], |
166
|
|
|
'redirectionio' |
167
|
|
|
); |
168
|
|
|
|
169
|
|
|
add_settings_field( |
170
|
|
|
'redirectionio-checkbox-do-not-redirect-admin', |
171
|
|
|
__("Yes, I wan't to disable it", 'redirectionio'), |
172
|
|
|
[$this, 'printDoNotRedirectAdminCheckbox'], |
173
|
|
|
'redirectionio', |
174
|
|
|
'redirectionio-section-do-not-redirect-admin', |
175
|
|
|
$options['doNotRedirectAdmin'] |
176
|
|
|
); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
public function sanitizeInput(array $input) |
180
|
|
|
{ |
181
|
|
|
$newInput = [ |
182
|
|
|
'projectKey' => $input['projectKey'], |
183
|
|
|
'doNotRedirectAdmin' => $input['doNotRedirectAdmin'], |
184
|
|
|
]; |
185
|
|
|
|
186
|
|
|
foreach ($input['connections'] as $i => $option) { |
187
|
|
|
foreach ($option as $key => $value) { |
188
|
|
|
$newInput['connections'][$i][$key] = sanitize_text_field($input['connections'][$i][$key]); |
189
|
|
|
} |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
return $newInput; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
public function printSection() |
196
|
|
|
{ |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
public function printProjectKeyField(string $projectKey) |
200
|
|
|
{ |
201
|
|
|
$placeholder = __('my-project-key', 'redirectionio'); |
202
|
|
|
echo "<input id='redirectionio_projectKey' name='redirectionio[projectKey]' type='text' size='100' value='$projectKey' placeholder='$placeholder' />"; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
public function printConnectionField(array $args) |
206
|
|
|
{ |
207
|
|
|
$id = isset($args['id']) ? $args['id'] : ''; |
208
|
|
|
$type = isset($args['type']) ? $args['type'] : ''; |
209
|
|
|
$value = isset($args['value']) ? $args['value'] : ''; |
210
|
|
|
$placeholder = isset($args['placeholder']) ? $args['placeholder'] : ''; |
211
|
|
|
$description = isset($args['description']) ? $args['description'] : ''; |
212
|
|
|
|
213
|
|
|
echo "<input id='redirectionio_{$id}_{$type}' name='redirectionio[connections][$id][$type]' size='40' type='text' value='$value' placeholder='$placeholder' />"; |
214
|
|
|
echo "<p class='description' id='redirectionio_{$id}_{$type}_description'>$description</p>"; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* @param bool $checked |
219
|
|
|
*/ |
220
|
|
|
public function printDoNotRedirectAdminCheckbox($checked) |
221
|
|
|
{ |
222
|
|
|
echo '<input id="redirectionio_doNotRedirectAdmin" name="redirectionio[doNotRedirectAdmin]" type="checkbox" ' . ($checked ? 'checked' : '') . ' />'; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
public function registerAssets() |
226
|
|
|
{ |
227
|
|
|
wp_enqueue_style('redirectionio', plugins_url('../assets/css/redirectionio.css', __FILE__)); |
228
|
|
|
wp_enqueue_script('redirectionio', plugins_url('../assets/js/redirectionio.js', __FILE__), [], false, true); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Return a connection (associative array with (`port` && `host`) || `remote_socket` keys). |
233
|
|
|
* |
234
|
|
|
* @param mixed $page |
235
|
|
|
* @param mixed $section |
236
|
|
|
*/ |
237
|
|
|
public static function getConnectionFromSection($page, $section) |
238
|
|
|
{ |
239
|
|
|
global $wp_settings_fields; |
240
|
|
|
|
241
|
|
|
if (!isset($wp_settings_fields[$page][$section])) { |
242
|
|
|
return false; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
foreach ((array) $wp_settings_fields[$page][$section] as $field) { |
246
|
|
|
if ($field['args']['type'] === 'remote_socket') { |
247
|
|
|
$remoteSocket = $field['args']['value']; |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
return ['remote_socket' => $remoteSocket]; |
|
|
|
|
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Test if a connection is currently working. |
256
|
|
|
* |
257
|
|
|
* @param mixed $connection array|bool(false) |
258
|
|
|
*/ |
259
|
|
|
public static function isWorkingConnection($connection) |
260
|
|
|
{ |
261
|
|
|
if ($connection === false) { |
262
|
|
|
return false; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
$client = new Client( |
266
|
|
|
'check-status-project-key', |
267
|
|
|
[ |
268
|
|
|
'checkStatus' => $connection['remote_socket'], |
269
|
|
|
], |
270
|
|
|
10000, |
271
|
|
|
true |
272
|
|
|
); |
273
|
|
|
|
274
|
|
|
try { |
275
|
|
|
$request = new Request('', '', ''); |
276
|
|
|
$client->request(new MatchWithResponseCommand($request)); |
277
|
|
|
} catch (AgentNotFoundException $e) { |
278
|
|
|
return false; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
return true; |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.