3
* This file implements general purpose functions.
5
* This file is part of Quam Plures - {@link http://quamplures.net/}
6
* See also {@link https://launchpad.net/quam-plures}.
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/}.
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
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/).
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/).
32
* @todo dh> Refactor into smaller chunks/files. We should avoid using a "huge" misc early!
34
* - _formatting.funcs.php
37
* NOTE: Encapsulation functions into classes would allow using autoloading (http://php.net/autoload) in PHP5..!
39
* {@internal Below is a list of authors who have contributed to design/coding of this file: }}
3
* This file implements general purpose functions
5
* @todo (0000): dh> Refactor into smaller chunks/files. We should avoid using a
8
* - _formatting.funcs.php
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
50
if( !defined('QP_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
56
load_funcs('antispam/model/_antispam.funcs.php');
57
load_funcs('files/model/_file.funcs.php');
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
24
if(!defined('QP_MAIN_INIT')) die('fail');
26
load_funcs( 'antispam/model/_antispam.funcs.php' );
27
load_funcs( 'files/model/_file.funcs.php' );
61
30
* Call a method for all modules in a row
85
53
global $$objectName;
87
55
if( isset( $$objectName ) )
88
{ // Cache already exists:
57
// Cache already exists
89
58
return $$objectName;
92
61
switch( $objectName )
95
load_class( 'collections/model/_blogcache.class.php' );
96
$BlogCache = new BlogCache(); // COPY (FUNC)
64
$BlogCache = new BlogCache(); // COPY (FUNC)
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)
105
load_class( 'files/model/_filecache.class.php' );
106
$FileCache = new FileCache(); // COPY (FUNC)
72
$FileCache = new FileCache(); // COPY (FUNC)
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;
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;
120
$GoalCache = new DataObjectCache( 'Goal', false, 'T_track__goal', 'goal_', 'goal_ID', 'goal_name', 'goal_name' ); // COPY (FUNC)
84
$GoalCache = new DataObjectCache( 'Goal', false, 'T_track__goal', 'goal_', 'goal_ID', 'goal_name', 'goal_name' ); // COPY (FUNC)
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\') )' );
88
$Plugins->get_object_from_cacheplugin_or_create( 'GroupCache', 'new DataObjectCache( \'Group\', true, \'T_groups\', \'grp_\', \'grp_ID\', \'grp_name\', \'\', T_(\'No group\') )' );
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;
132
load_class( 'items/model/_itemcache.class.php' );
133
$ItemCache = new ItemCache(); // COPY (FUNC)
96
$ItemCache = new ItemCache(); // COPY (FUNC)
136
99
case 'ItemPrerenderingCache':
137
$ItemPrerenderingCache = array();
138
return $ItemPrerenderingCache;
100
$ItemPrerenderingCache = array();
101
return $ItemPrerenderingCache;
140
103
case 'ItemTagsCache':
141
$ItemTagsCache = array();
142
return $ItemTagsCache;
104
$ItemTagsCache = array();
105
return $ItemTagsCache;
144
107
case 'ItemCatsCache':
145
$ItemCatsCache = array();
146
return $ItemCatsCache;
108
$ItemCatsCache = array();
109
return $ItemCatsCache;
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;
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;
157
119
case 'LinkCache':
158
load_class( 'items/model/_linkcache.class.php' );
159
$LinkCache = new LinkCache(); // COPY (FUNC)
120
$LinkCache = new LinkCache(); // COPY (FUNC)
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;
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;
172
131
case 'UserCache':
173
load_class( 'users/model/_usercache.class.php' );
174
$UserCache = new UserCache(); // COPY (FUNC)
132
$UserCache = new UserCache(); // COPY (FUNC)
177
135
case 'WidgetCache':
178
load_class( 'widgets/model/_widgetcache.class.php' );
179
$WidgetCache = new WidgetCache(); // COPY (FUNC)
136
$WidgetCache = new WidgetCache(); // COPY (FUNC)
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;
193
debug_die( 'getCache(): Unknown Cache type:'.$objectName );
149
debug_die( 'getCache(): Unknown Cache type:'.$objectName );
275
225
switch( $format )
231
// display in HTML page body: allow full HTML
282
// display in HTML page body: allow full HTML
283
$content = convert_chars($content, 'html');
233
$content = convert_chars( $content, 'html' );
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 );
238
$content = rawurlencode( $content );
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 );
243
$content = convert_chars( $content, 'html' );
244
$content = htmlspecialchars( $content );
247
// strips out HTML (mainly for use in Title)
298
// strips out HTML (mainly for use in Title)
299
$content = strip_tags($content);
300
$content = convert_chars($content, 'html');
249
$content = strip_tags( $content );
250
$content = convert_chars( $content, 'html' );
253
// use as an attribute: strips tags and escapes quotes
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('"', '"', $content );
308
$content = str_replace("'", ''', $content );
255
$content = strip_tags( $content );
256
$content = convert_chars( $content, 'html' );
257
$content = str_replace('"', '"', $content );
258
$content = str_replace("'", ''', $content );
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 >
263
$content = htmlspecialchars( $content, ENT_QUOTES ); // Handles &, ", ', < and >
266
// use in an XML file: strip HTML tags
317
// use in an XML file: strip HTML tags
318
$content = strip_tags($content);
319
$content = convert_chars($content, 'xml');
268
$content = strip_tags( $content );
269
$content = convert_chars( $content, 'xml' );
272
// use as an attribute: strips tags and escapes quotes
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('"', '"', $content );
327
$content = str_replace("'", ''', $content );
274
$content = strip_tags( $content );
275
$content = convert_chars( $content, 'xml' );
276
$content = str_replace('"', '"', $content );
277
$content = str_replace("'", ''', $content );
280
// use as plain-text, e.g. for ascii-mails
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);
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 );
341
debug_die( 'Output format ['.$format.'] not supported.' );
291
debug_die( 'Output format ['.$format.'] not supported.' );
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++ )
442
387
switch( $char = $str[$i] )
444
case '<' : // start of a tag
447
case '>' : // end of a tag
451
case ctype_space($char):
454
// Eat any other whitespace.
455
while( isset($str[$i+1]) && ctype_space($str[$i+1]) )
459
if( isset($str[$i+1]) && $have_seen_non_whitespace )
460
{ // only decrement words, if there's a non-space char left.
399
case ctype_space( $char ):
403
// Eat any other whitespace.
404
while( isset( $str[$i+1] ) && ctype_space( $str[$i+1] ) )
408
if( isset( $str[$i+1] ) && $have_seen_non_whitespace )
410
// only decrement words, if there's a non-space char left
467
$have_seen_non_whitespace = true;
417
$have_seen_non_whitespace = true;
470
420
if( $maxwords < 1 ) break;
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 ) );
476
426
if( $params['always_continue'] || $maxwords == false )
477
{ // we want a continued text
428
// we want a continued text
478
429
if( $params['continued_link'] )
480
432
$str .= ' <a href="'.$params['continued_link'].'">'.$params['continued_text'].'</a>';
483
{ // we don't have a url
436
// we don't have a url
484
437
$str .= ' '.$params['continued_text'];
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' ) ) )
500
// This is a single byte charset
548
501
// fp> why do we actually bother doing this:?
549
502
$content = preg_replace_callback(
551
create_function( '$j', 'return "&#".ord($j[0]).";";' ),
504
create_function( '$j', 'return "&#".ord( $j[0] ).";";' ),
555
508
// Convert Windows CP1252 => Unicode (valid HTML)
556
// TODO: should this go to input conversions instead (?)
557
509
$content = strtr( $content, $b2_htmltranswinuni );
559
511
if( $flag == 'html' )
560
{ // we can use entities
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};)/', '&', $content);
566
520
// Convert & chars that are not used in an entity
567
521
$content = preg_replace('/&(?![#A-Za-z0-9]{2,20};)/', '&', $content);
569
523
// Convert HTML entities to urefs:
570
$content = strtr($content, $b2_htmltrans);
524
$content = strtr( $content, $b2_htmltrans );
573
527
return( $content );
623
575
* Split $text into blocks by using $pattern and call $callback on the non-matching blocks.
625
* The non-matching block's text is the first param to $callback and additionally $params gets passed.
627
* This gets used to make links clickable or replace smilies.
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>
632
* {@internal This function gets tested in misc.funcs.simpletest.php.}}
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.
642
589
function callback_on_non_matching_blocks( $text, $pattern, $callback, $params = array() )
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
593
// $pattern matches, call the callback method on each non-matching block
649
597
foreach( $matches[0] as $l_matching )
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 ) );
655
603
$callback_params = $params;
697
643
$in_tag_quote = false;
646
$n = strlen( $text );
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)
706
{ // Go through each char in string... (we will fast forward from tag to tag)
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:
656
// State: We're currently inside some tag:
709
657
switch( $text[$i] )
713
{ // This is in a quoted string so it doesn't really matter...
718
$r .= substr($text, $from_pos, $i-$from_pos+1);
662
// This is in a quoted string so it doesn't really matter...
667
$r .= substr( $text, $from_pos, $i-$from_pos+1 );
672
// This is the beginning or the end of a quoted string
725
// This is the beginning or the end of a quoted string:
726
if( ! $in_tag_quote )
728
$in_tag_quote = $text[$i];
730
elseif( $in_tag_quote == $text[$i] )
732
$in_tag_quote = false;
675
if( ! $in_tag_quote )
677
$in_tag_quote = $text[$i];
679
elseif( $in_tag_quote == $text[$i] )
681
$in_tag_quote = false;
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
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] )
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);
747
$r .= substr($text, $from_pos, $i-$from_pos);
750
$in_tag_quote = false;
692
if( strtolower( substr( $text, $i+1, 3 ) ) == '/a>' )
694
// Ok, this is the end tag of the link:
695
// $r .= substr( $text, $from_pos, $i-$from_pos+4 );
698
$r .= substr( $text, $from_pos, $i-$from_pos );
701
$in_tag_quote = false;
756
{ // State: we're not currently in any tag:
757
// Find next tag opening:
758
$i = strpos($text, '<', $i);
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:
712
// No more opening tags
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
1043
function mysql_date_diff( $from_date, $to_date = 0 )
1045
$from_date = mysql2timestamp( $from_date );
1048
$to_date = mysql2timestamp( $to_date );
1055
$delta_seconds = round( abs( $to_date - $from_date ) );
1056
$delta_minutes = round( $delta_seconds / 60 );
1058
if( $delta_minutes <= 1 )
1060
return ($delta_minutes == 0) ? T_('less than a minute') : T_('1 minute');
1063
if( $delta_minutes < 45 )
1065
return $delta_minutes.' '.T_('minutes');
1067
if( $delta_minutes < 90 )
1069
return T_('~ 1 hour');
1071
if( $delta_minutes < 1440 )
1073
return sprintf( T_('~ %d hours'), round( floatval( $delta_minutes ) / 60.0 ) );
1075
if( $delta_minutes < 2880 )
1079
if( $delta_minutes < 43200 )
1081
return sprintf( T_('~ %d days'), round( floatval( $delta_minutes ) / 1440 ) );
1083
if( $delta_minutes < 86400 )
1085
return T_('~ 1 month');
1087
if( $delta_minutes < 525600 )
1089
return sprintf( T_('~ %d months'), round( floatval( $delta_minutes ) / 43200 ) );
1091
if( $delta_minutes < 1051199 )
1093
return T_('~ 1 year');
1095
return sprintf( T_('over %d years'), round( floatval( $delta_minutes ) / 525600 ) );
1084
1100
* Check that email address looks valid.
1086
1102
* @param string email address to check
1093
1109
* - Me <example@example.org>
1094
1110
* - "Me" <example@example.org>
1096
* @return bool True if the email address appears to be valid, false otherwise.
1098
1112
* @see Plugin::IsValidRawEmail()
1099
1113
* @see Plugin::IsValidFilteredEmail()
1114
* @return bool True if the email address appears to be valid, false otherwise.
1101
1116
function is_email( $email, $format = 'simple' )
1103
global $Plugins, $Debuglog;
1105
1120
if( $format == 'rfc2822' )
1106
{ // Backward compatibility
1122
// Backward compatibility
1107
1123
$format = 'rfc';
1111
1127
$plug_ret = $Plugins->trigger_event_first_return( 'IsValidRawEmail',
1114
1130
'format' => $format,
1116
1132
$plug_choice = empty( $plug_ret ) ? Plugin::EmailNotSure : $plug_ret['plugin_ret'];
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'],
1136
// The plugin thinks the email address is invalid. No further processing.
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'],
1141
// The plugin assures us that everything is perfectly fine.
1130
1144
else if( $plug_choice == Plugin::EmailNotSure )
1131
{ // No plugin could decide on the validity of the address.
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' );
1135
1148
switch( $format )
1139
* Regexp pattern converted from: http://www.regexlib.com/REDetails.aspx?regexp_id=711
1140
* Extended to allow escaped quotes.
1142
$pattern_email = '/^
1144
(?>[a-zA-Z\d!\#$%&\'*+\-\/=?^_`{|}~]+\x20*
1145
|"( \\\" | (?=[\x01-\x7f])[^"\\\] | \\[\x01-\x7f] )*"\x20*)* # Name
1149
(?!\.)(?>\.?[a-zA-Z\d!\#$%&\'*+\-\/=?^_`{|}~]+)+
1150
|"( \\\" | (?=[\x01-\x7f])[^"\\\] | \\[\x01-\x7f] )* " # quoted mailbox name
1154
((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}
1152
* Regexp pattern converted from: http://www.regexlib.com/REDetails.aspx?regexp_id=711
1153
* Extended to allow escaped quotes.
1155
$pattern_email = '/^
1157
(?>[a-zA-Z\d!\#$%&\'*+\-\/=?^_`{|}~]+\x20*
1158
|"( \\\" | (?=[\x01-\x7f])[^"\\\] | \\[\x01-\x7f] )*"\x20*)* # Name
1162
(?!\.)(?>\.?[a-zA-Z\d!\#$%&\'*+\-\/=?^_`{|}~]+)+
1163
|"( \\\" | (?=[\x01-\x7f])[^"\\\] | \\[\x01-\x7f] )* " # quoted mailbox name
1167
((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}
1170
( (?(?<!\[)\.)(25[0-5] | 2[0-4]\d | [01]?\d?\d) ){4}
1157
( (?(?<!\[)\.)(25[0-5] | 2[0-4]\d | [01]?\d?\d) ){4}
1159
[a-zA-Z\d\-]*[a-zA-Z\d]:( (?=[\x01-\x7f])[^\\\[\]] | \\[\x01-\x7f] )+
1162
(?(3)>) # match ">" if it was there
1172
[a-zA-Z\d\-]*[a-zA-Z\d]:( (?=[\x01-\x7f])[^\\\[\]] | \\[\x01-\x7f] )+
1175
(?(3)>) # match ">" if it was there
1168
$pattern_email = '~^(([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,}))$~i';
1181
$pattern_email = '~^(([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,}))$~i';
1185
?><?php // humors my editor into looking like PHP again ;)
1172
1187
// Short-circuit definitely invalid addresses:
1173
1188
if( strpos( $email, '@' ) === false || strpos( $email, '.' ) === false ||
1174
1189
! preg_match( $pattern_email, $email ) )
1176
$Debuglog->add( 'BUILTIN REJECT ['.$email.']', 'email' );
1181
{ // Plugin::EmailValidSyntax
1182
$Debuglog->add( 'SYNTAX ACCEPT ['.$email.'] by plugin #'.$plug_ret['plugin_ID'],
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',
1191
1200
'format' => $format,
1194
1203
if( ! empty( $plug_ret ) )
1196
$Debuglog->add( 'POST SYNTAX REJECT ['.$email.'] by plugin #'.$plug_ret['plugin_ID'],
1201
$Debuglog->add( 'ACCEPT ['.$email.']', 'email' );
1513
1524
$limited = false; // remember if we have limited to $limit_to_last
1515
1526
if( $ignore_from )
1516
{ // we want to ignore from a certain point
1528
// we want to ignore from a certain point
1517
1529
$trace_length = 0;
1518
1530
$break_because_of_offset = false;
1520
1532
for( $i = count($backtrace); $i > 0; $i-- )
1521
{ // Search the backtrace from behind (first call).
1534
// Search the backtrace from behind (first call)
1522
1535
$l_stack = & $backtrace[$i-1];
1524
1537
if( $break_because_of_offset && $offset_ignore_from < 1 )
1525
{ // we've respected the offset, but need to break now
1539
// we've respected the offset, but need to break now
1526
1540
break; // ignore from here
1529
1543
foreach( $ignore_from as $l_ignore_key => $l_ignore_value )
1530
{ // Check if we want to ignore from here
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
1548
// It's an array - all must match
1533
1549
foreach( $l_ignore_value as $l_ignore_mult_key => $l_ignore_mult_val )
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) */ )
1538
1554
continue 2; // next ignore setting, because not all match.
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...
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')
1700
1717
function debug_die( $additional_info = '', $params = array() )
1702
1719
global $debug, $app_baseurl;
1703
1720
global $log_app_errors, $app_name, $is_cli;
1705
$params = array_merge( array(
1706
'status' => '500 Internal Server Error',
1722
$params = array_merge( array( 'status' => '500 Internal Server Error', ), $params );
1710
{ // Command line interface, e.g. in cron_exec.php:
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";
1743
if( $log_app_errors > 1 || $debug )
1744
{ // Prepare backtrace
1759
$log_app_errors = 1;
1762
// Prepare backtrace
1745
1763
$backtrace = debug_get_backtrace();
1747
1765
if( $log_app_errors > 1 || $is_cli )
1749
$backtrace_cli = trim(strip_tags($backtrace));
1753
if( $log_app_errors )
1754
{ // Log error through PHP's logging facilities:
1755
$log_message = $app_name.' error: ';
1756
if( ! empty($additional_info) )
1758
$log_message .= trim( strip_tags($additional_info) );
1762
$log_message .= 'No info specified in debug_die()';
1765
// Get file and line info:
1768
if( function_exists('debug_backtrace') /* PHP 4.3 */ )
1769
{ // get the file and line
1770
foreach( debug_backtrace() as $v )
1772
if( isset($v['function']) && $v['function'] == 'debug_die' )
1774
$file = isset($v['file']) ? $v['file'] : 'Unknown';
1775
$line = isset($v['line']) ? $v['line'] : 'Unknown';
1780
$log_message .= ' in '.$file.' at line '.$line;
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;
1788
$log_message .= "\nREQUEST_URI: ".( isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '-' );
1789
$log_message .= "\nHTTP_REFERER: ".( isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '-' );
1791
error_log( str_replace("\n", ' / ', $log_message), 0 /* PHP's system logger */ );
1767
$backtrace_cli = trim( strip_tags( $backtrace ) );
1771
// Log error through PHP's logging facilities
1772
$log_message = $app_name.' error: ';
1773
if( ! empty($additional_info) )
1775
$log_message .= trim( strip_tags($additional_info) );
1779
$log_message .= 'No info specified in debug_die()';
1782
// Get file and line info
1785
// get the file and line
1786
foreach( debug_backtrace() as $v )
1788
if( isset( $v['function'] ) && $v['function'] == 'debug_die' )
1790
$file = isset( $v['file'] ) ? $v['file'] : 'Unknown';
1791
$line = isset( $v['line'] ) ? $v['line'] : 'Unknown';
1795
$log_message .= ' in '.$file.' at line '.$line;
1797
if( $log_app_errors > 1 )
1800
// indent after newlines
1801
$backtrace_cli = preg_replace( '~(\S)(\n)(\S)~', '$1 $2$3', $backtrace_cli );
1802
$log_message .= "\nBacktrace:\n".$backtrace_cli;
1805
$log_message .= "\nREQUEST_URI: ".( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '-' );
1806
$log_message .= "\nHTTP_REFERER: ".( isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '-' );
1808
error_log( str_replace("\n", ' / ', $log_message), 0 /* PHP's system logger */ );
1795
1810
// DEBUG OUTPUT:
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;
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;
1930
1944
$ReqHostPathQuery = $ReqHost.$ReqPath.( empty( $_SERVER['QUERY_STRING'] ) ? '' : '?'.$_SERVER['QUERY_STRING'] );
1933
1947
echo ( $clean ? '*** Debug info ***'."\n\n" : '<div class="debug" id="debug_info"><h2>Debug info</h2>' );
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' );
1938
if( !$obhandler_debug )
1939
{ // don't display changing items when we want to test obhandler
1949
if( ! $debug_obhandler )
1951
// don't display changing items when we want to test obhandler
1941
1953
// Timer table:
1942
1954
$time_page = $Timer->get_duration( 'total' );
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()})
2296
2313
function send_mail( $to, $to_name, $subject, $message, $from = NULL, $from_name = NULL, $headers = array() )
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;
2317
global $current_locale;
2318
global $current_charset;
2320
global $app_charset;
2322
global $notify_from;
2303
if( !is_array( $headers ) )
2304
{ // Make sure $headers is an array
2327
if( ! is_array( $headers ) )
2329
// Make sure $headers is an array
2305
2330
$headers = array( $headers );
2333
if( empty( $from ) )
2310
2335
$from = $notify_from;
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 ) )
2340
// fplanque: Windows XP, Apache 1.3, PHP 4.4, MS SMTP : will not accept "nice" addresses.
2341
if( ! empty( $to_name ) )
2317
2343
$to = '"'.mail_encode_header_string($to_name).'" <'.$to.'>';
2319
if( !empty( $from_name ) )
2345
if( ! empty( $from_name ) )
2321
2347
$from = '"'.mail_encode_header_string($from_name).'" <'.$from.'>';
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;
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() );
2347
2371
$headerstring = '';
2348
2372
reset( $headers );
2349
2373
while( list( $lKey, $lValue ) = each( $headers ) )
2350
{ // Add additional headers
2375
// Add additional headers
2351
2376
$headerstring .= $lKey.': '.$lValue.$NL;
2356
2380
if( ! $Plugins->trigger_event_first_true( 'ModifySendMessage', array( $to, $subject, $message, $headerstring, $debug ) ) )
2358
2382
// if no plugin takes over we do boring stuff
2359
2383
if( $debug > 1 )
2360
{ // We agree to die for debugging...
2385
// We agree to die for debugging...
2361
2386
if( ! mail( $to, $subject, $message, $headerstring ) )
2363
debug_die( 'Sending mail from «'.htmlspecialchars($from).'» to «'.htmlspecialchars($to).'», Subject «'.htmlspecialchars($subject).'» FAILED.' );
2388
debug_die( 'Sending mail from «'.htmlspecialchars( $from ).'» to «'.htmlspecialchars( $to ).'», Subject «'.htmlspecialchars( $subject ).'» FAILED.' );
2367
{ // Soft debugging only....
2393
// Soft debugging only....
2368
2394
if( ! @mail( $to, $subject, $message, $headerstring ) )
2370
$Debuglog->add( 'Sending mail from «'.htmlspecialchars($from).'» to «'.htmlspecialchars($to).'», Subject «'.htmlspecialchars($subject).'» FAILED.', 'error' );
2376
$Debuglog->add( 'Sent mail from «'.htmlspecialchars($from).'» to «'.htmlspecialchars($to).'», Subject «'.htmlspecialchars($subject).'».' );
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 ).'>';
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 );
2506
2532
if( $display_icon || ! $display_word )
2507
{ // We MUST display an action icon in order to make the user happy:
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!!
2510
$r .= get_icon( $icon, 'imgtag', array( 'title'=>$title ), true );
2537
$r .= get_icon( $icon, 'imgtag', array( 'title' => $title ), true );
2513
2540
if( $display_word )
2514
{ // We MUST display an action word in order to make the user happy:
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:
2519
{ // We have provided a short word:
2545
// We already have an icon, display a SHORT word
2546
if( ! empty( $word ) )
2548
// We have provided a short word
2523
{ // We fall back to alt:
2553
// We fall back to alt
2524
2554
$r .= get_icon( $icon, 'legend' );
2528
{ // No icon display, let's display a LONG word/text:
2559
// No icon display, let's display a LONG word/text
2529
2560
$r .= trim( $title, ' .!' );
2570
2602
switch( $what )
2572
2604
case 'rollover':
2573
if( isset( $icon['rollover'] ) )
2574
{ // Image has rollover available
2575
return $icon['rollover'];
2605
if( isset( $icon['rollover'] ) )
2607
// Image has rollover available
2608
return $icon['rollover'];
2582
return $rsc_path.$icon['file'];
2614
return $rsc_path.$icon['file'];
2587
if( isset( $icon['alt'] ) )
2588
{ // alt tag from $map_iconfiles
2589
return $icon['alt'];
2592
{ // fallback to $iconKey as alt-tag
2618
if( isset( $icon['alt'] ) )
2620
// alt tag from $map_iconfiles
2621
return $icon['alt'];
2625
// fallback to $iconKey as alt-tag
2599
if( isset( $icon['legend'] ) )
2600
{ // legend tag from $map_iconfiles
2601
return $icon['legend'];
2604
if( isset( $icon['alt'] ) )
2605
{ // alt tag from $map_iconfiles
2606
return $icon['alt'];
2609
{ // fallback to $iconKey as alt-tag
2631
if( isset( $icon['legend'] ) )
2633
// legend tag from $map_iconfiles
2634
return $icon['legend'];
2637
if( isset( $icon['alt'] ) )
2639
// alt tag from $map_iconfiles
2640
return $icon['alt'];
2644
// fallback to $iconKey as alt-tag
2616
if( isset($icon['class']) )
2618
return $icon['class'];
2651
if( isset($icon['class']) )
2653
return $icon['class'];
2627
return $rsc_url.$icon['file'];
2662
return $rsc_url.$icon['file'];
2631
if( !isset( $icon['size'] ) )
2633
$Debuglog->add( 'No iconsize for ['.$iconKey.']', 'icons' );
2635
$icon['size'] = imgsize( $rsc_path.$icon['file'] );
2666
if( ! isset( $icon['size'] ) )
2668
$icon['size'] = imgsize( $rsc_path.$icon['file'] );
2638
2671
switch( $params['size'] )
2641
return $icon['size'][0];
2674
return $icon['size'][0];
2644
return $icon['size'][1];
2677
return $icon['size'][1];
2646
2679
case 'widthxheight':
2647
return $icon['size'][0].'x'.$icon['size'][1];
2680
return $icon['size'][0].'x'.$icon['size'][1];
2650
return $icon['size'][0];
2683
return $icon['size'][0];
2653
return 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'"';
2686
return 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'"';
2656
return $icon['size'];
2689
return $icon['size'];
2662
$r = '<img src="'.$rsc_url.$icon['file'].'" ';
2664
// Include class (will default to "icon"):
2665
if( ! isset( $params['class'] ) )
2667
if( isset($icon['class']) )
2668
{ // This icon has a class
2669
$params['class'] = $icon['class'];
2673
$params['class'] = 'middle';
2677
// Include size (optional):
2678
if( isset( $icon['size'] ) )
2680
$r .= 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'" ';
2683
// Include alt (XHTML mandatory):
2684
if( ! isset( $params['alt'] ) )
2686
if( isset( $icon['alt'] ) )
2687
{ // alt-tag from $map_iconfiles
2688
$params['alt'] = $icon['alt'];
2691
{ // $iconKey as alt-tag
2692
$params['alt'] = $iconKey;
2696
// Add all the attributes:
2697
$r .= get_field_attribs_as_string( $params, false );
2703
if( $include_in_legend && ( $IconLegend = & get_IconLegend() ) )
2704
{ // This icon should be included into the legend:
2705
$IconLegend->add_icon( $iconKey );
2695
$r = '<img src="'.$rsc_url.$icon['file'].'" ';
2697
// Include class (will default to "icon"):
2698
if( ! isset( $params['class'] ) )
2700
if( isset( $icon['class'] ) )
2702
// This icon has a class
2703
$params['class'] = $icon['class'];
2707
$params['class'] = 'middle';
2711
// Include size (optional)
2712
if( isset( $icon['size'] ) )
2714
$r .= 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'" ';
2717
// Include alt (XHTML mandatory)
2718
if( ! isset( $params['alt'] ) )
2720
if( isset( $icon['alt'] ) )
2722
// alt-tag from $map_iconfiles
2723
$params['alt'] = $icon['alt'];
2727
// $iconKey as alt-tag
2728
$params['alt'] = $iconKey;
2732
// Add all the attributes
2733
$r .= get_field_attribs_as_string( $params, false );
2738
if( $include_in_legend && ( $IconLegend = & get_IconLegend() ) )
2740
// This icon should be included into the legend
2741
$IconLegend->add_icon( $iconKey );
2712
$blank_icon = get_icon_info('pixel');
2714
$r = '<img src="'.$rsc_url.$blank_icon['file'].'" ';
2716
// Include class (will default to "no_icon"):
2717
if( ! isset( $params['class'] ) )
2719
if( isset($icon['class']) )
2720
{ // This icon has a class
2721
$params['class'] = $icon['class'];
2725
$params['class'] = 'no_icon';
2729
// Include size (optional):
2730
if( isset( $icon['size'] ) )
2732
$r .= 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'" ';
2735
// Include alt (XHTML mandatory):
2736
if( ! isset( $params['alt'] ) )
2738
$params['alt'] = '';
2741
// Add all the attributes:
2742
$r .= get_field_attribs_as_string( $params, false );
2748
$blank_icon = get_icon_info('pixel');
2750
$r = '<img src="'.$rsc_url.$blank_icon['file'].'" ';
2752
// Include class (will default to "no_icon")
2753
if( ! isset( $params['class'] ) )
2755
if( isset( $icon['class'] ) )
2757
// This icon has a class
2758
$params['class'] = $icon['class'];
2762
$params['class'] = 'no_icon';
2766
// Include size (optional)
2767
if( isset( $icon['size'] ) )
2769
$r .= 'width="'.$icon['size'][0].'" height="'.$icon['size'][1].'" ';
2772
// Include alt (XHTML mandatory)
2773
if( ! isset( $params['alt'] ) )
2775
$params['alt'] = '';
2778
// Add all the attributes
2779
$r .= get_field_attribs_as_string( $params, false );
2934
* Escape a string to be used in Javascript.
2973
* Escape a string to be used in Javascript
2936
2974
* @param string
2937
2975
* @return string
2939
function jsspecialchars($s)
2977
function jsspecialchars( $s )
2941
2979
$r = str_replace(
2942
2980
array( '\\', '"', "'" ),
2943
2981
array( '\\\\', '\"', "\'" ),
2945
return htmlspecialchars($r, ENT_QUOTES);
2983
return htmlspecialchars( $r, ENT_QUOTES );
2950
2988
* Compact a date in a number keeping only integer value of the string
2952
2989
* @param string date
2954
2991
function compact_date( $date )
2956
return preg_replace( '#[^0-9]#', '', $date );
2993
return preg_replace( '#[^0-9]#', '', $date );
2961
2998
* Decompact a date in a date format ( Y-m-d h:m:s )
2963
2999
* @param string date
2965
3001
function decompact_date( $date )
2967
3003
$date0 = $date;
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);
2974
* Check the format of the phone number param and
2975
* format it in a french number if it is.
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
2979
3011
function format_phone( $phone, $hide_country_dialing_code_if_same_as_locale = true )
2983
3015
$dialing_code = NULL;
2985
3017
if( substr( $phone, 0, 1 ) == '+' )
2986
{ // We have a dialing code in the phone, so we extract it:
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 ) );
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
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 )
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 ) );
2998
{ // ( 0xxxxxxxxxxxxxx )
3034
// ( 0xxxxxxxxxxxxxx )
2999
3035
$phone_formated = '0'.substr( $phone, strlen( $dialing_code )+1 );
3003
3039
elseif( !is_null( $dialing_code ) )
3004
{ // Phone has a dialing code
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 )
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 ) );
3010
{ // ( +dialing xxxxxxxxxxx )
3049
// ( +dialing xxxxxxxxxxx )
3011
3050
$phone_formated = '+'.$dialing_code.' '.substr( $phone, strlen( $dialing_code )+1 );
3016
3055
if( strlen( $phone ) == 10 )
3017
{ // We can format it like a french phone number ( xx.xx.xx.xx.xx )
3057
// We can format it like a french phone number ( xx.xx.xx.xx.xx )
3018
3058
$phone_formated = format_french_phone( $phone );
3021
{ // We don't format phone: TODO generic format phone ( xxxxxxxxxxxxxxxx )
3062
// We don't format phone: TODO generic format phone ( xxxxxxxxxxxxxxxx )
3022
3063
$phone_formated = $phone;
3121
3161
global $is_admin_page;
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!
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'.
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.
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
3138
3180
function implode_with_and( $arr, $implode_by = ', ', $implode_last = ' & ' )
3140
switch( count($arr) )
3182
switch( count( $arr ) )
3146
$r = array_shift($arr);
3188
$r = array_shift( $arr );
3193
{ // we have some messages
3235
// we have some messages
3194
3236
$output = $target.'DisplayServerMessages( \''.format_to_js( $output ).'\');'."\n";
3197
if( !empty( $methods ) )
3198
{ // we have a methods to call
3239
if( ! empty( $methods ) )
3241
// we have a methods to call
3199
3242
foreach( $methods as $method => $param_list )
3200
{ // loop through each requested method
3244
// loop through each requested method
3201
3245
$params = array();
3202
3246
if( !is_array( $param_list ) )
3203
{ // lets make it an array
3248
// lets make it an array
3204
3249
$param_list = array( $param_list );
3206
3251
foreach( $param_list as $param )
3207
{ // add each parameter to the output
3253
// add each parameter to the output
3208
3254
if( !is_numeric( $param ) )
3209
{ // this is a string, quote it
3256
// this is a string, quote it
3210
3257
$param = '\''.format_to_js( $param ).'\'';
3212
3259
$params[] = $param;// add param to the list
3271
3318
function get_available_sort_options()
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!'),
3289
3336
* Generate order by clause
3291
3337
* @return string
3293
3339
function gen_order_clause( $order_by, $order_dir, $dbprefix, $dbIDname_disambiguation )