2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
37 /*********************************************************************************
39 * Description: Includes generic helper functions used throughout the application.
40 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
41 * All Rights Reserved.
42 * Contributor(s): ______________________________________..
43 ********************************************************************************/
44 require_once('include/SugarObjects/SugarConfig.php');
45 require_once('include/utils/security_utils.php');
49 function make_sugar_config(&$sugar_config)
51 /* used to convert non-array config.php file to array format */
52 global $admin_export_only;
54 global $calculate_response_time;
55 global $create_default_user;
58 global $dbconfigoption;
59 global $default_action;
60 global $default_charset;
61 global $default_currency_name;
62 global $default_currency_symbol;
63 global $default_currency_iso4217;
64 global $defaultDateFormat;
65 global $default_language;
66 global $default_module;
67 global $default_password;
68 global $default_permission_mode;
69 global $default_theme;
70 global $defaultTimeFormat;
71 global $default_user_is_admin;
72 global $default_user_name;
73 global $disable_export;
74 global $disable_persistent_connections;
75 global $display_email_template_variable_chooser;
76 global $display_inbound_email_buttons;
77 global $history_max_viewed;
81 global $list_max_entries_per_page;
82 global $lock_default_user_name;
83 global $log_memory_usage;
84 global $requireAccounts;
85 global $RSS_CACHE_TIME;
89 global $sugar_version;
92 global $translation_string_prefix;
94 global $upload_badext;
96 global $upload_maxsize;
97 global $import_max_execution_time;
98 global $list_max_entries_per_subpanel;
99 global $passwordsetting;
101 // assumes the following variables must be set:
102 // $dbconfig, $dbconfigoption, $cache_dir, $import_dir, $session_dir, $site_URL, $tmp_dir, $upload_dir
104 $sugar_config = array (
105 'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
106 'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
107 'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
108 'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
109 'create_default_user' => empty($create_default_user) ? false : $create_default_user,
110 'chartEngine' => 'Jit',
111 'date_formats' => empty($dateFormats) ? array(
112 'Y-m-d'=>'2010-12-23',
113 'd-m-Y' => '23-12-2010',
114 'm-d-Y'=>'12-23-2010',
115 'Y/m/d'=>'2010/12/23',
116 'd/m/Y' => '23/12/2010',
117 'm/d/Y'=>'12/23/2010',
118 'Y.m.d' => '2010.12.23',
119 'd.m.Y' => '23.12.2010',
120 'm.d.Y' => '12.23.2010'
122 'dbconfig' => $dbconfig, // this must be set!!
123 'dbconfigoption' => $dbconfigoption, // this must be set!!
124 'default_action' => empty($default_action) ? 'index' : $default_action,
125 'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
126 'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
127 'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
128 'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
129 'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
130 'default_export_charset' => 'UTF-8',
131 'default_language' => empty($default_language) ? 'en_us' : $default_language,
132 'default_module' => empty($default_module) ? 'Home' : $default_module,
133 'default_password' => empty($default_password) ? '' : $default_password,
134 'default_permissions' => array (
140 'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
141 'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
142 'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
143 'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
144 'disable_export' => empty($disable_export) ? false : $disable_export,
145 'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
146 'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
147 'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
148 'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
149 'host_name' => empty($host_name) ? 'localhost' : $host_name,
150 'import_dir' => $import_dir, // this must be set!!
151 'import_max_records_per_file' => 100,
152 'import_max_records_total_limit' => '',
153 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
154 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
155 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
156 'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
157 'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
158 'portal_view' => 'single_user',
159 'resource_management' => array (
160 'special_query_limit' => 50000,
161 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
162 'default_limit' => 1000,
164 'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
165 'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
166 'session_dir' => $session_dir, // this must be set!!
167 'site_url' => empty($site_URL) ? $site_url : $site_URL, // this must be set!!
168 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
169 'showThemePicker' => true,
170 'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
171 'time_formats' => empty($timeFormats) ? array (
172 'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM',
173 'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats,
174 'tmp_dir' => $tmp_dir, // this must be set!!
175 'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
176 'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
177 'upload_badext' => empty($upload_badext) ? array (
178 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
179 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext,
180 'upload_dir' => $upload_dir, // this must be set!!
181 'upload_maxsize' => empty($upload_maxsize) ? 3000000 : $upload_maxsize,
182 'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
183 'lock_homepage' => false,
184 'lock_subpanels' => false,
185 'max_dashlets_homepage' => 15,
186 'dashlet_display_row_options' => array('1','3','5','10'),
187 'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
188 'default_subpanel_tabs' => empty($subpanel_tabs) ? true : $subpanel_tabs,
189 'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
190 'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
191 'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
192 'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
193 'default_call_status' => 'Planned',
194 'js_lang_version' => 1,
195 'passwordsetting' => empty($passwordsetting) ? array (
196 'SystemGeneratedPasswordON' => '',
197 'generatepasswordtmpl' => '',
198 'lostpasswordtmpl' => '',
199 'forgotpasswordON' => true,
200 'linkexpiration' => '1',
201 'linkexpirationtime' => '30',
202 'linkexpirationtype' => '1',
203 'systexpiration' => '0',
204 'systexpirationtime' => '',
205 'systexpirationtype' => '0',
206 'systexpirationlogin' => '',
207 ) : $passwordsetting,
211 function get_sugar_config_defaults() {
214 * used for getting base values for array style config.php. used by the
215 * installer and to fill in new entries on upgrades. see also:
219 $sugar_config_defaults = array (
220 'admin_export_only' => false,
221 'export_delimiter' => ',',
222 'cache_dir' => 'cache/',
223 'calculate_response_time' => true,
224 'create_default_user' => false,
225 'chartEngine' => 'Jit',
226 'date_formats' => array (
227 'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
228 'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
229 'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
230 'dbconfigoption' => array (
231 'persistent' => true,
234 'seqname_format' => '%s_seq',
237 'default_action' => 'index',
238 'default_charset' => return_session_value_or_default('default_charset',
240 'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
241 'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
242 'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
243 'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
244 'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
245 'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
246 'default_date_format' => 'm/d/Y',
247 'default_export_charset' => 'UTF-8',
248 'default_language' => return_session_value_or_default('default_language',
250 'default_module' => 'Home',
251 'default_password' => '',
252 'default_permissions' => array (
258 'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
259 'default_time_format' => 'h:ia',
260 'default_user_is_admin' => false,
261 'default_user_name' => '',
262 'disable_export' => false,
263 'disable_persistent_connections' =>
264 return_session_value_or_default('disable_persistent_connections',
266 'display_email_template_variable_chooser' => false,
267 'display_inbound_email_buttons' => false,
268 'dump_slow_queries' => false,
269 'email_default_editor' => 'html',
270 'email_default_client' => 'sugar',
271 'email_default_delete_attachments' => true,
272 'history_max_viewed' => 50,
273 'installer_locked' => true,
274 'import_max_records_per_file' => 100,
275 'import_max_records_total_limit' => '',
276 'languages' => array('en_us' => 'English (US)'),
277 'large_scale_test' => false,
278 'list_max_entries_per_page' => 20,
279 'list_max_entries_per_subpanel' => 10,
280 'lock_default_user_name' => false,
281 'log_memory_usage' => false,
282 'portal_view' => 'single_user',
283 'resource_management' => array (
284 'special_query_limit' => 50000,
285 'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
286 'default_limit' => 1000,
288 'require_accounts' => true,
289 'rss_cache_time' => return_session_value_or_default('rss_cache_time',
291 'save_query' => 'all',
292 'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
293 'showThemePicker' => true,
294 'slow_query_time_msec' => '100',
296 'time_formats' => array (
297 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM',
298 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ),
299 'tracker_max_display_length' => 15,
300 'translation_string_prefix' =>
301 return_session_value_or_default('translation_string_prefix', false),
302 'upload_badext' => array (
303 'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
304 'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
305 'upload_maxsize' => 3000000,
306 'import_max_execution_time' => 3600,
307 // 'use_php_code_json' => returnPhpJsonStatus(),
308 'verify_client_ip' => true,
309 'js_custom_version' => '',
310 'js_lang_version' => 1,
311 'lead_conv_activity_opt' => 'donothing',
312 'default_number_grouping_seperator' => ',',
313 'default_decimal_seperator' => '.',
314 'lock_homepage' => false,
315 'lock_subpanels' => false,
316 'max_dashlets_homepage' => '15',
317 'default_max_tabs' => '7',
318 'dashlet_display_row_options' => array('1','3','5','10'),
319 'default_subpanel_tabs' => true,
320 'default_subpanel_links' => false,
321 'default_swap_last_viewed' => false,
322 'default_swap_shortcuts' => false,
323 'default_navigation_paradigm' => 'gm',
324 'admin_access_control' => false,
325 'use_common_ml_dir' => false,
326 'common_ml_dir' => '',
328 'passwordsetting' => empty($passwordsetting) ? array (
329 'SystemGeneratedPasswordON' => '',
330 'generatepasswordtmpl' => '',
331 'lostpasswordtmpl' => '',
332 'forgotpasswordON' => false,
333 'linkexpiration' => '1',
334 'linkexpirationtime' => '30',
335 'linkexpirationtype' => '1',
336 'systexpiration' => '0',
337 'systexpirationtime' => '',
338 'systexpirationtype' => '0',
339 'systexpirationlogin' => '',
340 ) : $passwordsetting,
341 'use_real_names' => true,
344 if(!is_object($locale)) {
345 $locale = new Localization();
348 $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
350 $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
351 return( $sugar_config_defaults );
355 * @deprecated use SugarView::getMenu() instead
357 function load_menu($path){
360 if(file_exists($path . 'Menu.php'))
362 require($path . 'Menu.php');
364 if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
366 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
368 if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
370 require('custom/application/Ext/Menus/menu.ext.php');
376 * get_notify_template_file
377 * This function will return the location of the email notifications template to use
379 * @return string relative file path to email notifications template file
381 function get_notify_template_file($language){
383 * Order of operation:
384 * 1) custom version of specified language
385 * 2) stock version of specified language
386 * 3) custom version of en_us template
387 * 4) stock en_us template
390 // set $file to the base code template so it's set if none of the conditions pass
391 $file = "include/language/en_us.notify_template.html";
393 if(file_exists("custom/include/language/{$language}.notify_template.html")){
394 $file = "custom/include/language/{$language}.notify_template.html";
396 else if(file_exists("include/language/{$language}.notify_template.html")){
397 $file = "include/language/{$language}.notify_template.html";
399 else if(file_exists("custom/include/language/en_us.notify_template.html")){
400 $file = "custom/include/language/en_us.notify_template.html";
406 function sugar_config_union( $default, $override ){
407 // a little different then array_merge and array_merge_recursive. we want
408 // the second array to override the first array if the same value exists,
409 // otherwise merge the unique keys. it handles arrays of arrays recursively
410 // might be suitable for a generic array_union
411 if( !is_array( $override ) ){
414 foreach( $default as $key => $value ){
415 if( !array_key_exists($key, $override) ){
416 $override[$key] = $value;
418 else if( is_array( $key ) ){
419 $override[$key] = sugar_config_union( $value, $override[$key] );
425 function make_not_writable( $file ){
426 // Returns true if the given file/dir has been made not writable
428 if( is_file($file) || is_dir($file) ){
429 if( !is_writable($file) ){
433 $original_fileperms = fileperms($file);
435 // take away writable permissions
436 $new_fileperms = $original_fileperms & ~0x0092;
437 @sugar_chmod($file, $new_fileperms);
439 if( !is_writable($file) ){
448 /** This function returns the name of the person.
449 * It currently returns "first last". It should not put the space if either name is not available.
450 * It should not return errors if either name is not available.
451 * If no names are present, it will return ""
452 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
453 * All Rights Reserved.
454 * Contributor(s): ______________________________________..
456 function return_name($row, $first_column, $last_column)
462 if(isset($row[$first_column]))
464 $first_name = stripslashes($row[$first_column]);
467 if(isset($row[$last_column]))
469 $last_name = stripslashes($row[$last_column]);
472 $full_name = $first_name;
474 // If we have a first name and we have a last name
475 if($full_name != "" && $last_name != "")
477 // append a space, then the last name
478 $full_name .= " ".$last_name;
480 // If we have no first name, but we have a last name
481 else if($last_name != "")
483 // append the last name without the space.
484 $full_name .= $last_name;
491 function get_languages()
493 global $sugar_config;
494 $lang = $sugar_config['languages'];
495 if(!empty($sugar_config['disabled_languages'])){
496 foreach(explode(',', $sugar_config['disabled_languages']) as $disable) {
497 unset($lang[$disable]);
503 function get_all_languages()
505 global $sugar_config;
506 return $sugar_config['languages'];
510 function get_language_display($key)
512 global $sugar_config;
513 return $sugar_config['languages'][$key];
516 function get_assigned_user_name($assigned_user_id, $is_group = '') {
517 static $saved_user_list = null;
519 if(empty($saved_user_list)) {
520 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
523 if(isset($saved_user_list[$assigned_user_id])) {
524 return $saved_user_list[$assigned_user_id];
531 * retrieves the user_name column value (login)
532 * @param string id GUID of user
535 function get_user_name($id) {
539 $db = DBManagerFactory::getInstance();
541 $q = "SELECT user_name FROM users WHERE id='{$id}'";
543 $a = $db->fetchByAssoc($r);
545 return (empty($a)) ? '' : $a['user_name'];
549 //TODO Update to use global cache
550 function get_user_array($add_blank=true, $status="Active", $assigned_user="", $use_real_name=false, $user_name_begins = null, $is_group=' AND portal_only=0 ', $from_cache = true) {
552 global $sugar_config;
556 $locale = new Localization();
559 $user_array = get_register_value('user_array', $add_blank. $status . $assigned_user);
561 if(empty($user_array)) {
562 $db = DBManagerFactory::getInstance();
563 $temp_result = Array();
564 // Including deleted users for now.
565 if (empty($status)) {
566 $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$is_group;
569 $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$is_group;
572 if (!empty($user_name_begins)) {
573 $query .= " AND user_name LIKE '$user_name_begins%' ";
575 if (!empty($assigned_user)) {
576 $query .= " OR id='$assigned_user'";
578 $query = $query.' ORDER BY user_name ASC';
579 $GLOBALS['log']->debug("get_user_array query: $query");
580 $result = $db->query($query, true, "Error filling in user array: ");
582 if ($add_blank==true) {
583 // Add in a blank row
584 $temp_result[''] = '';
587 // Get the id and the name.
588 while($row = $db->fetchByAssoc($result)) {
589 if($use_real_name == true || showFullName()) {
590 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
591 $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
593 $temp_result[$row['id']] = $row['user_name'];
596 $temp_result[$row['id']] = $row['user_name'];
600 $user_array = $temp_result;
602 set_register_value('user_array', $add_blank. $status . $assigned_user, $temp_result);
611 * uses a different query to return a list of users than get_user_array()
612 * @param args string where clause entry
613 * @return array Array of Users' details that match passed criteria
615 function getUserArrayFromFullName($args, $hide_portal_users = false) {
617 $db = DBManagerFactory::getInstance();
620 if(strpos($args, " ")) {
621 $argArray = explode(" ", $args);
627 foreach($argArray as $arg) {
628 if(!empty($inClause)) {
634 $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
637 $query = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
638 if ( $hide_portal_users ) {
639 $query .= " portal_only=0 AND ";
642 $query .= " ORDER BY last_name ASC";
644 $r = $db->query($query);
646 while($a = $db->fetchByAssoc($r)) {
647 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
655 * based on user pref then system pref
657 function showFullName() {
658 global $sugar_config;
659 global $current_user;
660 static $showFullName = null;
662 if (is_null($showFullName)) {
663 $sysPref = !empty($sugar_config['use_real_names']);
664 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
666 if($userPref != null) {
667 $showFullName = ($userPref == 'on');
669 $showFullName = $sysPref;
673 return $showFullName;
676 function clean($string, $maxLength)
678 $string = substr($string, 0, $maxLength);
679 return escapeshellcmd($string);
683 * Copy the specified request variable to the member variable of the specified object.
684 * Do no copy if the member variable is already set.
685 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
686 * All Rights Reserved.
687 * Contributor(s): ______________________________________..
689 function safe_map($request_var, & $focus, $always_copy = false)
691 safe_map_named($request_var, $focus, $request_var, $always_copy);
695 * Copy the specified request variable to the member variable of the specified object.
696 * Do no copy if the member variable is already set.
697 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
698 * All Rights Reserved.
699 * Contributor(s): ______________________________________..
701 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
703 if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
704 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
705 $focus->$member_var = $_REQUEST[$request_var];
710 * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
712 * @param string $language specific language to load
713 * @return array lang strings
715 function return_app_list_strings_language($language)
717 global $app_list_strings;
718 global $sugar_config;
720 $cache_key = 'app_list_strings.'.$language;
722 // Check for cached value
723 $cache_entry = sugar_cache_retrieve($cache_key);
724 if(!empty($cache_entry))
729 $default_language = $sugar_config['default_language'];
730 $temp_app_list_strings = $app_list_strings;
733 if ($language != 'en_us') {
736 if ($default_language != 'en_us' && $language != $default_language) {
737 $langs[] = $default_language;
739 $langs[] = $language;
741 $app_list_strings_array = array();
743 foreach ( $langs as $lang ) {
744 $app_list_strings = array();
745 if(file_exists("include/language/$lang.lang.php")) {
746 include("include/language/$lang.lang.php");
747 $GLOBALS['log']->info("Found language file: $lang.lang.php");
749 if(file_exists("include/language/$lang.lang.override.php")) {
750 include("include/language/$lang.lang.override.php");
751 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
753 if(file_exists("include/language/$lang.lang.php.override")) {
754 include("include/language/$lang.lang.php.override");
755 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
758 $app_list_strings_array[] = $app_list_strings;
761 $app_list_strings = array();
762 foreach ( $app_list_strings_array as $app_list_strings_item ) {
763 $app_list_strings = sugarArrayMerge($app_list_strings, $app_list_strings_item);
766 foreach ( $langs as $lang ) {
767 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
768 $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
769 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
771 if(file_exists("custom/include/language/$lang.lang.php")) {
772 include("custom/include/language/$lang.lang.php");
773 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
777 if(!isset($app_list_strings)) {
778 $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");
782 $return_value = $app_list_strings;
783 $app_list_strings = $temp_app_list_strings;
785 sugar_cache_put($cache_key, $return_value);
787 return $return_value;
791 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
792 * $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.
793 * @param file string the language that you want include,
794 * @param app_list_strings array the golbal strings
798 function _mergeCustomAppListStrings($file , $app_list_strings){
799 $app_list_strings_original = $app_list_strings;
800 unset($app_list_strings);
801 // FG - bug 45525 - $exemptDropdown array is defined (once) here, not inside the foreach
802 // This way, language file can add items to save specific standard codelist from being overwritten
803 $exemptDropdowns = array();
805 if(!isset($app_list_strings) || !is_array($app_list_strings)){
806 return $app_list_strings_original;
808 //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
810 // FG - bug 45525 - Specific codelists must NOT be overwritten
811 $exemptDropdowns[] = "moduleList";
812 $exemptDropdowns[] = "parent_type_display";
813 $exemptDropdowns[] = "record_type_display";
814 $exemptDropdowns[] = "record_type_display_notes";
816 foreach($app_list_strings as $key=>$value)
818 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
820 unset($app_list_strings_original["$key"]);
823 $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
824 return $app_list_strings;
828 * This function retrieves an application language file and returns the array of strings included.
830 * @param string $language specific language to load
831 * @return array lang strings
833 function return_application_language($language)
835 global $app_strings, $sugar_config;
837 $cache_key = 'app_strings.'.$language;
839 // Check for cached value
840 $cache_entry = sugar_cache_retrieve($cache_key);
841 if(!empty($cache_entry))
846 $temp_app_strings = $app_strings;
847 $default_language = $sugar_config['default_language'];
850 if ($language != 'en_us') {
853 if ($default_language != 'en_us' && $language != $default_language) {
854 $langs[] = $default_language;
857 $langs[] = $language;
859 $app_strings_array = array();
861 foreach ( $langs as $lang ) {
862 $app_strings = array();
863 if(file_exists("include/language/$lang.lang.php")) {
864 include("include/language/$lang.lang.php");
865 $GLOBALS['log']->info("Found language file: $lang.lang.php");
867 if(file_exists("include/language/$lang.lang.override.php")) {
868 include("include/language/$lang.lang.override.php");
869 $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
871 if(file_exists("include/language/$lang.lang.php.override")) {
872 include("include/language/$lang.lang.php.override");
873 $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
875 if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
876 include("custom/application/Ext/Language/$lang.lang.ext.php");
877 $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
879 if(file_exists("custom/include/language/$lang.lang.php")) {
880 include("custom/include/language/$lang.lang.php");
881 $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
883 $app_strings_array[] = $app_strings;
886 $app_strings = array();
887 foreach ( $app_strings_array as $app_strings_item ) {
888 $app_strings = sugarArrayMerge($app_strings, $app_strings_item);
891 if(!isset($app_strings)) {
892 $GLOBALS['log']->fatal("Unable to load the application language strings");
896 // If we are in debug mode for translating, turn on the prefix now!
897 if($sugar_config['translation_string_prefix']) {
898 foreach($app_strings as $entry_key=>$entry_value) {
899 $app_strings[$entry_key] = $language.' '.$entry_value;
902 if(isset($_SESSION['show_deleted'])) {
903 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
904 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
905 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
906 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
909 $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
911 $return_value = $app_strings;
912 $app_strings = $temp_app_strings;
914 sugar_cache_put($cache_key, $return_value);
916 return $return_value;
920 * This function retrieves a module's language file and returns the array of strings included.
922 * @param string $language specific language to load
923 * @param string $module module name to load strings for
924 * @param bool $refresh optional, true if you want to rebuild the language strings
925 * @return array lang strings
927 function return_module_language($language, $module, $refresh=false)
930 global $sugar_config;
931 global $currentModule;
933 // Jenny - Bug 8119: Need to check if $module is not empty
934 if (empty($module)) {
935 $stack = debug_backtrace();
936 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
942 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
943 // Check for cached value
944 $cache_entry = sugar_cache_retrieve($cache_key);
945 if(!empty($cache_entry))
950 // Store the current mod strings for later
951 $temp_mod_strings = $mod_strings;
952 $loaded_mod_strings = array();
953 $language_used = $language;
954 $default_language = $sugar_config['default_language'];
956 if(empty($language)) {
957 $language = $default_language;
960 // Bug 21559 - So we can get all the strings defined in the template, refresh
961 // the vardefs file if the cached language file doesn't exist.
962 if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/'. $module . '/language/'.$language.'.lang.php')
963 && !empty($GLOBALS['beanList'][$module])){
964 $object = BeanFactory::getObjectName($module);
965 VardefManager::refreshVardefs($module,$object);
968 $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
970 // cn: bug 6048 - merge en_us with requested language
971 if($language != $sugar_config['default_language'])
972 $loaded_mod_strings = sugarArrayMerge(
973 LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
977 // Load in en_us strings by default
978 if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
979 $loaded_mod_strings = sugarArrayMerge(
980 LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
984 // If we are in debug mode for translating, turn on the prefix now!
985 if($sugar_config['translation_string_prefix']) {
986 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
987 $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
991 $return_value = $loaded_mod_strings;
992 if(!isset($mod_strings)){
993 $mod_strings = $return_value;
996 $mod_strings = $temp_mod_strings;
998 $cache_key = LanguageManager::getLanguageCacheKey($module, $language);
999 sugar_cache_put($cache_key, $return_value);
1000 return $return_value;
1004 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
1005 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1006 * All Rights Reserved.
1007 * Contributor(s): ______________________________________..
1008 * If you are using the current language, do not call this function unless you are loading it for the first time */
1009 function return_mod_list_strings_language($language,$module) {
1010 global $mod_list_strings;
1011 global $sugar_config;
1012 global $currentModule;
1014 $cache_key = "mod_list_str_lang.".$language.$module;
1016 // Check for cached value
1017 $cache_entry = sugar_cache_retrieve($cache_key);
1018 if(!empty($cache_entry))
1020 return $cache_entry;
1023 $language_used = $language;
1024 $temp_mod_list_strings = $mod_list_strings;
1025 $default_language = $sugar_config['default_language'];
1027 if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
1028 return $mod_list_strings;
1031 // cn: bug 6351 - include en_us if file langpack not available
1032 // cn: bug 6048 - merge en_us with requested language
1033 include("modules/$module/language/en_us.lang.php");
1034 $en_mod_list_strings = array();
1035 if($language_used != $default_language)
1036 $en_mod_list_strings = $mod_list_strings;
1038 if(file_exists("modules/$module/language/$language.lang.php")) {
1039 include("modules/$module/language/$language.lang.php");
1042 if(file_exists("modules/$module/language/$language.lang.override.php")){
1043 include("modules/$module/language/$language.lang.override.php");
1046 if(file_exists("modules/$module/language/$language.lang.php.override")){
1047 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1048 include("modules/$module/language/$language.lang.php.override");
1051 // cn: bug 6048 - merge en_us with requested language
1052 $mod_list_strings = sugarArrayMerge($en_mod_list_strings, $mod_list_strings);
1054 // if we still don't have a language pack, then log an error
1055 if(!isset($mod_list_strings)) {
1056 $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})");
1060 $return_value = $mod_list_strings;
1061 $mod_list_strings = $temp_mod_list_strings;
1063 sugar_cache_put($cache_key, $return_value);
1064 return $return_value;
1068 /** This function retrieves a theme's language file and returns the array of strings included.
1069 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1070 * All Rights Reserved.
1071 * Contributor(s): ______________________________________..
1073 function return_theme_language($language, $theme)
1075 global $mod_strings, $sugar_config, $currentModule;
1077 $language_used = $language;
1078 $default_language = $sugar_config['default_language'];
1080 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1081 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1082 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1084 if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1085 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";
1086 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1088 if(!isset($theme_strings))
1090 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1091 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1092 $language_used = $default_language;
1095 if(!isset($theme_strings))
1097 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1101 // If we are in debug mode for translating, turn on the prefix now!
1102 if($sugar_config['translation_string_prefix'])
1104 foreach($theme_strings as $entry_key=>$entry_value)
1106 $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1110 return $theme_strings;
1115 /** If the session variable is defined and is not equal to "" then return it. Otherwise, return the default value.
1116 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1117 * All Rights Reserved.
1118 * Contributor(s): ______________________________________..
1120 function return_session_value_or_default($varname, $default)
1122 if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1124 return $_SESSION[$varname];
1131 * Creates an array of where restrictions. These are used to construct a where SQL statement on the query
1132 * 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.
1133 * @param &$where_clauses - The array to append the clause to
1134 * @param $variable_name - The name of the variable to look for an add to the where clause if found
1135 * @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.
1136 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1137 * All Rights Reserved.
1138 * Contributor(s): ______________________________________..
1140 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1142 if($SQL_name == null)
1144 $SQL_name = $variable_name;
1147 if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1149 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1154 * Generate the appropriate SQL based on the where clauses.
1155 * @param $where_clauses - An Array of individual where clauses stored as strings
1156 * @returns string where_clause - The final SQL where clause to be executed.
1157 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1158 * All Rights Reserved.
1159 * Contributor(s): ______________________________________..
1161 function generate_where_statement($where_clauses)
1164 foreach($where_clauses as $clause)
1171 $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1176 * determines if a passed string matches the criteria for a Sugar GUID
1177 * @param string $guid
1178 * @return bool False on failure
1180 function is_guid($guid) {
1181 if(strlen($guid) != 36) {
1185 if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1194 * A temporary method of generating GUIDs of the correct format for our DB.
1195 * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1197 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1198 * All Rights Reserved.
1199 * Contributor(s): ______________________________________..
1201 function create_guid()
1203 $microTime = microtime();
1204 list($a_dec, $a_sec) = explode(" ", $microTime);
1206 $dec_hex = dechex($a_dec* 1000000);
1207 $sec_hex = dechex($a_sec);
1209 ensure_length($dec_hex, 5);
1210 ensure_length($sec_hex, 6);
1214 $guid .= create_guid_section(3);
1216 $guid .= create_guid_section(4);
1218 $guid .= create_guid_section(4);
1220 $guid .= create_guid_section(4);
1223 $guid .= create_guid_section(6);
1229 function create_guid_section($characters)
1232 for($i=0; $i<$characters; $i++)
1234 $return .= dechex(mt_rand(0,15));
1239 function ensure_length(&$string, $length)
1241 $strlen = strlen($string);
1242 if($strlen < $length)
1244 $string = str_pad($string,$length,"0");
1246 else if($strlen > $length)
1248 $string = substr($string, 0, $length);
1252 function microtime_diff($a, $b) {
1253 list($a_dec, $a_sec) = explode(" ", $a);
1254 list($b_dec, $b_sec) = explode(" ", $b);
1255 return $b_sec - $a_sec + $b_dec - $a_dec;
1258 // check if Studio is displayed.
1259 function displayStudioForCurrentUser()
1261 global $current_user;
1262 if ( $current_user->isAdmin() ) {
1272 function displayWorkflowForCurrentUser()
1274 $_SESSION['display_workflow_for_user'] = false;
1278 // return an array with all modules where the user is an admin.
1279 function get_admin_modules_for_user($user) {
1280 $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");
1287 return($user->getDeveloperModules());
1291 function get_workflow_admin_modules_for_user($user){
1292 if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1293 return $_SESSION['get_workflow_admin_modules_for_user'];
1297 $workflow_mod_list = array();
1298 foreach($moduleList as $module){
1299 $workflow_mod_list[$module] = $module;
1302 // This list is taken from teh previous version of workflow_utils.php
1303 $workflow_mod_list['Tasks'] = "Tasks";
1304 $workflow_mod_list['Calls'] = "Calls";
1305 $workflow_mod_list['Meetings'] = "Meetings";
1306 $workflow_mod_list['Notes'] = "Notes";
1307 $workflow_mod_list['ProjectTask'] = "Project Tasks";
1308 $workflow_mod_list['Leads'] = "Leads";
1309 $workflow_mod_list['Opportunities'] = "Opportunities";
1312 $workflow_admin_modules = array();
1314 return $workflow_admin_modules;
1316 $actions = ACLAction::getUserActions($user->id);
1317 //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1318 if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1319 $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1320 $workflow_admin_modules['Forecasts'] = 'Forecasts';
1322 foreach ($workflow_mod_list as $key=>$val) {
1323 if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1324 && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1325 ($user->isDeveloperForModule($key))) {
1326 $workflow_admin_modules[$key] = $val;
1329 $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1330 return ($workflow_admin_modules);
1333 // Check if user is admin for at least one module.
1334 function is_admin_for_any_module($user) {
1338 if($user->isAdmin()) {
1345 // Check if user is admin for a specific module.
1346 function is_admin_for_module($user,$module) {
1347 if (!isset($user)) {
1350 if ($user->isAdmin()) {
1358 * Check if user id belongs to a system admin.
1359 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1360 * All Rights Reserved.
1361 * Contributor(s): ______________________________________..
1363 function is_admin($user) {
1368 return $user->isAdmin();
1372 * Return the display name for a theme if it exists.
1373 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1374 * All Rights Reserved.
1375 * Contributor(s): ______________________________________..
1377 * @deprecated use SugarThemeRegistry::get($theme)->name instead
1379 function get_theme_display($theme)
1381 return SugarThemeRegistry::get($theme)->name;
1385 * Return an array of directory names.
1386 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1387 * All Rights Reserved.
1388 * Contributor(s): ______________________________________..
1390 * @deprecated use SugarThemeRegistry::availableThemes() instead.
1392 function get_themes()
1394 return SugarThemeRegistry::availableThemes();
1398 * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1399 * Create HTML to display select options in a dropdown list. To be used inside
1400 * of a select statement in a form.
1401 * param $option_list - the array of strings to that contains the option list
1402 * param $selected - the string which contains the default value
1403 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1404 * All Rights Reserved.
1405 * Contributor(s): ______________________________________..
1407 function get_select_options ($option_list, $selected) {
1408 return get_select_options_with_id($option_list, $selected);
1412 * Create HTML to display select options in a dropdown list. To be used inside
1413 * 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.
1414 * param $option_list - the array of strings to that contains the option list
1415 * param $selected - the string which contains the default value
1416 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1417 * All Rights Reserved.
1418 * Contributor(s): ______________________________________..
1420 function get_select_options_with_id ($option_list, $selected_key) {
1421 return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1426 * Create HTML to display select options in a dropdown list. To be used inside
1427 * 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.
1428 * param $label_list - the array of strings to that contains the option list
1429 * param $key_list - the array of strings to that contains the values list
1430 * param $selected - the string which contains the default value
1431 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1432 * All Rights Reserved.
1433 * Contributor(s): ______________________________________..
1435 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1436 global $app_strings;
1437 $select_options = "";
1439 //for setting null selection values to human readable --None--
1440 $pattern = "/'0?'></";
1441 $replacement = "''>".$app_strings['LBL_NONE']."<";
1443 $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
1446 if (empty($key_list)) $key_list = array();
1447 //create the type dropdown domain and set the selected value if $opp value already exists
1448 foreach ($key_list as $option_key=>$option_value) {
1450 $selected_string = '';
1451 // the system is evaluating $selected_key == 0 || '' to true. Be very careful when changing this. Test all cases.
1452 // The bug was only happening with one of the users in the drop down. It was being replaced by none.
1453 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) && in_array($option_key, $selected_key)))
1455 $selected_string = 'selected ';
1458 $html_value = $option_key;
1460 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1462 $select_options = preg_replace($pattern, $replacement, $select_options);
1463 return $select_options;
1468 * Call this method instead of die().
1469 * Then we call the die method with the error message that is passed in.
1471 function sugar_die($error_message)
1475 die($error_message);
1480 * Create javascript to clear values of all elements in a form.
1481 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1482 * All Rights Reserved.
1483 * Contributor(s): ______________________________________..
1485 function get_clear_form_js () {
1486 $the_script = <<<EOQ
1487 <script type="text/javascript" language="JavaScript">
1488 function clear_form(form) {
1489 var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1490 if(typeof(form.advanced) != 'undefined'){
1491 newLoc += '&advanced=' + form.advanced.value;
1493 document.location.href= newLoc;
1502 * Create javascript to set the cursor focus to specific field in a form
1503 * when the screen is rendered. The field name is currently hardcoded into the
1505 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1506 * All Rights Reserved.
1507 * Contributor(s): ______________________________________..
1509 function get_set_focus_js () {
1510 //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1511 $the_script = <<<EOQ
1512 <script type="text/javascript" language="JavaScript">
1514 function set_focus() {
1515 if (document.forms.length > 0) {
1516 for (i = 0; i < document.forms.length; i++) {
1517 for (j = 0; j < document.forms[i].elements.length; j++) {
1518 var field = document.forms[i].elements[j];
1519 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1520 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1522 if (field.type == "text") {
1539 * Very cool algorithm for sorting multi-dimensional arrays. Found at http://us2.php.net/manual/en/function.array-multisort.php
1540 * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1541 * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1542 * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1543 * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1544 * the first - so the array is sorted by the last given column first, then the one before ...
1545 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1546 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1547 * All Rights Reserved.
1548 * Contributor(s): ______________________________________..
1550 function array_csort() {
1551 $args = func_get_args();
1552 $marray = array_shift($args);
1555 $msortline = "return(array_multisort(";
1556 foreach ($args as $arg) {
1558 if (is_string($arg)) {
1559 foreach ($marray as $row) {
1560 $sortarr[$i][] = $row[$arg];
1563 $sortarr[$i] = $arg;
1565 $msortline .= "\$sortarr[".$i."],";
1567 $msortline .= "\$marray));";
1574 * Converts localized date format string to jscalendar format
1575 * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1576 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1577 * All Rights Reserved.
1578 * Contributor(s): ______________________________________..
1580 function parse_calendardate($local_format) {
1581 preg_match('/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/', $local_format, $matches);
1582 $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1583 return str_replace(array("y", "ᅣ1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1590 function translate($string, $mod='', $selectedValue=''){
1591 //$test_start = microtime();
1592 //static $mod_strings_results = array();
1594 global $current_language;
1596 if(isset($_REQUEST['login_language'])){
1597 $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1599 $mod_strings = return_module_language($current_language, $mod);
1602 global $mod_strings;
1606 global $app_strings, $app_list_strings;
1608 if(isset($mod_strings[$string]))
1609 $returnValue = $mod_strings[$string];
1610 else if(isset($app_strings[$string]))
1611 $returnValue = $app_strings[$string];
1612 else if(isset($app_list_strings[$string]))
1613 $returnValue = $app_list_strings[$string];
1614 else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1615 $returnValue = $app_list_strings['moduleList'][$string];
1618 //$test_end = microtime();
1620 // $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1622 // echo("translate results:");
1624 // $total_strings = 0;
1625 // foreach($mod_strings_results as $key=>$value)
1627 // echo("Module $key \t\t time $value \t\t<br>");
1628 // $total_time += $value;
1631 // echo("Total time: $total_time<br>");
1635 if(empty($returnValue)){
1639 if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){
1640 return $returnValue[$selectedValue];
1643 return $returnValue;
1646 function unTranslateNum($num) {
1648 static $num_grp_sep;
1649 global $current_user, $sugar_config;
1651 if($dec_sep == null) {
1652 $user_dec_sep = $current_user->getPreference('dec_sep');
1653 $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1655 if($num_grp_sep == null) {
1656 $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1657 $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1660 $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1661 $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1666 function add_http($url) {
1667 if(!preg_match("@://@i", $url)) {
1669 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1673 return "{$scheme}://{$url}";
1680 * returns a default array of XSS tags to clean
1683 function getDefaultXssTags() {
1685 "applet" => "applet",
1690 "frameset" => "frameset",
1691 "iframe" => "iframe",
1692 "import" => "\?import",
1695 "object" => "object",
1696 "script" => "script",
1700 $ret = base64_encode(serialize($tmp));
1706 * Remove potential xss vectors from strings
1707 * @param string str String to search for XSS attack vectors
1708 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1711 function remove_xss($str, $cleanImg=true)
1713 $potentials = clean_xss($str, $cleanImg);
1714 if(is_array($potentials) && !empty($potentials)) {
1715 foreach($potentials as $bad) {
1716 $str = str_replace($bad, "", $str);
1723 * Detects typical XSS attack patterns
1724 * @param string str String to search for XSS attack vectors
1725 * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1726 * @return array Array of matches, empty on clean string
1728 function clean_xss($str, $cleanImg=true) {
1729 global $sugar_config;
1731 if(empty($sugar_config['email_xss']))
1732 $sugar_config['email_xss'] = getDefaultXssTags();
1734 $xsstags = unserialize(base64_decode($sugar_config['email_xss']));
1736 // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1737 $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1738 $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1739 $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop";
1741 $attribute_regex = "#\b({$jsEvents})\s*=\s*(?|(?!['\"])\S+|['\"].+?['\"])#sim";
1742 $javascript_regex = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1743 $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim';
1744 $css_url = '#url\(.*\.\w+\)#';
1746 $tagsrex = '#<\/?(\w+)((?:\s+(?:\w|\w[\w-]*\w)(?:\s*=\s*(?:\".*?\"|\'.*?\'|[^\'\">\s]+))?)+\s*|\s*)\/?>#im';
1748 $tagmatches = array();
1750 preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER);
1751 foreach($tagmatches[1] as $no => $tag) {
1752 if(in_array($tag, $xsstags)) {
1753 // dangerous tag - take out whole
1754 $matches[] = $tagmatches[0][$no];
1757 $attrmatch = array();
1758 preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER);
1759 if(!empty($attrmatch[0])) {
1760 $matches = array_merge($matches, $attrmatch[0]);
1764 $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str));
1767 $matches = array_merge($matches,
1768 xss_check_pattern($imgsrc_regex, $str)
1772 // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1773 preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1775 if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1776 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1777 // normalize whitelist
1778 foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1779 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1782 foreach($cssUrlMatches[0] as $match) {
1783 $domain = strtolower(substr(strstr($match, "://"), 3));
1784 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1786 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1787 $matches[] = $match;
1792 $matches = array_merge($matches, $cssUrlMatches[0]);
1799 * Helper function used by clean_xss() to parse for known-bad vectors
1800 * @param string pattern Regex pattern to use
1801 * @param string str String to parse for badness
1804 function xss_check_pattern($pattern, $str) {
1805 preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1810 * Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1812 * @param string $str
1813 * @param string $filter which corresponds to a regular expression to use; choices are:
1814 * "STANDARD" ( default )
1824 * @param boolean $dieOnBadData true (default) if you want to die if bad data if found, false if not
1826 function clean_string($str, $filter = "STANDARD", $dieOnBadData = true)
1828 global $sugar_config;
1831 "STANDARD" => '#[^A-Z0-9\-_\.\@]#i',
1832 "STANDARDSPACE" => '#[^A-Z0-9\-_\.\@\ ]#i',
1833 "FILE" => '#[^A-Z0-9\-_\.]#i',
1834 "NUMBER" => '#[^0-9\-]#i',
1835 "SQL_COLUMN_LIST" => '#[^A-Z0-9\(\),_\.]#i',
1836 "PATH_NO_URL" => '#://#i',
1837 "SAFED_GET" => '#[^A-Z0-9\@\=\&\?\.\/\-_~]#i', /* range of allowed characters in a GET string */
1838 "UNIFIED_SEARCH" => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1839 "AUTO_INCREMENT" => '#[^0-9\-,\ ]#i',
1840 "ALPHANUM" => '#[^A-Z0-9\-]#i',
1843 if (preg_match($filters[$filter], $str)) {
1844 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1845 $GLOBALS['log']->fatal("SECURITY: bad data passed in; string: {$str}");
1847 if ( $dieOnBadData ) {
1848 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1857 function clean_special_arguments() {
1858 if(isset($_SERVER['PHP_SELF'])) {
1859 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1861 if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1862 if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1863 if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1864 if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1865 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1866 if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1867 if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1868 if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1869 if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1870 if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1871 if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1872 if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1873 if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1874 if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1875 if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1876 if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1877 clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1878 clean_superglobals('offset', 'ALPHANUM');
1879 clean_superglobals('return_action');
1880 clean_superglobals('return_module');
1885 * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1887 function clean_superglobals($key, $filter = 'STANDARD') {
1888 if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1889 if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1890 if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1893 function set_superglobals($key, $val){
1895 $_POST[$key] = $val;
1896 $_REQUEST[$key] = $val;
1899 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1900 function clean_incoming_data() {
1901 global $sugar_config;
1903 if (get_magic_quotes_gpc() == 1) {
1904 $req = array_map("preprocess_param", $_REQUEST);
1905 $post = array_map("preprocess_param", $_POST);
1906 $get = array_map("preprocess_param", $_GET);
1909 $req = array_map("securexss", $_REQUEST);
1910 $post = array_map("securexss", $_POST);
1911 $get = array_map("securexss", $_GET);
1914 // PHP cannot stomp out superglobals reliably
1915 foreach($post as $k => $v) { $_POST[$k] = $v; }
1916 foreach($get as $k => $v) { $_GET[$k] = $v; }
1917 foreach($req as $k => $v) {
1919 //ensure the keys are safe as well
1922 // Any additional variables that need to be cleaned should be added here
1923 if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1924 if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1925 if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
1926 if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
1927 if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
1928 if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
1929 if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
1930 if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
1931 if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
1932 if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
1933 if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
1934 if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
1935 if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
1937 if(isset($_REQUEST['lvso'])){
1938 set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
1940 // Clean "offset" and "order_by" parameters in URL
1941 foreach ($_REQUEST as $key => $val) {
1942 if (str_end($key, "_offset")) {
1943 clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
1944 set_superglobals($key, $_REQUEST[$key]);
1946 elseif (str_end($key, "_ORDER_BY")) {
1947 clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
1948 set_superglobals($key, $_REQUEST[$key]);
1956 // Returns TRUE if $str begins with $begin
1957 function str_begin($str, $begin) {
1958 return (substr($str, 0, strlen($begin)) == $begin);
1961 // Returns TRUE if $str ends with $end
1962 function str_end($str, $end) {
1963 return (substr($str, strlen($str) - strlen($end)) == $end);
1966 function securexss($value) {
1967 if(is_array($value)){
1969 foreach($value as $key=>$val){
1970 $new[$key] = securexss($val);
1974 static $xss_cleanup= array('"' =>'"', "'" => ''' , '<' =>'<' , '>'=>'>');
1975 $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
1976 $value = preg_replace('/javascript:/i', 'java script:', $value);
1977 return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
1980 function securexsskey($value, $die=true){
1981 global $sugar_config;
1983 preg_match("/[\'\"\<\>]/", $value, $matches);
1984 if(!empty($matches)){
1986 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1988 unset($_REQUEST[$value]);
1989 unset($_POST[$value]);
1990 unset($_GET[$value]);
1995 function preprocess_param($value){
1996 if(is_string($value)){
1997 if(get_magic_quotes_gpc() == 1){
1998 $value = stripslashes($value);
2001 $value = securexss($value);
2010 function set_register_value($category, $name, $value){
2011 return sugar_cache_put("{$category}:{$name}", $value);
2014 function get_register_value($category,$name){
2015 return sugar_cache_retrieve("{$category}:{$name}");
2018 function clear_register_value($category,$name){
2019 return sugar_cache_clear("{$category}:{$name}");
2021 // this function cleans id's when being imported
2022 function convert_id($string)
2024 return preg_replace_callback( '|[^A-Za-z0-9\-]|',
2026 // single quotes are essential here,
2027 // or alternative escape all $ as \$
2029 'return ord($matches[0]);'
2034 * @deprecated use SugarTheme::getImage()
2036 function get_image($image,$other_attributes,$width="",$height="")
2038 return SugarThemeRegistry::current()->getImage(basename($image),
2040 empty($width) ? null : $width,
2041 empty($height) ? null : $height
2045 * @deprecated use SugarTheme::getImageURL()
2047 function getImagePath($image_name)
2049 return SugarThemeRegistry::current()->getImageURL($image_name);
2052 function getWebPath($relative_path){
2053 //if it has a :// then it isn't a relative path
2054 if(substr_count($relative_path, '://') > 0) return $relative_path;
2055 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2056 return $relative_path;
2059 function getJSPath($relative_path, $additional_attrs=''){
2060 if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
2061 if(empty($GLOBALS['sugar_config']['js_custom_version']))$GLOBALS['sugar_config']['js_custom_version'] = 1;
2062 $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
2063 $path = $relative_path . '?s=' . $js_version_key . '&c=' . $GLOBALS['sugar_config']['js_custom_version'] ;
2064 if ( inDeveloperMode() ) $path .= '&developerMode='.mt_rand();
2065 if(!empty($additonal_attrs)) $path .= '&' . $additional_attrs;
2069 function getSWFPath($relative_path, $additional_params=''){
2070 $path = $relative_path;
2071 if (!empty($additional_params)){
2072 $path .= '?' . $additional_params;
2074 if (defined('TEMPLATE_URL')){
2075 $path = TEMPLATE_URL . '/' . $path;
2084 function getSQLDate($date_str)
2086 if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
2088 if ( strlen($match[2]) == 1)
2090 $match[2] = "0".$match[2];
2092 if ( strlen($match[1]) == 1)
2094 $match[1] = "0".$match[1];
2096 return "{$match[3]}-{$match[1]}-{$match[2]}";
2098 else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2100 if ( strlen($match[2]) == 1)
2102 $match[2] = "0".$match[2];
2104 if ( strlen($match[1]) == 1)
2106 $match[1] = "0".$match[1];
2108 return "{$match[3]}-{$match[1]}-{$match[2]}";
2116 function clone_history(&$db, $from_id,$to_id, $to_type)
2121 require_once('include/upload_file.php');
2122 $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2124 $location=array('Email'=>"modules/Emails/Email.php",
2125 'Call'=>"modules/Calls/Call.php",
2126 'Meeting'=>"modules/Meetings/Meeting.php",
2127 'Note'=>"modules/Notes/Note.php",
2128 'Tasks'=>"modules/Tasks/Task.php",
2132 foreach($tables as $table=>$bean_class)
2135 if (!class_exists($bean_class))
2137 require_once($location[$bean_class]);
2140 $bProcessingNotes=false;
2141 if ($table=='notes')
2143 $bProcessingNotes=true;
2145 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2146 $results = $db->query($query);
2147 while($row = $db->fetchByAssoc($results))
2149 //retrieve existing record.
2150 $bean= new $bean_class();
2151 $bean->retrieve($row['id']);
2152 //process for new instance.
2153 if ($bProcessingNotes)
2155 $old_note_id=$row['id'];
2156 $old_filename=$bean->filename;
2159 $bean->parent_id=$to_id;
2160 $bean->parent_type=$to_type;
2161 if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2163 $bean->contact_id=$to_id;
2165 $bean->update_date_modified = false;
2166 $bean->update_modified_by = false;
2167 if(isset($bean->date_modified))
2168 $bean->date_modified = $timedate->to_db($bean->date_modified);
2169 if(isset($bean->date_entered))
2170 $bean->date_entered = $timedate->to_db($bean->date_entered);
2172 $new_id=$bean->save();
2174 //duplicate the file now. for notes.
2175 if ($bProcessingNotes && !empty($old_filename))
2177 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2179 //reset the values needed for attachment duplication.
2186 function values_to_keys($array)
2188 $new_array = array();
2189 if(!is_array($array))
2193 foreach($array as $arr){
2194 $new_array[$arr] = $arr;
2199 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2201 foreach($tables as $table)
2204 if ($table == 'emails_beans') {
2205 $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2207 $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2209 $results = $db->query($query);
2210 while($row = $db->fetchByAssoc($results))
2212 $query = "INSERT INTO $table ";
2215 $row[$from_column] = $to_id;
2216 $row['id'] = create_guid();
2217 if ($table=='emails_beans') {
2218 $row['bean_module'] =='Contacts';
2221 foreach($row as $name=>$value)
2227 $values .= "'$value'";
2230 $names .= ', '. $name;
2231 $values .= ", '$value'";
2234 $query .= "($names) VALUES ($values)";
2240 function get_unlinked_email_query($type, $bean) {
2241 global $current_user;
2243 $return_array['select']='SELECT emails.id ';
2244 $return_array['from']='FROM emails ';
2245 $return_array['where']="";
2246 $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear
2248 join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2249 eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2250 where eear.deleted=0 and eear.email_id not in
2251 (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2252 ) derivedemails on derivedemails.email_id = emails.id";
2253 $return_array['join_tables'][0] = '';
2255 if (isset($type) and !empty($type['return_as_array'])) {
2256 return $return_array;
2259 return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ;
2263 * Check to see if the number is empty or non-zero
2267 function number_empty($value)
2269 return empty($value) && $value != '0';
2272 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2275 require_once($beanFiles[$bean_name]);
2276 $focus = new $bean_name();
2277 $user_array = array();
2279 $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by;
2280 $user_array = get_register_value('select_array', $key );
2284 $db = DBManagerFactory::getInstance();
2285 $temp_result = Array();
2286 $query = "SELECT {$focus->table_name}.id, {$display_columns} as display from {$focus->table_name} ";
2290 $query .= $where." AND ";
2293 $query .= " {$focus->table_name}.deleted=0";
2295 if ( $order_by != '')
2297 $query .= " order by {$focus->table_name}.{$order_by}";
2300 $GLOBALS['log']->debug("get_user_array query: $query");
2301 $result = $db->query($query, true, "Error filling in user array: ");
2303 if ($add_blank==true){
2304 // Add in a blank row
2305 if($blank_is_none == true) { // set 'blank row' to "--None--"
2306 global $app_strings;
2307 $temp_result[''] = $app_strings['LBL_NONE'];
2309 $temp_result[''] = '';
2313 // Get the id and the name.
2314 while($row = $db->fetchByAssoc($result))
2316 $temp_result[$row['id']] = $row['display'];
2319 $user_array = $temp_result;
2320 set_register_value('select_array', $key ,$temp_result);
2329 * @param unknown_type $listArray
2331 // function parse_list_modules
2332 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2333 function parse_list_modules(&$listArray)
2335 global $modListHeader;
2336 $returnArray = array();
2338 foreach($listArray as $optionName => $optionVal)
2340 if(array_key_exists($optionName, $modListHeader))
2342 $returnArray[$optionName] = $optionVal;
2345 // special case for projects
2346 if(array_key_exists('Project', $modListHeader))
2348 $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2351 $acldenied = ACLController::disabledModuleList($listArray,false);
2352 foreach($acldenied as $denied){
2353 unset($returnArray[$denied]);
2355 asort($returnArray);
2357 return $returnArray;
2360 function display_notice($msg = false){
2361 global $error_notice;
2362 //no error notice - lets just display the error to the user
2363 if(!isset($error_notice)){
2364 echo '<br>'.$msg . '<br>';
2366 $error_notice .= $msg . '<br>';
2370 /* checks if it is a number that atleast has the plus at the beggining
2372 function skype_formatted($number){
2373 //kbrill - BUG #15375
2374 if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2377 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2379 // return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2382 function format_skype($number) {
2383 return preg_replace('/[^\+0-9]/','',$number);
2386 function insert_charset_header() {
2387 header('Content-Type: text/html; charset=UTF-8');
2390 function getCurrentURL()
2393 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2398 $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2402 function javascript_escape($str) {
2405 for($i = 0; $i < strlen($str); $i++) {
2407 if(ord(substr($str, $i, 1))==10){
2409 }elseif(ord(substr($str, $i, 1))==13){
2413 $new_str .= $str{$i};
2417 $new_str = str_replace("'", "\\'", $new_str);
2422 function js_escape($str, $keep=true){
2423 $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2426 $str = javascript_escape($str);
2429 $str = str_replace("'", " ", $str);
2430 $str = str_replace('"', " ", $str);
2435 //end function js_escape
2438 function br2nl($str) {
2439 $regex = "#<[^>]+br.+?>#i";
2440 preg_match_all($regex, $str, $matches);
2442 foreach($matches[0] as $match) {
2443 $str = str_replace($match, "<br>", $str);
2446 $brs = array('<br>','<br/>', '<br />');
2447 $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2448 $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2449 $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2450 $str = str_ireplace($brs, "\n", $str); // to retrieve it
2456 * Private helper function for displaying the contents of a given variable.
2457 * This function is only intended to be used for SugarCRM internal development.
2458 * The ppd stands for Pre Print Die.
2460 function _ppd($mixed)
2466 * Private helper function for displaying the contents of a given variable in
2467 * the Logger. This function is only intended to be used for SugarCRM internal
2468 * development. The pp stands for Pre Print.
2469 * @param $mixed var to print_r()
2470 * @param $die boolean end script flow
2471 * @param $displayStackTrace also show stack trace
2473 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2474 if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) {
2476 $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM');
2480 $mix = print_r($mixed, true); // send print_r() output to $mix
2481 $stack = debug_backtrace();
2483 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------');
2484 $GLOBALS['log']->$loglevel($mix);
2485 if($displayStackTrace) {
2486 foreach($stack as $position) {
2487 $GLOBALS['log']->$loglevel($position['file']."({$position['line']})");
2491 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------');
2492 $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------');
2500 * private helper function to quickly show the major, direct, field attributes of a given bean.
2501 * The ppf stands for Pre[formatted] Print Focus [object]
2502 * @param object bean The focus bean
2504 function _ppf($bean, $die=false) {
2510 * Private helper function for displaying the contents of a given variable.
2511 * This function is only intended to be used for SugarCRM internal development.
2512 * The pp stands for Pre Print.
2514 function _pp($mixed)
2519 * Private helper function for displaying the contents of a given variable.
2520 * This function is only intended to be used for SugarCRM internal development.
2521 * The pp stands for Pre Print.
2523 function _pstack_trace($mixed=NULL)
2528 * Private helper function for displaying the contents of a given variable.
2529 * This function is only intended to be used for SugarCRM internal development.
2530 * The pp stands for Pre Print Trace.
2532 function _ppt($mixed, $textOnly=false)
2537 * Private helper function for displaying the contents of a given variable.
2538 * This function is only intended to be used for SugarCRM internal development.
2539 * The pp stands for Pre Print Trace Die.
2541 function _pptd($mixed)
2546 * Private helper function for decoding javascript UTF8
2547 * This function is only intended to be used for SugarCRM internal development.
2549 function decodeJavascriptUTF8($str) {
2553 * Will check if a given PHP version string is supported (tested on this ver),
2554 * unsupported (results unknown), or invalid (something will break on this
2555 * ver). Do not pass in any pararameter to default to a check against the
2556 * current environment's PHP version.
2558 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2560 function check_php_version($sys_php_version = '') {
2561 $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2562 // versions below $min_considered_php_version considered invalid by default,
2563 // versions equal to or above this ver will be considered depending
2564 // on the rules that follow
2565 $min_considered_php_version = '5.2.1';
2567 // only the supported versions,
2568 // should be mutually exclusive with $invalid_php_versions
2569 $supported_php_versions = array (
2570 '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2572 //Find out what Database the system is using.
2573 global $sugar_config;
2575 if (isset($_REQUEST['setup_db_type'])) {
2576 $dbType = $_REQUEST['setup_db_type'];
2577 } else if (isset ($sugar_config['dbconfig']) && isset ($sugar_config['dbconfig']['db_type'])) {
2578 $dbType = $sugar_config['dbconfig']['db_type'];
2581 // invalid versions above the $min_considered_php_version,
2582 // should be mutually exclusive with $supported_php_versions
2584 // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2585 $invalid_php_versions = array('5.2.7');
2587 // default unsupported
2590 // versions below $min_considered_php_version are invalid
2591 if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2595 // supported version check overrides default unsupported
2596 foreach($supported_php_versions as $ver) {
2597 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2603 // invalid version check overrides default unsupported
2604 foreach($invalid_php_versions as $ver) {
2605 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2611 //allow a redhat distro to install, regardless of version. We are assuming the redhat naming convention is followed
2612 //and the php version contains 'rh' characters
2613 if(strpos($sys_php_version, 'rh') !== false) {
2621 * Will check if a given IIS version string is supported (tested on this ver),
2622 * unsupported (results unknown), or invalid (something will break on this
2625 * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2627 function check_iis_version($sys_iis_version = '') {
2629 $server_software = $_SERVER["SERVER_SOFTWARE"];
2631 if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/", $server_software, $out))
2632 $iis_version = $out[1][0];
2634 $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2636 // versions below $min_considered_iis_version considered invalid by default,
2637 // versions equal to or above this ver will be considered depending
2638 // on the rules that follow
2639 $min_considered_iis_version = '6.0';
2641 // only the supported versions,
2642 // should be mutually exclusive with $invalid_iis_versions
2643 $supported_iis_versions = array ('6.0', '7.0',);
2644 $unsupported_iis_versions = array();
2645 $invalid_iis_versions = array('5.0',);
2647 // default unsupported
2650 // versions below $min_considered_iis_version are invalid
2651 if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2655 // supported version check overrides default unsupported
2656 foreach($supported_iis_versions as $ver) {
2657 if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2663 // unsupported version check overrides default unsupported
2664 foreach($unsupported_iis_versions as $ver) {
2665 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2671 // invalid version check overrides default unsupported
2672 foreach($invalid_iis_versions as $ver) {
2673 if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2682 function pre_login_check(){
2683 global $action, $login_error;
2684 if(!empty($action)&& $action == 'Login'){
2686 if(!empty($login_error)){
2687 $login_error = htmlentities($login_error);
2688 $login_error = str_replace(array("<pre>","</pre>","\r\n", "\n"), "<br>", $login_error);
2689 $_SESSION['login_error'] = $login_error;
2691 function set_focus() {}
2692 if(document.getElementById("post_error")) {
2693 document.getElementById("post_error").innerHTML="'. $login_error. '";
2694 document.getElementById("cant_login").value=1;
2695 document.getElementById("login_button").disabled = true;
2696 document.getElementById("user_name").disabled = true;
2697 //document.getElementById("user_password").disabled = true;
2706 function sugar_cleanup($exit = false) {
2707 static $called = false;
2710 set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2711 chdir(realpath(dirname(__FILE__) . '/..'));
2712 global $sugar_config;
2713 require_once('include/utils/LogicHook.php');
2714 LogicHook::initialize();
2715 $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2717 //added this check to avoid errors during install.
2718 if (empty($sugar_config['dbconfig'])) {
2719 if ($exit) exit; else return;
2722 if (!class_exists('Tracker', true)) {
2723 require_once 'modules/Trackers/Tracker.php';
2726 // Now write the cached tracker_queries
2727 if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2728 if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2729 $GLOBALS['current_user']->savePreferencesToDB();
2732 //check to see if this is not an `ajax call AND the user preference error flag is set
2734 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2735 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction')
2736 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )
2737 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] )
2740 global $app_strings;
2741 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2742 $err_mess = $app_strings['ERROR_USER_PREFS'];
2743 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2746 ajaxStatus.flashStatus('$err_mess',7000);
2752 if(class_exists('DBManagerFactory')) {
2753 $db = DBManagerFactory::getInstance();
2761 register_shutdown_function('sugar_cleanup');
2765 check_logic_hook - checks to see if your custom logic is in the logic file
2766 if not, it will add it. If the file isn't built yet, it will create the file
2769 function check_logic_hook_file($module_name, $event, $action_array){
2770 require_once('include/utils/logic_utils.php');
2773 if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2775 $hook_array = get_hook_array($module_name);
2777 if(check_existing_element($hook_array, $event, $action_array)==true){
2778 //the hook at hand is present, so do nothing
2783 if(!empty($hook_array[$event]))
2785 $logic_count = count($hook_array[$event]);
2788 if($action_array[0]==""){
2789 $action_array[0] = $logic_count + 1;
2791 $hook_array[$event][] = $action_array;
2794 //end if the file exists already
2797 if($action_array[0]==""){
2798 $action_array[0] = 1;
2800 $hook_array = array();
2801 $hook_array[$event][] = $action_array;
2802 //end if else file exists already
2804 if($add_logic == true){
2806 //reorder array by element[0]
2807 //$hook_array = reorder_array($hook_array, $event);
2808 //!!!Finish this above TODO
2810 $new_contents = replace_or_add_logic_type($hook_array);
2811 write_logic_file($module_name, $new_contents);
2813 //end if add_element is true
2816 //end function check_logic_hook_file
2819 function remove_logic_hook($module_name, $event, $action_array) {
2820 require_once('include/utils/logic_utils.php');
2823 if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2824 // The file exists, let's make sure the hook is there
2825 $hook_array = get_hook_array($module_name);
2827 if(check_existing_element($hook_array, $event, $action_array)==true){
2828 // The hook is there, time to take it out.
2830 foreach ( $hook_array[$event] as $i => $hook ) {
2831 // We don't do a full comparison below just in case the filename changes
2832 if ( $hook[0] == $action_array[0]
2833 && $hook[1] == $action_array[1]
2834 && $hook[3] == $action_array[3]
2835 && $hook[4] == $action_array[4] ) {
2836 unset($hook_array[$event][$i]);
2840 $new_contents = replace_or_add_logic_type($hook_array);
2841 write_logic_file($module_name, $new_contents);
2847 function display_stack_trace($textOnly=false){
2849 $stack = debug_backtrace();
2851 echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
2859 foreach($stack as $item) {
2865 if(isset($item['file']))
2866 $file = $item['file'];
2867 if(isset($item['class']))
2868 $class = $item['class'];
2869 if(isset($item['line']))
2870 $line = $item['line'];
2871 if(isset($item['function']))
2872 $function = $item['function'];
2876 $out .= '<font color="black"><b>';
2882 $out .= '</b></font><font color="blue">';
2885 $out .= "[L:{$line}]";
2888 $out .= '</font><font color="red">';
2891 $out .= "({$class}:{$function})";
2894 $out .= '</font><br>';
2906 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
2907 $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
2908 $halt_script = true;
2910 case 2048: return; //depricated we have lots of these ignore them
2913 if ( error_reporting() & E_NOTICE ) {
2914 $halt_script = false;
2920 case E_USER_WARNING:
2921 case E_COMPILE_WARNING:
2922 case E_CORE_WARNING:
2925 $halt_script = false;
2930 case E_COMPILE_ERROR:
2934 $type = "Fatal Error";
2939 $type = "Parse Error";
2943 //don't know what it is might not be so bad
2944 $halt_script = false;
2945 $type = "Unknown Error ($errno)";
2948 $error_msg = '<b>'.$type.'</b>:' . $error_msg;
2950 display_stack_trace();
2960 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
2962 set_error_handler('StackTraceErrorHandler');
2964 function get_sub_cookies($name){
2966 if(isset($_COOKIE[$name])){
2967 $subs = explode('#', $_COOKIE[$name]);
2968 foreach($subs as $cookie){
2969 if(!empty($cookie)){
2970 $cookie = explode('=', $cookie);
2972 $cookies[$cookie[0]] = $cookie[1];
2981 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
2983 if(!empty($sub_object_array)){
2985 foreach($sub_object_array as $sub_object){
2987 //run_second level is set to true if you need to remove sub-sub components
2988 if($run_second_level==true){
2990 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
2992 //end if run_second_level is true
2994 $sub_object->mark_deleted($sub_object->id);
2995 //end foreach sub component
2997 //end if this is not empty
3000 //end function mark_delete_components
3004 * For translating the php.ini memory values into bytes. e.g. input value of '8M' will return 8388608.
3006 function return_bytes($val)
3009 $last = strtolower($val{strlen($val)-1});
3013 // The 'G' modifier is available since PHP 5.1.0
3026 * Adds the href HTML tags around any URL in the $string
3028 function url2html($string) {
3030 $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new" style="font-weight: normal;">\\1\\2</a>', $string);
3031 return $return_string;
3033 // End customization by Julian
3036 * tries to determine whether the Host machine is a Windows machine
3038 function is_windows() {
3039 static $is_windows = null;
3040 if (!isset($is_windows)) {
3041 $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
3047 * equivalent for windows filesystem for PHP's is_writable()
3048 * @param string file Full path to the file/dir
3049 * @return bool true if writable
3051 function is_writable_windows($file) {
3052 if($file{strlen($file)-1}=='/') {
3053 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
3056 // the assumption here is that Windows has an inherited permissions scheme
3057 // any file that is a descendant of an unwritable directory will inherit
3058 // that property and will trigger a failure below.
3063 $file = str_replace("/", '\\', $file);
3065 if(file_exists($file)) {
3066 if (!($f = @sugar_fopen($file, 'r+')))
3072 if(!($f = @sugar_fopen($file, 'w')))
3081 * best guesses Timezone based on webserver's TZ settings
3083 function lookupTimezone($userOffset = 0)
3085 return TimeDate::guessTimezone($userOffset);
3088 function convert_module_to_singular($module_array){
3091 foreach($module_array as $key => $value){
3092 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
3094 if($value=="Cases") {
3095 $module_array[$key] = "Case";
3097 if($key=="projecttask"){
3098 $module_array['ProjectTask'] = "Project Task";
3099 unset($module_array[$key]);
3103 return $module_array;
3105 //end function convert_module_to_singular
3109 * Given the bean_name which may be plural or singular return the singular
3110 * bean_name. This is important when you need to include files.
3112 function get_singular_bean_name($bean_name){
3113 global $beanFiles, $beanList;
3114 if(array_key_exists($bean_name, $beanList)){
3115 return $beanList[$bean_name];
3123 * Given the potential module name (singular name, renamed module name)
3124 * Return the real internal module name.
3126 function get_module_from_singular($singular) {
3128 // find the internal module name for a singular name
3129 if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) {
3131 $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular'];
3133 foreach ($singular_modules as $mod_name=>$sin_name) {
3134 if ($singular == $sin_name and $mod_name != $sin_name) {
3140 // find the internal module name for a renamed module
3141 if (isset($GLOBALS['app_list_strings']['moduleList'])) {
3143 $moduleList = $GLOBALS['app_list_strings']['moduleList'];
3145 foreach ($moduleList as $mod_name=>$name) {
3146 if ($singular == $name and $mod_name != $name) {
3152 // if it's not a singular name, nor a renamed name, return the original value
3156 function get_label($label_tag, $temp_module_strings){
3157 global $app_strings;
3158 if(!empty($temp_module_strings[$label_tag])){
3160 $label_name = $temp_module_strings[$label_tag];
3162 if(!empty($app_strings[$label_tag])){
3163 $label_name = $app_strings[$label_tag];
3165 $label_name = $label_tag;
3170 //end function get_label
3174 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3176 $rel_list = array();
3178 foreach($focus->relationship_fields as $rel_key => $rel_value){
3179 if($rel_value == $relationship_name){
3180 $temp_bean = get_module_info($tar_rel_module);
3181 // echo $focus->$rel_key;
3182 $temp_bean->retrieve($focus->$rel_key);
3183 if($temp_bean->id!=""){
3185 $rel_list[] = $temp_bean;
3191 foreach($focus->field_defs as $field_name => $field_def){
3192 //Check if the relationship_name matches a "relate" field
3193 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3194 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3195 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3196 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3198 $temp_bean = get_module_info($tar_rel_module);
3199 // echo $focus->$field_def['id_name'];
3200 $temp_bean->retrieve($focus->$field_def['id_name']);
3201 if($temp_bean->id!=""){
3203 $rel_list[] = $temp_bean;
3206 //Check if the relationship_name matches a "link" in a relate field
3207 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3208 $temp_bean = get_module_info($tar_rel_module);
3209 // echo $focus->$rel_value['id_name'];
3210 $temp_bean->retrieve($focus->$rel_value['id_name']);
3211 if($temp_bean->id!=""){
3213 $rel_list[] = $temp_bean;
3219 // special case for unlisted parent-type relationships
3220 if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3221 $temp_bean = get_module_info($tar_rel_module);
3222 $temp_bean->retrieve($focus->parent_id);
3223 if($temp_bean->id!=""){
3224 $rel_list[] = $temp_bean;
3231 //end function search_filter_rel_info
3234 function get_module_info($module_name){
3238 //Get dictionary and focus data for module
3239 $vardef_name = $beanList[$module_name];
3241 if($vardef_name=="aCase"){
3242 $class_name = "Case";
3244 $class_name = $vardef_name;
3247 if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3251 include_once('modules/'. $module_name . '/'.$class_name.'.php');
3253 $module_bean = new $vardef_name();
3254 return $module_bean;
3255 //end function get_module_table
3259 * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3261 * @param string $moduleName
3263 function get_valid_bean_name($module_name){
3266 $vardef_name = $beanList[$module_name];
3267 if($vardef_name=="aCase"){
3268 $bean_name = "Case";
3270 $bean_name = $vardef_name;
3277 function checkAuthUserStatus(){
3284 * This function returns an array of phpinfo() results that can be parsed and
3285 * used to figure out what version we run, what modules are compiled in, etc.
3286 * @param $level int info level constant (1,2,4,8...64);
3287 * @return $returnInfo array array of info about the PHP environment
3288 * @author original by "code at adspeed dot com" Fron php.net
3289 * @author customized for Sugar by Chris N.
3291 function getPhpInfo($level=-1) {
3292 /** Name (constant) Value Description
3293 INFO_GENERAL 1 The configuration line, php.ini location, build date, Web Server, System and more.
3294 INFO_CREDITS 2 PHP Credits. See also phpcredits().
3295 INFO_CONFIGURATION 4 Current Local and Master values for PHP directives. See also ini_get().
3296 INFO_MODULES 8 Loaded modules and their respective settings. See also get_loaded_extensions().
3297 INFO_ENVIRONMENT 16 Environment Variable information that's also available in $_ENV.
3298 INFO_VARIABLES 32 Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3299 INFO_LICENSE 64 PHP License information. See also the license FAQ.
3300 INFO_ALL -1 Shows all of the above. This is the default value.
3304 $phpinfo = ob_get_contents();
3307 $phpinfo = strip_tags($phpinfo,'<h1><h2><th><td>');
3308 $phpinfo = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3309 $phpinfo = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3310 $parsedInfo = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3313 $returnInfo = array();
3315 if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3316 $returnInfo['PHP Version'] = $version[1];
3320 for ($i=1; $i<count($parsedInfo); $i++) {
3321 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3322 $vName = trim($match[1]);
3323 $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3325 foreach ($parsedInfo2 AS $vOne) {
3326 $vPat = '<info>([^<]+)<\/info>';
3327 $vPat3 = "/$vPat\s*$vPat\s*$vPat/";
3328 $vPat2 = "/$vPat\s*$vPat/";
3330 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3331 $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3332 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3333 $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3345 * This function will take a string that has tokens like {0}, {1} and will replace
3346 * those tokens with the args provided
3347 * @param $format string to format
3348 * @param $args args to replace
3349 * @return $result a formatted string
3351 function string_format($format, $args){
3355 * If args array has only one argument, and it's empty, so empty single quotes are used '' . That's because
3356 * IN () fails and IN ('') works.
3358 if (count($args) == 1)
3361 $singleArgument = current($args);
3362 if (empty($singleArgument))
3364 return str_replace("{0}", "''", $result);
3369 for($i = 0; $i < count($args); $i++){
3370 $result = str_replace('{'.$i.'}', $args[$i], $result);
3376 * Generate a string for displaying a unique identifier that is composed
3377 * of a system_id and number. This is use to allow us to generate quote
3378 * numbers using a DB auto-increment key from offline clients and still
3379 * have the number be unique (since it is modified by the system_id.
3381 * @param $num of bean
3382 * @param $system_id from system
3383 * @return $result a formatted string
3385 function format_number_display($num, $system_id){
3386 global $sugar_config;
3387 if(isset($num) && !empty($num)){
3388 $num=unformat_number($num);
3389 if(isset($system_id) && $system_id == 1){
3390 return sprintf("%d", $num);
3393 return sprintf("%d-%d", $num, $system_id);
3397 function checkLoginUserStatus(){
3401 * This function will take a number and system_id and format
3402 * @param $url URL containing host to append port
3403 * @param $port the port number - if '' is passed, no change to url
3404 * @return $resulturl the new URL with the port appended to the host
3406 function appendPortToHost($url, $port)
3410 // if no port, don't change the url
3413 $split = explode("/", $url);
3414 //check if it starts with http, in case they didn't include that in url
3415 if(str_begin($url, 'http'))
3417 //third index ($split[2]) will be the host
3418 $split[2] .= ":".$port;
3420 else // otherwise assumed to start with host name
3422 //first index ($split[0]) will be the host
3423 $split[0] .= ":".$port;
3426 $resulturl = implode("/", $split);
3433 * Singleton to return JSON object
3434 * @return JSON object
3436 function getJSONobj() {
3437 static $json = null;
3439 require_once('include/JSON.php');
3440 $json = new JSON(JSON_LOOSE_TYPE);
3445 require_once('include/utils/db_utils.php');
3448 * Set default php.ini settings for entry points
3450 function setPhpIniSettings() {
3452 // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3454 if(function_exists('gzclose') && headers_sent() == false) {
3455 ini_set('zlib.output_compression', 1);
3459 //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3461 /*if(function_exists('mb_strlen')) {
3462 ini_set('mbstring.func_overload', 7);
3463 ini_set('mbstring.internal_encoding', 'UTF-8');
3467 // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3468 // starting with 5.2.0, backtrack_limit breaks JSON decoding
3469 $backtrack_limit = ini_get('pcre.backtrack_limit');
3470 if(!empty($backtrack_limit)) {
3471 ini_set('pcre.backtrack_limit', '-1');
3475 if(ini_get("mssql.charset")) {
3476 ini_set('mssql.charset', "UTF-8");
3481 * like array_merge() but will handle array elements that are themselves arrays;
3482 * PHP's version just overwrites the element with the new one.
3484 * @internal Note that this function deviates from the internal array_merge()
3485 * functions in that it does does not treat numeric keys differently
3486 * than string keys. Additionally, it deviates from
3487 * array_merge_recursive() by not creating an array when like values
3490 * @param array gimp the array whose values will be overloaded
3491 * @param array dom the array whose values will pwn the gimp's
3492 * @return array beaten gimp
3494 function sugarArrayMerge($gimp, $dom) {
3495 if(is_array($gimp) && is_array($dom)) {
3496 foreach($dom as $domKey => $domVal) {
3497 if(array_key_exists($domKey, $gimp)) {
3498 if(is_array($domVal)) {
3500 foreach ( $domVal as $domArrKey => $domArrVal )
3501 $tempArr[$domArrKey] = $domArrVal;
3502 foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3503 if ( !array_key_exists($gimpArrKey, $tempArr) )
3504 $tempArr[$gimpArrKey] = $gimpArrVal;
3505 $gimp[$domKey] = $tempArr;
3507 $gimp[$domKey] = $domVal;
3510 $gimp[$domKey] = $domVal;
3514 // if the passed value for gimp isn't an array, then return the $dom
3515 elseif(is_array($dom))
3522 * Similiar to sugarArrayMerge except arrays of N depth are merged.
3524 * @param array gimp the array whose values will be overloaded
3525 * @param array dom the array whose values will pwn the gimp's
3526 * @return array beaten gimp
3528 function sugarArrayMergeRecursive($gimp, $dom) {
3529 if(is_array($gimp) && is_array($dom)) {
3530 foreach($dom as $domKey => $domVal) {
3531 if(array_key_exists($domKey, $gimp)) {
3532 if(is_array($domVal) && is_array($gimp[$domKey])) {
3533 $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3535 $gimp[$domKey] = $domVal;
3538 $gimp[$domKey] = $domVal;
3542 // if the passed value for gimp isn't an array, then return the $dom
3543 elseif(is_array($dom))
3550 * finds the correctly working versions of PHP-JSON
3551 * @return bool True if NOT found or WRONG version
3553 function returnPhpJsonStatus() {
3554 if(function_exists('json_encode')) {
3555 $phpInfo = getPhpInfo(8);
3556 return version_compare($phpInfo['json']['json version'], '1.1.1', '<');
3558 return true; // not found
3563 * getTrackerSubstring
3565 * Returns a [number]-char or less string for the Tracker to display in the header
3566 * based on the tracker_max_display_length setting in config.php. If not set,
3567 * or invalid length, then defaults to 15 for COM editions, 30 for others.
3569 * @param string name field for a given Object
3570 * @return string [number]-char formatted string if length of string exceeds the max allowed
3572 function getTrackerSubstring($name) {
3573 static $max_tracker_item_length;
3576 $name = html_entity_decode($name, ENT_QUOTES, 'UTF-8');
3577 $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3579 global $sugar_config;
3581 if(!isset($max_tracker_item_length)) {
3582 if(isset($sugar_config['tracker_max_display_length'])) {
3583 $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;
3585 $max_tracker_item_length = 15;
3589 if($strlen > $max_tracker_item_length) {
3590 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length, "UTF-8");
3597 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3598 $where_clauses= array();
3600 $table_name=$bean->object_name;
3601 foreach ($field_list[$module] as $field=>$parms) {
3602 if(isset($values[$field]) && $values[$field] != "") {
3604 if (!empty($parms['operator'])) {
3605 $operator=$parms['operator'];
3607 if (is_array($values[$field])) {
3610 foreach ($values[$field] as $key => $val) {
3611 if ($val != ' ' and $val != '') {
3612 if (!empty($field_value)) {
3615 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3619 $field_value=$GLOBALS['db']->quote($values[$field]);
3621 //set db_fields array.
3622 if (!isset($parms['db_field']) ) {
3623 $parms['db_field'] = array($field);
3625 if (isset($parms['my_items']) and $parms['my_items'] == true) {
3626 global $current_user;
3627 $field_value = $GLOBALS['db']->quote($current_user->id);
3633 if ($field_value != '') {
3635 foreach ($parms['db_field'] as $db_field) {
3636 if (strstr($db_field,'.')===false) {
3637 $db_field=$bean->table_name.".".$db_field;
3639 if ($GLOBALS['db']->dbType=='oci8' && isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3640 $db_field='upper('.$db_field.")";
3641 $field_value=strtoupper($field_value);
3645 if (!empty($where)) {
3648 switch (strtolower($operator)) {
3650 $where .= $db_field . " like '".$field_value.$like_char."'";
3653 $where .= $db_field . " in (".$field_value.')';
3656 $where .= $db_field . " = '".$field_value ."'";
3661 if (!empty($where)) {
3663 array_push($where_clauses, '( '.$where.' )');
3665 array_push($where_clauses, $where);
3670 if ($add_custom_fields) {
3671 require_once('modules/DynamicFields/DynamicField.php');
3672 $bean->setupCustomFields($module);
3673 $bean->custom_fields->setWhereClauses($where_clauses);
3675 return $where_clauses;
3678 function add_quotes($str) {
3683 * This function will rebuild the config file
3684 * @param $sugar_config
3685 * @param $sugar_version
3686 * @return bool true if successful
3688 function rebuildConfigFile($sugar_config, $sugar_version) {
3689 // add defaults to missing values of in-memory sugar_config
3690 $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3691 // need to override version with default no matter what
3692 $sugar_config['sugar_version'] = $sugar_version;
3694 ksort( $sugar_config );
3696 if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3705 * getJavascriptSiteURL
3706 * This function returns a URL for the client javascript calls to access
3707 * the site. It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3708 * are used to access the site. Thus, the hostname in the URL returned may
3709 * not always match that of $sugar_config['site_url']. Basically, the
3710 * assumption is that however the user accessed the website is how they
3711 * will continue to with subsequent javascript requests. If the variable
3712 * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3713 * @return $site_url The url used to refer to the website
3715 function getJavascriptSiteURL() {
3716 global $sugar_config;
3717 if(!empty($_SERVER['HTTP_REFERER'])) {
3718 $url = parse_url($_SERVER['HTTP_REFERER']);
3719 $replacement_url = $url['scheme']."://".$url['host'];
3720 if(!empty($url['port']))
3721 $replacement_url .= ':'.$url['port'];
3722 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3724 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3725 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3726 $site_url = preg_replace('/^http\:/','https:',$site_url);
3729 $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=". $site_url);
3733 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3734 function add_squotes($str) {
3735 return "'" . $str . "'";
3739 // recursive function to count the number of levels within an array
3740 function array_depth($array, $depth_count=-1, $depth_array=array()){
3742 if (is_array($array)){
3743 foreach ($array as $key => $value){
3744 $depth_array[] = array_depth($value, $depth_count);
3748 return $depth_count;
3750 foreach ($depth_array as $value){
3751 $depth_count = $value > $depth_count ? $value : $depth_count;
3753 return $depth_count;
3757 * Creates a new Group User
3758 * @param string $name Name of Group User
3759 * @return string GUID of new Group User
3761 function createGroupUser($name) {
3764 $group = new User();
3765 $group->user_name = $name;
3766 $group->last_name = $name;
3767 $group->is_group = 1;
3768 $group->deleted = 0;
3769 $group->status = 'Active'; // cn: bug 6711
3770 $group->setPreference('timezone', TimeDate::userTimezone());
3777 * Helper function to locate an icon file given only a name
3778 * Searches through the various paths for the file
3779 * @param string iconFileName The filename of the icon
3780 * @return string Relative pathname of the located icon, or '' if not found
3783 function _getIcon($iconFileName)
3785 $iconPath = SugarThemeRegistry::current()->getImageURL("icon_{$iconFileName}.gif");
3786 //First try un-ucfirst-ing the icon name
3787 if ( empty($iconPath) )
3788 $iconPath = SugarThemeRegistry::current()->getImageURL(
3789 "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif");
3790 //Next try removing the icon prefix
3791 if ( empty($iconPath) )
3792 $iconPath = SugarThemeRegistry::current()->getImageURL("{$iconFileName}.gif");
3797 * Function to grab the correct icon image for Studio
3798 * @param string $iconFileName Name of the icon file
3799 * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3800 * @param string $width Width of image
3801 * @param string $height Height of image
3802 * @param string $align Alignment of image
3803 * @return string $string <img> tag with corresponding image
3806 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline' )
3808 global $app_strings, $theme;
3810 $iconPath = _getIcon($iconFileName);
3811 if(empty($iconPath)){
3812 $iconPath = _getIcon($altFileName);
3813 if (empty($iconPath))
3815 return $app_strings['LBL_NO_IMAGE'];
3818 return '<img border="0" src="'.$iconPath.'" width="'.$width.'" height="'.$height.'" align="'.$align.'">';
3822 * Function to grab the correct icon image for Dashlets Dialog
3823 * @param string $filename Location of the icon file
3824 * @param string $module Name of the module to fall back onto if file does not exist
3825 * @param string $width Width of image
3826 * @param string $height Height of image
3827 * @param string $align Alignment of image
3828 * @return string $string <img> tag with corresponding image
3831 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle'){
3832 global $app_strings, $theme;
3833 $icon_path = _getIcon($module . "_32");
3834 if (empty($icon_path))
3836 $icon_path = _getIcon($module);
3838 if(empty($icon_path)){
3839 $icon = $app_strings['LBL_NO_IMAGE'];
3842 $icon = '<img border="0" src="'.$icon_path.'" width="'.$width.'" height="'.$height.'" align="'.$align.'">';
3847 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
3848 function html_entity_decode_utf8($string)
3851 // replace numeric entities
3852 //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
3853 $string = preg_replace('~�*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
3854 $string = preg_replace('~�*([0-9]+);~e', 'code2utf(\\1)', $string);
3855 // replace literal entities
3856 if (!isset($trans_tbl))
3858 $trans_tbl = array();
3859 foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
3860 $trans_tbl[$key] = utf8_encode($val);
3862 return strtr($string, $trans_tbl);
3865 // Returns the utf string corresponding to the unicode value
3866 function code2utf($num)
3868 if ($num < 128) return chr($num);
3869 if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
3870 if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3871 if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3875 function str_split_php4($string, $length = 1) {
3876 $string_length = strlen($string);
3879 if ($length > $string_length) {
3880 // use the string_length as the string is shorter than the length
3881 $length = $string_length;
3883 for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
3884 $return[] = substr($string, $cursor, $length);
3889 if (version_compare(phpversion(), '5.0.0', '<')) {
3890 function str_split($string, $length = 1) {
3891 return str_split_php4($string, $length);
3896 * Invoked when connected to mssql. checks if we have freetds version of mssql library.
3897 * the response is put into a global variable.
3899 function is_freetds() {
3902 if (isset($GLOBALS['mssql_library_version'])) {
3903 if ($GLOBALS['mssql_library_version']=='freetds') {
3911 $info=ob_get_contents();
3914 if (strpos($info,'FreeTDS') !== false) {
3915 $GLOBALS['mssql_library_version']='freetds';
3918 $GLOBALS['mssql_library_version']='regular';
3926 * stripos - Find position of first occurrence of a case-insensitive string
3928 * The function is being defined for systems with PHP version < 5.
3931 if (!function_exists("stripos")){
3932 function stripos($haystack,$needle,$offset=0){
3933 return strpos(strtolower($haystack),strtolower($needle),$offset);
3938 * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
3940 * @todo this won't work completely right until we impliment css compression and combination
3941 * for now, we'll just include the last css file found.
3943 * @return chart.css file to use
3945 function chartStyle()
3947 return SugarThemeRegistry::current()->getCSSURL('chart.css');
3951 * Chart dashlet helper functions that returns the correct XML color file for charts,
3952 * dependent on the current theme.
3954 * @return sugarColors.xml to use
3956 function chartColors()
3958 if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
3959 return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
3960 return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
3962 /* End Chart Dashlet helper functions */
3965 * This function is designed to set up the php enviroment
3966 * for AJAX requests.
3969 function ajaxInit() {
3970 ini_set('display_errors', 'false');
3974 * Returns an absolute path from the given path, determining if it is relative or absolute
3976 * @param string $path
3979 function getAbsolutePath(
3981 $currentServer = false
3984 $path = trim($path);
3986 // try to match absolute paths like \\server\share, /directory or c:\
3987 if ( ( substr($path,0,2) == '\\\\' )
3988 || ( $path[0] == '/' )
3989 || preg_match('/^[A-z]:/i',$path)
3993 return getcwd().'/'.$path;
3997 * Returns the bean object of the given module
3999 * @deprecated use SugarModule::loadBean() instead
4000 * @param string $module
4007 return SugarModule::get($module)->loadBean();
4012 * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
4014 function isTouchScreen()
4016 $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
4018 // first check if we have forced use of the touch enhanced interface
4019 if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
4023 // next check if we should use the touch interface with our device
4024 if ( strpos($ua, 'ipad') !== false ) {
4032 * Returns the shortcut keys to access the shortcut links. Shortcut
4033 * keys vary depending on browser versions and operating systems.
4034 * @return String value of the shortcut keys
4036 function get_alt_hot_key() {
4038 if ( isset($_SERVER['HTTP_USER_AGENT']) )
4039 $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
4040 $isMac = strpos($ua, 'mac') !== false;
4041 $isLinux = strpos($ua, 'linux') !== false;
4043 if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
4044 if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
4045 return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
4048 return $isMac ? 'Ctrl+' : 'Alt+';
4051 function can_start_session(){
4052 if(!empty($_GET['PHPSESSID'])) {
4055 $session_id = session_id();
4056 return empty($session_id) ? true : false;
4059 function load_link_class($properties){
4061 if(!empty($properties['link_class']) && !empty($properties['link_file'])){
4062 require_once($properties['link_file']);
4063 $class = $properties['link_class'];
4069 function inDeveloperMode()
4071 return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
4075 * Filter the protocol list for inbound email accounts.
4077 * @param array $protocol
4079 function filterInboundEmailPopSelection($protocol)
4081 if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
4083 if( isset($protocol['pop3']) )
4084 unset($protocol['pop3']);
4087 $protocol['pop3'] = 'POP3';
4093 * The function is used because currently we are not supporting mbstring.func_overload
4094 * 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.
4095 * 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.
4096 * @returns the substred strings.
4098 function sugar_substr($string, $length, $charset='UTF-8') {
4099 if($GLOBALS['db']->dbType == 'mssql' && empty($GLOBALS['db']->isFreeTDS)) {
4100 if(strlen($string) > $length) {
4101 $string = trim(substr(trim($string),0,$length));
4105 if(mb_strlen($string,$charset) > $length) {
4106 $string = trim(mb_substr(trim($string),0,$length,$charset));
4113 * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
4114 * This will work even without setting the mbstring.*encoding
4116 function sugar_ucfirst($string, $charset='UTF-8') {
4117 return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
4124 function unencodeMultienum($string) {
4125 if (is_array($string))
4129 if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
4130 $string = substr(substr($string, 1), 0, strlen($string) -2);
4133 return explode('^,^', $string);
4136 function encodeMultienumValue($arr) {
4137 if (!is_array($arr))
4143 $string = "^" . implode('^,^', $arr) . "^";
4149 * create_export_query is used for export and massupdate
4150 * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4151 * This function will correct the where clause and output necessary join condition for them
4152 * @param $module: the module name
4153 * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4154 * @param $where: where clauses
4155 * @return $ret_array['where']: corrected where clause
4156 * @return $ret_array['join']: extra join condition
4158 function create_export_query_relate_link_patch($module, $searchFields, $where){
4159 if(file_exists('modules/'.$module.'/SearchForm.html')){
4160 $ret_array['where'] = $where;
4163 $seed = loadBean($module);
4164 foreach($seed->field_defs as $name=>$field)
4167 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4168 $seed->load_relationship($field['link']);
4170 if(empty($join_type))
4172 $params['join_type'] = ' LEFT JOIN ';
4176 $params['join_type'] = $join_type;
4178 if(isset($data['join_name']))
4180 $params['join_table_alias'] = $field['join_name'];
4184 $params['join_table_alias'] = 'join_'.$field['name'];
4187 if(isset($data['join_link_name']))
4189 $params['join_table_link_alias'] = $field['join_link_name'];
4193 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4195 $join = $seed->$field['link']->getJoin($params, true);
4196 $join_table_alias = 'join_'.$field['name'];
4197 if(isset($field['db_concat_fields'])){
4198 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4199 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4201 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4205 $ret_array = array('where'=>$where, 'join'=>$join['join']);
4210 * 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.
4211 * @Depends on QuickRepairAndRebuild.php
4212 * @Relate bug 30642 ,23177
4214 function clearAllJsAndJsLangFilesWithoutOutput(){
4215 global $current_language , $mod_strings;
4216 $MBmodStrings = $mod_strings;
4217 $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4218 include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4219 $repair = new RepairAndClear();
4220 $repair->module_list = array();
4221 $repair->show_output = false;
4222 $repair->clearJsLangFiles();
4223 $repair->clearJsFiles();
4224 $mod_strings = $MBmodStrings;
4228 * This function will allow you to get a variable value from query string
4230 function getVariableFromQueryString($variable, $string){
4232 $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4242 * should_hide_iframes
4243 * This is a helper method to determine whether or not to show iframes (My Sites) related
4244 * information in the application.
4246 * @return boolean flag indicating whether or not iframes module should be hidden
4248 function should_hide_iframes() {
4249 //Remove the MySites module
4250 if(file_exists('modules/iFrames/iFrame.php')) {
4251 if(!class_exists("iFrame")) {
4252 require_once('modules/iFrames/iFrame.php');
4260 * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4262 * @param string $version
4263 * @return string RC, BETA, GA
4265 function getVersionStatus($version){
4266 if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4267 return strtoupper($matches[1]);
4274 * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4275 * 5.5.1RC1 then return 5.5.1
4277 * @param string $version
4280 function getMajorMinorVersion($version){
4281 if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4282 $version = $matches2[1];
4283 $arr = explode('.', $version);
4284 if(count($arr) > 2){
4286 $version = substr($version, 0, 3);
4294 * Return string composed of seconds & microseconds of current time, without dots
4297 function sugar_microtime()
4299 $now = explode(' ', microtime());
4300 $unique_id = $now[1].str_replace('.', '', $now[0]);
4305 * Extract urls from a piece of text
4307 * @return array of urls found in $string
4309 function getUrls($string)
4311 $lines = explode("<br>", trim($string));
4313 foreach($lines as $line){
4314 $regex = '/http?\:\/\/[^\" ]+/i';
4315 preg_match_all($regex, $line, $matches);
4316 foreach($matches[0] as $match){
4325 * Sanitize image file from hostile content
4326 * @param string $path Image file
4327 * @param bool $jpeg Accept only JPEGs?
4329 function verify_image_file($path, $jpeg = false)
4331 if(function_exists('imagepng') && function_exists('imagejpeg') && function_exists('imagecreatefromstring')) {
4332 $img = imagecreatefromstring(file_get_contents($path));
4336 $img_size = getimagesize($path);
4337 $filetype = $img_size['mime'];
4338 //if filetype is jpeg or if we are only allowing jpegs, create jpg image
4339 if($filetype == "image/jpeg" || $jpeg) {
4340 if(imagejpeg($img, $path)) {
4343 } elseif ($filetype == "image/png") { // else if the filetype is png, create png
4344 imagealphablending($img, true);
4345 imagesavealpha($img, true);
4346 if(imagepng($img, $path)) {
4353 // check image manually
4354 $fp = fopen($path, "r");
4355 if(!$fp) return false;
4356 $data = fread($fp, 4096);
4358 if(preg_match("/<(html|!doctype|script|body|head|plaintext|table|img |pre(>| )|frameset|iframe|object|link|base|style|font|applet|meta|center|form|isindex)/i",
4360 $GLOBALS['log']->info("Found {$m[0]} in $path, not allowing upload");
4369 * Verify uploaded image
4370 * Verifies that image has proper extension, MIME type and doesn't contain hostile contant
4371 * @param string $path Image path
4372 * @param bool $jpeg_only Accept only JPEGs?
4374 function verify_uploaded_image($path, $jpeg_only = false)
4376 $supportedExtensions = array('jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
4378 $supportedExtensions['png'] = 'image/png';
4381 if(!file_exists($path) || !is_file($path)) {
4385 $img_size = getimagesize($path);
4386 $filetype = $img_size['mime'];
4387 $ext = end(explode(".", $path));
4388 if(substr_count('..', $path) > 0 || $ext === $path || !in_array(strtolower($ext), array_keys($supportedExtensions)) ||
4389 !in_array($filetype, array_values($supportedExtensions))) {
4392 return verify_image_file($path, $jpeg_only);
4395 function cmp_beans($a, $b)
4397 global $sugar_web_service_order_by;
4398 //If the order_by field is not valid, return 0;
4399 if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){
4402 if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by)
4403 || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by))
4407 if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by)
4415 function order_beans($beans, $field_name)
4417 //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans.
4418 global $sugar_web_service_order_by;
4419 $sugar_web_service_order_by = $field_name;
4420 usort($beans, "cmp_beans");
4424 //check to see if custom utils exists
4425 if(file_exists('custom/include/custom_utils.php')){
4426 include_once('custom/include/custom_utils.php');
4429 //check to see if custom utils exists in Extension framework
4430 if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) {
4431 include_once('custom/application/Ext/Utils/custom_utils.ext.php');
4434 * @param $input - the input string to sanitize
4435 * @param int $quotes - use quotes
4436 * @param string $charset - the default charset
4437 * @param bool $remove - strip tags or not
4438 * @return string - the sanitized string
4440 function sanitize($input, $quotes = ENT_QUOTES, $charset = 'UTF-8', $remove = false)
4442 return htmlentities($input, $quotes, $charset);
4447 * utf8_recursive_encode
4449 * This function walks through an Array and recursively calls utf8_encode on the
4450 * values of each of the elements.
4452 * @param $data Array of data to encode
4453 * @return utf8 encoded Array data
4455 function utf8_recursive_encode($data)
4458 foreach($data as $key=>$val) {
4459 if(is_array($val)) {
4460 $result[$key] = utf8_recursive_encode($val);
4462 $result[$key] = utf8_encode($val);