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