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