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