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