55 public function header( $string, $replace =
true, $http_response_code =
null ) {
57 LoggerFactory::getInstance(
'header' )->warning(
'ignored post-send header {header}', [
59 'replace' => $replace,
60 'http_response_code' => $http_response_code,
61 'exception' =>
new RuntimeException(
'Ignored post-send header' ),
66 \MediaWiki\Request\HeaderCallback::warnIfHeadersSent();
67 if ( $http_response_code ) {
68 header( $string, $replace, $http_response_code );
70 header( $string, $replace );
145 public function setCookie( $name, $value, $expire = 0, $options = [] ) {
146 $logger = LoggerFactory::getInstance(
'cookie' );
148 $mainConfig = $services->getMainConfig();
155 $options = array_filter( $options,
static fn ( $a ) => $a !==
null ) + [
156 'prefix' => $cookiePrefix,
157 'domain' => $cookieDomain,
158 'path' => $cookiePath,
159 'secure' => $cookieSecure,
160 'httpOnly' => $cookieHttpOnly,
165 if ( $expire ===
null ) {
167 } elseif ( $expire == 0 && $cookieExpiration != 0 ) {
168 $expire = ConvertibleTimestamp::time() + $cookieExpiration;
172 $prefixedName = $options[
'prefix'] . $name;
173 $logger->warning(
'ignored post-send cookie {cookie}', [
174 'cookie' => $prefixedName,
176 'name' => $prefixedName,
177 'value' => (
string)$value,
178 'expire' => (
int)$expire,
179 'path' => (
string)$options[
'path'],
180 'domain' => (
string)$options[
'domain'],
181 'secure' => (
bool)$options[
'secure'],
182 'httpOnly' => (
bool)$options[
'httpOnly'],
183 'sameSite' => (
string)$options[
'sameSite']
185 'exception' =>
new RuntimeException(
'Ignored post-send cookie' ),
190 $hookRunner =
new HookRunner( $services->getHookContainer() );
191 if ( !$hookRunner->onWebResponseSetCookie( $name, $value, $expire, $options ) ) {
197 $prefixedName = $options[
'prefix'] . $name;
198 $value = (string)$value;
199 $func = $options[
'raw'] ?
'setrawcookie' :
'setcookie';
201 'expires' => (int)$expire,
202 'path' => (
string)$options[
'path'],
203 'domain' => (string)$options[
'domain'],
204 'secure' => (
bool)$options[
'secure'],
205 'httponly' => (bool)$options[
'httpOnly'],
206 'samesite' => (
string)$options[
'sameSite'],
210 $key =
"{$prefixedName}\n{$setOptions['domain']}\n{$setOptions['path']}";
214 if ( isset( $_COOKIE[$prefixedName] ) && !array_key_exists( $key, self::$setCookies ) ) {
215 self::$setCookies[$key] = [];
219 $deleting = ( $value ===
''
220 || ( $setOptions[
'expires'] > 0
221 && $setOptions[
'expires'] <= ConvertibleTimestamp::time()
225 $logDesc =
"$func: \"$prefixedName\", \"$value\", \"" .
226 implode(
'", "', array_map(
'strval', $setOptions ) ) .
'"';
227 $optionsForDeduplication = [ $func, $prefixedName, $value, $setOptions ];
229 if ( $deleting && !isset( self::$setCookies[$key] ) ) {
230 $logger->debug(
"already deleted $logDesc" );
232 } elseif ( !$deleting && isset( self::$setCookies[$key] ) &&
233 self::$setCookies[$key] === $optionsForDeduplication
235 $logger->debug(
"already set $logDesc" );
239 $logger->info( $logDesc );
241 self::$setCookies[$key] = $deleting ? null : $optionsForDeduplication;
267 protected function actuallySetCookie(
string $func,
string $prefixedName,
string $value, array $setOptions ): void {
268 if ( $func ===
'setrawcookie' ) {
269 setrawcookie( $prefixedName, $value, $setOptions );
271 setcookie( $prefixedName, $value, $setOptions );