1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
//! ref: composer/src/Composer/Util/ErrorHandler.php
use crate::io::io_interface::IOInterface;
use shirabe_php_shim::{
E_ALL, E_DEPRECATED, E_USER_DEPRECATED, E_USER_WARNING, E_WARNING, ErrorException,
FILTER_VALIDATE_BOOLEAN, PHP_EOL, PhpMixed, STDERR, debug_backtrace, error_reporting,
filter_var, ini_get, is_resource, set_error_handler,
};
use std::sync::{Mutex, OnceLock};
static IO: OnceLock<Mutex<Option<Box<dyn IOInterface + Send>>>> = OnceLock::new();
static HAS_SHOWN_DEPRECATION_NOTICE: Mutex<i64> = Mutex::new(0);
fn io() -> &'static Mutex<Option<Box<dyn IOInterface + Send>>> {
IO.get_or_init(|| Mutex::new(None))
}
pub struct ErrorHandler;
impl ErrorHandler {
pub fn handle(
level: i64,
message: String,
file: String,
line: i64,
) -> Result<bool, ErrorException> {
let is_deprecation_notice = level == E_DEPRECATED || level == E_USER_DEPRECATED;
// error code is not included in error_reporting
if !is_deprecation_notice && 0 == (error_reporting(None) & level) {
return Ok(true);
}
let mut message = message;
let xdebug_scream = ini_get("xdebug.scream").unwrap_or_default();
if filter_var(&xdebug_scream, FILTER_VALIDATE_BOOLEAN) {
message += "\n\nWarning: You have xdebug.scream enabled, the warning above may be\na legitimately suppressed error that you were not supposed to see.";
}
if !is_deprecation_notice {
// ignore some newly introduced warnings in new php versions until dependencies
// can be fixed as we do not want to abort execution for those
if (level == E_WARNING || level == E_USER_WARNING)
&& message.contains(
"should either be used or intentionally ignored by casting it as (void)",
)
{
Self::output_warning(
&format!(
"Ignored new PHP warning but it should be reported and fixed: {} in {}:{}",
message, file, line
),
true,
);
return Ok(true);
}
return Err(ErrorException {
message,
code: 0,
severity: level,
filename: file,
lineno: line,
});
}
let mut io_guard = io().lock().unwrap();
if io_guard.is_some() {
let has_shown = *HAS_SHOWN_DEPRECATION_NOTICE.lock().unwrap();
if has_shown > 0 && !io_guard.as_ref().unwrap().is_verbose() {
if has_shown == 1 {
io_guard.as_mut().unwrap().write_error("<warning>More deprecation notices were hidden, run again with `-v` to show them.</warning>");
*HAS_SHOWN_DEPRECATION_NOTICE.lock().unwrap() = 2;
}
return Ok(true);
}
*HAS_SHOWN_DEPRECATION_NOTICE.lock().unwrap() = 1;
drop(io_guard);
Self::output_warning(
&format!("Deprecation Notice: {} in {}:{}", message, file, line),
false,
);
}
Ok(true)
}
pub fn register(io: Option<Box<dyn IOInterface + Send>>) {
set_error_handler(|level, message, file, line| {
Self::handle(level, message.to_string(), file.to_string(), line).unwrap_or(true)
});
error_reporting(Some(E_ALL));
*self::io().lock().unwrap() = io;
}
fn output_warning(message: &str, output_even_without_io: bool) {
let mut io_guard = io().lock().unwrap();
if let Some(io) = io_guard.as_mut() {
io.write_error(&format!("<warning>{}</warning>", message));
if io.is_verbose() {
io.write_error("<warning>Stack trace:</warning>");
let frames: Vec<String> = debug_backtrace()
.into_iter()
.skip(2)
.filter_map(|frame| {
let line = frame.get("line").and_then(|v| v.as_int());
let file = frame
.get("file")
.and_then(|v| v.as_string())
.map(|s| s.to_string());
if let (Some(line), Some(file)) = (line, file) {
Some(format!("<warning> {}:{}</warning>", file, line))
} else {
None
}
})
.collect();
for frame_str in frames {
io.write_error(&frame_str);
}
}
return;
}
drop(io_guard);
if output_even_without_io {
if is_resource(&PhpMixed::Int(STDERR)) {
shirabe_php_shim::fwrite(
PhpMixed::Int(STDERR),
&format!("Warning: {}{}", message, PHP_EOL),
-1,
);
} else {
print!("Warning: {}{}", message, PHP_EOL);
}
}
}
}
|