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