~quam-plures-core/quam-plures/file_manager_limits

« back to all changes in this revision

Viewing changes to qp_inc/_core/_misc.funcs.php

  • Committer: EdB
  • Date: 2013-03-04 07:15:41 UTC
  • mfrom: (7655.1.3 qp5_antispam)
  • Revision ID: 1912webworks@gmail.com-20130304071541-x462crs4d531rh69
http://forums.quamplures.net/viewtopic.php?f=6&t=1887

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
<?php
2
2
/**
3
 
 * This file implements general purpose functions.
4
 
 *
5
 
 * This file is part of Quam Plures - {@link http://quamplures.net/}
6
 
 * See also {@link https://launchpad.net/quam-plures}.
7
 
 *
8
 
 * @copyright (c) 2009 - 2011 by the Quam Plures developers - {@link http://quamplures.net/}
9
 
 * @copyright (c)2003-2009 by Francois PLANQUE - {@link http://fplanque.net/}
10
 
 * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
11
 
 * Parts of this file are copyright (c)2005-2006 by PROGIDISTRI - {@link http://progidistri.com/}.
12
 
 *
13
 
 * {@internal License choice
14
 
 * - If you have received this file as part of a package, please find the license.txt file in
15
 
 *   the same folder or the closest folder above for complete license terms.
16
 
 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
17
 
 *   then you must choose one of the following licenses before using the file:
18
 
 *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
19
 
 *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
20
 
 * }}
21
 
 *
22
 
 * {@internal Open Source relicensing agreement:
23
 
 * Daniel HAHLER grants Francois PLANQUE the right to license
24
 
 * Daniel HAHLER's contributions to this file and the b2evolution project
25
 
 * under any OSI approved OSS license (http://www.opensource.org/licenses/).
26
 
 *
27
 
 * PROGIDISTRI S.A.S. grants Francois PLANQUE the right to license
28
 
 * PROGIDISTRI S.A.S.'s contributions to this file and the b2evolution project
29
 
 * under any OSI approved OSS license (http://www.opensource.org/licenses/).
30
 
 * }}
31
 
 *
32
 
 * @todo dh> Refactor into smaller chunks/files. We should avoid using a "huge" misc early!
33
 
 *       - _debug.funcs.php
34
 
 *       - _formatting.funcs.php
35
 
 *       - _date.funcs.php
36
 
 *       - ?
37
 
 *       NOTE: Encapsulation functions into classes would allow using autoloading (http://php.net/autoload) in PHP5..!
38
 
 *
39
 
 * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
 
3
 * This file implements general purpose functions
 
4
 *
 
5
 * @todo (0000): dh> Refactor into smaller chunks/files. We should avoid using a
 
6
 * "huge" misc early!
 
7
 * - _debug.funcs.php
 
8
 * - _formatting.funcs.php
 
9
 * - _date.funcs.php
 
10
 * - ?
 
11
 *
 
12
 * @author {@link http://wonderwinds.com/ Ed Bennett}
 
13
 * @author {@link http://progidistri.com/ PROGIDISTRI}
 
14
 * @author {@link http://daniel.hahler.de/ Daniel HAHLER}
 
15
 * @author {@link http://funky-m.com/ Vegar BERG GULDAL}
 
16
 * @author {@link http://fplanque.net/ Francois PLANQUE}
 
17
 * @author {@link http://www.sakichan.org/ Nobuo SAKIYAMA}
 
18
 * @author {@link http://www.jeffbearer.com/ Jeff BEARER}
40
19
 * @author cafelog (team)
41
 
 * @author blueyed: Daniel HAHLER.
42
 
 * @author fplanque: Francois PLANQUE.
43
 
 * @author jeffbearer: Jeff BEARER.
44
 
 * @author sakichan: Nobuo SAKIYAMA.
45
 
 * @author vegarg: Vegar BERG GULDAL.
46
 
 * @author mbruneau: Marc BRUNEAU / PROGIDISTRI
47
 
 *
48
 
 * @package pond
49
 
 */
50
 
if( !defined('QP_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
51
 
 
52
 
 
53
 
/**
54
 
 * Dependencies
55
 
 */
56
 
load_funcs('antispam/model/_antispam.funcs.php');
57
 
load_funcs('files/model/_file.funcs.php');
58
 
 
 
20
 * @copyright (c) 2009 by {@link http://quamplures.net/ the Quam Plures project}
 
21
 * @license http://www.gnu.org/licenses/gpl.txt GNU General Public License v3
 
22
 * @package core
 
23
 */
 
24
if(!defined('QP_MAIN_INIT')) die('fail');
 
25
 
 
26
load_funcs( 'antispam/model/_antispam.funcs.php' );
 
27
load_funcs( 'files/model/_file.funcs.php' );
59
28
 
60
29
/**
61
30
 * Call a method for all modules in a row
75
44
 * Get a cache reference.
76
45
 *
77
46
 * @todo fp> split into 1 function per case. (typed @return values)
78
 
 *
79
47
 * @param string The cache to get (see source code for possible names).
80
48
 * @return mixed The requested cache (debug_die()s on invalid cache name).
81
49
 */
85
53
        global $$objectName;
86
54
 
87
55
        if( isset( $$objectName ) )
88
 
        {       // Cache already exists:
 
56
        {
 
57
                // Cache already exists
89
58
                return $$objectName;
90
59
        }
91
60
 
92
61
        switch( $objectName )
93
62
        {
94
63
                case 'BlogCache':
95
 
                        load_class( 'collections/model/_blogcache.class.php' );
96
 
                        $BlogCache = new BlogCache(); // COPY (FUNC)
97
 
                        return $BlogCache;
 
64
                $BlogCache = new BlogCache(); // COPY (FUNC)
 
65
                return $BlogCache;
98
66
 
99
67
                case 'ChapterCache':
100
 
                        load_class( 'chapters/model/_chaptercache.class.php' );
101
 
                        $ChapterCache = new ChapterCache(); // COPY (FUNC)
102
 
                        return $ChapterCache;
 
68
                $ChapterCache = new ChapterCache(); // COPY (FUNC)
 
69
                return $ChapterCache;
103
70
 
104
71
                case 'FileCache':
105
 
                        load_class( 'files/model/_filecache.class.php' );
106
 
                        $FileCache = new FileCache(); // COPY (FUNC)
107
 
                        return $FileCache;
 
72
                $FileCache = new FileCache(); // COPY (FUNC)
 
73
                return $FileCache;
108
74
 
109
75
                case 'FileRootCache':
110
 
                        load_class( 'files/model/_filerootcache.class.php' );
111
 
                        $Plugins->get_object_from_cacheplugin_or_create( 'FileRootCache' );
112
 
                        return $FileRootCache;
 
76
                $Plugins->get_object_from_cacheplugin_or_create( 'FileRootCache' );
 
77
                return $FileRootCache;
113
78
 
114
79
                case 'FiletypeCache':
115
 
                        load_class( 'files/model/_filetypecache.class.php' );
116
 
                        $Plugins->get_object_from_cacheplugin_or_create( 'FiletypeCache' );
117
 
                        return $FiletypeCache;
 
80
                $Plugins->get_object_from_cacheplugin_or_create( 'FiletypeCache' );
 
81
                return $FiletypeCache;
118
82
 
119
83
                case 'GoalCache';
120
 
                        $GoalCache = new DataObjectCache( 'Goal', false, 'T_track__goal', 'goal_', 'goal_ID', 'goal_name', 'goal_name' ); // COPY (FUNC)
121
 
                        return $GoalCache;
 
84
                $GoalCache = new DataObjectCache( 'Goal', false, 'T_track__goal', 'goal_', 'goal_ID', 'goal_name', 'goal_name' ); // COPY (FUNC)
 
85
                return $GoalCache;
122
86
 
123
87
                case 'GroupCache':
124
 
                        $Plugins->get_object_from_cacheplugin_or_create( 'GroupCache', 'new DataObjectCache( \'Group\', true, \'T_groups\', \'grp_\', \'grp_ID\', \'grp_name\', \'\', T_(\'No group\') )' );
125
 
                        return $GroupCache;
 
88
                $Plugins->get_object_from_cacheplugin_or_create( 'GroupCache', 'new DataObjectCache( \'Group\', true, \'T_groups\', \'grp_\', \'grp_ID\', \'grp_name\', \'\', T_(\'No group\') )' );
 
89
                return $GroupCache;
126
90
 
127
91
                case 'ItemCacheLight';
128
 
                        $ItemCacheLight = new DataObjectCache( 'ItemLight', false, 'T_items__item', 'post_', 'post_ID' ); // COPY (FUNC)
129
 
                        return $ItemCacheLight;
 
92
                $ItemCacheLight = new DataObjectCache( 'ItemLight', false, 'T_items__item', 'post_', 'post_ID' ); // COPY (FUNC)
 
93
                return $ItemCacheLight;
130
94
 
131
95
                case 'ItemCache';
132
 
                        load_class( 'items/model/_itemcache.class.php' );
133
 
                        $ItemCache = new ItemCache(); // COPY (FUNC)
134
 
                        return $ItemCache;
 
96
                $ItemCache = new ItemCache(); // COPY (FUNC)
 
97
                return $ItemCache;
135
98
 
136
99
                case 'ItemPrerenderingCache':
137
 
                        $ItemPrerenderingCache = array();
138
 
                        return $ItemPrerenderingCache;
 
100
                $ItemPrerenderingCache = array();
 
101
                return $ItemPrerenderingCache;
139
102
 
140
103
                case 'ItemTagsCache':
141
 
                        $ItemTagsCache = array();
142
 
                        return $ItemTagsCache;
 
104
                $ItemTagsCache = array();
 
105
                return $ItemTagsCache;
143
106
 
144
107
                case 'ItemCatsCache':
145
 
                        $ItemCatsCache = array();
146
 
                        return $ItemCatsCache;
 
108
                $ItemCatsCache = array();
 
109
                return $ItemCatsCache;
147
110
 
148
111
                case 'ItemStatusCache':
149
 
                        $Plugins->get_object_from_cacheplugin_or_create( 'ItemStatusCache', 'new GenericCache( \'GenericElement\', true, \'T_items__status\', \'pst_\', \'pst_ID\', NULL, \'\', T_(\'No status\') )' );
150
 
                        return $ItemStatusCache;
 
112
                $Plugins->get_object_from_cacheplugin_or_create( 'ItemStatusCache', 'new GenericCache( \'GenericElement\', true, \'T_items__status\', \'pst_\', \'pst_ID\', NULL, \'\', T_(\'No status\') )' );
 
113
                return $ItemStatusCache;
151
114
 
152
115
                case 'ItemTypeCache':
153
 
                        load_class( 'items/model/_itemtypecache.class.php' );
154
 
                        $Plugins->get_object_from_cacheplugin_or_create( 'ItemTypeCache', 'new ItemTypeCache( \'ptyp_\', \'ptyp_ID\' )' );
155
 
                        return $ItemTypeCache;
 
116
                $Plugins->get_object_from_cacheplugin_or_create( 'ItemTypeCache', 'new ItemTypeCache( \'ptyp_\', \'ptyp_ID\' )' );
 
117
                return $ItemTypeCache;
156
118
 
157
119
                case 'LinkCache':
158
 
                        load_class( 'items/model/_linkcache.class.php' );
159
 
                        $LinkCache = new LinkCache(); // COPY (FUNC)
160
 
                        return $LinkCache;
 
120
                $LinkCache = new LinkCache(); // COPY (FUNC)
 
121
                return $LinkCache;
161
122
 
162
123
                case 'Plugins_admin':
163
 
                        load_class('plugins/model/_plugins_admin.class.php');
164
 
                        $Plugins_admin = new Plugins_admin(); // COPY (FUNC)
165
 
                        return $Plugins_admin;
 
124
                $Plugins_admin = new Plugins_admin(); // COPY (FUNC)
 
125
                return $Plugins_admin;
166
126
 
167
127
                case 'TemplateCache':
168
 
                        load_class( 'templates/model/_templatecache.class.php' );
169
 
                        $TemplateCache = new TemplateCache(); // COPY (FUNC)
170
 
                        return $TemplateCache;
 
128
                $TemplateCache = new TemplateCache(); // COPY (FUNC)
 
129
                return $TemplateCache;
171
130
 
172
131
                case 'UserCache':
173
 
                        load_class( 'users/model/_usercache.class.php' );
174
 
                        $UserCache = new UserCache(); // COPY (FUNC)
175
 
                        return $UserCache;
 
132
                $UserCache = new UserCache(); // COPY (FUNC)
 
133
                return $UserCache;
176
134
 
177
135
                case 'WidgetCache':
178
 
                        load_class( 'widgets/model/_widgetcache.class.php' );
179
 
                        $WidgetCache = new WidgetCache(); // COPY (FUNC)
180
 
                        return $WidgetCache;
 
136
                $WidgetCache = new WidgetCache(); // COPY (FUNC)
 
137
                return $WidgetCache;
181
138
 
182
139
                case 'EnabledWidgetCache':
183
 
                        // This simply instantiates a WidgetCache object, setting the
184
 
                        // $enabled_only parameter to true. Using a member variable
185
 
                        // instead of per-method parameters to load only the enabled
186
 
                        // widgets should be cleaner when there will be more methods
187
 
                        // in the WidgetCache class in the future.
188
 
                        load_class( 'widgets/model/_widgetcache.class.php' );
189
 
                        $EnabledWidgetCache = new WidgetCache( true );
190
 
                        return $EnabledWidgetCache;
 
140
                // This simply instantiates a WidgetCache object, setting the
 
141
                // $enabled_only parameter to true. Using a member variable
 
142
                // instead of per-method parameters to load only the enabled
 
143
                // widgets should be cleaner when there will be more methods
 
144
                // in the WidgetCache class in the future.
 
145
                $EnabledWidgetCache = new WidgetCache( true );
 
146
                return $EnabledWidgetCache;
191
147
 
192
148
                default:
193
 
                        debug_die( 'getCache(): Unknown Cache type:'.$objectName );
 
149
                debug_die( 'getCache(): Unknown Cache type:'.$objectName );
194
150
        }
195
151
}
196
152
 
201
157
function load_funcs( $funcs_path )
202
158
{
203
159
        global $inc_path;
 
160
 
204
161
        require_once $inc_path.$funcs_path;
205
162
}
206
163
 
213
170
 */
214
171
function shutdown()
215
172
{
216
 
        /**
217
 
         * @var Session
218
 
         */
219
173
        global $Session;
220
 
 
221
174
        global $Settings;
222
 
        global $Debuglog;
223
175
 
224
176
        // fp> do we need special processing if we are in CLI mode?  probably earlier actually
225
177
        // if( ! $is_cli )
226
 
 
227
178
        // Note: it might be useful at some point to do special processing if the script has been aborted or has timed out
228
179
        // connection_aborted()
229
180
        // connection_status()
233
184
 
234
185
        // Auto pruning of old HITS, old SESSIONS and potentially MORE analytics data:
235
186
        if( $Settings->get( 'auto_prune_stats_mode' ) == 'page' )
236
 
        { // Autopruning is requested
237
 
                load_class('sessions/model/_hitlist.class.php');
 
187
        {
 
188
                // Autopruning is requested
238
189
                Hitlist::dbprune(); // will prune once per day, according to Settings
239
190
        }
240
191
 
253
204
/**
254
205
 * Format a string/content for being output
255
206
 *
256
 
 * @author fplanque
257
 
 * @todo htmlspecialchars() takes a charset argument, which we could provide ($evo_charset?)
 
207
 * @todo (0000): htmlspecialchars() takes a charset argument, which we could provide ( $app_charset? )
258
208
 * @param string raw text
259
209
 * @param string format, can be one of the following
260
210
 * - raw: do nothing
274
224
 
275
225
        switch( $format )
276
226
        {
 
227
                // do nothing!
277
228
                case 'raw':
278
 
                        // do nothing!
279
 
                        break;
 
229
                break;
280
230
 
 
231
                // display in HTML page body: allow full HTML
281
232
                case 'htmlbody':
282
 
                        // display in HTML page body: allow full HTML
283
 
                        $content = convert_chars($content, 'html');
284
 
                        break;
 
233
                $content = convert_chars( $content, 'html' );
 
234
                break;
285
235
 
 
236
                // Encode string to be passed as part of an URL
286
237
                case 'urlencoded':
287
 
                        // Encode string to be passed as part of an URL
288
 
                        $content = rawurlencode( $content );
289
 
                        break;
 
238
                $content = rawurlencode( $content );
 
239
                break;
290
240
 
 
241
                // Special mode for RSS 0.92: apply renders and allow full HTML but escape it
291
242
                case 'entityencoded':
292
 
                        // Special mode for RSS 0.92: apply renders and allow full HTML but escape it
293
 
                        $content = convert_chars($content, 'html');
294
 
                        $content = htmlspecialchars( $content );
295
 
                        break;
 
243
                $content = convert_chars( $content, 'html' );
 
244
                $content = htmlspecialchars( $content );
 
245
                break;
296
246
 
 
247
                // strips out HTML (mainly for use in Title)
297
248
                case 'htmlhead':
298
 
                        // strips out HTML (mainly for use in Title)
299
 
                        $content = strip_tags($content);
300
 
                        $content = convert_chars($content, 'html');
301
 
                        break;
 
249
                $content = strip_tags( $content );
 
250
                $content = convert_chars( $content, 'html' );
 
251
                break;
302
252
 
 
253
                // use as an attribute: strips tags and escapes quotes
303
254
                case 'htmlattr':
304
 
                        // use as an attribute: strips tags and escapes quotes
305
 
                        $content = strip_tags($content);
306
 
                        $content = convert_chars($content, 'html');
307
 
                        $content = str_replace('"', '&quot;', $content );
308
 
                        $content = str_replace("'", '&#039;', $content );
309
 
                        break;
 
255
                $content = strip_tags( $content );
 
256
                $content = convert_chars( $content, 'html' );
 
257
                $content = str_replace('"', '&quot;', $content );
 
258
                $content = str_replace("'", '&#039;', $content );
 
259
                break;
310
260
 
 
261
                // use as a form value: escapes &, quotes and < > but leaves code alone
311
262
                case 'formvalue':
312
 
                        // use as a form value: escapes &, quotes and < > but leaves code alone
313
 
                        $content = htmlspecialchars( $content, ENT_QUOTES );  // Handles &, ", ', < and >
314
 
                        break;
 
263
                $content = htmlspecialchars( $content, ENT_QUOTES );  // Handles &, ", ', < and >
 
264
                break;
315
265
 
 
266
                // use in an XML file: strip HTML tags
316
267
                case 'xml':
317
 
                        // use in an XML file: strip HTML tags
318
 
                        $content = strip_tags($content);
319
 
                        $content = convert_chars($content, 'xml');
320
 
                        break;
 
268
                $content = strip_tags( $content );
 
269
                $content = convert_chars( $content, 'xml' );
 
270
                break;
321
271
 
 
272
                // use as an attribute: strips tags and escapes quotes
322
273
                case 'xmlattr':
323
 
                        // use as an attribute: strips tags and escapes quotes
324
 
                        $content = strip_tags($content);
325
 
                        $content = convert_chars($content, 'xml');
326
 
                        $content = str_replace('"', '&quot;', $content );
327
 
                        $content = str_replace("'", '&#039;', $content );
328
 
                        break;
 
274
                $content = strip_tags( $content );
 
275
                $content = convert_chars( $content, 'xml' );
 
276
                $content = str_replace('"', '&quot;', $content );
 
277
                $content = str_replace("'", '&#039;', $content );
 
278
                break;
329
279
 
 
280
                // use as plain-text, e.g. for ascii-mails
330
281
                case 'text':
331
 
                        // use as plain-text, e.g. for ascii-mails
332
 
                        $content = strip_tags( $content );
333
 
                        $trans_tbl = get_html_translation_table( HTML_ENTITIES );
334
 
                        $trans_tbl = array_flip( $trans_tbl );
335
 
                        $content = strtr( $content, $trans_tbl );
336
 
                        $content = preg_replace( '/[ \t]+/', ' ', $content);
337
 
                        $content = trim($content);
338
 
                        break;
 
282
                $content = strip_tags( $content );
 
283
                $trans_tbl = get_html_translation_table( HTML_ENTITIES );
 
284
                $trans_tbl = array_flip( $trans_tbl );
 
285
                $content = strtr( $content, $trans_tbl );
 
286
                $content = preg_replace( '/[ \t]+/', ' ', $content);
 
287
                $content = trim( $content );
 
288
                break;
339
289
 
340
290
                default:
341
 
                        debug_die( 'Output format ['.$format.'] not supported.' );
 
291
                debug_die( 'Output format ['.$format.'] not supported.' );
342
292
        }
343
293
 
344
294
        return $content;
348
298
/*
349
299
 * autobrize(-)
350
300
 */
351
 
function autobrize($content) {
 
301
function autobrize( $content ) {
352
302
        $content = callback_on_non_matching_blocks( $content, '~<code>.+?</code>~is', 'autobrize_callback' );
353
303
        return $content;
354
304
}
355
305
 
356
306
/**
357
307
 * Adds <br>'s to non code blocks
358
 
 *
359
308
 * @param string $content
360
309
 * @return string content with <br>'s added
361
310
 */
364
313
        $content = preg_replace("/<br>\n/", "\n", $content);
365
314
        $content = preg_replace("/<br \/>\n/", "\n", $content);
366
315
        $content = preg_replace("/(\015\012)|(\015)|(\012)/", "<br />\n", $content);
367
 
        return($content);
 
316
        return( $content );
368
317
}
369
318
 
370
319
/*
371
320
 * unautobrize(-)
372
321
 */
373
 
function unautobrize($content)
 
322
function unautobrize( $content )
374
323
{
375
324
        $content = callback_on_non_matching_blocks( $content, '~<code>.+?</code>~is', 'unautobrize_callback' );
376
325
        return $content;
378
327
 
379
328
/**
380
329
 * Removes <br>'s from non code blocks
381
 
 *
382
330
 * @param string $content
383
331
 * @return string content with <br>'s removed
384
332
 */
386
334
{
387
335
        $content = preg_replace("/<br>\n/", "\n", $content);   //for PHP versions before 4.0.5
388
336
        $content = preg_replace("/<br \/>\n/", "\n", $content);
389
 
        return($content);
 
337
        return( $content );
390
338
}
391
339
 
392
340
/**
393
341
 * Add leading zeroes to a number when necessary.
394
 
 *
395
342
 * @param string The original number.
396
343
 * @param integer How many digits shall the number have?
397
344
 * @return string The padded number.
403
350
 
404
351
/**
405
352
 * Crop string to maxlen with &hellip; at the end if needed.
406
 
 *
407
353
 * @param string
408
354
 * @param int Maximum length
409
355
 * @return string
410
356
 */
411
357
function strmaxlen( $str, $maxlen = 50 )
412
358
{
413
 
        if( evo_strlen( $str ) > $maxlen )
 
359
        if( app_strlen( $str ) > $maxlen )
414
360
        {
415
 
                $str = evo_substr( $str, 0, $maxlen-1 ).'&hellip;';
 
361
                $str = app_substr( $str, 0, $maxlen-1 ).'&hellip;';
416
362
        }
417
363
 
418
364
        return $str;
421
367
 
422
368
/**
423
369
 * Crop string to maxwords preserving tags.
424
 
 *
425
370
 * @param string
426
371
 * @param int Maximum number words
427
372
 * @param mixed array Optional parameters
436
381
                ), $params );
437
382
        $open = false;
438
383
        $have_seen_non_whitespace = false;
439
 
        $end = evo_strlen( $str );
 
384
        $end = app_strlen( $str );
440
385
        for( $i = 0; $i < $end; $i++ )
441
386
        {
442
387
                switch( $char = $str[$i] )
443
388
                {
444
 
                        case '<' :      // start of a tag
445
 
                                $open = true;
446
 
                                break;
447
 
                        case '>' : // end of a tag
448
 
                                $open = false;
449
 
                                break;
450
 
 
451
 
                        case ctype_space($char):
452
 
                                if( ! $open )
453
 
                                { // it's a word gap
454
 
                                        // Eat any other whitespace.
455
 
                                        while( isset($str[$i+1]) && ctype_space($str[$i+1]) )
456
 
                                        {
457
 
                                                $i++;
458
 
                                        }
459
 
                                        if( isset($str[$i+1]) && $have_seen_non_whitespace )
460
 
                                        { // only decrement words, if there's a non-space char left.
461
 
                                                --$maxwords;
462
 
                                        }
463
 
                                }
464
 
                                break;
 
389
                        // start of a tag
 
390
                        case '<' :
 
391
                        $open = true;
 
392
                        break;
 
393
 
 
394
                        // end of a tag
 
395
                        case '>' :
 
396
                        $open = false;
 
397
                        break;
 
398
 
 
399
                        case ctype_space( $char ):
 
400
                        if( ! $open )
 
401
                        {
 
402
                                // it's a word gap
 
403
                                // Eat any other whitespace.
 
404
                                while( isset( $str[$i+1] ) && ctype_space( $str[$i+1] ) )
 
405
                                {
 
406
                                        $i++;
 
407
                                }
 
408
                                if( isset( $str[$i+1] ) && $have_seen_non_whitespace )
 
409
                                {
 
410
                                        // only decrement words, if there's a non-space char left
 
411
                                        --$maxwords;
 
412
                                }
 
413
                        }
 
414
                        break;
465
415
 
466
416
                        default:
467
 
                                $have_seen_non_whitespace = true;
468
 
                                break;
 
417
                        $have_seen_non_whitespace = true;
 
418
                        break;
469
419
                }
470
420
                if( $maxwords < 1 ) break;
471
421
        }
472
422
 
473
423
        // restrict content to required number of words and balance the tags out
474
 
        $str = balance_Tags( evo_substr( $str, 0, $i ) );
 
424
        $str = balance_Tags( app_substr( $str, 0, $i ) );
475
425
 
476
426
        if( $params['always_continue'] || $maxwords == false )
477
 
        { // we want a continued text
 
427
        {
 
428
                // we want a continued text
478
429
                if( $params['continued_link'] )
479
 
                { // we have a url
 
430
                {
 
431
                        // we have a url
480
432
                        $str .= ' <a href="'.$params['continued_link'].'">'.$params['continued_text'].'</a>';
481
433
                }
482
434
                else
483
 
                { // we don't have a url
 
435
                {
 
436
                        // we don't have a url
484
437
                        $str .= ' '.$params['continued_text'];
485
438
                }
486
439
        }
493
446
 
494
447
/**
495
448
 * Convert all non ASCII chars (except if UTF-8, GB2312 or CP1251) to &#nnnn; unicode references.
 
449
 *
496
450
 * Also convert entities to &#nnnn; unicode references if output is not HTML (eg XML)
497
 
 *
 
451
 
498
452
 * Preserves < > and quotes.
499
 
 *
500
 
 * fplanque: simplified
501
 
 * sakichan: pregs instead of loop
502
453
 */
503
454
function convert_chars( $content, $flag = 'html' )
504
455
{
505
 
        global $b2_htmltrans, $evo_charset;
 
456
        global $app_charset;
 
457
        global $b2_htmltrans;
506
458
 
507
459
        /**
508
460
         * Translation of invalid Unicode references range to valid range.
543
495
        );
544
496
 
545
497
        // Convert highbyte non ASCII/UTF-8 chars to urefs:
546
 
        if( ! in_array(strtolower($evo_charset), array( 'utf8', 'utf-8', 'gb2312', 'windows-1251') ) )
547
 
        { // This is a single byte charset
 
498
        if( ! in_array( strtolower( $app_charset ), array( 'utf8', 'utf-8', 'gb2312', 'windows-1251' ) ) )
 
499
        {
 
500
                // This is a single byte charset
548
501
                // fp> why do we actually bother doing this:?
549
502
                $content = preg_replace_callback(
550
503
                        '/[\x80-\xff]/',
551
 
                        create_function( '$j', 'return "&#".ord($j[0]).";";' ),
 
504
                        create_function( '$j', 'return "&#".ord( $j[0] ).";";' ),
552
505
                        $content);
553
506
        }
554
507
 
555
508
        // Convert Windows CP1252 => Unicode (valid HTML)
556
 
        // TODO: should this go to input conversions instead (?)
557
509
        $content = strtr( $content, $b2_htmltranswinuni );
558
510
 
559
511
        if( $flag == 'html' )
560
 
        { // we can use entities
 
512
        {
 
513
                // we can use entities
561
514
                // Convert & chars that are not used in an entity
562
515
                $content = preg_replace('/&(?![#A-Za-z0-9]{2,20};)/', '&amp;', $content);
563
516
        }
564
517
        else
565
 
        { // unicode, xml...
 
518
        {
 
519
                // unicode, xml...
566
520
                // Convert & chars that are not used in an entity
567
521
                $content = preg_replace('/&(?![#A-Za-z0-9]{2,20};)/', '&#38;', $content);
568
522
 
569
523
                // Convert HTML entities to urefs:
570
 
                $content = strtr($content, $b2_htmltrans);
 
524
                $content = strtr( $content, $b2_htmltrans );
571
525
        }
572
526
 
573
527
        return( $content );
576
530
 
577
531
/**
578
532
 * mbstring wrapper for strlen function
579
 
 *
580
533
 * @param string
581
534
 * @return string
582
535
 */
583
 
function evo_strlen( $string )
 
536
function app_strlen( $string )
584
537
{
585
538
        global $current_charset;
586
539
 
589
542
                return mb_strlen( $string, $current_charset );
590
543
        }
591
544
 
592
 
        return strlen($string);
 
545
        return strlen( $string );
593
546
}
594
547
 
595
548
 
596
549
/**
597
550
 * mbstring wrapper for substr function
598
 
 *
599
551
 * @param string
600
552
 * @param int start position
601
553
 * @param int string length
602
554
 * @return string
603
555
 */
604
 
function evo_substr( $string, $start = 0, $length = '#' )
 
556
function app_substr( $string, $start = 0, $length = '#' )
605
557
{
606
558
        global $current_charset;
607
559
 
608
560
        if( $length == '#' )
609
561
        {
610
 
                $length = evo_strlen($string);
 
562
                $length = app_strlen( $string );
611
563
        }
612
564
 
613
565
        if( $current_charset != 'iso-8859-1' && $current_charset != '' && function_exists('mb_substr') )
622
574
/**
623
575
 * Split $text into blocks by using $pattern and call $callback on the non-matching blocks.
624
576
 *
625
 
 * The non-matching block's text is the first param to $callback and additionally $params gets passed.
626
 
 *
627
 
 * This gets used to make links clickable or replace smilies.
628
 
 *
629
 
 * E.g., to replace only in non-HTML tags, call it like:
 
577
 * The non-matching block's text is the first param to $callback and additionally $params
 
578
 * gets passed. This gets used to make links clickable or replace smilies. E.g., to replace
 
579
 * only in non-HTML tags, call it like:
630
580
 * <code>callback_on_non_matching_blocks( $text, '~<[^>]*>~s', 'your_callback' );</code>
631
 
 *
632
 
 * {@internal This function gets tested in misc.funcs.simpletest.php.}}
633
 
 *
634
581
 * @param string Text to handle
635
582
 * @param string Regular expression pattern that defines blocks to exclude.
636
583
 * @param callback Function name or object/method array to use as callback.
637
 
 *               Each non-matching block gets passed as first param, additional params may be
638
 
 *               passed with $params.
 
584
 * Each non-matching block gets passed as first param, additional params may be
 
585
 * passed with $params.
639
586
 * @param array Of additional ("static") params to $callback.
640
587
 * @return string
641
588
 */
642
589
function callback_on_non_matching_blocks( $text, $pattern, $callback, $params = array() )
643
590
{
644
591
        if( preg_match_all( $pattern, $text, $matches, PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER ) )
645
 
        { // $pattern matches, call the callback method on each non-matching block
 
592
        {
 
593
                // $pattern matches, call the callback method on each non-matching block
646
594
                $pos = 0;
647
595
                $new_r = '';
648
596
 
649
597
                foreach( $matches[0] as $l_matching )
650
598
                {
651
599
                        $pos_match = $l_matching[1];
652
 
                        $non_match = substr( $text, $pos, ($pos_match - $pos) );
 
600
                        $non_match = substr( $text, $pos, ( $pos_match - $pos ) );
653
601
 
654
602
                        // Callback:
655
603
                        $callback_params = $params;
657
605
                        $new_r .= call_user_func_array( $callback, $callback_params );
658
606
 
659
607
                        $new_r .= $l_matching[0];
660
 
                        $pos += strlen($non_match)+strlen($l_matching[0]);
 
608
                        $pos += strlen( $non_match )+strlen( $l_matching[0] );
661
609
                }
662
610
 
663
611
                // Callback:
680
628
 *
681
629
 * It replaces only text which is not between <a> tags already.
682
630
 *
683
 
 * @todo dh> this should not replace links in tags! currently fails for something
684
 
 *           like '<img src=" http://example.com/" />' (not usual though!)
685
 
 * fp> I am trying to address this by not replacing anything inside tags
686
 
 * fp> This should be replaced by a clean state machine (one single variable for current state)
687
 
 *
688
 
 * {@internal This function gets tested in misc.funcs.simpletest.php.}}
 
631
 * @todo (0000): dh> this should not replace links in tags! currently fails for
 
632
 * something like '<img src=" http://example.com/" />' (not usual though!). fp> I
 
633
 * am trying to address this by not replacing anything inside tags. This should
 
634
 * be replaced by a clean state machine (one single variable for current state)
689
635
 *
690
636
 * @return string
691
637
 */
697
643
        $in_tag_quote = false;
698
644
        $from_pos = 0;
699
645
        $i = 0;
700
 
        $n = strlen($text);
 
646
        $n = strlen( $text );
701
647
 
702
648
        // Not using callback_on_non_matching_blocks(), because it requires
703
649
        // wellformed HTML and the implementation below should be
704
650
        // faster and less memory intensive (tested for some example content)
705
651
        while( $i < $n )
706
 
        {       // Go through each char in string... (we will fast forward from tag to tag)
 
652
        {
 
653
                // Go through each char in string... (we will fast forward from tag to tag)
707
654
                if( $inside_tag )
708
 
                {       // State: We're currently inside some tag:
 
655
                {
 
656
                        // State: We're currently inside some tag:
709
657
                        switch( $text[$i] )
710
658
                        {
711
659
                                case '>':
712
 
                                        if( $in_tag_quote )
713
 
                                        { // This is in a quoted string so it doesn't really matter...
714
 
                                                break;
715
 
                                        }
716
 
                                        // end of tag:
717
 
                                        $inside_tag = false;
718
 
                                        $r .= substr($text, $from_pos, $i-$from_pos+1);
719
 
                                        $from_pos = $i+1;
720
 
                                        // $r .= '}';
 
660
                                if( $in_tag_quote )
 
661
                                {
 
662
                                        // This is in a quoted string so it doesn't really matter...
721
663
                                        break;
 
664
                                }
 
665
                                // end of tag
 
666
                                $inside_tag = false;
 
667
                                $r .= substr( $text, $from_pos, $i-$from_pos+1 );
 
668
                                $from_pos = $i+1;
 
669
                                // $r .= '}';
 
670
                                break;
722
671
 
 
672
                                // This is the beginning or the end of a quoted string
723
673
                                case '"':
724
674
                                case '\'':
725
 
                                        // This is the beginning or the end of a quoted string:
726
 
                                        if( ! $in_tag_quote )
727
 
                                        {
728
 
                                                $in_tag_quote = $text[$i];
729
 
                                        }
730
 
                                        elseif( $in_tag_quote == $text[$i] )
731
 
                                        {
732
 
                                                $in_tag_quote = false;
733
 
                                        }
734
 
                                        break;
 
675
                                if( ! $in_tag_quote )
 
676
                                {
 
677
                                        $in_tag_quote = $text[$i];
 
678
                                }
 
679
                                elseif( $in_tag_quote == $text[$i] )
 
680
                                {
 
681
                                        $in_tag_quote = false;
 
682
                                }
 
683
                                break;
735
684
                        }
736
685
                }
737
686
                elseif( $in_a_tag )
738
 
                {       // In a link but no longer inside <a>...</a> tag or any other embedded tag like <strong> or whatever
 
687
                {
 
688
                 // In a link but no longer inside <a>...</a> tag or any other embedded tag like <strong> or whatever
739
689
                        switch( $text[$i] )
740
690
                        {
741
691
                                case '<':
742
 
                                        if( strtolower(substr($text, $i+1, 3)) == '/a>' )
743
 
                                        {       // Ok, this is the end tag of the link:
744
 
                                                // $r .= substr($text, $from_pos, $i-$from_pos+4);
745
 
                                                // $from_pos = $i+4;
746
 
                                                $i += 4;
747
 
                                                $r .= substr($text, $from_pos, $i-$from_pos);
748
 
                                                $from_pos = $i;
749
 
                                                $in_a_tag = false;
750
 
                                                $in_tag_quote = false;
751
 
                                        }
752
 
                                        break;
 
692
                                if( strtolower( substr( $text, $i+1, 3 ) ) == '/a>' )
 
693
                                {
 
694
                                        // Ok, this is the end tag of the link:
 
695
                                        // $r .= substr( $text, $from_pos, $i-$from_pos+4 );
 
696
                                        // $from_pos = $i+4;
 
697
                                        $i += 4;
 
698
                                        $r .= substr( $text, $from_pos, $i-$from_pos );
 
699
                                        $from_pos = $i;
 
700
                                        $in_a_tag = false;
 
701
                                        $in_tag_quote = false;
 
702
                                }
 
703
                                break;
753
704
                        }
754
705
                }
755
706
                else
756
 
                { // State: we're not currently in any tag:
757
 
                        // Find next tag opening:
758
 
                        $i = strpos($text, '<', $i);
 
707
                {
 
708
                        // State: we're not currently in any tag ... find next tag opening:
 
709
                        $i = strpos( $text, '<', $i );
759
710
                        if( $i === false )
760
 
                        { // No more opening tags:
 
711
                        {
 
712
                                // No more opening tags
761
713
                                break;
762
714
                        }
763
715
 
765
717
                        $in_tag_quote = false;
766
718
                        // s$r .= '{'.$text[$i+1];
767
719
 
768
 
                        if( ($text[$i+1] == 'a' || $text[$i+1] == 'A') && ctype_space($text[$i+2]) )
769
 
                        { // opening "A" tag
 
720
                        if( ( $text[$i+1] == 'a' || $text[$i+1] == 'A') && ctype_space( $text[$i+2] ) )
 
721
                        {
 
722
                                // opening "A" tag
770
723
                                $in_a_tag = true;
771
724
                        }
772
725
 
773
 
                        // Make the text before the opening < clickable:
774
 
                        if( is_array($callback) )
 
726
                        // Make the text before the opening < clickable
 
727
                        if( is_array( $callback ) )
775
728
                        {
776
 
                                $r .= $callback[0]->$callback[1]( substr($text, $from_pos, $i-$from_pos), $moredelim );
 
729
                                $r .= $callback[0]->$callback[1]( substr( $text, $from_pos, $i-$from_pos ), $moredelim );
777
730
                        }
778
731
                        else
779
732
                        {
780
 
                                $r .= $callback( substr($text, $from_pos, $i-$from_pos), $moredelim );
 
733
                                $r .= $callback( substr( $text, $from_pos, $i-$from_pos ), $moredelim );
781
734
                        }
782
735
                        $from_pos = $i;
783
736
 
787
740
                $i++;
788
741
        }
789
742
 
790
 
        // the remaining part:
 
743
        // the remaining part
791
744
        if( $in_a_tag )
792
 
        { // may happen for invalid html:
793
 
                $r .= substr($text, $from_pos);
 
745
        {
 
746
                // may happen for invalid html
 
747
                $r .= substr( $text, $from_pos );
794
748
        }
795
749
        else
796
 
        {       // Make remplacements in the remaining part:
797
 
                if( is_array($callback) )
 
750
        {
 
751
                // Make remplacements in the remaining part
 
752
                if( is_array( $callback ) )
798
753
                {
799
 
                        $r .= $callback[0]->$callback[1]( substr($text, $from_pos), $moredelim );
 
754
                        $r .= $callback[0]->$callback[1]( substr( $text, $from_pos ), $moredelim );
800
755
                }
801
756
                else
802
757
                {
803
 
                        $r .= $callback( substr($text, $from_pos), $moredelim );
 
758
                        $r .= $callback( substr( $text, $from_pos ), $moredelim );
804
759
                }
805
760
        }
806
761
 
856
811
 */
857
812
function mysql2timestamp( $m )
858
813
{
859
 
        return mktime(substr($m,11,2),substr($m,14,2),substr($m,17,2),substr($m,5,2),substr($m,8,2),substr($m,0,4));
 
814
        return mktime( substr( $m, 11, 2 ), substr( $m, 14, 2 ), substr( $m, 17, 2 ), substr( $m, 5, 2 ), substr( $m, 8, 2 ), substr( $m, 0, 4 ) );
860
815
}
861
816
 
862
817
/**
864
819
 */
865
820
function mysql2datestamp( $m )
866
821
{
867
 
        return mktime( 0, 0, 0, substr($m,5,2), substr($m,8,2), substr($m,0,4) );
 
822
        return mktime( 0, 0, 0, substr( $m, 5, 2 ), substr( $m, 8, 2 ), substr( $m, 0, 4 ) );
868
823
}
869
824
 
870
825
/**
871
826
 * Format a MYSQL date to current locale date format.
872
 
 *
873
827
 * @param string MYSQL date YYYY-MM-DD HH:MM:SS
874
828
 */
875
829
function mysql2localedate( $mysqlstring )
907
861
 
908
862
 
909
863
/**
910
 
 * Format a MYSQL date.
911
 
 *
 
864
 * Format a MYSQL date
912
865
 * @param string enhanced format string
913
866
 * @param string MYSQL date YYYY-MM-DD HH:MM:SS
914
867
 * @param boolean true to use GM time
916
869
function mysql2date( $dateformatstring, $mysqlstring, $useGM = false )
917
870
{
918
871
        $m = $mysqlstring;
919
 
        if( empty($m) || ($m == '0000-00-00 00:00:00' ))
 
872
        if( empty( $m ) || ( $m == '0000-00-00 00:00:00' ) )
920
873
                return false;
921
874
 
922
875
        // Get a timestamp:
928
881
 
929
882
/**
930
883
 * Date internationalization: same as date() formatting but with i18n support
931
 
 *
932
884
 * @param string enhanced format string
933
885
 * @param integer UNIX timestamp
934
886
 * @param boolean true to use GM time
939
891
        global $localtimenow, $time_difference;
940
892
 
941
893
        if( $dateformatstring == 'isoZ' )
942
 
        { // full ISO 8601 format
 
894
        {
 
895
                // full ISO 8601 format
943
896
                $dateformatstring = 'Y-m-d\TH:i:s\Z';
944
897
        }
945
898
 
946
899
        if( $useGM )
947
 
        { // We want a Greenwich Meridian time:
948
 
                $r = gmdate($dateformatstring, ($unixtimestamp - $time_difference));
 
900
        {
 
901
                // We want a Greenwich Meridian time
 
902
                $r = gmdate( $dateformatstring, ( $unixtimestamp - $time_difference ) );
949
903
        }
950
904
        else
951
 
        { // We want default timezone time:
 
905
        {
 
906
                // We want default timezone time
952
907
 
953
908
                /*
954
909
                Special symbols:
970
925
                $r = date( $protected_dateformatstring, $unixtimestamp );
971
926
 
972
927
                if( $protected_dateformatstring != $dateformatstring )
973
 
                { // we had special symbols, replace them
974
 
 
975
 
                        $istoday = ( date('Ymd',$unixtimestamp) == date('Ymd',$localtimenow) ) ? '1' : '0';
976
 
                        $datemonth = date('m', $unixtimestamp);
977
 
                        $dateweekday = date('w', $unixtimestamp);
 
928
                {
 
929
                        // we had special symbols, replace them
 
930
                        $istoday = ( date( 'Ymd', $unixtimestamp ) == date( 'Ymd', $localtimenow ) ) ? '1' : '0';
 
931
                        $datemonth = date( 'm', $unixtimestamp );
 
932
                        $dateweekday = date( 'w', $unixtimestamp );
978
933
 
979
934
                        // replace special symbols
980
935
                        $r = str_replace( array(
986
941
                                                '@@@M@@@',
987
942
                                                ),
988
943
                                        array( $istoday,
989
 
                                                trim(T_($weekday[$dateweekday])),
990
 
                                                trim(T_($weekday_abbrev[$dateweekday])),
991
 
                                                trim(T_($weekday_letter[$dateweekday])),
992
 
                                                trim(T_($month[$datemonth])),
993
 
                                                trim(T_($month_abbrev[$datemonth])) ),
 
944
                                                trim( T_( $weekday[$dateweekday] ) ),
 
945
                                                trim( T_( $weekday_abbrev[$dateweekday] ) ),
 
946
                                                trim( T_( $weekday_letter[$dateweekday] ) ),
 
947
                                                trim( T_( $month[$datemonth] ) ),
 
948
                                                trim( T_( $month_abbrev[$datemonth] ) ) ),
994
949
                                        $r );
995
950
                }
996
951
        }
1001
956
 
1002
957
/**
1003
958
 * Add given # of days to a timestamp
1004
 
 *
1005
959
 * @param integer timestamp
1006
960
 * @param integer days
1007
961
 * @return integer timestamp
1008
962
 */
1009
963
function date_add_days( $timestamp, $days )
1010
964
{
1011
 
        return mktime( date('H',$timestamp), date('m',$timestamp), date('s',$timestamp),
1012
 
                                                                date('m',$timestamp), date('d',$timestamp)+$days, date('Y',$timestamp)  );
 
965
        return mktime( date( 'H', $timestamp ), date( 'm', $timestamp ), date( 's', $timestamp ),
 
966
                date( 'm', $timestamp ), date( 'd', $timestamp )+$days, date( 'Y', $timestamp ) );
1013
967
}
1014
968
 
1015
969
/**
1041
995
function get_start_date_for_week( $year, $week, $startofweek )
1042
996
{
1043
997
        $new_years_date = mktime( 0, 0, 0, 1, 1, $year );
1044
 
        $weekday = date('w', $new_years_date);
 
998
        $weekday = date( 'w', $new_years_date );
1045
999
 
1046
1000
        // How many days until start of week:
1047
1001
        $days_to_new_week = (7 - $weekday + $startofweek) % 7;
1050
1004
        //$first_week_start_date = $new_years_date + $days_to_new_week * 86400;
1051
1005
 
1052
1006
        // We add the number of requested weeks:
1053
 
        // This will fail when passing to Daylight Savings Time: $date = $first_week_start_date + (($week-1) * 604800);
1054
 
        $date = mktime( 0, 0, 0, 1, $days_to_new_week + 1 + ($week-1) * 7, $year );
 
1007
        // This will fail when passing to Daylight Savings Time: $date = $first_week_start_date + (( $week-1 ) * 604800);
 
1008
        $date = mktime( 0, 0, 0, 1, $days_to_new_week + 1 + ( $week-1 ) * 7, $year );
1055
1009
 
1056
1010
        return $date;
1057
1011
}
1058
1012
 
1059
1013
 
1060
 
 
1061
1014
/**
1062
1015
 * Get start and end day of a week, based on day f the week and start-of-week
1063
1016
 *
1068
1021
 */
1069
1022
function get_weekstartend( $date, $startOfWeek )
1070
1023
{
1071
 
        while( date('w', $date) <> $startOfWeek )
 
1024
        while( date( 'w', $date ) <> $startOfWeek )
1072
1025
        {
1073
1026
                // mktime is needed so calculations work for DST enabling. Example: March 30th 2008, start of week 0 sunday
1074
 
                $date = mktime( 0, 0, 0, date('m',$date), date('d',$date)-1, date('Y',$date) );
 
1027
                $date = mktime( 0, 0, 0, date( 'm', $date ), date( 'd', $date )-1, date( 'Y', $date ) );
1075
1028
        }
1076
1029
        $week['start'] = $date;
1077
1030
        $week['end']   = $date + 604800; // 7 days
1081
1034
 
1082
1035
 
1083
1036
/**
 
1037
 * Get difference between two MySQL timestamps
 
1038
 * @link http://www.php.net/manual/en/function.time.php#85481
 
1039
 * @param string MYSQL date (YYYY-MM-DD HH:MM:SS) 
 
1040
 * @param string MYSQL date (YYYY-MM-DD HH:MM:SS), defaults to 0 for right now
 
1041
 * @return string Approximation of the time difference between $from_date and $to_date
 
1042
 */
 
1043
function mysql_date_diff( $from_date, $to_date = 0 )
 
1044
{
 
1045
        $from_date = mysql2timestamp( $from_date );
 
1046
        if( $to_date != 0 )
 
1047
        {
 
1048
                $to_date = mysql2timestamp( $to_date );
 
1049
        }
 
1050
        else
 
1051
        {
 
1052
                $to_date = time();
 
1053
        }
 
1054
 
 
1055
        $delta_seconds = round( abs( $to_date - $from_date ) );
 
1056
        $delta_minutes = round( $delta_seconds / 60 );
 
1057
 
 
1058
        if( $delta_minutes <= 1 )
 
1059
        {
 
1060
                return ($delta_minutes == 0) ? T_('less than a minute') : T_('1 minute');
 
1061
        }
 
1062
 
 
1063
        if( $delta_minutes < 45 )
 
1064
        {
 
1065
                return $delta_minutes.' '.T_('minutes');
 
1066
        }
 
1067
        if( $delta_minutes < 90 )
 
1068
        {
 
1069
                return T_('~ 1 hour');
 
1070
        }
 
1071
        if( $delta_minutes < 1440 )
 
1072
        {
 
1073
                return sprintf( T_('~ %d hours'), round( floatval( $delta_minutes ) / 60.0 ) );
 
1074
        }
 
1075
        if( $delta_minutes < 2880 )
 
1076
        {
 
1077
                return T_('1 day');
 
1078
        }
 
1079
        if( $delta_minutes < 43200 )
 
1080
        {
 
1081
                return sprintf( T_('~ %d days'), round( floatval( $delta_minutes ) / 1440 ) );
 
1082
        }
 
1083
        if( $delta_minutes < 86400 )
 
1084
        {
 
1085
                return T_('~ 1 month');
 
1086
        }
 
1087
        if( $delta_minutes < 525600 )
 
1088
        {
 
1089
                return sprintf( T_('~ %d months'), round( floatval( $delta_minutes ) / 43200 ) );
 
1090
        }
 
1091
        if( $delta_minutes < 1051199 )
 
1092
        {
 
1093
                return T_('~ 1 year');
 
1094
        }
 
1095
        return sprintf( T_('over %d years'), round( floatval( $delta_minutes ) / 525600 ) );
 
1096
}
 
1097
 
 
1098
 
 
1099
/**
1084
1100
 * Check that email address looks valid.
1085
1101
 *
1086
1102
 * @param string email address to check
1093
1109
 *      - Me <example@example.org>
1094
1110
 *      - "Me" <example@example.org>
1095
1111
 *
1096
 
 * @return bool True if the email address appears to be valid, false otherwise.
1097
 
 *
1098
1112
 * @see Plugin::IsValidRawEmail()
1099
1113
 * @see Plugin::IsValidFilteredEmail()
 
1114
 * @return bool True if the email address appears to be valid, false otherwise.
1100
1115
 */
1101
1116
function is_email( $email, $format = 'simple' )
1102
1117
{
1103
 
        global $Plugins, $Debuglog;
 
1118
        global $Plugins;
1104
1119
 
1105
1120
        if( $format == 'rfc2822' )
1106
 
        {       // Backward compatibility
 
1121
        {
 
1122
                // Backward compatibility
1107
1123
                $format = 'rfc';
1108
1124
        }
1109
1125
 
1110
 
        // Check plugins:
 
1126
        // Check plugins
1111
1127
        $plug_ret = $Plugins->trigger_event_first_return( 'IsValidRawEmail',
1112
1128
                array(
1113
 
                        'email'  => $email,
 
1129
                        'email' => $email,
1114
1130
                        'format' => $format,
1115
1131
                ) );
1116
1132
        $plug_choice = empty( $plug_ret ) ? Plugin::EmailNotSure : $plug_ret['plugin_ret'];
1117
1133
 
1118
1134
        if( $plug_choice == Plugin::EmailInvalid )
1119
 
        {       // The plugin thinks the email address is invalid. No further processing.
1120
 
                $Debuglog->add( 'REJECT ['.$email.'] by plugin #'.$plug_ret['plugin_ID'],
1121
 
                        'email' );
 
1135
        {
 
1136
                // The plugin thinks the email address is invalid. No further processing.
1122
1137
                return false;
1123
1138
        }
1124
1139
        else if( $plug_choice == Plugin::EmailValid )
1125
 
        {       // The plugin assures us that everything is perfectly fine.
1126
 
                $Debuglog->add( 'ACCEPT ['.$email.'] by plugin #'.$plug_ret['plugin_ID'],
1127
 
                        'email' );
 
1140
        {
 
1141
                // The plugin assures us that everything is perfectly fine.
1128
1142
                return true;
1129
1143
        }
1130
1144
        else if( $plug_choice == Plugin::EmailNotSure )
1131
 
        {       // No plugin could decide on the validity of the address.
 
1145
        {
 
1146
                // No plugin could decide on the validity of the address.
1132
1147
                // Apply our own checks.
1133
 
                $Debuglog->add( 'Applying built-in checks', 'email' );
1134
 
 
1135
1148
                switch( $format )
1136
1149
                {
1137
1150
                        case 'rfc':
1138
 
                                /**
1139
 
                                 * Regexp pattern converted from: http://www.regexlib.com/REDetails.aspx?regexp_id=711
1140
 
                                 * Extended to allow escaped quotes.
1141
 
                                 */
1142
 
                                $pattern_email = '/^
1143
 
                                        (
1144
 
                                                (?>[a-zA-Z\d!\#$%&\'*+\-\/=?^_`{|}~]+\x20*
1145
 
                                                        |"( \\\" | (?=[\x01-\x7f])[^"\\\] | \\[\x01-\x7f] )*"\x20*)* # Name
1146
 
                                                (<)
1147
 
                                        )?
1148
 
                                        (
1149
 
                                                (?!\.)(?>\.?[a-zA-Z\d!\#$%&\'*+\-\/=?^_`{|}~]+)+
1150
 
                                                |"( \\\" | (?=[\x01-\x7f])[^"\\\] | \\[\x01-\x7f] )* " # quoted mailbox name
1151
 
                                        )
1152
 
                                        @
1153
 
                                        (
1154
 
                                                ((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}
 
1151
                        /**
 
1152
                         * Regexp pattern converted from: http://www.regexlib.com/REDetails.aspx?regexp_id=711
 
1153
                         * Extended to allow escaped quotes.
 
1154
                         */
 
1155
                        $pattern_email = '/^
 
1156
                                (
 
1157
                                        (?>[a-zA-Z\d!\#$%&\'*+\-\/=?^_`{|}~]+\x20*
 
1158
                                                |"( \\\" | (?=[\x01-\x7f])[^"\\\] | \\[\x01-\x7f] )*"\x20*)* # Name
 
1159
                                        (<)
 
1160
                                )?
 
1161
                                (
 
1162
                                        (?!\.)(?>\.?[a-zA-Z\d!\#$%&\'*+\-\/=?^_`{|}~]+)+
 
1163
                                        |"( \\\" | (?=[\x01-\x7f])[^"\\\] | \\[\x01-\x7f] )* " # quoted mailbox name
 
1164
                                )
 
1165
                                @
 
1166
                                (
 
1167
                                        ((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}
 
1168
                                        |
 
1169
                                        \[(
 
1170
                                                ( (?(?<!\[)\.)(25[0-5] | 2[0-4]\d | [01]?\d?\d) ){4}
1155
1171
                                                |
1156
 
                                                \[(
1157
 
                                                        ( (?(?<!\[)\.)(25[0-5] | 2[0-4]\d | [01]?\d?\d) ){4}
1158
 
                                                        |
1159
 
                                                        [a-zA-Z\d\-]*[a-zA-Z\d]:( (?=[\x01-\x7f])[^\\\[\]] | \\[\x01-\x7f] )+
1160
 
                                                )\]
1161
 
                                        )
1162
 
                                        (?(3)>) # match ">" if it was there
1163
 
                                        $/x';
1164
 
                                break;
 
1172
                                                [a-zA-Z\d\-]*[a-zA-Z\d]:( (?=[\x01-\x7f])[^\\\[\]] | \\[\x01-\x7f] )+
 
1173
                                        )\]
 
1174
                                )
 
1175
                                (?(3)>) # match ">" if it was there
 
1176
                                $/x';
 
1177
                        break;
1165
1178
 
1166
1179
                        case 'simple':
1167
1180
                        default:
1168
 
                                $pattern_email = '~^(([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,}))$~i';
1169
 
                                break;
 
1181
                        $pattern_email = '~^(([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,}))$~i';
 
1182
                        break;
1170
1183
                }
1171
1184
 
 
1185
?><?php // humors my editor into looking like PHP again ;)
 
1186
 
1172
1187
                // Short-circuit definitely invalid addresses:
1173
1188
                if( strpos( $email, '@' ) === false || strpos( $email, '.' ) === false ||
1174
1189
                        ! preg_match( $pattern_email, $email ) )
1175
1190
                {
1176
 
                        $Debuglog->add( 'BUILTIN REJECT ['.$email.']', 'email' );
1177
1191
                        return false;
1178
1192
                }
1179
1193
        }
1180
 
        else
1181
 
        {       // Plugin::EmailValidSyntax
1182
 
                $Debuglog->add( 'SYNTAX ACCEPT ['.$email.'] by plugin #'.$plug_ret['plugin_ID'],
1183
 
                        'email' );
1184
 
        }
1185
1194
 
1186
1195
        // Now we have a syntactically valid email. Let's see if there are any other
1187
1196
        // plugins that might decide that there's something else wrong with the address.
1188
1197
        $plug_ret = $Plugins->trigger_event_first_false( 'IsValidFilteredEmail',
1189
1198
                array(
1190
 
                        'email'  => $email,
 
1199
                        'email' => $email,
1191
1200
                        'format' => $format,
1192
1201
                ) );
1193
1202
 
1194
1203
        if( ! empty( $plug_ret ) )
1195
1204
        {
1196
 
                $Debuglog->add( 'POST SYNTAX REJECT ['.$email.'] by plugin #'.$plug_ret['plugin_ID'],
1197
 
                        'email' );
1198
1205
                return false;
1199
1206
        }
1200
1207
 
1201
 
        $Debuglog->add( 'ACCEPT ['.$email.']', 'email' );
1202
1208
        return true;
1203
1209
}
1204
1210
 
1215
1221
function xmlrpc_getposttitle($content)
1216
1222
{
1217
1223
        global $post_default_title;
1218
 
        if (preg_match('/<title>(.+?)<\/title>/is', $content, $matchtitle))
 
1224
        if( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) )
1219
1225
        {
1220
1226
                $post_title = $matchtitle[1];
1221
1227
        }
1231
1237
 * Also used by post by mail
1232
1238
 *
1233
1239
 * @deprecated by xmlrpc_getpostcategories()
1234
 
 * @todo EdB: this is used only by qp_srvc/getmail.php in v0.0.0 (EdB)
 
1240
 * @todo (1111): this is used only by qp_srvc/getmail.php in v0.0.0 (EdB)
1235
1241
 */
1236
1242
function xmlrpc_getpostcategory($content)
1237
1243
{
1238
 
        if (preg_match('/<category>([0-9]+?)<\/category>/is', $content, $matchcat))
 
1244
        if( preg_match( '/<category>([0-9]+?)<\/category>/is', $content, $matchcat ) )
1239
1245
        {
1240
1246
                return $matchcat[1];
1241
1247
        }
1283
1289
 
1284
1290
/**
1285
1291
 * Echo the XML-RPC call Result and optionally log into file
1286
 
 *
1287
1292
 * @param object XMLRPC response object
1288
1293
 * @param boolean true to echo
1289
1294
 * @param mixed File resource or == '' for no file logging.
1291
1296
function xmlrpc_displayresult( $result, $display = true, $log = '' )
1292
1297
{
1293
1298
        if( ! $result )
1294
 
        { // We got no response:
 
1299
        {
 
1300
                // We got no response
1295
1301
                if( $display ) echo T_('No response!')."<br />\n";
1296
1302
                return false;
1297
1303
        }
1298
1304
 
1299
1305
        if( $result->faultCode() )
1300
 
        { // We got a remote error:
 
1306
        {
 
1307
                // We got a remote error
1301
1308
                if( $display ) echo T_('Remote error'), ': ', $result->faultString(), ' (', $result->faultCode(), ")<br />\n";
1302
1309
                debug_fwrite($log, $result->faultCode().' -- '.$result->faultString());
1303
1310
                return false;
1304
1311
        }
1305
1312
 
1306
 
        // We'll display the response:
 
1313
        // We'll display the response
1307
1314
        $val = $result->value();
1308
1315
        $value = xmlrpc_decode_recurse($result->value());
1309
1316
 
1330
1337
 
1331
1338
/**
1332
1339
 * Log the XML-RPC call Result into LOG object
1333
 
 *
1334
1340
 * @param object XMLRPC response object
1335
1341
 * @param Log object to add messages to
1336
1342
 * @return boolean true = success, false = error
1338
1344
function xmlrpc_logresult( $result, & $message_Log, $log_payload = true )
1339
1345
{
1340
1346
        if( ! $result )
1341
 
        { // We got no response:
 
1347
        {
 
1348
                // We got no response
1342
1349
                $message_Log->add( T_('No response!'), 'error' );
1343
1350
                return false;
1344
1351
        }
1345
1352
 
1346
1353
        if( $result->faultCode() )
1347
 
        { // We got a remote error:
 
1354
        {
 
1355
                // We got a remote error
1348
1356
                $message_Log->add( T_('Remote error').': '.$result->faultString().' ('.$result->faultCode().')', 'error' );
1349
1357
                return false;
1350
1358
        }
1351
1359
 
1352
 
        // We got a response:
 
1360
        // We got a response
1353
1361
        $val = $result->value();
1354
1362
        $value = xmlrpc_decode_recurse($result->value());
1355
1363
 
1378
1386
 
1379
1387
function debug_fopen($filename, $mode) {
1380
1388
        global $debug;
1381
 
        if ($debug == 1 && ( !empty($filename) ) )
 
1389
        if( $debug == 1 && ( ! empty( $filename ) ) )
1382
1390
        {
1383
1391
                $fp = fopen($filename, $mode);
1384
1392
                return $fp;
1408
1416
 
1409
1417
 
1410
1418
/**
1411
 
 * Wrap pre tag around {@link var_dump()} for better debugging.
1412
 
 *
 
1419
 * Wrap pre tag around {@link var_dump()} for better debugging
1413
1420
 * @param $var__var__var__var__,... mixed variable(s) to dump
1414
1421
 */
1415
1422
function pre_dump( $var__var__var__var__ )
1422
1429
        $count = 0;
1423
1430
 
1424
1431
        if( ! empty($is_cli) )
1425
 
        { // CLI, no encoding of special chars:
 
1432
        {
 
1433
                // CLI, no encoding of special chars
1426
1434
                $count = 0;
1427
1435
                foreach( func_get_args() as $lvar )
1428
1436
                {
1430
1438
 
1431
1439
                        $count++;
1432
1440
                        if( $count < $func_num_args )
1433
 
                        { // Put newline between arguments
 
1441
                        {
 
1442
                                // Put newline between arguments
1434
1443
                                echo "\n";
1435
1444
                        }
1436
1445
                }
1437
1446
        }
1438
1447
        elseif( function_exists('xdebug_var_dump') )
1439
 
        { // xdebug already does fancy displaying:
 
1448
        {
 
1449
                // xdebug already does fancy displaying
1440
1450
 
1441
1451
                // no limits:
1442
1452
                $old_var_display_max_children = ini_set('xdebug.var_display_max_children', -1); // default: 128
1450
1460
 
1451
1461
                        $count++;
1452
1462
                        if( $count < $func_num_args )
1453
 
                        { // Put HR between arguments
 
1463
                        {
 
1464
                                // Put HR between arguments
1454
1465
                                echo "<hr />\n";
1455
1466
                        }
1456
1467
                }
1469
1480
                foreach( func_get_args() as $lvar )
1470
1481
                {
1471
1482
                        ob_start();
1472
 
                        var_dump($lvar); // includes "\n"; do not use var_export() because it does not detect recursion by design
 
1483
                        var_dump( $lvar ); // includes "\n"; do not use var_export() because it does not detect recursion by design
1473
1484
                        $buffer = ob_get_contents();
1474
1485
                        ob_end_clean();
1475
 
                        echo htmlspecialchars($buffer);
 
1486
                        echo htmlspecialchars( $buffer );
1476
1487
 
1477
1488
                        $count++;
1478
1489
                        if( $count < $func_num_args )
1479
 
                        { // Put HR between arguments
 
1490
                        {
 
1491
                                // Put HR between arguments
1480
1492
                                echo "<hr />\n";
1481
1493
                        }
1482
1494
                }
1490
1502
 * Get a function trace from {@link debug_backtrace()} as html table.
1491
1503
 *
1492
1504
 * Adopted from {@link http://us2.php.net/manual/de/function.debug-backtrace.php#47644}.
1493
 
 *
1494
1505
 * @param integer|NULL Get the last x entries from the stack (after $ignore_from is applied). Anything non-numeric means "all".
1495
1506
 * @param array After a key/value pair matches a stack entry, this and the rest is ignored.
1496
 
 *              For example, array('class' => 'DB') would exclude everything after the stack
1497
 
 *              "enters" class DB and everything that got called afterwards.
1498
 
 *              You can also give an array of arrays which means that every condition in one of the given array must match.
 
1507
 * For example, array( 'class' => 'DB' ) would exclude everything after the stack
 
1508
 * "enters" class DB and everything that got called afterwards.
 
1509
 * You can also give an array of arrays which means that every condition in one of the given array must match.
1499
1510
 * @param integer Number of stack entries to include, after $ignore_from matches.
1500
1511
 * @return string HTML table
1501
1512
 */
1513
1524
        $limited = false;   // remember if we have limited to $limit_to_last
1514
1525
 
1515
1526
        if( $ignore_from )
1516
 
        {       // we want to ignore from a certain point
 
1527
        {
 
1528
                // we want to ignore from a certain point
1517
1529
                $trace_length = 0;
1518
1530
                $break_because_of_offset = false;
1519
1531
 
1520
1532
                for( $i = count($backtrace); $i > 0; $i-- )
1521
 
                {       // Search the backtrace from behind (first call).
 
1533
                {
 
1534
                        // Search the backtrace from behind (first call)
1522
1535
                        $l_stack = & $backtrace[$i-1];
1523
1536
 
1524
1537
                        if( $break_because_of_offset && $offset_ignore_from < 1 )
1525
 
                        { // we've respected the offset, but need to break now
 
1538
                        {
 
1539
                                // we've respected the offset, but need to break now
1526
1540
                                break; // ignore from here
1527
1541
                        }
1528
1542
 
1529
1543
                        foreach( $ignore_from as $l_ignore_key => $l_ignore_value )
1530
 
                        {       // Check if we want to ignore from here
 
1544
                        {
 
1545
                                // Check if we want to ignore from here
1531
1546
                                if( is_array($l_ignore_value) )
1532
 
                                {       // It's an array - all must match
 
1547
                                {
 
1548
                                        // It's an array - all must match
1533
1549
                                        foreach( $l_ignore_value as $l_ignore_mult_key => $l_ignore_mult_val )
1534
1550
                                        {
1535
 
                                                if( !isset($l_stack[$l_ignore_mult_key]) /* not set with this stack entry */
 
1551
                                                if( ! isset( $l_stack[$l_ignore_mult_key] ) /* not set with this stack entry */
1536
1552
                                                        || strcasecmp($l_stack[$l_ignore_mult_key], $l_ignore_mult_val) /* not this value (case-insensitive) */ )
1537
1553
                                                {
1538
1554
                                                        continue 2; // next ignore setting, because not all match.
1566
1582
 
1567
1583
        $count_backtrace = count($backtrace);
1568
1584
        if( is_numeric($limit_to_last) && $limit_to_last < $count_backtrace )
1569
 
        {       // we want to limit to a maximum number
 
1585
        {
 
1586
                // we want to limit to a maximum number
1570
1587
                $limited = true;
1571
1588
                $backtrace = array_slice( $backtrace, 0, $limit_to_last );
1572
1589
                $count_backtrace = $limit_to_last;
1591
1608
                        }
1592
1609
                        $args = array();
1593
1610
                        if( isset($l_trace['args']) && is_array( $l_trace['args'] ) )
1594
 
                        {       // Prepare args:
 
1611
                        {
 
1612
                                // Prepare args
1595
1613
                                foreach( $l_trace['args'] as $l_arg )
1596
1614
                                {
1597
1615
                                        $l_arg_type = gettype($l_arg);
1605
1623
                                                        $args[] = '"'.htmlspecialchars(str_replace("\n", '', substr($l_arg, 0, 64))).((strlen($l_arg) > 64) ? '...' : '').'"';
1606
1624
                                                        break;
1607
1625
                                                case 'array':
1608
 
                                                        $args[] = 'Array('.count($l_arg).')';
 
1626
                                                        $args[] = 'Array('.count( $l_arg ).')';
1609
1627
                                                        break;
1610
1628
                                                case 'object':
1611
1629
                                                        $args[] = 'Object('.get_class($l_arg).')';
1692
1710
 * Dying means the application has encontered and unexpected situation,
1693
1711
 * i-e: something that should never occur during normal operation.
1694
1712
 * Examples: database broken, user changed URL by hand...
1695
 
 *
1696
1713
 * @param string Message to output
1697
1714
 * @param array Additional params
1698
 
 *        - "status" (Default: '500 Internal Server Error')
 
1715
 * - "status" (Default: '500 Internal Server Error')
1699
1716
 */
1700
1717
function debug_die( $additional_info = '', $params = array() )
1701
1718
{
1702
1719
        global $debug, $app_baseurl;
1703
1720
        global $log_app_errors, $app_name, $is_cli;
1704
1721
 
1705
 
        $params = array_merge( array(
1706
 
                'status' => '500 Internal Server Error',
1707
 
                ), $params );
 
1722
        $params = array_merge( array( 'status' => '500 Internal Server Error', ), $params );
1708
1723
 
1709
1724
        if( $is_cli )
1710
 
        { // Command line interface, e.g. in cron_exec.php:
 
1725
        {
 
1726
                // Command line interface, e.g. in cron_exec.php
1711
1727
                echo '== '.T_('An unexpected error has occurred!')." ==\n";
1712
1728
                echo T_('If this error persists, please report it to the administrator.')."\n";
1713
1729
                echo T_('Additional information about this error:')."\n";
1719
1735
                // This should help preventing indexing robots from indexing the error :P
1720
1736
                if( ! headers_sent() )
1721
1737
                {
1722
 
                        load_funcs('_core/_template.funcs.php');
 
1738
                        load_funcs( '_core/_template.funcs.php' );
1723
1739
                        header_content_type( 'text/html' ); // it's ok, if a previous header would be replaced;
1724
1740
                        $status_header = $_SERVER['SERVER_PROTOCOL'].' '.$params['status'];
1725
1741
                        header($status_header);
1740
1756
                }
1741
1757
        }
1742
1758
 
1743
 
        if( $log_app_errors > 1 || $debug )
1744
 
        { // Prepare backtrace
 
1759
        $log_app_errors = 1;
 
1760
        if( $debug )
 
1761
        {
 
1762
                // Prepare backtrace
1745
1763
                $backtrace = debug_get_backtrace();
1746
1764
 
1747
1765
                if( $log_app_errors > 1 || $is_cli )
1748
1766
                {
1749
 
                        $backtrace_cli = trim(strip_tags($backtrace));
1750
 
                }
1751
 
        }
1752
 
 
1753
 
        if( $log_app_errors )
1754
 
        { // Log error through PHP's logging facilities:
1755
 
                $log_message = $app_name.' error: ';
1756
 
                if( ! empty($additional_info) )
1757
 
                {
1758
 
                        $log_message .= trim( strip_tags($additional_info) );
1759
 
                }
1760
 
                else
1761
 
                {
1762
 
                        $log_message .= 'No info specified in debug_die()';
1763
 
                }
1764
 
 
1765
 
                // Get file and line info:
1766
 
                $file = 'Unknown';
1767
 
                $line = 'Unknown';
1768
 
                if( function_exists('debug_backtrace') /* PHP 4.3 */ )
1769
 
                { // get the file and line
1770
 
                        foreach( debug_backtrace() as $v )
1771
 
                        {
1772
 
                                if( isset($v['function']) && $v['function'] == 'debug_die' )
1773
 
                                {
1774
 
                                        $file = isset($v['file']) ? $v['file'] : 'Unknown';
1775
 
                                        $line = isset($v['line']) ? $v['line'] : 'Unknown';
1776
 
                                        break;
1777
 
                                }
1778
 
                        }
1779
 
                }
1780
 
                $log_message .= ' in '.$file.' at line '.$line;
1781
 
 
1782
 
                if( $log_app_errors > 1 )
1783
 
                { // Append backtrace:
1784
 
                        // indent after newlines:
1785
 
                        $backtrace_cli = preg_replace( '~(\S)(\n)(\S)~', '$1  $2$3', $backtrace_cli );
1786
 
                        $log_message .= "\nBacktrace:\n".$backtrace_cli;
1787
 
                }
1788
 
                $log_message .= "\nREQUEST_URI:  ".( isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '-' );
1789
 
                $log_message .= "\nHTTP_REFERER: ".( isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '-' );
1790
 
 
1791
 
                error_log( str_replace("\n", ' / ', $log_message), 0 /* PHP's system logger */ );
1792
 
        }
1793
 
 
 
1767
                        $backtrace_cli = trim( strip_tags( $backtrace ) );
 
1768
                }
 
1769
        }
 
1770
 
 
1771
        // Log error through PHP's logging facilities
 
1772
        $log_message = $app_name.' error: ';
 
1773
        if( ! empty($additional_info) )
 
1774
        {
 
1775
                $log_message .= trim( strip_tags($additional_info) );
 
1776
        }
 
1777
        else
 
1778
        {
 
1779
                $log_message .= 'No info specified in debug_die()';
 
1780
        }
 
1781
 
 
1782
        // Get file and line info
 
1783
        $file = 'Unknown';
 
1784
        $line = 'Unknown';
 
1785
        // get the file and line
 
1786
        foreach( debug_backtrace() as $v )
 
1787
        {
 
1788
                if( isset( $v['function'] ) && $v['function'] == 'debug_die' )
 
1789
                {
 
1790
                        $file = isset( $v['file'] ) ? $v['file'] : 'Unknown';
 
1791
                        $line = isset( $v['line'] ) ? $v['line'] : 'Unknown';
 
1792
                        break;
 
1793
                }
 
1794
        }
 
1795
        $log_message .= ' in '.$file.' at line '.$line;
 
1796
 
 
1797
        if( $log_app_errors > 1 )
 
1798
        {
 
1799
                // Append backtrace
 
1800
                // indent after newlines
 
1801
                $backtrace_cli = preg_replace( '~(\S)(\n)(\S)~', '$1  $2$3', $backtrace_cli );
 
1802
                $log_message .= "\nBacktrace:\n".$backtrace_cli;
 
1803
        }
 
1804
 
 
1805
        $log_message .= "\nREQUEST_URI:  ".( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '-' );
 
1806
        $log_message .= "\nHTTP_REFERER: ".( isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '-' );
 
1807
 
 
1808
        error_log( str_replace("\n", ' / ', $log_message), 0 /* PHP's system logger */ );
1794
1809
 
1795
1810
        // DEBUG OUTPUT:
1796
1811
        if( $debug )
1803
1818
 
1804
1819
        // EXIT:
1805
1820
        if( ! $is_cli )
1806
 
        { // Attempt to keep the html valid (but it doesn't really matter anyway)
 
1821
        {
 
1822
                // Attempt to keep the html valid (but it doesn't really matter anyway)
1807
1823
                echo '</body></html>';
1808
1824
        }
1809
1825
 
1810
 
        die(1); // Error code 1. Note: This will still call the shutdown function.
 
1826
        die(1); // Error code 1. Note: This will still call the shutdown function.
1811
1827
}
1812
1828
 
1813
1829
 
1814
1830
/**
1815
 
 * Outputs Bad request Error message. When in debug mode it also prints a backtrace.
 
1831
 * Outputs Bad request Error message. When in debug mode it also prints a backtrace
1816
1832
 *
1817
1833
 * This should be used when a bad user input is detected?
1818
 
 *
1819
1834
 * @param string Message to output (HTML)
1820
1835
 */
1821
1836
function bad_request_die( $additional_info = '' )
1826
1841
        // This should help preventing indexing robots from indexing the error :P
1827
1842
        if( ! headers_sent() )
1828
1843
        {
1829
 
                load_funcs('_core/_template.funcs.php');
 
1844
                load_funcs( '_core/_template.funcs.php' );
1830
1845
                header_content_type( 'text/html' ); // it's ok, if a previous header would be replaced;
1831
1846
                header('HTTP/1.0 400 Bad Request');
1832
1847
        }
1838
1853
        echo '<p><a href="'.$app_baseurl.'">'.T_('Go back to home page').'</a></p>';
1839
1854
        echo '</div>';
1840
1855
 
1841
 
        if( !empty( $additional_info ) )
 
1856
        if( ! empty( $additional_info ) )
1842
1857
        {
1843
1858
                echo '<div style="background-color: #ddd; padding: 1ex; margin-bottom: 1ex;">';
1844
1859
                echo '<h3>'.T_('Additional information about this error:').'</h3>';
1859
1874
 
1860
1875
 
1861
1876
/**
1862
 
 * T-Tag: Outputs debug info according to {@link $debug} or $force param.
1863
 
 *
 
1877
 * Outputs debug info according to {@link $debug} or $force param
1864
1878
 * @param boolean true to force output regardless of {@link $debug}
1865
1879
 * @param boolean true to force clean output (without HTML) regardless of {@link $is_cli}
1866
1880
 */
1873
1887
        global $DB;
1874
1888
        global $debug;
1875
1889
        global $debug_done;
 
1890
        global $debug_obhandler;
1876
1891
        global $debug_visitors;
1877
1892
        global $Debuglog;
1878
 
        /**
1879
 
         * @var Hit
1880
 
         */
1881
1893
        global $Hit;
1882
1894
        global $is_cli;
1883
 
        global $obhandler_debug;
1884
1895
        global $ReqHost;
1885
1896
        global $ReqPath;
1886
1897
        global $Session;
1887
1898
        global $Timer;
1888
1899
 
1889
1900
        if( ! is_logged_in() && ! $debug_visitors )
1890
 
        { // No debug for visitors
 
1901
        {
 
1902
                // No debug for visitors
1891
1903
                return;
1892
1904
        }
1893
1905
 
1894
 
        if( !$force )
 
1906
        if( ! $force )
1895
1907
        {
1896
 
                if( !empty( $debug_done ) )
1897
 
                { // Already displayed!
 
1908
                if( ! empty( $debug_done ) )
 
1909
                {
 
1910
                        // Already displayed!
1898
1911
                        return;
1899
1912
                }
1900
1913
 
1901
1914
                if( empty( $debug ) )
1902
 
                { // No debug output desired:
 
1915
                {
 
1916
                        // No debug output desired
1903
1917
                        return;
1904
1918
                }
1905
1919
 
1906
1920
                if( $debug < 2 && ( empty( $Hit ) || $Hit->get_agent_type() != 'browser' ) )
1907
 
                {       // Don't display if it's not a browser (very needed for proper RSS display btw)
 
1921
                {
 
1922
                        // Don't display if it's not a browser (very needed for proper RSS display btw)
1908
1923
                        // ($Hit is empty e.g. during install)
1909
1924
                        return;
1910
1925
                }
1911
1926
        }
 
1927
 
1912
1928
        //Make sure debug output only happens once:
1913
1929
        $debug_done = true;
1914
1930
 
1916
1932
        $clean = $is_cli || $force_clean;
1917
1933
        $printf_format = '| %-45s | %-5s | %-7s | %-5s |';
1918
1934
        $table_headerlen = 73;
1919
 
        /* This calculates the number of dashes to print e. g. on the top and
1920
 
         * bottom of the table and after the header, making the table look
1921
 
         * better (looks like the tables of the mysql command line client).
1922
 
         * Normally, the value won't change, so it's hardcoded above. If you
1923
 
         * change the printf() format above, this might be useful.
1924
 
        preg_match_all( '#\d+#', $printf_format, $table_headerlen );
1925
 
        $table_headerlen = array_sum( $table_headerlen[0] ) +
1926
 
                                                                        strlen( preg_replace( '#[^ \|]+#', '',
1927
 
                                                                                                $printf_format ) ) - 2;
1928
 
        */
 
1935
 
 
1936
        // This calculates the number of dashes to print e. g. on the top and bottom of the
 
1937
        // table and after the header, making the table look better (looks like the tables of
 
1938
        // the mysql command line client). Normally, the value won't change, so it's hardcoded
 
1939
        // above. If you change the printf() format above, this might be useful.
 
1940
#       preg_match_all( '#\d+#', $printf_format, $table_headerlen );
 
1941
#       $table_headerlen = array_sum( $table_headerlen[0] ) +
 
1942
#               strlen( preg_replace( '#[^ \|]+#', '', $printf_format ) ) - 2;
1929
1943
 
1930
1944
        $ReqHostPathQuery = $ReqHost.$ReqPath.( empty( $_SERVER['QUERY_STRING'] ) ? '' : '?'.$_SERVER['QUERY_STRING'] );
1931
1945
 
1932
1946
        echo "\n\n\n";
1933
1947
        echo ( $clean ? '*** Debug info ***'."\n\n" : '<div class="debug" id="debug_info"><h2>Debug info</h2>' );
1934
1948
 
1935
 
        $Debuglog->add( 'Len of serialized $cache_imgsize: '.strlen(serialize($cache_imgsize)), 'memory' );
1936
 
        $Debuglog->add( 'Len of serialized $cache_File: '.strlen(serialize($cache_File)), 'memory' );
1937
 
 
1938
 
        if( !$obhandler_debug )
1939
 
        { // don't display changing items when we want to test obhandler
 
1949
        if( ! $debug_obhandler )
 
1950
        {
 
1951
                // don't display changing items when we want to test obhandler
1940
1952
 
1941
1953
                // Timer table:
1942
1954
                $time_page = $Timer->get_duration( 'total' );
1947
1959
                        {
1948
1960
                                continue;
1949
1961
                        }
1950
 
                        $timer_rows[ $l_cat ] = $Timer->get_duration( $l_cat );
 
1962
                        $timer_rows[$l_cat] = $Timer->get_duration( $l_cat );
1951
1963
                }
 
1964
 
1952
1965
                // arsort( $timer_rows );
1953
1966
                ksort( $timer_rows );
1954
1967
 
1955
 
                // Remove "total", it will get outputted as the last one:
 
1968
                // Remove "total", it will get outputted as the last one
1956
1969
                $total_time = $timer_rows['total'];
1957
1970
                unset($timer_rows['total']);
1958
1971
 
1959
 
                if ( $clean )
 
1972
                if( $clean )
1960
1973
                {
1961
1974
                        echo '== Timers =='."\n\n";
1962
1975
                        echo '+'.str_repeat( '-', $table_headerlen ).'+'."\n";
1965
1978
                }
1966
1979
                else
1967
1980
                {
1968
 
                        echo '<table><thead>'
1969
 
                                .'<tr><th colspan="4" class="center">Timers</th></tr>'
1970
 
                                .'<tr><th>Category</th><th>Time</th><th>%</th><th>Count</th></tr>'
1971
 
                                .'</thead><tbody>';
 
1981
                        echo '<table><thead><tr><th colspan="4" class="center">Timers</th></tr><tr>'
 
1982
                                .'<th>Category</th><th>Time</th><th>%</th><th>Count</th></tr></thead><tbody>';
1972
1983
                }
1973
1984
 
1974
1985
                $table_rows_collapse = array();
1976
1987
                {
1977
1988
                        $percent_l_cat = $time_page > 0 ? number_format( 100/$time_page * $l_time, 2 ) : '0';
1978
1989
 
1979
 
                        if ( $clean )
 
1990
                        if( $clean )
1980
1991
                        {
1981
1992
                                $row = sprintf( $printf_format, $l_cat, $l_time, $percent_l_cat.'%', $Timer->get_count( $l_cat ) );
1982
1993
                        }
2016
2027
 
2017
2028
                // Output "total":
2018
2029
                $percent_total = $time_page > 0 ? number_format( 100/$time_page * $total_time, 2 ) : '0';
2019
 
                if ( $clean )
 
2030
                if( $clean )
2020
2031
                {
2021
2032
                        echo sprintf( $printf_format, 'total', $total_time, $percent_total.'%', $Timer->get_count('total') );
2022
2033
                }
2029
2040
                                .'<td class="right">'.$Timer->get_count('total').'</td></tr>';
2030
2041
                }
2031
2042
 
2032
 
                if ( $clean )
 
2043
                if( $clean )
2033
2044
                {
2034
2045
                        echo '+'.str_repeat( '-', $table_headerlen ).'+'."\n\n";
2035
2046
                }
2041
2052
 
2042
2053
                if( isset($DB) )
2043
2054
                {
2044
 
                        if ( $clean )
 
2055
                        if( $clean )
2045
2056
                        {
2046
2057
                                echo 'Database queries: '.$DB->num_queries."\n";
2047
2058
                        }
2048
2059
                        else
2049
2060
                        {
2050
 
                                echo '<a href="'.$ReqHostPathQuery.'#evo_debug_queries">Database queries: '.$DB->num_queries.'.</a><br />';
 
2061
                                echo '<a href="'.$ReqHostPathQuery.'#app_debug_queries">Database queries: '.$DB->num_queries.'.</a><br />';
2051
2062
                        }
2052
2063
                }
2053
2064
 
2076
2087
        }
2077
2088
 
2078
2089
        // DEBUGLOG(s) FROM PREVIOUS SESSIONS, after REDIRECT(s) (with list of categories at top):
2079
 
        if( isset($Session) && ($sess_Debuglogs = $Session->get('Debuglogs')) && ! empty($sess_Debuglogs) )
 
2090
        if( isset( $Session ) && ( $sess_Debuglogs = $Session->get( 'Debuglogs' ) ) && ! empty( $sess_Debuglogs ) )
2080
2091
        {
2081
2092
                $count_sess_Debuglogs = count($sess_Debuglogs);
2082
2093
                if( $count_sess_Debuglogs > 1 )
2083
 
                { // Links to those Debuglogs:
2084
 
                        if ( $clean )
2085
 
                        {       // kind of useless, but anyway...
 
2094
                {
 
2095
                        // Links to those Debuglogs
 
2096
                        if( $clean )
 
2097
                        {
 
2098
                                // kind of useless, but anyway...
2086
2099
                                echo "\n".'There are '.$count_sess_Debuglogs.' Debuglogs from redirected pages.'."\n";
2087
2100
                        }
2088
2101
                        else
2100
2113
                {
2101
2114
                        $log_categories = array( 'error', 'note', 'all' ); // Categories to output (in that order)
2102
2115
 
2103
 
                        if ( $clean )
 
2116
                        if( $clean )
2104
2117
                        {
2105
 
                                $log_container_head = "\n".'== Debug messages from redirected page (#'.($k+1).') =='."\n"
2106
 
                                                                         .'See below for the Debuglog from the current request.'."\n";
 
2118
                                $log_container_head = "\n".'== Debug messages from redirected page (#'.( $k+1 ).') =='."\n"
 
2119
                                        .'See below for the Debuglog from the current request.'."\n";
2107
2120
                                echo format_to_output(
2108
2121
                                        $sess_Debuglog->display( array(
2109
2122
                                                        'container' => array( 'string' => $log_container_head, 'template' => false ),
2136
2149
                $Session->delete( 'Debuglogs' );
2137
2150
        }
2138
2151
 
2139
 
 
2140
2152
        // CURRENT DEBUGLOG (with list of categories at top):
2141
2153
        $log_categories = array( 'error', 'note', 'all' ); // Categories to output (in that order)
2142
2154
        $log_container_head = $clean ? ( "\n".'== Debug messages =='."\n" ) : '<h3 id="debug_debuglog">Debug messages</h3>';
2143
2155
        if( ! empty($sess_Debuglogs) )
2144
 
        { // link to first sess_Debuglog:
2145
 
                if ( $clean )
 
2156
        {
 
2157
                // link to first sess_Debuglog
 
2158
                if( $clean )
2146
2159
                {
2147
2160
                        $log_container_head .= 'See above for the Debuglog(s) from before the redirect.'."\n";
2148
2161
                }
2152
2165
                }
2153
2166
        }
2154
2167
 
2155
 
        if ( ! $clean )
 
2168
        if( ! $clean )
2156
2169
        {
2157
2170
                $log_cats = array_keys($Debuglog->get_messages( $log_categories )); // the real list (with all replaced and only existing ones)
2158
2171
                $log_head_links = array();
2169
2182
                                '', false, $log_categories ),
2170
2183
                        'htmlbody' );
2171
2184
 
2172
 
                echo '<h3 id="evo_debug_queries">DB</h3>';
 
2185
                echo '<h3 id="app_debug_queries">DB</h3>';
2173
2186
        }
2174
2187
        else
2175
2188
        {
2185
2198
 
2186
2199
        if($app_db_config)
2187
2200
        {
2188
 
                if ( ! $clean )
 
2201
                if( ! $clean )
2189
2202
                {
2190
2203
                        echo '<pre>';
2191
2204
                }
2199
2212
                echo $clean ? "\n" : '</pre>';
2200
2213
        }
2201
2214
 
2202
 
        if( !isset($DB) )
 
2215
        if( ! isset($DB) )
2203
2216
        {
2204
2217
                echo 'No DB object.'.( $clean ? "\n" : '' );
2205
2218
        }
2208
2221
                $DB->dump_queries( ! $clean );
2209
2222
        }
2210
2223
 
2211
 
        if ( ! $clean )
 
2224
        if( ! $clean )
2212
2225
        {
2213
2226
                echo '</div>';
2214
2227
        }
2224
2237
        $header_str = preg_replace( '~(\r|\n).*$~s', '', trim($header_str) );
2225
2238
 
2226
2239
        if( $close_brace && strpos( $header_str, '<' ) !== false && strpos( $header_str, '>' ) === false )
2227
 
        { // We have probably stripped the '>' at the end!
 
2240
        {
 
2241
                // We have probably stripped the '>' at the end!
2228
2242
                $header_str .= '>';
2229
2243
        }
2230
2244
 
2233
2247
 
2234
2248
/**
2235
2249
 * Encode to RFC 1342 "Representation of Non-ASCII Text in Internet Message Headers"
2236
 
 *
2237
2250
 * @param string
2238
2251
 * @param string 'Q' for Quoted printable, 'B' for base64
2239
2252
 */
2240
2253
function mail_encode_header_string( $header_str, $mode = 'Q' )
2241
2254
{
2242
 
        global $evo_charset;
 
2255
        global $app_charset;
2243
2256
 
2244
2257
        /* mbstring way  (did not work for Alex RU)
2245
2258
        if( function_exists('mb_encode_mimeheader') )
2246
 
        { // encode subject
 
2259
        {
 
2260
                // encode subject
2247
2261
                $orig = mb_internal_encoding();
2248
2262
                mb_internal_encoding('utf-8');
2249
2263
                $r = mb_encode_mimeheader( $header_str, 'utf-8', $mode );
2253
2267
        */
2254
2268
 
2255
2269
        if( preg_match( '�[^a-z0-9!*+\-/ ]�i', $header_str ) )
2256
 
        {       // If the string actually needs some encoding
 
2270
        {
 
2271
                // If the string actually needs some encoding
2257
2272
                if( $mode == 'Q' )
2258
 
                {       // Quoted printable is best for reading with old/text terminal mail reading/debugging stuff:
 
2273
                {
 
2274
                        // Quoted printable is best for reading with old/text terminal mail reading/debugging stuff:
2259
2275
                        $header_str = preg_replace( '�([^a-z0-9!*+\-/ ])�ie', 'sprintf("=%02x", ord(StripSlashes("\\1")))', $header_str );
2260
2276
                        $header_str = str_replace( ' ', '_', $header_str );
2261
2277
 
2262
 
                        $header_str = '=?'.$evo_charset.'?Q?'.$header_str.'?=';
 
2278
                        $header_str = '=?'.$app_charset.'?Q?'.$header_str.'?=';
2263
2279
                }
2264
2280
                else
2265
 
                { // Base 64 -- Alex RU way:
2266
 
                        $header_str = '=?'.$evo_charset.'?B?'.base64_encode( $header_str ).'?=';
 
2281
                {
 
2282
                        // Base 64 -- Alex RU way
 
2283
                        $header_str = '=?'.$app_charset.'?B?'.base64_encode( $header_str ).'?=';
2267
2284
                }
2268
2285
        }
2269
2286
 
2287
2304
 * @param string Subject of the mail
2288
2305
 * @param string The message text
2289
2306
 * @param string From address, being added to headers (we'll prevent injections);
2290
 
 *               see {@link http://securephp.damonkohler.com/index.php/Email_Injection}.
2291
 
 *               Defaults to {@link $notify_from} if NULL.
 
2307
 * see {@link http://securephp.damonkohler.com/index.php/Email_Injection}.
 
2308
 * Defaults to {@link $notify_from} if NULL.
2292
2309
 * @param string From name.
2293
2310
 * @param array Additional headers ( headername => value ). Take care of injection!
2294
2311
 * @return boolean True if mail could be sent (not necessarily delivered!), false if not - (return value of {@link mail()})
2295
2312
 */
2296
2313
function send_mail( $to, $to_name, $subject, $message, $from = NULL, $from_name = NULL, $headers = array() )
2297
2314
{
2298
 
        global $debug, $app_name, $app_version, $app_name, $current_locale, $current_charset, $evo_charset;
2299
 
        global $locales, $Debuglog, $notify_from;
 
2315
        global $app_version;
 
2316
        global $app_name;
 
2317
        global $current_locale;
 
2318
        global $current_charset;
 
2319
        global $debug;
 
2320
        global $app_charset;
 
2321
        global $locales;
 
2322
        global $notify_from;
 
2323
        global $Plugins;
2300
2324
 
2301
2325
        $NL = "\n";
2302
2326
 
2303
 
        if( !is_array( $headers ) )
2304
 
        { // Make sure $headers is an array
 
2327
        if( ! is_array( $headers ) )
 
2328
        {
 
2329
                // Make sure $headers is an array
2305
2330
                $headers = array( $headers );
2306
2331
        }
2307
2332
 
2308
 
        if( empty($from) )
 
2333
        if( empty( $from ) )
2309
2334
        {
2310
2335
                $from = $notify_from;
2311
2336
        }
2312
2337
 
2313
2338
        if( ! is_windows() )
2314
 
        {       // fplanque: Windows XP, Apache 1.3, PHP 4.4, MS SMTP : will not accept "nice" addresses.
2315
 
                if( !empty( $to_name ) )
 
2339
        {
 
2340
                // fplanque: Windows XP, Apache 1.3, PHP 4.4, MS SMTP : will not accept "nice" addresses.
 
2341
                if( ! empty( $to_name ) )
2316
2342
                {
2317
2343
                        $to = '"'.mail_encode_header_string($to_name).'" <'.$to.'>';
2318
2344
                }
2319
 
                if( !empty( $from_name ) )
 
2345
                if( ! empty( $from_name ) )
2320
2346
                {
2321
2347
                        $from = '"'.mail_encode_header_string($from_name).'" <'.$from.'>';
2322
2348
                }
2332
2358
 
2333
2359
        // Convert encoding of message (from internal encoding to the one of the message):
2334
2360
        // fp> why do we actually convert to $current_charset?
2335
 
        // dh> I do not remember. Appears to make sense sending it unconverted in $evo_charset.
2336
 
        $message = convert_charset( $message, $current_charset, $evo_charset );
 
2361
        // dh> I do not remember. Appears to make sense sending it unconverted in $app_charset.
 
2362
        $message = convert_charset( $message, $current_charset, $app_charset );
2337
2363
        // Specify charset and content-type of email
2338
2364
        $headers['Content-Type'] = 'text/plain; charset='.$current_charset;
2339
2365
 
2340
 
 
2341
 
        // ADDITIONAL HEADERS:
 
2366
        // ADDITIONAL HEADERS
2342
2367
        $headers['X-Mailer'] = $app_name.' '.$app_version.' - PHP/'.phpversion();
2343
2368
        $headers['X-Remote-Addr'] = implode( ',', get_ip_list() );
2344
2369
 
2345
 
 
2346
 
        // COMPACT HEADERS:
 
2370
        // COMPACT HEADERS
2347
2371
        $headerstring = '';
2348
2372
        reset( $headers );
2349
2373
        while( list( $lKey, $lValue ) = each( $headers ) )
2350
 
        { // Add additional headers
 
2374
        {
 
2375
                // Add additional headers
2351
2376
                $headerstring .= $lKey.': '.$lValue.$NL;
2352
2377
        }
2353
2378
 
2354
 
        // SEND MESSAGE:
2355
 
        global $Plugins;
 
2379
        // SEND MESSAGE
2356
2380
        if( ! $Plugins->trigger_event_first_true( 'ModifySendMessage', array( $to, $subject, $message, $headerstring, $debug ) ) )
2357
2381
        {
2358
2382
                // if no plugin takes over we do boring stuff
2359
2383
                if( $debug > 1 )
2360
 
                {       // We agree to die for debugging...
 
2384
                {
 
2385
                        // We agree to die for debugging...
2361
2386
                        if( ! mail( $to, $subject, $message, $headerstring ) )
2362
2387
                        {
2363
 
                                debug_die( 'Sending mail from &laquo;'.htmlspecialchars($from).'&raquo; to &laquo;'.htmlspecialchars($to).'&raquo;, Subject &laquo;'.htmlspecialchars($subject).'&raquo; FAILED.' );
 
2388
                                debug_die( 'Sending mail from &laquo;'.htmlspecialchars( $from ).'&raquo; to &laquo;'.htmlspecialchars( $to ).'&raquo;, Subject &laquo;'.htmlspecialchars( $subject ).'&raquo; FAILED.' );
2364
2389
                        }
2365
2390
                }
2366
2391
                else
2367
 
                {       // Soft debugging only....
 
2392
                {
 
2393
                        // Soft debugging only....
2368
2394
                        if( ! @mail( $to, $subject, $message, $headerstring ) )
2369
2395
                        {
2370
 
                                $Debuglog->add( 'Sending mail from &laquo;'.htmlspecialchars($from).'&raquo; to &laquo;'.htmlspecialchars($to).'&raquo;, Subject &laquo;'.htmlspecialchars($subject).'&raquo; FAILED.', 'error' );
2371
2396
                                return false;
2372
2397
                        }
2373
2398
                }
2374
2399
        }
2375
2400
 
2376
 
        $Debuglog->add( 'Sent mail from &laquo;'.htmlspecialchars($from).'&raquo; to &laquo;'.htmlspecialchars($to).'&raquo;, Subject &laquo;'.htmlspecialchars($subject).'&raquo;.' );
2377
2401
        return true;
2378
2402
}
2379
2403
 
2414
2438
/**
2415
2439
 * Create IMG tag for an action icon.
2416
2440
 *
 
2441
 * @todo (EdB) $icon_weight and $word_weight need serious overhaul.
 
2442
 *
2417
2443
 * @param string TITLE text (IMG and A link)
2418
2444
 * @param string icon code for {@link get_icon()}
2419
2445
 * @param string URL where the icon gets linked to (empty to not wrap the icon in a link)
2463
2489
        }
2464
2490
 
2465
2491
        // "use_js_popup": open link in a JS popup
2466
 
        // TODO: this needs to be rewritten with jQuery instead
 
2492
        // @todo (0000): this needs to be rewritten with jQuery instead
2467
2493
        if( false && ! empty($link_attribs['use_js_popup']) )
2468
2494
        {
2469
2495
                $popup_js = 'var win = new PopupWindow(); win.setUrl( \''.$link_attribs['href'].'\' ); win.setSize(  ); ';
2500
2526
        // NOTE: We do not use format_to_output with get_field_attribs_as_string() here, because it interferes with the Results class (eval() fails on entitied quotes..) (blueyed)
2501
2527
        $r = '<a '.get_field_attribs_as_string( $link_attribs, false ).'>';
2502
2528
 
2503
 
        $display_icon = ($icon_weight >= $UserSettings->get('action_icon_threshold'));
2504
 
        $display_word = ($word_weight >= $UserSettings->get('action_word_threshold'));
 
2529
        $display_icon = ( $icon_weight >= 3 );
 
2530
        $display_word = ( $word_weight >= 3 );
2505
2531
 
2506
2532
        if( $display_icon || ! $display_word )
2507
 
        {       // We MUST display an action icon in order to make the user happy:
 
2533
        {
 
2534
                // We MUST display an action icon in order to make the user happy
2508
2535
                // OR we default to icon because the user doesn't want the word either!!
2509
2536
 
2510
 
                $r .= get_icon( $icon, 'imgtag', array( 'title'=>$title ), true );
 
2537
                $r .= get_icon( $icon, 'imgtag', array( 'title' => $title ), true );
2511
2538
        }
2512
2539
 
2513
2540
        if( $display_word )
2514
 
        {       // We MUST display an action word in order to make the user happy:
2515
 
 
 
2541
        {
 
2542
                // We MUST display an action word in order to make the user happy
2516
2543
                if( $display_icon )
2517
 
                { // We already have an icon, display a SHORT word:
2518
 
                        if( !empty($word) )
2519
 
                        {       // We have provided a short word:
 
2544
                {
 
2545
                        // We already have an icon, display a SHORT word
 
2546
                        if( ! empty( $word ) )
 
2547
                        {
 
2548
                                // We have provided a short word
2520
2549
                                $r .= $word;
2521
2550
                        }
2522
2551
                        else
2523
 
                        {       // We fall back to alt:
 
2552
                        {
 
2553
                                // We fall back to alt
2524
2554
                                $r .= get_icon( $icon, 'legend' );
2525
2555
                        }
2526
2556
                }
2527
2557
                else
2528
 
                {       // No icon display, let's display a LONG word/text:
 
2558
                {
 
2559
                        // No icon display, let's display a LONG word/text
2529
2560
                        $r .= trim( $title, ' .!' );
2530
2561
                }
2531
2562
        }
2552
2583
 */
2553
2584
function get_icon( $iconKey, $what = 'imgtag', $params = NULL, $include_in_legend = false )
2554
2585
{
2555
 
        global $admin_subdir, $Debuglog, $use_strict;
 
2586
        global $admin_subdir;
2556
2587
        global $conf_path;
2557
 
        global $rsc_path, $rsc_url;
 
2588
        global $rsc_path;
 
2589
        global $rsc_url;
2558
2590
 
2559
2591
        if( ! function_exists('get_icon_info') )
2560
2592
        {
2570
2602
        switch( $what )
2571
2603
        {
2572
2604
                case 'rollover':
2573
 
                        if( isset( $icon['rollover'] ) )
2574
 
                        {       // Image has rollover available
2575
 
                                return $icon['rollover'];
2576
 
                        }
2577
 
                        return false;
2578
 
                        /* BREAK */
2579
 
 
 
2605
                if( isset( $icon['rollover'] ) )
 
2606
                {
 
2607
                        // Image has rollover available
 
2608
                        return $icon['rollover'];
 
2609
                }
 
2610
                return false;
 
2611
                /* BREAK */
2580
2612
 
2581
2613
                case 'file':
2582
 
                        return $rsc_path.$icon['file'];
2583
 
                        /* BREAK */
2584
 
 
 
2614
                return $rsc_path.$icon['file'];
 
2615
                /* BREAK */
2585
2616
 
2586
2617
                case 'alt':
2587
 
                        if( isset( $icon['alt'] ) )
2588
 
                        { // alt tag from $map_iconfiles
2589
 
                                return $icon['alt'];
2590
 
                        }
2591
 
                        else
2592
 
                        { // fallback to $iconKey as alt-tag
2593
 
                                return $iconKey;
2594
 
                        }
2595
 
                        /* BREAK */
2596
 
 
 
2618
                if( isset( $icon['alt'] ) )
 
2619
                {
 
2620
                        // alt tag from $map_iconfiles
 
2621
                        return $icon['alt'];
 
2622
                }
 
2623
                else
 
2624
                {
 
2625
                        // fallback to $iconKey as alt-tag
 
2626
                        return $iconKey;
 
2627
                }
 
2628
                /* BREAK */
2597
2629
 
2598
2630
                case 'legend':
2599
 
                        if( isset( $icon['legend'] ) )
2600
 
                        { // legend tag from $map_iconfiles
2601
 
                                return $icon['legend'];
2602
 
                        }
2603
 
                        else
2604
 
                        if( isset( $icon['alt'] ) )
2605
 
                        { // alt tag from $map_iconfiles
2606
 
                                return $icon['alt'];
2607
 
                        }
2608
 
                        else
2609
 
                        { // fallback to $iconKey as alt-tag
2610
 
                                return $iconKey;
2611
 
                        }
2612
 
                        /* BREAK */
 
2631
                if( isset( $icon['legend'] ) )
 
2632
                {
 
2633
                        // legend tag from $map_iconfiles
 
2634
                        return $icon['legend'];
 
2635
                }
 
2636
                else
 
2637
                if( isset( $icon['alt'] ) )
 
2638
                {
 
2639
                        // alt tag from $map_iconfiles
 
2640
                        return $icon['alt'];
 
2641
                }
 
2642
                else
 
2643
                {
 
2644
                        // fallback to $iconKey as alt-tag
 
2645
                        return $iconKey;
 
2646
                }
 
2647
                /* BREAK */
2613
2648
 
2614
2649
 
2615
2650
                case 'class':
2616
 
                        if( isset($icon['class']) )
2617
 
                        {
2618
 
                                return $icon['class'];
2619
 
                        }
2620
 
                        else
2621
 
                        {
2622
 
                                return '';
2623
 
                        }
2624
 
                        /* BREAK */
 
2651
                if( isset($icon['class']) )
 
2652
                {
 
2653
                        return $icon['class'];
 
2654
                }
 
2655
                else
 
2656
                {
 
2657
                        return '';
 
2658
                }
 
2659
                /* BREAK */
2625
2660
 
2626
2661
                case 'url':
2627
 
                        return $rsc_url.$icon['file'];
2628
 
                        /* BREAK */
 
2662
                return $rsc_url.$icon['file'];
 
2663
                /* BREAK */
2629
2664
 
2630
2665
                case 'size':
2631
 
                        if( !isset( $icon['size'] ) )
2632
 
                        {
2633
 
                                $Debuglog->add( 'No iconsize for ['.$iconKey.']', 'icons' );
2634
 
 
2635
 
                                $icon['size'] = imgsize( $rsc_path.$icon['file'] );
2636
 
                        }
 
2666
                if( ! isset( $icon['size'] ) )
 
2667
                {
 
2668
                        $icon['size'] = imgsize( $rsc_path.$icon['file'] );
 
2669
                }
2637
2670
 
2638
2671
                        switch( $params['size'] )
2639
2672
                        {
2640
2673
                                case 'width':
2641
 
                                        return $icon['size'][0];
 
2674
                                return $icon['size'][0];
2642
2675
 
2643
2676
                                case 'height':
2644
 
                                        return $icon['size'][1];
 
2677
                                return $icon['size'][1];
2645
2678
 
2646
2679
                                case 'widthxheight':
2647
 
                                        return $icon['size'][0].'x'.$icon['size'][1];
 
2680
                                return $icon['size'][0].'x'.$icon['size'][1];
2648
2681
 
2649
2682
                                case 'width':
2650
 
                                        return $icon['size'][0];
 
2683
                                return $icon['size'][0];
2651
2684
 
2652
2685
                                case 'string':
2653
 
                                        return 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'"';
 
2686
                                return 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'"';
2654
2687
 
2655
2688
                                default:
2656
 
                                        return $icon['size'];
 
2689
                                return $icon['size'];
2657
2690
                        }
2658
2691
                        /* BREAK */
2659
2692
 
2660
2693
 
2661
2694
                case 'imgtag':
2662
 
                        $r = '<img src="'.$rsc_url.$icon['file'].'" ';
2663
 
 
2664
 
                        // Include class (will default to "icon"):
2665
 
                        if( ! isset( $params['class'] ) )
2666
 
                        {
2667
 
                                if( isset($icon['class']) )
2668
 
                                {       // This icon has a class
2669
 
                                        $params['class'] = $icon['class'];
2670
 
                                }
2671
 
                                else
2672
 
                                {
2673
 
                                        $params['class'] = 'middle';
2674
 
                                }
2675
 
                        }
2676
 
 
2677
 
                        // Include size (optional):
2678
 
                        if( isset( $icon['size'] ) )
2679
 
                        {
2680
 
                                $r .= 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'" ';
2681
 
                        }
2682
 
 
2683
 
                        // Include alt (XHTML mandatory):
2684
 
                        if( ! isset( $params['alt'] ) )
2685
 
                        {
2686
 
                                if( isset( $icon['alt'] ) )
2687
 
                                { // alt-tag from $map_iconfiles
2688
 
                                        $params['alt'] = $icon['alt'];
2689
 
                                }
2690
 
                                else
2691
 
                                { // $iconKey as alt-tag
2692
 
                                        $params['alt'] = $iconKey;
2693
 
                                }
2694
 
                        }
2695
 
 
2696
 
                        // Add all the attributes:
2697
 
                        $r .= get_field_attribs_as_string( $params, false );
2698
 
 
2699
 
                        // Close tag:
2700
 
                        $r .= ' />';
2701
 
 
2702
 
 
2703
 
                        if( $include_in_legend && ( $IconLegend = & get_IconLegend() ) )
2704
 
                        { // This icon should be included into the legend:
2705
 
                                $IconLegend->add_icon( $iconKey );
2706
 
                        }
2707
 
 
2708
 
                        return $r;
2709
 
                        /* BREAK */
 
2695
                $r = '<img src="'.$rsc_url.$icon['file'].'" ';
 
2696
 
 
2697
                // Include class (will default to "icon"):
 
2698
                if( ! isset( $params['class'] ) )
 
2699
                {
 
2700
                        if( isset( $icon['class'] ) )
 
2701
                        {
 
2702
                                // This icon has a class
 
2703
                                $params['class'] = $icon['class'];
 
2704
                        }
 
2705
                        else
 
2706
                        {
 
2707
                                $params['class'] = 'middle';
 
2708
                        }
 
2709
                }
 
2710
 
 
2711
                // Include size (optional)
 
2712
                if( isset( $icon['size'] ) )
 
2713
                {
 
2714
                        $r .= 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'" ';
 
2715
                }
 
2716
 
 
2717
                // Include alt (XHTML mandatory)
 
2718
                if( ! isset( $params['alt'] ) )
 
2719
                {
 
2720
                        if( isset( $icon['alt'] ) )
 
2721
                        {
 
2722
                                // alt-tag from $map_iconfiles
 
2723
                                $params['alt'] = $icon['alt'];
 
2724
                        }
 
2725
                        else
 
2726
                        {
 
2727
                                // $iconKey as alt-tag
 
2728
                                $params['alt'] = $iconKey;
 
2729
                        }
 
2730
                }
 
2731
 
 
2732
                // Add all the attributes
 
2733
                $r .= get_field_attribs_as_string( $params, false );
 
2734
                // Close tag
 
2735
                $r .= ' />';
 
2736
 
 
2737
 
 
2738
                if( $include_in_legend && ( $IconLegend = & get_IconLegend() ) )
 
2739
                {
 
2740
                        // This icon should be included into the legend
 
2741
                        $IconLegend->add_icon( $iconKey );
 
2742
                }
 
2743
 
 
2744
                return $r;
 
2745
                /* BREAK */
2710
2746
 
2711
2747
                case 'noimg':
2712
 
                        $blank_icon = get_icon_info('pixel');
2713
 
 
2714
 
                        $r = '<img src="'.$rsc_url.$blank_icon['file'].'" ';
2715
 
 
2716
 
                        // Include class (will default to "no_icon"):
2717
 
                        if( ! isset( $params['class'] ) )
2718
 
                        {
2719
 
                                if( isset($icon['class']) )
2720
 
                                {       // This icon has a class
2721
 
                                        $params['class'] = $icon['class'];
2722
 
                                }
2723
 
                                else
2724
 
                                {
2725
 
                                        $params['class'] = 'no_icon';
2726
 
                                }
2727
 
                        }
2728
 
 
2729
 
                        // Include size (optional):
2730
 
                        if( isset( $icon['size'] ) )
2731
 
                        {
2732
 
                                $r .= 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'" ';
2733
 
                        }
2734
 
 
2735
 
                        // Include alt (XHTML mandatory):
2736
 
                        if( ! isset( $params['alt'] ) )
2737
 
                        {
2738
 
                                $params['alt'] = '';
2739
 
                        }
2740
 
 
2741
 
                        // Add all the attributes:
2742
 
                        $r .= get_field_attribs_as_string( $params, false );
2743
 
 
2744
 
                        // Close tag:
2745
 
                        $r .= ' />';
2746
 
 
2747
 
                        return $r;
2748
 
                        /* BREAK */
 
2748
                $blank_icon = get_icon_info('pixel');
 
2749
 
 
2750
                $r = '<img src="'.$rsc_url.$blank_icon['file'].'" ';
 
2751
 
 
2752
                // Include class (will default to "no_icon")
 
2753
                if( ! isset( $params['class'] ) )
 
2754
                {
 
2755
                        if( isset( $icon['class'] ) )
 
2756
                        {
 
2757
                                // This icon has a class
 
2758
                                $params['class'] = $icon['class'];
 
2759
                        }
 
2760
                        else
 
2761
                        {
 
2762
                                $params['class'] = 'no_icon';
 
2763
                        }
 
2764
                }
 
2765
 
 
2766
                // Include size (optional)
 
2767
                if( isset( $icon['size'] ) )
 
2768
                {
 
2769
                        $r .= 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'" ';
 
2770
                }
 
2771
 
 
2772
                // Include alt (XHTML mandatory)
 
2773
                if( ! isset( $params['alt'] ) )
 
2774
                {
 
2775
                        $params['alt'] = '';
 
2776
                }
 
2777
 
 
2778
                // Add all the attributes
 
2779
                $r .= get_field_attribs_as_string( $params, false );
 
2780
                // Close tag
 
2781
                $r .= ' />';
 
2782
 
 
2783
                return $r;
 
2784
                /* BREAK */
2749
2785
 
2750
2786
        }
2751
2787
}
2757
2793
 */
2758
2794
function form_date( $date, $time = '' )
2759
2795
{
2760
 
        return substr( $date.'          ', 0, 10 ).' '.$time;
 
2796
        return substr( $date.' ', 0, 10 ).' '.$time;
2761
2797
}
2762
2798
 
2763
2799
 
2772
2808
{
2773
2809
        $r = array();
2774
2810
 
2775
 
        if( !empty( $_SERVER['REMOTE_ADDR'] ) )
 
2811
        if( ! empty( $_SERVER['REMOTE_ADDR'] ) )
2776
2812
        {
2777
2813
                foreach( explode( ',', $_SERVER['REMOTE_ADDR'] ) as $l_ip )
2778
2814
                {
2779
2815
                        $l_ip = trim($l_ip);
2780
 
                        if( !empty($l_ip) )
 
2816
                        if( ! empty($l_ip) )
2781
2817
                        {
2782
2818
                                $r[] = $l_ip;
2783
2819
                        }
2784
2820
                }
2785
2821
        }
2786
2822
 
2787
 
        if( !empty($_SERVER['HTTP_X_FORWARDED_FOR']) )
2788
 
        { // IP(s) behind Proxy - this can be easily forged!
 
2823
        if( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) )
 
2824
        {
 
2825
                // IP(s) behind Proxy - this can be easily forged!
2789
2826
                foreach( explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) as $l_ip )
2790
2827
                {
2791
 
                        $l_ip = trim($l_ip);
2792
 
                        if( !empty($l_ip) && $l_ip != 'unknown' )
 
2828
                        $l_ip = trim( $l_ip );
 
2829
                        if( ! empty( $l_ip ) && $l_ip != 'unknown' )
2793
2830
                        {
2794
2831
                                $r[] = $l_ip;
2795
2832
                        }
2796
2833
                }
2797
2834
        }
2798
2835
 
2799
 
        if( !isset( $r[0] ) )
2800
 
        { // No IP found.
 
2836
        if( ! isset( $r[0] ) )
 
2837
        {
 
2838
                // No IP found
2801
2839
                $r[] = '';
2802
2840
        }
2803
2841
 
2806
2844
 
2807
2845
 
2808
2846
/**
2809
 
 * Get the base domain (without protocol and any subdomain) of an URL.
 
2847
 * Get the base domain (without protocol and any subdomain) of an URL
2810
2848
 *
2811
2849
 * Gets a max of 3 domain parts (x.y.tld)
2812
 
 *
2813
2850
 * @param string URL
2814
2851
 * @return string the base domain (may become empty, if found invalid)
2815
2852
 */
2816
2853
function get_base_domain( $url )
2817
2854
{
2818
 
        global $evo_charset;
 
2855
        global $app_charset;
2819
2856
 
2820
2857
        // Chop away the http part and the path:
2821
2858
        $domain = preg_replace( '~^([a-z]+://)?([^:/#]+)(.*)$~i', '\\2', $url );
2822
2859
 
2823
2860
        if( empty($domain) || preg_match( '~^(\d+\.)+\d+$~', $domain ) )
2824
 
        {       // Empty or All numeric = IP address, don't try to cut it any further
 
2861
        {
 
2862
                // Empty or All numeric = IP address, don't try to cut it any further
2825
2863
                return $domain;
2826
2864
        }
2827
2865
 
2837
2875
        {
2838
2876
                return '';
2839
2877
        }
2840
 
        $base_domain = convert_charset(idna_decode($match[0]), $evo_charset, 'UTF-8');
 
2878
        $base_domain = convert_charset(idna_decode($match[0]), $app_charset, 'UTF-8');
2841
2879
 
2842
2880
        // Remove any www*. prefix:
2843
2881
        $base_domain = preg_replace( '~^www.*?\.~i', '', $base_domain );
2847
2885
 
2848
2886
 
2849
2887
/**
2850
 
 * Generate a valid key of size $length.
2851
 
 *
 
2888
 * Generate a valid key of size $length
2852
2889
 * @param integer length of key
2853
2890
 * @param string chars to use in generated key
2854
2891
 * @return string key
2869
2906
 
2870
2907
/**
2871
2908
 * Generate a random password with no ambiguous chars
2872
 
 *
2873
2909
 * @param integer length of password
2874
2910
 * @return string password
2875
2911
 */
2892
2928
                case 'new':
2893
2929
                case 'new_switchtab':
2894
2930
                case 'copy':
2895
 
                case 'create':  // we return in this state after a validation error
2896
 
                        return true;
 
2931
                case 'create':
 
2932
                // we return in this state after a validation error
 
2933
                return true;
2897
2934
 
2898
2935
                case 'edit':
2899
2936
                case 'edit_switchtab':
2900
 
                case 'update':  // we return in this state after a validation error
 
2937
                case 'update':
 
2938
                // we return in this state after a validation error
2901
2939
                case 'delete':
2902
2940
                // The following one's a bit far fetched, but can happen if we have no sheet display:
2903
2941
                case 'unlink':
2904
2942
                case 'view':
2905
 
                        return false;
 
2943
                return false;
2906
2944
 
2907
2945
                default:
2908
 
                        debug_die( 'Unhandled action in form: '.strip_tags($action_parts[0]) );
 
2946
                debug_die( 'Unhandled action in form: '.strip_tags($action_parts[0]) );
2909
2947
        }
2910
2948
}
2911
2949
 
2912
2950
 
2913
2951
/**
2914
 
 * Generate a link that toggles display of an element on clicking.
 
2952
 * Generate a link that toggles display of an element on clicking
2915
2953
 *
2916
2954
 * @todo Provide functionality to make those links accessible without JS (using GET parameter)
 
2955
 *
2917
2956
 * @uses toggle_display_by_id() (JS)
2918
2957
 * @param string ID (html) of the link
2919
2958
 * @param string ID (html) of the target to toggle displaying
2931
2970
 
2932
2971
 
2933
2972
/**
2934
 
 * Escape a string to be used in Javascript.
2935
 
 *
 
2973
 * Escape a string to be used in Javascript
2936
2974
 * @param string
2937
2975
 * @return string
2938
2976
 */
2939
 
function jsspecialchars($s)
 
2977
function jsspecialchars( $s )
2940
2978
{
2941
2979
        $r = str_replace(
2942
2980
                array(  '\\', '"', "'" ),
2943
2981
                array( '\\\\', '\"', "\'" ),
2944
2982
                $s );
2945
 
        return htmlspecialchars($r, ENT_QUOTES);
 
2983
        return htmlspecialchars( $r, ENT_QUOTES );
2946
2984
}
2947
2985
 
2948
2986
 
2949
2987
/**
2950
2988
 * Compact a date in a number keeping only integer value of the string
2951
 
 *
2952
2989
 * @param string date
2953
2990
 */
2954
2991
function compact_date( $date )
2955
2992
{
2956
 
        return preg_replace( '#[^0-9]#', '', $date );
 
2993
        return preg_replace( '#[^0-9]#', '', $date );
2957
2994
}
2958
2995
 
2959
2996
 
2960
2997
/**
2961
2998
 * Decompact a date in a date format ( Y-m-d h:m:s )
2962
 
 *
2963
2999
 * @param string date
2964
3000
 */
2965
3001
function decompact_date( $date )
2966
3002
{
2967
3003
        $date0 = $date;
2968
 
 
2969
 
        return  substr($date0,0,4).'-'.substr($date0,4,2).'-'.substr($date0,6,2).' '
2970
 
                                                                .substr($date0,8,2).':'.substr($date0,10,2).':'.substr($date0,12,2);
 
3004
        return  substr($date0,0,4).'-'.substr($date0,4,2).'-'.substr($date0,6,2).' '.substr($date0,8,2).':'.substr($date0,10,2).':'.substr($date0,12,2);
2971
3005
}
2972
3006
 
2973
3007
/**
2974
 
 * Check the format of the phone number param and
2975
 
 * format it in a french number if it is.
2976
 
 *
 
3008
 * Check the format of the phone number param and format it in a french number if it is
2977
3009
 * @param string phone number
2978
3010
 */
2979
3011
function format_phone( $phone, $hide_country_dialing_code_if_same_as_locale = true )
2983
3015
        $dialing_code = NULL;
2984
3016
 
2985
3017
        if( substr( $phone, 0, 1 ) == '+' )
2986
 
        {       // We have a dialing code in the phone, so we extract it:
 
3018
        {
 
3019
                // We have a dialing code in the phone, so we extract it
2987
3020
                $dialing_code = $CountryCache->extract_country_dialing_code( substr( $phone, 1 ) );
2988
3021
        }
2989
3022
 
2990
3023
        if( !is_null( $dialing_code ) && ( locale_dialing_code() == $dialing_code )
2991
3024
                        && $hide_country_dialing_code_if_same_as_locale )
2992
 
        {       // The phone dialing code is same as locale and we want to hide it in this case
 
3025
        {
 
3026
                // The phone dialing code is same as locale and we want to hide it in this case
2993
3027
                if( ( strlen( $phone ) - strlen( $dialing_code ) ) == 10 )
2994
 
                {       // We can format it like a french phone number ( 0x.xx.xx.xx.xx )
 
3028
                {
 
3029
                        // We can format it like a french phone number ( 0x.xx.xx.xx.xx )
2995
3030
                        $phone_formated = format_french_phone( '0'.substr( $phone, strlen( $dialing_code )+1 ) );
2996
3031
                }
2997
3032
                else
2998
 
                { // ( 0xxxxxxxxxxxxxx )
 
3033
                {
 
3034
                        // ( 0xxxxxxxxxxxxxx )
2999
3035
                        $phone_formated = '0'.substr( $phone, strlen( $dialing_code )+1 );
3000
3036
                }
3001
3037
 
3002
3038
        }
3003
3039
        elseif( !is_null( $dialing_code ) )
3004
 
        {       // Phone has a dialing code
 
3040
        {
 
3041
                // Phone has a dialing code
3005
3042
                if( ( strlen( $phone ) - strlen( $dialing_code ) ) == 10 )
3006
 
                { // We can format it like a french phone number with the dialing code ( +dialing x.xx.xx.xx.xx )
 
3043
                {
 
3044
                        // We can format it like a french phone number with the dialing code ( +dialing x.xx.xx.xx.xx )
3007
3045
                        $phone_formated = '+'.$dialing_code.format_french_phone( ' '.substr( $phone, strlen( $dialing_code )+1 ) );
3008
3046
                }
3009
3047
                else
3010
 
                { // ( +dialing  xxxxxxxxxxx )
 
3048
                {
 
3049
                        // ( +dialing  xxxxxxxxxxx )
3011
3050
                        $phone_formated = '+'.$dialing_code.' '.substr( $phone, strlen( $dialing_code )+1 );
3012
3051
                }
3013
3052
        }
3014
3053
        else
3015
3054
        {
3016
3055
                if( strlen( $phone ) == 10 )
3017
 
                { //  We can format it like a french phone number ( xx.xx.xx.xx.xx )
 
3056
                {
 
3057
                        //  We can format it like a french phone number ( xx.xx.xx.xx.xx )
3018
3058
                        $phone_formated = format_french_phone( $phone );
3019
3059
                }
3020
3060
                else
3021
 
                {       // We don't format phone: TODO generic format phone ( xxxxxxxxxxxxxxxx )
 
3061
                {
 
3062
                        // We don't format phone: TODO generic format phone ( xxxxxxxxxxxxxxxx )
3022
3063
                        $phone_formated = $phone;
3023
3064
                }
3024
3065
        }
3029
3070
 
3030
3071
/**
3031
3072
 * Format a string in a french phone number
3032
 
 *
3033
3073
 * @param string phone number
3034
3074
 */
3035
3075
function format_french_phone( $phone )
3036
3076
{
3037
 
        return substr($phone, 0 , 2).'.'.substr($phone, 2, 2).'.'.substr($phone, 4, 2)
3038
 
                                        .'.'.substr($phone, 6, 2).'.'.substr($phone, 8, 2);
 
3077
        return substr( $phone, 0, 2 ).'.'.substr( $phone, 2, 2 ).'.'.substr( $phone, 4, 2 ).'.'.substr( $phone, 6, 2 ).'.'.substr( $phone, 8, 2 );
3039
3078
}
3040
3079
 
3041
3080
 
3071
3110
 
3072
3111
 
3073
3112
/**
3074
 
 * Build a string out of $field_attribs, with each attribute
3075
 
 * prefixed by a space character.
3076
 
 *
 
3113
 * Build a string out of $field_attribs, with each attribute prefixed by a space character.
3077
3114
 * @param array Array of field attributes.
3078
3115
 * @param boolean Use format_to_output() for the attributes?
3079
3116
 * @return string
3085
3122
        foreach( $field_attribs as $l_attr => $l_value )
3086
3123
        {
3087
3124
                if( $l_value === '' || $l_value === NULL )
3088
 
                { // don't generate empty attributes (it may be NULL if we pass 'value' => NULL as field_param for example, because isset() does not match it!)
 
3125
                {
 
3126
                        // don't generate empty attributes (it may be NULL if we pass 'value' => NULL as field_param for example, because isset() does not match it!)
3089
3127
                        continue;
3090
3128
                }
3091
3129
 
3097
3135
                        }
3098
3136
                        else
3099
3137
                        {
3100
 
                                // TODO: this uses strip_tags et al! Shouldn't we just use "formvalue" always? (E.g. it kills "for( var i=0; i<a; i++ )..." (in an onclick attr) from "<a" on. The workaround is to use spaces ("i < a"), but I was confused first)
 
3138
                                // @todo (0000): this uses strip_tags et al! Shouldn't we just use "formvalue" always?
 
3139
                                // (E.g. it kills "for( var i=0; i<a; i++ )..." (in an onclick attr) from "<a" on.
 
3140
                                // The workaround is to use spaces ("i < a"), but I was confused first)
3101
3141
                                $r .= ' '.$l_attr.'="'.format_to_output( $l_value, 'htmlattr' ).'"';
3102
3142
                        }
3103
3143
                }
3120
3160
{
3121
3161
        global $is_admin_page;
3122
3162
 
3123
 
        return isset($is_admin_page) && $is_admin_page === true; // check for type also, because of register_globals!
 
3163
        return isset( $is_admin_page ) && $is_admin_page === true; // check for type also, because of register_globals!
3124
3164
}
3125
3165
 
3126
3166
 
3127
3167
/**
3128
 
 * Implode array( 'x', 'y', 'z' ) to something like 'x, y and z'. Useful for displaying list to the end user.
 
3168
 * Implode array( 'x', 'y', 'z' ) to something like 'x, y and z'.
3129
3169
 *
 
3170
 * Useful for displaying list to the end user.
3130
3171
 * If there's one element in the table, it is returned.
3131
 
 * If there are at least two elements, the last one is concatenated using $implode_last, while the ones before are imploded using $implode_by.
 
3172
 * If there are at least two elements, the last one is concatenated using
 
3173
 * $implode_last, while the ones before are imploded using $implode_by.
3132
3174
 *
3133
 
 * @todo dh> I don't think using entities/HTML as default for $implode_last is sane!
3134
 
 *           Use "&" instead and make sure that the output for HTML is HTML compliant..
3135
 
 * @todo Support for locales that have a different kind of enumeration?!
 
3175
 * @todo (0000): I don't think using entities/HTML as default for $implode_last is sane!
 
3176
 * Use "&" instead and make sure that the output for HTML is HTML compliant..
 
3177
 * @todo (0000): Support for locales that have a different kind of enumeration?!
3136
3178
 * @return string
3137
3179
 */
3138
3180
function implode_with_and( $arr, $implode_by = ', ', $implode_last = ' &amp; ' )
3139
3181
{
3140
 
        switch( count($arr) )
 
3182
        switch( count( $arr ) )
3141
3183
        {
3142
3184
                case 0:
3143
3185
                        return '';
3144
3186
 
3145
3187
                case 1:
3146
 
                        $r = array_shift($arr);
 
3188
                        $r = array_shift( $arr );
3147
3189
                        return $r;
3148
3190
 
3149
3191
                default:
3156
3198
 
3157
3199
/**
3158
3200
 * Send a result as javascript
3159
 
 * automatically includes any Messages ( @see Log::display() )
 
3201
 *
 
3202
 * automatically includes any Messages (see {@link Log::display()})
3160
3203
 * no return from function as it terminates processing
3161
3204
 *
3162
 
 * @author Yabba
3163
 
 *
3164
 
 * @todo dh> Move this out into some more specific (not always included) file.
3165
 
 *
 
3205
 * @author {@link http://astonishme.co.uk/ Yabba (Paul Jones, rest in peace)}
3166
3206
 * @param array $methods javascript funtions to call with array of parameters
3167
 
 *              format : 'function_name' => array( param1, parm2, param3 )
 
3207
 * format : 'function_name' => array( param1, parm2, param3 )
3168
3208
 * @param boolean $send_as_html Wrap the script into an html page with script tag; default is to send as js file
3169
3209
 * @param string $target prepended to function calls : blank or window.parent
3170
3210
 */
3179
3219
        // set target
3180
3220
        $target = ( $target ? $target : param( 'js_target', 'string' ) );
3181
3221
        if( $target )
3182
 
        {       // add trailing [dot]
 
3222
        {
 
3223
                // add trailing [dot]
3183
3224
                $target = trim( $target, '.' ).'.';
3184
3225
        }
3185
3226
 
3190
3231
        }
3191
3232
 
3192
3233
        if( $output )
3193
 
        {       // we have some messages
 
3234
        {
 
3235
                // we have some messages
3194
3236
                $output = $target.'DisplayServerMessages( \''.format_to_js( $output ).'\');'."\n";
3195
3237
        }
3196
3238
 
3197
 
        if( !empty( $methods ) )
3198
 
        {       // we have a methods to call
 
3239
        if( ! empty( $methods ) )
 
3240
        {
 
3241
                // we have a methods to call
3199
3242
                foreach( $methods as $method => $param_list )
3200
 
                {       // loop through each requested method
 
3243
                {
 
3244
                        // loop through each requested method
3201
3245
                        $params = array();
3202
3246
                        if( !is_array( $param_list ) )
3203
 
                        {       // lets make it an array
 
3247
                        {
 
3248
                                // lets make it an array
3204
3249
                                $param_list = array( $param_list );
3205
3250
                        }
3206
3251
                        foreach( $param_list as $param )
3207
 
                        {       // add each parameter to the output
 
3252
                        {
 
3253
                                // add each parameter to the output
3208
3254
                                if( !is_numeric( $param ) )
3209
 
                                {       // this is a string, quote it
 
3255
                                {
 
3256
                                        // this is a string, quote it
3210
3257
                                        $param = '\''.format_to_js( $param ).'\'';
3211
3258
                                }
3212
3259
                                $params[] = $param;// add param to the list
3217
3264
        }
3218
3265
 
3219
3266
        if( $send_as_html )
3220
 
        {       // we want to send as a html document
 
3267
        {
 
3268
                // we want to send as a html document
3221
3269
                header_content_type();
3222
3270
                echo '<html><head></head><body><script type="text/javascript">'."\n";
3223
3271
                echo $output;
3224
3272
                echo '</script></body></html>';
3225
3273
        }
3226
3274
        else
3227
 
        {       // we want to send as js
 
3275
        {
 
3276
                // we want to send as js
3228
3277
                header_content_type( 'text/javascript' );
3229
3278
                header( 'Cache-Control: no-cache, must-revalidate' );
3230
3279
                header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' );
3237
3286
 
3238
3287
/**
3239
3288
 * Basic tidy up of strings
3240
 
 *
3241
 
 * @author Yabba
 
3289
 * @author {@link http://astonishme.co.uk/ Yabba (Paul Jones, rest in peace)}
3242
3290
 * @author Tblue
3243
 
 *
3244
3291
 * @param string $unformatted raw data
3245
3292
 * @return string formatted data
3246
3293
 */
3271
3318
function get_available_sort_options()
3272
3319
{
3273
3320
        return array(
3274
 
                'datestart'    => T_('Date issued (Default)'),
3275
 
                'order'        => T_('Order (as explicitely specified)'),
 
3321
                'datestart' => T_('Date issued (Default)'),
 
3322
                'order' => T_('Order (as explicitely specified)'),
3276
3323
                //'datedeadline' => T_('Deadline'),
3277
 
                'title'        => T_('Title'),
3278
 
                'datecreated'  => T_('Date created'),
 
3324
                'title' => T_('Title'),
 
3325
                'datecreated' => T_('Date created'),
3279
3326
                'datemodified' => T_('Date last modified'),
3280
 
                'urltitle'     => T_('URL "filename"'),
3281
 
                'priority'     => T_('Priority'),
3282
 
                'views'        => T_('Views'),
3283
 
                'RAND'         => T_('Random order!'),
 
3327
                'urltitle' => T_('URL "filename"'),
 
3328
                'priority' => T_('Priority'),
 
3329
                'views' => T_('Views'),
 
3330
                'RAND' => T_('Random order!'),
3284
3331
        );
3285
3332
}
3286
3333
 
3287
3334
 
3288
3335
/**
3289
3336
 * Generate order by clause
3290
 
 *
3291
3337
 * @return string
3292
3338
 */
3293
3339
function gen_order_clause( $order_by, $order_dir, $dbprefix, $dbIDname_disambiguation )
3311
3357
 
3312
3358
 
3313
3359
/**
3314
 
 * Get the IconLegend instance.
3315
 
 *
 
3360
 * Get the IconLegend instance
3316
3361
 * @return IconLegend or false, if the user has not set "display_icon_legend"
3317
3362
 */
3318
3363
function & get_IconLegend()
3319
3364
{
3320
3365
        static $IconLegend;
3321
3366
 
3322
 
        if( ! isset($IconLegend) )
 
3367
        if( ! isset( $IconLegend ) )
3323
3368
        {
3324
3369
                global $UserSettings;
3325
 
                if( $UserSettings->get('display_icon_legend') )
 
3370
                if( $UserSettings->get( 'display_icon_legend' ) )
3326
3371
                {
3327
 
                        /**
3328
 
                         * Icon Legend
3329
 
                         */
3330
 
                        load_class( '_core/ui/_iconlegend.class.php' );
 
3372
                        // Icon Legend
3331
3373
                        $IconLegend = new IconLegend();
3332
3374
                }
3333
3375
                else
3340
3382
 
3341
3383
 
3342
3384
/**
3343
 
 * Check if two arrays contain the same elements.
3344
 
 *
3345
 
 * @param array    The first array.
3346
 
 * @param array    The second array.
3347
 
 * @return boolean True if both arrays contain the same elements, false
3348
 
 *                 otherwise.
 
3385
 * Check if two arrays contain the same elements
 
3386
 * @param array The first array.
 
3387
 * @param array The second array.
 
3388
 * @return boolean True if both arrays contain the same elements, false otherwise.
3349
3389
 */
3350
3390
function array_equal( $one, $two )
3351
3391
{
3354
3394
        /* We consider the arrays to be equal if they have the same number of
3355
3395
         * elements and all elements of $one are present in $two.
3356
3396
         */
3357
 
        return $one_count == count( $two ) &&
3358
 
                                count( array_intersect( $one, $two ) ) == $one_count;
 
3397
        return $one_count == count( $two ) && count( array_intersect( $one, $two ) ) == $one_count;
3359
3398
}
3360
3399
 
3361
3400
 
3362
3401
/**
3363
 
 * Get the Bazaar revision of this QP installation.
 
3402
 * Get the Bazaar revision of this QP installation
3364
3403
 * 
3365
3404
 * Useful for snapshot users etc. -- they can include it in bug reports.
3366
3405
 * This function tries to find out the current revision from the .bzr control
3390
3429
                fclose( $fh );
3391
3430
                
3392
3431
                if( $n == 1 && $revno >= 1 )
3393
 
                {       // We got a valid revision number!
 
3432
                {
 
3433
                        // We got a valid revision number!
3394
3434
                        return $revno;
3395
3435
                }
3396
3436
        }
3397
3437
        
3398
3438
        // Nothing found...
3399
3439
        return false;
3400
 
}
 
 
b'\\ No newline at end of file'
 
3440
}
 
3441
 
 
3442
?>