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