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