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