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