1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* The filter/plugin API is located in this file, which allows for creating filters |
5
|
|
|
* and hooking functions, and methods. The functions or methods will be run when |
6
|
|
|
* the filter is called. |
7
|
|
|
* |
8
|
|
|
* Any of the syntaxes explained in the PHP documentation for the |
9
|
|
|
* {@link http://us2.php.net/manual/en/language.pseudo-types.php#language.types.callback 'callback'} |
10
|
|
|
* type are valid. |
11
|
|
|
* |
12
|
|
|
* This API is heavily inspired by the one I implemented in Zenphoto 1.3, which was heavily inspired by the one used in WordPress. |
13
|
|
|
* |
14
|
|
|
* @author Ozh |
15
|
|
|
* @since 1.5 |
16
|
|
|
*/ |
17
|
|
|
|
18
|
|
|
if ( !isset( $yourls_filters ) ) { |
19
|
|
|
$yourls_filters = []; |
20
|
|
|
} |
21
|
|
|
/* |
22
|
|
|
* This global var will collect filters with the following structure: |
23
|
|
|
* $yourls_filters['hook']['array of priorities']['serialized function names']['array of ['array (functions, accepted_args, filter or action)]'] |
24
|
|
|
*/ |
25
|
|
|
|
26
|
|
|
if ( !isset( $yourls_actions ) ) { |
27
|
|
|
$yourls_actions = []; |
28
|
|
|
} |
29
|
|
|
/* |
30
|
|
|
* This global var will collect 'done' actions with the following structure: |
31
|
|
|
* $yourls_actions['hook'] => number of time this action was done |
32
|
|
|
*/ |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Registers a filtering function |
36
|
|
|
* |
37
|
|
|
* Typical use: |
38
|
|
|
* yourls_add_filter('some_hook', 'function_handler_for_hook'); |
39
|
|
|
* |
40
|
|
|
* @param string $hook the name of the YOURLS element to be filtered or YOURLS action to be triggered |
41
|
|
|
* @param callback $function_name the name of the function that is to be called. |
42
|
|
|
* @param int $priority optional. Used to specify the order in which the functions associated with a |
43
|
|
|
* particular action are executed (default=10, lower=earlier execution, and functions |
44
|
|
|
* with the same priority are executed in the order in which they were added to the |
45
|
|
|
* filter) |
46
|
|
|
* @param int $accepted_args optional. The number of arguments the function accept (default is the number |
47
|
|
|
* provided). |
48
|
|
|
* @param string $type |
49
|
|
|
* @global array $yourls_filters Storage for all of the filters |
50
|
|
|
*/ |
51
|
|
|
function yourls_add_filter( $hook, $function_name, $priority = 10, $accepted_args = NULL, $type = 'filter' ) { |
52
|
109 |
|
global $yourls_filters; |
53
|
|
|
// At this point, we cannot check if the function exists, as it may well be defined later (which is OK) |
54
|
109 |
|
$id = yourls_filter_unique_id( $hook, $function_name, $priority ); |
55
|
|
|
|
56
|
109 |
|
$yourls_filters[ $hook ][ $priority ][ $id ] = [ |
57
|
109 |
|
'function' => $function_name, |
58
|
109 |
|
'accepted_args' => $accepted_args, |
59
|
109 |
|
'type' => $type, |
60
|
|
|
]; |
61
|
109 |
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Hooks a function on to a specific action. |
65
|
|
|
* |
66
|
|
|
* Actions are the hooks that YOURLS launches at specific points |
67
|
|
|
* during execution, or when specific events occur. Plugins can specify that |
68
|
|
|
* one or more of its PHP functions are executed at these points, using the |
69
|
|
|
* Action API. |
70
|
|
|
* |
71
|
|
|
* @param string $hook The name of the action to which the $function_to_add is hooked. |
72
|
|
|
* @param callback $function_name The name of the function you wish to be called. |
73
|
|
|
* @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action. |
74
|
|
|
* @param int $accepted_args optional. The number of arguments the function accept (default 1). |
75
|
|
|
*/ |
76
|
|
|
function yourls_add_action( $hook, $function_name, $priority = 10, $accepted_args = 1 ) { |
77
|
29 |
|
yourls_add_filter( $hook, $function_name, $priority, $accepted_args, 'action' ); |
78
|
29 |
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Build Unique ID for storage and retrieval. |
82
|
|
|
* |
83
|
|
|
* Simply using a function name is not enough, as several functions can have the same name when they are enclosed in classes. |
84
|
|
|
* |
85
|
|
|
* @global array $yourls_filters storage for all of the filters |
86
|
|
|
* @param string $hook hook to which the function is attached |
87
|
|
|
* @param string|array $function used for creating unique id |
88
|
|
|
* @param int|bool $priority used in counting how many hooks were applied. If === false and $function is an object reference, we return the unique id only if it already has one, false otherwise. |
89
|
|
|
* @return string unique ID for usage as array key |
90
|
|
|
*/ |
91
|
|
|
function yourls_filter_unique_id( $hook, $function, $priority ) { |
92
|
|
|
// If function then just skip all of the tests and not overwrite the following. |
93
|
202 |
|
if ( is_string( $function ) ) { |
94
|
150 |
|
return $function; |
95
|
|
|
} |
96
|
|
|
|
97
|
64 |
|
if ( is_object( $function ) ) { |
98
|
|
|
// Closures are currently implemented as objects |
99
|
15 |
|
$function = [ $function, '' ]; |
100
|
|
|
} |
101
|
|
|
else { |
102
|
49 |
|
$function = (array)$function; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
// Object Class Calling |
106
|
64 |
|
if ( is_object( $function[ 0 ] ) ) { |
107
|
59 |
|
return spl_object_hash( $function[ 0 ] ).$function[ 1 ]; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
// Static Calling |
111
|
5 |
|
if ( is_string( $function[ 0 ] ) ) { |
112
|
5 |
|
return $function[ 0 ].'::'.$function[ 1 ]; |
113
|
|
|
} |
114
|
|
|
// TODO: missing final return; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Performs a filtering operation on a YOURLS element or event. |
119
|
|
|
* |
120
|
|
|
* Typical use: |
121
|
|
|
* |
122
|
|
|
* 1) Modify a variable if a function is attached to hook 'yourls_hook' |
123
|
|
|
* $yourls_var = "default value"; |
124
|
|
|
* $yourls_var = yourls_apply_filter( 'yourls_hook', $yourls_var ); |
125
|
|
|
* |
126
|
|
|
* 2) Trigger functions is attached to event 'yourls_event' |
127
|
|
|
* yourls_apply_filter( 'yourls_event' ); |
128
|
|
|
* (see yourls_do_action() ) |
129
|
|
|
* |
130
|
|
|
* Returns an element which may have been filtered by a filter. |
131
|
|
|
* |
132
|
|
|
* @global array $yourls_filters storage for all of the filters |
133
|
|
|
* @param string $hook the name of the YOURLS element or action |
134
|
|
|
* @param mixed $value the value of the element before filtering |
135
|
|
|
* @return mixed |
136
|
|
|
*/ |
137
|
|
|
function yourls_apply_filter( $hook, $value = '' ) { |
138
|
456 |
|
global $yourls_filters; |
139
|
456 |
|
if ( !isset( $yourls_filters[ $hook ] ) ) { |
140
|
430 |
|
return $value; |
141
|
|
|
} |
142
|
|
|
|
143
|
105 |
|
$args = func_get_args(); |
144
|
|
|
|
145
|
|
|
// Sort filters by priority |
146
|
105 |
|
ksort( $yourls_filters[ $hook ] ); |
147
|
|
|
|
148
|
|
|
// Loops through each filter |
149
|
105 |
|
reset( $yourls_filters[ $hook ] ); |
150
|
|
|
do { |
151
|
105 |
|
foreach ( (array)current( $yourls_filters[ $hook ] ) as $the_ ) { |
152
|
105 |
|
if ( !is_null($the_[ 'function' ]) ) { |
153
|
105 |
|
$args[ 1 ] = $value; |
154
|
105 |
|
$count = $the_[ 'accepted_args' ]; |
155
|
105 |
|
if ( is_null( $count ) ) { |
156
|
82 |
|
$_value = call_user_func_array( $the_[ 'function' ], array_slice( $args, 1 ) ); |
157
|
|
|
} |
158
|
|
|
else { |
159
|
23 |
|
$_value = call_user_func_array( $the_[ 'function' ], array_slice( $args, 1, (int)$count ) ); |
160
|
|
|
} |
161
|
|
|
} |
162
|
100 |
|
if ( $the_[ 'type' ] == 'filter' ) { |
163
|
82 |
|
$value = $_value; |
164
|
|
|
} |
165
|
|
|
} |
166
|
100 |
|
} while ( next( $yourls_filters[ $hook ] ) !== false ); |
167
|
|
|
|
168
|
|
|
// TODO: Missing final return - Why not just return all the time? It's up receiving code to use or not. |
169
|
100 |
|
if ( $the_[ 'type' ] == 'filter' ) { |
|
|
|
|
170
|
82 |
|
return $value; |
171
|
|
|
} |
172
|
18 |
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Performs an action triggered by a YOURLS event. |
176
|
|
|
* |
177
|
|
|
* @param string $hook the name of the YOURLS action |
178
|
|
|
* @param mixed $arg action arguments |
179
|
|
|
*/ |
180
|
|
|
function yourls_do_action( $hook, $arg = '' ) { |
181
|
136 |
|
global $yourls_actions; |
182
|
|
|
|
183
|
|
|
// Keep track of actions that are "done" |
184
|
136 |
|
if ( !isset( $yourls_actions ) ) { |
185
|
|
|
$yourls_actions = []; |
186
|
|
|
} |
187
|
136 |
|
if ( !isset( $yourls_actions[ $hook ] ) ) { |
188
|
33 |
|
$yourls_actions[ $hook ] = 1; |
189
|
|
|
} |
190
|
|
|
else { |
191
|
119 |
|
++$yourls_actions[ $hook ]; |
192
|
|
|
} |
193
|
|
|
|
194
|
136 |
|
$args = []; |
195
|
136 |
|
if ( is_array( $arg ) && 1 == count( $arg ) && isset( $arg[ 0 ] ) && is_object( $arg[ 0 ] ) ) { // array(&$this) |
196
|
|
|
$args[] =& $arg[ 0 ]; |
197
|
|
|
} |
198
|
|
|
else { |
199
|
136 |
|
$args[] = $arg; |
200
|
|
|
} |
201
|
|
|
|
202
|
136 |
|
for ( $a = 2 ; $a < func_num_args() ; $a++ ) { |
203
|
104 |
|
$args[] = func_get_arg( $a ); |
204
|
|
|
} |
205
|
|
|
|
206
|
136 |
|
yourls_apply_filter( $hook, $args ); |
207
|
132 |
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Retrieve the number times an action is fired. |
211
|
|
|
* |
212
|
|
|
* @param string $hook Name of the action hook. |
213
|
|
|
* @return int The number of times action hook <tt>$hook</tt> is fired |
214
|
|
|
*/ |
215
|
|
|
function yourls_did_action( $hook ) { |
216
|
25 |
|
global $yourls_actions; |
217
|
25 |
|
return empty( $yourls_actions[ $hook ] ) ? 0 : $yourls_actions[ $hook ]; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* Removes a function from a specified filter hook. |
222
|
|
|
* |
223
|
|
|
* This function removes a function attached to a specified filter hook. This |
224
|
|
|
* method can be used to remove default functions attached to a specific filter |
225
|
|
|
* hook and possibly replace them with a substitute. |
226
|
|
|
* |
227
|
|
|
* To remove a hook, the $function_to_remove and $priority arguments must match |
228
|
|
|
* when the hook was added. |
229
|
|
|
* |
230
|
|
|
* @global array $yourls_filters storage for all of the filters |
231
|
|
|
* @param string $hook The filter hook to which the function to be removed is hooked. |
232
|
|
|
* @param callback $function_to_remove The name of the function which should be removed. |
233
|
|
|
* @param int $priority optional. The priority of the function (default: 10). |
234
|
|
|
* @return bool Whether the function was registered as a filter before it was removed. |
235
|
|
|
*/ |
236
|
|
|
function yourls_remove_filter( $hook, $function_to_remove, $priority = 10 ) { |
237
|
122 |
|
global $yourls_filters; |
238
|
|
|
|
239
|
122 |
|
$function_to_remove = yourls_filter_unique_id( $hook, $function_to_remove, $priority ); |
240
|
|
|
|
241
|
122 |
|
$remove = isset( $yourls_filters[ $hook ][ $priority ][ $function_to_remove ] ); |
242
|
|
|
|
243
|
122 |
|
if ( $remove === true ) { |
244
|
32 |
|
unset ( $yourls_filters[ $hook ][ $priority ][ $function_to_remove ] ); |
245
|
32 |
|
if ( empty( $yourls_filters[ $hook ][ $priority ] ) ) { |
246
|
32 |
|
unset( $yourls_filters[ $hook ] ); |
247
|
|
|
} |
248
|
|
|
} |
249
|
122 |
|
return $remove; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Removes a function from a specified action hook. |
254
|
|
|
* |
255
|
|
|
* @see yourls_remove_filter() |
256
|
|
|
* @param string $hook The action hook to which the function to be removed is hooked. |
257
|
|
|
* @param callable $function_to_remove The name of the function which should be removed. |
258
|
|
|
* @param int $priority optional. The priority of the function (default: 10). |
259
|
|
|
* @return bool Whether the function was registered as an action before it was removed. |
260
|
|
|
*/ |
261
|
|
|
function yourls_remove_action( $hook, $function_to_remove, $priority = 10 ) { |
262
|
1 |
|
return yourls_remove_filter( $hook, $function_to_remove, $priority ); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Removes all functions from a specified action hook. |
267
|
|
|
* |
268
|
|
|
* @see yourls_remove_all_filters() |
269
|
|
|
* @since 1.7.1 |
270
|
|
|
* @param string $hook The action to remove hooks from |
271
|
|
|
* @param int|false $priority optional. The priority of the functions to remove |
272
|
|
|
* @return bool true when it's finished |
273
|
|
|
*/ |
274
|
|
|
function yourls_remove_all_actions( $hook, $priority = false ) { |
275
|
28 |
|
return yourls_remove_all_filters( $hook, $priority ); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* Removes all functions from a specified filter hook. |
280
|
|
|
* |
281
|
|
|
* @since 1.7.1 |
282
|
|
|
* @param string $hook The filter to remove hooks from |
283
|
|
|
* @param int|false $priority optional. The priority of the functions to remove |
284
|
|
|
* @return bool true when it's finished |
285
|
|
|
*/ |
286
|
|
|
function yourls_remove_all_filters( $hook, $priority = false ) { |
287
|
84 |
|
global $yourls_filters; |
288
|
|
|
|
289
|
84 |
|
if ( isset( $yourls_filters[ $hook ] ) ) { |
290
|
51 |
|
if ( $priority === false ) { |
291
|
50 |
|
unset( $yourls_filters[ $hook ] ); |
292
|
|
|
} |
293
|
1 |
|
elseif ( isset( $yourls_filters[ $hook ][ $priority ] ) ) { |
294
|
1 |
|
unset( $yourls_filters[ $hook ][ $priority ] ); |
295
|
|
|
} |
296
|
|
|
} |
297
|
|
|
|
298
|
84 |
|
return true; |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Check if any filter has been registered for a hook. |
303
|
|
|
* |
304
|
|
|
* @param string $hook The name of the filter hook. |
305
|
|
|
* @param callable|false $function_to_check optional. If specified, return the priority of that function on this hook or false if not attached. |
306
|
|
|
* @return int|bool Optionally returns the priority on that hook for the specified function. |
307
|
|
|
* @global array $yourls_filters storage for all of the filters |
308
|
|
|
*/ |
309
|
|
|
function yourls_has_filter( $hook, $function_to_check = false ) { |
310
|
26 |
|
global $yourls_filters; |
311
|
|
|
|
312
|
26 |
|
$has = !empty( $yourls_filters[ $hook ] ); |
313
|
26 |
|
if ( false === $function_to_check || false === $has ) { |
314
|
26 |
|
return $has; |
315
|
|
|
} |
316
|
|
|
|
317
|
4 |
|
if ( !$idx = yourls_filter_unique_id( $hook, $function_to_check, false ) ) { |
318
|
|
|
return false; |
319
|
|
|
} |
320
|
|
|
|
321
|
4 |
|
foreach ( array_keys( $yourls_filters[ $hook ] ) as $priority ) { |
322
|
4 |
|
if ( isset( $yourls_filters[ $hook ][ $priority ][ $idx ] ) ) { |
323
|
4 |
|
return $priority; |
324
|
|
|
} |
325
|
|
|
} |
326
|
1 |
|
return false; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* @param string $hook |
331
|
|
|
* @param callable|false $function_to_check |
332
|
|
|
* @return bool|int |
333
|
|
|
*/ |
334
|
|
|
function yourls_has_action( $hook, $function_to_check = false ) { |
335
|
13 |
|
return yourls_has_filter( $hook, $function_to_check ); |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* Return number of active plugins |
340
|
|
|
* |
341
|
|
|
* @return int Number of activated plugins |
342
|
|
|
*/ |
343
|
|
|
function yourls_has_active_plugins() { |
344
|
15 |
|
return count( yourls_get_db()->get_plugins() ); |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
/** |
348
|
|
|
* List plugins in /user/plugins |
349
|
|
|
* |
350
|
|
|
* @return array Array of [/plugindir/plugin.php]=>array('Name'=>'Ozh', 'Title'=>'Hello', ) |
351
|
|
|
*/ |
352
|
|
|
function yourls_get_plugins() { |
353
|
3 |
|
$plugins = (array)glob( YOURLS_PLUGINDIR.'/*/plugin.php' ); |
354
|
|
|
|
355
|
3 |
|
if ( is_array( $plugins ) ) { |
|
|
|
|
356
|
3 |
|
foreach ( $plugins as $key => $plugin ) { |
357
|
3 |
|
$plugins[ yourls_plugin_basename( $plugin ) ] = yourls_get_plugin_data( $plugin ); |
358
|
3 |
|
unset( $plugins[ $key ] ); |
359
|
|
|
} |
360
|
|
|
} |
361
|
|
|
|
362
|
3 |
|
return empty( $plugins ) ? [] : $plugins; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
/** |
366
|
|
|
* Check if a plugin is active |
367
|
|
|
* |
368
|
|
|
* @param string $plugin Physical path to plugin file |
369
|
|
|
* @return bool |
370
|
|
|
*/ |
371
|
|
|
function yourls_is_active_plugin( $plugin ) { |
372
|
5 |
|
return yourls_has_active_plugins() > 0 ? |
373
|
3 |
|
in_array( yourls_plugin_basename( $plugin ), yourls_get_db()->get_plugins() ) |
374
|
5 |
|
: false; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
/** |
378
|
|
|
* Parse a plugin header |
379
|
|
|
* |
380
|
|
|
* The plugin header has the following form: |
381
|
|
|
* /* |
382
|
|
|
* Plugin Name: <plugin name> |
383
|
|
|
* Plugin URI: <plugin home page> |
384
|
|
|
* Description: <plugin description> |
385
|
|
|
* Version: <plugin version number> |
386
|
|
|
* Author: <author name> |
387
|
|
|
* Author URI: <author home page> |
388
|
|
|
* * / |
389
|
|
|
* |
390
|
|
|
* Or in the form of a phpdoc block |
391
|
|
|
* /** |
392
|
|
|
* * Plugin Name: <plugin name> |
393
|
|
|
* * Plugin URI: <plugin home page> |
394
|
|
|
* * Description: <plugin description> |
395
|
|
|
* * Version: <plugin version number> |
396
|
|
|
* * Author: <author name> |
397
|
|
|
* * Author URI: <author home page> |
398
|
|
|
* * / |
399
|
|
|
* |
400
|
|
|
* @since 1.5 |
401
|
|
|
* @param string $file Physical path to plugin file |
402
|
|
|
* @return array Array of 'Field'=>'Value' from plugin comment header lines of the form "Field: Value" |
403
|
|
|
*/ |
404
|
|
|
function yourls_get_plugin_data( $file ) { |
405
|
8 |
|
$fp = fopen( $file, 'r' ); // assuming $file is readable, since yourls_load_plugins() filters this |
406
|
8 |
|
$data = fread( $fp, 8192 ); // get first 8kb |
407
|
8 |
|
fclose( $fp ); |
408
|
|
|
|
409
|
|
|
// Capture all the header within first comment block |
410
|
8 |
|
if ( !preg_match( '!.*?/\*(.*?)\*/!ms', $data, $matches ) ) |
411
|
|
|
return []; |
412
|
|
|
|
413
|
|
|
// Capture each line with "Something: some text" |
414
|
8 |
|
unset( $data ); |
415
|
8 |
|
$lines = preg_split( "[\n|\r]", $matches[ 1 ] ); |
416
|
8 |
|
unset( $matches ); |
417
|
|
|
|
418
|
8 |
|
$plugin_data = []; |
419
|
8 |
|
foreach ( $lines as $line ) { |
420
|
8 |
|
if ( !preg_match( '!(\s*)?\*?(\s*)?(.*?):\s+(.*)!', $line, $matches ) ) { |
421
|
8 |
|
continue; |
422
|
|
|
} |
423
|
|
|
|
424
|
6 |
|
$plugin_data[ trim($matches[3]) ] = yourls_esc_html(trim($matches[4])); |
425
|
|
|
} |
426
|
|
|
|
427
|
8 |
|
return $plugin_data; |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
/** |
431
|
|
|
* Include active plugins |
432
|
|
|
* |
433
|
|
|
* This function includes every 'YOURLS_PLUGINDIR/plugin_name/plugin.php' found in option 'active_plugins' |
434
|
|
|
* It will return a diagnosis array with the following keys: |
435
|
|
|
* (bool)'loaded' : true if plugin(s) loaded, false otherwise |
436
|
|
|
* (string)'info' : extra information |
437
|
|
|
* |
438
|
|
|
* @since 1.5 |
439
|
|
|
* @return array Array('loaded' => bool, 'info' => string) |
440
|
|
|
*/ |
441
|
|
|
function yourls_load_plugins() { |
442
|
|
|
// Don't load plugins when installing or updating |
443
|
1 |
|
if ( yourls_is_installing() OR yourls_is_upgrading() OR !yourls_is_installed() ) { |
444
|
|
|
return [ |
445
|
|
|
'loaded' => false, |
446
|
|
|
'info' => 'install/upgrade' |
447
|
|
|
]; |
448
|
|
|
} |
449
|
|
|
|
450
|
1 |
|
$active_plugins = (array)yourls_get_option( 'active_plugins' ); |
451
|
1 |
|
if ( empty( $active_plugins ) ) { |
452
|
|
|
return [ |
453
|
|
|
'loaded' => false, |
454
|
|
|
'info' => 'no active plugin' |
455
|
|
|
]; |
456
|
|
|
} |
457
|
|
|
|
458
|
1 |
|
$plugins = []; |
459
|
1 |
|
foreach ( $active_plugins as $key => $plugin ) { |
460
|
1 |
|
if ( yourls_validate_plugin_file( YOURLS_PLUGINDIR.'/'.$plugin ) ) { |
461
|
1 |
|
include_once( YOURLS_PLUGINDIR.'/'.$plugin ); |
462
|
1 |
|
$plugins[] = $plugin; |
463
|
1 |
|
unset( $active_plugins[ $key ] ); |
464
|
|
|
} |
465
|
|
|
} |
466
|
|
|
|
467
|
|
|
// Replace active plugin list with list of plugins we just activated |
468
|
1 |
|
yourls_get_db()->set_plugins( $plugins ); |
469
|
1 |
|
$info = count( $plugins ).' activated'; |
470
|
|
|
|
471
|
|
|
// $active_plugins should be empty now, if not, a plugin could not be find: remove it |
472
|
1 |
|
$missing_count = count( $active_plugins ); |
473
|
1 |
|
if ( $missing_count > 0 ) { |
474
|
1 |
|
yourls_update_option( 'active_plugins', $plugins ); |
475
|
1 |
|
$message = yourls_n( 'Could not find and deactivate plugin :', 'Could not find and deactivate plugins :', $missing_count ); |
476
|
1 |
|
$missing = '<strong>'.implode( '</strong>, <strong>', $active_plugins ).'</strong>'; |
477
|
1 |
|
yourls_add_notice( $message.' '.$missing ); |
478
|
1 |
|
$info .= ', '.$missing_count.' removed'; |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
return [ |
482
|
1 |
|
'loaded' => true, |
483
|
1 |
|
'info' => $info |
484
|
|
|
]; |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
/** |
488
|
|
|
* Check if a file is safe for inclusion (well, "safe", no guarantee) |
489
|
|
|
* |
490
|
|
|
* @param string $file Full pathname to a file |
491
|
|
|
* @return bool |
492
|
|
|
*/ |
493
|
|
|
function yourls_validate_plugin_file( $file ) { |
494
|
6 |
|
return false === strpos( $file, '..' ) |
495
|
6 |
|
&& false === strpos( $file, './' ) |
496
|
6 |
|
&& 'plugin.php' === substr( $file, -10 ) |
497
|
6 |
|
&& is_readable( $file ); |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
/** |
501
|
|
|
* Activate a plugin |
502
|
|
|
* |
503
|
|
|
* @param string $plugin Plugin filename (full or relative to plugins directory) |
504
|
|
|
* @return string|true string if error or true if success |
505
|
|
|
*/ |
506
|
|
|
function yourls_activate_plugin( $plugin ) { |
507
|
|
|
// validate file |
508
|
3 |
|
$plugin = yourls_plugin_basename( $plugin ); |
509
|
3 |
|
$plugindir = yourls_sanitize_filename( YOURLS_PLUGINDIR ); |
510
|
3 |
|
if ( !yourls_validate_plugin_file( $plugindir.'/'.$plugin ) ) { |
511
|
1 |
|
return yourls__( 'Not a valid plugin file' ); |
512
|
|
|
} |
513
|
|
|
|
514
|
|
|
// check not activated already |
515
|
2 |
|
$ydb = yourls_get_db(); |
516
|
2 |
|
if ( yourls_is_active_plugin( $plugin ) ) { |
517
|
1 |
|
return yourls__( 'Plugin already activated' ); |
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
// attempt activation. TODO: uber cool fail proof sandbox like in WP. |
521
|
1 |
|
ob_start(); |
522
|
1 |
|
include_once( $plugindir.'/'.$plugin ); |
523
|
1 |
|
if ( ob_get_length() > 0 ) { |
524
|
|
|
// there was some output: error |
525
|
|
|
// @codeCoverageIgnoreStart |
526
|
|
|
$output = ob_get_clean(); |
527
|
|
|
return yourls_s( 'Plugin generated unexpected output. Error was: <br/><pre>%s</pre>', $output ); |
528
|
|
|
// @codeCoverageIgnoreEnd |
529
|
|
|
} |
530
|
1 |
|
ob_end_clean(); |
531
|
|
|
|
532
|
|
|
// so far, so good: update active plugin list |
533
|
1 |
|
$ydb->add_plugin( $plugin ); |
534
|
1 |
|
yourls_update_option( 'active_plugins', $ydb->get_plugins() ); |
535
|
1 |
|
yourls_do_action( 'activated_plugin', $plugin ); |
536
|
1 |
|
yourls_do_action( 'activated_'.$plugin ); |
537
|
|
|
|
538
|
1 |
|
return true; |
539
|
|
|
} |
540
|
|
|
|
541
|
|
|
/** |
542
|
|
|
* Deactivate a plugin |
543
|
|
|
* |
544
|
|
|
* @param string $plugin Plugin filename (full relative to plugins directory) |
545
|
|
|
* @return string|true string if error or true if success |
546
|
|
|
*/ |
547
|
|
|
function yourls_deactivate_plugin( $plugin ) { |
548
|
2 |
|
$plugin = yourls_plugin_basename( $plugin ); |
549
|
|
|
|
550
|
|
|
// Check plugin is active |
551
|
2 |
|
if ( !yourls_is_active_plugin( $plugin ) ) { |
552
|
1 |
|
return yourls__( 'Plugin not active' ); |
553
|
|
|
} |
554
|
|
|
|
555
|
|
|
// Deactivate the plugin |
556
|
1 |
|
$ydb = yourls_get_db(); |
557
|
1 |
|
$plugins = $ydb->get_plugins(); |
558
|
1 |
|
$key = array_search( $plugin, $plugins ); |
559
|
1 |
|
if ( $key !== false ) { |
560
|
1 |
|
array_splice( $plugins, $key, 1 ); |
561
|
|
|
} |
562
|
|
|
|
563
|
1 |
|
$ydb->set_plugins( $plugins ); |
564
|
1 |
|
yourls_update_option( 'active_plugins', $plugins ); |
565
|
1 |
|
yourls_do_action( 'deactivated_plugin', $plugin ); |
566
|
1 |
|
yourls_do_action( 'deactivated_'.$plugin ); |
567
|
|
|
|
568
|
1 |
|
return true; |
569
|
|
|
} |
570
|
|
|
|
571
|
|
|
/** |
572
|
|
|
* Return the path of a plugin file, relative to the plugins directory |
573
|
|
|
* @param string $file |
574
|
|
|
* @return string |
575
|
|
|
*/ |
576
|
|
|
function yourls_plugin_basename( $file ) { |
577
|
11 |
|
return trim( str_replace( yourls_sanitize_filename( YOURLS_PLUGINDIR ), '', yourls_sanitize_filename( $file ) ), '/' ); |
578
|
|
|
} |
579
|
|
|
|
580
|
|
|
/** |
581
|
|
|
* Return the URL of the directory a plugin |
582
|
|
|
* @param string $file |
583
|
|
|
* @return string |
584
|
|
|
*/ |
585
|
|
|
function yourls_plugin_url( $file ) { |
586
|
4 |
|
$url = YOURLS_PLUGINURL.'/'.yourls_plugin_basename( $file ); |
587
|
4 |
|
if ( yourls_is_ssl() or yourls_needs_ssl() ) { |
588
|
3 |
|
$url = str_replace( 'http://', 'https://', $url ); |
589
|
|
|
} |
590
|
4 |
|
return (string)yourls_apply_filter( 'plugin_url', $url, $file ); |
591
|
|
|
} |
592
|
|
|
|
593
|
|
|
/** |
594
|
|
|
* Build list of links to plugin admin pages, if any |
595
|
|
|
* |
596
|
|
|
* @return array[] Array of arrays of URL and anchor of plugin admin pages, or void if no plugin page |
597
|
|
|
*/ |
598
|
|
|
function yourls_list_plugin_admin_pages() { |
599
|
1 |
|
$plugin_links = []; |
600
|
1 |
|
foreach ( yourls_get_db()->get_plugin_pages() as $plugin => $page ) { |
601
|
1 |
|
$plugin_links[ $plugin ] = [ |
602
|
1 |
|
'url' => yourls_admin_url( 'plugins.php?page='.$page[ 'slug' ] ), |
603
|
1 |
|
'anchor' => $page[ 'title' ], |
604
|
|
|
]; |
605
|
|
|
} |
606
|
1 |
|
return $plugin_links; |
607
|
|
|
} |
608
|
|
|
|
609
|
|
|
/** |
610
|
|
|
* Register a plugin administration page |
611
|
|
|
* @param string $slug |
612
|
|
|
* @param string $title |
613
|
|
|
* @param callable $function |
614
|
|
|
*/ |
615
|
|
|
function yourls_register_plugin_page( $slug, $title, $function ) { |
616
|
4 |
|
yourls_get_db()->add_plugin_page( $slug, $title, $function ); |
617
|
4 |
|
} |
618
|
|
|
|
619
|
|
|
/** |
620
|
|
|
* Handle plugin administration page |
621
|
|
|
* |
622
|
|
|
* @param string $plugin_page |
623
|
|
|
*/ |
624
|
|
|
function yourls_plugin_admin_page( $plugin_page ) { |
625
|
|
|
// Check the plugin page is actually registered |
626
|
3 |
|
$pages = yourls_get_db()->get_plugin_pages(); |
627
|
3 |
|
if ( !isset( $pages[ $plugin_page ] ) ) { |
628
|
1 |
|
yourls_die( yourls__( 'This page does not exist. Maybe a plugin you thought was activated is inactive?' ), yourls__( 'Invalid link' ) ); |
629
|
|
|
} |
630
|
|
|
|
631
|
|
|
// Check the plugin page function is actually callable |
632
|
2 |
|
$page_function = $pages[ $plugin_page ][ 'function' ]; |
633
|
2 |
|
if (!is_callable($page_function)) { |
634
|
1 |
|
yourls_die( yourls__( 'This page cannot be displayed because the displaying function is not callable.' ), yourls__( 'Invalid code' ) ); |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
// Draw the page itself |
638
|
1 |
|
yourls_do_action( 'load-'.$plugin_page ); |
639
|
1 |
|
yourls_html_head( 'plugin_page_'.$plugin_page, $pages[ $plugin_page ][ 'title' ] ); |
640
|
1 |
|
yourls_html_logo(); |
641
|
1 |
|
yourls_html_menu(); |
642
|
|
|
|
643
|
1 |
|
$page_function( ); |
644
|
|
|
|
645
|
1 |
|
yourls_html_footer(); |
646
|
1 |
|
} |
647
|
|
|
|
648
|
|
|
/** |
649
|
|
|
* Callback function: Sort plugins |
650
|
|
|
* |
651
|
|
|
* @link http://php.net/uasort |
652
|
|
|
* @codeCoverageIgnore |
653
|
|
|
* |
654
|
|
|
* @param array $plugin_a |
655
|
|
|
* @param array $plugin_b |
656
|
|
|
* @return int 0, 1 or -1, see uasort() |
657
|
|
|
*/ |
658
|
|
|
function yourls_plugins_sort_callback( $plugin_a, $plugin_b ) { |
659
|
|
|
$orderby = yourls_apply_filter( 'plugins_sort_callback', 'Plugin Name' ); |
660
|
|
|
$order = yourls_apply_filter( 'plugins_sort_callback', 'ASC' ); |
661
|
|
|
|
662
|
|
|
$a = isset( $plugin_a[ $orderby ] ) ? $plugin_a[ $orderby ] : ''; |
663
|
|
|
$b = isset( $plugin_b[ $orderby ] ) ? $plugin_b[ $orderby ] : ''; |
664
|
|
|
|
665
|
|
|
if ( $a == $b ) { |
666
|
|
|
return 0; |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
if ( 'DESC' == $order ) { |
670
|
|
|
return ( $a < $b ) ? 1 : -1; |
671
|
|
|
} |
672
|
|
|
else { |
673
|
|
|
return ( $a < $b ) ? -1 : 1; |
674
|
|
|
} |
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
/** |
678
|
|
|
* Shutdown function, runs just before PHP shuts down execution. Stolen from WP |
679
|
|
|
* |
680
|
|
|
* This function is automatically tied to the script execution end at startup time, see |
681
|
|
|
* var $actions->register_shutdown in includes/Config/Init.php |
682
|
|
|
* |
683
|
|
|
* You can use this function to fire one or several actions when the PHP execution ends. |
684
|
|
|
* Example of use: |
685
|
|
|
* yourls_add_action('shutdown', 'my_plugin_action_this'); |
686
|
|
|
* yourls_add_action('shutdown', 'my_plugin_action_that'); |
687
|
|
|
* // functions my_plugin_action_this() and my_plugin_action_that() will be triggered |
688
|
|
|
* // after YOURLS is completely executed |
689
|
|
|
* |
690
|
|
|
* @since 1.5.1 |
691
|
|
|
* @return void |
692
|
|
|
*/ |
693
|
|
|
function yourls_shutdown() { |
694
|
|
|
yourls_do_action( 'shutdown' ); |
695
|
|
|
} |
696
|
|
|
|
697
|
|
|
/** |
698
|
|
|
* Returns true. |
699
|
|
|
* |
700
|
|
|
* Useful for returning true to filters easily. |
701
|
|
|
* |
702
|
|
|
* @since 1.7.1 |
703
|
|
|
* @return bool True. |
704
|
|
|
*/ |
705
|
|
|
function yourls_return_true() { |
706
|
35 |
|
return true; |
707
|
|
|
} |
708
|
|
|
|
709
|
|
|
/** |
710
|
|
|
* Returns false. |
711
|
|
|
* |
712
|
|
|
* Useful for returning false to filters easily. |
713
|
|
|
* |
714
|
|
|
* @since 1.7.1 |
715
|
|
|
* @return bool False. |
716
|
|
|
*/ |
717
|
|
|
function yourls_return_false() { |
718
|
16 |
|
return false; |
719
|
|
|
} |
720
|
|
|
|
721
|
|
|
/** |
722
|
|
|
* Returns 0. |
723
|
|
|
* |
724
|
|
|
* Useful for returning 0 to filters easily. |
725
|
|
|
* |
726
|
|
|
* @since 1.7.1 |
727
|
|
|
* @return int 0. |
728
|
|
|
*/ |
729
|
|
|
function yourls_return_zero() { |
730
|
1 |
|
return 0; |
731
|
|
|
} |
732
|
|
|
|
733
|
|
|
/** |
734
|
|
|
* Returns an empty array. |
735
|
|
|
* |
736
|
|
|
* Useful for returning an empty array to filters easily. |
737
|
|
|
* |
738
|
|
|
* @since 1.7.1 |
739
|
|
|
* @return array Empty array. |
740
|
|
|
*/ |
741
|
|
|
function yourls_return_empty_array() { |
742
|
4 |
|
return []; |
743
|
|
|
} |
744
|
|
|
|
745
|
|
|
/** |
746
|
|
|
* Returns null. |
747
|
|
|
* |
748
|
|
|
* Useful for returning null to filters easily. |
749
|
|
|
* |
750
|
|
|
* @since 1.7.1 |
751
|
|
|
* @return null Null value. |
752
|
|
|
*/ |
753
|
|
|
function yourls_return_null() { |
754
|
|
|
return null; |
755
|
|
|
} |
756
|
|
|
|
757
|
|
|
/** |
758
|
|
|
* Returns an empty string. |
759
|
|
|
* |
760
|
|
|
* Useful for returning an empty string to filters easily. |
761
|
|
|
* |
762
|
|
|
* @since 1.7.1 |
763
|
|
|
* @return string Empty string. |
764
|
|
|
*/ |
765
|
|
|
function yourls_return_empty_string() { |
766
|
|
|
return ''; |
767
|
|
|
} |
768
|
|
|
|