Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

include/utils.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

Code
1
<?php
2
/*
3
 *
4
 * SugarCRM Community Edition is a customer relationship management program developed by
5
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
6
 *
7
 * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
8
 * Copyright (C) 2011 - 2016 SalesAgility Ltd.
9
 *
10
 * This program is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU Affero General Public License version 3 as published by the
12
 * Free Software Foundation with the addition of the following permission added
13
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
14
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
15
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
16
 *
17
 * This program is distributed in the hope that it will be useful, but WITHOUT
18
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
20
 * details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License along with
23
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
24
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25
 * 02110-1301 USA.
26
 *
27
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
28
 * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected].
29
 *
30
 * The interactive user interfaces in modified source and object code versions
31
 * of this program must display Appropriate Legal Notices, as required under
32
 * Section 5 of the GNU Affero General Public License version 3.
33
 *
34
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
35
 * these Appropriate Legal Notices must retain the display of the "Powered by
36
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
37
 * reasonably feasible for  technical reasons, the Appropriate Legal Notices must
38
 * display the words  "Powered by SugarCRM" and "Supercharged by SuiteCRM".
39
 */
40
41
/*********************************************************************************
42
 * Description:  Includes generic helper functions used throughout the application.
43
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
44
 * All Rights Reserved.
45
 * Contributor(s): ______________________________________..
46
 ********************************************************************************/
47
require_once 'include/SugarObjects/SugarConfig.php';
48
require_once 'include/utils/security_utils.php';
49
50
function make_sugar_config(&$sugar_config)
51
{
52
    /* used to convert non-array config.php file to array format */
53
    global $admin_export_only;
54
    global $cache_dir;
55
    global $calculate_response_time;
56
    global $create_default_user;
57
    global $dateFormats;
58
    global $dbconfig;
59
    global $dbconfigoption;
60
    global $default_action;
61
    global $default_charset;
62
    global $default_currency_name;
63
    global $default_currency_symbol;
64
    global $default_currency_iso4217;
65
    global $defaultDateFormat;
66
    global $default_language;
67
    global $default_module;
68
    global $default_password;
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' => 0755,
139
            'chown' => '',
140
            'chgrp' => '',
141
        ),
142
        'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
143
        'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
144
        'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
145
        'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
146
        'disable_export' => empty($disable_export) ? false : $disable_export,
147
        'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
148
        'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
149
        'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
150
        'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
151
        'host_name' => empty($host_name) ? 'localhost' : $host_name,
152
        'import_dir' => $import_dir,  // this must be set!!
153
        'import_max_records_per_file' => 100,
154
        'import_max_records_total_limit' => '',
155
        'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
156
        'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
157
        'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
158
        'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
159
        'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
160
        'name_formats' => empty($nameFormats) ? array(
161
            's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
162
            'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s',
163
        ) : $nameFormats,
164
        'portal_view' => 'single_user',
165
        'resource_management' => array(
166
            'special_query_limit' => 50000,
167
            'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
168
            'default_limit' => 1000,
169
        ),
170
        'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
171
        'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
172
        'session_dir' => $session_dir,  // this must be set!!
173
        'site_url' => empty($site_URL) ? $site_url : $site_URL,  // this must be set!!
174
        'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
175
        'showThemePicker' => true,
176
        'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
177
        'time_formats' => empty($timeFormats) ? array(
178
            'H:i' => '23:00', 'h:ia' => '11:00 pm', 'h:iA' => '11:00PM',
179
            'H.i' => '23.00', 'h.ia' => '11.00 pm', 'h.iA' => '11.00PM', ) : $timeFormats,
180
        'tmp_dir' => $tmp_dir,  // this must be set!!
181
        'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
182
        'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
183
        'upload_badext' => empty($upload_badext) ? array(
184
            'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
185
            'asp', 'cfm', 'js', 'vbs', 'html', 'htm', ) : $upload_badext,
186
        'upload_dir' => $upload_dir,  // this must be set!!
187
        'upload_maxsize' => empty($upload_maxsize) ? 30000000 : $upload_maxsize,
188
        'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
189
        'lock_homepage' => false,
190
        'lock_subpanels' => false,
191
        'max_dashlets_homepage' => 15,
192
        'dashlet_display_row_options' => array('1', '3', '5', '10'),
193
        'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
194
        'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs,
195
        'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
196
        'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
197
        'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
198
        'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
199
        'default_call_status' => 'Planned',
200
        'js_lang_version' => 1,
201
        'passwordsetting' => empty($passwordsetting) ? array(
202
            'SystemGeneratedPasswordON' => '',
203
            'generatepasswordtmpl' => '',
204
            'lostpasswordtmpl' => '',
205
            'forgotpasswordON' => true,
206
            'linkexpiration' => '1',
207
            'linkexpirationtime' => '30',
208
            'linkexpirationtype' => '1',
209
            'systexpiration' => '0',
210
            'systexpirationtime' => '',
211
            'systexpirationtype' => '0',
212
            'systexpirationlogin' => '',
213
        ) : $passwordsetting,
214
        'use_sprites' => function_exists('imagecreatetruecolor'),
215
        'search_wildcard_infront' => false,
216
        'search_wildcard_char' => '%',
217
        'jobs' => array(
218
            'min_retry_interval' => 60, // minimal job retry delay
219
            'max_retries' => 5, // how many times to retry the job
220
            'timeout' => 86400, // how long a job may spend as running before being force-failed
221
            'soft_lifetime' => 7, // how many days until job record will be soft deleted after completion
222
            'hard_lifetime' => 21, // how many days until job record will be purged from DB
223
        ),
224
        'cron' => array(
225
            'max_cron_jobs' => 10, // max jobs per cron schedule run
226
            'max_cron_runtime' => 60, // max runtime for cron jobs
227
            'min_cron_interval' => 30, // minimal interval between cron jobs
228
        ),
229
    );
230
}
231
232
function get_sugar_config_defaults()
233
{
234
    global $locale;
235
    /*
236
     * used for getting base values for array style config.php.  used by the
237
     * installer and to fill in new entries on upgrades.  see also:
238
     * sugar_config_union
239
     */
240
241
    $sugar_config_defaults = array(
242
        'admin_export_only' => false,
243
        'export_delimiter' => ',',
244
        'export_excel_compatible' => false,
245
        'cache_dir' => 'cache/',
246
        'calculate_response_time' => true,
247
        'create_default_user' => false,
248
        'chartEngine' => 'Jit',
249
        'date_formats' => array(
250
            'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
251
            'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
252
            'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010', ),
253
        'name_formats' => array(
254
            's f l' => 's f l', 'f l' => 'f l', 's l' => 's l', 'l, s f' => 'l, s f',
255
            'l, f' => 'l, f', 's l, f' => 's l, f', 'l s f' => 'l s f', 'l f s' => 'l f s',
256
        ),
257
        'dbconfigoption' => array(
258
            'persistent' => true,
259
            'autofree' => false,
260
            'debug' => 0,
261
            'ssl' => false, ),
262
        'default_action' => 'index',
263
        'default_charset' => return_session_value_or_default('default_charset',
264
            'UTF-8'),
265
        'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
266
        'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
267
        'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
268
        'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
269
        'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
270
        'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
271
        'default_date_format' => 'm/d/Y',
272
        'default_locale_name_format' => 's f l',
273
        'default_export_charset' => 'UTF-8',
274
        'default_language' => return_session_value_or_default('default_language',
275
            'en_us'),
276
        'default_module' => 'Home',
277
        'default_password' => '',
278
        'default_permissions' => array(
279
            'dir_mode' => 02770,
280
            'file_mode' => 0755,
281
            'user' => '',
282
            'group' => '',
283
        ),
284
        'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
285
        'default_time_format' => 'h:ia',
286
        'default_user_is_admin' => false,
287
        'default_user_name' => '',
288
        'disable_export' => false,
289
        'disable_persistent_connections' => return_session_value_or_default('disable_persistent_connections',
290
            'false'),
291
        'display_email_template_variable_chooser' => false,
292
        'display_inbound_email_buttons' => false,
293
        'dump_slow_queries' => false,
294
        'email_address_separator' => ',', // use RFC2368 spec unless we have a noncompliant email client
295
        'email_default_editor' => 'html',
296
        'email_default_client' => 'sugar',
297
        'email_default_delete_attachments' => true,
298
        'history_max_viewed' => 50,
299
        'installer_locked' => true,
300
        'import_max_records_per_file' => 100,
301
        'import_max_records_total_limit' => '',
302
        'languages' => array('en_us' => 'English (US)'),
303
        'large_scale_test' => false,
304
        'list_max_entries_per_page' => 20,
305
        'list_max_entries_per_subpanel' => 10,
306
        'lock_default_user_name' => false,
307
        'log_memory_usage' => false,
308
        'portal_view' => 'single_user',
309
        'resource_management' => array(
310
            'special_query_limit' => 50000,
311
            'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
312
            'default_limit' => 1000,
313
        ),
314
        'require_accounts' => true,
315
        'rss_cache_time' => return_session_value_or_default('rss_cache_time',
316
            '10800'),
317
        'save_query' => 'all',
318
        'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
319
        'showThemePicker' => true,
320
        'slow_query_time_msec' => '100',
321
        'sugarbeet' => true,
322
        'time_formats' => array(
323
            'H:i' => '23:00', 'h:ia' => '11:00pm', 'h:iA' => '11:00PM', 'h:i a' => '11:00 pm', 'h:i A' => '11:00 PM',
324
            'H.i' => '23.00', 'h.ia' => '11.00pm', 'h.iA' => '11.00PM', 'h.i a' => '11.00 pm', 'h.i A' => '11.00 PM', ),
325
        'tracker_max_display_length' => 15,
326
        'translation_string_prefix' => return_session_value_or_default('translation_string_prefix', false),
327
        'upload_badext' => array(
328
            'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
329
            'asp', 'cfm', 'js', 'vbs', 'html', 'htm', 'phtml', ),
330
        'upload_maxsize' => 30000000,
331
        'import_max_execution_time' => 3600,
332
//	'use_php_code_json' => returnPhpJsonStatus(),
333
        'verify_client_ip' => true,
334
        'js_custom_version' => '',
335
        'js_lang_version' => 1,
336
        'lead_conv_activity_opt' => 'donothing',
337
        '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
            'show_completed_by_default' => true,
356
            'editview_width' => 990,
357
            'editview_height' => 485,
358
            'day_timestep' => 15,
359
            'week_timestep' => 30,
360
            'items_draggable' => true,
361
            'items_resizable' => true,
362
            'enable_repeat' => true,
363
            'max_repeat_count' => 1000,
364
        ),
365
        'passwordsetting' => empty($passwordsetting) ? array(
366
            'SystemGeneratedPasswordON' => '',
367
            'generatepasswordtmpl' => '',
368
            'lostpasswordtmpl' => '',
369
            'forgotpasswordON' => false,
370
            'linkexpiration' => '1',
371
            'linkexpirationtime' => '30',
372
            'linkexpirationtype' => '1',
373
            'systexpiration' => '0',
374
            'systexpirationtime' => '',
375
            'systexpirationtype' => '0',
376
            'systexpirationlogin' => '',
377
        ) : $passwordsetting,
378
        'use_real_names' => true,
379
380
        'search_wildcard_infront' => false,
381
        'search_wildcard_char' => '%',
382
        'jobs' => array(
383
            'min_retry_interval' => 30, // 30 seconds minimal job retry
384
            'max_retries' => 5, // how many times to retry the job
385
            'timeout' => 86400, // how long a job may spend as running before being force-failed
386
        ),
387
        'cron' => array(
388
            'max_cron_jobs' => 10, // max jobs per cron schedule run
389
            'max_cron_runtime' => 30, // max runtime for cron jobs
390
            'min_cron_interval' => 30, // minimal interval between cron jobs
391
        ),
392
    );
393
394
    if (!is_object($locale)) {
395
        $locale = new Localization();
396
    }
397
398
    $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
399
400
    $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
401
402
    return $sugar_config_defaults;
403
}
404
405
/**
406
 * @deprecated use SugarView::getMenu() instead
407
 */
408
function load_menu($path)
409
{
410
    global $module_menu;
411
412
    if (file_exists($path.'Menu.php')) {
413
        require $path.'Menu.php';
414
    }
415
    if (file_exists('custom/'.$path.'Ext/Menus/menu.ext.php')) {
416
        require 'custom/'.$path.'Ext/Menus/menu.ext.php';
417
    }
418
    if (file_exists('custom/application/Ext/Menus/menu.ext.php')) {
419
        require 'custom/application/Ext/Menus/menu.ext.php';
420
    }
421
422
    return $module_menu;
423
}
424
425
/**
426
 * get_notify_template_file
427
 * This function will return the location of the email notifications template to use.
428
 *
429
 * @return string relative file path to email notifications template file
430
 */
431
function get_notify_template_file($language)
432
{
433
    /*
434
     * Order of operation:
435
     * 1) custom version of specified language
436
     * 2) stock version of specified language
437
     * 3) custom version of en_us template
438
     * 4) stock en_us template
439
     */
440
441
    // set $file to the base code template so it's set if none of the conditions pass
442 2
    $file = 'include/language/en_us.notify_template.html';
443
444 2
    if (file_exists("custom/include/language/{$language}.notify_template.html")) {
445
        $file = "custom/include/language/{$language}.notify_template.html";
446 2
    } elseif (file_exists("include/language/{$language}.notify_template.html")) {
447 2
        $file = "include/language/{$language}.notify_template.html";
448
    } elseif (file_exists('custom/include/language/en_us.notify_template.html')) {
449
        $file = 'custom/include/language/en_us.notify_template.html';
450
    }
451
452 2
    return $file;
453
}
454
455
function sugar_config_union($default, $override)
456
{
457
    // a little different then array_merge and array_merge_recursive.  we want
458
    // the second array to override the first array if the same value exists,
459
    // otherwise merge the unique keys.  it handles arrays of arrays recursively
460
    // might be suitable for a generic array_union
461
    if (!is_array($override)) {
462
        $override = array();
463
    }
464
    foreach ($default as $key => $value) {
465
        if (!array_key_exists($key, $override)) {
466
            $override[$key] = $value;
467
        } elseif (is_array($key)) {
468
            $override[$key] = sugar_config_union($value, $override[$key]);
469
        }
470
    }
471
472
    return $override;
473
}
474
475
function make_not_writable($file)
476
{
477
    // Returns true if the given file/dir has been made not writable
478
    $ret_val = false;
479
    if (is_file($file) || is_dir($file)) {
480
        if (!is_writable($file)) {
481
            $ret_val = true;
482
        } else {
483
            $original_fileperms = fileperms($file);
484
485
            // take away writable permissions
486
            $new_fileperms = $original_fileperms & ~0x0092;
487
            @sugar_chmod($file, $new_fileperms);
488
489
            if (!is_writable($file)) {
490
                $ret_val = true;
491
            }
492
        }
493
    }
494
495
    return $ret_val;
496
}
497
498
/** This function returns the name of the person.
499
 * It currently returns "first last".  It should not put the space if either name is not available.
500
 * It should not return errors if either name is not available.
501
 * If no names are present, it will return ""
502
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
503
 * All Rights Reserved.
504
 * Contributor(s): ______________________________________..
505
 */
506
function return_name($row, $first_column, $last_column)
507
{
508
    $first_name = '';
509
    $last_name = '';
510
    $full_name = '';
511
512
    if (isset($row[$first_column])) {
513
        $first_name = stripslashes($row[$first_column]);
514
    }
515
516
    if (isset($row[$last_column])) {
517
        $last_name = stripslashes($row[$last_column]);
518
    }
519
520
    $full_name = $first_name;
521
522
    // If we have a first name and we have a last name
523
    if ($full_name != '' && $last_name != '') {
524
        // append a space, then the last name
525
        $full_name .= ' '.$last_name;
526
    } // If we have no first name, but we have a last name
527
    elseif ($last_name != '') {
528
        // append the last name without the space.
529
        $full_name .= $last_name;
530
    }
531
532
    return $full_name;
533
}
534
535
function get_languages()
536
{
537
    global $sugar_config;
538
    $lang = $sugar_config['languages'];
539
    if (!empty($sugar_config['disabled_languages'])) {
540
        foreach (explode(',', $sugar_config['disabled_languages']) as $disable) {
541
            unset($lang[$disable]);
542
        }
543
    }
544
545
    return $lang;
546
}
547
548
function get_all_languages()
549
{
550
    global $sugar_config;
551
552
    return $sugar_config['languages'];
553
}
554
555
function get_language_display($key)
556
{
557
    global $sugar_config;
558
559
    return $sugar_config['languages'][$key];
560
}
561
562
function get_assigned_user_name($assigned_user_id, $is_group = '')
563
{
564 71
    static $saved_user_list = null;
565
566 71
    if (empty($saved_user_list)) {
567 1
        $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
568
    }
569
570 71
    if (isset($saved_user_list[$assigned_user_id])) {
571 64
        return $saved_user_list[$assigned_user_id];
572
    }
573
574 13
    return '';
575
}
576
577
/**
578
 * retrieves the user_name column value (login).
579
 *
580
 * @param string id GUID of user
581
 *
582
 * @return string
583
 */
584
function get_user_name($id)
585
{
586
    global $db;
587
588
    if (empty($db)) {
589
        $db = DBManagerFactory::getInstance();
590
    }
591
592
    $q = "SELECT user_name FROM users WHERE id='{$id}'";
593
    $r = $db->query($q);
594
    $a = $db->fetchByAssoc($r);
595
596
    return (empty($a)) ? '' : $a['user_name'];
597
}
598
599
//TODO Update to use global cache
600
/**
601
 * get_user_array.
602
 *
603
 * This is a helper function to return an Array of users depending on the parameters passed into the function.
604
 * This function uses the get_register_value function by default to use a caching layer where supported.
605
 * This function has been updated return the array sorted by user preference of name display (bug 62712)
606
 *
607
 * @param bool   $add_blank        Boolean value to add a blank entry to the array results, true by default
608
 * @param string $status           String value indicating the status to filter users by, "Active" by default
609
 * @param string $user_id          String value to specify a particular user id value (searches the id column of users table), blank by default
610
 * @param bool   $use_real_name    Boolean value indicating whether or not results should include the full name or just user_name, false by default
611
 * @param string $user_name_filter String value indicating the user_name filter (searches the user_name column of users table) to optionally search with, blank by default
612
 * @param string $portal_filter    String query filter for portal users (defaults to searching non-portal users), change to blank if you wish to search for all users including portal users
613
 * @param bool   $from_cache       Boolean value indicating whether or not to use the get_register_value function for caching, true by default
614
 *
615
 * @return array Array of users matching the filter criteria that may be from cache (if similar search was previously run)
616
 */
617
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)
618
{
619 3
    global $locale, $sugar_config, $current_user;
620
621 3
    if (empty($locale)) {
622
        $locale = new Localization();
623
    }
624
625 3
    if ($from_cache) {
626 3
        $key_name = $add_blank.$status.$user_id.$use_real_name.$user_name_filter.$portal_filter;
627 3
        $user_array = get_register_value('user_array', $key_name);
628
    }
629
630 3
    if (empty($user_array)) {
631 3
        $db = DBManagerFactory::getInstance();
632 3
        $temp_result = array();
633
        // Including deleted users for now.
634 3
        if (empty($status)) {
635 1
            $query = 'SELECT id, first_name, last_name, user_name FROM users WHERE 1=1'.$portal_filter;
636
        } else {
637 2
            $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$portal_filter;
638
        }
639
        /* BEGIN - SECURITY GROUPS */
640 3
        global $current_user, $sugar_config;
641 3
        if (!is_admin($current_user)
642 3
            && isset($sugar_config['securitysuite_filter_user_list'])
643 3
            && $sugar_config['securitysuite_filter_user_list'] == true
644 3
            && (empty($_REQUEST['module']) || $_REQUEST['module'] != 'Home')
645 3
            && (empty($_REQUEST['action']) || $_REQUEST['action'] != 'DynamicAction')
646
        ) {
647
            require_once 'modules/SecurityGroups/SecurityGroup.php';
648
            global $current_user;
649
            $group_where = SecurityGroup::getGroupUsersWhere($current_user->id);
650
            $query .= ' AND ('.$group_where.') ';
651
        }
652
        /* END - SECURITY GROUPS */
653 3
        if (!empty($user_name_filter)) {
654
            $user_name_filter = $db->quote($user_name_filter);
655
            $query .= " AND user_name LIKE '$user_name_filter%' ";
656
        }
657 3
        if (!empty($user_id)) {
658
            $query .= " OR id='{$user_id}'";
659
        }
660
661
        //get the user preference for name formatting, to be used in order by
662 3
        $order_by_string = ' user_name ASC ';
663 3
        if (!empty($current_user) && !empty($current_user->id)) {
664
            $formatString = $current_user->getPreference('default_locale_name_format');
665
666
            //create the order by string based on position of first and last name in format string
667
            $order_by_string = ' user_name ASC ';
668
            $firstNamePos = strpos($formatString, 'f');
669
            $lastNamePos = strpos($formatString, 'l');
670
            if ($firstNamePos !== false || $lastNamePos !== false) {
671
                //its possible for first name to be skipped, check for this
672
                if ($firstNamePos === false) {
673
                    $order_by_string = 'last_name ASC';
674
                } else {
675
                    $order_by_string = ($lastNamePos < $firstNamePos) ? 'last_name, first_name ASC' : 'first_name, last_name ASC';
676
                }
677
            }
678
        }
679
680 3
        $query = $query.' ORDER BY '.$order_by_string;
681 3
        $GLOBALS['log']->debug("get_user_array query: $query");
682 3
        $result = $db->query($query, true, 'Error filling in user array: ');
683
684 3
        if ($add_blank == true) {
685
            // Add in a blank row
686
            $temp_result[''] = '';
687
        }
688
689
        // Get the id and the name.
690 3
        while ($row = $db->fetchByAssoc($result)) {
691 2
            if ($use_real_name == true || showFullName()) {
692 2
                if (isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
693 2
                    $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'], $row['last_name']);
694
                } else {
695 2
                    $temp_result[$row['id']] = $row['user_name'];
696
                }
697
            } else {
698
                $temp_result[$row['id']] = $row['user_name'];
699
            }
700
        }
701
702 3
        $user_array = $temp_result;
703 3
        if ($from_cache) {
704 3
            set_register_value('user_array', $key_name, $temp_result);
705
        }
706
    }
707
708 3
    return $user_array;
709
}
710
711
/**
712
 * uses a different query to return a list of users than get_user_array()
713
 * Used from QuickSearch.php.
714
 *
715
 * @param args string where clause entry
716
 *
717
 * @return array Array of Users' details that match passed criteria
718
 */
719
function getUserArrayFromFullName($args, $hide_portal_users = false)
720
{
721
    global $locale;
722
    $db = DBManagerFactory::getInstance();
723
724
    // jmorais@dri - Bug #51411
725
    //
726
    // Refactor the code responsible for parsing supplied $args, this way we
727
    // ensure that if $args has at least one space (after trim), the $inClause
728
    // will be composed by several clauses ($inClauses) inside parenthesis.
729
    //
730
    // Ensuring that operator precedence is respected, and avoiding
731
    // inactive/deleted users to be retrieved.
732
    //
733
    $args = trim($args);
734
    if (strpos($args, ' ')) {
735
        $inClauses = array();
736
737
        $argArray = explode(' ', $args);
738
        foreach ($argArray as $arg) {
739
            $arg = $db->quote($arg);
740
            $inClauses[] = "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
741
        }
742
743
        $inClause = '('.implode('OR ', $inClauses).')';
744
    } else {
745
        $args = $db->quote($args);
746
        $inClause = "(first_name LIKE '{$args}%' OR last_name LIKE '{$args}%')";
747
    }
748
    // ~jmorais@dri
749
750
    $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
751
    if ($hide_portal_users) {
752
        $query .= ' portal_only=0 AND ';
753
    }
754
    $query .= $inClause;
755
    /* BEGIN - SECURITY GROUPS */
756
    global $current_user, $sugar_config;
757
    if (!is_admin($current_user)
758
        && isset($sugar_config['securitysuite_filter_user_list'])
759
        && $sugar_config['securitysuite_filter_user_list'] == true
760
    ) {
761
        require_once 'modules/SecurityGroups/SecurityGroup.php';
762
        global $current_user;
763
        $group_where = SecurityGroup::getGroupUsersWhere($current_user->id);
764
        $query .= ' AND ('.$group_where.') ';
765
    }
766
    /* END - SECURITY GROUPS */
767
    $query .= ' ORDER BY last_name ASC';
768
769
    $r = $db->query($query);
770
    $ret = array();
771
    while ($a = $db->fetchByAssoc($r)) {
772
        $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
773
    }
774
775
    return $ret;
776
}
777
778
/**
779
 * based on user pref then system pref.
780
 */
781
function showFullName()
782
{
783 3
    global $sugar_config;
784 3
    global $current_user;
785 3
    static $showFullName = null;
786
787 3
    if (is_null($showFullName)) {
788 1
        $sysPref = !empty($sugar_config['use_real_names']);
789 1
        $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
790
791 1
        if ($userPref != null) {
792 1
            $showFullName = ($userPref == 'on');
793
        } else {
794
            $showFullName = $sysPref;
795
        }
796
    }
797
798 3
    return $showFullName;
799
}
800
801
function clean($string, $maxLength)
802
{
803
    $string = substr($string, 0, $maxLength);
804
805
    return escapeshellcmd($string);
806
}
807
808
/**
809
 * Copy the specified request variable to the member variable of the specified object.
810
 * Do no copy if the member variable is already set.
811
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
812
 * All Rights Reserved.
813
 * Contributor(s): ______________________________________..
814
 */
815
function safe_map($request_var, &$focus, $always_copy = false)
816
{
817
    safe_map_named($request_var, $focus, $request_var, $always_copy);
818
}
819
820
/**
821
 * Copy the specified request variable to the member variable of the specified object.
822
 * Do no copy if the member variable is already set.
823
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
824
 * All Rights Reserved.
825
 * Contributor(s): ______________________________________..
826
 */
827
function safe_map_named($request_var, &$focus, $member_var, $always_copy)
828
{
829
    if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
830
        $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
831
        $focus->$member_var = $_REQUEST[$request_var];
832
    }
833
}
834
835
/**
836
 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
837
 *
838
 * @param string $language specific language to load
839
 *
840
 * @return array lang strings
841
 */
842
function return_app_list_strings_language($language)
843
{
844 5
    global $app_list_strings;
845 5
    global $sugar_config;
846
847 5
    $cache_key = 'app_list_strings.'.$language;
848
849
    // Check for cached value
850 5
    $cache_entry = sugar_cache_retrieve($cache_key);
851 5
    if (!empty($cache_entry)) {
852 5
        return $cache_entry;
853
    }
854
855
    $default_language = isset($sugar_config['default_language']) ? $sugar_config['default_language'] : 'en_us';
856
    $temp_app_list_strings = $app_list_strings;
857
858
    $langs = array();
859
    if ($language != 'en_us') {
860
        $langs[] = 'en_us';
861
    }
862
    if ($default_language != 'en_us' && $language != $default_language) {
863
        $langs[] = $default_language;
864
    }
865
    $langs[] = $language;
866
867
    $app_list_strings_array = array();
868
869
    foreach ($langs as $lang) {
870
        $app_list_strings = array();
871
        if (file_exists("include/language/$lang.lang.php")) {
872
            include "include/language/$lang.lang.php";
873
            $GLOBALS['log']->info("Found language file: $lang.lang.php");
874
        }
875
        if (file_exists("include/language/$lang.lang.override.php")) {
876
            include "include/language/$lang.lang.override.php";
877
            $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
878
        }
879
        if (file_exists("include/language/$lang.lang.php.override")) {
880
            include "include/language/$lang.lang.php.override";
881
            $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
882
        }
883
884
        $app_list_strings_array[] = $app_list_strings;
885
    }
886
887
    $app_list_strings = array();
888
    foreach ($app_list_strings_array as $app_list_strings_item) {
889
        $app_list_strings = sugarLangArrayMerge($app_list_strings, $app_list_strings_item);
890
    }
891
892
    foreach ($langs as $lang) {
893
        if (file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
894
            $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php", $app_list_strings);
895
            $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
896
        }
897
        if (file_exists("custom/include/language/$lang.lang.php")) {
898
            include "custom/include/language/$lang.lang.php";
899
            $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
900
        }
901
    }
902
903
    if (!isset($app_list_strings)) {
904
        $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");
905
906
        return;
907
    }
908
909
    $return_value = $app_list_strings;
910
    $app_list_strings = $temp_app_list_strings;
911
912
    sugar_cache_put($cache_key, $return_value);
913
914
    return $return_value;
915
}
916
917
/**
918
 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
919
 * $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.
920
 *
921
 * @param file string the language that you want include,
922
 * @param app_list_strings array the golbal strings
923
 *
924
 * @return array
925
 */
926
//jchi 25347
927
function _mergeCustomAppListStrings($file, $app_list_strings)
928
{
929
    $app_list_strings_original = $app_list_strings;
930
    unset($app_list_strings);
931
    // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
932
    //                  This way, language file can add items to save specific standard codelist from being overwritten
933
    $exemptDropdowns = array();
934
    include $file;
935
    if (!isset($app_list_strings) || !is_array($app_list_strings)) {
936
        return $app_list_strings_original;
937
    }
938
    //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
939
940
    // FG - bug 45525 - Specific codelists must NOT be overwritten
941
    $exemptDropdowns[] = 'moduleList';
942
    $exemptDropdowns[] = 'moduleListSingular';
943
    $exemptDropdowns = array_merge($exemptDropdowns, getTypeDisplayList());
944
945
    foreach ($app_list_strings as $key => $value) {
946
        if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original)) {
947
            unset($app_list_strings_original["$key"]);
948
        }
949
    }
950
    $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original, $app_list_strings);
951
952
    return $app_list_strings;
953
}
954
955
/**
956
 * This function retrieves an application language file and returns the array of strings included.
957
 *
958
 * @param string $language specific language to load
959
 *
960
 * @return array lang strings
961
 */
962
function return_application_language($language)
963
{
964 4
    global $app_strings, $sugar_config;
965
966 4
    $cache_key = 'app_strings.'.$language;
967
968
    // Check for cached value
969 4
    $cache_entry = sugar_cache_retrieve($cache_key);
970 4
    if (!empty($cache_entry)) {
971 4
        return $cache_entry;
972
    }
973
974
    $temp_app_strings = $app_strings;
975
    $default_language = $sugar_config['default_language'];
976
977
    $langs = array();
978
    if ($language != 'en_us') {
979
        $langs[] = 'en_us';
980
    }
981
    if ($default_language != 'en_us' && $language != $default_language) {
982
        $langs[] = $default_language;
983
    }
984
985
    $langs[] = $language;
986
987
    $app_strings_array = array();
988
989
    foreach ($langs as $lang) {
990
        $app_strings = array();
991
        if (file_exists("include/language/$lang.lang.php")) {
992
            include "include/language/$lang.lang.php";
993
            $GLOBALS['log']->info("Found language file: $lang.lang.php");
994
        }
995
        if (file_exists("include/language/$lang.lang.override.php")) {
996
            include "include/language/$lang.lang.override.php";
997
            $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
998
        }
999
        if (file_exists("include/language/$lang.lang.php.override")) {
1000
            include "include/language/$lang.lang.php.override";
1001
            $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
1002
        }
1003
        if (file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
1004
            include "custom/application/Ext/Language/$lang.lang.ext.php";
1005
            $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
1006
        }
1007
        if (file_exists("custom/include/language/$lang.lang.php")) {
1008
            include "custom/include/language/$lang.lang.php";
1009
            $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
1010
        }
1011
        $app_strings_array[] = $app_strings;
1012
    }
1013
1014
    $app_strings = array();
1015
    foreach ($app_strings_array as $app_strings_item) {
1016
        $app_strings = sugarLangArrayMerge($app_strings, $app_strings_item);
1017
    }
1018
1019
    if (!isset($app_strings)) {
1020
        $GLOBALS['log']->fatal('Unable to load the application language strings');
1021
1022
        return;
1023
    }
1024
1025
    // If we are in debug mode for translating, turn on the prefix now!
1026
    if (!empty($sugar_config['translation_string_prefix'])) {
1027
        foreach ($app_strings as $entry_key => $entry_value) {
1028
            $app_strings[$entry_key] = $language.' '.$entry_value;
1029
        }
1030
    }
1031
    if (isset($_SESSION['show_deleted'])) {
1032
        $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
1033
        $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
1034
        $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
1035
        $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
1036
    }
1037
1038
    $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
1039
1040
    $return_value = $app_strings;
1041
    $app_strings = $temp_app_strings;
1042
1043
    sugar_cache_put($cache_key, $return_value);
1044
1045
    return $return_value;
1046
}
1047
1048
/**
1049
 * This function retrieves a module's language file and returns the array of strings included.
1050
 *
1051
 * @param string $language specific language to load
1052
 * @param string $module   module name to load strings for
1053
 * @param bool   $refresh  optional, true if you want to rebuild the language strings
1054
 *
1055
 * @return array lang strings
1056
 */
1057
function return_module_language($language, $module, $refresh = false)
1058
{
1059 47
    global $mod_strings;
1060 47
    global $sugar_config;
1061 47
    global $currentModule;
1062
1063
    // Jenny - Bug 8119: Need to check if $module is not empty
1064 47
    if (empty($module)) {
1065
        $stack = debug_backtrace();
1066
        $GLOBALS['log']->warn('Variable module is not in return_module_language '.var_export($stack, true));
1067
1068
        return array();
1069
    }
1070
1071 47
    if (!$refresh) {
1072 47
        $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1073
        // Check for cached value
1074 47
        $cache_entry = sugar_cache_retrieve($cache_key);
1075 47
        if (!empty($cache_entry) && is_array($cache_entry)) {
1076 40
            return $cache_entry;
1077
        }
1078
    }
1079
    // Store the current mod strings for later
1080 14
    $temp_mod_strings = $mod_strings;
1081 14
    $loaded_mod_strings = array();
1082 14
    $language_used = $language;
1083 14
    $default_language = $sugar_config['default_language'];
1084
1085 14
    if (empty($language)) {
1086 7
        $language = $default_language;
1087
    }
1088
1089
    // Bug 21559 - So we can get all the strings defined in the template, refresh
1090
    // the vardefs file if the cached language file doesn't exist.
1091 14
    if (!file_exists(sugar_cached('modules/').$module.'/language/'.$language.'.lang.php')
1092 14
        && !empty($GLOBALS['beanList'][$module])
1093
    ) {
1094 7
        $object = BeanFactory::getObjectName($module);
1095 7
        VardefManager::refreshVardefs($module, $object);
1096
    }
1097
1098 14
    $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language, $refresh);
1099
1100
    // cn: bug 6048 - merge en_us with requested language
1101 14
    if ($language != $sugar_config['default_language']) {
1102
        $loaded_mod_strings = sugarLangArrayMerge(
1103
            LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'], $refresh),
1104
            $loaded_mod_strings
1105
        );
1106
    }
1107
1108
    // Load in en_us strings by default
1109 14
    if ($language != 'en_us' && $sugar_config['default_language'] != 'en_us') {
1110
        $loaded_mod_strings = sugarLangArrayMerge(
1111
            LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
1112
            $loaded_mod_strings
1113
        );
1114
    }
1115
1116
    // If we are in debug mode for translating, turn on the prefix now!
1117 14
    if ($sugar_config['translation_string_prefix']) {
1118
        foreach ($loaded_mod_strings as $entry_key => $entry_value) {
1119
            $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
1120
        }
1121
    }
1122
1123 14
    $return_value = $loaded_mod_strings;
1124 14
    if (!isset($mod_strings)) {
1125 8
        $mod_strings = $return_value;
1126
    } else {
1127 8
        $mod_strings = $temp_mod_strings;
1128
    }
1129
1130 14
    $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
1131 14
    sugar_cache_put($cache_key, $return_value);
1132
1133 14
    return $return_value;
1134
}
1135
1136
/** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1137
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1138
 * All Rights Reserved.
1139
 * Contributor(s): ______________________________________..
1140
 * If you are using the current language, do not call this function unless you are loading it for the first time */
1141
function return_mod_list_strings_language($language, $module)
1142
{
1143
    global $mod_list_strings;
1144
    global $sugar_config;
1145
    global $currentModule;
1146
1147
    $cache_key = 'mod_list_str_lang.'.$language.$module;
1148
1149
    // Check for cached value
1150
    $cache_entry = sugar_cache_retrieve($cache_key);
1151
    if (!empty($cache_entry)) {
1152
        return $cache_entry;
1153
    }
1154
1155
    $language_used = $language;
1156
    $temp_mod_list_strings = $mod_list_strings;
1157
    $default_language = $sugar_config['default_language'];
1158
1159
    if ($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1160
        return $mod_list_strings;
1161
    }
1162
1163
    // cn: bug 6351 - include en_us if file langpack not available
1164
    // cn: bug 6048 - merge en_us with requested language
1165
    include "modules/$module/language/en_us.lang.php";
1166
    $en_mod_list_strings = array();
1167
    if ($language_used != $default_language) {
1168
        $en_mod_list_strings = $mod_list_strings;
1169
    }
1170
1171
    if (file_exists("modules/$module/language/$language.lang.php")) {
1172
        include "modules/$module/language/$language.lang.php";
1173
    }
1174
1175
    if (file_exists("modules/$module/language/$language.lang.override.php")) {
1176
        include "modules/$module/language/$language.lang.override.php";
1177
    }
1178
1179
    if (file_exists("modules/$module/language/$language.lang.php.override")) {
1180
        echo 'Please Change:<br>'."modules/$module/language/$language.lang.php.override".'<br>to<br>'.'Please Change:<br>'."modules/$module/language/$language.lang.override.php";
1181
        include "modules/$module/language/$language.lang.php.override";
1182
    }
1183
1184
    // cn: bug 6048 - merge en_us with requested language
1185
    $mod_list_strings = sugarLangArrayMerge($en_mod_list_strings, $mod_list_strings);
1186
1187
    // if we still don't have a language pack, then log an error
1188
    if (!isset($mod_list_strings)) {
1189
        $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})");
1190
1191
        return;
1192
    }
1193
1194
    $return_value = $mod_list_strings;
1195
    $mod_list_strings = $temp_mod_list_strings;
1196
1197
    sugar_cache_put($cache_key, $return_value);
1198
1199
    return $return_value;
1200
}
1201
1202
/** This function retrieves a theme's language file and returns the array of strings included.
1203
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1204
 * All Rights Reserved.
1205
 * Contributor(s): ______________________________________..
1206
 */
1207
function return_theme_language($language, $theme)
1208
{
1209
    global $mod_strings, $sugar_config, $current_language;
1210
1211
    $language_used = $language;
1212
    $default_language = $sugar_config['default_language'];
1213
1214
    include SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php";
1215
    if (file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")) {
1216
        include SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php";
1217
    }
1218
    if (file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")) {
1219
        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";
1220
        include SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override";
1221
    }
1222
    if (!isset($theme_strings)) {
1223
        $GLOBALS['log']->warn('Unable to find the theme file for language: '.$language.' and theme: '.$theme);
1224
        require SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php";
1225
        $language_used = $default_language;
1226
    }
1227
1228
    if (!isset($theme_strings)) {
1229
        $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1230
1231
        return;
1232
    }
1233
1234
    // If we are in debug mode for translating, turn on the prefix now!
1235
    if ($sugar_config['translation_string_prefix']) {
1236
        foreach ($theme_strings as $entry_key => $entry_value) {
1237
            $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1238
        }
1239
    }
1240
1241
    return $theme_strings;
1242
}
1243
1244
/** If the session variable is defined and is not equal to "" then return it.  Otherwise, return the default value.
1245
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1246
 * All Rights Reserved.
1247
 * Contributor(s): ______________________________________..
1248
 */
1249
function return_session_value_or_default($varname, $default)
1250
{
1251
    if (isset($_SESSION[$varname]) && $_SESSION[$varname] != '') {
1252
        return $_SESSION[$varname];
1253
    }
1254
1255
    return $default;
1256
}
1257
1258
/**
1259
 * Creates an array of where restrictions.  These are used to construct a where SQL statement on the query
1260
 * 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.
1261
 *
1262
 * @param &$where_clauses - The array to append the clause to
1263
 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1264
 * @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.
1265
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1266
 * All Rights Reserved.
1267
 * Contributor(s): ______________________________________..
1268
 */
1269
function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1270
{
1271
    if ($SQL_name == null) {
1272
        $SQL_name = $variable_name;
1273
    }
1274
1275
    if (isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != '') {
1276
        array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1277
    }
1278
}
1279
1280
/**
1281
 * Generate the appropriate SQL based on the where clauses.
1282
 *
1283
 * @param $where_clauses - An Array of individual where clauses stored as strings
1284
 * @returns string where_clause - The final SQL where clause to be executed.
1285
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1286
 * All Rights Reserved.
1287
 * Contributor(s): ______________________________________..
1288
 */
1289
function generate_where_statement($where_clauses)
1290
{
1291
    $where = '';
1292
    foreach ($where_clauses as $clause) {
1293
        if ($where != '') {
1294
            $where .= ' and ';
1295
        }
1296
        $where .= $clause;
1297
    }
1298
1299
    $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1300
1301
    return $where;
1302
}
1303
1304
/**
1305
 * determines if a passed string matches the criteria for a Sugar GUID.
1306
 *
1307
 * @param string $guid
1308
 *
1309
 * @return bool False on failure
1310
 */
1311
function is_guid($guid)
1312
{
1313 1
    if (strlen($guid) != 36) {
1314 1
        return false;
1315
    }
1316
1317
    if (preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1318
        return true;
1319
    }
1320
1321
    return true;
1322
}
1323
1324
/**
1325
 * A temporary method of generating GUIDs of the correct format for our DB.
1326
 *
1327
 * @return string contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1328
 *
1329
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1330
 * All Rights Reserved.
1331
 * Contributor(s): ______________________________________..
1332
 */
1333
function create_guid()
1334
{
1335 73
    $microTime = microtime();
1336 73
    list($a_dec, $a_sec) = explode(' ', $microTime);
1337
1338 73
    $dec_hex = dechex($a_dec * 1000000);
1339 73
    $sec_hex = dechex($a_sec);
1340
1341 73
    ensure_length($dec_hex, 5);
1342 73
    ensure_length($sec_hex, 6);
1343
1344 73
    $guid = '';
1345 73
    $guid .= $dec_hex;
1346 73
    $guid .= create_guid_section(3);
1347 73
    $guid .= '-';
1348 73
    $guid .= create_guid_section(4);
1349 73
    $guid .= '-';
1350 73
    $guid .= create_guid_section(4);
1351 73
    $guid .= '-';
1352 73
    $guid .= create_guid_section(4);
1353 73
    $guid .= '-';
1354 73
    $guid .= $sec_hex;
1355 73
    $guid .= create_guid_section(6);
1356
1357 73
    return $guid;
1358
}
1359
1360
function create_guid_section($characters)
1361
{
1362 73
    $return = '';
1363 73
    for ($i = 0; $i < $characters; ++$i) {
1364 73
        $return .= dechex(mt_rand(0, 15));
1365
    }
1366
1367 73
    return $return;
1368
}
1369
1370
function ensure_length(&$string, $length)
1371
{
1372 73
    $strlen = strlen($string);
1373 73
    if ($strlen < $length) {
1374 7
        $string = str_pad($string, $length, '0');
1375 73
    } elseif ($strlen > $length) {
1376 73
        $string = substr($string, 0, $length);
1377
    }
1378 73
}
1379
1380
function microtime_diff($a, $b)
1381
{
1382
    list($a_dec, $a_sec) = explode(' ', $a);
1383
    list($b_dec, $b_sec) = explode(' ', $b);
1384
1385
    return $b_sec - $a_sec + $b_dec - $a_dec;
1386
}
1387
1388
// check if Studio is displayed.
1389
function displayStudioForCurrentUser()
1390
{
1391
    global $current_user;
1392
    if ($current_user->isAdmin()) {
1393
        return true;
1394
    }
1395
1396
    return true;
1397
}
1398
1399
function displayWorkflowForCurrentUser()
1400
{
1401
    $_SESSION['display_workflow_for_user'] = false;
1402
1403
    return false;
1404
}
1405
1406
// return an array with all modules where the user is an admin.
1407
function get_admin_modules_for_user($user)
1408
{
1409
    $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');
1410
1411
    if (!isset($user)) {
1412
        $modules = array();
1413
1414
        return $modules;
1415
    }
1416
1417
    return $user->getDeveloperModules();
1418
}
1419
1420
function get_workflow_admin_modules_for_user($user)
1421
{
1422
    if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1423
        return $_SESSION['get_workflow_admin_modules_for_user'];
1424
    }
1425
1426
    global $moduleList;
1427
    $workflow_mod_list = array();
1428
    foreach ($moduleList as $module) {
1429
        $workflow_mod_list[$module] = $module;
1430
    }
1431
1432
    // This list is taken from teh previous version of workflow_utils.php
1433
    $workflow_mod_list['Tasks'] = 'Tasks';
1434
    $workflow_mod_list['Calls'] = 'Calls';
1435
    $workflow_mod_list['Meetings'] = 'Meetings';
1436
    $workflow_mod_list['Notes'] = 'Notes';
1437
    $workflow_mod_list['ProjectTask'] = 'Project Tasks';
1438
    $workflow_mod_list['Leads'] = 'Leads';
1439
    $workflow_mod_list['Opportunities'] = 'Opportunities';
1440
    // End of list
1441
1442
    $workflow_admin_modules = array();
1443
    if (empty($user)) {
1444
        return $workflow_admin_modules;
1445
    }
1446
    $actions = ACLAction::getUserActions($user->id);
1447
    //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1448
    if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess'] == ACL_ALLOW_DEV ||
1449
            $actions['ForecastSchedule']['module']['admin']['aclaccess'] == ACL_ALLOW_ADMIN_DEV)
1450
    ) {
1451
        $workflow_admin_modules['Forecasts'] = 'Forecasts';
1452
    }
1453
    foreach ($workflow_mod_list as $key => $val) {
1454
        if (!in_array($val, $workflow_admin_modules) && ($val != 'iFrames' && $val != 'Feeds' && $val != 'Home' && $val != 'Dashboard'
1455
                && $val != 'Calendar' && $val != 'Activities' && $val != 'Reports') &&
1456
            ($user->isDeveloperForModule($key))
1457
        ) {
1458
            $workflow_admin_modules[$key] = $val;
1459
        }
1460
    }
1461
    $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1462
1463
    return $workflow_admin_modules;
1464
}
1465
1466
// Check if user is admin for at least one module.
1467
function is_admin_for_any_module($user)
1468
{
1469
    if (!isset($user)) {
1470
        return false;
1471
    }
1472
    if ($user->isAdmin()) {
1473
        return true;
1474
    }
1475
1476
    return false;
1477
}
1478
1479
// Check if user is admin for a specific module.
1480
function is_admin_for_module($user, $module)
1481
{
1482
    if (!isset($user)) {
1483
        return false;
1484
    }
1485
    if ($user->isAdmin()) {
1486
        return true;
1487
    }
1488
1489
    return false;
1490
}
1491
1492
/**
1493
 * Check if user id belongs to a system admin.
1494
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1495
 * All Rights Reserved.
1496
 * Contributor(s): ______________________________________..
1497
 */
1498
function is_admin($user)
1499
{
1500 92
    if (empty($user)) {
1501
        return false;
1502
    }
1503
1504 92
    return $user->isAdmin();
1505
}
1506
1507
/**
1508
 * Return the display name for a theme if it exists.
1509
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1510
 * All Rights Reserved.
1511
 * Contributor(s): ______________________________________..
1512
 *
1513
 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1514
 */
1515
function get_theme_display($theme)
1516
{
1517
    return SugarThemeRegistry::get($theme)->name;
1518
}
1519
1520
/**
1521
 * Return an array of directory names.
1522
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1523
 * All Rights Reserved.
1524
 * Contributor(s): ______________________________________..
1525
 *
1526
 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1527
 */
1528
function get_themes()
1529
{
1530
    return SugarThemeRegistry::availableThemes();
1531
}
1532
1533
/**
1534
 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1535
 * Create HTML to display select options in a dropdown list.  To be used inside
1536
 * of a select statement in a form.
1537
 * param $option_list - the array of strings to that contains the option list
1538
 * param $selected - the string which contains the default value
1539
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1540
 * All Rights Reserved.
1541
 * Contributor(s): ______________________________________..
1542
 */
1543
function get_select_options($option_list, $selected)
1544
{
1545
    return get_select_options_with_id($option_list, $selected);
1546
}
1547
1548
/**
1549
 * Create HTML to display select options in a dropdown list.  To be used inside
1550
 * 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.
1551
 * param $option_list - the array of strings to that contains the option list
1552
 * param $selected - the string which contains the default value
1553
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1554
 * All Rights Reserved.
1555
 * Contributor(s): ______________________________________..
1556
 */
1557
function get_select_options_with_id($option_list, $selected_key)
1558
{
1559 19
    return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1560
}
1561
1562
/**
1563
 * Create HTML to display select options in a dropdown list.  To be used inside
1564
 * 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.
1565
 * param $label_list - the array of strings to that contains the option list
1566
 * param $key_list - the array of strings to that contains the values list
1567
 * param $selected - the string which contains the default value
1568
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1569
 * All Rights Reserved.
1570
 * Contributor(s): ______________________________________..
1571
 */
1572
function get_select_options_with_id_separate_key($label_list, $key_list, $selected_key, $massupdate = false)
1573
{
1574 20
    global $app_strings;
1575 20
    $select_options = '';
1576
1577
    //for setting null selection values to human readable --None--
1578 20
    $pattern = "/'0?'></";
1579 20
    $replacement = "''>".$app_strings['LBL_NONE'].'<';
1580 20
    if ($massupdate) {
1581 1
        $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
1582
    }
1583
1584 20
    if (empty($key_list)) {
1585 1
        $key_list = array();
1586
    }
1587
    //create the type dropdown domain and set the selected value if $opp value already exists
1588 20
    foreach ($key_list as $option_key => $option_value) {
1589 20
        $selected_string = '';
1590
        // the system is evaluating $selected_key == 0 || '' to true.  Be very careful when changing this.  Test all cases.
1591
        // The bug was only happening with one of the users in the drop down.  It was being replaced by none.
1592
        if (
1593 20
            ($option_key != '' && $selected_key == $option_key)
1594
            || (
1595 20
                $option_key == ''
1596 20
                && (($selected_key == '' && !$massupdate) || $selected_key == '__SugarMassUpdateClearField__')
1597
            )
1598 20
            || (is_array($selected_key) && in_array($option_key, $selected_key))
1599
        ) {
1600 12
            $selected_string = 'selected ';
1601
        }
1602
1603 20
        $html_value = $option_key;
1604
1605 20
        $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1606
    }
1607 20
    $select_options = preg_replace($pattern, $replacement, $select_options);
1608
1609 20
    return $select_options;
1610
}
1611
1612
/**
1613
 * Call this method instead of die().
1614
 * We print the error message and then die with an appropriate
1615
 * exit code.
1616
 */
1617
function sugar_die($error_message, $exit_code = 1)
1618
{
1619
    global $focus;
1620
    sugar_cleanup();
1621
    //echo $error_message;
1622
    //die($exit_code);
1623
    throw new \Exception($error_message, $exit_code);
1624
}
1625
1626
/**
1627
 * Create javascript to clear values of all elements in a form.
1628
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1629
 * All Rights Reserved.
1630
 * Contributor(s): ______________________________________..
1631
 */
1632
function get_clear_form_js()
1633
{
1634
    $the_script = <<<EOQ
1635
<script type="text/javascript" language="JavaScript">
1636
function clear_form(form) {
1637
	var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1638
	if(typeof(form.advanced) != 'undefined'){
1639
		newLoc += '&advanced=' + form.advanced.value;
1640
	}
1641
	document.location.href= newLoc;
1642
}
1643
</script>
1644
EOQ;
1645
1646
    return $the_script;
1647
}
1648
1649
/**
1650
 * Create javascript to set the cursor focus to specific field in a form
1651
 * when the screen is rendered.  The field name is currently hardcoded into the
1652
 * the function.
1653
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1654
 * All Rights Reserved.
1655
 * Contributor(s): ______________________________________..
1656
 */
1657
function get_set_focus_js()
1658
{
1659
    //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1660
    $the_script = <<<EOQ
1661
<script type="text/javascript" language="JavaScript">
1662
<!--
1663
function set_focus() {
1664
	if (document.forms.length > 0) {
1665
		for (i = 0; i < document.forms.length; i++) {
1666
			for (j = 0; j < document.forms[i].elements.length; j++) {
1667
				var field = document.forms[i].elements[j];
1668
				if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1669
						!field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1670
					field.focus();
1671
                    if (field.type == "text") {
1672
                        field.select();
1673
                    }
1674
					break;
1675
	    		}
1676
			}
1677
      	}
1678
   	}
1679
}
1680
-->
1681 6
</script>
1682
EOQ;
1683
1684 6
    return $the_script;
1685
}
1686
1687
/**
1688
 * Very cool algorithm for sorting multi-dimensional arrays.  Found at http://us2.php.net/manual/en/function.array-multisort.php
1689
 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1690
 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1691
 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1692
 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1693
 * the first - so the array is sorted by the last given column first, then the one before ...
1694
 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1695
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1696
 * All Rights Reserved.
1697
 * Contributor(s): ______________________________________..
1698
 */
1699
function array_csort()
1700
{
1701
    $args = func_get_args();
1702
    $marray = array_shift($args);
1703
    $i = 0;
1704
1705
    $msortline = 'return(array_multisort(';
1706
    foreach ($args as $arg) {
1707
        ++$i;
1708
        if (is_string($arg)) {
1709
            foreach ($marray as $row) {
1710
                $sortarr[$i][] = $row[$arg];
1711
            }
1712
        } else {
1713
            $sortarr[$i] = $arg;
1714
        }
1715
        $msortline .= '$sortarr['.$i.'],';
1716
    }
1717
    $msortline .= '$marray));';
1718
1719
    eval($msortline);
1720
1721
    return $marray;
1722
}
1723
1724
/**
1725
 * Converts localized date format string to jscalendar format
1726
 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1727
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1728
 * All Rights Reserved.
1729
 * Contributor(s): ______________________________________..
1730
 */
1731
function parse_calendardate($local_format)
1732
{
1733
    preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1734
    $calendar_format = '%'.$matches[1].'-%'.$matches[2].'-%'.$matches[3];
1735
1736
    return str_replace(array('y', 'ᅣ1�7', 'a', 'j'), array('Y', 'Y', 'Y', 'd'), $calendar_format);
1737
}
1738
1739
function translate($string, $mod = '', $selectedValue = '')
1740
{
1741
    //$test_start = microtime();
1742
    //static $mod_strings_results = array();
1743 37
    if (!empty($mod)) {
1744 27
        global $current_language;
1745
        //Bug 31275
1746 27
        if (isset($_REQUEST['login_language'])) {
1747
            $current_language = ($_REQUEST['login_language'] == $current_language) ? $current_language : $_REQUEST['login_language'];
1748
        }
1749 27
        $mod_strings = return_module_language($current_language, $mod);
1750 27
        if ($mod == '') {
1751 27
            echo 'Language is <pre>'.$mod_strings.'</pre>';
1752
        }
1753
    } else {
1754 16
        global $mod_strings;
1755
    }
1756
1757 37
    $returnValue = '';
1758 37
    global $app_strings, $app_list_strings;
1759
1760 37
    if (isset($mod_strings[$string])) {
1761 25
        $returnValue = $mod_strings[$string];
1762 21
    } elseif (isset($app_strings[$string])) {
1763 10
        $returnValue = $app_strings[$string];
1764 16
    } elseif (isset($app_list_strings[$string])) {
1765 10
        $returnValue = $app_list_strings[$string];
1766 7
    } elseif (isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string])) {
1767
        $returnValue = $app_list_strings['moduleList'][$string];
1768
    }
1769
1770
    //$test_end = microtime();
1771
    //
1772
    //    $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1773
    //
1774
    //    echo("translate results:");
1775
    //    $total_time = 0;
1776
    //    $total_strings = 0;
1777
    //    foreach($mod_strings_results as $key=>$value)
1778
    //    {
1779
    //        echo("Module $key \t\t time $value \t\t<br>");
1780
    //        $total_time += $value;
1781
    //    }
1782
    //
1783
    //    echo("Total time: $total_time<br>");
1784
1785 37
    if (empty($returnValue)) {
1786 7
        return $string;
1787
    }
1788
1789
    // Bug 48996 - Custom enums with '0' value were not returning because of empty check
1790
    // Added a numeric 0 checker to the conditional to allow 0 value indexed to pass
1791 37
    if (is_array($returnValue) && (!empty($selectedValue) || (is_numeric($selectedValue) && $selectedValue == 0)) && isset($returnValue[$selectedValue])) {
1792 2
        return $returnValue[$selectedValue];
1793
    }
1794
1795 37
    return $returnValue;
1796
}
1797
1798
function unTranslateNum($num)
1799
{
1800
    static $dec_sep;
1801
    static $num_grp_sep;
1802
    global $current_user, $sugar_config;
1803
1804
    if ($dec_sep == null) {
1805
        $user_dec_sep = $current_user->getPreference('dec_sep');
1806
        $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1807
    }
1808
    if ($num_grp_sep == null) {
1809
        $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1810
        $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1811
    }
1812
1813
    $num = preg_replace("'".preg_quote($num_grp_sep)."'", '', $num);
1814
    $num = preg_replace("'".preg_quote($dec_sep)."'", '.', $num);
1815
1816
    return $num;
1817
}
1818
1819
function add_http($url)
1820
{
1821
    if (!preg_match('@://@i', $url)) {
1822
        $scheme = 'http';
1823
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1824
            $scheme = 'https';
1825
        }
1826
1827
        return "{$scheme}://{$url}";
1828
    }
1829
1830
    return $url;
1831
}
1832
1833
/**
1834
 * returns a default array of XSS tags to clean.
1835
 *
1836
 * @return array
1837
 */
1838
function getDefaultXssTags()
1839
{
1840
    $tmp = array(
1841
        'applet' => 'applet',
1842
        'base' => 'base',
1843
        'embed' => 'embed',
1844
        'form' => 'form',
1845
        'frame' => 'frame',
1846
        'frameset' => 'frameset',
1847
        'iframe' => 'iframe',
1848
        'import' => "\?import",
1849
        'layer' => 'layer',
1850
        'link' => 'link',
1851
        'object' => 'object',
1852
        'script' => 'script',
1853
        'xmp' => 'xmp',
1854
    );
1855
1856
    $ret = base64_encode(serialize($tmp));
1857
1858
    return $ret;
1859
}
1860
1861
/**
1862
 * Remove potential xss vectors from strings.
1863
 *
1864
 * @param string str String to search for XSS attack vectors
1865
 *
1866
 * @deprecated
1867
 *
1868
 * @return string
1869
 */
1870
function remove_xss($str)
1871
{
1872
    return SugarCleaner::cleanHtml($str, false);
1873
}
1874
1875
/**
1876
 * Detects typical XSS attack patterns.
1877
 *
1878
 * @deprecated
1879
 *
1880
 * @param string str String to search for XSS attack vectors
1881
 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1882
 *
1883
 * @return array Array of matches, empty on clean string
1884
 */
1885
function clean_xss($str, $cleanImg = true)
1886
{
1887
    global $sugar_config;
1888
1889
    if (empty($sugar_config['email_xss'])) {
1890
        $sugar_config['email_xss'] = getDefaultXssTags();
1891
    }
1892
1893
    $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1894
1895
    // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1896
    $jsEvents = 'onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|';
1897
    $jsEvents .= 'onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|';
1898
    $jsEvents .= 'onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop';
1899
1900
    $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1901
    $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1902
    $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1903
    $css_url = '#url\(.*\.\w+\)#';
1904
1905
    $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1906
1907
    $tagmatches = array();
1908
    $matches = array();
1909
    preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1910
    foreach ($tagmatches[1] as $no => $tag) {
1911
        if (in_array($tag, $xsstags)) {
1912
            // dangerous tag - take out whole
1913
            $matches[] = $tagmatches[0][$no];
1914
            continue;
1915
        }
1916
        $attrmatch = array();
1917
        preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1918
        if (!empty($attrmatch[0])) {
1919
            $matches = array_merge($matches, $attrmatch[0]);
1920
        }
1921
    }
1922
1923
    $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1924
1925
    if ($cleanImg) {
1926
        $matches = array_merge($matches,
1927
            xss_check_pattern($imgsrc_regex, $str)
1928
        );
1929
    }
1930
1931
    // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1932
    preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1933
1934
    if (isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1935
        if (is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1936
            // normalize whitelist
1937
            foreach ($sugar_config['security_trusted_domains'] as $k => $v) {
1938
                $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1939
            }
1940
1941
            foreach ($cssUrlMatches[0] as $match) {
1942
                $domain = strtolower(substr(strstr($match, '://'), 3));
1943
                $baseUrl = substr($domain, 0, strpos($domain, '/'));
1944
1945
                if (!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1946
                    $matches[] = $match;
1947
                }
1948
            }
1949
        }
1950
    } else {
1951
        $matches = array_merge($matches, $cssUrlMatches[0]);
1952
    }
1953
1954
    return $matches;
1955
}
1956
1957
/**
1958
 * Helper function used by clean_xss() to parse for known-bad vectors.
1959
 *
1960
 * @param string pattern Regex pattern to use
1961
 * @param string str String to parse for badness
1962
 *
1963
 * @return array
1964
 */
1965
function xss_check_pattern($pattern, $str)
1966
{
1967
    preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1968
1969
    return $matches[1];
1970
}
1971
1972
/**
1973
 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it.
1974
 *
1975
 * @param string $str
1976
 * @param string $filter       which corresponds to a regular expression to use; choices are:
1977
 *                             "STANDARD" ( default )
1978
 *                             "STANDARDSPACE"
1979
 *                             "FILE"
1980
 *                             "NUMBER"
1981
 *                             "SQL_COLUMN_LIST"
1982
 *                             "PATH_NO_URL"
1983
 *                             "SAFED_GET"
1984
 *                             "UNIFIED_SEARCH"
1985
 *                             "AUTO_INCREMENT"
1986
 *                             "ALPHANUM"
1987
 * @param bool   $dieOnBadData true (default) if you want to die if bad data if found, false if not
1988
 */
1989
function clean_string($str, $filter = 'STANDARD', $dieOnBadData = true)
1990
{
1991
    global $sugar_config;
1992
1993
    $filters = array(
1994
        'STANDARD' => '#[^A-Z0-9\-_\.\@]#i',
1995
        'STANDARDSPACE' => '#[^A-Z0-9\-_\.\@\ ]#i',
1996
        'FILE' => '#[^A-Z0-9\-_\.]#i',
1997
        'NUMBER' => '#[^0-9\-]#i',
1998
        'SQL_COLUMN_LIST' => '#[^A-Z0-9\(\),_\.]#i',
1999
        'PATH_NO_URL' => '#://#i',
2000
        'SAFED_GET' => '#[^A-Z0-9\@\=\&\?\.\/\-_~+]#i', /* range of allowed characters in a GET string */
2001
        'UNIFIED_SEARCH' => '#[\\x00]#', /* cn: bug 3356 & 9236 - MBCS search strings */
2002
        'AUTO_INCREMENT' => '#[^0-9\-,\ ]#i',
2003
        'ALPHANUM' => '#[^A-Z0-9\-]#i',
2004
    );
2005
2006
    if (preg_match($filters[$filter], $str)) {
2007
        if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
2008
            $GLOBALS['log']->fatal("SECURITY[$filter]: bad data passed in; string: {$str}");
2009
        }
2010
        if ($dieOnBadData) {
2011
            die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2012
        }
2013
2014
        return false;
2015
    } else {
2016
        return $str;
2017
    }
2018
}
2019
2020
function clean_special_arguments()
2021
{
2022
    if (isset($_SERVER['PHP_SELF'])) {
2023
        if (!empty($_SERVER['PHP_SELF'])) {
2024
            clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
2025
        }
2026
    }
2027
    if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) {
2028
        clean_string($_REQUEST['login_theme'], 'STANDARD');
2029
    }
2030
    if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) {
2031
        clean_string($_REQUEST['login_module'], 'STANDARD');
2032
    }
2033
    if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) {
2034
        clean_string($_REQUEST['login_action'], 'STANDARD');
2035
    }
2036
    if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) {
2037
        clean_string($_REQUEST['ck_login_theme_20'], 'STANDARD');
2038
    }
2039
    if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) {
2040
        clean_string($_SESSION['authenticated_user_theme'], 'STANDARD');
2041
    }
2042
    if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) {
2043
        clean_string($_REQUEST['module_name'], 'STANDARD');
2044
    }
2045
    if (!empty($_REQUEST) && !empty($_REQUEST['module'])) {
2046
        clean_string($_REQUEST['module'], 'STANDARD');
2047
    }
2048
    if (!empty($_POST) && !empty($_POST['parent_type'])) {
2049
        clean_string($_POST['parent_type'], 'STANDARD');
2050
    }
2051
    if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) {
2052
        clean_string($_REQUEST['mod_lang'], 'STANDARD');
2053
    }
2054
    if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) {
2055
        clean_string($_SESSION['authenticated_user_language'], 'STANDARD');
2056
    }
2057
    if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) {
2058
        clean_string($_SESSION['dyn_layout_file'], 'PATH_NO_URL');
2059
    }
2060
    if (!empty($_GET) && !empty($_GET['from'])) {
2061
        clean_string($_GET['from']);
2062
    }
2063
    if (!empty($_GET) && !empty($_GET['gmto'])) {
2064
        clean_string($_GET['gmto'], 'NUMBER');
2065
    }
2066
    if (!empty($_GET) && !empty($_GET['case_number'])) {
2067
        clean_string($_GET['case_number'], 'AUTO_INCREMENT');
2068
    }
2069
    if (!empty($_GET) && !empty($_GET['bug_number'])) {
2070
        clean_string($_GET['bug_number'], 'AUTO_INCREMENT');
2071
    }
2072
    if (!empty($_GET) && !empty($_GET['quote_num'])) {
2073
        clean_string($_GET['quote_num'], 'AUTO_INCREMENT');
2074
    }
2075
    clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
2076
    clean_superglobals('offset', 'ALPHANUM');
2077
    clean_superglobals('return_action');
2078
    clean_superglobals('return_module');
2079
2080
    return true;
2081
}
2082
2083
/**
2084
 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST.
2085
 */
2086
function clean_superglobals($key, $filter = 'STANDARD')
2087
{
2088
    if (isset($_GET[$key])) {
2089
        clean_string($_GET[$key], $filter);
2090
    }
2091
    if (isset($_POST[$key])) {
2092
        clean_string($_POST[$key], $filter);
2093
    }
2094
    if (isset($_REQUEST[$key])) {
2095
        clean_string($_REQUEST[$key], $filter);
2096
    }
2097
}
2098
2099
function set_superglobals($key, $val)
2100
{
2101
    $_GET[$key] = $val;
2102
    $_POST[$key] = $val;
2103
    $_REQUEST[$key] = $val;
2104
}
2105
2106
// Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
2107
function clean_incoming_data()
2108
{
2109
    global $sugar_config;
2110
    global $RAW_REQUEST;
2111
2112
    if (get_magic_quotes_gpc()) {
2113
        // magic quotes screw up data, we'd have to clean up
2114
        $RAW_REQUEST = array_map('cleanup_slashes', $_REQUEST);
2115
    } else {
2116
        $RAW_REQUEST = $_REQUEST;
2117
    }
2118
2119
    if (get_magic_quotes_gpc() == 1) {
2120
        $req = array_map('preprocess_param', $_REQUEST);
2121
        $post = array_map('preprocess_param', $_POST);
2122
        $get = array_map('preprocess_param', $_GET);
2123
    } else {
2124
        $req = array_map('securexss', $_REQUEST);
2125
        $post = array_map('securexss', $_POST);
2126
        $get = array_map('securexss', $_GET);
2127
    }
2128
2129
    // PHP cannot stomp out superglobals reliably
2130
    foreach ($post as $k => $v) {
2131
        $_POST[$k] = $v;
2132
    }
2133
    foreach ($get as $k => $v) {
2134
        $_GET[$k] = $v;
2135
    }
2136
    foreach ($req as $k => $v) {
2137
        $_REQUEST[$k] = $v;
2138
2139
        //ensure the keys are safe as well.  If mbstring encoding translation is on, the post keys don't
2140
        //get translated, so scrub the data but don't die
2141
        if (ini_get('mbstring.encoding_translation') === '1') {
2142
            securexsskey($k, false);
2143
        } else {
2144
            securexsskey($k, true);
2145
        }
2146
    }
2147
    // Any additional variables that need to be cleaned should be added here
2148
    if (isset($_REQUEST['login_theme'])) {
2149
        clean_string($_REQUEST['login_theme']);
2150
    }
2151
    if (isset($_REQUEST['login_module'])) {
2152
        clean_string($_REQUEST['login_module']);
2153
    }
2154
    if (isset($_REQUEST['login_action'])) {
2155
        clean_string($_REQUEST['login_action']);
2156
    }
2157
    if (isset($_REQUEST['login_language'])) {
2158
        clean_string($_REQUEST['login_language']);
2159
    }
2160
    if (isset($_REQUEST['action'])) {
2161
        clean_string($_REQUEST['action']);
2162
    }
2163
    if (isset($_REQUEST['module'])) {
2164
        clean_string($_REQUEST['module']);
2165
    }
2166
    if (isset($_REQUEST['record'])) {
2167
        clean_string($_REQUEST['record'], 'STANDARDSPACE');
2168
    }
2169
    if (isset($_SESSION['authenticated_user_theme'])) {
2170
        clean_string($_SESSION['authenticated_user_theme']);
2171
    }
2172
    if (isset($_SESSION['authenticated_user_language'])) {
2173
        clean_string($_SESSION['authenticated_user_language']);
2174
    }
2175
    if (isset($_REQUEST['language'])) {
2176
        clean_string($_REQUEST['language']);
2177
    }
2178
    if (isset($sugar_config['default_theme'])) {
2179
        clean_string($sugar_config['default_theme']);
2180
    }
2181
    if (isset($_REQUEST['offset'])) {
2182
        clean_string($_REQUEST['offset']);
2183
    }
2184
    if (isset($_REQUEST['stamp'])) {
2185
        clean_string($_REQUEST['stamp']);
2186
    }
2187
2188
    if (isset($_REQUEST['lvso'])) {
2189
        set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc') ? 'desc' : 'asc');
2190
    }
2191
    // Clean "offset" and "order_by" parameters in URL
2192
    foreach ($_REQUEST as $key => $val) {
2193
        if (str_end($key, '_offset')) {
2194
            clean_string($_REQUEST[$key], 'ALPHANUM'); // keep this ALPHANUM for disable_count_query
2195
            set_superglobals($key, $_REQUEST[$key]);
2196
        } elseif (str_end($key, '_ORDER_BY')) {
2197
            clean_string($_REQUEST[$key], 'SQL_COLUMN_LIST');
2198
            set_superglobals($key, $_REQUEST[$key]);
2199
        }
2200
    }
2201
2202
    return 0;
2203
}
2204
2205
// Returns TRUE if $str begins with $begin
2206
function str_begin($str, $begin)
2207
{
2208 99
    return substr($str, 0, strlen($begin)) == $begin;
2209
}
2210
2211
// Returns TRUE if $str ends with $end
2212
function str_end($str, $end)
2213
{
2214
    return substr($str, strlen($str) - strlen($end)) == $end;
2215
}
2216
2217
function securexss($value)
2218
{
2219 1
    if (is_array($value)) {
2220
        $new = array();
2221
        foreach ($value as $key => $val) {
2222
            $new[$key] = securexss($val);
2223
        }
2224
2225
        return $new;
2226
    }
2227 1
    static $xss_cleanup = array('&quot;' => '&#38;', '"' => '&quot;', "'" => '&#039;', '<' => '&lt;', '>' => '&gt;');
2228 1
    $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
2229 1
    $value = preg_replace('/javascript:/i', 'java script:', $value);
2230
2231 1
    return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
2232
}
2233
2234
function securexsskey($value, $die = true)
2235
{
2236
    global $sugar_config;
2237
    $matches = array();
2238
    preg_match('/[\'"<>]/', $value, $matches);
2239
    if (!empty($matches)) {
2240
        if ($die) {
2241
            die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
2242
        } else {
2243
            unset($_REQUEST[$value]);
2244
            unset($_POST[$value]);
2245
            unset($_GET[$value]);
2246
        }
2247
    }
2248
}
2249
2250
function preprocess_param($value)
2251
{
2252
    if (is_string($value)) {
2253
        if (get_magic_quotes_gpc() == 1) {
2254
            $value = stripslashes($value);
2255
        }
2256
2257
        $value = securexss($value);
2258
    } elseif (is_array($value)) {
2259
        foreach ($value as $key => $element) {
2260
            $value[$key] = preprocess_param($element);
2261
        }
2262
    }
2263
2264
    return $value;
2265
}
2266
2267
function cleanup_slashes($value)
2268
{
2269
    if (is_string($value)) {
2270
        return stripslashes($value);
2271
    }
2272
2273
    return $value;
2274
}
2275
2276
function set_register_value($category, $name, $value)
2277
{
2278 4
    return sugar_cache_put("{$category}:{$name}", $value);
2279
}
2280
2281
function get_register_value($category, $name)
2282
{
2283 4
    return sugar_cache_retrieve("{$category}:{$name}");
2284
}
2285
2286
function clear_register_value($category, $name)
2287
{
2288
    return sugar_cache_clear("{$category}:{$name}");
2289
}
2290
2291
// this function cleans id's when being imported
2292
function convert_id($string)
2293
{
2294
    return preg_replace_callback('|[^A-Za-z0-9\-]|',
2295
        create_function(
2296
        // single quotes are essential here,
2297
        // or alternative escape all $ as \$
2298
            '$matches',
2299
            'return ord($matches[0]);'
2300
        ), $string);
2301
}
2302
2303
/**
2304
 * @deprecated use SugarTheme::getImage()
2305
 */
2306
function get_image($image, $other_attributes, $width = '', $height = '', $ext = '.gif', $alt = '')
2307
{
2308
    return SugarThemeRegistry::current()->getImage(basename($image), $other_attributes, empty($width) ? null : $width, empty($height) ? null : $height, $ext, $alt);
2309
}
2310
2311
/**
2312
 * @deprecated use SugarTheme::getImageURL()
2313
 */
2314
function getImagePath($image_name)
2315
{
2316
    return SugarThemeRegistry::current()->getImageURL($image_name);
2317
}
2318
2319
function getWebPath($relative_path)
2320
{
2321
    //if it has  a :// then it isn't a relative path
2322
    if (substr_count($relative_path, '://') > 0) {
2323
        return $relative_path;
2324
    }
2325
    if (defined('TEMPLATE_URL')) {
2326
        $relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2327
    }
2328
2329
    return $relative_path;
2330
}
2331
2332
function getVersionedPath($path, $additional_attrs = '')
2333
{
2334 211
    if (empty($GLOBALS['sugar_config']['js_custom_version'])) {
2335
        $GLOBALS['sugar_config']['js_custom_version'] = 1;
2336
    }
2337 211
    $js_version_key = isset($GLOBALS['js_version_key']) ? $GLOBALS['js_version_key'] : '';
2338 211
    if (inDeveloperMode()) {
2339
        static $rand;
2340
        if (empty($rand)) {
2341
            $rand = mt_rand();
2342
        }
2343
        $dev = $rand;
2344
    } else {
2345 211
        $dev = '';
2346
    }
2347 211
    if (is_array($additional_attrs)) {
2348
        $additional_attrs = implode('|', $additional_attrs);
2349
    }
2350
    // cutting 2 last chars here because since md5 is 32 chars, it's always ==
2351 211
    $str = substr(base64_encode(md5("$js_version_key|{$GLOBALS['sugar_config']['js_custom_version']}|$dev|$additional_attrs", true)), 0, -2);
2352
    // remove / - it confuses some parsers
2353 211
    $str = strtr($str, '/+', '-_');
2354 211
    if (empty($path)) {
2355 198
        return $str;
2356
    }
2357
2358 28
    return $path."?v=$str";
2359
}
2360
2361
function getVersionedScript($path, $additional_attrs = '')
2362
{
2363 5
    return '<script type="text/javascript" src="'.getVersionedPath($path, $additional_attrs).'"></script>';
2364
}
2365
2366
function getJSPath($relative_path, $additional_attrs = '')
2367
{
2368 27
    if (defined('TEMPLATE_URL')) {
2369
        $relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2370
    }
2371
2372 27
    return getVersionedPath($relative_path).(!empty($additional_attrs) ? "&$additional_attrs" : '');
2373
}
2374
2375
function getSWFPath($relative_path, $additional_params = '')
2376
{
2377
    $path = $relative_path;
2378
    if (!empty($additional_params)) {
2379
        $path .= '?'.$additional_params;
2380
    }
2381
    if (defined('TEMPLATE_URL')) {
2382
        $path = TEMPLATE_URL.'/'.$path;
2383
    }
2384
2385
    return $path;
2386
}
2387
2388
function getSQLDate($date_str)
2389
{
2390
    if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/', $date_str, $match)) {
2391
        if (strlen($match[2]) == 1) {
2392
            $match[2] = '0'.$match[2];
2393
        }
2394
        if (strlen($match[1]) == 1) {
2395
            $match[1] = '0'.$match[1];
2396
        }
2397
2398
        return "{$match[3]}-{$match[1]}-{$match[2]}";
2399
    } elseif (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/', $date_str, $match)) {
2400
        if (strlen($match[2]) == 1) {
2401
            $match[2] = '0'.$match[2];
2402
        }
2403
        if (strlen($match[1]) == 1) {
2404
            $match[1] = '0'.$match[1];
2405
        }
2406
2407
        return "{$match[3]}-{$match[1]}-{$match[2]}";
2408
    } else {
2409
        return '';
2410
    }
2411
}
2412
2413
function clone_history(&$db, $from_id, $to_id, $to_type)
2414
{
2415
    global $timedate;
2416
    $old_note_id = null;
2417
    $old_filename = null;
2418
    require_once 'include/upload_file.php';
2419
    $tables = array('calls' => 'Call', 'meetings' => 'Meeting', 'notes' => 'Note', 'tasks' => 'Task');
2420
2421
    $location = array('Email' => 'modules/Emails/Email.php',
2422
        'Call' => 'modules/Calls/Call.php',
2423
        'Meeting' => 'modules/Meetings/Meeting.php',
2424
        'Note' => 'modules/Notes/Note.php',
2425
        'Tasks' => 'modules/Tasks/Task.php',
2426
    );
2427
2428
    foreach ($tables as $table => $bean_class) {
2429
        if (!class_exists($bean_class)) {
2430
            require_once $location[$bean_class];
2431
        }
2432
2433
        $bProcessingNotes = false;
2434
        if ($table == 'notes') {
2435
            $bProcessingNotes = true;
2436
        }
2437
        $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2438
        $results = $db->query($query);
2439
        while ($row = $db->fetchByAssoc($results)) {
2440
            //retrieve existing record.
2441
            $bean = new $bean_class();
2442
            $bean->retrieve($row['id']);
2443
            //process for new instance.
2444
            if ($bProcessingNotes) {
2445
                $old_note_id = $row['id'];
2446
                $old_filename = $bean->filename;
2447
            }
2448
            $bean->id = null;
2449
            $bean->parent_id = $to_id;
2450
            $bean->parent_type = $to_type;
2451
            if ($to_type == 'Contacts' and in_array('contact_id', $bean->column_fields)) {
2452
                $bean->contact_id = $to_id;
2453
            }
2454
            $bean->update_date_modified = false;
2455
            $bean->update_modified_by = false;
2456
            if (isset($bean->date_modified)) {
2457
                $bean->date_modified = $timedate->to_db($bean->date_modified);
2458
            }
2459
            if (isset($bean->date_entered)) {
2460
                $bean->date_entered = $timedate->to_db($bean->date_entered);
2461
            }
2462
            //save
2463
            $new_id = $bean->save();
2464
2465
            //duplicate the file now. for notes.
2466
            if ($bProcessingNotes && !empty($old_filename)) {
2467
                UploadFile::duplicate_file($old_note_id, $new_id, $old_filename);
2468
            }
2469
            //reset the values needed for attachment duplication.
2470
            $old_note_id = null;
2471
            $old_filename = null;
2472
        }
2473
    }
2474
}
2475
2476
function values_to_keys($array)
2477
{
2478
    $new_array = array();
2479
    if (!is_array($array)) {
2480
        return $new_array;
2481
    }
2482
    foreach ($array as $arr) {
2483
        $new_array[$arr] = $arr;
2484
    }
2485
2486
    return $new_array;
2487
}
2488
2489
function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2490
{
2491
    foreach ($tables as $table) {
2492
        if ($table == 'emails_beans') {
2493
            $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2494
        } else {
2495
            $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2496
        }
2497
        $results = $db->query($query);
2498
        while ($row = $db->fetchByAssoc($results)) {
2499
            $query = "INSERT INTO $table ";
2500
            $names = '';
2501
            $values = '';
2502
            $row[$from_column] = $to_id;
2503
            $row['id'] = create_guid();
2504
            if ($table == 'emails_beans') {
2505
                $row['bean_module'] == 'Contacts';
2506
            }
2507
2508
            foreach ($row as $name => $value) {
2509
                if (empty($names)) {
2510
                    $names .= $name;
2511
                    $values .= "'$value'";
2512
                } else {
2513
                    $names .= ', '.$name;
2514
                    $values .= ", '$value'";
2515
                }
2516
            }
2517
            $query .= "($names)	VALUES ($values)";
2518
            $db->query($query);
2519
        }
2520
    }
2521
}
2522
2523
function get_unlinked_email_query($type, $bean)
2524
{
2525 4
    global $current_user;
2526
2527 4
    $return_array['select'] = 'SELECT emails.id ';
2528 4
    $return_array['from'] = 'FROM emails ';
2529 4
    $return_array['where'] = '';
2530 4
    $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2531
2532 4
	join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2533
	eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2534
	where eear.deleted=0 and eear.email_id not in
2535 4
	(select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2536 4
	) derivedemails on derivedemails.email_id = emails.id";
2537 4
    $return_array['join_tables'][0] = '';
2538
2539 4
    if (isset($type) and !empty($type['return_as_array'])) {
2540 1
        return $return_array;
2541
    }
2542
2543 4
    return $return_array['select'].$return_array['from'].$return_array['where'].$return_array['join'];
2544
} // fn
2545
2546
function get_emails_by_assign_or_link($params)
2547
{
2548
    $relation = $params['link'];
2549
    $bean = $GLOBALS['app']->controller->bean;
2550
    if (empty($bean->$relation)) {
2551
        $bean->load_relationship($relation);
2552
    }
2553
    if (empty($bean->$relation)) {
2554
        $GLOBALS['log']->error("Bad relation '$relation' for bean '{$bean->object_name}' id '{$bean->id}'");
2555
2556
        return array();
2557
    }
2558
    $rel_module = $bean->$relation->getRelatedModuleName();
2559
    $rel_join = $bean->$relation->getJoin(array(
2560
        'join_table_alias' => 'link_bean',
2561
        'join_table_link_alias' => 'linkt',
2562
    ));
2563
    $rel_join = str_replace("{$bean->table_name}.id", "'{$bean->id}'", $rel_join);
2564
    $return_array['select'] = 'SELECT DISTINCT emails.id ';
2565
    $return_array['from'] = 'FROM emails ';
2566
2567
    $return_array['join'] = array();
2568
2569
    // directly assigned emails
2570
    $return_array['join'][] = "
2571
        SELECT
2572
            eb.email_id,
2573
            'direct' source
2574
        FROM
2575
            emails_beans eb
2576
        WHERE
2577
            eb.bean_module = '{$bean->module_dir}'
2578
            AND eb.bean_id = '{$bean->id}'
2579
            AND eb.deleted=0
2580
    ";
2581
2582
    // Related by directly by email
2583
    $return_array['join'][] = "
2584
        SELECT DISTINCT
2585
            eear.email_id,
2586
            'relate' source
2587
        FROM
2588
            emails_email_addr_rel eear
2589
        INNER JOIN
2590
            email_addr_bean_rel eabr
2591
        ON
2592
            eabr.bean_id ='{$bean->id}'
2593
            AND eabr.bean_module = '{$bean->module_dir}'
2594
            AND eabr.email_address_id = eear.email_address_id
2595
            AND eabr.deleted=0
2596
        WHERE
2597
            eear.deleted=0
2598
    ";
2599
2600
    $showEmailsOfRelatedContacts = empty($bean->field_defs[$relation]['hide_history_contacts_emails']);
2601
    if (!empty($GLOBALS['sugar_config']['hide_history_contacts_emails']) && isset($GLOBALS['sugar_config']['hide_history_contacts_emails'][$bean->module_name])) {
2602
        $showEmailsOfRelatedContacts = empty($GLOBALS['sugar_config']['hide_history_contacts_emails'][$bean->module_name]);
2603
    }
2604
    if ($showEmailsOfRelatedContacts) {
2605
        // Assigned to contacts
2606
        $return_array['join'][] = "
2607
            SELECT DISTINCT
2608
                eb.email_id,
2609
                'contact' source
2610
            FROM
2611
                emails_beans eb
2612
            $rel_join AND link_bean.id = eb.bean_id
2613
            WHERE
2614
                eb.bean_module = '$rel_module'
2615
                AND eb.deleted=0
2616
        ";
2617
        // Related by email to linked contact
2618
        $return_array['join'][] = "
2619
            SELECT DISTINCT
2620
                eear.email_id,
2621
                'relate_contact' source
2622
            FROM
2623
                emails_email_addr_rel eear
2624
            INNER JOIN
2625
                email_addr_bean_rel eabr
2626
            ON
2627
                eabr.email_address_id=eear.email_address_id
2628
                AND eabr.bean_module = '$rel_module'
2629
                AND eabr.deleted=0
2630
            $rel_join AND link_bean.id = eabr.bean_id
2631
            WHERE
2632
                eear.deleted=0
2633
        ";
2634
    }
2635
2636
    $return_array['join'] = ' INNER JOIN ('.implode(' UNION ', $return_array['join']).') email_ids ON emails.id=email_ids.email_id ';
2637
2638
    $return_array['where'] = ' WHERE emails.deleted=0 ';
2639
2640
    //$return_array['join'] = '';
2641
    $return_array['join_tables'][0] = '';
2642
2643
    if ($bean->object_name == 'Case' && !empty($bean->case_number)) {
2644
        $where = str_replace('%1', $bean->case_number, $bean->getEmailSubjectMacro());
2645
        $return_array['where'] .= "\n AND (email_ids.source = 'direct' OR emails.name LIKE '%$where%')";
2646
    }
2647
2648
    return $return_array;
2649
}
2650
2651
/**
2652
 * Check to see if the number is empty or non-zero.
2653
 *
2654
 * @param $value
2655
 *
2656
 * @return bool
2657
 **/
2658
function number_empty($value)
2659
{
2660 8
    return empty($value) && $value != '0';
2661
}
2662
2663
function get_bean_select_array($add_blank = true, $bean_name, $display_columns, $where = '', $order_by = '', $blank_is_none = false)
2664
{
2665 1
    global $beanFiles;
2666 1
    require_once $beanFiles[$bean_name];
2667 1
    $focus = new $bean_name();
2668 1
    $user_array = array();
2669
2670 1
    $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name.$display_columns.$where.$order_by;
2671 1
    $user_array = get_register_value('select_array', $key);
2672 1
    if (!$user_array) {
2673 1
        $db = DBManagerFactory::getInstance();
2674
2675 1
        $temp_result = array();
2676 1
        $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2677 1
        $query .= 'where ';
2678 1
        if ($where != '') {
2679
            $query .= $where.' AND ';
2680
        }
2681
2682 1
        $query .= " {$focus->table_name}.deleted=0";
2683
2684
        /* BEGIN - SECURITY GROUPS */
2685 1
        global $current_user, $sugar_config;
2686 1
        if ($focus->module_dir == 'Users' && !is_admin($current_user)
2687 1
            && isset($sugar_config['securitysuite_filter_user_list'])
2688 1
            && $sugar_config['securitysuite_filter_user_list'] == true
2689
        ) {
2690
            require_once 'modules/SecurityGroups/SecurityGroup.php';
2691
            $group_where = SecurityGroup::getGroupUsersWhere($current_user->id);
2692
            $query .= ' AND ('.$group_where.') ';
2693 1
        } elseif ($focus->bean_implements('ACL') && ACLController::requireSecurityGroup($focus->module_dir, 'list')) {
2694
            require_once 'modules/SecurityGroups/SecurityGroup.php';
2695
            $owner_where = $focus->getOwnerWhere($current_user->id);
2696
            $group_where = SecurityGroup::getGroupWhere($focus->table_name, $focus->module_dir, $current_user->id);
2697
            if (!empty($owner_where)) {
2698
                $query .= ' AND ('.$owner_where.' or '.$group_where.') ';
2699
            } else {
2700
                $query .= ' AND '.$group_where;
2701
            }
2702
        }
2703
        /* END - SECURITY GROUPS */
2704
2705 1
        if ($order_by != '') {
2706
            $query .= " order by {$focus->table_name}.{$order_by}";
2707
        }
2708
2709 1
        $GLOBALS['log']->debug("get_user_array query: $query");
2710 1
        $result = $db->query($query, true, 'Error filling in user array: ');
2711
2712 1
        if ($add_blank == true) {
2713
            // Add in a blank row
2714 1
            if ($blank_is_none == true) { // set 'blank row' to "--None--"
2715
                global $app_strings;
2716
                $temp_result[''] = $app_strings['LBL_NONE'];
2717
            } else {
2718 1
                $temp_result[''] = '';
2719
            }
2720
        }
2721
2722
        // Get the id and the name.
2723 1
        while ($row = $db->fetchByAssoc($result)) {
2724 1
            $temp_result[$row['id']] = $row['display'];
2725
        }
2726
2727 1
        $user_array = $temp_result;
2728 1
        set_register_value('select_array', $key, $temp_result);
2729
    }
2730
2731 1
    return $user_array;
2732
}
2733
2734
/**
2735
 * @param unknown_type $listArray
2736
 */
2737
// function parse_list_modules
2738
// searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2739
function parse_list_modules(&$listArray)
2740
{
2741
    global $modListHeader;
2742
    $returnArray = array();
2743
2744
    foreach ($listArray as $optionName => $optionVal) {
2745
        if (array_key_exists($optionName, $modListHeader)) {
2746
            $returnArray[$optionName] = $optionVal;
2747
        }
2748
2749
        // special case for projects
2750
        if (array_key_exists('Project', $modListHeader)) {
2751
            $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2752
        }
2753
    }
2754
    $acldenied = ACLController::disabledModuleList($listArray, false);
2755
    foreach ($acldenied as $denied) {
2756
        unset($returnArray[$denied]);
2757
    }
2758
    asort($returnArray);
2759
2760
    return $returnArray;
2761
}
2762
2763
function display_notice($msg = false)
2764
{
2765
    global $error_notice;
2766
    //no error notice - lets just display the error to the user
2767
    if (!isset($error_notice)) {
2768
        echo '<br>'.$msg.'<br>';
2769
    } else {
2770
        $error_notice .= $msg.'<br>';
2771
    }
2772
}
2773
2774
/* checks if it is a number that at least has the plus at the beginning.
2775
 */
2776
function skype_formatted($number)
2777
{
2778
    //kbrill - BUG #15375
2779
    if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'Popup') {
2780
        return false;
2781
    } else {
2782
        return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2783
    }
2784
//	return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2785
}
2786
2787
function format_skype($number)
2788
{
2789
    return preg_replace('/[^\+0-9]/', '', $number);
2790
}
2791
2792
function insert_charset_header()
2793
{
2794 1
    header('Content-Type: text/html; charset=UTF-8');
2795
}
2796
2797
function getCurrentURL()
2798
{
2799
    $href = 'http:';
2800
    if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
2801
        $href = 'https:';
2802
    }
2803
2804
    $href .= '//'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2805
2806
    return $href;
2807
}
2808
2809
function javascript_escape($str)
2810
{
2811
    $new_str = '';
2812
2813
    for ($i = 0; $i < strlen($str); ++$i) {
2814
        if (ord(substr($str, $i, 1)) == 10) {
2815
            $new_str .= '\n';
2816
        } elseif (ord(substr($str, $i, 1)) == 13) {
2817
            $new_str .= '\r';
2818
        } else {
2819
            $new_str .= $str{$i};
2820
        }
2821
    }
2822
2823
    $new_str = str_replace("'", "\\'", $new_str);
2824
2825
    return $new_str;
2826
}
2827
2828
function js_escape($str, $keep = true)
2829
{
2830
    $str = html_entity_decode(str_replace('\\', '', $str), ENT_QUOTES);
2831
2832
    if ($keep) {
2833
        $str = javascript_escape($str);
2834
    } else {
2835
        $str = str_replace("'", ' ', $str);
2836
        $str = str_replace('"', ' ', $str);
2837
    }
2838
2839
    return $str;
2840
2841
    //end function js_escape
2842
}
2843
2844
function br2nl($str)
2845
{
2846 5
    $regex = '#<[^>]+br.+?>#i';
2847 5
    preg_match_all($regex, $str, $matches);
2848
2849 5
    foreach ($matches[0] as $match) {
2850
        $str = str_replace($match, '<br>', $str);
2851
    }
2852
2853 5
    $brs = array('<br>', '<br/>', '<br />');
2854 5
    $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2855 5
    $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2856 5
    $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2857 5
    $str = str_ireplace($brs, "\n", $str); // to retrieve it
2858
2859 5
    return $str;
2860
}
2861
2862
/**
2863
 * Private helper function for displaying the contents of a given variable.
2864
 * This function is only intended to be used for SugarCRM internal development.
2865
 * The ppd stands for Pre Print Die.
2866
 */
2867
function _ppd($mixed)
2868
{
2869
}
2870
2871
/**
2872
 * Private helper function for displaying the contents of a given variable in
2873
 * the Logger. This function is only intended to be used for SugarCRM internal
2874
 * development. The pp stands for Pre Print.
2875
 *
2876
 * @param $mixed var to print_r()
2877
 * @param $die boolean end script flow
2878
 * @param $displayStackTrace also show stack trace
2879
 */
2880
function _ppl($mixed, $die = false, $displayStackTrace = false, $loglevel = 'fatal')
2881
{
2882
    if (!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2883
        $GLOBALS['log'] = LoggerManager:: getLogger('SugarCRM');
2884
    }
2885
2886
    $mix = print_r($mixed, true); // send print_r() output to $mix
2887
    $stack = debug_backtrace();
2888
2889
    $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2890
    $GLOBALS['log']->$loglevel($mix);
2891
    if ($displayStackTrace) {
2892
        foreach ($stack as $position) {
2893
            $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2894
        }
2895
    }
2896
2897
    $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2898
    $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2899
2900
    if ($die) {
2901
        die();
2902
    }
2903
}
2904
2905
/**
2906
 * private helper function to quickly show the major, direct, field attributes of a given bean.
2907
 * The ppf stands for Pre[formatted] Print Focus [object].
2908
 *
2909
 * @param object bean The focus bean
2910
 */
2911
function _ppf($bean, $die = false)
2912
{
2913
}
2914
2915
/**
2916
 * Private helper function for displaying the contents of a given variable.
2917
 * This function is only intended to be used for SugarCRM internal development.
2918
 * The pp stands for Pre Print.
2919
 */
2920
function _pp($mixed)
2921
{
2922
}
2923
2924
/**
2925
 * Private helper function for displaying the contents of a given variable.
2926
 * This function is only intended to be used for SugarCRM internal development.
2927
 * The pp stands for Pre Print.
2928
 */
2929
function _pstack_trace($mixed = null)
2930
{
2931
}
2932
2933
/**
2934
 * Private helper function for displaying the contents of a given variable.
2935
 * This function is only intended to be used for SugarCRM internal development.
2936
 * The pp stands for Pre Print Trace.
2937
 */
2938
function _ppt($mixed, $textOnly = false)
2939
{
2940
}
2941
2942
/**
2943
 * Private helper function for displaying the contents of a given variable.
2944
 * This function is only intended to be used for SugarCRM internal development.
2945
 * The pp stands for Pre Print Trace Die.
2946
 */
2947
function _pptd($mixed)
2948
{
2949
}
2950
2951
/**
2952
 * Private helper function for decoding javascript UTF8
2953
 * This function is only intended to be used for SugarCRM internal development.
2954
 */
2955
function decodeJavascriptUTF8($str)
2956
{
2957
}
2958
2959
/**
2960
 * Will check if a given PHP version string is supported (tested on this ver),
2961
 * unsupported (results unknown), or invalid (something will break on this
2962
 * ver).  Do not pass in any pararameter to default to a check against the
2963
 * current environment's PHP version.
2964
 *
2965
 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2966
 */
2967
function check_php_version($sys_php_version = '')
2968
{
2969
    $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2970
    // versions below $min_considered_php_version considered invalid by default,
2971
    // versions equal to or above this ver will be considered depending
2972
    // on the rules that follow
2973
    $min_considered_php_version = '5.3.0';
2974
2975
    // only the supported versions,
2976
    // should be mutually exclusive with $invalid_php_versions
2977
    $supported_php_versions = array(
2978
        '5.3.0',
2979
    );
2980
2981
    // invalid versions above the $min_considered_php_version,
2982
    // should be mutually exclusive with $supported_php_versions
2983
2984
    // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2985
    $invalid_php_versions = array('5.2.7');
2986
2987
    // default unsupported
2988
    $retval = 0;
2989
2990
    // versions below $min_considered_php_version are invalid
2991
    if (1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2992
        $retval = -1;
2993
    }
2994
2995
    // supported version check overrides default unsupported
2996
    foreach ($supported_php_versions as $ver) {
2997
        if (1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version, $ver) !== false) {
2998
            $retval = 1;
2999
            break;
3000
        }
3001
    }
3002
3003
    // invalid version check overrides default unsupported
3004
    foreach ($invalid_php_versions as $ver) {
3005
        if (1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version, $ver) !== false) {
3006
            $retval = -1;
3007
            break;
3008
        }
3009
    }
3010
3011
    //allow a redhat distro to install, regardless of version.  We are assuming the redhat naming convention is followed
3012
    //and the php version contains 'rh' characters
3013
    if (strpos($sys_php_version, 'rh') !== false) {
3014
        $retval = 1;
3015
    }
3016
3017
    return $retval;
3018
}
3019
3020
/**
3021
 * Will check if a given IIS version string is supported (tested on this ver),
3022
 * unsupported (results unknown), or invalid (something will break on this
3023
 * ver).
3024
 *
3025
 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
3026
 */
3027
function check_iis_version($sys_iis_version = '')
3028
{
3029
    $server_software = $_SERVER['SERVER_SOFTWARE'];
3030
    $iis_version = '';
3031
    if (strpos($server_software, 'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out)) {
3032
        $iis_version = $out[1][0];
3033
    }
3034
3035
    $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
3036
3037
    // versions below $min_considered_iis_version considered invalid by default,
3038
    // versions equal to or above this ver will be considered depending
3039
    // on the rules that follow
3040
    $min_considered_iis_version = '6.0';
3041
3042
    // only the supported versions,
3043
    // should be mutually exclusive with $invalid_iis_versions
3044
    $supported_iis_versions = array('6.0', '7.0');
3045
    $unsupported_iis_versions = array();
3046
    $invalid_iis_versions = array('5.0');
3047
3048
    // default unsupported
3049
    $retval = 0;
3050
3051
    // versions below $min_considered_iis_version are invalid
3052
    if (1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
3053
        $retval = -1;
3054
    }
3055
3056
    // supported version check overrides default unsupported
3057
    foreach ($supported_iis_versions as $ver) {
3058
        if (1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version, $ver) !== false) {
3059
            $retval = 1;
3060
            break;
3061
        }
3062
    }
3063
3064
    // unsupported version check overrides default unsupported
3065
    foreach ($unsupported_iis_versions as $ver) {
3066
        if (1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version, $ver) !== false) {
3067
            $retval = 0;
3068
            break;
3069
        }
3070
    }
3071
3072
    // invalid version check overrides default unsupported
3073
    foreach ($invalid_iis_versions as $ver) {
3074
        if (1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version, $ver) !== false) {
3075
            $retval = -1;
3076
            break;
3077
        }
3078
    }
3079
3080
    return $retval;
3081
}
3082
3083
function pre_login_check()
3084
{
3085
    global $action, $login_error;
3086
    if (!empty($action) && $action == 'Login') {
3087
        if (!empty($login_error)) {
3088
            $login_error = htmlentities($login_error);
3089
            $login_error = str_replace(array('&lt;pre&gt;', '&lt;/pre&gt;', "\r\n", "\n"), '<br>', $login_error);
3090
            $_SESSION['login_error'] = $login_error;
3091
            echo '<script>
3092
						function set_focus() {}
3093
						if(document.getElementById("post_error")) {
3094
							document.getElementById("post_error").innerHTML="'.$login_error.'";
3095
							document.getElementById("cant_login").value=1;
3096
							document.getElementById("login_button").disabled = true;
3097
							document.getElementById("user_name").disabled = true;
3098
							//document.getElementById("user_password").disabled = true;
3099
						}
3100
						</script>';
3101
        }
3102
    }
3103
}
3104
3105
function sugar_cleanup($exit = false)
3106
{
3107
    static $called = false;
3108
    if ($called) {
3109
        return;
3110
    }
3111
    $called = true;
3112
    set_include_path(realpath(dirname(__FILE__).'/..').PATH_SEPARATOR.get_include_path());
3113
    chdir(realpath(dirname(__FILE__).'/..'));
3114
    global $sugar_config;
3115
    require_once 'include/utils/LogicHook.php';
3116
    LogicHook::initialize();
3117
    $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
3118
3119
    //added this check to avoid errors during install.
3120
    if (empty($sugar_config['dbconfig'])) {
3121
        if ($exit) {
3122
            exit;
3123
        } else {
3124
            return;
3125
        }
3126
    }
3127
3128
    if (!class_exists('Tracker', true)) {
3129
        require_once 'modules/Trackers/Tracker.php';
3130
    }
3131
    Tracker::logPage();
3132
    // Now write the cached tracker_queries
3133
    if (!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
3134
        if (isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceof User) {
3135
            $GLOBALS['current_user']->savePreferencesToDB();
3136
        }
3137
    }
3138
3139
    //check to see if this is not an `ajax call AND the user preference error flag is set
3140
    if (
3141
        (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
3142
        && ($_REQUEST['action'] != 'modulelistmenu' && $_REQUEST['action'] != 'DynamicAction')
3143
        && ($_REQUEST['action'] != 'favorites' && $_REQUEST['action'] != 'DynamicAction')
3144
        && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'])
3145
        && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'])
3146
3147
    ) {
3148
        global $app_strings;
3149
        //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
3150
        $err_mess = $app_strings['ERROR_USER_PREFS'];
3151
        $_SESSION['USER_PREFRENCE_ERRORS'] = false;
3152
        echo "
3153
		<script>
3154
			ajaxStatus.flashStatus('$err_mess',7000);
3155
		</script>";
3156
    }
3157
3158
    pre_login_check();
3159
    if (class_exists('DBManagerFactory')) {
3160
        $db = DBManagerFactory::getInstance();
3161
        $db->disconnect();
3162
        if ($exit) {
3163
            exit;
3164
        }
3165
    }
3166
}
3167
3168
register_shutdown_function('sugar_cleanup');
3169
3170
/*
3171
 check_logic_hook - checks to see if your custom logic is in the logic file
3172
 if not, it will add it. If the file isn't built yet, it will create the file
3173
3174
 */
3175
function check_logic_hook_file($module_name, $event, $action_array)
3176
{
3177
    require_once 'include/utils/logic_utils.php';
3178
    $add_logic = false;
3179
3180
    if (file_exists("custom/modules/$module_name/logic_hooks.php")) {
3181
        $hook_array = get_hook_array($module_name);
3182
3183
        if (check_existing_element($hook_array, $event, $action_array) == true) {
3184
            //the hook at hand is present, so do nothing
3185
        } else {
3186
            $add_logic = true;
3187
3188
            $logic_count = 0;
3189
            if (!empty($hook_array[$event])) {
3190
                $logic_count = count($hook_array[$event]);
3191
            }
3192
3193
            if ($action_array[0] == '') {
3194
                $action_array[0] = $logic_count + 1;
3195
            }
3196
            $hook_array[$event][] = $action_array;
3197
        }
3198
        //end if the file exists already
3199
    } else {
3200
        $add_logic = true;
3201
        if ($action_array[0] == '') {
3202
            $action_array[0] = 1;
3203
        }
3204
        $hook_array = array();
3205
        $hook_array[$event][] = $action_array;
3206
        //end if else file exists already
3207
    }
3208
    if ($add_logic == true) {
3209
3210
        //reorder array by element[0]
3211
        //$hook_array = reorder_array($hook_array, $event);
3212
        //!!!Finish this above TODO
3213
3214
        $new_contents = replace_or_add_logic_type($hook_array);
3215
        write_logic_file($module_name, $new_contents);
3216
3217
        //end if add_element is true
3218
    }
3219
3220
    //end function check_logic_hook_file
3221
}
3222
3223
function remove_logic_hook($module_name, $event, $action_array)
3224
{
3225
    require_once 'include/utils/logic_utils.php';
3226
    $add_logic = false;
3227
3228
    if (file_exists('custom/modules/'.$module_name.'/logic_hooks.php')) {
3229
        // The file exists, let's make sure the hook is there
3230
        $hook_array = get_hook_array($module_name);
3231
3232
        if (check_existing_element($hook_array, $event, $action_array) == true) {
3233
            // The hook is there, time to take it out.
3234
3235
            foreach ($hook_array[$event] as $i => $hook) {
3236
                // We don't do a full comparison below just in case the filename changes
3237
                if ($hook[0] == $action_array[0]
3238
                    && $hook[1] == $action_array[1]
3239
                    && $hook[3] == $action_array[3]
3240
                    && $hook[4] == $action_array[4]
3241
                ) {
3242
                    unset($hook_array[$event][$i]);
3243
                }
3244
            }
3245
3246
            $new_contents = replace_or_add_logic_type($hook_array);
3247
            write_logic_file($module_name, $new_contents);
3248
        }
3249
    }
3250
}
3251
3252
function display_stack_trace($textOnly = false)
3253
{
3254
    $stack = debug_backtrace();
3255
3256
    echo "\n\n display_stack_trace caller, file: ".$stack[0]['file'].' line#: '.$stack[0]['line'];
3257
3258
    if (!$textOnly) {
3259
        echo '<br>';
3260
    }
3261
3262
    $first = true;
3263
    $out = '';
3264
3265
    foreach ($stack as $item) {
3266
        $file = '';
3267
        $class = '';
3268
        $line = '';
3269
        $function = '';
3270
3271
        if (isset($item['file'])) {
3272
            $file = $item['file'];
3273
        }
3274
        if (isset($item['class'])) {
3275
            $class = $item['class'];
3276
        }
3277
        if (isset($item['line'])) {
3278
            $line = $item['line'];
3279
        }
3280
        if (isset($item['function'])) {
3281
            $function = $item['function'];
3282
        }
3283
3284
        if (!$first) {
3285
            if (!$textOnly) {
3286
                $out .= '<font color="black"><b>';
3287
            }
3288
3289
            $out .= $file;
3290
3291
            if (!$textOnly) {
3292
                $out .= '</b></font><font color="blue">';
3293
            }
3294
3295
            $out .= "[L:{$line}]";
3296
3297
            if (!$textOnly) {
3298
                $out .= '</font><font color="red">';
3299
            }
3300
3301
            $out .= "({$class}:{$function})";
3302
3303
            if (!$textOnly) {
3304
                $out .= '</font><br>';
3305
            } else {
3306
                $out .= "\n";
3307
            }
3308
        } else {
3309
            $first = false;
3310
        }
3311
    }
3312
3313
    echo $out;
3314
}
3315
3316
function StackTraceErrorHandler($errno, $errstr, $errfile, $errline, $errcontext)
3317
{
3318
    $error_msg = " $errstr occurred in <b>$errfile</b> on line $errline [".date('Y-m-d H:i:s').']';
3319
    $halt_script = true;
3320
    switch ($errno) {
3321
        case 2048 :
3322
            return; //depricated we have lots of these ignore them
3323
        case E_USER_NOTICE:
3324
        case E_NOTICE:
3325
            if (error_reporting() & E_NOTICE) {
3326
                $halt_script = false;
3327
                $type = 'Notice';
3328
            } else {
3329
                return;
3330
            }
3331
            break;
3332
        case E_USER_WARNING:
3333
        case E_COMPILE_WARNING:
3334
        case E_CORE_WARNING:
3335
        case E_WARNING:
3336
3337
            $halt_script = false;
3338
            $type = 'Warning';
3339
            break;
3340
3341
        case E_USER_ERROR:
3342
        case E_COMPILE_ERROR:
3343
        case E_CORE_ERROR:
3344
        case E_ERROR:
3345
3346
            $type = 'Fatal Error';
3347
            break;
3348
3349
        case E_PARSE:
3350
3351
            $type = 'Parse Error';
3352
            break;
3353
3354
        default:
3355
            //don't know what it is might not be so bad
3356
            $halt_script = false;
3357
            $type = "Unknown Error ($errno)";
3358
            break;
3359
    }
3360
    $error_msg = '<b>'.$type.'</b>:'.$error_msg;
3361
    echo $error_msg;
3362
    display_stack_trace();
3363
    if ($halt_script) {
3364
        exit -1;
3365
    }
3366
}
3367
3368
if (isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']) {
3369
    set_error_handler('StackTraceErrorHandler');
3370
}
3371
function get_sub_cookies($name)
3372
{
3373
    $cookies = array();
3374
    if (isset($_COOKIE[$name])) {
3375
        $subs = explode('#', $_COOKIE[$name]);
3376
        foreach ($subs as $cookie) {
3377
            if (!empty($cookie)) {
3378
                $cookie = explode('=', $cookie);
3379
3380
                $cookies[$cookie[0]] = $cookie[1];
3381
            }
3382
        }
3383
    }
3384
3385
    return $cookies;
3386
}
3387
3388
function mark_delete_components($sub_object_array, $run_second_level = false, $sub_sub_array = '')
3389
{
3390
    if (!empty($sub_object_array)) {
3391
        foreach ($sub_object_array as $sub_object) {
3392
3393
            //run_second level is set to true if you need to remove sub-sub components
3394
            if ($run_second_level == true) {
3395
                mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'], $sub_sub_array['rel_module']));
3396
3397
                //end if run_second_level is true
3398
            }
3399
            $sub_object->mark_deleted($sub_object->id);
3400
            //end foreach sub component
3401
        }
3402
        //end if this is not empty
3403
    }
3404
3405
    //end function mark_delete_components
3406
}
3407
3408
/**
3409
 * For translating the php.ini memory values into bytes.  e.g. input value of '8M' will return 8388608.
3410
 */
3411
function return_bytes($val)
3412
{
3413
    $val = trim($val);
3414
    $last = strtolower($val{strlen($val) - 1});
3415
3416
    switch ($last) {
3417
        // The 'G' modifier is available since PHP 5.1.0
3418
        case 'g':
3419
            $val *= 1024;
3420
        case 'm':
3421
            $val *= 1024;
3422
        case 'k':
3423
            $val *= 1024;
3424
    }
3425
3426
    return $val;
3427
}
3428
3429
/**
3430
 * Adds the href HTML tags around any URL in the $string.
3431
 */
3432
function url2html($string)
3433
{
3434
    //
3435 2
    $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new"  style="font-weight: normal;">\\1\\2</a>', $string);
3436
3437 2
    return $return_string;
3438
}
3439
3440
// End customization by Julian
3441
3442
/**
3443
 * tries to determine whether the Host machine is a Windows machine.
3444
 */
3445
function is_windows()
3446
{
3447 876
    static $is_windows = null;
3448 876
    if (!isset($is_windows)) {
3449 1
        $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3450
    }
3451
3452 876
    return $is_windows;
3453
}
3454
3455
/**
3456
 * equivalent for windows filesystem for PHP's is_writable().
3457
 *
3458
 * @param string file Full path to the file/dir
3459
 *
3460
 * @return bool true if writable
3461
 */
3462
function is_writable_windows($file)
3463
{
3464
    if ($file{strlen($file) - 1} == '/') {
3465
        return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3466
    }
3467
3468
    // the assumption here is that Windows has an inherited permissions scheme
3469
    // any file that is a descendant of an unwritable directory will inherit
3470
    // that property and will trigger a failure below.
3471
    if (is_dir($file)) {
3472
        return true;
3473
    }
3474
3475
    $file = str_replace('/', '\\', $file);
3476
3477
    if (file_exists($file)) {
3478
        if (!($f = @sugar_fopen($file, 'r+'))) {
3479
            return false;
3480
        }
3481
        fclose($f);
3482
3483
        return true;
3484
    }
3485
3486
    if (!($f = @sugar_fopen($file, 'w'))) {
3487
        return false;
3488
    }
3489
    fclose($f);
3490
    unlink($file);
3491
3492
    return true;
3493
}
3494
3495
/**
3496
 * best guesses Timezone based on webserver's TZ settings.
3497
 */
3498
function lookupTimezone($userOffset = 0)
3499
{
3500
    return TimeDate::guessTimezone($userOffset);
3501
}
3502
3503
function convert_module_to_singular($module_array)
3504
{
3505
    global $beanList;
3506
3507
    foreach ($module_array as $key => $value) {
3508
        if (!empty($beanList[$value])) {
3509
            $module_array[$key] = $beanList[$value];
3510
        }
3511
3512
        if ($value == 'Cases') {
3513
            $module_array[$key] = 'Case';
3514
        }
3515
        if ($key == 'projecttask') {
3516
            $module_array['ProjectTask'] = 'Project Task';
3517
            unset($module_array[$key]);
3518
        }
3519
    }
3520
3521
    return $module_array;
3522
3523
    //end function convert_module_to_singular
3524
}
3525
3526
/*
3527
 * Given the bean_name which may be plural or singular return the singular
3528
 * bean_name. This is important when you need to include files.
3529
 */
3530
function get_singular_bean_name($bean_name)
3531
{
3532
    global $beanFiles, $beanList;
3533
    if (array_key_exists($bean_name, $beanList)) {
3534
        return $beanList[$bean_name];
3535
    } else {
3536
        return $bean_name;
3537
    }
3538
}
3539
3540
/*
3541
 * Given the potential module name (singular name, renamed module name)
3542
 * Return the real internal module name.
3543
 */
3544
function get_module_from_singular($singular)
3545
{
3546
3547
    // find the internal module name for a singular name
3548
    if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3549
        $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3550
3551
        foreach ($singular_modules as $mod_name => $sin_name) {
3552
            if ($singular == $sin_name and $mod_name != $sin_name) {
3553
                return $mod_name;
3554
            }
3555
        }
3556
    }
3557
3558
    // find the internal module name for a renamed module
3559
    if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3560
        $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3561
3562
        foreach ($moduleList as $mod_name => $name) {
3563
            if ($singular == $name and $mod_name != $name) {
3564
                return $mod_name;
3565
            }
3566
        }
3567
    }
3568
3569
    // if it's not a singular name, nor a renamed name, return the original value
3570
    return $singular;
3571
}
3572
3573
function get_label($label_tag, $temp_module_strings)
3574
{
3575
    global $app_strings;
3576
    if (!empty($temp_module_strings[$label_tag])) {
3577
        $label_name = $temp_module_strings[$label_tag];
3578
    } else {
3579
        if (!empty($app_strings[$label_tag])) {
3580
            $label_name = $app_strings[$label_tag];
3581
        } else {
3582
            $label_name = $label_tag;
3583
        }
3584
    }
3585
3586
    return $label_name;
3587
3588
    //end function get_label
3589
}
3590
3591
function search_filter_rel_info(&$focus, $tar_rel_module, $relationship_name)
3592
{
3593
    $rel_list = array();
3594
3595
    foreach ($focus->relationship_fields as $rel_key => $rel_value) {
3596
        if ($rel_value == $relationship_name) {
3597
            $temp_bean = BeanFactory::getBean($tar_rel_module, $focus->$rel_key);
3598
            if ($temp_bean) {
3599
                $rel_list[] = $temp_bean;
3600
3601
                return $rel_list;
3602
            }
3603
        }
3604
    }
3605
3606
    foreach ($focus->field_defs as $field_name => $field_def) {
3607
        //Check if the relationship_name matches a "relate" field
3608
        if (!empty($field_def['type']) && $field_def['type'] == 'relate'
3609
            && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3610
            && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3611
            && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name
3612
        ) {
3613
            $temp_bean = BeanFactory::getBean($tar_rel_module, $field_def['id_name']);
3614
            if ($temp_bean) {
3615
                $rel_list[] = $temp_bean;
3616
3617
                return $rel_list;
3618
            }
3619
            //Check if the relationship_name matches a "link" in a relate field
3620
        } elseif (!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name) {
3621
            $temp_bean = BeanFactory::getBean($tar_rel_module, $rel_value['id_name']);
3622
            if ($temp_bean) {
3623
                $rel_list[] = $temp_bean;
3624
3625
                return $rel_list;
3626
            }
3627
        }
3628
    }
3629
3630
    // special case for unlisted parent-type relationships
3631
    if (!empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3632
        $temp_bean = BeanFactory::getBean($tar_rel_module, $focus->parent_id);
3633
        if ($temp_bean) {
3634
            $rel_list[] = $temp_bean;
3635
3636
            return $rel_list;
3637
        }
3638
    }
3639
3640
    return $rel_list;
3641
3642
    //end function search_filter_rel_info
3643
}
3644
3645
function get_module_info($module_name)
3646
{
3647 6
    global $beanList;
3648 6
    global $dictionary;
3649
3650
    //Get dictionary and focus data for module
3651 6
    $vardef_name = $beanList[$module_name];
3652
3653 6
    if ($vardef_name == 'aCase') {
3654
        $class_name = 'Case';
3655
    } else {
3656 6
        $class_name = $vardef_name;
3657
    }
3658
3659 6
    if (!file_exists('modules/'.$module_name.'/'.$class_name.'.php')) {
3660
        return;
3661
    }
3662
3663 6
    include_once 'modules/'.$module_name.'/'.$class_name.'.php';
3664
3665 6
    $module_bean = new $vardef_name();
3666
3667 6
    return $module_bean;
3668
    //end function get_module_table
3669
}
3670
3671
/**
3672
 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3673
 *
3674
 * @param string $moduleName
3675
 */
3676
function get_valid_bean_name($module_name)
3677
{
3678
    global $beanList;
3679
3680
    $vardef_name = $beanList[$module_name];
3681
    if ($vardef_name == 'aCase') {
3682
        $bean_name = 'Case';
3683
    } else {
3684
        $bean_name = $vardef_name;
3685
    }
3686
3687
    return $bean_name;
3688
}
3689
3690
function checkAuthUserStatus()
3691
{
3692
3693
    //authUserStatus();
3694
}
3695
3696
/**
3697
 * This function returns an array of phpinfo() results that can be parsed and
3698
 * used to figure out what version we run, what modules are compiled in, etc.
3699
 *
3700
 * @param   $level int        info level constant (1,2,4,8...64);
3701
 *
3702
 * @return $returnInfo array    array of info about the PHP environment
3703
 *
3704
 * @author    original by "code at adspeed dot com" Fron php.net
3705
 * @author    customized for Sugar by Chris N.
3706
 */
3707
function getPhpInfo($level = -1)
3708
{
3709
    /*	Name (constant)		Value	Description
3710
        INFO_GENERAL		1		The configuration line, php.ini location, build date, Web Server, System and more.
3711
        INFO_CREDITS		2		PHP Credits. See also phpcredits().
3712
        INFO_CONFIGURATION	4		Current Local and Master values for PHP directives. See also ini_get().
3713
        INFO_MODULES		8		Loaded modules and their respective settings. See also get_loaded_extensions().
3714
        INFO_ENVIRONMENT	16		Environment Variable information that's also available in $_ENV.
3715
        INFO_VARIABLES		32		Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3716
        INFO_LICENSE		64		PHP License information. See also the license FAQ.
3717
        INFO_ALL			-1		Shows all of the above. This is the default value.
3718
     */
3719
    ob_start();
3720
    phpinfo($level);
3721
    $phpinfo = ob_get_contents();
3722
    ob_end_clean();
3723
3724
    $phpinfo = strip_tags($phpinfo, '<h1><h2><th><td>');
3725
    $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/', '<info>\\1</info>', $phpinfo);
3726
    $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/', '<info>\\1</info>', $phpinfo);
3727
    $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3728
    $match = '';
3729
    $version = '';
3730
    $returnInfo = array();
3731
3732
    if (preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3733
        $returnInfo['PHP Version'] = $version[1];
3734
    }
3735
3736
    for ($i = 1; $i < count($parsedInfo); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
3737
        if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3738
            $vName = trim($match[1]);
3739
            $parsedInfo2 = explode("\n", $parsedInfo[$i + 1]);
3740
3741
            foreach ($parsedInfo2 as $vOne) {
3742
                $vPat = '<info>([^<]+)<\/info>';
3743
                $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3744
                $vPat2 = "/$vPat\s*$vPat/";
3745
3746
                if (preg_match($vPat3, $vOne, $match)) { // 3cols
3747
                    $returnInfo[$vName][trim($match[1])] = array(trim($match[2]), trim($match[3]));
3748
                } elseif (preg_match($vPat2, $vOne, $match)) { // 2cols
3749
                    $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3750
                }
3751
            }
3752
        } elseif (true) {
3753
        }
3754
    }
3755
3756
    return $returnInfo;
3757
}
3758
3759
/**
3760
 * This function will take a string that has tokens like {0}, {1} and will replace
3761
 * those tokens with the args provided.
3762
 *
3763
 * @param   $format string to format
3764
 * @param   $args   args to replace
3765
 *
3766
 * @return $result a formatted string
3767
 */
3768
function string_format($format, $args)
3769
{
3770 2
    $result = $format;
3771
3772
    /* Bug47277 fix.
3773
     * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3774
     * IN () fails and IN ('') works.
3775
     */
3776 2
    if (count($args) == 1) {
3777 2
        reset($args);
3778 2
        $singleArgument = current($args);
3779 2
        if (empty($singleArgument)) {
3780 1
            return str_replace('{0}', "''", $result);
3781
        }
3782
    }
3783
    /* End of fix */
3784
3785 1
    for ($i = 0; $i < count($args); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
3786 1
        $result = str_replace('{'.$i.'}', $args[$i], $result);
3787
    }
3788
3789 1
    return $result;
3790
}
3791
3792
/**
3793
 * Generate a string for displaying a unique identifier that is composed
3794
 * of a system_id and number.  This is use to allow us to generate quote
3795
 * numbers using a DB auto-increment key from offline clients and still
3796
 * have the number be unique (since it is modified by the system_id.
3797
 *
3798
 * @param   $num       of bean
3799
 * @param   $system_id from system
3800
 *
3801
 * @return $result a formatted string
3802
 */
3803
function format_number_display($num, $system_id)
3804
{
3805
    global $sugar_config;
3806
    if (isset($num) && !empty($num)) {
3807
        $num = unformat_number($num);
3808
        if (isset($system_id) && $system_id == 1) {
3809
            return sprintf('%d', $num);
3810
        } else {
3811
            return sprintf('%d-%d', $num, $system_id);
3812
        }
3813
    }
3814
}
3815
3816
function checkLoginUserStatus()
3817
{
3818
}
3819
3820
/**
3821
 * This function will take a number and system_id and format.
3822
 *
3823
 * @param   $url  URL containing host to append port
3824
 * @param   $port the port number - if '' is passed, no change to url
3825
 *
3826
 * @return $resulturl the new URL with the port appended to the host
3827
 */
3828
function appendPortToHost($url, $port)
3829
{
3830
    $resulturl = $url;
3831
3832
    // if no port, don't change the url
3833
    if ($port != '') {
3834
        $split = explode('/', $url);
3835
        //check if it starts with http, in case they didn't include that in url
3836
        if (str_begin($url, 'http')) {
3837
            //third index ($split[2]) will be the host
3838
            $split[2] .= ':'.$port;
3839
        } else {
3840
            // otherwise assumed to start with host name
3841
3842
            //first index ($split[0]) will be the host
3843
            $split[0] .= ':'.$port;
3844
        }
3845
3846
        $resulturl = implode('/', $split);
3847
    }
3848
3849
    return $resulturl;
3850
}
3851
3852
/**
3853
 * Singleton to return JSON object.
3854
 *
3855
 * @return JSON object
3856
 */
3857
function getJSONobj()
3858
{
3859 9
    static $json = null;
3860 9
    if (!isset($json)) {
3861 1
        require_once 'include/JSON.php';
3862 1
        $json = new JSON(JSON_LOOSE_TYPE);
3863
    }
3864
3865 9
    return $json;
3866
}
3867
3868
require_once 'include/utils/db_utils.php';
3869
3870
/**
3871
 * Set default php.ini settings for entry points.
3872
 */
3873
function setPhpIniSettings()
3874
{
3875
    // zlib module
3876
    // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3877
    /*
3878
    if(function_exists('gzclose') && headers_sent() == false) {
3879
        ini_set('zlib.output_compression', 1);
3880
    }
3881
    */
3882
    // mbstring module
3883
    //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3884
3885
    /*if(function_exists('mb_strlen')) {
3886
        ini_set('mbstring.func_overload', 7);
3887
        ini_set('mbstring.internal_encoding', 'UTF-8');
3888
    }*/
3889
3890
    // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3891
    // starting with 5.2.0, backtrack_limit breaks JSON decoding
3892
    $backtrack_limit = ini_get('pcre.backtrack_limit');
3893
    if (!empty($backtrack_limit)) {
3894
        ini_set('pcre.backtrack_limit', '-1');
3895
    }
3896
}
3897
3898
/**
3899
 * Identical to sugarArrayMerge but with some speed improvements and used specifically to merge
3900
 * language files.  Language file merges do not need to account for null values so we can get some
3901
 * performance increases by using this specialized function. Note this merge function does not properly
3902
 * handle null values.
3903
 *
3904
 * @param $gimp
3905
 * @param $dom
3906
 *
3907
 * @return array
3908
 */
3909
function sugarLangArrayMerge($gimp, $dom)
3910
{
3911 20
    if (is_array($gimp) && is_array($dom)) {
3912 20
        foreach ($dom as $domKey => $domVal) {
3913 20
            if (isset($gimp[$domKey])) {
3914 20
                if (is_array($domVal)) {
3915
                    $tempArr = array();
3916
                    foreach ($domVal as $domArrKey => $domArrVal) {
3917
                        $tempArr[$domArrKey] = $domArrVal;
3918
                    }
3919
                    foreach ($gimp[$domKey] as $gimpArrKey => $gimpArrVal) {
3920
                        if (!isset($tempArr[$gimpArrKey])) {
3921
                            $tempArr[$gimpArrKey] = $gimpArrVal;
3922
                        }
3923
                    }
3924
                    $gimp[$domKey] = $tempArr;
3925
                } else {
3926 20
                    $gimp[$domKey] = $domVal;
3927
                }
3928
            } else {
3929 20
                $gimp[$domKey] = $domVal;
3930
            }
3931
        }
3932
    } // if the passed value for gimp isn't an array, then return the $dom
3933
    elseif (is_array($dom)) {
3934
        return $dom;
3935
    }
3936
3937 20
    return $gimp;
3938
}
3939
3940
/**
3941
 * like array_merge() but will handle array elements that are themselves arrays;
3942
 * PHP's version just overwrites the element with the new one.
3943
 *
3944
 * @internal Note that this function deviates from the internal array_merge()
3945
 *           functions in that it does does not treat numeric keys differently
3946
 *           than string keys.  Additionally, it deviates from
3947
 *           array_merge_recursive() by not creating an array when like values
3948
 *           found.
3949
 *
3950
 * @param array gimp the array whose values will be overloaded
3951
 * @param array dom the array whose values will pwn the gimp's
3952
 *
3953
 * @return array beaten gimp
3954
 */
3955
function sugarArrayMerge($gimp, $dom)
3956
{
3957
    if (is_array($gimp) && is_array($dom)) {
3958
        foreach ($dom as $domKey => $domVal) {
3959
            if (array_key_exists($domKey, $gimp)) {
3960
                if (is_array($domVal)) {
3961
                    $tempArr = array();
3962
                    foreach ($domVal as $domArrKey => $domArrVal) {
3963
                        $tempArr[$domArrKey] = $domArrVal;
3964
                    }
3965
                    foreach ($gimp[$domKey] as $gimpArrKey => $gimpArrVal) {
3966
                        if (!array_key_exists($gimpArrKey, $tempArr)) {
3967
                            $tempArr[$gimpArrKey] = $gimpArrVal;
3968
                        }
3969
                    }
3970
                    $gimp[$domKey] = $tempArr;
3971
                } else {
3972
                    $gimp[$domKey] = $domVal;
3973
                }
3974
            } else {
3975
                $gimp[$domKey] = $domVal;
3976
            }
3977
        }
3978
    } // if the passed value for gimp isn't an array, then return the $dom
3979
    elseif (is_array($dom)) {
3980
        return $dom;
3981
    }
3982
3983
    return $gimp;
3984
}
3985
3986
/**
3987
 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3988
 *
3989
 * @param array gimp the array whose values will be overloaded
3990
 * @param array dom the array whose values will pwn the gimp's
3991
 *
3992
 * @return array beaten gimp
3993
 */
3994
function sugarArrayMergeRecursive($gimp, $dom)
3995
{
3996 27
    if (is_array($gimp) && is_array($dom)) {
3997 27
        foreach ($dom as $domKey => $domVal) {
3998 27
            if (array_key_exists($domKey, $gimp)) {
3999 17
                if (is_array($domVal) && is_array($gimp[$domKey])) {
4000
                    $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
4001
                } else {
4002 17
                    $gimp[$domKey] = $domVal;
4003
                }
4004
            } else {
4005 27
                $gimp[$domKey] = $domVal;
4006
            }
4007
        }
4008
    } // if the passed value for gimp isn't an array, then return the $dom
4009
    elseif (is_array($dom)) {
4010
        return $dom;
4011
    }
4012
4013 27
    return $gimp;
4014
}
4015
4016
/**
4017
 * finds the correctly working versions of PHP-JSON.
4018
 *
4019
 * @return bool True if NOT found or WRONG version
4020
 */
4021
function returnPhpJsonStatus()
4022
{
4023
    if (function_exists('json_encode')) {
4024
        $phpInfo = getPhpInfo(8);
4025
4026
        return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
4027
    }
4028
4029
    return true; // not found
4030
}
4031
4032
/**
4033
 * getTrackerSubstring.
4034
 *
4035
 * Returns a [number]-char or less string for the Tracker to display in the header
4036
 * based on the tracker_max_display_length setting in config.php.  If not set,
4037
 * or invalid length, then defaults to 15 for COM editions, 30 for others.
4038
 *
4039
 * @param string name field for a given Object
4040
 *
4041
 * @return string [number]-char formatted string if length of string exceeds the max allowed
4042
 */
4043
function getTrackerSubstring($name)
4044
{
4045
    static $max_tracker_item_length;
4046
4047
    //Trim the name
4048
    $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
4049
    $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
4050
4051
    global $sugar_config;
4052
4053
    if (!isset($max_tracker_item_length)) {
4054
        if (isset($sugar_config['tracker_max_display_length'])) {
4055
            $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;
4056
        } else {
4057
            $max_tracker_item_length = 15;
4058
        }
4059
    }
4060
4061
    if ($strlen > $max_tracker_item_length) {
4062
        $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length - 3, 'UTF-8') : substr($name, 0, $max_tracker_item_length - 3);
4063
        $chopped .= '...';
4064
    } else {
4065
        $chopped = $name;
4066
    }
4067
4068
    return $chopped;
4069
}
4070
4071
function generate_search_where($field_list = array(), $values = array(), &$bean, $add_custom_fields = false, $module = '')
4072
{
4073
    $where_clauses = array();
4074
    $like_char = '%';
4075
    $table_name = $bean->object_name;
4076
    foreach ($field_list[$module] as $field => $parms) {
4077
        if (isset($values[$field]) && $values[$field] != '') {
4078
            $operator = 'like';
4079
            if (!empty($parms['operator'])) {
4080
                $operator = $parms['operator'];
4081
            }
4082
            if (is_array($values[$field])) {
4083
                $operator = 'in';
4084
                $field_value = '';
4085
                foreach ($values[$field] as $key => $val) {
4086
                    if ($val != ' ' and $val != '') {
4087
                        if (!empty($field_value)) {
4088
                            $field_value .= ',';
4089
                        }
4090
                        $field_value .= "'".$GLOBALS['db']->quote($val)."'";
4091
                    }
4092
                }
4093
            } else {
4094
                $field_value = $GLOBALS['db']->quote($values[$field]);
4095
            }
4096
            //set db_fields array.
4097
            if (!isset($parms['db_field'])) {
4098
                $parms['db_field'] = array($field);
4099
            }
4100
            if (isset($parms['my_items']) and $parms['my_items'] == true) {
4101
                global $current_user;
4102
                $field_value = $GLOBALS['db']->quote($current_user->id);
4103
                $operator = '=';
4104
            }
4105
4106
            $where = '';
4107
            $itr = 0;
4108
            if ($field_value != '') {
4109
                foreach ($parms['db_field'] as $db_field) {
4110
                    if (strstr($db_field, '.') === false) {
4111
                        $db_field = $bean->table_name.'.'.$db_field;
4112
                    }
4113
                    if ($GLOBALS['db']->supports('case_sensitive') && isset($parms['query_type']) && $parms['query_type'] == 'case_insensitive') {
4114
                        $db_field = 'upper('.$db_field.')';
4115
                        $field_value = strtoupper($field_value);
4116
                    }
4117
4118
                    ++$itr;
4119
                    if (!empty($where)) {
4120
                        $where .= ' OR ';
4121
                    }
4122
                    switch (strtolower($operator)) {
4123
                        case 'like' :
4124
                            $where .= $db_field." like '".$field_value.$like_char."'";
4125
                            break;
4126
                        case 'in':
4127
                            $where .= $db_field.' in ('.$field_value.')';
4128
                            break;
4129
                        case '=':
4130
                            $where .= $db_field." = '".$field_value."'";
4131
                            break;
4132
                    }
4133
                }
4134
            }
4135
            if (!empty($where)) {
4136
                if ($itr > 1) {
4137
                    array_push($where_clauses, '( '.$where.' )');
4138
                } else {
4139
                    array_push($where_clauses, $where);
4140
                }
4141
            }
4142
        }
4143
    }
4144
    if ($add_custom_fields) {
4145
        require_once 'modules/DynamicFields/DynamicField.php';
4146
        $bean->setupCustomFields($module);
4147
        $bean->custom_fields->setWhereClauses($where_clauses);
4148
    }
4149
4150
    return $where_clauses;
4151
}
4152
4153
function add_quotes($str)
4154
{
4155
    return "'{$str}'";
4156
}
4157
4158
/**
4159
 * This function will rebuild the config file.
4160
 *
4161
 * @param   $sugar_config
4162
 * @param   $sugar_version
4163
 *
4164
 * @return bool true if successful
4165
 */
4166
function rebuildConfigFile($sugar_config, $sugar_version)
4167
{
4168
    // add defaults to missing values of in-memory sugar_config
4169
    $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config);
4170
    // need to override version with default no matter what
4171
    $sugar_config['sugar_version'] = $sugar_version;
4172
4173
    ksort($sugar_config);
4174
4175
    if (write_array_to_file('sugar_config', $sugar_config, 'config.php')) {
4176
        return true;
4177
    } else {
4178
        return false;
4179
    }
4180
}
4181
4182
/**
4183
 * Loads clean configuration, not overridden by config_override.php.
4184
 *
4185
 * @return array
4186
 */
4187
function loadCleanConfig()
4188
{
4189
    $sugar_config = array();
4190
    require 'config.php';
4191
4192
    return $sugar_config;
4193
}
4194
4195
/**
4196
 * getJavascriptSiteURL
4197
 * This function returns a URL for the client javascript calls to access
4198
 * the site.  It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
4199
 * are used to access the site.  Thus, the hostname in the URL returned may
4200
 * not always match that of $sugar_config['site_url'].  Basically, the
4201
 * assumption is that however the user accessed the website is how they
4202
 * will continue to with subsequent javascript requests.  If the variable
4203
 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
4204
 *
4205
 * @return $site_url The url used to refer to the website
4206
 */
4207
function getJavascriptSiteURL()
4208
{
4209
    global $sugar_config;
4210
    if (!empty($_SERVER['HTTP_REFERER'])) {
4211
        $url = parse_url($_SERVER['HTTP_REFERER']);
4212
        $replacement_url = $url['scheme'].'://'.$url['host'];
4213
        if (!empty($url['port'])) {
4214
            $replacement_url .= ':'.$url['port'];
4215
        }
4216
        $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/', $replacement_url, $sugar_config['site_url']);
4217
    } else {
4218
        $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/', 'http$1://'.$_SERVER['HTTP_HOST'], $sugar_config['site_url']);
4219
        if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443') {
4220
            $site_url = preg_replace('/^http\:/', 'https:', $site_url);
4221
        }
4222
    }
4223
    $GLOBALS['log']->debug('getJavascriptSiteURL(), site_url='.$site_url);
4224
4225
    return $site_url;
4226
}
4227
4228
// works nicely with array_map() -- can be used to wrap single quotes around each element in an array
4229
function add_squotes($str)
4230
{
4231
    return "'".$str."'";
4232
}
4233
4234
// recursive function to count the number of levels within an array
4235
function array_depth($array, $depth_count = -1, $depth_array = array())
4236
{
4237
    ++$depth_count;
4238
    if (is_array($array)) {
4239
        foreach ($array as $key => $value) {
4240
            $depth_array[] = array_depth($value, $depth_count);
4241
        }
4242
    } else {
4243
        return $depth_count;
4244
    }
4245
    foreach ($depth_array as $value) {
4246
        $depth_count = $value > $depth_count ? $value : $depth_count;
4247
    }
4248
4249
    return $depth_count;
4250
}
4251
4252
/**
4253
 * Creates a new Group User.
4254
 *
4255
 * @param string $name Name of Group User
4256
 *
4257
 * @return string GUID of new Group User
4258
 */
4259
function createGroupUser($name)
4260
{
4261
    $group = new User();
4262
    $group->user_name = $name;
4263
    $group->last_name = $name;
4264
    $group->is_group = 1;
4265
    $group->deleted = 0;
4266
    $group->status = 'Active'; // cn: bug 6711
4267
    $group->setPreference('timezone', TimeDate::userTimezone());
4268
    $group->save();
4269
4270
    return $group->id;
4271
}
4272
4273
/*
4274
 * Helper function to locate an icon file given only a name
4275
 * Searches through the various paths for the file
4276
 * @param string iconFileName   The filename of the icon
4277
 * @return string Relative pathname of the located icon, or '' if not found
4278
 */
4279
4280
function _getIcon($iconFileName)
4281
{
4282
    $iconName = "icon_{$iconFileName}.gif";
4283
    $iconFound = SugarThemeRegistry::current()->getImageURL($iconName, false);
4284
4285
    //First try un-ucfirst-ing the icon name
4286
    if (empty($iconFound)) {
4287
        $iconName = 'icon_'.strtolower(substr($iconFileName, 0, 1)).substr($iconFileName, 1).'.gif';
4288
    }
4289
    $iconFound = SugarThemeRegistry::current()->getImageURL($iconName, false);
4290
4291
    //Next try removing the icon prefix
4292
    if (empty($iconFound)) {
4293
        $iconName = "{$iconFileName}.gif";
4294
    }
4295
    $iconFound = SugarThemeRegistry::current()->getImageURL($iconName, false);
4296
4297
    if (empty($iconFound)) {
4298
        $iconName = '';
4299
    }
4300
4301
    return $iconName;
4302
}
4303
4304
/**
4305
 * Function to grab the correct icon image for Studio.
4306
 *
4307
 * @param string $iconFileName Name of the icon file
4308
 * @param string $altfilename  Name of a fallback icon file (displayed if the imagefilename doesn't exist)
4309
 * @param string $width        Width of image
4310
 * @param string $height       Height of image
4311
 * @param string $align        Alignment of image
4312
 * @param string $alt          Alt tag of image
4313
 *
4314
 * @return string $string <img> tag with corresponding image
4315
 */
4316
function getStudioIcon($iconFileName = '', $altFileName = '', $width = '48', $height = '48', $align = 'baseline', $alt = '')
4317
{
4318
    global $app_strings, $theme;
4319
4320
    $iconName = _getIcon($iconFileName);
4321
    if (empty($iconName)) {
4322
        $iconName = _getIcon($altFileName);
4323
        if (empty($iconName)) {
4324
            return $app_strings['LBL_NO_IMAGE'];
4325
        }
4326
    }
4327
4328
    return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4329
}
4330
4331
/**
4332
 * Function to grab the correct icon image for Dashlets Dialog.
4333
 *
4334
 * @param string $filename Location of the icon file
4335
 * @param string $module   Name of the module to fall back onto if file does not exist
4336
 * @param string $width    Width of image
4337
 * @param string $height   Height of image
4338
 * @param string $align    Alignment of image
4339
 * @param string $alt      Alt tag of image
4340
 *
4341
 * @return string $string <img> tag with corresponding image
4342
 */
4343
function get_dashlets_dialog_icon($module = '', $width = '32', $height = '32', $align = 'absmiddle', $alt = '')
4344
{
4345
    global $app_strings, $theme;
4346
    $iconName = _getIcon($module.'_32');
4347
    if (empty($iconName)) {
4348
        $iconName = _getIcon($module);
4349
    }
4350
    if (empty($iconName)) {
4351
        return $app_strings['LBL_NO_IMAGE'];
4352
    }
4353
4354
    return SugarThemeRegistry::current()->getImage($iconName, "align=\"$align\" border=\"0\"", $width, $height);
4355
}
4356
4357
// works nicely to change UTF8 strings that are html entities - good for PDF conversions
4358
function html_entity_decode_utf8($string)
4359
{
4360
    static $trans_tbl;
4361
    // replace numeric entities
4362
    //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
4363
    $string = preg_replace('~&#x0*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
4364
    $string = preg_replace('~&#0*([0-9]+);~e', 'code2utf(\\1)', $string);
4365
    // replace literal entities
4366
    if (!isset($trans_tbl)) {
4367
        $trans_tbl = array();
4368
        foreach (get_html_translation_table(HTML_ENTITIES) as $val => $key) {
4369
            $trans_tbl[$key] = utf8_encode($val);
4370
        }
4371
    }
4372
4373
    return strtr($string, $trans_tbl);
4374
}
4375
4376
// Returns the utf string corresponding to the unicode value
4377
function code2utf($num)
4378
{
4379
    if ($num < 128) {
4380
        return chr($num);
4381
    }
4382
    if ($num < 2048) {
4383
        return chr(($num >> 6) + 192).chr(($num & 63) + 128);
4384
    }
4385
    if ($num < 65536) {
4386
        return chr(($num >> 12) + 224).chr((($num >> 6) & 63) + 128).chr(($num & 63) + 128);
4387
    }
4388
    if ($num < 2097152) {
4389
        return chr(($num >> 18) + 240).chr((($num >> 12) & 63) + 128).chr((($num >> 6) & 63) + 128).chr(($num & 63) + 128);
4390
    }
4391
4392
    return '';
4393
}
4394
4395
function str_split_php4($string, $length = 1)
4396
{
4397
    $string_length = strlen($string);
4398
    $return = array();
4399
    $cursor = 0;
4400
    if ($length > $string_length) {
4401
        // use the string_length as the string is shorter than the length
4402
        $length = $string_length;
4403
    }
4404
    for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
4405
        $return[] = substr($string, $cursor, $length);
4406
    }
4407
4408
    return $return;
4409
}
4410
4411
if (version_compare(phpversion(), '5.0.0', '<')) {
4412
    function str_split($string, $length = 1)
4413
    {
4414
        return str_split_php4($string, $length);
4415
    }
4416
}
4417
4418
/*
4419
 * @deprecated use DBManagerFactory::isFreeTDS
4420
 */
4421
function is_freetds()
4422
{
4423
    return DBManagerFactory::isFreeTDS();
4424
}
4425
4426
/**
4427
 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
4428
 *
4429
 * @todo this won't work completely right until we impliment css compression and combination
4430
 *       for now, we'll just include the last css file found.
4431
 *
4432
 * @return chart.css file to use
4433
 */
4434
function chartStyle()
4435
{
4436
    return SugarThemeRegistry::current()->getCSSURL('chart.css');
4437
}
4438
4439
/**
4440
 * Chart dashlet helper functions that returns the correct XML color file for charts,
4441
 * dependent on the current theme.
4442
 *
4443
 * @return sugarColors.xml to use
4444
 */
4445
function chartColors()
4446
{
4447
    if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml') == '') {
4448
        return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
4449
    }
4450
4451
    return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
4452
}
4453
4454
/* End Chart Dashlet helper functions */
4455
4456
/**
4457
 * This function is designed to set up the php enviroment
4458
 * for AJAX requests.
4459
 */
4460
function ajaxInit()
4461
{
4462
    ini_set('display_errors', 'false');
4463
}
4464
4465
/**
4466
 * Returns an absolute path from the given path, determining if it is relative or absolute.
4467
 *
4468
 * @param string $path
4469
 *
4470
 * @return string
4471
 */
4472
function getAbsolutePath(
4473
    $path,
4474
    $currentServer = false
4475
) {
4476
    $path = trim($path);
4477
4478
    // try to match absolute paths like \\server\share, /directory or c:\
4479
    if ((substr($path, 0, 2) == '\\\\')
4480
        || ($path[0] == '/')
4481
        || preg_match('/^[A-z]:/i', $path)
4482
        || $currentServer
4483
    ) {
4484
        return $path;
4485
    }
4486
4487
    return getcwd().'/'.$path;
4488
}
4489
4490
/**
4491
 * Returns the bean object of the given module.
4492
 *
4493
 * @deprecated use SugarModule::loadBean() instead
4494
 *
4495
 * @param string $module
4496
 *
4497
 * @return object
4498
 */
4499
function loadBean(
4500
    $module
4501
) {
4502 5
    return SugarModule::get($module)->loadBean();
4503
}
4504
4505
/**
4506
 * Returns true if the application is being accessed on a touch screen interface ( like an iPad ).
4507
 */
4508
function isTouchScreen()
4509
{
4510
    $ua = empty($_SERVER['HTTP_USER_AGENT']) ? 'undefined' : strtolower($_SERVER['HTTP_USER_AGENT']);
4511
4512
    // first check if we have forced use of the touch enhanced interface
4513
    if (isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1') {
4514
        return true;
4515
    }
4516
4517
    // next check if we should use the touch interface with our device
4518
    if (strpos($ua, 'ipad') !== false) {
4519
        return true;
4520
    }
4521
4522
    return false;
4523
}
4524
4525
/**
4526
 * Returns the shortcut keys to access the shortcut links.  Shortcut
4527
 * keys vary depending on browser versions and operating systems.
4528
 *
4529
 * @return string value of the shortcut keys
4530
 */
4531
function get_alt_hot_key()
4532
{
4533
    $ua = '';
4534
    if (isset($_SERVER['HTTP_USER_AGENT'])) {
4535
        $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4536
    }
4537
    $isMac = strpos($ua, 'mac') !== false;
4538
    $isLinux = strpos($ua, 'linux') !== false;
4539
4540
    if (!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4541
        if (preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4542
            return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4543
        }
4544
    }
4545
4546
    return $isMac ? 'Ctrl+' : 'Alt+';
4547
}
4548
4549
function can_start_session()
4550
{
4551 1
    if (!empty($_GET['PHPSESSID'])) {
4552
        return true;
4553
    }
4554 1
    $session_id = session_id();
4555
4556 1
    return empty($session_id) ? true : false;
4557
}
4558
4559
function load_link_class($properties)
4560
{
4561 128
    $class = 'Link2';
4562 128
    if (!empty($properties['link_class']) && !empty($properties['link_file'])) {
4563
        require_once $properties['link_file'];
4564
        $class = $properties['link_class'];
4565
    }
4566
4567 128
    return $class;
4568
}
4569
4570
function inDeveloperMode()
4571
{
4572 800
    return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4573
}
4574
4575
/**
4576
 * Filter the protocol list for inbound email accounts.
4577
 *
4578
 * @param array $protocol
4579
 */
4580
function filterInboundEmailPopSelection($protocol)
4581
{
4582
    if (!isset($GLOBALS['sugar_config']['allow_pop_inbound']) || !$GLOBALS['sugar_config']['allow_pop_inbound']) {
4583
        if (isset($protocol['pop3'])) {
4584
            unset($protocol['pop3']);
4585
        }
4586
    } else {
4587
        $protocol['pop3'] = 'POP3';
4588
    }
4589
4590
    return $protocol;
4591
}
4592
4593
/**
4594
 * The function is used because currently we are not supporting mbstring.func_overload
4595
 * 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.
4596
 * 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.
4597
 *
4598
 * @returns the substred strings.
4599
 */
4600
function sugar_substr($string, $length, $charset = 'UTF-8')
4601
{
4602
    if (mb_strlen($string, $charset) > $length) {
4603
        $string = trim(mb_substr(trim($string), 0, $length, $charset));
4604
    }
4605
4606
    return $string;
4607
}
4608
4609
/**
4610
 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4611
 * This will work even without setting the mbstring.*encoding.
4612
 */
4613
function sugar_ucfirst($string, $charset = 'UTF-8')
4614
{
4615
    return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_substr($string, 1, mb_strlen($string), $charset);
4616
}
4617
4618
/**
4619
 *
4620
 */
4621
function unencodeMultienum($string)
4622
{
4623
    if (is_array($string)) {
4624
        return $string;
4625
    }
4626
    if (substr($string, 0, 1) == '^' && substr($string, -1) == '^') {
4627
        $string = substr(substr($string, 1), 0, strlen($string) - 2);
4628
    }
4629
4630
    return explode('^,^', $string);
4631
}
4632
4633
function encodeMultienumValue($arr)
4634
{
4635
    if (!is_array($arr)) {
4636
        return $arr;
4637
    }
4638
4639
    if (empty($arr)) {
4640
        return '';
4641
    }
4642
4643
    $string = '^'.implode('^,^', $arr).'^';
4644
4645
    return $string;
4646
}
4647
4648
/**
4649
 * create_export_query is used for export and massupdate
4650
 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4651
 * This function will correct the where clause and output necessary join condition for them.
4652
 *
4653
 * @param $module : the module name
4654
 * @param $searchFields : searchFields which is got after $searchForm->populateFromArray()
4655
 * @param $where : where clauses
4656
 *
4657
 * @return array
4658
 */
4659
function create_export_query_relate_link_patch($module, $searchFields, $where)
4660
{
4661
    if (file_exists('modules/'.$module.'/SearchForm.html')) {
4662
        $ret_array['where'] = $where;
4663
4664
        return $ret_array;
4665
    }
4666
    $seed = BeanFactory::getBean($module);
4667
    foreach ($seed->field_defs as $name => $field) {
4668
        if ($field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value'])) {
4669
            $seed->load_relationship($field['link']);
4670
            $params = array();
4671
            if (empty($join_type)) {
4672
                $params['join_type'] = ' LEFT JOIN ';
4673
            } else {
4674
                $params['join_type'] = $join_type;
4675
            }
4676
            if (isset($data['join_name'])) {
4677
                $params['join_table_alias'] = $field['join_name'];
4678
            } else {
4679
                $params['join_table_alias'] = 'join_'.$field['name'];
4680
            }
4681
            if (isset($data['join_link_name'])) {
4682
                $params['join_table_link_alias'] = $field['join_link_name'];
4683
            } else {
4684
                $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4685
            }
4686
            $fieldLink = $field['link'];
4687
            $join = $seed->$fieldLink->getJoin($params, true);
4688
            $join_table_alias = 'join_'.$field['name'];
4689
            if (isset($field['db_concat_fields'])) {
4690
                $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4691
                $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4692
            } else {
4693
                $where = preg_replace('/(^|[\s(])'.$field['name'].'/', '${1}'.$join_table_alias.'.'.$field['rname'], $where);
4694
            }
4695
        }
4696
    }
4697
    $ret_array = array('where' => $where, 'join' => isset($join['join']) ? $join['join'] : '');
4698
4699
    return $ret_array;
4700
}
4701
4702
/**
4703
 * 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.
4704
 *
4705
 * @Depends on QuickRepairAndRebuild.php
4706
 * @Relate bug 30642  ,23177
4707
 */
4708
function clearAllJsAndJsLangFilesWithoutOutput()
4709
{
4710
    global $current_language, $mod_strings;
4711
    $MBmodStrings = $mod_strings;
4712
    $mod_strings = return_module_language($current_language, 'Administration');
4713
    include_once 'modules/Administration/QuickRepairAndRebuild.php';
4714
    $repair = new RepairAndClear();
4715
    $repair->module_list = array();
4716
    $repair->show_output = false;
4717
    $repair->clearJsLangFiles();
4718
    $repair->clearJsFiles();
4719
    $mod_strings = $MBmodStrings;
4720
}
4721
4722
/**
4723
 * This function will allow you to get a variable value from query string.
4724
 */
4725
function getVariableFromQueryString($variable, $string)
4726
{
4727
    $matches = array();
4728
    $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4729
    if ($number) {
4730
        return $matches[1];
4731
    } else {
4732
        return false;
4733
    }
4734
}
4735
4736
/**
4737
 * should_hide_iframes
4738
 * This is a helper method to determine whether or not to show iframes (My Sites) related
4739
 * information in the application.
4740
 *
4741
 * @return bool flag indicating whether or not iframes module should be hidden
4742
 */
4743
function should_hide_iframes()
4744
{
4745
    //Remove the MySites module
4746
    if (file_exists('modules/iFrames/iFrame.php')) {
4747
        if (!class_exists('iFrame')) {
4748
            require_once 'modules/iFrames/iFrame.php';
4749
        }
4750
4751
        return false;
4752
    }
4753
4754
    return true;
4755
}
4756
4757
/**
4758
 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA.
4759
 *
4760
 * @param string $version
4761
 *
4762
 * @return string RC, BETA, GA
4763
 */
4764
function getVersionStatus($version)
4765
{
4766
    if (preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4767
        return strtoupper($matches[1]);
4768
    } else {
4769
        return 'GA';
4770
    }
4771
}
4772
4773
/**
4774
 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4775
 * 5.5.1RC1 then return 5.5.1.
4776
 *
4777
 * @param string $version
4778
 *
4779
 * @return version
4780
 */
4781
function getMajorMinorVersion($version)
4782
{
4783
    if (preg_match('/^([\d\.]+).*$/si', $version, $matches2)) {
4784
        $version = $matches2[1];
4785
        $arr = explode('.', $version);
4786
        if (count($arr) > 2) {
4787
            if ($arr[2] == '0') {
4788
                $version = substr($version, 0, 3);
4789
            }
4790
        }
4791
    }
4792
4793
    return $version;
4794
}
4795
4796
/**
4797
 * Return string composed of seconds & microseconds of current time, without dots.
4798
 *
4799
 * @return string
4800
 */
4801
function sugar_microtime()
4802
{
4803 4
    $now = explode(' ', microtime());
4804 4
    $unique_id = $now[1].str_replace('.', '', $now[0]);
4805
4806 4
    return $unique_id;
4807
}
4808
4809
/**
4810
 * Extract urls from a piece of text.
4811
 *
4812
 * @param  $string
4813
 *
4814
 * @return array of urls found in $string
4815
 */
4816
function getUrls($string)
4817
{
4818 1
    $lines = explode('<br>', trim($string));
4819 1
    $urls = array();
4820 1
    foreach ($lines as $line) {
4821 1
        $regex = '/http?\:\/\/[^\" ]+/i';
4822 1
        preg_match_all($regex, $line, $matches);
4823 1
        foreach ($matches[0] as $match) {
4824 1
            $urls[] = $match;
4825
        }
4826
    }
4827
4828 1
    return $urls;
4829
}
4830
4831
/**
4832
 * Sanitize image file from hostile content.
4833
 *
4834
 * @param string $path Image file
4835
 * @param bool   $jpeg Accept only JPEGs?
4836
 */
4837
function verify_image_file($path, $jpeg = false)
4838
{
4839
    if (function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4840
        $img = imagecreatefromstring(file_get_contents($path));
4841
        if (!$img) {
4842
            return false;
4843
        }
4844
        $img_size = getimagesize($path);
4845
        $filetype = $img_size['mime'];
4846
        //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4847
        if ($filetype == 'image/jpeg' || $jpeg) {
4848
            ob_start();
4849
            imagejpeg($img);
4850
            $image = ob_get_clean();
4851
            // not writing directly because imagejpeg does not work with streams
4852
            if (file_put_contents($path, $image)) {
4853
                return true;
4854
            }
4855
        } elseif ($filetype == 'image/png') {
4856
            // else if the filetype is png, create png
4857
            imagealphablending($img, true);
4858
            imagesavealpha($img, true);
4859
            ob_start();
4860
            imagepng($img);
4861
            $image = ob_get_clean();
4862
            if (file_put_contents($path, $image)) {
4863
                return true;
4864
            }
4865
        } else {
4866
            return false;
4867
        }
4868
    } else {
4869
        // check image manually
4870
        $fp = fopen($path, 'rb');
4871
        if (!$fp) {
4872
            return false;
4873
        }
4874
        $data = '';
4875
        // read the whole file in chunks
4876
        while (!feof($fp)) {
4877
            $data .= fread($fp, 8192);
4878
        }
4879
4880
        fclose($fp);
4881
        if (preg_match("/<(\?php|html|!doctype|script|body|head|plaintext|table|img |pre(>| )|frameset|iframe|object|link|base|style|font|applet|meta|center|form|isindex)/i",
4882
            $data, $m)) {
4883
            $GLOBALS['log']->fatal("Found {$m[0]} in $path, not allowing upload");
4884
4885
            return false;
4886
        }
4887
4888
        return true;
4889
    }
4890
4891
    return false;
4892
}
4893
4894
/**
4895
 * Verify uploaded image
4896
 * Verifies that image has proper extension, MIME type and doesn't contain hostile content.
4897
 *
4898
 * @param string $path      Image path
4899
 * @param bool   $jpeg_only Accept only JPEGs?
4900
 */
4901
function verify_uploaded_image($path, $jpeg_only = false)
4902
{
4903
    $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4904
    if (!$jpeg_only) {
4905
        $supportedExtensions['png'] = 'image/png';
4906
    }
4907
4908
    if (!file_exists($path) || !is_file($path)) {
4909
        return false;
4910
    }
4911
4912
    $img_size = getimagesize($path);
4913
    $filetype = $img_size['mime'];
4914
    $tmpArray = explode('.', $path);
4915
    $ext = end($tmpArray);
4916
    if (substr_count('..', $path) > 0 || ($ext !== $path && !isset($supportedExtensions[strtolower($ext)])) ||
4917
        !in_array($filetype, array_values($supportedExtensions))
4918
    ) {
4919
        return false;
4920
    }
4921
4922
    return verify_image_file($path, $jpeg_only);
4923
}
4924
4925
function cmp_beans($a, $b)
4926
{
4927
    global $sugar_web_service_order_by;
4928
    //If the order_by field is not valid, return 0;
4929
    if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)) {
4930
        return 0;
4931
    }
4932
    if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4933
        || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by)
4934
    ) {
4935
        return 0;
4936
    }
4937
    if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by) {
4938
        return -1;
4939
    } else {
4940
        return 1;
4941
    }
4942
}
4943
4944
function order_beans($beans, $field_name)
4945
{
4946
    //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4947
    global $sugar_web_service_order_by;
4948
    $sugar_web_service_order_by = $field_name;
4949
    usort($beans, 'cmp_beans');
4950
4951
    return $beans;
4952
}
4953
4954
/**
4955
 * Return search like string
4956
 * This function takes a user input string and returns a string that contains wild card(s) that can be used in db query.
4957
 *
4958
 * @param string $str       string to be searched
4959
 * @param string $like_char Database like character, usually '%'
4960
 *
4961
 * @return string Returns a string to be searched in db query
4962
 */
4963
function sql_like_string($str, $like_char, $wildcard = '%', $appendWildcard = true)
4964
{
4965
4966
    // override default wildcard character
4967
    if (isset($GLOBALS['sugar_config']['search_wildcard_char']) &&
4968
        strlen($GLOBALS['sugar_config']['search_wildcard_char']) == 1
4969
    ) {
4970
        $wildcard = $GLOBALS['sugar_config']['search_wildcard_char'];
4971
    }
4972
4973
    // add wildcard at the beginning of the search string
4974
    if (isset($GLOBALS['sugar_config']['search_wildcard_infront']) &&
4975
        $GLOBALS['sugar_config']['search_wildcard_infront'] == true
4976
    ) {
4977
        if (substr($str, 0, 1) != $wildcard) {
4978
            $str = $wildcard.$str;
4979
        }
4980
    }
4981
4982
    // add wildcard at the end of search string (default)
4983
    if ($appendWildcard) {
4984
        if (substr($str, -1) != $wildcard) {
4985
            $str .= $wildcard;
4986
        }
4987
    }
4988
4989
    return str_replace($wildcard, $like_char, $str);
4990
}
4991
4992
//check to see if custom utils exists
4993
if (file_exists('custom/include/custom_utils.php')) {
4994
    include_once 'custom/include/custom_utils.php';
4995
}
4996
4997
//check to see if custom utils exists in Extension framework
4998
if (file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4999
    include_once 'custom/application/Ext/Utils/custom_utils.ext.php';
5000
}
5001
/**
5002
 * @param $input - the input string to sanitize
5003
 * @param int    $quotes  - use quotes
5004
 * @param string $charset - the default charset
5005
 * @param bool   $remove  - strip tags or not
5006
 *
5007
 * @return string - the sanitized string
5008
 */
5009
function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
5010
{
5011
    return htmlentities($input, $quotes, $charset);
5012
}
5013
5014
/**
5015
 * @return string - the full text search engine name
5016
 */
5017
function getFTSEngineType()
5018
{
5019
    if (isset($GLOBALS['sugar_config']['full_text_engine']) && is_array($GLOBALS['sugar_config']['full_text_engine'])) {
5020
        foreach ($GLOBALS['sugar_config']['full_text_engine'] as $name => $defs) {
5021
            return $name;
5022
        }
5023
    }
5024
5025
    return '';
5026
}
5027
5028
/**
5029
 * @param string $optionName - name of the option to be retrieved from app_list_strings
5030
 *
5031
 * @return array - the array to be used in option element
5032
 */
5033
function getFTSBoostOptions($optionName)
5034
{
5035
    if (isset($GLOBALS['app_list_strings'][$optionName])) {
5036
        return $GLOBALS['app_list_strings'][$optionName];
5037
    } else {
5038
        return array();
5039
    }
5040
}
5041
5042
/**
5043
 * utf8_recursive_encode.
5044
 *
5045
 * This function walks through an Array and recursively calls utf8_encode on the
5046
 * values of each of the elements.
5047
 *
5048
 * @param $data Array of data to encode
5049
 *
5050
 * @return utf8 encoded Array data
5051
 */
5052
function utf8_recursive_encode($data)
5053
{
5054
    $result = array();
5055
    foreach ($data as $key => $val) {
5056
        if (is_array($val)) {
5057
            $result[$key] = utf8_recursive_encode($val);
5058
        } else {
5059
            $result[$key] = utf8_encode($val);
5060
        }
5061
    }
5062
5063
    return $result;
5064
}
5065
5066
/**
5067
 * get_language_header.
5068
 *
5069
 * This is a utility function for 508 Compliance.  It returns the lang=[Current Language] text string used
5070
 * inside the <html> tag.  If no current language is specified, it defaults to lang='en'.
5071
 *
5072
 * @return string The lang=[Current Language] markup to insert into the <html> tag
5073
 */
5074
function get_language_header()
5075
{
5076 4
    return isset($GLOBALS['current_language']) ? "lang='{$GLOBALS['current_language']}'" : "lang='en'";
5077
}
5078
5079
/**
5080
 * get_custom_file_if_exists.
5081
 *
5082
 * This function handles the repetitive code we have where we first check if a file exists in the
5083
 * custom directory to determine whether we should load it, require it, include it, etc.  This function returns the
5084
 * path of the custom file if it exists.  It basically checks if custom/{$file} exists and returns this path if so;
5085
 * otherwise it return $file
5086
 *
5087
 * @param $file String of filename to check
5088
 *
5089
 * @return $file String of filename including custom directory if found
5090
 */
5091
function get_custom_file_if_exists($file)
5092
{
5093 7
    return file_exists("custom/{$file}") ? "custom/{$file}" : $file;
5094
}
5095
5096
/**
5097
 * get_help_url.
5098
 *
5099
 * This will return the URL used to redirect the user to the help documentation.
5100
 * It can be overriden completely by setting the custom_help_url or partially by setting the custom_help_base_url
5101
 * in config.php or config_override.php.
5102
 *
5103
 * @param string $send_edition
5104
 * @param string $send_version
5105
 * @param string $send_lang
5106
 * @param string $send_module
5107
 * @param string $send_action
5108
 * @param string $dev_status
5109
 * @param string $send_key
5110
 * @param string $send_anchor
5111
 *
5112
 * @return string the completed help URL
5113
 */
5114
function get_help_url($send_edition = '', $send_version = '', $send_lang = '', $send_module = '', $send_action = '', $dev_status = '', $send_key = '', $send_anchor = '')
5115
{
5116
    global $sugar_config;
5117
5118
    if (!empty($sugar_config['custom_help_url'])) {
5119
        $sendUrl = $sugar_config['custom_help_url'];
5120
    } else {
5121
        if (!empty($sugar_config['custom_help_base_url'])) {
5122
            $baseUrl = $sugar_config['custom_help_base_url'];
5123
        } else {
5124
            $baseUrl = 'http://www.sugarcrm.com/crm/product_doc.php';
5125
        }
5126
        $sendUrl = $baseUrl."?edition={$send_edition}&version={$send_version}&lang={$send_lang}&module={$send_module}&help_action={$send_action}&status={$dev_status}&key={$send_key}";
5127
        if (!empty($send_anchor)) {
5128
            $sendUrl .= '&anchor='.$send_anchor;
5129
        }
5130
    }
5131
5132
    return $sendUrl;
5133
}
5134
5135
/**
5136
 * generateETagHeader.
5137
 *
5138
 * This function generates the necessary cache headers for using ETags with dynamic content. You
5139
 * simply have to generate the ETag, pass it in, and the function handles the rest.
5140
 *
5141
 * @param string $etag ETag to use for this content.
5142
 */
5143
function generateETagHeader($etag)
5144
{
5145 1
    header('cache-control:');
5146
    header('Expires: ');
5147
    header('ETag: '.$etag);
5148
    header('Pragma:');
5149
    if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
5150
        if ($etag == $_SERVER['HTTP_IF_NONE_MATCH']) {
5151
            ob_clean();
5152
            header('Status: 304 Not Modified');
5153
            header('HTTP/1.0 304 Not Modified');
5154
            die();
5155
        }
5156
    }
5157
}
5158
5159
/**
5160
 * getReportNameTranslation.
5161
 *
5162
 * Translates the report name if a translation exists,
5163
 * otherwise just returns the name
5164
 *
5165
 * @param string $reportName
5166
 *
5167
 * @return string translated report name
5168
 */
5169
function getReportNameTranslation($reportName)
5170
{
5171
    global $current_language;
5172
5173
    // Used for translating reports
5174
    $mod_strings = return_module_language($current_language, 'Reports');
5175
5176
    // Search for the report name in the default language and get the key
5177
    $key = array_search($reportName, return_module_language('', 'Reports'));
5178
5179
    // If the key was found, use it to get a translation, otherwise just use report name
5180
    if (!empty($key)) {
5181
        $title = $mod_strings[$key];
5182
    } else {
5183
        $title = $reportName;
5184
    }
5185
5186
    return $title;
5187
}
5188
5189
/**
5190
 * Remove vars marked senstitive from array.
5191
 *
5192
 * @param array           $defs
5193
 * @param SugarBean|array $data
5194
 *
5195
 * @return mixed $data without sensitive fields
5196
 */
5197
function clean_sensitive_data($defs, $data)
5198
{
5199
    foreach ($defs as $field => $def) {
5200
        if (!empty($def['sensitive'])) {
5201
            if (is_array($data)) {
5202
                $data[$field] = '';
5203
            }
5204
            if ($data instanceof SugarBean) {
5205
                $data->$field = '';
5206
            }
5207
        }
5208
    }
5209
5210
    return $data;
5211
}
5212
5213
/**
5214
 * Return relations with labels for duplicates.
5215
 */
5216
function getDuplicateRelationListWithTitle($def, $var_def, $module)
5217
{
5218
    global $current_language;
5219
    $select_array = array_unique($def);
5220
    if (count($select_array) < count($def)) {
5221
        $temp_module_strings = return_module_language($current_language, $module);
5222
        $temp_duplicate_array = array_diff_assoc($def, $select_array);
5223
        $temp_duplicate_array = array_merge($temp_duplicate_array, array_intersect($select_array, $temp_duplicate_array));
5224
5225
        foreach ($temp_duplicate_array as $temp_key => $temp_value) {
5226
            // Don't add duplicate relationships
5227
            if (!empty($var_def[$temp_key]['relationship']) && array_key_exists($var_def[$temp_key]['relationship'], $select_array)) {
5228
                continue;
5229
            }
5230
            $select_array[$temp_key] = $temp_value;
5231
        }
5232
5233
        // Add the relationship name for easier recognition
5234
        foreach ($select_array as $key => $value) {
5235
            $select_array[$key] .= ' ('.$key.')';
5236
        }
5237
    }
5238
    asort($select_array);
5239
5240
    return $select_array;
5241
}
5242
5243
/**
5244
 * Gets the list of "*type_display*".
5245
 *
5246
 * @return array
5247
 */
5248
function getTypeDisplayList()
5249
{
5250
    return array('record_type_display', 'parent_type_display', 'record_type_display_notes');
5251
}
5252
5253
/**
5254
 * Breaks given string into substring according
5255
 * to 'db_concat_fields' from field definition
5256
 * and assigns values to corresponding properties
5257
 * of bean.
5258
 *
5259
 * @param SugarBean $bean
5260
 * @param array     $fieldDef
5261
 * @param string    $value
5262
 */
5263
function assignConcatenatedValue(SugarBean $bean, $fieldDef, $value)
5264
{
5265
    $valueParts = explode(' ', $value);
5266
    $valueParts = array_filter($valueParts);
5267
    $fieldNum = count($fieldDef['db_concat_fields']);
5268
5269
    if (count($valueParts) == 1 && $fieldDef['db_concat_fields'] == array('first_name', 'last_name')) {
5270
        $bean->last_name = $value;
5271
    } // elseif ($fieldNum >= count($valueParts))
5272
    else {
5273
        for ($i = 0; $i < $fieldNum; ++$i) {
5274
            $fieldValue = array_shift($valueParts);
5275
            $fieldName = $fieldDef['db_concat_fields'][$i];
5276
            $bean->$fieldName = $fieldValue !== false ? $fieldValue : '';
5277
        }
5278
5279
        if (!empty($valueParts)) {
5280
            $bean->$fieldName .= ' '.implode(' ', $valueParts);
5281
        }
5282
    }
5283
}
5284
5285
/**
5286
 * Performs unserialization. Accepts all types except Objects.
5287
 *
5288
 * @param string $value Serialized value of any type except Object
5289
 *
5290
 * @return mixed False if Object, converted value for other cases
5291
 */
5292
function sugar_unserialize($value)
5293
{
5294 1
    preg_match('/[oc]:\d+:/i', $value, $matches);
5295
5296 1
    if (count($matches)) {
5297
        return false;
5298
    }
5299
5300 1
    return unserialize($value);
5301
}
5302
5303
define('DEFAULT_UTIL_SUITE_ENCODING', 'UTF-8');
5304
5305
function suite_strlen($input, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
5306
{
5307
    if (function_exists('mb_strlen')) {
5308
        return mb_strlen($input, $encoding);
5309
    } else {
5310
        return strlen($input);
5311
    }
5312
}
5313
5314
function suite_substr($input, $start, $length = null, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
5315
{
5316
    if (function_exists('mb_substr')) {
5317
        return mb_substr($input, $start, $length, $encoding);
5318
    } else {
5319
        return substr($input, $start, $length);
5320
    }
5321
}
5322
5323
function suite_strtoupper($input, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
5324
{
5325
    if (function_exists('mb_strtoupper')) {
5326
        return mb_strtoupper($input, $encoding);
5327
    } else {
5328
        return strtoupper($input);
5329
    }
5330
}
5331
5332
function suite_strtolower($input, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
5333
{
5334
    if (function_exists('mb_strtolower')) {
5335
        return mb_strtolower($input, $encoding);
5336
    } else {
5337
        return strtolower($input);
5338
    }
5339
}
5340
5341
function suite_strpos($haystack, $needle, $offset = 0, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
5342
{
5343
    if (function_exists('mb_strpos')) {
5344
        return mb_strpos($haystack, $needle, $offset, $encoding);
5345
    } else {
5346
        return strpos($haystack, $needle, $offset);
5347
    }
5348
}
5349
5350
function suite_strrpos($haystack, $needle, $offset = 0, $encoding = DEFAULT_UTIL_SUITE_ENCODING)
5351
{
5352
    if (function_exists('mb_strrpos')) {
5353
        return mb_strrpos($haystack, $needle, $offset, $encoding);
5354
    } else {
5355
        return strrpos($haystack, $needle, $offset);
5356
    }
5357
}
5358