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