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