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