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