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