xoops_setcookie()   F
last analyzed

Complexity

Conditions 15
Paths 289

Size

Total Lines 64
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 32
c 0
b 0
f 0
nc 289
nop 8
dl 0
loc 64
rs 3.9708

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits of supporting
4
 developers from this source code or any supporting source code which is considered
5
 copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 */
11
12
/**
13
 * Safe, modern cookie setter with RFC 6265 domain validation and SameSite support.
14
 *
15
 * This function replaces the legacy func_get_args() version with an explicit
16
 * signature, making it more robust and easier for static analysis to validate.
17
 *
18
 * @copyright       Copyright 2021-2025 The XOOPS Project https://xoops.org
19
 * @license         GNU GPL 2.0 or later (https://www.gnu.org/licenses/gpl-2.0.html)
20
 * @author          Richard Griffith <[email protected]>
21
 *
22
 * @param string $name The name of the cookie.
23
 * @param string|null $value The value of the cookie.
24
 * @param int $expire The time the cookie expires. This is a Unix timestamp.
25
 * @param string $path The path on the server in which the cookie will be available on.
26
 * @param string $domain The (sub)domain that the cookie is available to.
27
 * @param bool|null $secure Indicates that the cookie should only be transmitted over a secure HTTPS connection.
28
 * If null, it will be auto-detected.
29
 * @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol.
30
 * @param string $samesite The SameSite attribute ('Lax', 'Strict', 'None').
31
 * @return bool True on success, false on failure.
32
 */
33
function xoops_setcookie(
34
    string $name,
35
    ?string $value = '',
36
    int $expire = 0,
37
    string $path = '/',
38
    string $domain = '',
39
    ?bool $secure = null,
40
    bool $httponly = true,
41
    string $samesite = 'Lax'
42
): bool {
43
    if (headers_sent()) {
44
        return false;
45
    }
46
47
    // Convert null values to empty string for compatibility with setcookie.
48
    $value = $value ?? '';
49
    $host = parse_url(XOOPS_URL, PHP_URL_HOST);
50
    if (!is_string($host)) {
0 ignored issues
show
introduced by
The condition is_string($host) is always true.
Loading history...
51
        $host = ''; // Fallback for invalid XOOPS_URL
52
    }
53
54
    // Validate the domain BEFORE using it.
55
    if (class_exists('\Xoops\RegDom\RegisteredDomain')) {
56
        if (!\Xoops\RegDom\RegisteredDomain::domainMatches($host, $domain)) {
57
            $originalDomain = $domain;
58
            $domain = ''; // Auto-correct to a safe, host-only cookie
59
60
            if (defined('XOOPS_DEBUG_MODE') && XOOPS_DEBUG_MODE) {
0 ignored issues
show
Bug introduced by
The constant XOOPS_DEBUG_MODE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
61
                error_log(
62
                    sprintf(
63
                        '[XOOPS Cookie] Invalid domain "%s" for host "%s" (cookie: %s) - using host-only.',
64
                        $originalDomain,
65
                        $host,
66
                        $name
67
                    )
68
                );
69
            }
70
        }
71
    }
72
73
    // Auto-detect 'secure' flag if not explicitly set
74
    if ($secure === null) {
75
        $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
76
            || (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)
77
            || (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
78
    }
79
80
    // Use modern array syntax for PHP 7.3+
81
    if (PHP_VERSION_ID >= 70300) {
82
        $options = [
83
            'expires'  => $expire,
84
            'path'     => $path,
85
            'secure'   => $secure,
86
            'httponly' => $httponly,
87
            'samesite' => $samesite,
88
        ];
89
        if ($domain !== '') {
90
            $options['domain'] = $domain;
91
        }
92
        return setcookie($name, $value, $options);
93
    }
94
95
    // Fallback for older PHP versions
96
    return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
97
}
98
99
/**
100
 * @param array $args 'name', 'value' and 'options' corresponding to php 7.3 arguments to setcookie()
101
 *
102
 * @return string
103
 */
104
function xoops_buildCookieHeader($args)
105
{
106
    //$optionsKeys = array('expires', 'path', 'domain', 'secure', 'httponly', 'samesite');
107
    $options = $args['options'];
108
109
    $header = 'Set-Cookie: ' . $args['name'] . '=' . rawurlencode($args['value']) . ' ';
110
111
    if (isset($options['expires']) && 0 !== $options['expires']) {
112
        $dateTime = new DateTime();
113
        if (time() >= $options['expires']) {
114
            $dateTime->setTimestamp(0);
115
            $header = 'Set-Cookie: ' . $args['name'] . '=deleted ; expires=' . $dateTime->format(DateTime::COOKIE) . ' ; Max-Age=0 ';
116
        } else {
117
            $dateTime->setTimestamp($options['expires']);
118
            $header .= '; expires=' . $dateTime->format(DateTime::COOKIE) . ' ';
119
        }
120
    }
121
122
    if (isset($options['path']) && '' !== $options['path']) {
123
        $header .= '; path=' . $options['path'] . ' ';
124
    }
125
126
    if (isset($options['domain']) && '' !== $options['domain']) {
127
        $header .= '; domain=' . $options['domain'] . ' ';
128
    }
129
130
    if (isset($options['secure']) && true === (bool) $options['secure']) {
131
        $header .= '; Secure ';
132
    }
133
134
    if (isset($options['httponly']) && true === (bool) $options['httponly']) {
135
        $header .= '; HttpOnly ';
136
    }
137
138
    if (isset($options['samesite']) && '' !== $options['samesite']) {
139
        $header .= '; samesite=' . $options['samesite'] . ' ';
140
    }
141
142
    return $header;
143
}
144