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