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