| [ Index ] |
PHP Cross Reference of MantisBT |
[Summary view] [Print] [Text view]
1 <?php 2 # MantisConnect - A webservice interface to Mantis Bug Tracker 3 # Copyright (C) 2004-2011 Victor Boctor - vboctor@users.sourceforge.net 4 # This program is distributed under dual licensing. These include 5 # GPL and a commercial licenses. Victor Boctor reserves the right to 6 # change the license of future releases. 7 # See docs/ folder for more details 8 9 # set up error_handler() as the new default error handling function 10 set_error_handler( 'mc_error_handler' ); 11 12 # override some MantisBT configurations 13 $g_show_detailed_errors = OFF; 14 $g_stop_on_errors = ON; 15 $g_display_errors = array( 16 E_WARNING => 'halt', 17 E_NOTICE => 'halt', 18 E_USER_ERROR => 'halt', 19 E_USER_WARNING => 'halt', 20 E_USER_NOTICE => 'halt', 21 ); 22 23 /** 24 * Get the MantisConnect webservice version. 25 */ 26 function mc_version() { 27 return MANTIS_VERSION; 28 } 29 30 # Checks if MantisBT installation is marked as offline by the administrator. 31 # true: offline, false: online 32 function mci_is_mantis_offline() { 33 $t_offline_file = dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'mantis_offline.php'; 34 return file_exists( $t_offline_file ); 35 } 36 37 # return user_id if successful, otherwise false. 38 function mci_check_login( $p_username, $p_password ) { 39 if( mci_is_mantis_offline() ) { 40 return false; 41 } 42 43 # if no user name supplied, then attempt to login as anonymous user. 44 if( is_blank( $p_username ) ) { 45 $t_anon_allowed = config_get( 'allow_anonymous_login' ); 46 if( OFF == $t_anon_allowed ) { 47 return false; 48 } 49 50 $p_username = config_get( 'anonymous_account' ); 51 52 # do not use password validation. 53 $p_password = null; 54 } 55 56 if( false === auth_attempt_script_login( $p_username, $p_password ) ) { 57 return false; 58 } 59 60 return auth_get_current_user_id(); 61 } 62 63 function mci_has_readonly_access( $p_user_id, $p_project_id = ALL_PROJECTS ) { 64 $t_access_level = user_get_access_level( $p_user_id, $p_project_id ); 65 return( $t_access_level >= config_get( 'mc_readonly_access_level_threshold' ) ); 66 } 67 68 function mci_has_readwrite_access( $p_user_id, $p_project_id = ALL_PROJECTS ) { 69 $t_access_level = user_get_access_level( $p_user_id, $p_project_id ); 70 return( $t_access_level >= config_get( 'mc_readwrite_access_level_threshold' ) ); 71 } 72 73 function mci_has_access( $p_access_level, $p_user_id, $p_project_id = ALL_PROJECTS ) { 74 $t_access_level = user_get_access_level( $p_user_id, $p_project_id ); 75 return( $t_access_level >= (int) $p_access_level ); 76 } 77 78 function mci_has_administrator_access( $p_user_id, $p_project_id = ALL_PROJECTS ) { 79 $t_access_level = user_get_access_level( $p_user_id, $p_project_id ); 80 return( $t_access_level >= config_get( 'mc_admin_access_level_threshold' ) ); 81 } 82 83 function mci_get_project_id( $p_project ) { 84 if( (int) $p_project['id'] != 0 ) { 85 $t_project_id = (int) $p_project['id']; 86 } else { 87 $t_project_id = project_get_id_by_name( $p_project['name'] ); 88 } 89 90 return $t_project_id; 91 } 92 93 function mci_get_project_status_id( $p_status ) { 94 return mci_get_enum_id_from_objectref( 'project_status', $p_status ); 95 } 96 97 function mci_get_project_view_state_id( $p_view_state ) { 98 return mci_get_enum_id_from_objectref( 'project_view_state', $p_view_state ); 99 } 100 101 function mci_get_user_id( $p_user ) { 102 $t_user_id = 0; 103 104 if ( isset( $p_user['id'] ) && (int) $p_user['id'] != 0 ) { 105 $t_user_id = (int) $p_user['id']; 106 } elseif ( isset( $p_user['name'] ) ) { 107 $t_user_id = user_get_id_by_name( $p_user['name'] ); 108 } 109 110 return $t_user_id; 111 } 112 113 function mci_get_user_lang( $p_user_id ) { 114 $t_lang = user_pref_get_pref( $p_user_id, 'language' ); 115 if( $t_lang == 'auto' ) { 116 $t_lang = config_get( 'fallback_language' ); 117 } 118 return $t_lang; 119 } 120 121 function mci_get_status_id( $p_status ) { 122 return mci_get_enum_id_from_objectref( 'status', $p_status ); 123 } 124 125 function mci_get_severity_id( $p_severity ) { 126 return mci_get_enum_id_from_objectref( 'severity', $p_severity ); 127 } 128 129 function mci_get_priority_id( $p_priority ) { 130 131 return mci_get_enum_id_from_objectref( 'priority', $p_priority ); 132 } 133 134 function mci_get_reproducibility_id( $p_reproducibility ) { 135 return mci_get_enum_id_from_objectref( 'reproducibility', $p_reproducibility ); 136 } 137 138 function mci_get_resolution_id( $p_resolution ) { 139 return mci_get_enum_id_from_objectref( 'resolution', $p_resolution ); 140 } 141 142 function mci_get_projection_id( $p_projection ) { 143 return mci_get_enum_id_from_objectref( 'projection', $p_projection ); 144 } 145 146 function mci_get_eta_id( $p_eta ) { 147 return mci_get_enum_id_from_objectref( 'eta', $p_eta ); 148 } 149 150 function mci_get_view_state_id( $p_view_state ) { 151 return mci_get_enum_id_from_objectref( 'view_state', $p_view_state ); 152 } 153 154 # Get null on empty value. 155 # 156 # @param Object $p_value The value 157 # @return Object The value if not empty; null otherwise. 158 # 159 function mci_null_if_empty( $p_value ) { 160 if( !is_blank( $p_value ) ) { 161 return $p_value; 162 } 163 164 return null; 165 } 166 167 /** 168 * Gets the url for MantisBT. 169 * 170 * @return MantisBT URL terminated by a /. 171 */ 172 function mci_get_mantis_path() { 173 174 return config_get( 'path' ); 175 } 176 177 # Given a enum string and num, return the appropriate localized string 178 function mci_get_enum_element( $p_enum_name, $p_val, $p_lang ) { 179 $t_enum_string = config_get( $p_enum_name . '_enum_string' ); 180 $t_localized_enum_string = lang_get( $p_enum_name . '_enum_string', $p_lang ); 181 182 return MantisEnum::getLocalizedLabel( $t_enum_string, $t_localized_enum_string, $p_val ); 183 } 184 185 # Gets the sub-projects that are accessible to the specified user / project. 186 function mci_user_get_accessible_subprojects( $p_user_id, $p_parent_project_id, $p_lang = null ) { 187 if( $p_lang === null ) { 188 $t_lang = mci_get_user_lang( $p_user_id ); 189 } else { 190 $t_lang = $p_lang; 191 } 192 193 $t_result = array(); 194 foreach( user_get_accessible_subprojects( $p_user_id, $p_parent_project_id ) as $t_subproject_id ) { 195 $t_subproject_row = project_cache_row( $t_subproject_id ); 196 $t_subproject = array(); 197 $t_subproject['id'] = $t_subproject_id; 198 $t_subproject['name'] = $t_subproject_row['name']; 199 $t_subproject['status'] = mci_enum_get_array_by_id( $t_subproject_row['status'], 'project_status', $t_lang ); 200 $t_subproject['enabled'] = $t_subproject_row['enabled']; 201 $t_subproject['view_state'] = mci_enum_get_array_by_id( $t_subproject_row['view_state'], 'project_view_state', $t_lang ); 202 $t_subproject['access_min'] = mci_enum_get_array_by_id( $t_subproject_row['access_min'], 'access_levels', $t_lang ); 203 $t_subproject['file_path'] = array_key_exists( 'file_path', $t_subproject_row ) ? $t_subproject_row['file_path'] : ""; 204 $t_subproject['description'] = array_key_exists( 'description', $t_subproject_row ) ? $t_subproject_row['description'] : ""; 205 $t_subproject['subprojects'] = mci_user_get_accessible_subprojects( $p_user_id, $t_subproject_id, $t_lang ); 206 $t_result[] = $t_subproject; 207 } 208 209 return $t_result; 210 } 211 212 function translate_category_name_to_id( $p_category_name, $p_project_id ) { 213 if ( !isset( $p_category_name ) ) { 214 return 0; 215 } 216 217 $t_cat_array = category_get_all_rows( $p_project_id ); 218 foreach( $t_cat_array as $t_category_row ) { 219 if( $t_category_row['name'] == $p_category_name ) { 220 return $t_category_row['id']; 221 } 222 } 223 return 0; 224 } 225 226 /** 227 * Basically this is a copy of core/filter_api.php#filter_db_get_available_queries(). 228 * The only difference is that the result of this function is not an array of filter 229 * names but an array of filter structures. 230 */ 231 function mci_filter_db_get_available_queries( $p_project_id = null, $p_user_id = null ) { 232 $t_filters_table = db_get_table( 'filters' ); 233 $t_overall_query_arr = array(); 234 235 if( null === $p_project_id ) { 236 $t_project_id = helper_get_current_project(); 237 } else { 238 $t_project_id = db_prepare_int( $p_project_id ); 239 } 240 241 if( null === $p_user_id ) { 242 $t_user_id = auth_get_current_user_id(); 243 } else { 244 $t_user_id = db_prepare_int( $p_user_id ); 245 } 246 247 # If the user doesn't have access rights to stored queries, just return 248 if( !access_has_project_level( config_get( 'stored_query_use_threshold' ) ) ) { 249 return $t_overall_query_arr; 250 } 251 252 # Get the list of available queries. By sorting such that public queries are 253 # first, we can override any query that has the same name as a private query 254 # with that private one 255 $query = "SELECT * FROM $t_filters_table 256 WHERE (project_id='$t_project_id' 257 OR project_id='0') 258 AND name!='' 259 ORDER BY is_public DESC, name ASC"; 260 $result = db_query( $query ); 261 $query_count = db_num_rows( $result ); 262 263 for( $i = 0;$i < $query_count;$i++ ) { 264 $row = db_fetch_array( $result ); 265 if(( $row['user_id'] == $t_user_id ) || db_prepare_bool( $row['is_public'] ) ) { 266 267 $t_filter_detail = explode( '#', $row['filter_string'], 2 ); 268 if ( !isset($t_filter_detail[1]) ) { 269 continue; 270 } 271 $t_filter = unserialize( $t_filter_detail[1] ); 272 $t_filter = filter_ensure_valid_filter( $t_filter ); 273 $row['url'] = filter_get_url( $t_filter ); 274 $t_overall_query_arr[$row['name']] = $row; 275 } 276 } 277 278 return array_values( $t_overall_query_arr ); 279 } 280 281 /** 282 * Get a category definition. 283 * 284 * @param integer $p_category_id The id of the category to retrieve. 285 * @return Array an Array containing the id and the name of the category. 286 */ 287 function mci_category_as_array_by_id( $p_category_id ) { 288 $t_result = array(); 289 $t_result['id'] = $p_category_id; 290 $t_result['name'] = category_get_name( $p_category_id ); 291 return $t_result; 292 } 293 294 /** 295 * Transforms a version array into an array suitable for marshalling into ProjectVersionData 296 * 297 * @param array $p_version 298 */ 299 function mci_project_version_as_array( $p_version ) { 300 301 return array( 302 'id' => $p_version['id'], 303 'name' => $p_version['version'], 304 'project_id' => $p_version['project_id'], 305 'date_order' => timestamp_to_iso8601( $p_version['date_order'] ), 306 'description' => mci_null_if_empty( $p_version['description'] ), 307 'released' => $p_version['released'], 308 'obsolete' => $p_version['obsolete'] 309 ); 310 } 311 312 /** 313 * Returns time tracking information from a bug note. 314 * 315 * @param int $p_issue_id The id of the issue 316 * @param Array $p_note A note as passed to the soap api methods 317 * 318 * @return String the string time entry to be added to the bugnote, in 'HH:mm' format 319 */ 320 function mci_get_time_tracking_from_note( $p_issue_id, $p_note) { 321 322 if ( !access_has_bug_level( config_get( 'time_tracking_view_threshold' ), $p_issue_id ) ) 323 return '00:00'; 324 325 if ( !isset( $p_note['time_tracking'] )) 326 return '00:00'; 327 328 return db_minutes_to_hhmm($p_note['time_tracking']); 329 } 330 331 /** 332 * SECURITY NOTE: these globals are initialized here to prevent them 333 * being spoofed if register_globals is turned on 334 */ 335 $g_error_parameters = array(); 336 $g_error_handled = false; 337 $g_error_proceed_url = null; 338 339 # Default error handler 340 # 341 # This handler will not receive E_ERROR, E_PARSE, E_CORE_*, or E_COMPILE_* 342 # errors. 343 # 344 # E_USER_* are triggered by us and will contain an error constant in $p_error 345 # The others, being system errors, will come with a string in $p_error 346 # 347 function mc_error_handler( $p_type, $p_error, $p_file, $p_line, $p_context ) { 348 global $g_error_parameters, $g_error_handled, $g_error_proceed_url; 349 global $g_lang_overrides; 350 global $g_error_send_page_header; 351 global $l_oServer; 352 353 # check if errors were disabled with @ somewhere in this call chain 354 # also suppress php 5 strict warnings 355 if( 0 == error_reporting() || 2048 == $p_type ) { 356 return; 357 } 358 359 $t_lang_pushed = false; 360 361 # flush any language overrides to return to user's natural default 362 if( function_exists( 'db_is_connected' ) ) { 363 if( db_is_connected() ) { 364 lang_push( lang_get_default() ); 365 $t_lang_pushed = true; 366 } 367 } 368 369 $t_short_file = basename( $p_file ); 370 $t_method_array = config_get( 'display_errors' ); 371 if( isset( $t_method_array[$p_type] ) ) { 372 $t_method = $t_method_array[$p_type]; 373 } else { 374 $t_method = 'none'; 375 } 376 377 # build an appropriate error string 378 switch( $p_type ) { 379 case E_WARNING: 380 $t_error_type = 'SYSTEM WARNING'; 381 $t_error_description = $p_error; 382 break; 383 case E_NOTICE: 384 $t_error_type = 'SYSTEM NOTICE'; 385 $t_error_description = $p_error; 386 break; 387 case E_USER_ERROR: 388 $t_error_type = "APPLICATION ERROR #$p_error"; 389 $t_error_description = error_string( $p_error ); 390 break; 391 case E_USER_WARNING: 392 $t_error_type = "APPLICATION WARNING #$p_error"; 393 $t_error_description = error_string( $p_error ); 394 break; 395 case E_USER_NOTICE: 396 397 # used for debugging 398 $t_error_type = 'DEBUG'; 399 $t_error_description = $p_error; 400 break; 401 default: 402 403 #shouldn't happen, just display the error just in case 404 $t_error_type = ''; 405 $t_error_description = $p_error; 406 } 407 408 $t_error_description = $t_error_description; 409 $t_error_stack = error_get_stack_trace(); 410 411 $l_oServer->fault( 'Server', "Error Type: $t_error_type,\nError Description:\n$t_error_description,\nStack Trace:\n$t_error_stack" ); 412 $l_oServer->send_response(); 413 exit(); 414 } 415 416 # Get a stack trace if PHP provides the facility or xdebug is present 417 function error_get_stack_trace() { 418 $t_trace = ''; 419 420 if ( extension_loaded( 'xdebug' ) ) { 421 422 #check for xdebug presence 423 $t_stack = xdebug_get_function_stack(); 424 425 # reverse the array in a separate line of code so the 426 # array_reverse() call doesn't appear in the stack 427 $t_stack = array_reverse( $t_stack ); 428 array_shift( $t_stack ); 429 430 #remove the call to this function from the stack trace 431 foreach( $t_stack as $t_frame ) { 432 $t_trace .= ( isset( $t_frame['file'] ) ? basename( $t_frame['file'] ) : 'UnknownFile' ) . ' L' . ( isset( $t_frame['line'] ) ? $t_frame['line'] : '?' ) . ' ' . ( isset( $t_frame['function'] ) ? $t_frame['function'] : 'UnknownFunction' ); 433 434 $t_args = array(); 435 if ( isset( $t_frame['params'] ) && ( count( $t_frame['params'] ) > 0 ) ) { 436 $t_trace .= ' Params: '; 437 foreach( $t_frame['params'] as $t_value ) { 438 $t_args[] = error_build_parameter_string( $t_value ); 439 } 440 441 $t_trace .= '(' . implode( $t_args, ', ' ) . ')'; 442 } else { 443 $t_trace .= '()'; 444 } 445 446 $t_trace .= "\n"; 447 } 448 } else { 449 $t_stack = debug_backtrace(); 450 451 array_shift( $t_stack ); #remove the call to this function from the stack trace 452 array_shift( $t_stack ); #remove the call to the error handler from the stack trace 453 454 foreach( $t_stack as $t_frame ) { 455 $t_trace .= ( isset( $t_frame['file'] ) ? basename( $t_frame['file'] ) : 'UnknownFile' ) . ' L' . ( isset( $t_frame['line'] ) ? $t_frame['line'] : '?' ) . ' ' . ( isset( $t_frame['function'] ) ? $t_frame['function'] : 'UnknownFunction' ); 456 457 $t_args = array(); 458 if( isset( $t_frame['args'] ) ) { 459 foreach( $t_frame['args'] as $t_value ) { 460 $t_args[] = error_build_parameter_string( $t_value ); 461 } 462 463 $t_trace .= '(' . implode( $t_args, ', ' ) . ')'; 464 } else { 465 $t_trace .= '()'; 466 } 467 468 $t_trace .= "\n"; 469 } 470 } 471 472 return $t_trace; 473 } 474 475 /** 476 * Returns a soap_fault signalling corresponding to a failed login 477 * situation 478 * 479 * @return soap_fault 480 */ 481 function mci_soap_fault_login_failed() { 482 return new soap_fault('Client', '', 'Access denied.'); 483 } 484 485 /** 486 * Returns a soap_fault signalling that the user does not have 487 * access rights for the specific action. 488 * 489 * @param int $p_user_id a valid user id 490 * @param string $p_detail The optional details to append to the error message 491 * @return soap_fault 492 */ 493 function mci_soap_fault_access_denied( $p_user_id, $p_detail = '' ) { 494 $t_user_name = user_get_name( $p_user_id ); 495 $t_reason = 'Access denied for user '. $t_user_name . '.'; 496 if ( !is_blank( $p_detail )) 497 $t_reason .= ' Reason: ' . $p_detail . '.'; 498 499 return new soap_fault( 'Client', '', $t_reason ); 500 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Jul 28 15:48:31 2011 | Cross-referenced by PHPXref 0.7 |