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