]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/utils.php
Release 6.5.0
[Github/sugarcrm.git] / include / utils.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM Community Edition is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-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) && is_array($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         if ($mod == "")
1680         echo "Language is <pre>" . $mod_strings . "</pre>";
1681
1682         }else{
1683                 global $mod_strings;
1684         }
1685
1686         $returnValue = '';
1687         global $app_strings, $app_list_strings;
1688
1689     if (isset($mod_strings[$string]))
1690         $returnValue = $mod_strings[$string];
1691     else if (isset($app_strings[$string]))
1692         $returnValue = $app_strings[$string];
1693     else if (isset($app_list_strings[$string]))
1694         $returnValue = $app_list_strings[$string];
1695     else if (isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1696         $returnValue = $app_list_strings['moduleList'][$string];
1697
1698
1699         //$test_end = microtime();
1700         //
1701         //    $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1702         //
1703         //    echo("translate results:");
1704         //    $total_time = 0;
1705         //    $total_strings = 0;
1706         //    foreach($mod_strings_results as $key=>$value)
1707         //    {
1708         //        echo("Module $key \t\t time $value \t\t<br>");
1709         //        $total_time += $value;
1710         //    }
1711         //
1712         //    echo("Total time: $total_time<br>");
1713
1714
1715
1716         if(empty($returnValue)){
1717                 return $string;
1718         }
1719
1720     // Bug 48996 - Custom enums with '0' value were not returning because of empty check
1721     // Added a numeric 0 checker to the conditional to allow 0 value indexed to pass
1722         if(is_array($returnValue) && (!empty($selectedValue) || (is_numeric($selectedValue) && $selectedValue == 0))  && isset($returnValue[$selectedValue]) ){
1723                 return $returnValue[$selectedValue];
1724         }
1725
1726         return $returnValue;
1727 }
1728
1729 function unTranslateNum($num) {
1730         static $dec_sep;
1731         static $num_grp_sep;
1732         global $current_user, $sugar_config;
1733
1734         if($dec_sep == null) {
1735             $user_dec_sep = $current_user->getPreference('dec_sep');
1736             $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1737         }
1738         if($num_grp_sep == null) {
1739             $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1740             $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1741         }
1742
1743         $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1744         $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1745         return $num;
1746
1747 }
1748
1749 function add_http($url) {
1750         if(!preg_match("@://@i", $url)) {
1751                 $scheme = "http";
1752                 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1753                         $scheme = 'https';
1754                 }
1755
1756                 return "{$scheme}://{$url}";
1757         }
1758
1759         return $url;
1760 }
1761
1762 /**
1763  * returns a default array of XSS tags to clean
1764  * @return array
1765  */
1766 function getDefaultXssTags() {
1767         $tmp = array(
1768         "applet" => "applet",
1769         "base" => "base",
1770         "embed" => "embed",
1771         "form" => "form",
1772         "frame" => "frame",
1773         "frameset" => "frameset",
1774         "iframe" => "iframe",
1775         "import" => "\?import",
1776         "layer" => "layer",
1777         "link" => "link",
1778         "object" => "object",
1779         "script" => "script",
1780         "xmp" => "xmp",
1781         );
1782
1783         $ret = base64_encode(serialize($tmp));
1784
1785         return $ret;
1786 }
1787
1788 /**
1789  * Remove potential xss vectors from strings
1790  * @param string str String to search for XSS attack vectors
1791  * @deprecated
1792  * @return string
1793  */
1794 function remove_xss($str)
1795 {
1796     return SugarCleaner::cleanHtml($str, false);
1797 }
1798
1799 /**
1800  * Detects typical XSS attack patterns
1801  * @deprecated
1802  * @param string str String to search for XSS attack vectors
1803  * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1804  * @return array Array of matches, empty on clean string
1805  */
1806 function clean_xss($str, $cleanImg=true) {
1807         global $sugar_config;
1808
1809         if(empty($sugar_config['email_xss']))
1810         $sugar_config['email_xss'] = getDefaultXssTags();
1811
1812         $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1813
1814         // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1815         $jsEvents  = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1816         $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1817         $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1818
1819         $attribute_regex        = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1820         $javascript_regex       = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1821         $imgsrc_regex           = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1822         $css_url                        = '#url\(.*\.\w+\)#';
1823
1824         $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1825
1826         $tagmatches = array();
1827         $matches = array();
1828         preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1829     foreach($tagmatches[1] as $no => $tag) {
1830         if(in_array($tag, $xsstags)) {
1831             // dangerous tag - take out whole
1832             $matches[] = $tagmatches[0][$no];
1833             continue;
1834         }
1835         $attrmatch = array();
1836         preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1837         if(!empty($attrmatch[0])) {
1838             $matches = array_merge($matches, $attrmatch[0]);
1839         }
1840     }
1841
1842         $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1843
1844         if($cleanImg) {
1845                 $matches = array_merge($matches,
1846                 xss_check_pattern($imgsrc_regex, $str)
1847                 );
1848         }
1849
1850         // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1851         preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1852
1853         if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1854                 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1855                         // normalize whitelist
1856                         foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1857                                 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1858                         }
1859
1860                         foreach($cssUrlMatches[0] as $match) {
1861                                 $domain = strtolower(substr(strstr($match, "://"), 3));
1862                                 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1863
1864                                 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1865                                         $matches[] = $match;
1866                                 }
1867                         }
1868                 }
1869         } else {
1870                 $matches = array_merge($matches, $cssUrlMatches[0]);
1871         }
1872
1873         return $matches;
1874 }
1875
1876 /**
1877  * Helper function used by clean_xss() to parse for known-bad vectors
1878  * @param string pattern Regex pattern to use
1879  * @param string str String to parse for badness
1880  * @return array
1881  */
1882 function xss_check_pattern($pattern, $str) {
1883         preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1884         return $matches[1];
1885 }
1886
1887 /**
1888  * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1889  *
1890  * @param string $str
1891  * @param string $filter which corresponds to a regular expression to use; choices are:
1892  *              "STANDARD" ( default )
1893  *              "STANDARDSPACE"
1894  *              "FILE"
1895  *              "NUMBER"
1896  *              "SQL_COLUMN_LIST"
1897  *              "PATH_NO_URL"
1898  *              "SAFED_GET"
1899  *              "UNIFIED_SEARCH"
1900  *              "AUTO_INCREMENT"
1901  *              "ALPHANUM"
1902  * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1903  */
1904 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1905 {
1906         global  $sugar_config;
1907
1908         $filters = Array(
1909         "STANDARD"        => '#[^A-Z0-9\-_\.\@]#i',
1910         "STANDARDSPACE"   => '#[^A-Z0-9\-_\.\@\ ]#i',
1911         "FILE"            => '#[^A-Z0-9\-_\.]#i',
1912         "NUMBER"          => '#[^0-9\-]#i',
1913         "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1914         "PATH_NO_URL"     => '#://#i',
1915         "SAFED_GET"               => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
1916         "UNIFIED_SEARCH"        => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1917         "AUTO_INCREMENT"        => '#[^0-9\-,\ ]#i',
1918         "ALPHANUM"        => '#[^A-Z0-9\-]#i',
1919         );
1920
1921         if (preg_match($filters[$filter], $str)) {
1922                 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1923                         $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
1924                 }
1925                 if ( $dieOnBadData ) {
1926                         die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1927                 }
1928                 return false;
1929         }
1930         else {
1931                 return $str;
1932         }
1933 }
1934
1935 function clean_special_arguments() {
1936         if(isset($_SERVER['PHP_SELF'])) {
1937                 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1938         }
1939         if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1940         if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1941         if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1942         if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1943         if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1944         if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1945         if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1946         if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1947         if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1948         if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1949         if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1950         if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1951         if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1952         if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1953         if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1954         if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1955         clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1956         clean_superglobals('offset', 'ALPHANUM');
1957         clean_superglobals('return_action');
1958         clean_superglobals('return_module');
1959         return TRUE;
1960 }
1961
1962 /**
1963  * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1964  */
1965 function clean_superglobals($key, $filter = 'STANDARD') {
1966         if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1967         if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1968         if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1969 }
1970
1971 function set_superglobals($key, $val){
1972         $_GET[$key] = $val;
1973         $_POST[$key] = $val;
1974         $_REQUEST[$key] = $val;
1975 }
1976
1977 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1978 function clean_incoming_data() {
1979         global $sugar_config;
1980     global $RAW_REQUEST;
1981
1982     if(get_magic_quotes_gpc()) {
1983         // magic quotes screw up data, we'd have to clean up
1984         $RAW_REQUEST = array_map("cleanup_slashes", $_REQUEST);
1985     } else {
1986         $RAW_REQUEST = $_REQUEST;
1987     }
1988
1989         if (get_magic_quotes_gpc() == 1) {
1990                 $req  = array_map("preprocess_param", $_REQUEST);
1991                 $post = array_map("preprocess_param", $_POST);
1992                 $get  = array_map("preprocess_param", $_GET);
1993         } else {
1994
1995                 $req  = array_map("securexss", $_REQUEST);
1996                 $post = array_map("securexss", $_POST);
1997                 $get  = array_map("securexss", $_GET);
1998         }
1999
2000         // PHP cannot stomp out superglobals reliably
2001         foreach($post as $k => $v) { $_POST[$k] = $v; }
2002         foreach($get  as $k => $v) { $_GET[$k] = $v; }
2003         foreach($req  as $k => $v) {
2004                  $_REQUEST[$k] = $v;
2005
2006             //ensure the keys are safe as well.  If mbstring encoding translation is on, the post keys don't
2007         //get translated, so scrub the data but don't die
2008             if(ini_get('mbstring.encoding_translation')==='1'){
2009             securexsskey($k,false);
2010         }else{
2011                     securexsskey($k,true);
2012         }
2013
2014         }
2015         // Any additional variables that need to be cleaned should be added here
2016         if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
2017         if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
2018         if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
2019         if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
2020         if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
2021         if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
2022         if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
2023         if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
2024         if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
2025         if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
2026         if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
2027         if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
2028         if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
2029
2030         if(isset($_REQUEST['lvso'])){
2031                         set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
2032         }
2033         // Clean "offset" and "order_by" parameters in URL
2034         foreach ($_REQUEST as $key => $val) {
2035                 if (str_end($key, "_offset")) {
2036                         clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
2037                         set_superglobals($key, $_REQUEST[$key]);
2038                 }
2039                 elseif (str_end($key, "_ORDER_BY")) {
2040                         clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
2041                         set_superglobals($key, $_REQUEST[$key]);
2042                 }
2043         }
2044
2045
2046         return 0;
2047 }
2048
2049 // Returns TRUE if $str begins with $begin
2050 function str_begin($str, $begin) {
2051         return (substr($str, 0, strlen($begin)) == $begin);
2052 }
2053
2054 // Returns TRUE if $str ends with $end
2055 function str_end($str, $end) {
2056         return (substr($str, strlen($str) - strlen($end)) == $end);
2057 }
2058
2059 function securexss($value) {
2060         if(is_array($value)){
2061         $new = array();
2062         foreach($value as $key=>$val){
2063                 $new[$key] = securexss($val);
2064         }
2065         return $new;
2066     }
2067         static $xss_cleanup=  array("&quot;" => "&#38;", '"' =>'&quot;', "'" =>  '&#039;' , '<' =>'&lt;' , '>'=>'&gt;');
2068         $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2069         $value = preg_replace('/javascript:/i', 'java script:', $value);
2070         return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2071 }
2072
2073 function securexsskey($value, $die=true){
2074         global $sugar_config;
2075         $matches = array();
2076         preg_match('/[\'"<>]/', $value, $matches);
2077         if(!empty($matches)){
2078                 if($die){
2079                         die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2080                 }else{
2081                         unset($_REQUEST[$value]);
2082                         unset($_POST[$value]);
2083                         unset($_GET[$value]);
2084                 }
2085         }
2086 }
2087
2088 function preprocess_param($value){
2089         if(is_string($value)){
2090                 if(get_magic_quotes_gpc() == 1){
2091                         $value = stripslashes($value);
2092                 }
2093
2094                 $value = securexss($value);
2095         }
2096
2097         return $value;
2098 }
2099
2100 function cleanup_slashes($value)
2101 {
2102     if(is_string($value)) return stripslashes($value);
2103     return $value;
2104 }
2105
2106
2107 function set_register_value($category, $name, $value){
2108     return sugar_cache_put("{$category}:{$name}", $value);
2109 }
2110
2111 function get_register_value($category,$name){
2112     return sugar_cache_retrieve("{$category}:{$name}");
2113 }
2114
2115 function clear_register_value($category,$name){
2116     return sugar_cache_clear("{$category}:{$name}");
2117 }
2118 // this function cleans id's when being imported
2119 function convert_id($string)
2120 {
2121         return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2122         create_function(
2123         // single quotes are essential here,
2124         // or alternative escape all $ as \$
2125         '$matches',
2126         'return ord($matches[0]);'
2127          ) ,$string);
2128 }
2129
2130 /**
2131  * @deprecated use SugarTheme::getImage()
2132  */
2133 function get_image($image,$other_attributes,$width="",$height="",$ext='.gif',$alt="")
2134 {
2135     return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt );
2136 }
2137 /**
2138  * @deprecated use SugarTheme::getImageURL()
2139  */
2140 function getImagePath($image_name)
2141 {
2142     return SugarThemeRegistry::current()->getImageURL($image_name);
2143 }
2144
2145 function getWebPath($relative_path){
2146         //if it has  a :// then it isn't a relative path
2147         if(substr_count($relative_path, '://') > 0) return $relative_path;
2148         if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2149         return $relative_path;
2150 }
2151
2152 function getVersionedPath($path, $additional_attrs='')
2153 {
2154         if(empty($GLOBALS['sugar_config']['js_custom_version'])) $GLOBALS['sugar_config']['js_custom_version'] = 1;
2155         $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2156         if(inDeveloperMode()) {
2157             static $rand;
2158             if(empty($rand)) $rand = mt_rand();
2159             $dev = $rand;
2160         } else {
2161             $dev = '';
2162         }
2163         if(is_array($additional_attrs)) {
2164             $additional_attrs = join("|",$additional_attrs);
2165         }
2166         // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2167         $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2168         // remove / - it confuses some parsers
2169         $str = strtr($str, '/+', '-_');
2170         if(empty($path)) return $str;
2171
2172         return $path . "?v=$str";
2173 }
2174
2175 function getVersionedScript($path, $additional_attrs='')
2176 {
2177     return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2178 }
2179
2180 function getJSPath($relative_path, $additional_attrs='')
2181 {
2182         if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2183         return getVersionedPath($relative_path).(!empty($additional_attrs)?"&$additional_attrs":"");
2184 }
2185
2186 function getSWFPath($relative_path, $additional_params=''){
2187         $path = $relative_path;
2188         if (!empty($additional_params)){
2189                 $path .= '?' . $additional_params;
2190         }
2191         if (defined('TEMPLATE_URL')){
2192                 $path = TEMPLATE_URL . '/' . $path;
2193         }
2194         return $path;
2195 }
2196
2197
2198
2199
2200
2201 function getSQLDate($date_str)
2202 {
2203         if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2204         {
2205                 if ( strlen($match[2]) == 1)
2206                 {
2207                         $match[2] = "0".$match[2];
2208                 }
2209                 if ( strlen($match[1]) == 1)
2210                 {
2211                         $match[1] = "0".$match[1];
2212                 }
2213                 return "{$match[3]}-{$match[1]}-{$match[2]}";
2214         }
2215         else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2216         {
2217                 if ( strlen($match[2]) == 1)
2218                 {
2219                         $match[2] = "0".$match[2];
2220                 }
2221                 if ( strlen($match[1]) == 1)
2222                 {
2223                         $match[1] = "0".$match[1];
2224                 }
2225                 return "{$match[3]}-{$match[1]}-{$match[2]}";
2226         }
2227         else
2228         {
2229                 return "";
2230         }
2231 }
2232
2233 function clone_history(&$db, $from_id,$to_id, $to_type)
2234 {
2235         global $timedate;
2236         $old_note_id=null;
2237         $old_filename=null;
2238         require_once('include/upload_file.php');
2239         $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2240
2241         $location=array('Email'=>"modules/Emails/Email.php",
2242         'Call'=>"modules/Calls/Call.php",
2243         'Meeting'=>"modules/Meetings/Meeting.php",
2244         'Note'=>"modules/Notes/Note.php",
2245         'Tasks'=>"modules/Tasks/Task.php",
2246         );
2247
2248
2249         foreach($tables as $table=>$bean_class)
2250         {
2251
2252                 if (!class_exists($bean_class))
2253                 {
2254                         require_once($location[$bean_class]);
2255                 }
2256
2257                 $bProcessingNotes=false;
2258                 if ($table=='notes')
2259                 {
2260                         $bProcessingNotes=true;
2261                 }
2262                 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2263                 $results = $db->query($query);
2264                 while($row = $db->fetchByAssoc($results))
2265                 {
2266                         //retrieve existing record.
2267                         $bean= new $bean_class();
2268                         $bean->retrieve($row['id']);
2269                         //process for new instance.
2270                         if ($bProcessingNotes)
2271                         {
2272                                 $old_note_id=$row['id'];
2273                                 $old_filename=$bean->filename;
2274                         }
2275                         $bean->id=null;
2276                         $bean->parent_id=$to_id;
2277                         $bean->parent_type=$to_type;
2278                         if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2279                         {
2280                                 $bean->contact_id=$to_id;
2281                         }
2282                         $bean->update_date_modified = false;
2283             $bean->update_modified_by = false;
2284             if(isset($bean->date_modified))
2285                 $bean->date_modified = $timedate->to_db($bean->date_modified);
2286             if(isset($bean->date_entered))
2287                 $bean->date_entered = $timedate->to_db($bean->date_entered);
2288                         //save
2289                         $new_id=$bean->save();
2290
2291                         //duplicate the file now. for notes.
2292                         if ($bProcessingNotes && !empty($old_filename))
2293                         {
2294                                 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2295                         }
2296                         //reset the values needed for attachment duplication.
2297                         $old_note_id=null;
2298                         $old_filename=null;
2299                 }
2300         }
2301 }
2302
2303 function values_to_keys($array)
2304 {
2305         $new_array = array();
2306         if(!is_array($array))
2307         {
2308                 return $new_array;
2309         }
2310         foreach($array as $arr){
2311                 $new_array[$arr] = $arr;
2312         }
2313         return $new_array;
2314 }
2315
2316 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2317 {
2318         foreach($tables as $table)
2319         {
2320
2321                 if ($table == 'emails_beans') {
2322                         $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2323                 } else {
2324                         $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2325                 }
2326                 $results = $db->query($query);
2327                 while($row = $db->fetchByAssoc($results))
2328                 {
2329                         $query = "INSERT INTO $table ";
2330                         $names = '';
2331                         $values = '';
2332                         $row[$from_column] = $to_id;
2333                         $row['id'] = create_guid();
2334                         if ($table=='emails_beans') {
2335                                 $row['bean_module'] =='Contacts';
2336                         }
2337
2338                         foreach($row as $name=>$value)
2339                         {
2340
2341                                 if(empty($names))
2342                                 {
2343                                         $names .= $name;
2344                                         $values .= "'$value'";
2345                                 } else
2346                                 {
2347                                         $names .= ', '. $name;
2348                                         $values .= ", '$value'";
2349                                 }
2350                         }
2351                         $query .= "($names)     VALUES ($values)";
2352                         $db->query($query);
2353                 }
2354         }
2355 }
2356
2357 function get_unlinked_email_query($type, $bean) {
2358     global $current_user;
2359
2360     $return_array['select']='SELECT emails.id ';
2361     $return_array['from']='FROM emails ';
2362     $return_array['where']="";
2363         $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2364
2365         join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2366         eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2367         where eear.deleted=0 and eear.email_id not in
2368         (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2369         ) derivedemails on derivedemails.email_id = emails.id";
2370     $return_array['join_tables'][0] = '';
2371
2372         if (isset($type) and !empty($type['return_as_array'])) {
2373                 return $return_array;
2374         }
2375
2376         return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2377 } // fn
2378
2379 function get_emails_by_assign_or_link($params)
2380 {
2381     $relation = $params['link'];
2382         $bean = $GLOBALS['app']->controller->bean;
2383     if(empty($bean->$relation)) {
2384         $bean->load_relationship($relation);
2385     }
2386     if(empty($bean->$relation)) {
2387         $GLOBALS['log']->error("Bad relation '$relation' for bean '{$bean->object_name}' id '{$bean->id}'");
2388         return array();
2389     }
2390     $rel_module = $bean->$relation->getRelatedModuleName();
2391     $rel_join = $bean->$relation->getJoin(array(
2392         'join_table_alias' => 'link_bean',
2393         'join_table_link_alias' => 'linkt',
2394     ));
2395     $rel_join = str_replace("{$bean->table_name}.id", "'{$bean->id}'", $rel_join);
2396     $return_array['select']='SELECT emails.id ';
2397     $return_array['from'] = "FROM emails ";
2398     $return_array['join'] = " INNER JOIN (".
2399         // directly assigned emails
2400                 "select eb.email_id, 'direct' source FROM emails_beans eb where eb.bean_module = '{$bean->module_dir}' AND eb.bean_id = '{$bean->id}' AND eb.deleted=0 ".
2401             " UNION ".
2402         // Assigned to contacts
2403                 "select DISTINCT eb.email_id, 'contact' source FROM emails_beans eb
2404                 $rel_join AND link_bean.id = eb.bean_id
2405                         where eb.bean_module = '$rel_module' AND eb.deleted=0".
2406                 " UNION ".
2407         // Related by directly by email
2408             "select DISTINCT eear.email_id, 'relate' source  from emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2409                 ON eabr.bean_id ='{$bean->id}' AND eabr.bean_module = '{$bean->module_dir}' AND
2410                         eabr.email_address_id = eear.email_address_id and eabr.deleted=0 where eear.deleted=0".
2411             " UNION ".
2412         // Related by email to linked contact
2413             "select DISTINCT eear.email_id, 'relate_contact' source FROM emails_email_addr_rel eear INNER JOIN email_addr_bean_rel eabr
2414                 ON eabr.email_address_id=eear.email_address_id AND eabr.bean_module = '$rel_module' AND eabr.deleted=0
2415                 $rel_join AND link_bean.id = eabr.bean_id
2416                 where eear.deleted=0".
2417             ") email_ids ON emails.id=email_ids.email_id ";
2418         $return_array['where']=" WHERE emails.deleted=0 ";
2419
2420         //$return_array['join'] = '';
2421         $return_array['join_tables'][0] = '';
2422
2423         if($bean->object_name == "Case" && !empty($bean->case_number)) {
2424             $where = str_replace("%1", $bean->case_number,      $bean->getEmailSubjectMacro());
2425             $return_array["where"] .= "\n AND (email_ids.source = 'direct' OR emails.name LIKE '%$where%')";
2426         }
2427
2428         return $return_array;
2429 }
2430
2431 /**
2432  * Check to see if the number is empty or non-zero
2433  * @param $value
2434  * @return boolean
2435  **/
2436 function number_empty($value)
2437 {
2438         return empty($value) && $value != '0';
2439 }
2440
2441 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2442 {
2443         global $beanFiles;
2444         require_once($beanFiles[$bean_name]);
2445         $focus = new $bean_name();
2446         $user_array = array();
2447
2448     $key = ($bean_name == 'EmailTemplate') ?  $bean_name : $bean_name . $display_columns. $where . $order_by;
2449         $user_array = get_register_value('select_array', $key );
2450         if(!$user_array)
2451         {
2452
2453                 $db = DBManagerFactory::getInstance();
2454
2455                 $temp_result = Array();
2456                 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2457                 $query .= "where ";
2458                 if ( $where != '')
2459                 {
2460                         $query .= $where." AND ";
2461                 }
2462
2463                 $query .=  " {$focus->table_name}.deleted=0";
2464
2465                 if ( $order_by != '')
2466                 {
2467                         $query .= " order by {$focus->table_name}.{$order_by}";
2468                 }
2469
2470                 $GLOBALS['log']->debug("get_user_array query: $query");
2471                 $result = $db->query($query, true, "Error filling in user array: ");
2472
2473                 if ($add_blank==true){
2474                         // Add in a blank row
2475                         if($blank_is_none == true) { // set 'blank row' to "--None--"
2476                                 global $app_strings;
2477                                 $temp_result[''] = $app_strings['LBL_NONE'];
2478                         } else {
2479                                 $temp_result[''] = '';
2480                         }
2481                 }
2482
2483                 // Get the id and the name.
2484                 while($row = $db->fetchByAssoc($result))
2485                 {
2486                         $temp_result[$row['id']] = $row['display'];
2487                 }
2488
2489                 $user_array = $temp_result;
2490                 set_register_value('select_array', $key ,$temp_result);
2491         }
2492
2493         return $user_array;
2494
2495 }
2496 /**
2497  *
2498  *
2499  * @param unknown_type $listArray
2500  */
2501 // function parse_list_modules
2502 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2503 function parse_list_modules(&$listArray)
2504 {
2505         global $modListHeader;
2506         $returnArray = array();
2507
2508         foreach($listArray as $optionName => $optionVal)
2509         {
2510                 if(array_key_exists($optionName, $modListHeader))
2511                 {
2512                         $returnArray[$optionName] = $optionVal;
2513                 }
2514
2515                 // special case for projects
2516                 if(array_key_exists('Project', $modListHeader))
2517                 {
2518                         $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2519                 }
2520         }
2521         $acldenied = ACLController::disabledModuleList($listArray,false);
2522         foreach($acldenied as $denied){
2523                 unset($returnArray[$denied]);
2524         }
2525         asort($returnArray);
2526
2527         return $returnArray;
2528 }
2529
2530 function display_notice($msg = false){
2531         global $error_notice;
2532         //no error notice - lets just display the error to the user
2533         if(!isset($error_notice)){
2534                 echo '<br>'.$msg . '<br>';
2535         }else{
2536                 $error_notice .= $msg . '<br>';
2537         }
2538 }
2539
2540 /* checks if it is a number that at least has the plus at the beginning.
2541  */
2542 function skype_formatted($number){
2543         //kbrill - BUG #15375
2544         if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2545                 return false;
2546         } else {
2547                 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2548         }
2549 //      return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2550 }
2551
2552 function format_skype($number) {
2553     return preg_replace('/[^\+0-9]/','',$number);
2554 }
2555
2556 function insert_charset_header() {
2557         header('Content-Type: text/html; charset=UTF-8');
2558 }
2559
2560 function getCurrentURL()
2561 {
2562         $href = "http:";
2563         if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2564         {
2565                 $href = 'https:';
2566         }
2567
2568         $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2569         return $href;
2570 }
2571
2572 function javascript_escape($str) {
2573         $new_str = '';
2574
2575         for($i = 0; $i < strlen($str); $i++) {
2576
2577                 if(ord(substr($str, $i, 1))==10){
2578                         $new_str .= '\n';
2579                 }elseif(ord(substr($str, $i, 1))==13){
2580                         $new_str .= '\r';
2581                 }
2582                 else {
2583                         $new_str .= $str{$i};
2584                 }
2585         }
2586
2587         $new_str = str_replace("'", "\\'", $new_str);
2588
2589         return $new_str;
2590 }
2591
2592 function js_escape($str, $keep=true){
2593         $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2594
2595         if($keep){
2596                 $str = javascript_escape($str);
2597         }
2598         else {
2599                 $str = str_replace("'", " ", $str);
2600                 $str = str_replace('"', " ", $str);
2601         }
2602
2603         return $str;
2604
2605         //end function js_escape
2606 }
2607
2608 function br2nl($str) {
2609         $regex = "#<[^>]+br.+?>#i";
2610         preg_match_all($regex, $str, $matches);
2611
2612         foreach($matches[0] as $match) {
2613                 $str = str_replace($match, "<br>", $str);
2614         }
2615
2616         $brs = array('<br>','<br/>', '<br />');
2617         $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2618         $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2619         $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2620         $str = str_ireplace($brs, "\n", $str); // to retrieve it
2621
2622         return $str;
2623 }
2624
2625 /**
2626  * Private helper function for displaying the contents of a given variable.
2627  * This function is only intended to be used for SugarCRM internal development.
2628  * The ppd stands for Pre Print Die.
2629  */
2630 function _ppd($mixed)
2631 {
2632 }
2633
2634
2635 /**
2636  * Private helper function for displaying the contents of a given variable in
2637  * the Logger. This function is only intended to be used for SugarCRM internal
2638  * development. The pp stands for Pre Print.
2639  * @param $mixed var to print_r()
2640  * @param $die boolean end script flow
2641  * @param $displayStackTrace also show stack trace
2642  */
2643 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2644         if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2645
2646                 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2647         }
2648
2649
2650         $mix    = print_r($mixed, true); // send print_r() output to $mix
2651         $stack  = debug_backtrace();
2652
2653         $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2654         $GLOBALS['log']->$loglevel($mix);
2655         if($displayStackTrace) {
2656                 foreach($stack as $position) {
2657                         $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2658                 }
2659         }
2660
2661         $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2662         $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2663
2664         if($die) {
2665                 die();
2666         }
2667 }
2668
2669 /**
2670  * private helper function to quickly show the major, direct, field attributes of a given bean.
2671  * The ppf stands for Pre[formatted] Print Focus [object]
2672  * @param object bean The focus bean
2673  */
2674 function _ppf($bean, $die=false) {
2675 }
2676
2677
2678
2679 /**
2680  * Private helper function for displaying the contents of a given variable.
2681  * This function is only intended to be used for SugarCRM internal development.
2682  * The pp stands for Pre Print.
2683  */
2684 function _pp($mixed)
2685 {
2686 }
2687
2688 /**
2689  * Private helper function for displaying the contents of a given variable.
2690  * This function is only intended to be used for SugarCRM internal development.
2691  * The pp stands for Pre Print.
2692  */
2693 function _pstack_trace($mixed=NULL)
2694 {
2695 }
2696
2697 /**
2698  * Private helper function for displaying the contents of a given variable.
2699  * This function is only intended to be used for SugarCRM internal development.
2700  * The pp stands for Pre Print Trace.
2701  */
2702 function _ppt($mixed, $textOnly=false)
2703 {
2704 }
2705
2706 /**
2707  * Private helper function for displaying the contents of a given variable.
2708  * This function is only intended to be used for SugarCRM internal development.
2709  * The pp stands for Pre Print Trace Die.
2710  */
2711 function _pptd($mixed)
2712 {
2713 }
2714
2715 /**
2716  * Private helper function for decoding javascript UTF8
2717  * This function is only intended to be used for SugarCRM internal development.
2718  */
2719 function decodeJavascriptUTF8($str) {
2720 }
2721
2722 /**
2723  * Will check if a given PHP version string is supported (tested on this ver),
2724  * unsupported (results unknown), or invalid (something will break on this
2725  * ver).  Do not pass in any pararameter to default to a check against the
2726  * current environment's PHP version.
2727  *
2728  * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2729  */
2730 function check_php_version($sys_php_version = '') {
2731         $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2732         // versions below $min_considered_php_version considered invalid by default,
2733         // versions equal to or above this ver will be considered depending
2734         // on the rules that follow
2735         $min_considered_php_version = '5.2.1';
2736
2737         // only the supported versions,
2738         // should be mutually exclusive with $invalid_php_versions
2739         $supported_php_versions = array (
2740         '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2741         );
2742
2743         // invalid versions above the $min_considered_php_version,
2744         // should be mutually exclusive with $supported_php_versions
2745
2746         // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2747         $invalid_php_versions = array('5.2.7');
2748
2749         // default unsupported
2750         $retval = 0;
2751
2752         // versions below $min_considered_php_version are invalid
2753         if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2754                 $retval = -1;
2755         }
2756
2757         // supported version check overrides default unsupported
2758         foreach($supported_php_versions as $ver) {
2759                 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2760                         $retval = 1;
2761                         break;
2762                 }
2763         }
2764
2765         // invalid version check overrides default unsupported
2766         foreach($invalid_php_versions as $ver) {
2767                 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2768                         $retval = -1;
2769                         break;
2770                 }
2771         }
2772
2773     //allow a redhat distro to install, regardless of version.  We are assuming the redhat naming convention is followed
2774     //and the php version contains 'rh' characters
2775     if(strpos($sys_php_version, 'rh') !== false) {
2776         $retval = 1;
2777     }
2778
2779         return $retval;
2780 }
2781
2782 /**
2783  * Will check if a given IIS version string is supported (tested on this ver),
2784  * unsupported (results unknown), or invalid (something will break on this
2785  * ver).
2786  *
2787  * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2788  */
2789 function check_iis_version($sys_iis_version = '') {
2790
2791         $server_software = $_SERVER["SERVER_SOFTWARE"];
2792         $iis_version = '';
2793         if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/",  $server_software, $out))
2794             $iis_version = $out[1][0];
2795
2796     $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2797
2798     // versions below $min_considered_iis_version considered invalid by default,
2799     // versions equal to or above this ver will be considered depending
2800     // on the rules that follow
2801     $min_considered_iis_version = '6.0';
2802
2803     // only the supported versions,
2804     // should be mutually exclusive with $invalid_iis_versions
2805     $supported_iis_versions = array ('6.0', '7.0',);
2806     $unsupported_iis_versions = array();
2807     $invalid_iis_versions = array('5.0',);
2808
2809     // default unsupported
2810     $retval = 0;
2811
2812     // versions below $min_considered_iis_version are invalid
2813     if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2814         $retval = -1;
2815     }
2816
2817     // supported version check overrides default unsupported
2818     foreach($supported_iis_versions as $ver) {
2819         if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2820             $retval = 1;
2821             break;
2822         }
2823     }
2824
2825     // unsupported version check overrides default unsupported
2826     foreach($unsupported_iis_versions as $ver) {
2827         if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2828             $retval = 0;
2829             break;
2830         }
2831     }
2832
2833     // invalid version check overrides default unsupported
2834     foreach($invalid_iis_versions as $ver) {
2835         if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2836             $retval = -1;
2837             break;
2838         }
2839     }
2840
2841     return $retval;
2842 }
2843
2844 function pre_login_check(){
2845         global $action, $login_error;
2846         if(!empty($action)&& $action == 'Login'){
2847
2848                 if(!empty($login_error)){
2849                         $login_error = htmlentities($login_error);
2850                         $login_error = str_replace(array("&lt;pre&gt;","&lt;/pre&gt;","\r\n", "\n"), "<br>", $login_error);
2851                         $_SESSION['login_error'] = $login_error;
2852                         echo '<script>
2853                                                 function set_focus() {}
2854                                                 if(document.getElementById("post_error")) {
2855                                                         document.getElementById("post_error").innerHTML="'. $login_error. '";
2856                                                         document.getElementById("cant_login").value=1;
2857                                                         document.getElementById("login_button").disabled = true;
2858                                                         document.getElementById("user_name").disabled = true;
2859                                                         //document.getElementById("user_password").disabled = true;
2860                                                 }
2861                                                 </script>';
2862                 }
2863         }
2864 }
2865
2866
2867
2868 function sugar_cleanup($exit = false) {
2869         static $called = false;
2870         if($called)return;
2871         $called = true;
2872         set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2873         chdir(realpath(dirname(__FILE__) . '/..'));
2874         global $sugar_config;
2875         require_once('include/utils/LogicHook.php');
2876         LogicHook::initialize();
2877         $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2878
2879         //added this check to avoid errors during install.
2880         if (empty($sugar_config['dbconfig'])) {
2881                 if ($exit) exit; else return;
2882         }
2883
2884     if (!class_exists('Tracker', true)) {
2885                 require_once 'modules/Trackers/Tracker.php';
2886         }
2887         Tracker::logPage();
2888         // Now write the cached tracker_queries
2889         if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2890             if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2891                 $GLOBALS['current_user']->savePreferencesToDB();
2892         }
2893
2894         //check to see if this is not an `ajax call AND the user preference error flag is set
2895         if(
2896                 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2897                 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2898                 && ($_REQUEST['action']!='favorites' && $_REQUEST['action']!='DynamicAction')
2899                 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2900                 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2901
2902         ){
2903                 global $app_strings;
2904                 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2905                 $err_mess = $app_strings['ERROR_USER_PREFS'];
2906                 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2907                 echo "
2908                 <script>
2909                         ajaxStatus.flashStatus('$err_mess',7000);
2910                 </script>";
2911
2912         }
2913
2914         pre_login_check();
2915         if(class_exists('DBManagerFactory')) {
2916                 $db = DBManagerFactory::getInstance();
2917                 $db->disconnect();
2918                 if($exit) {
2919                         exit;
2920                 }
2921         }
2922 }
2923
2924 register_shutdown_function('sugar_cleanup');
2925
2926
2927 /*
2928  check_logic_hook - checks to see if your custom logic is in the logic file
2929  if not, it will add it. If the file isn't built yet, it will create the file
2930
2931  */
2932 function check_logic_hook_file($module_name, $event, $action_array){
2933         require_once('include/utils/logic_utils.php');
2934         $add_logic = false;
2935
2936         if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2937
2938                 $hook_array = get_hook_array($module_name);
2939
2940                 if(check_existing_element($hook_array, $event, $action_array)==true){
2941                         //the hook at hand is present, so do nothing
2942                 } else {
2943                         $add_logic = true;
2944
2945             $logic_count = 0;
2946             if(!empty($hook_array[$event]))
2947             {
2948                             $logic_count = count($hook_array[$event]);
2949             }
2950
2951                         if($action_array[0]==""){
2952                                 $action_array[0] = $logic_count  + 1;
2953                         }
2954                         $hook_array[$event][] = $action_array;
2955
2956                 }
2957                 //end if the file exists already
2958         } else {
2959                 $add_logic = true;
2960                 if($action_array[0]==""){
2961                         $action_array[0] = 1;
2962                 }
2963                 $hook_array = array();
2964                 $hook_array[$event][] = $action_array;
2965                 //end if else file exists already
2966         }
2967         if($add_logic == true){
2968
2969                 //reorder array by element[0]
2970                 //$hook_array = reorder_array($hook_array, $event);
2971                 //!!!Finish this above TODO
2972
2973                 $new_contents = replace_or_add_logic_type($hook_array);
2974                 write_logic_file($module_name, $new_contents);
2975
2976                 //end if add_element is true
2977         }
2978
2979         //end function check_logic_hook_file
2980 }
2981
2982 function remove_logic_hook($module_name, $event, $action_array) {
2983     require_once('include/utils/logic_utils.php');
2984         $add_logic = false;
2985
2986         if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2987         // The file exists, let's make sure the hook is there
2988                 $hook_array = get_hook_array($module_name);
2989
2990                 if(check_existing_element($hook_array, $event, $action_array)==true){
2991             // The hook is there, time to take it out.
2992
2993             foreach ( $hook_array[$event] as $i => $hook ) {
2994                 // We don't do a full comparison below just in case the filename changes
2995                 if ( $hook[0] == $action_array[0]
2996                      && $hook[1] == $action_array[1]
2997                      && $hook[3] == $action_array[3]
2998                      && $hook[4] == $action_array[4] ) {
2999                     unset($hook_array[$event][$i]);
3000                 }
3001             }
3002
3003             $new_contents = replace_or_add_logic_type($hook_array);
3004             write_logic_file($module_name, $new_contents);
3005
3006         }
3007     }
3008 }
3009
3010 function display_stack_trace($textOnly=false){
3011
3012         $stack  = debug_backtrace();
3013
3014         echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
3015
3016         if(!$textOnly)
3017         echo '<br>';
3018
3019         $first = true;
3020         $out = '';
3021
3022         foreach($stack as $item) {
3023                 $file  = '';
3024                 $class = '';
3025                 $line  = '';
3026                 $function  = '';
3027
3028                 if(isset($item['file']))
3029                 $file = $item['file'];
3030                 if(isset($item['class']))
3031                 $class = $item['class'];
3032                 if(isset($item['line']))
3033                 $line = $item['line'];
3034                 if(isset($item['function']))
3035                 $function = $item['function'];
3036
3037                 if(!$first) {
3038                         if(!$textOnly) {
3039                                 $out .= '<font color="black"><b>';
3040                         }
3041
3042                         $out .= $file;
3043
3044                         if(!$textOnly) {
3045                                 $out .= '</b></font><font color="blue">';
3046                         }
3047
3048                         $out .= "[L:{$line}]";
3049
3050                         if(!$textOnly) {
3051                                 $out .= '</font><font color="red">';
3052                         }
3053
3054                         $out .= "({$class}:{$function})";
3055
3056                         if(!$textOnly) {
3057                                 $out .= '</font><br>';
3058                         } else {
3059                                 $out .= "\n";
3060                         }
3061                 } else {
3062                         $first = false;
3063                 }
3064         }
3065
3066         echo $out;
3067 }
3068
3069 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
3070         $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
3071         $halt_script = true;
3072         switch($errno){
3073                 case 2048: return; //depricated we have lots of these ignore them
3074                 case E_USER_NOTICE:
3075                 case E_NOTICE:
3076                     if ( error_reporting() & E_NOTICE ) {
3077                         $halt_script = false;
3078                         $type = 'Notice';
3079                     }
3080                     else
3081                         return;
3082                         break;
3083                 case E_USER_WARNING:
3084                 case E_COMPILE_WARNING:
3085                 case E_CORE_WARNING:
3086                 case E_WARNING:
3087
3088                         $halt_script = false;
3089                         $type = "Warning";
3090                         break;
3091
3092                 case E_USER_ERROR:
3093                 case E_COMPILE_ERROR:
3094                 case E_CORE_ERROR:
3095                 case E_ERROR:
3096
3097                         $type = "Fatal Error";
3098                         break;
3099
3100                 case E_PARSE:
3101
3102                         $type = "Parse Error";
3103                         break;
3104
3105                 default:
3106                         //don't know what it is might not be so bad
3107                         $halt_script = false;
3108                         $type = "Unknown Error ($errno)";
3109                         break;
3110         }
3111         $error_msg = '<b>'.$type.'</b>:' . $error_msg;
3112         echo $error_msg;
3113         display_stack_trace();
3114         if($halt_script){
3115                 exit -1;
3116         }
3117
3118
3119
3120 }
3121
3122
3123 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
3124
3125         set_error_handler('StackTraceErrorHandler');
3126 }
3127 function get_sub_cookies($name){
3128         $cookies = array();
3129         if(isset($_COOKIE[$name])){
3130                 $subs = explode('#', $_COOKIE[$name]);
3131                 foreach($subs as $cookie){
3132                         if(!empty($cookie)){
3133                                 $cookie = explode('=', $cookie);
3134
3135                                 $cookies[$cookie[0]] = $cookie[1];
3136                         }
3137                 }
3138         }
3139         return $cookies;
3140
3141 }
3142
3143
3144 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
3145
3146         if(!empty($sub_object_array)){
3147
3148                 foreach($sub_object_array as $sub_object){
3149
3150                         //run_second level is set to true if you need to remove sub-sub components
3151                         if($run_second_level==true){
3152
3153                                 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
3154
3155                                 //end if run_second_level is true
3156                         }
3157                         $sub_object->mark_deleted($sub_object->id);
3158                         //end foreach sub component
3159                 }
3160                 //end if this is not empty
3161         }
3162
3163         //end function mark_delete_components
3164 }
3165
3166 /**
3167  * For translating the php.ini memory values into bytes.  e.g. input value of '8M' will return 8388608.
3168  */
3169 function return_bytes($val)
3170 {
3171         $val = trim($val);
3172         $last = strtolower($val{strlen($val)-1});
3173
3174         switch($last)
3175         {
3176                 // The 'G' modifier is available since PHP 5.1.0
3177                 case 'g':
3178                         $val *= 1024;
3179                 case 'm':
3180                         $val *= 1024;
3181                 case 'k':
3182                         $val *= 1024;
3183         }
3184
3185         return $val;
3186 }
3187
3188 /**
3189  * Adds the href HTML tags around any URL in the $string
3190  */
3191 function url2html($string) {
3192         //
3193         $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new"  style="font-weight: normal;">\\1\\2</a>', $string);
3194         return $return_string;
3195 }
3196 // End customization by Julian
3197
3198 /**
3199  * tries to determine whether the Host machine is a Windows machine
3200  */
3201 function is_windows() {
3202     static $is_windows = null;
3203     if (!isset($is_windows)) {
3204         $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3205     }
3206     return $is_windows;
3207 }
3208
3209 /**
3210  * equivalent for windows filesystem for PHP's is_writable()
3211  * @param string file Full path to the file/dir
3212  * @return bool true if writable
3213  */
3214 function is_writable_windows($file) {
3215         if($file{strlen($file)-1}=='/') {
3216                 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3217         }
3218
3219         // the assumption here is that Windows has an inherited permissions scheme
3220         // any file that is a descendant of an unwritable directory will inherit
3221         // that property and will trigger a failure below.
3222         if(is_dir($file)) {
3223                 return true;
3224         }
3225
3226         $file = str_replace("/", '\\', $file);
3227
3228         if(file_exists($file)) {
3229                 if (!($f = @sugar_fopen($file, 'r+')))
3230                 return false;
3231                 fclose($f);
3232                 return true;
3233         }
3234
3235         if(!($f = @sugar_fopen($file, 'w')))
3236         return false;
3237         fclose($f);
3238         unlink($file);
3239         return true;
3240 }
3241
3242
3243 /**
3244  * best guesses Timezone based on webserver's TZ settings
3245  */
3246 function lookupTimezone($userOffset = 0)
3247 {
3248     return TimeDate::guessTimezone($userOffset);
3249 }
3250
3251 function convert_module_to_singular($module_array){
3252         global $beanList;
3253
3254         foreach($module_array as $key => $value){
3255                 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3256
3257                 if($value=="Cases") {
3258                         $module_array[$key] = "Case";
3259                 }
3260                 if($key=="projecttask"){
3261                         $module_array['ProjectTask'] = "Project Task";
3262                         unset($module_array[$key]);
3263                 }
3264         }
3265
3266         return $module_array;
3267
3268         //end function convert_module_to_singular
3269 }
3270
3271 /*
3272  * Given the bean_name which may be plural or singular return the singular
3273  * bean_name. This is important when you need to include files.
3274  */
3275 function get_singular_bean_name($bean_name){
3276         global $beanFiles, $beanList;
3277         if(array_key_exists($bean_name, $beanList)){
3278                 return $beanList[$bean_name];
3279         }
3280         else{
3281                 return $bean_name;
3282         }
3283 }
3284
3285 /*
3286  * Given the potential module name (singular name, renamed module name)
3287  * Return the real internal module name.
3288  */
3289 function get_module_from_singular($singular) {
3290
3291     // find the internal module name for a singular name
3292     if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3293
3294         $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3295
3296         foreach ($singular_modules as $mod_name=>$sin_name) {
3297             if ($singular == $sin_name and $mod_name != $sin_name) {
3298                 return $mod_name;
3299             }
3300         }
3301     }
3302
3303     // find the internal module name for a renamed module
3304     if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3305
3306         $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3307
3308         foreach ($moduleList as $mod_name=>$name) {
3309             if ($singular == $name and $mod_name != $name) {
3310                 return $mod_name;
3311             }
3312         }
3313     }
3314
3315     // if it's not a singular name, nor a renamed name, return the original value
3316     return $singular;
3317 }
3318
3319 function get_label($label_tag, $temp_module_strings){
3320         global $app_strings;
3321         if(!empty($temp_module_strings[$label_tag])){
3322
3323                 $label_name = $temp_module_strings[$label_tag];
3324         } else {
3325                 if(!empty($app_strings[$label_tag])){
3326                         $label_name = $app_strings[$label_tag];
3327                 } else {
3328                         $label_name = $label_tag;
3329                 }
3330         }
3331         return $label_name;
3332
3333         //end function get_label
3334 }
3335
3336
3337 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3338
3339         $rel_list = array();
3340
3341         foreach($focus->relationship_fields as $rel_key => $rel_value){
3342                 if($rel_value == $relationship_name){
3343                         $temp_bean = get_module_info($tar_rel_module);
3344         //              echo $focus->$rel_key;
3345                         $temp_bean->retrieve($focus->$rel_key);
3346                         if($temp_bean->id!=""){
3347
3348                                 $rel_list[] = $temp_bean;
3349                                 return $rel_list;
3350                         }
3351                 }
3352         }
3353
3354         foreach($focus->field_defs as $field_name => $field_def){
3355                 //Check if the relationship_name matches a "relate" field
3356                 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3357                 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3358                 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3359                 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3360                 {
3361                         $temp_bean = get_module_info($tar_rel_module);
3362                 //      echo $focus->$field_def['id_name'];
3363                         $temp_bean->retrieve($focus->$field_def['id_name']);
3364                         if($temp_bean->id!=""){
3365
3366                                 $rel_list[] = $temp_bean;
3367                                 return $rel_list;
3368                         }
3369                 //Check if the relationship_name matches a "link" in a relate field
3370                 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3371                         $temp_bean = get_module_info($tar_rel_module);
3372                 //      echo $focus->$rel_value['id_name'];
3373                         $temp_bean->retrieve($focus->$rel_value['id_name']);
3374                         if($temp_bean->id!=""){
3375
3376                                 $rel_list[] = $temp_bean;
3377                                 return $rel_list;
3378                         }
3379                 }
3380         }
3381
3382         // special case for unlisted parent-type relationships
3383         if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3384                 $temp_bean = get_module_info($tar_rel_module);
3385                 $temp_bean->retrieve($focus->parent_id);
3386                 if($temp_bean->id!=""){
3387                         $rel_list[] = $temp_bean;
3388                         return $rel_list;
3389                 }
3390         }
3391
3392         return $rel_list;
3393
3394         //end function search_filter_rel_info
3395 }
3396
3397 function get_module_info($module_name){
3398         global $beanList;
3399         global $dictionary;
3400
3401         //Get dictionary and focus data for module
3402         $vardef_name = $beanList[$module_name];
3403
3404         if($vardef_name=="aCase"){
3405                 $class_name = "Case";
3406         } else {
3407                 $class_name = $vardef_name;
3408         }
3409
3410         if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3411                 return;
3412         }
3413
3414         include_once('modules/'. $module_name . '/'.$class_name.'.php');
3415
3416         $module_bean = new $vardef_name();
3417         return $module_bean;
3418         //end function get_module_table
3419 }
3420
3421 /**
3422  * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3423  *
3424  * @param string $moduleName
3425  */
3426 function get_valid_bean_name($module_name){
3427         global $beanList;
3428
3429         $vardef_name = $beanList[$module_name];
3430         if($vardef_name=="aCase"){
3431                 $bean_name = "Case";
3432         } else {
3433                 $bean_name = $vardef_name;
3434         }
3435         return $bean_name;
3436 }
3437
3438
3439
3440 function  checkAuthUserStatus(){
3441
3442         //authUserStatus();
3443 }
3444
3445
3446 /**
3447  * This function returns an array of phpinfo() results that can be parsed and
3448  * used to figure out what version we run, what modules are compiled in, etc.
3449  * @param       $level                  int             info level constant (1,2,4,8...64);
3450  * @return      $returnInfo             array   array of info about the PHP environment
3451  * @author      original by "code at adspeed dot com" Fron php.net
3452  * @author      customized for Sugar by Chris N.
3453  */
3454 function getPhpInfo($level=-1) {
3455         /**     Name (constant)         Value   Description
3456                 INFO_GENERAL            1               The configuration line, php.ini location, build date, Web Server, System and more.
3457                 INFO_CREDITS            2               PHP Credits. See also phpcredits().
3458                 INFO_CONFIGURATION      4               Current Local and Master values for PHP directives. See also ini_get().
3459                 INFO_MODULES            8               Loaded modules and their respective settings. See also get_loaded_extensions().
3460                 INFO_ENVIRONMENT        16              Environment Variable information that's also available in $_ENV.
3461                 INFO_VARIABLES          32              Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3462                 INFO_LICENSE            64              PHP License information. See also the license FAQ.
3463                 INFO_ALL                        -1              Shows all of the above. This is the default value.
3464          */
3465         ob_start();
3466         phpinfo($level);
3467         $phpinfo = ob_get_contents();
3468         ob_end_clean();
3469
3470         $phpinfo        = strip_tags($phpinfo,'<h1><h2><th><td>');
3471         $phpinfo        = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3472         $phpinfo        = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3473         $parsedInfo     = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3474         $match          = '';
3475         $version        = '';
3476         $returnInfo     = array();
3477
3478         if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3479                 $returnInfo['PHP Version'] = $version[1];
3480         }
3481
3482
3483         for ($i=1; $i<count($parsedInfo); $i++) {
3484                 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3485                         $vName = trim($match[1]);
3486                         $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3487
3488                         foreach ($parsedInfo2 AS $vOne) {
3489                                 $vPat   = '<info>([^<]+)<\/info>';
3490                                 $vPat3  = "/$vPat\s*$vPat\s*$vPat/";
3491                                 $vPat2  = "/$vPat\s*$vPat/";
3492
3493                                 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3494                                         $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3495                                 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3496                                         $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3497                                 }
3498                         }
3499                 } elseif(true) {
3500
3501                 }
3502         }
3503
3504         return $returnInfo;
3505 }
3506
3507 /**
3508  * This function will take a string that has tokens like {0}, {1} and will replace
3509  * those tokens with the args provided
3510  * @param       $format string to format
3511  * @param       $args args to replace
3512  * @return      $result a formatted string
3513  */
3514 function string_format($format, $args){
3515         $result = $format;
3516
3517     /** Bug47277 fix.
3518      * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3519      * IN () fails and IN ('') works.
3520      */
3521     if (count($args) == 1)
3522     {
3523         reset($args);
3524         $singleArgument = current($args);
3525         if (empty($singleArgument))
3526         {
3527             return str_replace("{0}", "''", $result);
3528         }
3529     }
3530     /* End of fix */
3531
3532         for($i = 0; $i < count($args); $i++){
3533                 $result = str_replace('{'.$i.'}', $args[$i], $result);
3534         }
3535         return $result;
3536 }
3537
3538 /**
3539  * Generate a string for displaying a unique identifier that is composed
3540  * of a system_id and number.  This is use to allow us to generate quote
3541  * numbers using a DB auto-increment key from offline clients and still
3542  * have the number be unique (since it is modified by the system_id.
3543  *
3544  * @param       $num of bean
3545  * @param       $system_id from system
3546  * @return      $result a formatted string
3547  */
3548 function format_number_display($num, $system_id){
3549         global $sugar_config;
3550         if(isset($num) && !empty($num)){
3551                 $num=unformat_number($num);
3552                 if(isset($system_id) && $system_id == 1){
3553                         return sprintf("%d", $num);
3554                 }
3555                 else{
3556                         return sprintf("%d-%d", $num, $system_id);
3557                 }
3558         }
3559 }
3560 function checkLoginUserStatus(){
3561 }
3562
3563 /**
3564  * This function will take a number and system_id and format
3565  * @param       $url URL containing host to append port
3566  * @param       $port the port number - if '' is passed, no change to url
3567  * @return      $resulturl the new URL with the port appended to the host
3568  */
3569 function appendPortToHost($url, $port)
3570 {
3571         $resulturl = $url;
3572
3573         // if no port, don't change the url
3574         if($port != '')
3575         {
3576                 $split = explode("/", $url);
3577                 //check if it starts with http, in case they didn't include that in url
3578                 if(str_begin($url, 'http'))
3579                 {
3580                         //third index ($split[2]) will be the host
3581                         $split[2] .= ":".$port;
3582                 }
3583                 else // otherwise assumed to start with host name
3584                 {
3585                         //first index ($split[0]) will be the host
3586                         $split[0] .= ":".$port;
3587                 }
3588
3589                 $resulturl = implode("/", $split);
3590         }
3591
3592         return $resulturl;
3593 }
3594
3595 /**
3596  * Singleton to return JSON object
3597  * @return      JSON object
3598  */
3599 function getJSONobj() {
3600         static $json = null;
3601         if(!isset($json)) {
3602                 require_once('include/JSON.php');
3603                 $json = new JSON(JSON_LOOSE_TYPE);
3604         }
3605         return $json;
3606 }
3607
3608 require_once('include/utils/db_utils.php');
3609
3610 /**
3611  * Set default php.ini settings for entry points
3612  */
3613 function setPhpIniSettings() {
3614         // zlib module
3615         // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3616         /*
3617     if(function_exists('gzclose') && headers_sent() == false) {
3618                 ini_set('zlib.output_compression', 1);
3619         }
3620         */
3621         // mbstring module
3622         //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3623
3624         /*if(function_exists('mb_strlen')) {
3625                 ini_set('mbstring.func_overload', 7);
3626                 ini_set('mbstring.internal_encoding', 'UTF-8');
3627         }*/
3628
3629
3630         // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3631         // starting with 5.2.0, backtrack_limit breaks JSON decoding
3632         $backtrack_limit = ini_get('pcre.backtrack_limit');
3633         if(!empty($backtrack_limit)) {
3634                 ini_set('pcre.backtrack_limit', '-1');
3635         }
3636 }
3637
3638 /**
3639  * Identical to sugarArrayMerge but with some speed improvements and used specifically to merge
3640  * language files.  Language file merges do not need to account for null values so we can get some
3641  * performance increases by using this specialized function. Note this merge function does not properly
3642  * handle null values.
3643  *
3644  * @param $gimp
3645  * @param $dom
3646  * @return array
3647  */
3648 function sugarLangArrayMerge($gimp, $dom)
3649 {
3650         if(is_array($gimp) && is_array($dom))
3651     {
3652                 foreach($dom as $domKey => $domVal)
3653         {
3654                         if(isset($gimp[$domKey]))
3655             {
3656                                 if(is_array($domVal))
3657                 {
3658                                         $tempArr = array();
3659                     foreach ( $domVal as $domArrKey => $domArrVal )
3660                         $tempArr[$domArrKey] = $domArrVal;
3661                     foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3662                         if ( !isset($tempArr[$gimpArrKey]) )
3663                             $tempArr[$gimpArrKey] = $gimpArrVal;
3664                     $gimp[$domKey] = $tempArr;
3665                                 }
3666                 else
3667                 {
3668                                         $gimp[$domKey] = $domVal;
3669                                 }
3670                         }
3671             else
3672             {
3673                                 $gimp[$domKey] = $domVal;
3674                         }
3675                 }
3676         }
3677     // if the passed value for gimp isn't an array, then return the $dom
3678     elseif(is_array($dom))
3679     {
3680         return $dom;
3681     }
3682
3683         return $gimp;
3684 }
3685 /**
3686  * like array_merge() but will handle array elements that are themselves arrays;
3687  * PHP's version just overwrites the element with the new one.
3688  *
3689  * @internal Note that this function deviates from the internal array_merge()
3690  *           functions in that it does does not treat numeric keys differently
3691  *           than string keys.  Additionally, it deviates from
3692  *           array_merge_recursive() by not creating an array when like values
3693  *           found.
3694  *
3695  * @param array gimp the array whose values will be overloaded
3696  * @param array dom the array whose values will pwn the gimp's
3697  * @return array beaten gimp
3698  */
3699 function sugarArrayMerge($gimp, $dom) {
3700         if(is_array($gimp) && is_array($dom)) {
3701                 foreach($dom as $domKey => $domVal) {
3702                         if(array_key_exists($domKey, $gimp)) {
3703                                 if(is_array($domVal)) {
3704                                         $tempArr = array();
3705                     foreach ( $domVal as $domArrKey => $domArrVal )
3706                         $tempArr[$domArrKey] = $domArrVal;
3707                     foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3708                         if ( !array_key_exists($gimpArrKey, $tempArr) )
3709                             $tempArr[$gimpArrKey] = $gimpArrVal;
3710                     $gimp[$domKey] = $tempArr;
3711                                 } else {
3712                                         $gimp[$domKey] = $domVal;
3713                                 }
3714                         } else {
3715                                 $gimp[$domKey] = $domVal;
3716                         }
3717                 }
3718         }
3719     // if the passed value for gimp isn't an array, then return the $dom
3720     elseif(is_array($dom))
3721         return $dom;
3722
3723         return $gimp;
3724 }
3725
3726 /**
3727  * Similiar to sugarArrayMerge except arrays of N depth are merged.
3728  *
3729  * @param array gimp the array whose values will be overloaded
3730  * @param array dom the array whose values will pwn the gimp's
3731  * @return array beaten gimp
3732  */
3733 function sugarArrayMergeRecursive($gimp, $dom) {
3734         if(is_array($gimp) && is_array($dom)) {
3735                 foreach($dom as $domKey => $domVal) {
3736                         if(array_key_exists($domKey, $gimp)) {
3737                                 if(is_array($domVal) && is_array($gimp[$domKey])) {
3738                                         $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3739                                 } else {
3740                                         $gimp[$domKey] = $domVal;
3741                                 }
3742                         } else {
3743                                 $gimp[$domKey] = $domVal;
3744                         }
3745                 }
3746         }
3747     // if the passed value for gimp isn't an array, then return the $dom
3748     elseif(is_array($dom))
3749         return $dom;
3750
3751         return $gimp;
3752 }
3753
3754 /**
3755  * finds the correctly working versions of PHP-JSON
3756  * @return bool True if NOT found or WRONG version
3757  */
3758 function returnPhpJsonStatus() {
3759         if(function_exists('json_encode')) {
3760                 $phpInfo = getPhpInfo(8);
3761         return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3762         }
3763         return true; // not found
3764 }
3765
3766
3767 /**
3768  * getTrackerSubstring
3769  *
3770  * Returns a [number]-char or less string for the Tracker to display in the header
3771  * based on the tracker_max_display_length setting in config.php.  If not set,
3772  * or invalid length, then defaults to 15 for COM editions, 30 for others.
3773  *
3774  * @param string name field for a given Object
3775  * @return string [number]-char formatted string if length of string exceeds the max allowed
3776  */
3777 function getTrackerSubstring($name) {
3778         static $max_tracker_item_length;
3779
3780         //Trim the name
3781         $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3782         $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3783
3784         global $sugar_config;
3785
3786         if(!isset($max_tracker_item_length)) {
3787                 if(isset($sugar_config['tracker_max_display_length'])) {
3788               $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;
3789                 } else {
3790               $max_tracker_item_length = 15;
3791                 }
3792         }
3793
3794         if($strlen > $max_tracker_item_length) {
3795                 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length);
3796         } else {
3797                 $chopped = $name;
3798         }
3799
3800         return $chopped;
3801 }
3802 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3803         $where_clauses= array();
3804         $like_char='%';
3805         $table_name=$bean->object_name;
3806         foreach ($field_list[$module] as $field=>$parms) {
3807                 if(isset($values[$field]) && $values[$field] != "") {
3808                         $operator='like';
3809                         if (!empty($parms['operator'])) {
3810                                 $operator=$parms['operator'];
3811                         }
3812                         if (is_array($values[$field])) {
3813                                 $operator='in';
3814                                 $field_value='';
3815                                 foreach ($values[$field] as $key => $val) {
3816                                         if ($val != ' ' and $val != '') {
3817                                                 if (!empty($field_value)) {
3818                                                         $field_value.=',';
3819                                                 }
3820                                                 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3821                                         }
3822                                 }
3823                         } else {
3824                                 $field_value=$GLOBALS['db']->quote($values[$field]);
3825                         }
3826                         //set db_fields array.
3827                         if (!isset($parms['db_field']) )  {
3828                                 $parms['db_field'] = array($field);
3829                         }
3830                         if (isset($parms['my_items']) and $parms['my_items'] == true) {
3831                                 global $current_user;
3832                                 $field_value = $GLOBALS['db']->quote($current_user->id);
3833                                 $operator='=';
3834                         }
3835
3836                         $where='';
3837                         $itr=0;
3838                         if ($field_value != '') {
3839
3840                                 foreach ($parms['db_field'] as $db_field) {
3841                                         if (strstr($db_field,'.')===false) {
3842                                                 $db_field=$bean->table_name.".".$db_field;
3843                                         }
3844                                         if ($GLOBALS['db']->supports('case_sensitive') &&  isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3845                                                 $db_field='upper('.$db_field.")";
3846                                                 $field_value=strtoupper($field_value);
3847                                         }
3848
3849                                         $itr++;
3850                                         if (!empty($where)) {
3851                                                 $where .= " OR ";
3852                                         }
3853                                         switch (strtolower($operator)) {
3854                                                 case 'like' :
3855                                                         $where .=  $db_field . " like '".$field_value.$like_char."'";
3856                                                         break;
3857                                                 case 'in':
3858                                                         $where .=  $db_field . " in (".$field_value.')';
3859                                                         break;
3860                                                 case '=':
3861                                                         $where .=  $db_field . " = '".$field_value ."'";
3862                                                         break;
3863                                         }
3864                                 }
3865                         }
3866                         if (!empty($where)) {
3867                                 if ($itr>1) {
3868                                         array_push($where_clauses, '( '.$where.' )');
3869                                 } else {
3870                                         array_push($where_clauses, $where);
3871                                 }
3872                         }
3873                 }
3874         }
3875         if ($add_custom_fields) {
3876                 require_once('modules/DynamicFields/DynamicField.php');
3877                 $bean->setupCustomFields($module);
3878                 $bean->custom_fields->setWhereClauses($where_clauses);
3879         }
3880         return $where_clauses;
3881 }
3882
3883 function add_quotes($str) {
3884         return "'{$str}'";
3885 }
3886
3887 /**
3888  * This function will rebuild the config file
3889  * @param       $sugar_config
3890  * @param       $sugar_version
3891  * @return      bool true if successful
3892  */
3893 function rebuildConfigFile($sugar_config, $sugar_version) {
3894         // add defaults to missing values of in-memory sugar_config
3895         $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3896         // need to override version with default no matter what
3897         $sugar_config['sugar_version'] = $sugar_version;
3898
3899         ksort( $sugar_config );
3900
3901         if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3902                 return true;
3903         }
3904         else {
3905                 return false;
3906         }
3907 }
3908
3909 /**
3910  * getJavascriptSiteURL
3911  * This function returns a URL for the client javascript calls to access
3912  * the site.  It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3913  * are used to access the site.  Thus, the hostname in the URL returned may
3914  * not always match that of $sugar_config['site_url'].  Basically, the
3915  * assumption is that however the user accessed the website is how they
3916  * will continue to with subsequent javascript requests.  If the variable
3917  * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3918  * @return $site_url The url used to refer to the website
3919  */
3920 function getJavascriptSiteURL() {
3921         global $sugar_config;
3922         if(!empty($_SERVER['HTTP_REFERER'])) {
3923                 $url = parse_url($_SERVER['HTTP_REFERER']);
3924                 $replacement_url = $url['scheme']."://".$url['host'];
3925                 if(!empty($url['port']))
3926                 $replacement_url .= ':'.$url['port'];
3927                 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3928         } else {
3929                 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3930                 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3931                         $site_url = preg_replace('/^http\:/','https:',$site_url);
3932                 }
3933         }
3934         $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=".  $site_url);
3935         return $site_url;
3936 }
3937
3938 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3939 function add_squotes($str) {
3940         return "'" . $str . "'";
3941 }
3942
3943
3944 // recursive function to count the number of levels within an array
3945 function array_depth($array, $depth_count=-1, $depth_array=array()){
3946         $depth_count++;
3947         if (is_array($array)){
3948                 foreach ($array as $key => $value){
3949                         $depth_array[] = array_depth($value, $depth_count);
3950                 }
3951         }
3952         else{
3953                 return $depth_count;
3954         }
3955         foreach ($depth_array as $value){
3956                 $depth_count = $value > $depth_count ? $value : $depth_count;
3957         }
3958         return $depth_count;
3959 }
3960
3961 /**
3962  * Creates a new Group User
3963  * @param string $name Name of Group User
3964  * @return string GUID of new Group User
3965  */
3966 function createGroupUser($name) {
3967
3968
3969         $group = new User();
3970         $group->user_name       = $name;
3971         $group->last_name       = $name;
3972         $group->is_group        = 1;
3973         $group->deleted         = 0;
3974         $group->status          = 'Active'; // cn: bug 6711
3975         $group->setPreference('timezone', TimeDate::userTimezone());
3976         $group->save();
3977
3978         return $group->id;
3979 }
3980
3981 /*
3982  * Helper function to locate an icon file given only a name
3983  * Searches through the various paths for the file
3984  * @param string iconFileName   The filename of the icon
3985  * @return string Relative pathname of the located icon, or '' if not found
3986  */
3987
3988 function _getIcon($iconFileName)
3989 {
3990
3991         $iconName = "icon_{$iconFileName}.gif";
3992     $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3993
3994     //First try un-ucfirst-ing the icon name
3995     if ( empty($iconFound) )
3996                 $iconName = "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif";
3997         $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
3998
3999         //Next try removing the icon prefix
4000     if ( empty($iconFound) )
4001                 $iconName = "{$iconFileName}.gif";
4002                 $iconFound = SugarThemeRegistry::current()->getImageURL($iconName,false);
4003
4004         if ( empty($iconFound) )
4005                 $iconName = '';
4006
4007         return $iconName;
4008 }
4009 /**
4010  * Function to grab the correct icon image for Studio
4011  * @param string $iconFileName Name of the icon file
4012  * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
4013  * @param string $width Width of image
4014  * @param string $height Height of image
4015  * @param string $align Alignment of image
4016  * @param string $alt Alt tag of image
4017  * @return string $string <img> tag with corresponding image
4018  */
4019
4020 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline', $alt='' )
4021 {
4022         global $app_strings, $theme;
4023
4024     $iconName = _getIcon($iconFileName);
4025         if(empty($iconName)){
4026             $iconName = _getIcon($altFileName);
4027             if (empty($iconName))
4028             {
4029             return $app_strings['LBL_NO_IMAGE'];
4030             }
4031         }
4032         return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4033 }
4034
4035 /**
4036  * Function to grab the correct icon image for Dashlets Dialog
4037  * @param string $filename Location of the icon file
4038  * @param string $module Name of the module to fall back onto if file does not exist
4039  * @param string $width Width of image
4040  * @param string $height Height of image
4041  * @param string $align Alignment of image
4042  * @param string $alt Alt tag of image
4043  * @return string $string <img> tag with corresponding image
4044  */
4045
4046 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle',$alt=''){
4047         global $app_strings, $theme;
4048         $iconName = _getIcon($module . "_32");
4049         if (empty($iconName))
4050         {
4051                 $iconName = _getIcon($module);
4052         }
4053         if(empty($iconName)){
4054                 return $app_strings['LBL_NO_IMAGE'];
4055         }
4056         return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4057 }
4058
4059 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
4060 function html_entity_decode_utf8($string)
4061 {
4062     static $trans_tbl;
4063     // replace numeric entities
4064     //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
4065     $string = preg_replace('~&#x0*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
4066     $string = preg_replace('~&#0*([0-9]+);~e', 'code2utf(\\1)', $string);
4067     // replace literal entities
4068     if (!isset($trans_tbl))
4069     {
4070         $trans_tbl = array();
4071         foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
4072             $trans_tbl[$key] = utf8_encode($val);
4073     }
4074     return strtr($string, $trans_tbl);
4075 }
4076
4077 // Returns the utf string corresponding to the unicode value
4078 function code2utf($num)
4079 {
4080     if ($num < 128) return chr($num);
4081     if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
4082     if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4083     if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
4084     return '';
4085 }
4086
4087 function str_split_php4($string, $length = 1) {
4088         $string_length = strlen($string);
4089         $return = array();
4090         $cursor = 0;
4091         if ($length > $string_length) {
4092                 // use the string_length as the string is shorter than the length
4093                 $length = $string_length;
4094         }
4095         for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
4096                 $return[] = substr($string, $cursor, $length);
4097         }
4098         return $return;
4099 }
4100
4101 if (version_compare(phpversion(), '5.0.0', '<')) {
4102         function str_split($string, $length = 1) {
4103                 return str_split_php4($string, $length);
4104         }
4105 }
4106
4107 /*
4108  * @deprecated use DBManagerFactory::isFreeTDS
4109  */
4110 function is_freetds()
4111 {
4112     return DBManagerFactory::isFreeTDS();
4113 }
4114
4115 /**
4116  * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
4117  *
4118  * @todo this won't work completely right until we impliment css compression and combination
4119  *       for now, we'll just include the last css file found.
4120  *
4121  * @return chart.css file to use
4122  */
4123 function chartStyle()
4124 {
4125     return SugarThemeRegistry::current()->getCSSURL('chart.css');
4126 }
4127
4128 /**
4129  * Chart dashlet helper functions that returns the correct XML color file for charts,
4130  * dependent on the current theme.
4131  *
4132  * @return sugarColors.xml to use
4133  */
4134 function chartColors()
4135 {
4136         if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
4137         return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
4138     return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
4139 }
4140 /* End Chart Dashlet helper functions */
4141
4142 /**
4143  * This function is designed to set up the php enviroment
4144  * for AJAX requests.
4145  */
4146
4147 function ajaxInit() {
4148         ini_set('display_errors', 'false');
4149 }
4150
4151 /**
4152  * Returns an absolute path from the given path, determining if it is relative or absolute
4153  *
4154  * @param  string $path
4155  * @return string
4156  */
4157 function getAbsolutePath(
4158     $path,
4159     $currentServer = false
4160     )
4161 {
4162     $path = trim($path);
4163
4164     // try to match absolute paths like \\server\share, /directory or c:\
4165     if ( ( substr($path,0,2) == '\\\\' )
4166             || ( $path[0] == '/' )
4167             || preg_match('/^[A-z]:/i',$path)
4168             || $currentServer )
4169         return $path;
4170
4171     return getcwd().'/'.$path;
4172 }
4173
4174 /**
4175  * Returns the bean object of the given module
4176  *
4177  * @deprecated use SugarModule::loadBean() instead
4178  * @param  string $module
4179  * @return object
4180  */
4181 function loadBean(
4182     $module
4183     )
4184 {
4185     return SugarModule::get($module)->loadBean();
4186 }
4187
4188
4189 /**
4190  * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4191  */
4192 function isTouchScreen()
4193 {
4194     $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4195
4196     // first check if we have forced use of the touch enhanced interface
4197     if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4198         return true;
4199     }
4200
4201     // next check if we should use the touch interface with our device
4202     if ( strpos($ua, 'ipad') !== false ) {
4203         return true;
4204     }
4205
4206     return false;
4207 }
4208
4209 /**
4210  * Returns the shortcut keys to access the shortcut links.  Shortcut
4211  * keys vary depending on browser versions and operating systems.
4212  * @return String value of the shortcut keys
4213  */
4214 function get_alt_hot_key() {
4215         $ua = '';
4216     if ( isset($_SERVER['HTTP_USER_AGENT']) )
4217         $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4218         $isMac = strpos($ua, 'mac') !== false;
4219         $isLinux = strpos($ua, 'linux') !== false;
4220
4221         if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4222            if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4223                   return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4224            }
4225         }
4226         return $isMac ? 'Ctrl+' : 'Alt+';
4227 }
4228
4229 function can_start_session(){
4230         if(!empty($_GET['PHPSESSID'])) {
4231            return true;
4232         }
4233         $session_id = session_id();
4234         return empty($session_id) ? true : false;
4235 }
4236
4237 function load_link_class($properties){
4238         $class = 'Link2';
4239         if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4240         require_once($properties['link_file']);
4241         $class = $properties['link_class'];
4242     }
4243     return $class;
4244 }
4245
4246
4247 function inDeveloperMode()
4248 {
4249     return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4250 }
4251
4252 /**
4253  * Filter the protocol list for inbound email accounts.
4254  *
4255  * @param array $protocol
4256  */
4257 function filterInboundEmailPopSelection($protocol)
4258 {
4259     if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4260     {
4261         if( isset($protocol['pop3']) )
4262                         unset($protocol['pop3']);
4263     }
4264     else
4265         $protocol['pop3'] = 'POP3';
4266
4267     return $protocol;
4268 }
4269
4270 /**
4271  * The function is used because currently we are not supporting mbstring.func_overload
4272  * 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.
4273  * 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.
4274 * @returns the substred strings.
4275  */
4276 function sugar_substr($string, $length, $charset='UTF-8')
4277 {
4278     if(mb_strlen($string,$charset) > $length) {
4279         $string = trim(mb_substr(trim($string),0,$length,$charset));
4280     }
4281     return $string;
4282 }
4283
4284 /**
4285  * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4286  * This will work even without setting the mbstring.*encoding
4287  */
4288 function sugar_ucfirst($string, $charset='UTF-8') {
4289     return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4290 }
4291
4292
4293 /**
4294  *
4295  */
4296 function unencodeMultienum($string) {
4297         if (is_array($string))
4298         {
4299            return $string;
4300         }
4301         if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4302           $string = substr(substr($string, 1), 0, strlen($string) -2);
4303         }
4304
4305         return explode('^,^', $string);
4306 }
4307
4308 function encodeMultienumValue($arr) {
4309     if (!is_array($arr))
4310         return $arr;
4311
4312     if (empty($arr))
4313         return "";
4314
4315         $string = "^" . implode('^,^', $arr) . "^";
4316
4317     return $string;
4318 }
4319
4320 /**
4321  * create_export_query is used for export and massupdate
4322  * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4323  * This function will correct the where clause and output necessary join condition for them
4324  * @param $module: the module name
4325  * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4326  * @param $where: where clauses
4327  * @return $ret_array['where']: corrected where clause
4328  * @return $ret_array['join']: extra join condition
4329  */
4330 function create_export_query_relate_link_patch($module, $searchFields, $where){
4331         if(file_exists('modules/'.$module.'/SearchForm.html')){
4332                 $ret_array['where'] = $where;
4333                 return $ret_array;
4334         }
4335         $seed = loadBean($module);
4336     foreach($seed->field_defs as $name=>$field)
4337         {
4338
4339                 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4340                         $seed->load_relationship($field['link']);
4341                         $params = array();
4342                         if(empty($join_type))
4343                         {
4344                                 $params['join_type'] = ' LEFT JOIN ';
4345                         }
4346                         else
4347                         {
4348                                 $params['join_type'] = $join_type;
4349                         }
4350                         if(isset($data['join_name']))
4351                         {
4352                                 $params['join_table_alias'] = $field['join_name'];
4353                         }
4354                         else
4355                         {
4356                                 $params['join_table_alias']     = 'join_'.$field['name'];
4357
4358                         }
4359                         if(isset($data['join_link_name']))
4360                         {
4361                                 $params['join_table_link_alias'] = $field['join_link_name'];
4362                         }
4363                         else
4364                         {
4365                                 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4366                         }
4367                         $join = $seed->$field['link']->getJoin($params, true);
4368                         $join_table_alias = 'join_'.$field['name'];
4369                         if(isset($field['db_concat_fields'])){
4370                                 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4371                                 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4372                         }else{
4373                                 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4374                         }
4375                 }
4376         }
4377         $ret_array = array('where'=>$where, 'join'=>$join['join']);
4378         return $ret_array;
4379 }
4380
4381 /**
4382   * 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.
4383   * @Depends on QuickRepairAndRebuild.php
4384   * @Relate bug 30642  ,23177
4385   */
4386 function clearAllJsAndJsLangFilesWithoutOutput(){
4387                 global $current_language , $mod_strings;
4388                 $MBmodStrings = $mod_strings;
4389         $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4390         include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4391         $repair = new RepairAndClear();
4392         $repair->module_list = array();
4393                 $repair->show_output = false;
4394                 $repair->clearJsLangFiles();
4395                 $repair->clearJsFiles();
4396                 $mod_strings = $MBmodStrings;
4397 }
4398
4399 /**
4400  * This function will allow you to get a variable value from query string
4401  */
4402 function getVariableFromQueryString($variable, $string){
4403         $matches = array();
4404         $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4405         if($number){
4406                 return $matches[1];
4407         }
4408         else{
4409                 return false;
4410         }
4411 }
4412
4413 /**
4414  * should_hide_iframes
4415  * This is a helper method to determine whether or not to show iframes (My Sites) related
4416  * information in the application.
4417  *
4418  * @return boolean flag indicating whether or not iframes module should be hidden
4419  */
4420 function should_hide_iframes() {
4421    //Remove the MySites module
4422    if(file_exists('modules/iFrames/iFrame.php')) {
4423         if(!class_exists("iFrame")) {
4424                 require_once('modules/iFrames/iFrame.php');
4425         }
4426         return false;
4427    }
4428    return true;
4429 }
4430
4431 /**
4432  * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4433  *
4434  * @param string $version
4435  * @return string RC, BETA, GA
4436  */
4437 function getVersionStatus($version){
4438         if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4439                 return strtoupper($matches[1]);
4440         }else{
4441                 return 'GA';
4442         }
4443 }
4444
4445 /**
4446  * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4447  * 5.5.1RC1 then return 5.5.1
4448  *
4449  * @param string $version
4450  * @return version
4451  */
4452 function getMajorMinorVersion($version){
4453         if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4454                 $version = $matches2[1];
4455                 $arr = explode('.', $version);
4456                 if(count($arr) > 2){
4457                         if($arr[2] == '0'){
4458                                 $version = substr($version, 0, 3);
4459                         }
4460                 }
4461         }
4462         return $version;
4463 }
4464
4465 /**
4466  * Return string composed of seconds & microseconds of current time, without dots
4467  * @return string
4468  */
4469 function sugar_microtime()
4470 {
4471         $now = explode(' ', microtime());
4472         $unique_id = $now[1].str_replace('.', '', $now[0]);
4473         return $unique_id;
4474 }
4475
4476 /**
4477  * Extract urls from a piece of text
4478  * @param  $string
4479  * @return array of urls found in $string
4480  */
4481 function getUrls($string)
4482 {
4483         $lines = explode("<br>", trim($string));
4484         $urls = array();
4485         foreach($lines as $line){
4486         $regex = '/http?\:\/\/[^\" ]+/i';
4487         preg_match_all($regex, $line, $matches);
4488         foreach($matches[0] as $match){
4489                 $urls[] = $match;
4490         }
4491         }
4492     return $urls;
4493 }
4494
4495
4496 /**
4497  * Sanitize image file from hostile content
4498  * @param string $path Image file
4499  * @param bool $jpeg  Accept only JPEGs?
4500  */
4501 function verify_image_file($path, $jpeg = false)
4502 {
4503         if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4504         $img = imagecreatefromstring(file_get_contents($path));
4505         if(!$img) {
4506             return false;
4507         }
4508         $img_size = getimagesize($path);
4509                 $filetype = $img_size['mime'];
4510                 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4511         if($filetype == "image/jpeg" || $jpeg) {
4512             ob_start();
4513             imagejpeg($img);
4514             $image = ob_get_clean();
4515             // not writing directly because imagejpeg does not work with streams
4516             if(file_put_contents($path, $image)) {
4517                 return true;
4518             }
4519         } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4520                 imagealphablending($img, true);
4521                 imagesavealpha($img, true);
4522                 ob_start();
4523             imagepng($img);
4524             $image = ob_get_clean();
4525             if(file_put_contents($path, $image)) {
4526                 return true;
4527             }
4528         } else {
4529                 return false;
4530         }
4531         } else {
4532             // check image manually
4533         $fp = fopen($path, "rb");
4534         if(!$fp) return false;
4535         $data = '';
4536         // read the whole file in chunks
4537         while(!feof($fp)) {
4538             $data .= fread($fp,8192);
4539         }
4540
4541             fclose($fp);
4542             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",
4543                  $data, $m)) {
4544                 $GLOBALS['log']->fatal("Found {$m[0]} in $path, not allowing upload");
4545                 return false;
4546             }
4547             return true;
4548         }
4549         return false;
4550 }
4551
4552 /**
4553  * Verify uploaded image
4554  * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4555  * @param string $path  Image path
4556  * @param bool $jpeg_only  Accept only JPEGs?
4557  */
4558 function verify_uploaded_image($path, $jpeg_only = false)
4559 {
4560     $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4561     if(!$jpeg_only) {
4562         $supportedExtensions['png'] = 'image/png';
4563     }
4564
4565     if(!file_exists($path) || !is_file($path)) {
4566             return false;
4567         }
4568
4569         $img_size = getimagesize($path);
4570         $filetype = $img_size['mime'];
4571         $ext = end(explode(".", $path));
4572         if(substr_count('..', $path) > 0 || ($ext !== $path && !in_array(strtolower($ext), array_keys($supportedExtensions))) ||
4573             !in_array($filetype, array_values($supportedExtensions))) {
4574                 return false;
4575         }
4576     return verify_image_file($path, $jpeg_only);
4577 }
4578
4579 function cmp_beans($a, $b)
4580 {
4581     global $sugar_web_service_order_by;
4582     //If the order_by field is not valid, return 0;
4583     if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4584         return 0;
4585     }
4586     if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4587         || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4588     {
4589         return 0;
4590     }
4591     if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4592     {
4593         return -1;
4594     } else {
4595         return 1;
4596     }
4597 }
4598
4599 function order_beans($beans, $field_name)
4600 {
4601     //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4602     global $sugar_web_service_order_by;
4603     $sugar_web_service_order_by = $field_name;
4604     usort($beans, "cmp_beans");
4605     return $beans;
4606 }
4607
4608 /**
4609  * Return search like string
4610  * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
4611  * @param string $str  string to be searched
4612  * @param string $like_char  Database like character, usually '%'
4613  * @return string Returns a string to be searched in db query
4614  */
4615 function sql_like_string($str, $like_char, $wildcard = '%', $appendWildcard = true) {
4616
4617     // override default wildcard character
4618     if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
4619         strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1) {
4620         $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
4621     }
4622
4623     // add wildcard at the beginning of the search string
4624     if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
4625         $GLOBALS['sugar_config']['search_wildcard_infront'] == true) {
4626         if (substr($str,0,1) <> $wildcard)
4627           $str = $wildcard.$str;
4628     }
4629
4630     // add wildcard at the end of search string (default)
4631     if ($appendWildcard) {
4632         if(substr($str,-1) <> $wildcard) {
4633             $str .= $wildcard;
4634         }
4635     }
4636
4637     return str_replace($wildcard, $like_char, $str);
4638 }
4639
4640 //check to see if custom utils exists
4641 if(file_exists('custom/include/custom_utils.php')){
4642         include_once('custom/include/custom_utils.php');
4643 }
4644
4645 //check to see if custom utils exists in Extension framework
4646 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4647     include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4648 }
4649 /**
4650  * @param $input - the input string to sanitize
4651  * @param int $quotes - use quotes
4652  * @param string $charset - the default charset
4653  * @param bool $remove - strip tags or not
4654  * @return string - the sanitized string
4655  */
4656 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4657 {
4658     return htmlentities($input, $quotes, $charset);
4659 }
4660
4661 /**
4662  * @return string - the full text search engine name
4663  */
4664 function getFTSEngineType()
4665 {
4666     if (isset($GLOBALS['sugar_config']['full_text_engine']) && is_array($GLOBALS['sugar_config']['full_text_engine'])) {
4667         foreach ($GLOBALS['sugar_config']['full_text_engine'] as $name => $defs) {
4668             return $name;
4669         }
4670     }
4671     return '';
4672 }
4673
4674 /**
4675  * @param string $optionName - name of the option to be retrieved from app_list_strings
4676  * @return array - the array to be used in option element
4677  */
4678 function getFTSBoostOptions($optionName)
4679 {
4680     if (isset($GLOBALS['app_list_strings'][$optionName])) {
4681         return $GLOBALS['app_list_strings'][$optionName];
4682     }
4683     else {
4684         return array();
4685     }
4686 }
4687
4688 /**
4689  * utf8_recursive_encode
4690  *
4691  * This function walks through an Array and recursively calls utf8_encode on the
4692  * values of each of the elements.
4693  *
4694  * @param $data Array of data to encode
4695  * @return utf8 encoded Array data
4696  */
4697 function utf8_recursive_encode($data)
4698 {
4699     $result = array();
4700     foreach($data as $key=>$val) {
4701         if(is_array($val)) {
4702            $result[$key] = utf8_recursive_encode($val);
4703         } else {
4704            $result[$key] = utf8_encode($val);
4705         }
4706     }
4707     return $result;
4708 }
4709
4710 /**
4711  * get_language_header
4712  *
4713  * This is a utility function for 508 Compliance.  It returns the lang=[Current Language] text string used
4714  * inside the <html> tag.  If no current language is specified, it defaults to lang='en'.
4715  *
4716  * @return String The lang=[Current Language] markup to insert into the <html> tag
4717  */
4718 function get_language_header()
4719 {
4720     return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
4721 }
4722
4723
4724 /**
4725  * get_custom_file_if_exists
4726  *
4727  * This function handles the repetitive code we have where we first check if a file exists in the
4728  * custom directory to determine whether we should load it, require it, include it, etc.  This function returns the
4729  * path of the custom file if it exists.  It basically checks if custom/{$file} exists and returns this path if so;
4730  * otherwise it return $file
4731  *
4732  * @param $file String of filename to check
4733  * @return $file String of filename including custom directory if found
4734  */
4735 function get_custom_file_if_exists($file)
4736 {
4737     return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
4738 }
4739
4740
4741 /**
4742  * get_help_url
4743  *
4744  * This will return the URL used to redirect the user to the help documentation.
4745  * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
4746  * in config.php or config_override.php.
4747  *
4748  * @param string $send_edition
4749  * @param string $send_version
4750  * @param string $send_lang
4751  * @param string $send_module
4752  * @param string $send_action
4753  * @param string $dev_status
4754  * @param string $send_key
4755  * @param string $send_anchor
4756  * @return string the completed help URL
4757  */
4758 function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '') {
4759     global $sugar_config;
4760
4761     if (!empty($sugar_config['custom_help_url'])) {
4762         $sendUrl = $sugar_config['custom_help_url'];
4763     } else {
4764         if (!empty($sugar_config['custom_help_base_url'])) {
4765             $baseUrl= $sugar_config['custom_help_base_url'];
4766         } else {
4767             $baseUrl = "http://www.sugarcrm.com/crm/product_doc.php";
4768         }
4769         $sendUrl = $baseUrl . "?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
4770         if(!empty($send_anchor)) {
4771             $sendUrl .= "&anchor=".$send_anchor;
4772         }
4773     }
4774     return $sendUrl;
4775 }
4776
4777 /**
4778  * generateETagHeader
4779  *
4780  * This function generates the necessary cache headers for using ETags with dynamic content. You
4781  * simply have to generate the ETag, pass it in, and the function handles the rest.
4782  *
4783  * @param string $etag ETag to use for this content.
4784  */
4785 function generateETagHeader($etag){
4786         header("cache-control:");
4787         header('Expires: ');
4788         header("ETag: " . $etag);
4789         header("Pragma:");
4790         if(isset($_SERVER["HTTP_IF_NONE_MATCH"])){
4791                 if($etag == $_SERVER["HTTP_IF_NONE_MATCH"]){
4792                         ob_clean();
4793                         header("Status: 304 Not Modified");
4794                         header("HTTP/1.0 304 Not Modified");
4795                         die();
4796                 }
4797         }
4798 }