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