]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/utils.php
Release 6.4.1
[Github/sugarcrm.git] / include / utils.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM Community Edition is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
16  * details.
17  * 
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  * 
23  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25  * 
26  * The interactive user interfaces in modified source and object code versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  * 
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the "Powered by
32  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33  * technical reasons, the Appropriate Legal Notices must display the words
34  * "Powered by SugarCRM".
35  ********************************************************************************/
36
37 /*********************************************************************************
38
39  * Description:  Includes generic helper functions used throughout the application.
40  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
41  * All Rights Reserved.
42  * Contributor(s): ______________________________________..
43  ********************************************************************************/
44 require_once('include/SugarObjects/SugarConfig.php');
45 require_once('include/utils/security_utils.php');
46
47
48
49 function make_sugar_config(&$sugar_config)
50 {
51         /* used to convert non-array config.php file to array format */
52         global $admin_export_only;
53         global $cache_dir;
54         global $calculate_response_time;
55         global $create_default_user;
56         global $dateFormats;
57         global $dbconfig;
58         global $dbconfigoption;
59         global $default_action;
60         global $default_charset;
61         global $default_currency_name;
62         global $default_currency_symbol;
63         global $default_currency_iso4217;
64         global $defaultDateFormat;
65         global $default_language;
66         global $default_module;
67         global $default_password;
68         global $default_permission_mode;
69         global $default_theme;
70         global $defaultTimeFormat;
71         global $default_user_is_admin;
72         global $default_user_name;
73         global $disable_export;
74         global $disable_persistent_connections;
75         global $display_email_template_variable_chooser;
76         global $display_inbound_email_buttons;
77         global $history_max_viewed;
78         global $host_name;
79         global $import_dir;
80         global $languages;
81         global $list_max_entries_per_page;
82         global $lock_default_user_name;
83         global $log_memory_usage;
84     global $nameFormats;
85         global $requireAccounts;
86         global $RSS_CACHE_TIME;
87         global $session_dir;
88         global $site_URL;
89         global $site_url;
90         global $sugar_version;
91         global $timeFormats;
92         global $tmp_dir;
93         global $translation_string_prefix;
94         global $unique_key;
95         global $upload_badext;
96         global $upload_dir;
97         global $upload_maxsize;
98         global $import_max_execution_time;
99         global $list_max_entries_per_subpanel;
100         global $passwordsetting;
101
102         // assumes the following variables must be set:
103         // $dbconfig, $dbconfigoption, $cache_dir,  $session_dir, $site_URL, $upload_dir
104
105         $sugar_config = array (
106         'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
107         'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
108         'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
109         'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
110         'create_default_user' => empty($create_default_user) ? false : $create_default_user,
111         'chartEngine' => 'Jit',
112         'date_formats' => empty($dateFormats) ? array(
113         'Y-m-d'=>'2010-12-23',
114         'd-m-Y' => '23-12-2010',
115         'm-d-Y'=>'12-23-2010',
116         'Y/m/d'=>'2010/12/23',
117         'd/m/Y' => '23/12/2010',
118         'm/d/Y'=>'12/23/2010',
119         'Y.m.d' => '2010.12.23',
120         'd.m.Y' => '23.12.2010',
121         'm.d.Y' => '12.23.2010'
122                 ) : $dateFormats,
123         'dbconfig' => $dbconfig,  // this must be set!!
124         'dbconfigoption' => $dbconfigoption,  // this must be set!!
125         'default_action' => empty($default_action) ? 'index' : $default_action,
126         'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
127         'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
128         'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
129         'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
130         'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
131     'default_locale_name_format' => empty($defaultNameFormat) ? 's f l' : $defaultNameFormat,
132         'default_export_charset' => 'UTF-8',
133         'default_language' => empty($default_language) ? 'en_us' : $default_language,
134         'default_module' => empty($default_module) ? 'Home' : $default_module,
135         'default_password' => empty($default_password) ? '' : $default_password,
136         'default_permissions' => array (
137                 'dir_mode' => 02770,
138                 'file_mode' => 0660,
139                 'chown' => '',
140                 'chgrp' => '',
141         ),
142     'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
143     'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
144         'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
145         'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
146         'disable_export' => empty($disable_export) ? false : $disable_export,
147     'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
148     'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
149         'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
150         'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
151         'host_name' => empty($host_name) ? 'localhost' : $host_name,
152         'import_dir' => $import_dir,  // this must be set!!
153         'import_max_records_per_file' => 100,
154     'import_max_records_total_limit' => '',
155         'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
156         'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
157         'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
158         'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
159         'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
160     'name_formats' => empty($nameFormats) ? array(
161         's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
162         'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
163     ) : $nameFormats,
164     'portal_view' => 'single_user',
165         'resource_management' => array (
166             'special_query_limit' => 50000,
167             'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
168             'default_limit' => 1000,
169     ),
170         'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
171         'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
172         'session_dir' => $session_dir,  // this must be set!!
173         'site_url' => empty($site_URL) ? $site_url : $site_URL,  // this must be set!!
174         'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
175         'showThemePicker' => true,
176         'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
177         'time_formats' => empty($timeFormats) ? array (
178         'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM',
179         'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats,
180         'tmp_dir' => $tmp_dir,  // this must be set!!
181         'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
182         'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
183         'upload_badext' => empty($upload_badext) ? array (
184         'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
185         'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext,
186         'upload_dir' => $upload_dir,  // this must be set!!
187         'upload_maxsize' => empty($upload_maxsize) ? 30000000 : $upload_maxsize,
188         'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
189         'lock_homepage' => false,
190         'lock_subpanels' => false,
191         'max_dashlets_homepage' => 15,
192         'dashlet_display_row_options' => array('1','3','5','10'),
193         'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
194         'default_subpanel_tabs' =>  empty($subpanel_tabs) ? true : $subpanel_tabs,
195         'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
196         'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
197         'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
198         'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
199     'default_call_status' => 'Planned',
200         'js_lang_version' => 1,
201         'passwordsetting' => empty($passwordsetting) ? array (
202             'SystemGeneratedPasswordON' => '',
203             'generatepasswordtmpl' => '',
204             'lostpasswordtmpl' => '',
205             'forgotpasswordON' => true,
206         'linkexpiration' => '1',
207         'linkexpirationtime' => '30',
208         'linkexpirationtype' => '1',
209             'systexpiration' => '0',
210             'systexpirationtime' => '',
211             'systexpirationtype' => '0',
212             'systexpirationlogin' => '',
213                 ) : $passwordsetting,
214                 'use_sprites' => function_exists('imagecreatetruecolor'),
215         );
216 }
217
218 function get_sugar_config_defaults() {
219         global $locale;
220         /**
221          * used for getting base values for array style config.php.  used by the
222          * installer and to fill in new entries on upgrades.  see also:
223          * sugar_config_union
224          */
225
226         $sugar_config_defaults = array (
227         'admin_export_only' => false,
228         'export_delimiter' => ',',
229         'cache_dir' => 'cache/',
230         'calculate_response_time' => true,
231         'create_default_user' => false,
232         'chartEngine' => 'Jit',
233         'date_formats' => array (
234         'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
235         'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
236         'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
237     'name_formats' => array (
238         's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
239         'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s'
240     ),
241         'dbconfigoption' => array (
242         'persistent' => true,
243         'autofree' => false,
244         'debug' => 0,
245         'ssl' => false ),
246         'default_action' => 'index',
247         'default_charset' => return_session_value_or_default('default_charset',
248         'UTF-8'),
249         'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
250         'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
251         'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
252         'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
253         'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
254         'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
255         'default_date_format' => 'm/d/Y',
256     'default_locale_name_format' => 's f l',
257         'default_export_charset' => 'UTF-8',
258         'default_language' => return_session_value_or_default('default_language',
259         'en_us'),
260         'default_module' => 'Home',
261         'default_password' => '',
262         'default_permissions' => array (
263                 'dir_mode' => 02770,
264                 'file_mode' => 0660,
265                 'user' => '',
266                 'group' => '',
267         ),
268         'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
269         'default_time_format' => 'h:ia',
270         'default_user_is_admin' => false,
271         'default_user_name' => '',
272         'disable_export' => false,
273         'disable_persistent_connections' =>
274         return_session_value_or_default('disable_persistent_connections',
275         'false'),
276     'display_email_template_variable_chooser' => false,
277         'display_inbound_email_buttons' => false,
278         'dump_slow_queries' => false,
279         'email_default_editor' => 'html',
280         'email_default_client' => 'sugar',
281         'email_default_delete_attachments' => true,
282         'history_max_viewed' => 50,
283         'installer_locked' => true,
284         'import_max_records_per_file' => 100,
285     'import_max_records_total_limit' => '',
286         'languages' => array('en_us' => 'English (US)'),
287         'large_scale_test' => false,
288         'list_max_entries_per_page' => 20,
289         'list_max_entries_per_subpanel' => 10,
290         'lock_default_user_name' => false,
291         'log_memory_usage' => false,
292         'portal_view' => 'single_user',
293     'resource_management' => array (
294             'special_query_limit' => 50000,
295             'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
296             'default_limit' => 1000,
297     ),
298         'require_accounts' => true,
299         'rss_cache_time' => return_session_value_or_default('rss_cache_time',
300         '10800'),
301         'save_query' => 'all',
302         'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
303         'showThemePicker' => true,
304         'slow_query_time_msec' => '100',
305     'sugarbeet' => true,
306     'time_formats' => array (
307         'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM',
308         'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ),
309     'tracker_max_display_length' => 15,
310         'translation_string_prefix' =>
311         return_session_value_or_default('translation_string_prefix', false),
312         'upload_badext' => array (
313         'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
314         'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
315         'upload_maxsize' => 30000000,
316         'import_max_execution_time' => 3600,
317 //      'use_php_code_json' => returnPhpJsonStatus(),
318         'verify_client_ip' => true,
319         'js_custom_version' => '',
320         'js_lang_version' => 1,
321         'lead_conv_activity_opt' => 'donothing',
322         'default_number_grouping_seperator' => ',',
323         'default_decimal_seperator' => '.',
324         'lock_homepage' => false,
325         'lock_subpanels' => false,
326         'max_dashlets_homepage' => '15',
327         'default_max_tabs' => '7',
328         'dashlet_display_row_options' => array('1','3','5','10'),
329         'default_subpanel_tabs' =>  true,
330         'default_subpanel_links' => false,
331         'default_swap_last_viewed' => false,
332         'default_swap_shortcuts' => false,
333         'default_navigation_paradigm' => 'gm',
334         'admin_access_control' => false,
335         'use_common_ml_dir'     => false,
336         'common_ml_dir' => '',
337         'vcal_time' => '2',
338         'calendar' => array(
339           'default_view' => 'week',
340           'show_calls_by_default' => true,
341           'show_tasks_by_default' => true,
342           'editview_width' => 990,
343           'editview_height' => 480,
344           'day_timestep' => 15,
345           'week_timestep' => 30,
346           'month_timestep' => 60,
347           'items_draggable' => true,
348           'mouseover_expand' => true,
349         ),
350         'passwordsetting' => empty($passwordsetting) ? array (
351             'SystemGeneratedPasswordON' => '',
352             'generatepasswordtmpl' => '',
353             'lostpasswordtmpl' => '',
354             'forgotpasswordON' => false,
355         'linkexpiration' => '1',
356         'linkexpirationtime' => '30',
357         'linkexpirationtype' => '1',
358             'systexpiration' => '0',
359             'systexpirationtime' => '',
360             'systexpirationtype' => '0',
361             'systexpirationlogin' => '',
362                 ) : $passwordsetting,
363         'use_real_names' => true,
364         );
365
366         if(!is_object($locale)) {
367                 $locale = new Localization();
368         }
369
370         $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
371
372         $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
373         return( $sugar_config_defaults );
374 }
375
376 /**
377  * @deprecated use SugarView::getMenu() instead
378  */
379 function load_menu($path){
380         global $module_menu;
381
382         if(file_exists($path . 'Menu.php'))
383         {
384                 require($path . 'Menu.php');
385         }
386         if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
387         {
388                 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
389         }
390         if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
391         {
392                 require('custom/application/Ext/Menus/menu.ext.php');
393         }
394         return $module_menu;
395 }
396
397 /**
398  * get_notify_template_file
399  * This function will return the location of the email notifications template to use
400  *
401  * @return string relative file path to email notifications template file
402  */
403 function get_notify_template_file($language){
404         /*
405          * Order of operation:
406          * 1) custom version of specified language
407          * 2) stock version of specified language
408          * 3) custom version of en_us template
409          * 4) stock en_us template
410          */
411
412         // set $file to the base code template so it's set if none of the conditions pass
413         $file = "include/language/en_us.notify_template.html";
414
415         if(file_exists("custom/include/language/{$language}.notify_template.html")){
416                 $file = "custom/include/language/{$language}.notify_template.html";
417         }
418         else if(file_exists("include/language/{$language}.notify_template.html")){
419                 $file = "include/language/{$language}.notify_template.html";
420         }
421         else if(file_exists("custom/include/language/en_us.notify_template.html")){
422                 $file = "custom/include/language/en_us.notify_template.html";
423         }
424
425         return $file;
426 }
427
428 function sugar_config_union( $default, $override ){
429         // a little different then array_merge and array_merge_recursive.  we want
430         // the second array to override the first array if the same value exists,
431         // otherwise merge the unique keys.  it handles arrays of arrays recursively
432         // might be suitable for a generic array_union
433         if( !is_array( $override ) ){
434                 $override = array();
435         }
436         foreach( $default as $key => $value ){
437                 if( !array_key_exists($key, $override) ){
438                         $override[$key] = $value;
439                 }
440                 else if( is_array( $key ) ){
441                         $override[$key] = sugar_config_union( $value, $override[$key] );
442                 }
443         }
444         return( $override );
445 }
446
447 function make_not_writable( $file ){
448         // Returns true if the given file/dir has been made not writable
449         $ret_val = false;
450         if( is_file($file) || is_dir($file) ){
451                 if( !is_writable($file) ){
452                         $ret_val = true;
453                 }
454                 else {
455                         $original_fileperms = fileperms($file);
456
457                         // take away writable permissions
458                         $new_fileperms = $original_fileperms & ~0x0092;
459                         @sugar_chmod($file, $new_fileperms);
460
461                         if( !is_writable($file) ){
462                                 $ret_val = true;
463                         }
464                 }
465         }
466         return $ret_val;
467 }
468
469
470 /** This function returns the name of the person.
471  * It currently returns "first last".  It should not put the space if either name is not available.
472  * It should not return errors if either name is not available.
473  * If no names are present, it will return ""
474  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
475  * All Rights Reserved.
476  * Contributor(s): ______________________________________..
477  */
478 function return_name($row, $first_column, $last_column)
479 {
480         $first_name = "";
481         $last_name = "";
482         $full_name = "";
483
484         if(isset($row[$first_column]))
485         {
486                 $first_name = stripslashes($row[$first_column]);
487         }
488
489         if(isset($row[$last_column]))
490         {
491                 $last_name = stripslashes($row[$last_column]);
492         }
493
494         $full_name = $first_name;
495
496         // If we have a first name and we have a last name
497         if($full_name != "" && $last_name != "")
498         {
499                 // append a space, then the last name
500                 $full_name .= " ".$last_name;
501         }
502         // If we have no first name, but we have a last name
503         else if($last_name != "")
504         {
505                 // append the last name without the space.
506                 $full_name .= $last_name;
507         }
508
509         return $full_name;
510 }
511
512
513 function get_languages()
514 {
515         global $sugar_config;
516         $lang = $sugar_config['languages'];
517     if(!empty($sugar_config['disabled_languages'])){
518         foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
519             unset($lang[$disable]);
520         }
521     }
522         return $lang;
523 }
524
525 function get_all_languages()
526 {
527         global $sugar_config;
528         return $sugar_config['languages'];
529 }
530
531
532 function get_language_display($key)
533 {
534         global $sugar_config;
535         return $sugar_config['languages'][$key];
536 }
537
538 function get_assigned_user_name($assigned_user_id, $is_group = '') {
539         static $saved_user_list = null;
540
541         if(empty($saved_user_list)) {
542                 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
543         }
544
545         if(isset($saved_user_list[$assigned_user_id])) {
546                 return $saved_user_list[$assigned_user_id];
547         }
548
549         return '';
550 }
551
552 /**
553  * retrieves the user_name column value (login)
554  * @param string id GUID of user
555  * @return string
556  */
557 function get_user_name($id) {
558         global $db;
559
560         if(empty($db))
561         $db = DBManagerFactory::getInstance();
562
563         $q = "SELECT user_name FROM users WHERE id='{$id}'";
564         $r = $db->query($q);
565         $a = $db->fetchByAssoc($r);
566
567         return (empty($a)) ? '' : $a['user_name'];
568 }
569
570
571 //TODO Update to use global cache
572 /**
573  * get_user_array
574  *
575  * This is a helper function to return an Array of users depending on the parameters passed into the function.
576  * This function uses the get_register_value function by default to use a caching layer where supported.
577  *
578  * @param bool $add_blank Boolean value to add a blank entry to the array results, true by default
579  * @param string $status String value indicating the status to filter users by, "Active" by default
580  * @param string $user_id String value to specify a particular user id value (searches the id column of users table), blank by default
581  * @param bool $use_real_name Boolean value indicating whether or not results should include the full name or just user_name, false by default
582  * @param String $user_name_filter String value indicating the user_name filter (searches the user_name column of users table) to optionally search with, blank by default
583  * @param string $portal_filter String query filter for portal users (defaults to searching non-portal users), change to blank if you wish to search for all users including portal users
584  * @param bool $from_cache Boolean value indicating whether or not to use the get_register_value function for caching, true by default
585  * @return array Array of users matching the filter criteria that may be from cache (if similar search was previously run)
586  */
587 function get_user_array($add_blank=true, $status="Active", $user_id='', $use_real_name=false, $user_name_filter='', $portal_filter=' AND portal_only=0 ', $from_cache = true) {
588         global $locale;
589         global $sugar_config;
590
591         if(empty($locale)) {
592                 $locale = new Localization();
593         }
594
595         if($from_cache) {
596         $key_name = $add_blank. $status . $user_id . $use_real_name . $user_name_filter . $portal_filter;
597                 $user_array = get_register_value('user_array', $key_name);
598     }
599
600         if(empty($user_array)) {
601                 $db = DBManagerFactory::getInstance();
602                 $temp_result = Array();
603                 // Including deleted users for now.
604                 if (empty($status)) {
605                         $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$portal_filter;
606                 }
607                 else {
608                         $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$portal_filter;
609                 }
610
611                 if (!empty($user_name_filter)) {
612                         $query .= " AND user_name LIKE '$user_name_filter%' ";
613                 }
614                 if (!empty($user_id)) {
615                         $query .= " OR id='{$user_id}'";
616                 }
617                 $query = $query.' ORDER BY user_name ASC';
618                 $GLOBALS['log']->debug("get_user_array query: $query");
619                 $result = $db->query($query, true, "Error filling in user array: ");
620
621                 if ($add_blank==true) {
622                         // Add in a blank row
623                         $temp_result[''] = '';
624                 }
625
626                 // Get the id and the name.
627                 while($row = $db->fetchByAssoc($result)) {
628                         if($use_real_name == true || showFullName()) {
629                                 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
630                                         $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
631                                 } else {
632                                         $temp_result[$row['id']] = $row['user_name'];
633                                 }
634                         } else {
635                                 $temp_result[$row['id']] = $row['user_name'];
636                         }
637                 }
638
639                 $user_array = $temp_result;
640                 if($from_cache)
641         {
642                         set_register_value('user_array', $key_name, $temp_result);
643         }
644         }
645
646
647         return $user_array;
648 }
649
650
651 /**
652  * uses a different query to return a list of users than get_user_array()
653  * @param args string where clause entry
654  * @return array Array of Users' details that match passed criteria
655  */
656 function getUserArrayFromFullName($args, $hide_portal_users = false) {
657         global $locale;
658         $db = DBManagerFactory::getInstance();
659
660         $argArray = array();
661         if(strpos($args, " ")) {
662                 $argArray = explode(" ", $args);
663         } else {
664                 $argArray[] = $args;
665         }
666
667         $inClause = '';
668         foreach($argArray as $arg) {
669                 if(!empty($inClause)) {
670                         $inClause .= ' OR ';
671                 }
672                 if(empty($arg))
673                 continue;
674
675                 $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
676         }
677
678         $query  = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
679         if ( $hide_portal_users ) {
680             $query .= " portal_only=0 AND ";
681         }
682         $query .= $inClause;
683         $query .= " ORDER BY last_name ASC";
684
685         $r = $db->query($query);
686         $ret = array();
687         while($a = $db->fetchByAssoc($r)) {
688                 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
689         }
690
691         return $ret;
692 }
693
694 /**
695  *
696  * based on user pref then system pref
697  */
698 function showFullName() {
699         global $sugar_config;
700         global $current_user;
701         static $showFullName = null;
702
703         if (is_null($showFullName)) {
704                 $sysPref = !empty($sugar_config['use_real_names']);
705                 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
706
707                 if($userPref != null) {
708                         $showFullName = ($userPref == 'on');
709                 } else {
710                         $showFullName = $sysPref;
711                 }
712         }
713
714         return $showFullName;
715 }
716
717 function clean($string, $maxLength)
718 {
719         $string = substr($string, 0, $maxLength);
720         return escapeshellcmd($string);
721 }
722
723 /**
724  * Copy the specified request variable to the member variable of the specified object.
725  * Do no copy if the member variable is already set.
726  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
727  * All Rights Reserved.
728  * Contributor(s): ______________________________________..
729  */
730 function safe_map($request_var, & $focus, $always_copy = false)
731 {
732         safe_map_named($request_var, $focus, $request_var, $always_copy);
733 }
734
735 /**
736  * Copy the specified request variable to the member variable of the specified object.
737  * Do no copy if the member variable is already set.
738  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
739  * All Rights Reserved.
740  * Contributor(s): ______________________________________..
741  */
742 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
743 {
744         if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
745                 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
746                 $focus->$member_var = $_REQUEST[$request_var];
747         }
748 }
749
750 /**
751  * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
752  *
753  * @param string $language specific language to load
754  * @return array lang strings
755  */
756 function return_app_list_strings_language($language)
757 {
758         global $app_list_strings;
759         global $sugar_config;
760
761         $cache_key = 'app_list_strings.'.$language;
762
763         // Check for cached value
764         $cache_entry = sugar_cache_retrieve($cache_key);
765         if(!empty($cache_entry))
766         {
767                 return $cache_entry;
768         }
769
770         $default_language = $sugar_config['default_language'];
771         $temp_app_list_strings = $app_list_strings;
772
773         $langs = array();
774         if ($language != 'en_us') {
775             $langs[] = 'en_us';
776         }
777         if ($default_language != 'en_us' && $language != $default_language) {
778             $langs[] = $default_language;
779         }
780         $langs[] = $language;
781
782         $app_list_strings_array = array();
783
784         foreach ( $langs as $lang ) {
785             $app_list_strings = array();
786             if(file_exists("include/language/$lang.lang.php")) {
787             include("include/language/$lang.lang.php");
788             $GLOBALS['log']->info("Found language file: $lang.lang.php");
789         }
790         if(file_exists("include/language/$lang.lang.override.php")) {
791             include("include/language/$lang.lang.override.php");
792             $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
793         }
794         if(file_exists("include/language/$lang.lang.php.override")) {
795             include("include/language/$lang.lang.php.override");
796             $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
797         }
798
799         $app_list_strings_array[] = $app_list_strings;
800     }
801
802     $app_list_strings = array();
803     foreach ( $app_list_strings_array as $app_list_strings_item ) {
804         $app_list_strings = sugarArrayMerge($app_list_strings, $app_list_strings_item);
805     }
806
807     foreach ( $langs as $lang ) {
808         if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
809             $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
810             $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
811         }
812         if(file_exists("custom/include/language/$lang.lang.php")) {
813             include("custom/include/language/$lang.lang.php");
814             $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
815         }
816     }
817
818         if(!isset($app_list_strings)) {
819                 $GLOBALS['log']->fatal("Unable to load the application language file for the selected language ($language) or the default language ($default_language) or the en_us language");
820                 return null;
821         }
822
823         $return_value = $app_list_strings;
824         $app_list_strings = $temp_app_list_strings;
825
826         sugar_cache_put($cache_key, $return_value);
827
828         return $return_value;
829 }
830
831 /**
832 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
833 * $GLOBALS['app_list_strings']['$key'] = $value, so we have to delete the original ones in app_list_strings and relace it with the custom ones.
834  * @param file string the language that you want include,
835  * @param app_list_strings array the golbal strings
836  * @return array
837  */
838  //jchi 25347
839 function _mergeCustomAppListStrings($file , $app_list_strings){
840         $app_list_strings_original = $app_list_strings;
841         unset($app_list_strings);
842         // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
843         //                  This way, language file can add items to save specific standard codelist from being overwritten
844         $exemptDropdowns = array();
845         include($file);
846         if(!isset($app_list_strings) || !is_array($app_list_strings)){
847                 return $app_list_strings_original;
848         }
849         //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
850
851         // FG - bug 45525 - Specific codelists must NOT be overwritten
852         $exemptDropdowns[] = "moduleList";
853         $exemptDropdowns[] = "parent_type_display";
854         $exemptDropdowns[] = "record_type_display";
855         $exemptDropdowns[] = "record_type_display_notes";
856
857         foreach($app_list_strings as $key=>$value)
858         {
859                 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
860                 {
861                         unset($app_list_strings_original["$key"]);
862                 }
863    }
864    $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
865    return $app_list_strings;
866 }
867
868 /**
869  * This function retrieves an application language file and returns the array of strings included.
870  *
871  * @param string $language specific language to load
872  * @return array lang strings
873  */
874 function return_application_language($language)
875 {
876         global $app_strings, $sugar_config;
877
878         $cache_key = 'app_strings.'.$language;
879
880         // Check for cached value
881         $cache_entry = sugar_cache_retrieve($cache_key);
882         if(!empty($cache_entry))
883         {
884                 return $cache_entry;
885         }
886
887         $temp_app_strings = $app_strings;
888         $default_language = $sugar_config['default_language'];
889
890         $langs = array();
891         if ($language != 'en_us') {
892             $langs[] = 'en_us';
893         }
894         if ($default_language != 'en_us' && $language != $default_language) {
895             $langs[] = $default_language;
896         }
897
898         $langs[] = $language;
899
900         $app_strings_array = array();
901
902         foreach ( $langs as $lang ) {
903             $app_strings = array();
904             if(file_exists("include/language/$lang.lang.php")) {
905             include("include/language/$lang.lang.php");
906             $GLOBALS['log']->info("Found language file: $lang.lang.php");
907         }
908         if(file_exists("include/language/$lang.lang.override.php")) {
909             include("include/language/$lang.lang.override.php");
910             $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
911         }
912         if(file_exists("include/language/$lang.lang.php.override")) {
913             include("include/language/$lang.lang.php.override");
914             $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
915         }
916         if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
917             include("custom/application/Ext/Language/$lang.lang.ext.php");
918             $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
919         }
920         if(file_exists("custom/include/language/$lang.lang.php")) {
921             include("custom/include/language/$lang.lang.php");
922             $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
923         }
924         $app_strings_array[] = $app_strings;
925         }
926
927         $app_strings = array();
928     foreach ( $app_strings_array as $app_strings_item ) {
929         $app_strings = sugarArrayMerge($app_strings, $app_strings_item);
930     }
931
932         if(!isset($app_strings)) {
933                 $GLOBALS['log']->fatal("Unable to load the application language strings");
934                 return null;
935         }
936
937         // If we are in debug mode for translating, turn on the prefix now!
938         if($sugar_config['translation_string_prefix']) {
939                 foreach($app_strings as $entry_key=>$entry_value) {
940                         $app_strings[$entry_key] = $language.' '.$entry_value;
941                 }
942         }
943         if(isset($_SESSION['show_deleted'])) {
944                 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
945                 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
946                 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
947                 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
948         }
949
950         $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
951
952         $return_value = $app_strings;
953         $app_strings = $temp_app_strings;
954
955         sugar_cache_put($cache_key, $return_value);
956
957         return $return_value;
958 }
959
960 /**
961  * This function retrieves a module's language file and returns the array of strings included.
962  *
963  * @param string $language specific language to load
964  * @param string $module module name to load strings for
965  * @param bool $refresh optional, true if you want to rebuild the language strings
966  * @return array lang strings
967  */
968 function return_module_language($language, $module, $refresh=false)
969 {
970         global $mod_strings;
971         global $sugar_config;
972         global $currentModule;
973
974         // Jenny - Bug 8119: Need to check if $module is not empty
975         if (empty($module)) {
976                 $stack  = debug_backtrace();
977                 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
978                 return array();
979         }
980
981     if( !$refresh )
982     {
983         $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
984         // Check for cached value
985         $cache_entry = sugar_cache_retrieve($cache_key);
986         if(!empty($cache_entry))
987         {
988             return $cache_entry;
989         }
990     }
991         // Store the current mod strings for later
992         $temp_mod_strings = $mod_strings;
993         $loaded_mod_strings = array();
994         $language_used = $language;
995         $default_language = $sugar_config['default_language'];
996
997         if(empty($language)) {
998                 $language = $default_language;
999         }
1000
1001         // Bug 21559 - So we can get all the strings defined in the template, refresh
1002         // the vardefs file if the cached language file doesn't exist.
1003     if(!file_exists(sugar_cached('modules/'). $module . '/language/'.$language.'.lang.php')
1004                         && !empty($GLOBALS['beanList'][$module])){
1005                 $object = BeanFactory::getObjectName($module);
1006                 VardefManager::refreshVardefs($module,$object);
1007         }
1008
1009         $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
1010
1011         // cn: bug 6048 - merge en_us with requested language
1012         if($language != $sugar_config['default_language'])
1013         $loaded_mod_strings = sugarArrayMerge(
1014             LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
1015                 $loaded_mod_strings
1016             );
1017
1018     // Load in en_us strings by default
1019     if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
1020         $loaded_mod_strings = sugarArrayMerge(
1021             LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1022                 $loaded_mod_strings
1023             );
1024
1025         // If we are in debug mode for translating, turn on the prefix now!
1026         if($sugar_config['translation_string_prefix']) {
1027                 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
1028                         $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1029                 }
1030         }
1031
1032         $return_value = $loaded_mod_strings;
1033         if(!isset($mod_strings)){
1034                 $mod_strings = $return_value;
1035         }
1036         else
1037                 $mod_strings = $temp_mod_strings;
1038
1039     $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1040     sugar_cache_put($cache_key, $return_value);
1041         return $return_value;
1042 }
1043
1044
1045 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1046  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1047  * All Rights Reserved.
1048  * Contributor(s): ______________________________________..
1049  * If you are using the current language, do not call this function unless you are loading it for the first time */
1050 function return_mod_list_strings_language($language,$module) {
1051         global $mod_list_strings;
1052         global $sugar_config;
1053         global $currentModule;
1054
1055         $cache_key = "mod_list_str_lang.".$language.$module;
1056
1057         // Check for cached value
1058         $cache_entry = sugar_cache_retrieve($cache_key);
1059         if(!empty($cache_entry))
1060         {
1061                 return $cache_entry;
1062         }
1063
1064         $language_used = $language;
1065         $temp_mod_list_strings = $mod_list_strings;
1066         $default_language = $sugar_config['default_language'];
1067
1068         if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1069                 return $mod_list_strings;
1070         }
1071
1072         // cn: bug 6351 - include en_us if file langpack not available
1073         // cn: bug 6048 - merge en_us with requested language
1074         include("modules/$module/language/en_us.lang.php");
1075         $en_mod_list_strings = array();
1076         if($language_used != $default_language)
1077         $en_mod_list_strings = $mod_list_strings;
1078
1079         if(file_exists("modules/$module/language/$language.lang.php")) {
1080                 include("modules/$module/language/$language.lang.php");
1081         }
1082
1083         if(file_exists("modules/$module/language/$language.lang.override.php")){
1084                 include("modules/$module/language/$language.lang.override.php");
1085         }
1086
1087         if(file_exists("modules/$module/language/$language.lang.php.override")){
1088                 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1089                 include("modules/$module/language/$language.lang.php.override");
1090         }
1091
1092         // cn: bug 6048 - merge en_us with requested language
1093         $mod_list_strings = sugarArrayMerge($en_mod_list_strings, $mod_list_strings);
1094
1095         // if we still don't have a language pack, then log an error
1096         if(!isset($mod_list_strings)) {
1097                 $GLOBALS['log']->fatal("Unable to load the application list language file for the selected language($language) or the default language($default_language) for module({$module})");
1098                 return null;
1099         }
1100
1101         $return_value = $mod_list_strings;
1102         $mod_list_strings = $temp_mod_list_strings;
1103
1104         sugar_cache_put($cache_key, $return_value);
1105         return $return_value;
1106 }
1107
1108
1109 /** This function retrieves a theme's language file and returns the array of strings included.
1110  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1111  * All Rights Reserved.
1112  * Contributor(s): ______________________________________..
1113  */
1114 function return_theme_language($language, $theme)
1115 {
1116         global $mod_strings, $sugar_config, $current_language;
1117
1118         $language_used = $language;
1119         $default_language = $sugar_config['default_language'];
1120
1121         include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1122         if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1123                 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1124         }
1125         if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1126                 echo 'Please Change:<br>' . SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php";
1127                 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1128         }
1129         if(!isset($theme_strings))
1130         {
1131                 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1132                 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1133                 $language_used = $default_language;
1134         }
1135
1136         if(!isset($theme_strings))
1137         {
1138                 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1139                 return null;
1140         }
1141
1142         // If we are in debug mode for translating, turn on the prefix now!
1143         if($sugar_config['translation_string_prefix'])
1144         {
1145                 foreach($theme_strings as $entry_key=>$entry_value)
1146                 {
1147                         $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1148                 }
1149         }
1150
1151         return $theme_strings;
1152 }
1153
1154
1155
1156 /** If the session variable is defined and is not equal to "" then return it.  Otherwise, return the default value.
1157  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1158  * All Rights Reserved.
1159  * Contributor(s): ______________________________________..
1160  */
1161 function return_session_value_or_default($varname, $default)
1162 {
1163         if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1164         {
1165                 return $_SESSION[$varname];
1166         }
1167
1168         return $default;
1169 }
1170
1171 /**
1172  * Creates an array of where restrictions.  These are used to construct a where SQL statement on the query
1173  * It looks for the variable in the $_REQUEST array.  If it is set and is not "" it will create a where clause out of it.
1174  * @param &$where_clauses - The array to append the clause to
1175  * @param $variable_name - The name of the variable to look for an add to the where clause if found
1176  * @param $SQL_name - [Optional] If specified, this is the SQL column name that is used.  If not specified, the $variable_name is used as the SQL_name.
1177  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1178  * All Rights Reserved.
1179  * Contributor(s): ______________________________________..
1180  */
1181 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1182 {
1183         if($SQL_name == null)
1184         {
1185                 $SQL_name = $variable_name;
1186         }
1187
1188         if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1189         {
1190                 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1191         }
1192 }
1193
1194 /**
1195  * Generate the appropriate SQL based on the where clauses.
1196  * @param $where_clauses - An Array of individual where clauses stored as strings
1197  * @returns string where_clause - The final SQL where clause to be executed.
1198  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1199  * All Rights Reserved.
1200  * Contributor(s): ______________________________________..
1201  */
1202 function generate_where_statement($where_clauses)
1203 {
1204         $where = "";
1205         foreach($where_clauses as $clause)
1206         {
1207                 if($where != "")
1208                 $where .= " and ";
1209                 $where .= $clause;
1210         }
1211
1212         $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1213         return $where;
1214 }
1215
1216 /**
1217  * determines if a passed string matches the criteria for a Sugar GUID
1218  * @param string $guid
1219  * @return bool False on failure
1220  */
1221 function is_guid($guid) {
1222         if(strlen($guid) != 36) {
1223                 return false;
1224         }
1225
1226         if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1227                 return true;
1228         }
1229
1230         return true;;
1231 }
1232
1233
1234 /**
1235  * A temporary method of generating GUIDs of the correct format for our DB.
1236  * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1237  *
1238  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1239  * All Rights Reserved.
1240  * Contributor(s): ______________________________________..
1241  */
1242 function create_guid()
1243 {
1244         $microTime = microtime();
1245         list($a_dec, $a_sec) = explode(" ", $microTime);
1246
1247         $dec_hex = dechex($a_dec* 1000000);
1248         $sec_hex = dechex($a_sec);
1249
1250         ensure_length($dec_hex, 5);
1251         ensure_length($sec_hex, 6);
1252
1253         $guid = "";
1254         $guid .= $dec_hex;
1255         $guid .= create_guid_section(3);
1256         $guid .= '-';
1257         $guid .= create_guid_section(4);
1258         $guid .= '-';
1259         $guid .= create_guid_section(4);
1260         $guid .= '-';
1261         $guid .= create_guid_section(4);
1262         $guid .= '-';
1263         $guid .= $sec_hex;
1264         $guid .= create_guid_section(6);
1265
1266         return $guid;
1267
1268 }
1269
1270 function create_guid_section($characters)
1271 {
1272         $return = "";
1273         for($i=0; $i<$characters; $i++)
1274         {
1275                 $return .= dechex(mt_rand(0,15));
1276         }
1277         return $return;
1278 }
1279
1280 function ensure_length(&$string, $length)
1281 {
1282         $strlen = strlen($string);
1283         if($strlen < $length)
1284         {
1285                 $string = str_pad($string,$length,"0");
1286         }
1287         else if($strlen > $length)
1288         {
1289                 $string = substr($string, 0, $length);
1290         }
1291 }
1292
1293 function microtime_diff($a, $b) {
1294         list($a_dec, $a_sec) = explode(" ", $a);
1295         list($b_dec, $b_sec) = explode(" ", $b);
1296         return $b_sec - $a_sec + $b_dec - $a_dec;
1297 }
1298
1299 // check if Studio is displayed.
1300 function displayStudioForCurrentUser()
1301 {
1302     global $current_user;
1303     if ( $current_user->isAdmin() ) {
1304         return true;
1305     }
1306
1307
1308
1309         return true;
1310
1311 }
1312
1313 function displayWorkflowForCurrentUser()
1314 {
1315     $_SESSION['display_workflow_for_user'] = false;
1316     return false;
1317 }
1318
1319 // return an array with all modules where the user is an admin.
1320 function get_admin_modules_for_user($user) {
1321     $GLOBALS['log']->deprecated("get_admin_modules_for_user() is deprecated as of 6.2.2 and may disappear in the future, use Users->getDeveloperModules() instead");
1322
1323     if(!isset($user)){
1324         $modules = array();
1325         return $modules;
1326     }
1327
1328     return($user->getDeveloperModules());
1329
1330 }
1331
1332  function get_workflow_admin_modules_for_user($user){
1333     if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1334         return $_SESSION['get_workflow_admin_modules_for_user'];
1335     }
1336
1337     global $moduleList;
1338     $workflow_mod_list = array();
1339     foreach($moduleList as $module){
1340                 $workflow_mod_list[$module] = $module;
1341         }
1342
1343         // This list is taken from teh previous version of workflow_utils.php
1344     $workflow_mod_list['Tasks'] = "Tasks";
1345     $workflow_mod_list['Calls'] = "Calls";
1346     $workflow_mod_list['Meetings'] = "Meetings";
1347     $workflow_mod_list['Notes'] = "Notes";
1348     $workflow_mod_list['ProjectTask'] = "Project Tasks";
1349         $workflow_mod_list['Leads'] = "Leads";
1350         $workflow_mod_list['Opportunities'] = "Opportunities";
1351         // End of list
1352
1353     $workflow_admin_modules = array();
1354     if(empty($user)) {
1355         return $workflow_admin_modules;
1356     }
1357     $actions = ACLAction::getUserActions($user->id);
1358     //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1359     if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1360         $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1361         $workflow_admin_modules['Forecasts'] = 'Forecasts';
1362     }
1363     foreach ($workflow_mod_list as $key=>$val) {
1364         if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1365             && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1366            ($user->isDeveloperForModule($key))) {
1367                 $workflow_admin_modules[$key] = $val;
1368         }
1369     }
1370     $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1371     return ($workflow_admin_modules);
1372 }
1373
1374 // Check if user is admin for at least one module.
1375 function is_admin_for_any_module($user) {
1376     if (!isset($user)){
1377         return false;
1378     }
1379     if($user->isAdmin()) {
1380         return true;
1381     }
1382     return false;
1383 }
1384
1385
1386 // Check if user is admin for a specific module.
1387 function is_admin_for_module($user,$module) {
1388     if (!isset($user)) {
1389         return false;
1390     }
1391     if ($user->isAdmin()) {
1392         return true;
1393     }
1394     return false;
1395 }
1396
1397
1398 /**
1399  * Check if user id belongs to a system admin.
1400  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1401  * All Rights Reserved.
1402  * Contributor(s): ______________________________________..
1403  */
1404 function is_admin($user) {
1405     if(empty($user)) {
1406         return false;
1407     }
1408
1409         return $user->isAdmin();
1410 }
1411
1412 /**
1413  * Return the display name for a theme if it exists.
1414  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1415  * All Rights Reserved.
1416  * Contributor(s): ______________________________________..
1417  *
1418  * @deprecated use SugarThemeRegistry::get($theme)->name instead
1419  */
1420 function get_theme_display($theme)
1421 {
1422         return SugarThemeRegistry::get($theme)->name;
1423 }
1424
1425 /**
1426  * Return an array of directory names.
1427  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1428  * All Rights Reserved.
1429  * Contributor(s): ______________________________________..
1430  *
1431  * @deprecated use SugarThemeRegistry::availableThemes() instead.
1432  */
1433 function get_themes()
1434 {
1435     return SugarThemeRegistry::availableThemes();
1436 }
1437
1438 /**
1439  * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1440  * Create HTML to display select options in a dropdown list.  To be used inside
1441  * of a select statement in a form.
1442  * param $option_list - the array of strings to that contains the option list
1443  * param $selected - the string which contains the default value
1444  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1445  * All Rights Reserved.
1446  * Contributor(s): ______________________________________..
1447  */
1448 function get_select_options ($option_list, $selected) {
1449         return get_select_options_with_id($option_list, $selected);
1450 }
1451
1452 /**
1453  * Create HTML to display select options in a dropdown list.  To be used inside
1454  * of a select statement in a form.   This method expects the option list to have keys and values.  The keys are the ids.  The values are the display strings.
1455  * param $option_list - the array of strings to that contains the option list
1456  * param $selected - the string which contains the default value
1457  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1458  * All Rights Reserved.
1459  * Contributor(s): ______________________________________..
1460  */
1461 function get_select_options_with_id ($option_list, $selected_key) {
1462         return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1463 }
1464
1465
1466 /**
1467  * Create HTML to display select options in a dropdown list.  To be used inside
1468  * of a select statement in a form.   This method expects the option list to have keys and values.  The keys are the ids.  The values are the display strings.
1469  * param $label_list - the array of strings to that contains the option list
1470  * param $key_list - the array of strings to that contains the values list
1471  * param $selected - the string which contains the default value
1472  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1473  * All Rights Reserved.
1474  * Contributor(s): ______________________________________..
1475  */
1476 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1477         global $app_strings;
1478         $select_options = "";
1479
1480         //for setting null selection values to human readable --None--
1481         $pattern = "/'0?'></";
1482         $replacement = "''>".$app_strings['LBL_NONE']."<";
1483     if($massupdate){
1484         $replacement .= "/OPTION>\n<OPTION value='__SugarMassUpdateClearField__'><"; // Giving the user the option to unset a drop down list. I.e. none means that it won't get updated
1485     }
1486
1487         if (empty($key_list)) $key_list = array();
1488         //create the type dropdown domain and set the selected value if $opp value already exists
1489         foreach ($key_list as $option_key=>$option_value) {
1490
1491                 $selected_string = '';
1492                 // the system is evaluating $selected_key == 0 || '' to true.  Be very careful when changing this.  Test all cases.
1493                 // The bug was only happening with one of the users in the drop down.  It was being replaced by none.
1494                 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) &&  in_array($option_key, $selected_key)))
1495                 {
1496                         $selected_string = 'selected ';
1497                 }
1498
1499                 $html_value = $option_key;
1500
1501                 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1502         }
1503         $select_options = preg_replace($pattern, $replacement, $select_options);
1504         return $select_options;
1505 }
1506
1507
1508 /**
1509  * Call this method instead of die().
1510  * Then we call the die method with the error message that is passed in.
1511  */
1512 function sugar_die($error_message)
1513 {
1514         global $focus;
1515         sugar_cleanup();
1516         die($error_message);
1517 }
1518
1519
1520 /**
1521  * Create javascript to clear values of all elements in a form.
1522  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1523  * All Rights Reserved.
1524  * Contributor(s): ______________________________________..
1525  */
1526 function get_clear_form_js () {
1527         $the_script = <<<EOQ
1528 <script type="text/javascript" language="JavaScript">
1529 function clear_form(form) {
1530         var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1531         if(typeof(form.advanced) != 'undefined'){
1532                 newLoc += '&advanced=' + form.advanced.value;
1533         }
1534         document.location.href= newLoc;
1535 }
1536 </script>
1537 EOQ;
1538
1539         return $the_script;
1540 }
1541
1542 /**
1543  * Create javascript to set the cursor focus to specific field in a form
1544  * when the screen is rendered.  The field name is currently hardcoded into the
1545  * the function.
1546  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1547  * All Rights Reserved.
1548  * Contributor(s): ______________________________________..
1549  */
1550 function get_set_focus_js () {
1551         //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1552         $the_script = <<<EOQ
1553 <script type="text/javascript" language="JavaScript">
1554 <!-- Begin
1555 function set_focus() {
1556         if (document.forms.length > 0) {
1557                 for (i = 0; i < document.forms.length; i++) {
1558                         for (j = 0; j < document.forms[i].elements.length; j++) {
1559                                 var field = document.forms[i].elements[j];
1560                                 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1561                                                 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1562                                         field.focus();
1563                     if (field.type == "text") {
1564                         field.select();
1565                     }
1566                                         break;
1567                         }
1568                         }
1569         }
1570         }
1571 }
1572 //  End -->
1573 </script>
1574 EOQ;
1575
1576         return $the_script;
1577 }
1578
1579 /**
1580  * Very cool algorithm for sorting multi-dimensional arrays.  Found at http://us2.php.net/manual/en/function.array-multisort.php
1581  * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1582  * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1583  * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1584  * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1585  * the first - so the array is sorted by the last given column first, then the one before ...
1586  * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1587  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1588  * All Rights Reserved.
1589  * Contributor(s): ______________________________________..
1590  */
1591 function array_csort() {
1592         $args = func_get_args();
1593         $marray = array_shift($args);
1594         $i = 0;
1595
1596         $msortline = "return(array_multisort(";
1597         foreach ($args as $arg) {
1598                 $i++;
1599                 if (is_string($arg)) {
1600                         foreach ($marray as $row) {
1601                                 $sortarr[$i][] = $row[$arg];
1602                         }
1603                 } else {
1604                         $sortarr[$i] = $arg;
1605                 }
1606                 $msortline .= "\$sortarr[".$i."],";
1607         }
1608         $msortline .= "\$marray));";
1609
1610         eval($msortline);
1611         return $marray;
1612 }
1613
1614 /**
1615  * Converts localized date format string to jscalendar format
1616  * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1617  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1618  * All Rights Reserved.
1619  * Contributor(s): ______________________________________..
1620  */
1621 function parse_calendardate($local_format) {
1622         preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1623         $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1624         return str_replace(array("y", "ï¿„1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1625 }
1626
1627
1628
1629
1630
1631 function translate($string, $mod='', $selectedValue=''){
1632         //$test_start = microtime();
1633         //static $mod_strings_results = array();
1634         if(!empty($mod)){
1635                 global $current_language;
1636                 //Bug 31275
1637                 if(isset($_REQUEST['login_language'])){
1638                     $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1639                 }
1640                 $mod_strings = return_module_language($current_language, $mod);
1641
1642         }else{
1643                 global $mod_strings;
1644         }
1645
1646         $returnValue = '';
1647         global $app_strings, $app_list_strings;
1648
1649         if(isset($mod_strings[$string]))
1650         $returnValue = $mod_strings[$string];
1651         else if(isset($app_strings[$string]))
1652         $returnValue = $app_strings[$string];
1653         else if(isset($app_list_strings[$string]))
1654         $returnValue = $app_list_strings[$string];
1655         else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1656         $returnValue = $app_list_strings['moduleList'][$string];
1657
1658
1659         //$test_end = microtime();
1660         //
1661         //    $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1662         //
1663         //    echo("translate results:");
1664         //    $total_time = 0;
1665         //    $total_strings = 0;
1666         //    foreach($mod_strings_results as $key=>$value)
1667         //    {
1668         //        echo("Module $key \t\t time $value \t\t<br>");
1669         //        $total_time += $value;
1670         //    }
1671         //
1672         //    echo("Total time: $total_time<br>");
1673
1674
1675
1676         if(empty($returnValue)){
1677                 return $string;
1678         }
1679
1680         if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){
1681                 return $returnValue[$selectedValue];
1682         }
1683
1684         return $returnValue;
1685 }
1686
1687 function unTranslateNum($num) {
1688         static $dec_sep;
1689         static $num_grp_sep;
1690         global $current_user, $sugar_config;
1691
1692         if($dec_sep == null) {
1693             $user_dec_sep = $current_user->getPreference('dec_sep');
1694             $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1695         }
1696         if($num_grp_sep == null) {
1697             $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1698             $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1699         }
1700
1701         $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1702         $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1703         return $num;
1704
1705 }
1706
1707 function add_http($url) {
1708         if(!preg_match("@://@i", $url)) {
1709                 $scheme = "http";
1710                 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1711                         $scheme = 'https';
1712                 }
1713
1714                 return "{$scheme}://{$url}";
1715         }
1716
1717         return $url;
1718 }
1719
1720 /**
1721  * returns a default array of XSS tags to clean
1722  * @return array
1723  */
1724 function getDefaultXssTags() {
1725         $tmp = array(
1726         "applet" => "applet",
1727         "base" => "base",
1728         "embed" => "embed",
1729         "form" => "form",
1730         "frame" => "frame",
1731         "frameset" => "frameset",
1732         "iframe" => "iframe",
1733         "import" => "\?import",
1734         "layer" => "layer",
1735         "link" => "link",
1736         "object" => "object",
1737         "script" => "script",
1738         "xmp" => "xmp",
1739         );
1740
1741         $ret = base64_encode(serialize($tmp));
1742
1743         return $ret;
1744 }
1745
1746 /**
1747  * Remove potential xss vectors from strings
1748  * @param string str String to search for XSS attack vectors
1749  * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1750  * @return string
1751  */
1752 function remove_xss($str, $cleanImg=true)
1753 {
1754     $potentials = clean_xss($str, $cleanImg);
1755     if(is_array($potentials) && !empty($potentials)) {
1756         foreach($potentials as $bad) {
1757             $str = str_replace($bad, "", $str);
1758         }
1759     }
1760     return $str;
1761 }
1762
1763 /**
1764  * Detects typical XSS attack patterns
1765  * @param string str String to search for XSS attack vectors
1766  * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1767  * @return array Array of matches, empty on clean string
1768  */
1769 function clean_xss($str, $cleanImg=true) {
1770         global $sugar_config;
1771
1772         if(empty($sugar_config['email_xss']))
1773         $sugar_config['email_xss'] = getDefaultXssTags();
1774
1775         $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1776
1777         // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1778         $jsEvents  = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1779         $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1780         $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1781
1782         $attribute_regex        = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1783         $javascript_regex       = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1784         $imgsrc_regex           = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1785         $css_url                        = '#url\(.*\.\w+\)#';
1786
1787         $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1788
1789         $tagmatches = array();
1790         $matches = array();
1791         preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1792     foreach($tagmatches[1] as $no => $tag) {
1793         if(in_array($tag, $xsstags)) {
1794             // dangerous tag - take out whole
1795             $matches[] = $tagmatches[0][$no];
1796             continue;
1797         }
1798         $attrmatch = array();
1799         preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1800         if(!empty($attrmatch[0])) {
1801             $matches = array_merge($matches, $attrmatch[0]);
1802         }
1803     }
1804
1805         $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1806
1807         if($cleanImg) {
1808                 $matches = array_merge($matches,
1809                 xss_check_pattern($imgsrc_regex, $str)
1810                 );
1811         }
1812
1813         // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1814         preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1815
1816         if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1817                 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1818                         // normalize whitelist
1819                         foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1820                                 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1821                         }
1822
1823                         foreach($cssUrlMatches[0] as $match) {
1824                                 $domain = strtolower(substr(strstr($match, "://"), 3));
1825                                 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1826
1827                                 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1828                                         $matches[] = $match;
1829                                 }
1830                         }
1831                 }
1832         } else {
1833                 $matches = array_merge($matches, $cssUrlMatches[0]);
1834         }
1835
1836         return $matches;
1837 }
1838
1839 /**
1840  * Helper function used by clean_xss() to parse for known-bad vectors
1841  * @param string pattern Regex pattern to use
1842  * @param string str String to parse for badness
1843  * @return array
1844  */
1845 function xss_check_pattern($pattern, $str) {
1846         preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1847         return $matches[1];
1848 }
1849
1850 /**
1851  * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1852  *
1853  * @param string $str
1854  * @param string $filter which corresponds to a regular expression to use; choices are:
1855  *              "STANDARD" ( default )
1856  *              "STANDARDSPACE"
1857  *              "FILE"
1858  *              "NUMBER"
1859  *              "SQL_COLUMN_LIST"
1860  *              "PATH_NO_URL"
1861  *              "SAFED_GET"
1862  *              "UNIFIED_SEARCH"
1863  *              "AUTO_INCREMENT"
1864  *              "ALPHANUM"
1865  * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1866  */
1867 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1868 {
1869         global  $sugar_config;
1870
1871         $filters = Array(
1872         "STANDARD"        => '#[^A-Z0-9\-_\.\@]#i',
1873         "STANDARDSPACE"   => '#[^A-Z0-9\-_\.\@\ ]#i',
1874         "FILE"            => '#[^A-Z0-9\-_\.]#i',
1875         "NUMBER"          => '#[^0-9\-]#i',
1876         "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1877         "PATH_NO_URL"     => '#://#i',
1878         "SAFED_GET"               => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1879         "UNIFIED_SEARCH"        => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1880         "AUTO_INCREMENT"        => '#[^0-9\-,\ ]#i',
1881         "ALPHANUM"        => '#[^A-Z0-9\-]#i',
1882         );
1883
1884         if (preg_match($filters[$filter], $str)) {
1885                 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1886                         $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1887                 }
1888                 if ( $dieOnBadData ) {
1889                         die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1890                 }
1891                 return false;
1892         }
1893         else {
1894                 return $str;
1895         }
1896 }
1897
1898 function clean_special_arguments() {
1899         if(isset($_SERVER['PHP_SELF'])) {
1900                 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1901         }
1902         if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1903         if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1904         if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1905         if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1906         if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1907         if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1908         if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1909         if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1910         if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1911         if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1912         if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1913         if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1914         if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1915         if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1916         if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1917         if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1918         clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1919         clean_superglobals('offset', 'ALPHANUM');
1920         clean_superglobals('return_action');
1921         clean_superglobals('return_module');
1922         return TRUE;
1923 }
1924
1925 /**
1926  * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1927  */
1928 function clean_superglobals($key, $filter = 'STANDARD') {
1929         if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1930         if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1931         if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1932 }
1933
1934 function set_superglobals($key, $val){
1935         $_GET[$key] = $val;
1936         $_POST[$key] = $val;
1937         $_REQUEST[$key] = $val;
1938 }
1939
1940 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1941 function clean_incoming_data() {
1942         global $sugar_config;
1943     global $RAW_REQUEST;
1944
1945     if(get_magic_quotes_gpc()) {
1946         // magic quotes screw up data, we'd have to clean up
1947         $RAW_REQUEST = array_map("cleanup_slashes", $_REQUEST);
1948     } else {
1949         $RAW_REQUEST = $_REQUEST;
1950     }
1951
1952         if (get_magic_quotes_gpc() == 1) {
1953                 $req  = array_map("preprocess_param", $_REQUEST);
1954                 $post = array_map("preprocess_param", $_POST);
1955                 $get  = array_map("preprocess_param", $_GET);
1956         } else {
1957
1958                 $req  = array_map("securexss", $_REQUEST);
1959                 $post = array_map("securexss", $_POST);
1960                 $get  = array_map("securexss", $_GET);
1961         }
1962
1963         // PHP cannot stomp out superglobals reliably
1964         foreach($post as $k => $v) { $_POST[$k] = $v; }
1965         foreach($get  as $k => $v) { $_GET[$k] = $v; }
1966         foreach($req  as $k => $v) {
1967                  $_REQUEST[$k] = $v;
1968                  //ensure the keys are safe as well
1969                  securexsskey($k);
1970         }
1971         // Any additional variables that need to be cleaned should be added here
1972         if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1973         if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1974         if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
1975         if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
1976         if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
1977         if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
1978         if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
1979         if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
1980         if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
1981         if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
1982         if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
1983         if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
1984         if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
1985
1986         if(isset($_REQUEST['lvso'])){
1987                         set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
1988         }
1989         // Clean "offset" and "order_by" parameters in URL
1990         foreach ($_REQUEST as $key => $val) {
1991                 if (str_end($key, "_offset")) {
1992                         clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
1993                         set_superglobals($key, $_REQUEST[$key]);
1994                 }
1995                 elseif (str_end($key, "_ORDER_BY")) {
1996                         clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
1997                         set_superglobals($key, $_REQUEST[$key]);
1998                 }
1999         }
2000
2001
2002         return 0;
2003 }
2004
2005 // Returns TRUE if $str begins with $begin
2006 function str_begin($str, $begin) {
2007         return (substr($str, 0, strlen($begin)) == $begin);
2008 }
2009
2010 // Returns TRUE if $str ends with $end
2011 function str_end($str, $end) {
2012         return (substr($str, strlen($str) - strlen($end)) == $end);
2013 }
2014
2015 function securexss($value) {
2016         if(is_array($value)){
2017         $new = array();
2018         foreach($value as $key=>$val){
2019                 $new[$key] = securexss($val);
2020         }
2021         return $new;
2022     }
2023         static $xss_cleanup=  array("&quot;" => "&#38;", '"' =>'&quot;', "'" =>  '&#039;' , '<' =>'&lt;' , '>'=>'&gt;');
2024         $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2025         $value = preg_replace('/javascript:/i', 'java script:', $value);
2026         return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2027 }
2028
2029 function securexsskey($value, $die=true){
2030         global $sugar_config;
2031         $matches = array();
2032         preg_match('/[\'"<>]/', $value, $matches);
2033         if(!empty($matches)){
2034                 if($die){
2035                         die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2036                 }else{
2037                         unset($_REQUEST[$value]);
2038                         unset($_POST[$value]);
2039                         unset($_GET[$value]);
2040                 }
2041         }
2042 }
2043
2044 function preprocess_param($value){
2045         if(is_string($value)){
2046                 if(get_magic_quotes_gpc() == 1){
2047                         $value = stripslashes($value);
2048                 }
2049
2050                 $value = securexss($value);
2051         }
2052
2053         return $value;
2054 }
2055
2056 function cleanup_slashes($value)
2057 {
2058     if(is_string($value)) return stripslashes($value);
2059     return $value;
2060 }
2061
2062
2063 function set_register_value($category, $name, $value){
2064     return sugar_cache_put("{$category}:{$name}", $value);
2065 }
2066
2067 function get_register_value($category,$name){
2068     return sugar_cache_retrieve("{$category}:{$name}");
2069 }
2070
2071 function clear_register_value($category,$name){
2072     return sugar_cache_clear("{$category}:{$name}");
2073 }
2074 // this function cleans id's when being imported
2075 function convert_id($string)
2076 {
2077         return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2078         create_function(
2079         // single quotes are essential here,
2080         // or alternative escape all $ as \$
2081         '$matches',
2082         'return ord($matches[0]);'
2083          ) ,$string);
2084 }
2085
2086 /**
2087  * @deprecated use SugarTheme::getImage()
2088  */
2089 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt)
2090 {
2091     return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2092 }
2093 /**
2094  * @deprecated use SugarTheme::getImageURL()
2095  */
2096 function getImagePath($image_name)
2097 {
2098     return SugarThemeRegistry::current()->getImageURL($image_name);
2099 }
2100
2101 function getWebPath($relative_path){
2102         //if it has  a :// then it isn't a relative path
2103         if(substr_count($relative_path, '://') > 0) return $relative_path;
2104         if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2105         return $relative_path;
2106 }
2107
2108 function getVersionedPath($path, $additional_attrs='')
2109 {
2110         if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2111         $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2112         if(inDeveloperMode()) {
2113             static $rand;
2114             if(empty($rand)) $rand = mt_rand();
2115             $dev = $rand;
2116         } else {
2117             $dev = '';
2118         }
2119         if(is_array($additional_attrs)) {
2120             $additional_attrs = join("|",$additional_attrs);
2121         }
2122         // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2123         $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2124         // remove / - it confuses some parsers
2125         $str = strtr($str, '/+', '-_');
2126         if(empty($path)) return $str;
2127
2128         return $path . "?v=$str";
2129 }
2130
2131 function getVersionedScript($path, $additional_attrs='')
2132 {
2133     return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2134 }
2135
2136 function getJSPath($relative_path, $additional_attrs='')
2137 {
2138         if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2139         return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2140 }
2141
2142 function getSWFPath($relative_path, $additional_params=''){
2143         $path = $relative_path;
2144         if (!empty($additional_params)){
2145                 $path .= '?' . $additional_params;
2146         }
2147         if (defined('TEMPLATE_URL')){
2148                 $path = TEMPLATE_URL . '/' . $path;
2149         }
2150         return $path;
2151 }
2152
2153
2154
2155
2156
2157 function getSQLDate($date_str)
2158 {
2159         if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2160         {
2161                 if ( strlen($match[2]) == 1)
2162                 {
2163                         $match[2] = "0".$match[2];
2164                 }
2165                 if ( strlen($match[1]) == 1)
2166                 {
2167                         $match[1] = "0".$match[1];
2168                 }
2169                 return "{$match[3]}-{$match[1]}-{$match[2]}";
2170         }
2171         else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2172         {
2173                 if ( strlen($match[2]) == 1)
2174                 {
2175                         $match[2] = "0".$match[2];
2176                 }
2177                 if ( strlen($match[1]) == 1)
2178                 {
2179                         $match[1] = "0".$match[1];
2180                 }
2181                 return "{$match[3]}-{$match[1]}-{$match[2]}";
2182         }
2183         else
2184         {
2185                 return "";
2186         }
2187 }
2188
2189 function clone_history(&$db, $from_id,$to_id, $to_type)
2190 {
2191         global $timedate;
2192         $old_note_id=null;
2193         $old_filename=null;
2194         require_once('include/upload_file.php');
2195         $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2196
2197         $location=array('Email'=>"modules/Emails/Email.php",
2198         'Call'=>"modules/Calls/Call.php",
2199         'Meeting'=>"modules/Meetings/Meeting.php",
2200         'Note'=>"modules/Notes/Note.php",
2201         'Tasks'=>"modules/Tasks/Task.php",
2202         );
2203
2204
2205         foreach($tables as $table=>$bean_class)
2206         {
2207
2208                 if (!class_exists($bean_class))
2209                 {
2210                         require_once($location[$bean_class]);
2211                 }
2212
2213                 $bProcessingNotes=false;
2214                 if ($table=='notes')
2215                 {
2216                         $bProcessingNotes=true;
2217                 }
2218                 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2219                 $results = $db->query($query);
2220                 while($row = $db->fetchByAssoc($results))
2221                 {
2222                         //retrieve existing record.
2223                         $bean= new $bean_class();
2224                         $bean->retrieve($row['id']);
2225                         //process for new instance.
2226                         if ($bProcessingNotes)
2227                         {
2228                                 $old_note_id=$row['id'];
2229                                 $old_filename=$bean->filename;
2230                         }
2231                         $bean->id=null;
2232                         $bean->parent_id=$to_id;
2233                         $bean->parent_type=$to_type;
2234                         if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2235                         {
2236                                 $bean->contact_id=$to_id;
2237                         }
2238                         $bean->update_date_modified = false;
2239             $bean->update_modified_by = false;
2240             if(isset($bean->date_modified))
2241                 $bean->date_modified = $timedate->to_db($bean->date_modified);
2242             if(isset($bean->date_entered))
2243                 $bean->date_entered = $timedate->to_db($bean->date_entered);
2244                         //save
2245                         $new_id=$bean->save();
2246
2247                         //duplicate the file now. for notes.
2248                         if ($bProcessingNotes && !empty($old_filename))
2249                         {
2250                                 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2251                         }
2252                         //reset the values needed for attachment duplication.
2253                         $old_note_id=null;
2254                         $old_filename=null;
2255                 }
2256         }
2257 }
2258
2259 function values_to_keys($array)
2260 {
2261         $new_array = array();
2262         if(!is_array($array))
2263         {
2264                 return $new_array;
2265         }
2266         foreach($array as $arr){
2267                 $new_array[$arr] = $arr;
2268         }
2269         return $new_array;
2270 }
2271
2272 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2273 {
2274         foreach($tables as $table)
2275         {
2276
2277                 if ($table == 'emails_beans') {
2278                         $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2279                 } else {
2280                         $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2281                 }
2282                 $results = $db->query($query);
2283                 while($row = $db->fetchByAssoc($results))
2284                 {
2285                         $query = "INSERT INTO $table ";
2286                         $names = '';
2287                         $values = '';
2288                         $row[$from_column] = $to_id;
2289                         $row['id'] = create_guid();
2290                         if ($table=='emails_beans') {
2291                                 $row['bean_module'] =='Contacts';
2292                         }
2293
2294                         foreach($row as $name=>$value)
2295                         {
2296
2297                                 if(empty($names))
2298                                 {
2299                                         $names .= $name;
2300                                         $values .= "'$value'";
2301                                 } else
2302                                 {
2303                                         $names .= ', '. $name;
2304                                         $values .= ", '$value'";
2305                                 }
2306                         }
2307                         $query .= "($names)     VALUES ($values)";
2308                         $db->query($query);
2309                 }
2310         }
2311 }
2312
2313 function get_unlinked_email_query($type, $bean) {
2314     global $current_user;
2315
2316     $return_array['select']='SELECT emails.id ';
2317     $return_array['from']='FROM emails ';
2318     $return_array['where']="";
2319         $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2320
2321         join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2322         eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2323         where eear.deleted=0 and eear.email_id not in
2324         (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2325         ) derivedemails on derivedemails.email_id = emails.id";
2326     $return_array['join_tables'][0] = '';
2327
2328         if (isset($type) and !empty($type['return_as_array'])) {
2329                 return $return_array;
2330         }
2331
2332         return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2333 } // fn
2334
2335 /**
2336  * Check to see if the number is empty or non-zero
2337  * @param $value
2338  * @return boolean
2339  **/
2340 function number_empty($value)
2341 {
2342         return empty($value) && $value != '0';
2343 }
2344
2345 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2346 {
2347         global $beanFiles;
2348         require_once($beanFiles[$bean_name]);
2349         $focus = new $bean_name();
2350         $user_array = array();
2351
2352     $key = ($bean_name == 'EmailTemplate') ?  $bean_name : $bean_name . $display_columns. $where . $order_by;
2353         $user_array = get_register_value('select_array', $key );
2354         if(!$user_array)
2355         {
2356
2357                 $db = DBManagerFactory::getInstance();
2358
2359                 $temp_result = Array();
2360                 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2361                 $query .= "where ";
2362                 if ( $where != '')
2363                 {
2364                         $query .= $where." AND ";
2365                 }
2366
2367                 $query .=  " {$focus->table_name}.deleted=0";
2368
2369                 if ( $order_by != '')
2370                 {
2371                         $query .= " order by {$focus->table_name}.{$order_by}";
2372                 }
2373
2374                 $GLOBALS['log']->debug("get_user_array query: $query");
2375                 $result = $db->query($query, true, "Error filling in user array: ");
2376
2377                 if ($add_blank==true){
2378                         // Add in a blank row
2379                         if($blank_is_none == true) { // set 'blank row' to "--None--"
2380                                 global $app_strings;
2381                                 $temp_result[''] = $app_strings['LBL_NONE'];
2382                         } else {
2383                                 $temp_result[''] = '';
2384                         }
2385                 }
2386
2387                 // Get the id and the name.
2388                 while($row = $db->fetchByAssoc($result))
2389                 {
2390                         $temp_result[$row['id']] = $row['display'];
2391                 }
2392
2393                 $user_array = $temp_result;
2394                 set_register_value('select_array', $key ,$temp_result);
2395         }
2396
2397         return $user_array;
2398
2399 }
2400 /**
2401  *
2402  *
2403  * @param unknown_type $listArray
2404  */
2405 // function parse_list_modules
2406 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2407 function parse_list_modules(&$listArray)
2408 {
2409         global $modListHeader;
2410         $returnArray = array();
2411
2412         foreach($listArray as $optionName => $optionVal)
2413         {
2414                 if(array_key_exists($optionName, $modListHeader))
2415                 {
2416                         $returnArray[$optionName] = $optionVal;
2417                 }
2418
2419                 // special case for projects
2420                 if(array_key_exists('Project', $modListHeader))
2421                 {
2422                         $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2423                 }
2424         }
2425         $acldenied = ACLController::disabledModuleList($listArray,false);
2426         foreach($acldenied as $denied){
2427                 unset($returnArray[$denied]);
2428         }
2429         asort($returnArray);
2430
2431         return $returnArray;
2432 }
2433
2434 function display_notice($msg = false){
2435         global $error_notice;
2436         //no error notice - lets just display the error to the user
2437         if(!isset($error_notice)){
2438                 echo '<br>'.$msg . '<br>';
2439         }else{
2440                 $error_notice .= $msg . '<br>';
2441         }
2442 }
2443
2444 /* checks if it is a number that atleast has the plus at the beggining
2445  */
2446 function skype_formatted($number){
2447         //kbrill - BUG #15375
2448         if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2449                 return false;
2450         } else {
2451                 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2452         }
2453 //      return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2454 }
2455
2456 function format_skype($number) {
2457     return preg_replace('/[^\+0-9]/','',$number);
2458 }
2459
2460 function insert_charset_header() {
2461         header('Content-Type: text/html; charset=UTF-8');
2462 }
2463
2464 function getCurrentURL()
2465 {
2466         $href = "http:";
2467         if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2468         {
2469                 $href = 'https:';
2470         }
2471
2472         $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2473         return $href;
2474 }
2475
2476 function javascript_escape($str) {
2477         $new_str = '';
2478
2479         for($i = 0; $i < strlen($str); $i++) {
2480
2481                 if(ord(substr($str, $i, 1))==10){
2482                         $new_str .= '\n';
2483                 }elseif(ord(substr($str, $i, 1))==13){
2484                         $new_str .= '\r';
2485                 }
2486                 else {
2487                         $new_str .= $str{$i};
2488                 }
2489         }
2490
2491         $new_str = str_replace("'", "\\'", $new_str);
2492
2493         return $new_str;
2494 }
2495
2496 function js_escape($str, $keep=true){
2497         $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2498
2499         if($keep){
2500                 $str = javascript_escape($str);
2501         }
2502         else {
2503                 $str = str_replace("'", " ", $str);
2504                 $str = str_replace('"', " ", $str);
2505         }
2506
2507         return $str;
2508
2509         //end function js_escape
2510 }
2511
2512 function br2nl($str) {
2513         $regex = "#<[^>]+br.+?>#i";
2514         preg_match_all($regex, $str, $matches);
2515
2516         foreach($matches[0] as $match) {
2517                 $str = str_replace($match, "<br>", $str);
2518         }
2519
2520         $brs = array('<br>','<br/>', '<br />');
2521         $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2522         $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2523         $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2524         $str = str_ireplace($brs, "\n", $str); // to retrieve it
2525
2526         return $str;
2527 }
2528
2529 /**
2530  * Private helper function for displaying the contents of a given variable.
2531  * This function is only intended to be used for SugarCRM internal development.
2532  * The ppd stands for Pre Print Die.
2533  */
2534 function _ppd($mixed)
2535 {
2536 }
2537
2538
2539 /**
2540  * Private helper function for displaying the contents of a given variable in
2541  * the Logger. This function is only intended to be used for SugarCRM internal
2542  * development. The pp stands for Pre Print.
2543  * @param $mixed var to print_r()
2544  * @param $die boolean end script flow
2545  * @param $displayStackTrace also show stack trace
2546  */
2547 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2548         if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2549
2550                 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2551         }
2552
2553
2554         $mix    = print_r($mixed, true); // send print_r() output to $mix
2555         $stack  = debug_backtrace();
2556
2557         $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2558         $GLOBALS['log']->$loglevel($mix);
2559         if($displayStackTrace) {
2560                 foreach($stack as $position) {
2561                         $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2562                 }
2563         }
2564
2565         $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2566         $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2567
2568         if($die) {
2569                 die();
2570         }
2571 }
2572
2573 /**
2574  * private helper function to quickly show the major, direct, field attributes of a given bean.
2575  * The ppf stands for Pre[formatted] Print Focus [object]
2576  * @param object bean The focus bean
2577  */
2578 function _ppf($bean, $die=false) {
2579 }
2580
2581
2582
2583 /**
2584  * Private helper function for displaying the contents of a given variable.
2585  * This function is only intended to be used for SugarCRM internal development.
2586  * The pp stands for Pre Print.
2587  */
2588 function _pp($mixed)
2589 {
2590 }
2591
2592 /**
2593  * Private helper function for displaying the contents of a given variable.
2594  * This function is only intended to be used for SugarCRM internal development.
2595  * The pp stands for Pre Print.
2596  */
2597 function _pstack_trace($mixed=NULL)
2598 {
2599 }
2600
2601 /**
2602  * Private helper function for displaying the contents of a given variable.
2603  * This function is only intended to be used for SugarCRM internal development.
2604  * The pp stands for Pre Print Trace.
2605  */
2606 function _ppt($mixed, $textOnly=false)
2607 {
2608 }
2609
2610 /**
2611  * Private helper function for displaying the contents of a given variable.
2612  * This function is only intended to be used for SugarCRM internal development.
2613  * The pp stands for Pre Print Trace Die.
2614  */
2615 function _pptd($mixed)
2616 {
2617 }
2618
2619 /**
2620  * Private helper function for decoding javascript UTF8
2621  * This function is only intended to be used for SugarCRM internal development.
2622  */
2623 function decodeJavascriptUTF8($str) {
2624 }
2625
2626 /**
2627  * Will check if a given PHP version string is supported (tested on this ver),
2628  * unsupported (results unknown), or invalid (something will break on this
2629  * ver).  Do not pass in any pararameter to default to a check against the
2630  * current environment's PHP version.
2631  *
2632  * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2633  */
2634 function check_php_version($sys_php_version = '') {
2635         $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2636         // versions below $min_considered_php_version considered invalid by default,
2637         // versions equal to or above this ver will be considered depending
2638         // on the rules that follow
2639         $min_considered_php_version = '5.2.1';
2640
2641         // only the supported versions,
2642         // should be mutually exclusive with $invalid_php_versions
2643         $supported_php_versions = array (
2644         '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2645         );
2646
2647         // invalid versions above the $min_considered_php_version,
2648         // should be mutually exclusive with $supported_php_versions
2649
2650         // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2651         $invalid_php_versions = array('5.2.7');
2652
2653         // default unsupported
2654         $retval = 0;
2655
2656         // versions below $min_considered_php_version are invalid
2657         if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2658                 $retval = -1;
2659         }
2660
2661         // supported version check overrides default unsupported
2662         foreach($supported_php_versions as $ver) {
2663                 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2664                         $retval = 1;
2665                         break;
2666                 }
2667         }
2668
2669         // invalid version check overrides default unsupported
2670         foreach($invalid_php_versions as $ver) {
2671                 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2672                         $retval = -1;
2673                         break;
2674                 }
2675         }
2676
2677     //allow a redhat distro to install, regardless of version.  We are assuming the redhat naming convention is followed
2678     //and the php version contains 'rh' characters
2679     if(strpos($sys_php_version, 'rh') !== false) {
2680         $retval = 1;
2681     }
2682
2683         return $retval;
2684 }
2685
2686 /**
2687  * Will check if a given IIS version string is supported (tested on this ver),
2688  * unsupported (results unknown), or invalid (something will break on this
2689  * ver).
2690  *
2691  * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2692  */
2693 function check_iis_version($sys_iis_version = '') {
2694
2695         $server_software = $_SERVER["SERVER_SOFTWARE"];
2696         $iis_version = '';
2697         if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/",  $server_software, $out))
2698             $iis_version = $out[1][0];
2699
2700     $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2701
2702     // versions below $min_considered_iis_version considered invalid by default,
2703     // versions equal to or above this ver will be considered depending
2704     // on the rules that follow
2705     $min_considered_iis_version = '6.0';
2706
2707     // only the supported versions,
2708     // should be mutually exclusive with $invalid_iis_versions
2709     $supported_iis_versions = array ('6.0', '7.0',);
2710     $unsupported_iis_versions = array();
2711     $invalid_iis_versions = array('5.0',);
2712
2713     // default unsupported
2714     $retval = 0;
2715
2716     // versions below $min_considered_iis_version are invalid
2717     if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2718         $retval = -1;
2719     }
2720
2721     // supported version check overrides default unsupported
2722     foreach($supported_iis_versions as $ver) {
2723         if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2724             $retval = 1;
2725             break;
2726         }
2727     }
2728
2729     // unsupported version check overrides default unsupported
2730     foreach($unsupported_iis_versions as $ver) {
2731         if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2732             $retval = 0;
2733             break;
2734         }
2735     }
2736
2737     // invalid version check overrides default unsupported
2738     foreach($invalid_iis_versions as $ver) {
2739         if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2740             $retval = -1;
2741             break;
2742         }
2743     }
2744
2745     return $retval;
2746 }
2747
2748 function pre_login_check(){
2749         global $action, $login_error;
2750         if(!empty($action)&& $action == 'Login'){
2751
2752                 if(!empty($login_error)){
2753                         $login_error = htmlentities($login_error);
2754                         $login_error = str_replace(array("&lt;pre&gt;","&lt;/pre&gt;","\r\n", "\n"), "<br>", $login_error);
2755                         $_SESSION['login_error'] = $login_error;
2756                         echo '<script>
2757                                                 function set_focus() {}
2758                                                 if(document.getElementById("post_error")) {
2759                                                         document.getElementById("post_error").innerHTML="'. $login_error. '";
2760                                                         document.getElementById("cant_login").value=1;
2761                                                         document.getElementById("login_button").disabled = true;
2762                                                         document.getElementById("user_name").disabled = true;
2763                                                         //document.getElementById("user_password").disabled = true;
2764                                                 }
2765                                                 </script>';
2766                 }
2767         }
2768 }
2769
2770
2771
2772 function sugar_cleanup($exit = false) {
2773         static $called = false;
2774         if($called)return;
2775         $called = true;
2776         set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2777         chdir(realpath(dirname(__FILE__) . '/..'));
2778         global $sugar_config;
2779         require_once('include/utils/LogicHook.php');
2780         LogicHook::initialize();
2781         $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2782
2783         //added this check to avoid errors during install.
2784         if (empty($sugar_config['dbconfig'])) {
2785                 if ($exit) exit; else return;
2786         }
2787
2788     if (!class_exists('Tracker', true)) {
2789                 require_once 'modules/Trackers/Tracker.php';
2790         }
2791         Tracker::logPage();
2792         // Now write the cached tracker_queries
2793         if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2794             if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2795                 $GLOBALS['current_user']->savePreferencesToDB();
2796         }
2797
2798         //check to see if this is not an `ajax call AND the user preference error flag is set
2799         if(
2800                 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2801                 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2802                 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2803                 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2804
2805         ){
2806                 global $app_strings;
2807                 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2808                 $err_mess = $app_strings['ERROR_USER_PREFS'];
2809                 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2810                 echo "
2811                 <script>
2812                         ajaxStatus.flashStatus('$err_mess',7000);
2813                 </script>";
2814
2815         }
2816
2817         pre_login_check();
2818         if(class_exists('DBManagerFactory')) {
2819                 $db = DBManagerFactory::getInstance();
2820                 $db->disconnect();
2821                 if($exit) {
2822                         exit;
2823                 }
2824         }
2825 }
2826
2827 register_shutdown_function('sugar_cleanup');
2828
2829
2830 /*
2831  check_logic_hook - checks to see if your custom logic is in the logic file
2832  if not, it will add it. If the file isn't built yet, it will create the file
2833
2834  */
2835 function check_logic_hook_file($module_name, $event, $action_array){
2836         require_once('include/utils/logic_utils.php');
2837         $add_logic = false;
2838
2839         if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2840
2841                 $hook_array = get_hook_array($module_name);
2842
2843                 if(check_existing_element($hook_array, $event, $action_array)==true){
2844                         //the hook at hand is present, so do nothing
2845                 } else {
2846                         $add_logic = true;
2847
2848             $logic_count = 0;
2849             if(!empty($hook_array[$event]))
2850             {
2851                             $logic_count = count($hook_array[$event]);
2852             }
2853
2854                         if($action_array[0]==""){
2855                                 $action_array[0] = $logic_count  + 1;
2856                         }
2857                         $hook_array[$event][] = $action_array;
2858
2859                 }
2860                 //end if the file exists already
2861         } else {
2862                 $add_logic = true;
2863                 if($action_array[0]==""){
2864                         $action_array[0] = 1;
2865                 }
2866                 $hook_array = array();
2867                 $hook_array[$event][] = $action_array;
2868                 //end if else file exists already
2869         }
2870         if($add_logic == true){
2871
2872                 //reorder array by element[0]
2873                 //$hook_array = reorder_array($hook_array, $event);
2874                 //!!!Finish this above TODO
2875
2876                 $new_contents = replace_or_add_logic_type($hook_array);
2877                 write_logic_file($module_name, $new_contents);
2878
2879                 //end if add_element is true
2880         }
2881
2882         //end function check_logic_hook_file
2883 }
2884
2885 function remove_logic_hook($module_name, $event, $action_array) {
2886     require_once('include/utils/logic_utils.php');
2887         $add_logic = false;
2888
2889         if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2890         // The file exists, let's make sure the hook is there
2891                 $hook_array = get_hook_array($module_name);
2892
2893                 if(check_existing_element($hook_array, $event, $action_array)==true){
2894             // The hook is there, time to take it out.
2895
2896             foreach ( $hook_array[$event] as $i => $hook ) {
2897                 // We don't do a full comparison below just in case the filename changes
2898                 if ( $hook[0] == $action_array[0]
2899                      && $hook[1] == $action_array[1]
2900                      && $hook[3] == $action_array[3]
2901                      && $hook[4] == $action_array[4] ) {
2902                     unset($hook_array[$event][$i]);
2903                 }
2904             }
2905
2906             $new_contents = replace_or_add_logic_type($hook_array);
2907             write_logic_file($module_name, $new_contents);
2908
2909         }
2910     }
2911 }
2912
2913 function display_stack_trace($textOnly=false){
2914
2915         $stack  = debug_backtrace();
2916
2917         echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
2918
2919         if(!$textOnly)
2920         echo '<br>';
2921
2922         $first = true;
2923         $out = '';
2924
2925         foreach($stack as $item) {
2926                 $file  = '';
2927                 $class = '';
2928                 $line  = '';
2929                 $function  = '';
2930
2931                 if(isset($item['file']))
2932                 $file = $item['file'];
2933                 if(isset($item['class']))
2934                 $class = $item['class'];
2935                 if(isset($item['line']))
2936                 $line = $item['line'];
2937                 if(isset($item['function']))
2938                 $function = $item['function'];
2939
2940                 if(!$first) {
2941                         if(!$textOnly) {
2942                                 $out .= '<font color="black"><b>';
2943                         }
2944
2945                         $out .= $file;
2946
2947                         if(!$textOnly) {
2948                                 $out .= '</b></font><font color="blue">';
2949                         }
2950
2951                         $out .= "[L:{$line}]";
2952
2953                         if(!$textOnly) {
2954                                 $out .= '</font><font color="red">';
2955                         }
2956
2957                         $out .= "({$class}:{$function})";
2958
2959                         if(!$textOnly) {
2960                                 $out .= '</font><br>';
2961                         } else {
2962                                 $out .= "\n";
2963                         }
2964                 } else {
2965                         $first = false;
2966                 }
2967         }
2968
2969         echo $out;
2970 }
2971
2972 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
2973         $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
2974         $halt_script = true;
2975         switch($errno){
2976                 case 2048: return; //depricated we have lots of these ignore them
2977                 case E_USER_NOTICE:
2978                 case E_NOTICE:
2979                     if ( error_reporting() & E_NOTICE ) {
2980                         $halt_script = false;
2981                         $type = 'Notice';
2982                     }
2983                     else
2984                         return;
2985                         break;
2986                 case E_USER_WARNING:
2987                 case E_COMPILE_WARNING:
2988                 case E_CORE_WARNING:
2989                 case E_WARNING:
2990
2991                         $halt_script = false;
2992                         $type = "Warning";
2993                         break;
2994
2995                 case E_USER_ERROR:
2996                 case E_COMPILE_ERROR:
2997                 case E_CORE_ERROR:
2998                 case E_ERROR:
2999
3000                         $type = "Fatal Error";
3001                         break;
3002
3003                 case E_PARSE:
3004
3005                         $type = "Parse Error";
3006                         break;
3007
3008                 default:
3009                         //don't know what it is might not be so bad
3010                         $halt_script = false;
3011                         $type = "Unknown Error ($errno)";
3012                         break;
3013         }
3014         $error_msg = '<b>'.$type.'</b>:' . $error_msg;
3015         echo $error_msg;
3016         display_stack_trace();
3017         if($halt_script){
3018                 exit -1;
3019         }
3020
3021
3022
3023 }
3024
3025
3026 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3027
3028         set_error_handler('StackTraceErrorHandler');
3029 }
3030 function get_sub_cookies($name){
3031         $cookies = array();
3032         if(isset($_COOKIE[$name])){
3033                 $subs = explode('#', $_COOKIE[$name]);
3034                 foreach($subs as $cookie){
3035                         if(!empty($cookie)){
3036                                 $cookie = explode('=', $cookie);
3037
3038                                 $cookies[$cookie[0]] = $cookie[1];
3039                         }
3040                 }
3041         }
3042         return $cookies;
3043
3044 }
3045
3046
3047 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3048
3049         if(!empty($sub_object_array)){
3050
3051                 foreach($sub_object_array as $sub_object){
3052
3053                         //run_second level is set to true if you need to remove sub-sub components
3054                         if($run_second_level==true){
3055
3056                                 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3057
3058                                 //end if run_second_level is true
3059                         }
3060                         $sub_object->mark_deleted($sub_object->id);
3061                         //end foreach sub component
3062                 }
3063                 //end if this is not empty
3064         }
3065
3066         //end function mark_delete_components
3067 }
3068
3069 /**
3070  * For translating the php.ini memory values into bytes.  e.g. input value of '8M' will return 8388608.
3071  */
3072 function return_bytes($val)
3073 {
3074         $val = trim($val);
3075         $last = strtolower($val{strlen($val)-1});
3076
3077         switch($last)
3078         {
3079                 // The 'G' modifier is available since PHP 5.1.0
3080                 case 'g':
3081                         $val *= 1024;
3082                 case 'm':
3083                         $val *= 1024;
3084                 case 'k':
3085                         $val *= 1024;
3086         }
3087
3088         return $val;
3089 }
3090
3091 /**
3092  * Adds the href HTML tags around any URL in the $string
3093  */
3094 function url2html($string) {
3095         //
3096         $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new"  style="font-weight: normal;">\\1\\2</a>', $string);
3097         return $return_string;
3098 }
3099 // End customization by Julian
3100
3101 /**
3102  * tries to determine whether the Host machine is a Windows machine
3103  */
3104 function is_windows() {
3105     static $is_windows = null;
3106     if (!isset($is_windows)) {
3107         $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3108     }
3109     return $is_windows;
3110 }
3111
3112 /**
3113  * equivalent for windows filesystem for PHP's is_writable()
3114  * @param string file Full path to the file/dir
3115  * @return bool true if writable
3116  */
3117 function is_writable_windows($file) {
3118         if($file{strlen($file)-1}=='/') {
3119                 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3120         }
3121
3122         // the assumption here is that Windows has an inherited permissions scheme
3123         // any file that is a descendant of an unwritable directory will inherit
3124         // that property and will trigger a failure below.
3125         if(is_dir($file)) {
3126                 return true;
3127         }
3128
3129         $file = str_replace("/", '\\', $file);
3130
3131         if(file_exists($file)) {
3132                 if (!($f = @sugar_fopen($file, 'r+')))
3133                 return false;
3134                 fclose($f);
3135                 return true;
3136         }
3137
3138         if(!($f = @sugar_fopen($file, 'w')))
3139         return false;
3140         fclose($f);
3141         unlink($file);
3142         return true;
3143 }
3144
3145
3146 /**
3147  * best guesses Timezone based on webserver's TZ settings
3148  */
3149 function lookupTimezone($userOffset = 0)
3150 {
3151     return TimeDate::guessTimezone($userOffset);
3152 }
3153
3154 function convert_module_to_singular($module_array){
3155         global $beanList;
3156
3157         foreach($module_array as $key => $value){
3158                 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3159
3160                 if($value=="Cases") {
3161                         $module_array[$key] = "Case";
3162                 }
3163                 if($key=="projecttask"){
3164                         $module_array['ProjectTask'] = "Project Task";
3165                         unset($module_array[$key]);
3166                 }
3167         }
3168
3169         return $module_array;
3170
3171         //end function convert_module_to_singular
3172 }
3173
3174 /*
3175  * Given the bean_name which may be plural or singular return the singular
3176  * bean_name. This is important when you need to include files.
3177  */
3178 function get_singular_bean_name($bean_name){
3179         global $beanFiles, $beanList;
3180         if(array_key_exists($bean_name, $beanList)){
3181                 return $beanList[$bean_name];
3182         }
3183         else{
3184                 return $bean_name;
3185         }
3186 }
3187
3188 /*
3189  * Given the potential module name (singular name, renamed module name)
3190  * Return the real internal module name.
3191  */
3192 function get_module_from_singular($singular) {
3193
3194     // find the internal module name for a singular name
3195     if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3196
3197         $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3198
3199         foreach ($singular_modules as $mod_name=>$sin_name) {
3200             if ($singular == $sin_name and $mod_name != $sin_name) {
3201                 return $mod_name;
3202             }
3203         }
3204     }
3205
3206     // find the internal module name for a renamed module
3207     if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3208
3209         $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3210
3211         foreach ($moduleList as $mod_name=>$name) {
3212             if ($singular == $name and $mod_name != $name) {
3213                 return $mod_name;
3214             }
3215         }
3216     }
3217
3218     // if it's not a singular name, nor a renamed name, return the original value
3219     return $singular;
3220 }
3221
3222 function get_label($label_tag, $temp_module_strings){
3223         global $app_strings;
3224         if(!empty($temp_module_strings[$label_tag])){
3225
3226                 $label_name = $temp_module_strings[$label_tag];
3227         } else {
3228                 if(!empty($app_strings[$label_tag])){
3229                         $label_name = $app_strings[$label_tag];
3230                 } else {
3231                         $label_name = $label_tag;
3232                 }
3233         }
3234         return $label_name;
3235
3236         //end function get_label
3237 }
3238
3239
3240 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3241
3242         $rel_list = array();
3243
3244         foreach($focus->relationship_fields as $rel_key => $rel_value){
3245                 if($rel_value == $relationship_name){
3246                         $temp_bean = get_module_info($tar_rel_module);
3247         //              echo $focus->$rel_key;
3248                         $temp_bean->retrieve($focus->$rel_key);
3249                         if($temp_bean->id!=""){
3250
3251                                 $rel_list[] = $temp_bean;
3252                                 return $rel_list;
3253                         }
3254                 }
3255         }
3256
3257         foreach($focus->field_defs as $field_name => $field_def){
3258                 //Check if the relationship_name matches a "relate" field
3259                 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3260                 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3261                 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3262                 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3263                 {
3264                         $temp_bean = get_module_info($tar_rel_module);
3265                 //      echo $focus->$field_def['id_name'];
3266                         $temp_bean->retrieve($focus->$field_def['id_name']);
3267                         if($temp_bean->id!=""){
3268
3269                                 $rel_list[] = $temp_bean;
3270                                 return $rel_list;
3271                         }
3272                 //Check if the relationship_name matches a "link" in a relate field
3273                 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3274                         $temp_bean = get_module_info($tar_rel_module);
3275                 //      echo $focus->$rel_value['id_name'];
3276                         $temp_bean->retrieve($focus->$rel_value['id_name']);
3277                         if($temp_bean->id!=""){
3278
3279                                 $rel_list[] = $temp_bean;
3280                                 return $rel_list;
3281                         }
3282                 }
3283         }
3284
3285         // special case for unlisted parent-type relationships
3286         if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3287                 $temp_bean = get_module_info($tar_rel_module);
3288                 $temp_bean->retrieve($focus->parent_id);
3289                 if($temp_bean->id!=""){
3290                         $rel_list[] = $temp_bean;
3291                         return $rel_list;
3292                 }
3293         }
3294
3295         return $rel_list;
3296
3297         //end function search_filter_rel_info
3298 }
3299
3300 function get_module_info($module_name){
3301         global $beanList;
3302         global $dictionary;
3303
3304         //Get dictionary and focus data for module
3305         $vardef_name = $beanList[$module_name];
3306
3307         if($vardef_name=="aCase"){
3308                 $class_name = "Case";
3309         } else {
3310                 $class_name = $vardef_name;
3311         }
3312
3313         if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3314                 return;
3315         }
3316
3317         include_once('modules/'. $module_name . '/'.$class_name.'.php');
3318
3319         $module_bean = new $vardef_name();
3320         return $module_bean;
3321         //end function get_module_table
3322 }
3323
3324 /**
3325  * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3326  *
3327  * @param string $moduleName
3328  */
3329 function get_valid_bean_name($module_name){
3330         global $beanList;
3331
3332         $vardef_name = $beanList[$module_name];
3333         if($vardef_name=="aCase"){
3334                 $bean_name = "Case";
3335         } else {
3336                 $bean_name = $vardef_name;
3337         }
3338         return $bean_name;
3339 }
3340
3341
3342
3343 function  checkAuthUserStatus(){
3344
3345         //authUserStatus();
3346 }
3347
3348
3349 /**
3350  * This function returns an array of phpinfo() results that can be parsed and
3351  * used to figure out what version we run, what modules are compiled in, etc.
3352  * @param       $level                  int             info level constant (1,2,4,8...64);
3353  * @return      $returnInfo             array   array of info about the PHP environment
3354  * @author      original by "code at adspeed dot com" Fron php.net
3355  * @author      customized for Sugar by Chris N.
3356  */
3357 function getPhpInfo($level=-1) {
3358         /**     Name (constant)         Value   Description
3359                 INFO_GENERAL            1               The configuration line, php.ini location, build date, Web Server, System and more.
3360                 INFO_CREDITS            2               PHP Credits. See also phpcredits().
3361                 INFO_CONFIGURATION      4               Current Local and Master values for PHP directives. See also ini_get().
3362                 INFO_MODULES            8               Loaded modules and their respective settings. See also get_loaded_extensions().
3363                 INFO_ENVIRONMENT        16              Environment Variable information that's also available in $_ENV.
3364                 INFO_VARIABLES          32              Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3365                 INFO_LICENSE            64              PHP License information. See also the license FAQ.
3366                 INFO_ALL                        -1              Shows all of the above. This is the default value.
3367          */
3368         ob_start();
3369         phpinfo($level);
3370         $phpinfo = ob_get_contents();
3371         ob_end_clean();
3372
3373         $phpinfo        = strip_tags($phpinfo,'<h1><h2><th><td>');
3374         $phpinfo        = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3375         $phpinfo        = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3376         $parsedInfo     = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3377         $match          = '';
3378         $version        = '';
3379         $returnInfo     = array();
3380
3381         if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3382                 $returnInfo['PHP Version'] = $version[1];
3383         }
3384
3385
3386         for ($i=1; $i<count($parsedInfo); $i++) {
3387                 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3388                         $vName = trim($match[1]);
3389                         $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3390
3391                         foreach ($parsedInfo2 AS $vOne) {
3392                                 $vPat   = '<info>([^<]+)<\/info>';
3393                                 $vPat3  = "/$vPat\s*$vPat\s*$vPat/";
3394                                 $vPat2  = "/$vPat\s*$vPat/";
3395
3396                                 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3397                                         $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3398                                 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3399                                         $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3400                                 }
3401                         }
3402                 } elseif(true) {
3403
3404                 }
3405         }
3406
3407         return $returnInfo;
3408 }
3409
3410 /**
3411  * This function will take a string that has tokens like {0}, {1} and will replace
3412  * those tokens with the args provided
3413  * @param       $format string to format
3414  * @param       $args args to replace
3415  * @return      $result a formatted string
3416  */
3417 function string_format($format, $args){
3418         $result = $format;
3419
3420     /** Bug47277 fix.
3421      * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3422      * IN () fails and IN ('') works.
3423      */
3424     if (count($args) == 1)
3425     {
3426         reset($args);
3427         $singleArgument = current($args);
3428         if (empty($singleArgument))
3429         {
3430             return str_replace("{0}", "''", $result);
3431         }
3432     }
3433     /* End of fix */
3434
3435         for($i = 0; $i < count($args); $i++){
3436                 $result = str_replace('{'.$i.'}', $args[$i], $result);
3437         }
3438         return $result;
3439 }
3440
3441 /**
3442  * Generate a string for displaying a unique identifier that is composed
3443  * of a system_id and number.  This is use to allow us to generate quote
3444  * numbers using a DB auto-increment key from offline clients and still
3445  * have the number be unique (since it is modified by the system_id.
3446  *
3447  * @param       $num of bean
3448  * @param       $system_id from system
3449  * @return      $result a formatted string
3450  */
3451 function format_number_display($num, $system_id){
3452         global $sugar_config;
3453         if(isset($num) && !empty($num)){
3454                 $num=unformat_number($num);
3455                 if(isset($system_id) && $system_id == 1){
3456                         return sprintf("%d", $num);
3457                 }
3458                 else{
3459                         return sprintf("%d-%d", $num, $system_id);
3460                 }
3461         }
3462 }
3463 function checkLoginUserStatus(){
3464 }
3465
3466 /**
3467  * This function will take a number and system_id and format
3468  * @param       $url URL containing host to append port
3469  * @param       $port the port number - if '' is passed, no change to url
3470  * @return      $resulturl the new URL with the port appended to the host
3471  */
3472 function appendPortToHost($url, $port)
3473 {
3474         $resulturl = $url;
3475
3476         // if no port, don't change the url
3477         if($port != '')
3478         {
3479                 $split = explode("/", $url);
3480                 //check if it starts with http, in case they didn't include that in url
3481                 if(str_begin($url, 'http'))
3482                 {
3483                         //third index ($split[2]) will be the host
3484                         $split[2] .= ":".$port;
3485                 }
3486                 else // otherwise assumed to start with host name
3487                 {
3488                         //first index ($split[0]) will be the host
3489                         $split[0] .= ":".$port;
3490                 }
3491
3492                 $resulturl = implode("/", $split);
3493         }
3494
3495         return $resulturl;
3496 }
3497
3498 /**
3499  * Singleton to return JSON object
3500  * @return      JSON object
3501  */
3502 function getJSONobj() {
3503         static $json = null;
3504         if(!isset($json)) {
3505                 require_once('include/JSON.php');
3506                 $json = new JSON(JSON_LOOSE_TYPE);
3507         }
3508         return $json;
3509 }
3510
3511 require_once('include/utils/db_utils.php');
3512
3513 /**
3514  * Set default php.ini settings for entry points
3515  */
3516 function setPhpIniSettings() {
3517         // zlib module
3518         // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3519         /*
3520     if(function_exists('gzclose') && headers_sent() == false) {
3521                 ini_set('zlib.output_compression', 1);
3522         }
3523         */
3524         // mbstring module
3525         //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3526
3527         /*if(function_exists('mb_strlen')) {
3528                 ini_set('mbstring.func_overload', 7);
3529                 ini_set('mbstring.internal_encoding', 'UTF-8');
3530         }*/
3531
3532
3533         // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3534         // starting with 5.2.0, backtrack_limit breaks JSON decoding
3535         $backtrack_limit = ini_get('pcre.backtrack_limit');
3536         if(!empty($backtrack_limit)) {
3537                 ini_set('pcre.backtrack_limit', '-1');
3538         }
3539 }
3540
3541 /**
3542  * like array_merge() but will handle array elements that are themselves arrays;
3543  * PHP's version just overwrites the element with the new one.
3544  *
3545  * @internal Note that this function deviates from the internal array_merge()
3546  *           functions in that it does does not treat numeric keys differently
3547  *           than string keys.  Additionally, it deviates from
3548  *           array_merge_recursive() by not creating an array when like values
3549  *           found.
3550  *
3551  * @param array gimp the array whose values will be overloaded
3552  * @param array dom the array whose values will pwn the gimp's
3553  * @return array beaten gimp
3554  */
3555 function sugarArrayMerge($gimp, $dom) {
3556         if(is_array($gimp) && is_array($dom)) {
3557                 foreach($dom as $domKey => $domVal) {
3558                         if(array_key_exists($domKey, $gimp)) {
3559                                 if(is_array($domVal)) {
3560                                         $tempArr = array();
3561                     foreach ( $domVal as $domArrKey => $domArrVal )
3562                         $tempArr[$domArrKey] = $domArrVal;
3563                     foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3564                         if ( !array_key_exists($gimpArrKey, $tempArr) )
3565                             $tempArr[$gimpArrKey] = $gimpArrVal;
3566                     $gimp[$domKey] = $tempArr;
3567                                 } else {
3568                                         $gimp[$domKey] = $domVal;
3569                                 }
3570                         } else {
3571                                 $gimp[$domKey] = $domVal;
3572                         }
3573                 }
3574         }
3575     // if the passed value for gimp isn't an array, then return the $dom
3576     elseif(is_array($dom))
3577         return $dom;
3578
3579         return $gimp;
3580 }
3581
3582 /**
3583  * Similiar to sugarArrayMerge except arrays of N depth are merged.
3584  *
3585  * @param array gimp the array whose values will be overloaded
3586  * @param array dom the array whose values will pwn the gimp's
3587  * @return array beaten gimp
3588  */
3589 function sugarArrayMergeRecursive($gimp, $dom) {
3590         if(is_array($gimp) && is_array($dom)) {
3591                 foreach($dom as $domKey => $domVal) {
3592                         if(array_key_exists($domKey, $gimp)) {
3593                                 if(is_array($domVal) && is_array($gimp[$domKey])) {
3594                                         $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3595                                 } else {
3596                                         $gimp[$domKey] = $domVal;
3597                                 }
3598                         } else {
3599                                 $gimp[$domKey] = $domVal;
3600                         }
3601                 }
3602         }
3603     // if the passed value for gimp isn't an array, then return the $dom
3604     elseif(is_array($dom))
3605         return $dom;
3606
3607         return $gimp;
3608 }
3609
3610 /**
3611  * finds the correctly working versions of PHP-JSON
3612  * @return bool True if NOT found or WRONG version
3613  */
3614 function returnPhpJsonStatus() {
3615         if(function_exists('json_encode')) {
3616                 $phpInfo = getPhpInfo(8);
3617         return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3618         }
3619         return true; // not found
3620 }
3621
3622
3623 /**
3624  * getTrackerSubstring
3625  *
3626  * Returns a [number]-char or less string for the Tracker to display in the header
3627  * based on the tracker_max_display_length setting in config.php.  If not set,
3628  * or invalid length, then defaults to 15 for COM editions, 30 for others.
3629  *
3630  * @param string name field for a given Object
3631  * @return string [number]-char formatted string if length of string exceeds the max allowed
3632  */
3633 function getTrackerSubstring($name) {
3634         static $max_tracker_item_length;
3635
3636         //Trim the name
3637         $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3638         $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3639
3640         global $sugar_config;
3641
3642         if(!isset($max_tracker_item_length)) {
3643                 if(isset($sugar_config['tracker_max_display_length'])) {
3644               $max_tracker_item_length = (is_int($sugar_config['tracker_max_display_length']) && $sugar_config['tracker_max_display_length'] > 0 && $sugar_config['tracker_max_display_length'] < 50) ? $sugar_config['tracker_max_display_length'] : 15;
3645                 } else {
3646               $max_tracker_item_length = 15;
3647                 }
3648         }
3649
3650         if($strlen > $max_tracker_item_length) {
3651                 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length, "UTF-8");
3652         } else {
3653                 $chopped = $name;
3654         }
3655
3656         return $chopped;
3657 }
3658 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3659         $where_clauses= array();
3660         $like_char='%';
3661         $table_name=$bean->object_name;
3662         foreach ($field_list[$module] as $field=>$parms) {
3663                 if(isset($values[$field]) && $values[$field] != "") {
3664                         $operator='like';
3665                         if (!empty($parms['operator'])) {
3666                                 $operator=$parms['operator'];
3667                         }
3668                         if (is_array($values[$field])) {
3669                                 $operator='in';
3670                                 $field_value='';
3671                                 foreach ($values[$field] as $key => $val) {
3672                                         if ($val != ' ' and $val != '') {
3673                                                 if (!empty($field_value)) {
3674                                                         $field_value.=',';
3675                                                 }
3676                                                 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3677                                         }
3678                                 }
3679                         } else {
3680                                 $field_value=$GLOBALS['db']->quote($values[$field]);
3681                         }
3682                         //set db_fields array.
3683                         if (!isset($parms['db_field']) )  {
3684                                 $parms['db_field'] = array($field);
3685                         }
3686                         if (isset($parms['my_items']) and $parms['my_items'] == true) {
3687                                 global $current_user;
3688                                 $field_value = $GLOBALS['db']->quote($current_user->id);
3689                                 $operator='=';
3690                         }
3691
3692                         $where='';
3693                         $itr=0;
3694                         if ($field_value != '') {
3695
3696                                 foreach ($parms['db_field'] as $db_field) {
3697                                         if (strstr($db_field,'.')===false) {
3698                                                 $db_field=$bean->table_name.".".$db_field;
3699                                         }
3700                                         if ($GLOBALS['db']->supports('case_sensitive') &&  isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3701                                                 $db_field='upper('.$db_field.")";
3702                                                 $field_value=strtoupper($field_value);
3703                                         }
3704
3705                                         $itr++;
3706                                         if (!empty($where)) {
3707                                                 $where .= " OR ";
3708                                         }
3709                                         switch (strtolower($operator)) {
3710                                                 case 'like' :
3711                                                         $where .=  $db_field . " like '".$field_value.$like_char."'";
3712                                                         break;
3713                                                 case 'in':
3714                                                         $where .=  $db_field . " in (".$field_value.')';
3715                                                         break;
3716                                                 case '=':
3717                                                         $where .=  $db_field . " = '".$field_value ."'";
3718                                                         break;
3719                                         }
3720                                 }
3721                         }
3722                         if (!empty($where)) {
3723                                 if ($itr>1) {
3724                                         array_push($where_clauses, '( '.$where.' )');
3725                                 } else {
3726                                         array_push($where_clauses, $where);
3727                                 }
3728                         }
3729                 }
3730         }
3731         if ($add_custom_fields) {
3732                 require_once('modules/DynamicFields/DynamicField.php');
3733                 $bean->setupCustomFields($module);
3734                 $bean->custom_fields->setWhereClauses($where_clauses);
3735         }
3736         return $where_clauses;
3737 }
3738
3739 function add_quotes($str) {
3740         return "'{$str}'";
3741 }
3742
3743 /**
3744  * This function will rebuild the config file
3745  * @param       $sugar_config
3746  * @param       $sugar_version
3747  * @return      bool true if successful
3748  */
3749 function rebuildConfigFile($sugar_config, $sugar_version) {
3750         // add defaults to missing values of in-memory sugar_config
3751         $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3752         // need to override version with default no matter what
3753         $sugar_config['sugar_version'] = $sugar_version;
3754
3755         ksort( $sugar_config );
3756
3757         if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3758                 return true;
3759         }
3760         else {
3761                 return false;
3762         }
3763 }
3764
3765 /**
3766  * getJavascriptSiteURL
3767  * This function returns a URL for the client javascript calls to access
3768  * the site.  It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3769  * are used to access the site.  Thus, the hostname in the URL returned may
3770  * not always match that of $sugar_config['site_url'].  Basically, the
3771  * assumption is that however the user accessed the website is how they
3772  * will continue to with subsequent javascript requests.  If the variable
3773  * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3774  * @return $site_url The url used to refer to the website
3775  */
3776 function getJavascriptSiteURL() {
3777         global $sugar_config;
3778         if(!empty($_SERVER['HTTP_REFERER'])) {
3779                 $url = parse_url($_SERVER['HTTP_REFERER']);
3780                 $replacement_url = $url['scheme']."://".$url['host'];
3781                 if(!empty($url['port']))
3782                 $replacement_url .= ':'.$url['port'];
3783                 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3784         } else {
3785                 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3786                 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3787                         $site_url = preg_replace('/^http\:/','https:',$site_url);
3788                 }
3789         }
3790         $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=".  $site_url);
3791         return $site_url;
3792 }
3793
3794 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3795 function add_squotes($str) {
3796         return "'" . $str . "'";
3797 }
3798
3799
3800 // recursive function to count the number of levels within an array
3801 function array_depth($array, $depth_count=-1, $depth_array=array()){
3802         $depth_count++;
3803         if (is_array($array)){
3804                 foreach ($array as $key => $value){
3805                         $depth_array[] = array_depth($value, $depth_count);
3806                 }
3807         }
3808         else{
3809                 return $depth_count;
3810         }
3811         foreach ($depth_array as $value){
3812                 $depth_count = $value > $depth_count ? $value : $depth_count;
3813         }
3814         return $depth_count;
3815 }
3816
3817 /**
3818  * Creates a new Group User
3819  * @param string $name Name of Group User
3820  * @return string GUID of new Group User
3821  */
3822 function createGroupUser($name) {
3823
3824
3825         $group = new User();
3826         $group->user_name       = $name;
3827         $group->last_name       = $name;
3828         $group->is_group        = 1;
3829         $group->deleted         = 0;
3830         $group->status          = 'Active'; // cn: bug 6711
3831         $group->setPreference('timezone', TimeDate::userTimezone());
3832         $group->save();
3833
3834         return $group->id;
3835 }
3836
3837 /*
3838  * Helper function to locate an icon file given only a name
3839  * Searches through the various paths for the file
3840  * @param string iconFileName   The filename of the icon
3841  * @return string Relative pathname of the located icon, or '' if not found
3842  */
3843
3844 function _getIcon($iconFileName)
3845 {
3846
3847         $iconName = "icon_{$iconFileName}.gif";
3848     $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3849
3850     //First try un-ucfirst-ing the icon name
3851     if ( empty($iconFound) )
3852                 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
3853         $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3854
3855         //Next try removing the icon prefix
3856     if ( empty($iconFound) )
3857                 $iconName = "{$iconFileName}.gif";
3858                 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3859
3860         if ( empty($iconFound) )
3861                 $iconName = '';
3862
3863         return $iconName;
3864 }
3865 /**
3866  * Function to grab the correct icon image for Studio
3867  * @param string $iconFileName Name of the icon file
3868  * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3869  * @param string $width Width of image
3870  * @param string $height Height of image
3871  * @param string $align Alignment of image
3872  * @param string $alt Alt tag of image
3873  * @return string $string <img> tag with corresponding image
3874  */
3875
3876 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
3877 {
3878         global $app_strings, $theme;
3879
3880     $iconName = _getIcon($iconFileName);
3881         if(empty($iconName)){
3882             $iconName = _getIcon($altFileName);
3883             if (empty($iconName))
3884             {
3885             return $app_strings['LBL_NO_IMAGE'];
3886             }
3887         }
3888         return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
3889 }
3890
3891 /**
3892  * Function to grab the correct icon image for Dashlets Dialog
3893  * @param string $filename Location of the icon file
3894  * @param string $module Name of the module to fall back onto if file does not exist
3895  * @param string $width Width of image
3896  * @param string $height Height of image
3897  * @param string $align Alignment of image
3898  * @param string $alt Alt tag of image
3899  * @return string $string <img> tag with corresponding image
3900  */
3901
3902 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
3903         global $app_strings, $theme;
3904         $iconName = _getIcon($module . "_32");
3905         if (empty($iconName))
3906         {
3907                 $iconName = _getIcon($module);
3908         }
3909         if(empty($iconName)){
3910                 return $app_strings['LBL_NO_IMAGE'];
3911         }
3912         return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
3913 }
3914
3915 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
3916 function html_entity_decode_utf8($string)
3917 {
3918     static $trans_tbl;
3919     // replace numeric entities
3920     //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
3921     $string = preg_replace('~&#x0*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
3922     $string = preg_replace('~&#0*([0-9]+);~e', 'code2utf(\\1)', $string);
3923     // replace literal entities
3924     if (!isset($trans_tbl))
3925     {
3926         $trans_tbl = array();
3927         foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
3928             $trans_tbl[$key] = utf8_encode($val);
3929     }
3930     return strtr($string, $trans_tbl);
3931 }
3932
3933 // Returns the utf string corresponding to the unicode value
3934 function code2utf($num)
3935 {
3936     if ($num < 128) return chr($num);
3937     if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
3938     if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3939     if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3940     return '';
3941 }
3942
3943 function str_split_php4($string, $length = 1) {
3944         $string_length = strlen($string);
3945         $return = array();
3946         $cursor = 0;
3947         if ($length > $string_length) {
3948                 // use the string_length as the string is shorter than the length
3949                 $length = $string_length;
3950         }
3951         for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
3952                 $return[] = substr($string, $cursor, $length);
3953         }
3954         return $return;
3955 }
3956
3957 if (version_compare(phpversion(), '5.0.0', '<')) {
3958         function str_split($string, $length = 1) {
3959                 return str_split_php4($string, $length);
3960         }
3961 }
3962
3963 /*
3964  * @deprecated use DBManagerFactory::isFreeTDS
3965  */
3966 function is_freetds()
3967 {
3968     return DBManagerFactory::isFreeTDS();
3969 }
3970
3971 /**
3972  * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
3973  *
3974  * @todo this won't work completely right until we impliment css compression and combination
3975  *       for now, we'll just include the last css file found.
3976  *
3977  * @return chart.css file to use
3978  */
3979 function chartStyle()
3980 {
3981     return SugarThemeRegistry::current()->getCSSURL('chart.css');
3982 }
3983
3984 /**
3985  * Chart dashlet helper functions that returns the correct XML color file for charts,
3986  * dependent on the current theme.
3987  *
3988  * @return sugarColors.xml to use
3989  */
3990 function chartColors()
3991 {
3992         if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
3993         return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
3994     return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
3995 }
3996 /* End Chart Dashlet helper functions */
3997
3998 /**
3999  * This function is designed to set up the php enviroment
4000  * for AJAX requests.
4001  */
4002
4003 function ajaxInit() {
4004         ini_set('display_errors', 'false');
4005 }
4006
4007 /**
4008  * Returns an absolute path from the given path, determining if it is relative or absolute
4009  *
4010  * @param  string $path
4011  * @return string
4012  */
4013 function getAbsolutePath(
4014     $path,
4015     $currentServer = false
4016     )
4017 {
4018     $path = trim($path);
4019
4020     // try to match absolute paths like \\server\share, /directory or c:\
4021     if ( ( substr($path,0,2) == '\\\\' )
4022             || ( $path[0] == '/' )
4023             || preg_match('/^[A-z]:/i',$path)
4024             || $currentServer )
4025         return $path;
4026
4027     return getcwd().'/'.$path;
4028 }
4029
4030 /**
4031  * Returns the bean object of the given module
4032  *
4033  * @deprecated use SugarModule::loadBean() instead
4034  * @param  string $module
4035  * @return object
4036  */
4037 function loadBean(
4038     $module
4039     )
4040 {
4041     return SugarModule::get($module)->loadBean();
4042 }
4043
4044
4045 /**
4046  * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4047  */
4048 function isTouchScreen()
4049 {
4050     $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4051
4052     // first check if we have forced use of the touch enhanced interface
4053     if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4054         return true;
4055     }
4056
4057     // next check if we should use the touch interface with our device
4058     if ( strpos($ua, 'ipad') !== false ) {
4059         return true;
4060     }
4061
4062     return false;
4063 }
4064
4065 /**
4066  * Returns the shortcut keys to access the shortcut links.  Shortcut
4067  * keys vary depending on browser versions and operating systems.
4068  * @return String value of the shortcut keys
4069  */
4070 function get_alt_hot_key() {
4071         $ua = '';
4072     if ( isset($_SERVER['HTTP_USER_AGENT']) )
4073         $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4074         $isMac = strpos($ua, 'mac') !== false;
4075         $isLinux = strpos($ua, 'linux') !== false;
4076
4077         if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4078            if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4079                   return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4080            }
4081         }
4082         return $isMac ? 'Ctrl+' : 'Alt+';
4083 }
4084
4085 function can_start_session(){
4086         if(!empty($_GET['PHPSESSID'])) {
4087            return true;
4088         }
4089         $session_id = session_id();
4090         return empty($session_id) ? true : false;
4091 }
4092
4093 function load_link_class($properties){
4094         $class = 'Link2';
4095         if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4096         require_once($properties['link_file']);
4097         $class = $properties['link_class'];
4098     }
4099     return $class;
4100 }
4101
4102
4103 function inDeveloperMode()
4104 {
4105     return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4106 }
4107
4108 /**
4109  * Filter the protocol list for inbound email accounts.
4110  *
4111  * @param array $protocol
4112  */
4113 function filterInboundEmailPopSelection($protocol)
4114 {
4115     if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4116     {
4117         if( isset($protocol['pop3']) )
4118                         unset($protocol['pop3']);
4119     }
4120     else
4121         $protocol['pop3'] = 'POP3';
4122
4123     return $protocol;
4124 }
4125
4126 /**
4127  * The function is used because currently we are not supporting mbstring.func_overload
4128  * For some user using mssql without FreeTDS, they may store multibyte charaters in varchar using latin_general collation. It cannot store so many mutilbyte characters, so we need to use strlen.
4129  * The varchar in MySQL, Orcale, and nvarchar in FreeTDS, we can store $length mutilbyte charaters in it. we need mb_substr to keep more info.
4130 * @returns the substred strings.
4131  */
4132 function sugar_substr($string, $length, $charset='UTF-8')
4133 {
4134     if(mb_strlen($string,$charset) > $length) {
4135         $string = trim(mb_substr(trim($string),0,$length,$charset));
4136     }
4137     return $string;
4138 }
4139
4140 /**
4141  * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4142  * This will work even without setting the mbstring.*encoding
4143  */
4144 function sugar_ucfirst($string, $charset='UTF-8') {
4145     return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4146 }
4147
4148
4149 /**
4150  *
4151  */
4152 function unencodeMultienum($string) {
4153         if (is_array($string))
4154         {
4155            return $string;
4156         }
4157         if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4158           $string = substr(substr($string, 1), 0, strlen($string) -2);
4159         }
4160
4161         return explode('^,^', $string);
4162 }
4163
4164 function encodeMultienumValue($arr) {
4165     if (!is_array($arr))
4166         return $arr;
4167
4168     if (empty($arr))
4169         return "";
4170
4171         $string = "^" . implode('^,^', $arr) . "^";
4172
4173     return $string;
4174 }
4175
4176 /**
4177  * create_export_query is used for export and massupdate
4178  * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4179  * This function will correct the where clause and output necessary join condition for them
4180  * @param $module: the module name
4181  * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4182  * @param $where: where clauses
4183  * @return $ret_array['where']: corrected where clause
4184  * @return $ret_array['join']: extra join condition
4185  */
4186 function create_export_query_relate_link_patch($module, $searchFields, $where){
4187         if(file_exists('modules/'.$module.'/SearchForm.html')){
4188                 $ret_array['where'] = $where;
4189                 return $ret_array;
4190         }
4191         $seed = loadBean($module);
4192     foreach($seed->field_defs as $name=>$field)
4193         {
4194
4195                 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4196                         $seed->load_relationship($field['link']);
4197                         $params = array();
4198                         if(empty($join_type))
4199                         {
4200                                 $params['join_type'] = ' LEFT JOIN ';
4201                         }
4202                         else
4203                         {
4204                                 $params['join_type'] = $join_type;
4205                         }
4206                         if(isset($data['join_name']))
4207                         {
4208                                 $params['join_table_alias'] = $field['join_name'];
4209                         }
4210                         else
4211                         {
4212                                 $params['join_table_alias']     = 'join_'.$field['name'];
4213
4214                         }
4215                         if(isset($data['join_link_name']))
4216                         {
4217                                 $params['join_table_link_alias'] = $field['join_link_name'];
4218                         }
4219                         else
4220                         {
4221                                 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4222                         }
4223                         $join = $seed->$field['link']->getJoin($params, true);
4224                         $join_table_alias = 'join_'.$field['name'];
4225                         if(isset($field['db_concat_fields'])){
4226                                 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4227                                 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4228                         }else{
4229                                 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4230                         }
4231                 }
4232         }
4233         $ret_array = array('where'=>$where, 'join'=>$join['join']);
4234         return $ret_array;
4235 }
4236
4237 /**
4238   * We need to clear all the js cache files, including the js language files  in serval places in MB. So I extract them into a util function here.
4239   * @Depends on QuickRepairAndRebuild.php
4240   * @Relate bug 30642  ,23177
4241   */
4242 function clearAllJsAndJsLangFilesWithoutOutput(){
4243                 global $current_language , $mod_strings;
4244                 $MBmodStrings = $mod_strings;
4245         $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4246         include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4247         $repair = new RepairAndClear();
4248         $repair->module_list = array();
4249                 $repair->show_output = false;
4250                 $repair->clearJsLangFiles();
4251                 $repair->clearJsFiles();
4252                 $mod_strings = $MBmodStrings;
4253 }
4254
4255 /**
4256  * This function will allow you to get a variable value from query string
4257  */
4258 function getVariableFromQueryString($variable, $string){
4259         $matches = array();
4260         $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4261         if($number){
4262                 return $matches[1];
4263         }
4264         else{
4265                 return false;
4266         }
4267 }
4268
4269 /**
4270  * should_hide_iframes
4271  * This is a helper method to determine whether or not to show iframes (My Sites) related
4272  * information in the application.
4273  *
4274  * @return boolean flag indicating whether or not iframes module should be hidden
4275  */
4276 function should_hide_iframes() {
4277    //Remove the MySites module
4278    if(file_exists('modules/iFrames/iFrame.php')) {
4279         if(!class_exists("iFrame")) {
4280                 require_once('modules/iFrames/iFrame.php');
4281         }
4282         return false;
4283    }
4284    return true;
4285 }
4286
4287 /**
4288  * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4289  *
4290  * @param string $version
4291  * @return string RC, BETA, GA
4292  */
4293 function getVersionStatus($version){
4294         if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4295                 return strtoupper($matches[1]);
4296         }else{
4297                 return 'GA';
4298         }
4299 }
4300
4301 /**
4302  * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4303  * 5.5.1RC1 then return 5.5.1
4304  *
4305  * @param string $version
4306  * @return version
4307  */
4308 function getMajorMinorVersion($version){
4309         if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4310                 $version = $matches2[1];
4311                 $arr = explode('.', $version);
4312                 if(count($arr) > 2){
4313                         if($arr[2] == '0'){
4314                                 $version = substr($version, 0, 3);
4315                         }
4316                 }
4317         }
4318         return $version;
4319 }
4320
4321 /**
4322  * Return string composed of seconds & microseconds of current time, without dots
4323  * @return string
4324  */
4325 function sugar_microtime()
4326 {
4327         $now = explode(' ', microtime());
4328         $unique_id = $now[1].str_replace('.', '', $now[0]);
4329         return $unique_id;
4330 }
4331
4332 /**
4333  * Extract urls from a piece of text
4334  * @param  $string
4335  * @return array of urls found in $string
4336  */
4337 function getUrls($string)
4338 {
4339         $lines = explode("<br>", trim($string));
4340         $urls = array();
4341         foreach($lines as $line){
4342         $regex = '/http?\:\/\/[^\" ]+/i';
4343         preg_match_all($regex, $line, $matches);
4344         foreach($matches[0] as $match){
4345                 $urls[] = $match;
4346         }
4347         }
4348     return $urls;
4349 }
4350
4351
4352 /**
4353  * Sanitize image file from hostile content
4354  * @param string $path Image file
4355  * @param bool $jpeg  Accept only JPEGs?
4356  */
4357 function verify_image_file($path, $jpeg = false)
4358 {
4359         if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4360         $img = imagecreatefromstring(file_get_contents($path));
4361         if(!$img) {
4362             return false;
4363         }
4364         $img_size = getimagesize($path);
4365                 $filetype = $img_size['mime'];
4366                 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4367         if($filetype == "image/jpeg" || $jpeg) {
4368             ob_start();
4369             imagejpeg($img);
4370             $image = ob_get_clean();
4371             // not writing directly because imagejpeg does not work with streams
4372             if(file_put_contents($path, $image)) {
4373                 return true;
4374             }
4375         } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4376                 imagealphablending($img, true);
4377                 imagesavealpha($img, true);
4378                 ob_start();
4379             imagepng($img);
4380             $image = ob_get_clean();
4381             if(file_put_contents($path, $image)) {
4382                 return true;
4383             }
4384         } else {
4385                 return false;
4386         }
4387         } else {
4388             // check image manually
4389             $fp = fopen($path, "r");
4390             if(!$fp) return false;
4391             $data = fread($fp, 4096);
4392             fclose($fp);
4393             if(preg_match("/<(html|!doctype|script|body|head|plaintext|table|img |pre(>| )|frameset|iframe|object|link|base|style|font|applet|meta|center|form|isindex)/i",
4394                  $data, $m)) {
4395                 $GLOBALS['log']->info("Found {$m[0]} in $path, not allowing upload");
4396                 return false;
4397             }
4398             return true;
4399         }
4400         return false;
4401 }
4402
4403 /**
4404  * Verify uploaded image
4405  * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4406  * @param string $path  Image path
4407  * @param bool $jpeg_only  Accept only JPEGs?
4408  */
4409 function verify_uploaded_image($path, $jpeg_only = false)
4410 {
4411     $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4412     if(!$jpeg_only) {
4413         $supportedExtensions['png'] = 'image/png';
4414     }
4415
4416     if(!file_exists($path) || !is_file($path)) {
4417             return false;
4418         }
4419
4420         $img_size = getimagesize($path);
4421         $filetype = $img_size['mime'];
4422         $ext = end(explode(".", $path));
4423         if(substr_count('..', $path) > 0 || ($ext !== $path && !in_array(strtolower($ext), array_keys($supportedExtensions))) ||
4424             !in_array($filetype, array_values($supportedExtensions))) {
4425                 return false;
4426         }
4427     return verify_image_file($path, $jpeg_only);
4428 }
4429
4430 function cmp_beans($a, $b)
4431 {
4432     global $sugar_web_service_order_by;
4433     //If the order_by field is not valid, return 0;
4434     if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4435         return 0;
4436     }
4437     if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4438         || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4439     {
4440         return 0;
4441     }
4442     if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4443     {
4444         return -1;
4445     } else {
4446         return 1;
4447     }
4448 }
4449
4450 function order_beans($beans, $field_name)
4451 {
4452     //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4453     global $sugar_web_service_order_by;
4454     $sugar_web_service_order_by = $field_name;
4455     usort($beans, "cmp_beans");
4456     return $beans;
4457 }
4458
4459 //check to see if custom utils exists
4460 if(file_exists('custom/include/custom_utils.php')){
4461         include_once('custom/include/custom_utils.php');
4462 }
4463
4464 //check to see if custom utils exists in Extension framework
4465 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4466     include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4467 }
4468 /**
4469  * @param $input - the input string to sanitize
4470  * @param int $quotes - use quotes
4471  * @param string $charset - the default charset
4472  * @param bool $remove - strip tags or not
4473  * @return string - the sanitized string
4474  */
4475 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4476 {
4477     return htmlentities($input, $quotes, $charset);
4478 }
4479
4480
4481 /**
4482  * utf8_recursive_encode
4483  *
4484  * This function walks through an Array and recursively calls utf8_encode on the
4485  * values of each of the elements.
4486  *
4487  * @param $data Array of data to encode
4488  * @return utf8 encoded Array data
4489  */
4490 function utf8_recursive_encode($data)
4491 {
4492     $result = array();
4493     foreach($data as $key=>$val) {
4494         if(is_array($val)) {
4495            $result[$key] = utf8_recursive_encode($val);
4496         } else {
4497            $result[$key] = utf8_encode($val);
4498         }
4499     }
4500     return $result;
4501 }
4502
4503 /**
4504  * get_language_header
4505  *
4506  * This is a utility function for 508 Compliance.  It returns the lang=[Current Language] text string used
4507  * inside the <html> tag.  If no current language is specified, it defaults to lang='en'.
4508  *
4509  * @return String The lang=[Current Language] markup to insert into the <html> tag
4510  */
4511 function get_language_header()
4512 {
4513     return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
4514 }
4515
4516
4517 /**
4518  * get_custom_file_if_exists
4519  *
4520  * This function handles the repetitive code we have where we first check if a file exists in the
4521  * custom directory to determine whether we should load it, require it, include it, etc.  This function returns the
4522  * path of the custom file if it exists.  It basically checks if custom/{$file} exists and returns this path if so;
4523  * otherwise it return $file
4524  *
4525  * @param $file String of filename to check
4526  * @return $file String of filename including custom directory if found
4527  */
4528 function get_custom_file_if_exists($file)
4529 {
4530     return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
4531 }