1
|
|
|
<?php namespace XoopsModules\Marquee; |
2
|
|
|
|
3
|
|
|
use \XoopsModules\Marquee; |
4
|
|
|
use \XoopsModules\Marquee\Common; |
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* Class Utility |
8
|
|
|
*/ |
9
|
|
|
class Utility |
10
|
|
|
{ |
11
|
|
|
use Common\VersionChecks; //checkVerXoops, checkVerPhp Traits |
12
|
|
|
|
13
|
|
|
use Common\ServerStats; // getServerStats Trait |
14
|
|
|
|
15
|
|
|
use Common\FilesManagement; // Files Management Trait |
16
|
|
|
|
17
|
|
|
//--------------- Custom module methods ----------------------------- |
18
|
|
|
const MODULE_NAME = 'marquee'; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* truncateHtml can truncate a string up to a number of characters while preserving whole words and HTML tags |
22
|
|
|
* www.gsdesign.ro/blog/cut-html-string-without-breaking-the-tags |
23
|
|
|
* www.cakephp.org |
24
|
|
|
* |
25
|
|
|
* @param string $text String to truncate. |
26
|
|
|
* @param integer $length Length of returned string, including ellipsis. |
27
|
|
|
* @param string $ending Ending to be appended to the trimmed string. |
28
|
|
|
* @param boolean $exact If false, $text will not be cut mid-word |
29
|
|
|
* @param boolean $considerHtml If true, HTML tags would be handled correctly |
30
|
|
|
* |
31
|
|
|
* @return string Trimmed string. |
32
|
|
|
*/ |
33
|
|
|
public static function truncateHtml($text, $length = 100, $ending = '...', $exact = false, $considerHtml = true) |
34
|
|
|
{ |
35
|
|
|
if ($considerHtml) { |
36
|
|
|
// if the plain text is shorter than the maximum length, return the whole text |
37
|
|
|
if (strlen(preg_replace('/<.*?' . '>/', '', $text)) <= $length) { |
38
|
|
|
return $text; |
39
|
|
|
} |
40
|
|
|
// splits all html-tags to scanable lines |
41
|
|
|
preg_match_all('/(<.+?' . '>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER); |
42
|
|
|
$total_length = strlen($ending); |
43
|
|
|
$open_tags = []; |
44
|
|
|
$truncate = ''; |
45
|
|
|
foreach ($lines as $line_matchings) { |
46
|
|
|
// if there is any html-tag in this line, handle it and add it (uncounted) to the output |
47
|
|
|
if (!empty($line_matchings[1])) { |
48
|
|
|
// if it's an "empty element" with or without xhtml-conform closing slash |
49
|
|
|
if (preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) { |
|
|
|
|
50
|
|
|
// do nothing |
51
|
|
|
// if tag is a closing tag |
52
|
|
|
} elseif (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) { |
53
|
|
|
// delete tag from $open_tags list |
54
|
|
|
$pos = array_search($tag_matchings[1], $open_tags); |
55
|
|
|
if (false !== $pos) { |
56
|
|
|
unset($open_tags[$pos]); |
57
|
|
|
} |
58
|
|
|
// if tag is an opening tag |
59
|
|
|
} elseif (preg_match('/^<\s*([^\s>!]+).*?' . '>$/s', $line_matchings[1], $tag_matchings)) { |
60
|
|
|
// add tag to the beginning of $open_tags list |
61
|
|
|
array_unshift($open_tags, strtolower($tag_matchings[1])); |
62
|
|
|
} |
63
|
|
|
// add html-tag to $truncate'd text |
64
|
|
|
$truncate .= $line_matchings[1]; |
65
|
|
|
} |
66
|
|
|
// calculate the length of the plain text part of the line; handle entities as one character |
67
|
|
|
$content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2])); |
68
|
|
|
if ($total_length + $content_length > $length) { |
69
|
|
|
// the number of characters which are left |
70
|
|
|
$left = $length - $total_length; |
71
|
|
|
$entities_length = 0; |
72
|
|
|
// search for html entities |
73
|
|
|
if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities, PREG_OFFSET_CAPTURE)) { |
74
|
|
|
// calculate the real length of all entities in the legal range |
75
|
|
|
foreach ($entities[0] as $entity) { |
76
|
|
|
if ($entity[1] + 1 - $entities_length <= $left) { |
77
|
|
|
$left--; |
78
|
|
|
$entities_length += strlen($entity[0]); |
79
|
|
|
} else { |
80
|
|
|
// no more characters left |
81
|
|
|
break; |
82
|
|
|
} |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
$truncate .= substr($line_matchings[2], 0, $left + $entities_length); |
86
|
|
|
// maximum lenght is reached, so get off the loop |
87
|
|
|
break; |
88
|
|
|
} else { |
89
|
|
|
$truncate .= $line_matchings[2]; |
90
|
|
|
$total_length += $content_length; |
91
|
|
|
} |
92
|
|
|
// if the maximum length is reached, get off the loop |
93
|
|
|
if ($total_length >= $length) { |
94
|
|
|
break; |
95
|
|
|
} |
96
|
|
|
} |
97
|
|
|
} else { |
98
|
|
|
if (strlen($text) <= $length) { |
99
|
|
|
return $text; |
100
|
|
|
} else { |
101
|
|
|
$truncate = substr($text, 0, $length - strlen($ending)); |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
// if the words shouldn't be cut in the middle... |
105
|
|
|
if (!$exact) { |
106
|
|
|
// ...search the last occurance of a space... |
107
|
|
|
$spacepos = strrpos($truncate, ' '); |
108
|
|
|
if (isset($spacepos)) { |
109
|
|
|
// ...and cut the text in this position |
110
|
|
|
$truncate = substr($truncate, 0, $spacepos); |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
// add the defined ending to the text |
114
|
|
|
$truncate .= $ending; |
115
|
|
|
if ($considerHtml) { |
116
|
|
|
// close all unclosed html-tags |
117
|
|
|
foreach ($open_tags as $tag) { |
|
|
|
|
118
|
|
|
$truncate .= '</' . $tag . '>'; |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
return $truncate; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Access the only instance of this class |
127
|
|
|
* |
128
|
|
|
* @return \XoopsModules\Marquee\Utility |
129
|
|
|
* |
130
|
|
|
* @static |
131
|
|
|
* @staticvar object |
132
|
|
|
*/ |
133
|
|
|
public static function getInstance() |
134
|
|
|
{ |
135
|
|
|
static $instance; |
136
|
|
|
if (null === $instance) { |
137
|
|
|
$instance = new static(); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $instance; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Returns a module's option (with cache) |
145
|
|
|
* |
146
|
|
|
* @param string $option module option's name |
147
|
|
|
* @param boolean $withCache Do we have to use some cache ? |
148
|
|
|
* |
149
|
|
|
* @return mixed option's value |
150
|
|
|
*/ |
151
|
|
|
// public static function getModuleOption($option, $withCache = true) |
|
|
|
|
152
|
|
|
// { |
153
|
|
|
// global $xoopsModuleConfig, $xoopsModule; |
154
|
|
|
// $repmodule = self::MODULE_NAME; |
155
|
|
|
// static $options = []; |
156
|
|
|
// if (is_array($options) && array_key_exists($option, $options) && $withCache) { |
157
|
|
|
// return $options[$option]; |
158
|
|
|
// } |
159
|
|
|
// |
160
|
|
|
// $retval = false; |
161
|
|
|
// if (null !== $xoopsModuleConfig && (is_object($xoopsModule) && ($xoopsModule->getVar('dirname') == $repmodule) && $xoopsModule->getVar('isactive'))) { |
162
|
|
|
// if (isset($xoopsModuleConfig[$option])) { |
163
|
|
|
// $retval = $xoopsModuleConfig[$option]; |
164
|
|
|
// } |
165
|
|
|
// } else { |
166
|
|
|
// /** @var \XoopsModuleHandler $moduleHandler */ |
167
|
|
|
// $moduleHandler = xoops_getHandler('module'); |
168
|
|
|
// $module = $moduleHandler->getByDirname($repmodule); |
169
|
|
|
// $configHandler = xoops_getHandler('config'); |
170
|
|
|
// if ($module) { |
171
|
|
|
// $moduleConfig = $configHandler->getConfigsByCat(0, $module->getVar('mid')); |
172
|
|
|
// if (isset($moduleConfig[$option])) { |
173
|
|
|
// $retval = $moduleConfig[$option]; |
174
|
|
|
// } |
175
|
|
|
// } |
176
|
|
|
// } |
177
|
|
|
// $options[$option] = $retval; |
178
|
|
|
// |
179
|
|
|
// return $retval; |
180
|
|
|
// } |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Is Xoops 2.3.x ? |
184
|
|
|
* |
185
|
|
|
* @return boolean need to say it ? |
186
|
|
|
*/ |
187
|
|
|
// function isX23() |
|
|
|
|
188
|
|
|
// { |
189
|
|
|
// $x23 = false; |
|
|
|
|
190
|
|
|
// $xv = str_replace('XOOPS ', '', XOOPS_VERSION); |
|
|
|
|
191
|
|
|
// if ((int)(substr($xv, 2, 1)) >= 3) { |
|
|
|
|
192
|
|
|
// $x23 = true; |
|
|
|
|
193
|
|
|
// } |
194
|
|
|
// |
195
|
|
|
// return $x23; |
196
|
|
|
// } |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Retreive an editor according to the module's option "form_options" |
200
|
|
|
* |
201
|
|
|
* @param string $caption Caption to give to the editor |
202
|
|
|
* @param string $name Editor's name |
203
|
|
|
* @param string $value Editor's value |
204
|
|
|
* @param string $width Editor's width |
205
|
|
|
* @param string $height Editor's height |
206
|
|
|
* @param string $supplemental |
207
|
|
|
* |
208
|
|
|
* @return \XoopsFormDhtmlTextArea|\XoopsFormEditor The editor to use |
209
|
|
|
*/ |
210
|
|
|
public static function getWysiwygForm( |
211
|
|
|
$caption, |
212
|
|
|
$name, |
213
|
|
|
$value = '', |
214
|
|
|
$width = '100%', |
|
|
|
|
215
|
|
|
$height = '400px', |
|
|
|
|
216
|
|
|
$supplemental = '' |
|
|
|
|
217
|
|
|
) { |
218
|
|
|
|
219
|
|
|
/** @var Marquee\Helper $helper */ |
220
|
|
|
$helper = Marquee\Helper::getInstance(); |
221
|
|
|
|
222
|
|
|
if (class_exists('XoopsFormEditor')) { |
223
|
|
|
$options['name'] = $name; |
|
|
|
|
224
|
|
|
$options['value'] = $value; |
225
|
|
|
$options['rows'] = 35; |
226
|
|
|
$options['cols'] = '100%'; |
227
|
|
|
$options['width'] = '100%'; |
228
|
|
|
$options['height'] = '400px'; |
229
|
|
|
$editor = new \XoopsFormEditor($caption, $helper->getConfig('form_options'), $options, $nohtml = false, $onfailure = 'textarea'); |
|
|
|
|
230
|
|
|
} else { |
231
|
|
|
$editor = new \XoopsFormDhtmlTextArea($caption, $name, $value, '100%', '100%'); |
|
|
|
|
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
return $editor; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* Create (in a link) a javascript confirmation's box |
239
|
|
|
* |
240
|
|
|
* @param string $message Message to display |
241
|
|
|
* @param boolean $form Is this a confirmation for a form ? |
242
|
|
|
* |
243
|
|
|
* @return string the javascript code to insert in the link (or in the form) |
244
|
|
|
*/ |
245
|
|
|
public static function javascriptLinkConfirm($message, $form = false) |
246
|
|
|
{ |
247
|
|
|
if (!$form) { |
248
|
|
|
return "onclick=\"javascript:return confirm('" . str_replace("'", ' ', $message) . "')\""; |
249
|
|
|
} else { |
250
|
|
|
return "onSubmit=\"javascript:return confirm('" . str_replace("'", ' ', $message) . "')\""; |
251
|
|
|
} |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Redirect user with a message |
256
|
|
|
* |
257
|
|
|
* @param string $message message to display |
258
|
|
|
* @param string $url The place where to go |
259
|
|
|
* @param integer timeout Time to wait before to redirect |
|
|
|
|
260
|
|
|
*/ |
261
|
|
|
public static function redirect($message = '', $url = 'index.php', $time = 2) |
262
|
|
|
{ |
263
|
|
|
redirect_header($url, $time, $message); |
|
|
|
|
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Internal function used to get the handler of the current module |
268
|
|
|
* @deprecated use $helper->getModule(); |
269
|
|
|
* @return \XoopsModule The module |
270
|
|
|
*/ |
271
|
|
|
protected static function getModule() |
272
|
|
|
{ |
273
|
|
|
$moduleDirName = basename(dirname(__DIR__)); |
274
|
|
|
static $mymodule; |
275
|
|
|
if (null === $mymodule) { |
276
|
|
|
global $xoopsModule; |
|
|
|
|
277
|
|
|
if (null !== $xoopsModule && is_object($xoopsModule) && $moduleDirName == $xoopsModule->getVar('dirname')) { |
278
|
|
|
$mymodule = $xoopsModule; |
279
|
|
|
} else { |
280
|
|
|
$hModule = xoops_getHandler('module'); |
|
|
|
|
281
|
|
|
$mymodule = $hModule->getByDirname($moduleDirName); |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
return $mymodule; |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* This function indicates if the current Xoops version needs to add asterisks to required fields in forms |
291
|
|
|
* |
292
|
|
|
* @return boolean Yes = we need to add them, false = no |
293
|
|
|
*/ |
294
|
|
|
public static function needsAsterisk() |
295
|
|
|
{ |
296
|
|
|
if (false === stripos(XOOPS_VERSION, 'legacy')) { |
|
|
|
|
297
|
|
|
$xv = xoops_trim(str_replace('XOOPS ', '', XOOPS_VERSION)); |
|
|
|
|
298
|
|
|
if ((int)substr($xv, 4, 2) >= 17) { |
299
|
|
|
return false; |
300
|
|
|
} |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
return true; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* Mark the mandatory fields of a form with a star |
308
|
|
|
* |
309
|
|
|
* @param \XoopsThemeForm $sform The form to modify |
|
|
|
|
310
|
|
|
* |
311
|
|
|
* @internal param string $caracter The character to use to mark fields |
312
|
|
|
* @return \XoopsThemeForm The modified form |
313
|
|
|
*/ |
314
|
|
|
public static function formMarkRequiredFields(&$sform) |
315
|
|
|
{ |
316
|
|
|
$required = $elements = []; |
|
|
|
|
317
|
|
|
if (self::needsAsterisk()) { |
318
|
|
|
foreach ($sform->getRequired() as $item) { |
319
|
|
|
$required[] = $item->_name; |
320
|
|
|
} |
321
|
|
|
$elements =& $sform->getElements(); |
322
|
|
|
foreach ($elements as $i => $iValue) { |
323
|
|
|
if (is_object($elements[$i]) && in_array($iValue->_name, $required)) { |
324
|
|
|
$iValue->_caption .= ' *'; |
325
|
|
|
} |
326
|
|
|
} |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
return $sform; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* @param $option |
334
|
|
|
* @param string $repmodule |
335
|
|
|
* @return bool |
336
|
|
|
*/ |
337
|
|
|
public static function getModuleOption($option, $repmodule = 'marquee') |
338
|
|
|
{ |
339
|
|
|
global $xoopsModule; |
|
|
|
|
340
|
|
|
/** @var Marquee\Helper $helper */ |
341
|
|
|
$helper = Marquee\Helper::getInstance(); |
342
|
|
|
|
343
|
|
|
static $tbloptions = []; |
344
|
|
|
if (is_array($tbloptions) && array_key_exists($option, $tbloptions)) { |
345
|
|
|
return $tbloptions[$option]; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
$retval = false; |
349
|
|
|
if (null !== $helper->getModule() |
350
|
|
|
&& (is_object($xoopsModule) && $xoopsModule->getVar('dirname') == $repmodule |
351
|
|
|
&& $xoopsModule->getVar('isactive'))) { |
352
|
|
|
if ('' !== ($helper->getConfig($option))) { |
353
|
|
|
$retval = $helper->getConfig($option); |
354
|
|
|
} |
355
|
|
|
} else { |
356
|
|
|
/** @var \XoopsModuleHandler $moduleHandler */ |
357
|
|
|
$moduleHandler = xoops_getHandler('module'); |
|
|
|
|
358
|
|
|
$module = $moduleHandler->getByDirname($repmodule); |
359
|
|
|
$configHandler = xoops_getHandler('config'); |
360
|
|
|
if ($module) { |
361
|
|
|
$moduleConfig = $configHandler->getConfigsByCat(0, $module->getVar('mid')); |
362
|
|
|
if (isset($moduleConfig[$option])) { |
363
|
|
|
$retval = $moduleConfig[$option]; |
364
|
|
|
} |
365
|
|
|
} |
366
|
|
|
} |
367
|
|
|
$tbloptions[$option] = $retval; |
368
|
|
|
|
369
|
|
|
return $retval; |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
/** |
373
|
|
|
* Verify if the current "user" is a bot or not |
374
|
|
|
* |
375
|
|
|
* If you have a problem with this function, insert the folowing code just before the line if (isset($_SESSION['news_cache_bot'])) { : |
376
|
|
|
* return false; |
377
|
|
|
* |
378
|
|
|
* @package Marquee |
379
|
|
|
* @author Hervé Thouzard (http://www.herve-thouzard.com) |
380
|
|
|
* @copyright (c) Hervé Thouzard |
381
|
|
|
*/ |
382
|
|
|
public static function isBot() |
383
|
|
|
{ |
384
|
|
|
if (isset($_SESSION['marquee_cache_bot'])) { |
385
|
|
|
return $_SESSION['marquee_cache_bot']; |
386
|
|
|
} else { |
387
|
|
|
// Add here every bot you know separated by a pipe | (not matter with the upper or lower cases) |
388
|
|
|
// If you want to see the result for yourself, add your navigator's user agent at the end (mozilla for example) |
389
|
|
|
$botlist = 'AbachoBOT|Arachnoidea|ASPSeek|Atomz|cosmos|crawl25-public.alexa.com|CrawlerBoy Pinpoint.com|Crawler|DeepIndex|EchO!|exabot|Excalibur Internet Spider|FAST-WebCrawler|Fluffy the spider|GAIS Robot/1.0B2|GaisLab data gatherer|Google|Googlebot-Image|googlebot|Gulliver|ia_archiver|Infoseek|Links2Go|Lycos_Spider_(modspider)|Lycos_Spider_(T-Rex)|MantraAgent|Mata Hari|Mercator|MicrosoftPrototypeCrawler|[email protected]|MSNBOT|NEC Research Agent|NetMechanic|Nokia-WAPToolkit|nttdirectory_robot|Openfind|Oracle Ultra Search|PicoSearch|Pompos|Scooter|Slider_Search_v1-de|Slurp|Slurp.so|SlySearch|Spider|Spinne|SurferF3|Surfnomore Spider|suzuran|teomaagent1|TurnitinBot|Ultraseek|VoilaBot|vspider|W3C_Validator|Web Link Validator|WebTrends|WebZIP|whatUseek_winona|WISEbot|Xenu Link Sleuth|ZyBorg'; |
390
|
|
|
$botlist = strtoupper($botlist); |
391
|
|
|
$currentagent = strtoupper(xoops_getenv('HTTP_USER_AGENT')); |
|
|
|
|
392
|
|
|
$retval = false; |
393
|
|
|
$botarray = explode('|', $botlist); |
394
|
|
|
foreach ($botarray as $onebot) { |
395
|
|
|
if (false !== strpos($currentagent, $onebot)) { |
396
|
|
|
$retval = true; |
397
|
|
|
break; |
398
|
|
|
} |
399
|
|
|
} |
400
|
|
|
} |
401
|
|
|
$_SESSION['marquee_cache_bot'] = $retval; |
402
|
|
|
|
403
|
|
|
return $retval; |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
/** |
407
|
|
|
* Escape a string so that it can be included in a javascript string |
408
|
|
|
* |
409
|
|
|
* @param $string |
410
|
|
|
* |
411
|
|
|
* @return mixed |
412
|
|
|
*/ |
413
|
|
|
public static function javascriptEscape($string) |
414
|
|
|
{ |
415
|
|
|
return str_replace("'", "\\'", $string); |
416
|
|
|
} |
417
|
|
|
} |
418
|
|
|
|
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.