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