Issues (2882)

src/includes/constants.php (1 issue)

Labels
Severity
1
<?php
2
3
use SilverStripe\Core\Convert;
4
use SilverStripe\Core\Environment;
5
use SilverStripe\Core\EnvironmentLoader;
6
use SilverStripe\Core\TempFolder;
7
8
/**
9
 * This file is the Framework constants bootstrap. It will prepare some basic common constants.
10
 *
11
 * It takes care of:
12
 *  - Initialisation of necessary constants (mostly paths)
13
 *
14
 * Initialized constants:
15
 * - BASE_URL: Full URL to the webroot, e.g. "http://my-host.com/my-webroot" (no trailing slash).
16
 * - BASE_PATH: Absolute path to the webroot, e.g. "/var/www/my-webroot" (no trailing slash).
17
 *   See Director::baseFolder(). Can be overwritten by
18
 *   Config::modify()->set(Director::class, 'alternate_base_folder', ).
19
 * - TEMP_PATH: Absolute path to temporary folder, used for manifest and template caches. Example: "/var/tmp"
20
 *   See getTempFolder(). No trailing slash.
21
 * - ASSETS_DIR: Dir for assets folder. e.g. "assets"
22
 * - ASSETS_PATH: Full path to assets folder. e.g. "/var/www/my-webroot/assets"
23
 * - THEMES_DIR: Path relative to webroot, e.g. "themes"
24
 * - THEMES_PATH: Absolute filepath, e.g. "/var/www/my-webroot/themes"
25
 * - FRAMEWORK_DIR: Path relative to webroot, e.g. "framework"
26
 * - FRAMEWORK_PATH:Absolute filepath, e.g. "/var/www/my-webroot/framework"
27
 * - PUBLIC_DIR: Webroot path relative to project root, e.g. "public" or ""
28
 * - PUBLIC_PATH: Absolute path to webroot, e.g. "/var/www/project/public"
29
 * - THIRDPARTY_DIR: Path relative to webroot, e.g. "framework/thirdparty"
30
 * - THIRDPARTY_PATH: Absolute filepath, e.g. "/var/www/my-webroot/framework/thirdparty"
31
 * - RESOURCES_DIR: Name of the directory where vendor assets will be exposed, e.g. "_ressources"
32
 */
33
34
require_once __DIR__ . '/functions.php';
35
36
///////////////////////////////////////////////////////////////////////////////
37
// ENVIRONMENT CONFIG
38
39
/**
40
 * Define system paths
41
 */
42
if (!defined('BASE_PATH')) {
43
    define('BASE_PATH', call_user_func(function () {
44
        // Determine BASE_PATH based on the composer autoloader
45
        foreach (debug_backtrace() as $backtraceItem) {
46
            if (!isset($backtraceItem['file'])) {
47
                continue;
48
            }
49
50
            $matched = preg_match(
51
                '#^(?<base>.*)(/|\\\\)vendor(/|\\\\)composer(/|\\\\)autoload_real.php#',
52
                $backtraceItem['file'],
53
                $matches
54
            );
55
56
            if ($matched) {
57
                return realpath($matches['base']) ?: DIRECTORY_SEPARATOR;
58
            }
59
        }
60
61
        // Determine BASE_PATH by assuming that this file is framework/src/Core/Constants.php
62
        //  we can then determine the base path
63
        $candidateBasePath = rtrim(dirname(dirname(dirname(__DIR__))), DIRECTORY_SEPARATOR);
64
        // We can't have an empty BASE_PATH.  Making it / means that double-slashes occur in places but that's benign.
65
        // This likely only happens on chrooted environemnts
66
        return $candidateBasePath ?: DIRECTORY_SEPARATOR;
67
    }));
68
}
69
70
// Set public webroot dir / path
71
if (!defined('PUBLIC_DIR')) {
72
    define('PUBLIC_DIR', is_dir(BASE_PATH . DIRECTORY_SEPARATOR . 'public') ? 'public' : '');
73
}
74
if (!defined('PUBLIC_PATH')) {
75
    define('PUBLIC_PATH', PUBLIC_DIR ? BASE_PATH . DIRECTORY_SEPARATOR . PUBLIC_DIR : BASE_PATH);
76
}
77
78
// Allow a first class env var to be set that disables .env file loading
79
if (!Environment::getEnv('SS_IGNORE_DOT_ENV')) {
80
    call_user_func(function () {
81
        $loader = new EnvironmentLoader();
82
        foreach ([BASE_PATH, dirname(BASE_PATH)] as $path) {
83
            // Stop searching after first `.env` file is loaded
84
            $dotEnvFile = $path . DIRECTORY_SEPARATOR . '.env';
85
            if ($loader->loadFile($dotEnvFile)) {
86
                break;
87
            }
88
        }
89
    });
90
}
91
92
// Validate SS_BASE_URL is absolute
93
if (Environment::getEnv('SS_BASE_URL') && !preg_match('#^(\w+:)?//.*#', Environment::getEnv('SS_BASE_URL'))) {
94
    call_user_func(function () {
95
        $base = Environment::getEnv('SS_BASE_URL');
96
        user_error(
97
            "SS_BASE_URL should be an absolute url with protocol "
98
            . "(http://$base) or without protocol (//$base)",
99
            E_USER_WARNING
100
        );
101
        // Treat as protocol-less absolute url
102
        $base = '//' . $base;
103
        Environment::setEnv('SS_BASE_URL', $base);
104
    });
105
}
106
107
if (!defined('BASE_URL')) {
108
    define('BASE_URL', call_user_func(function () {
109
        // Prefer explicitly provided SS_BASE_URL
110
        $base = Environment::getEnv('SS_BASE_URL');
111
        if ($base) {
112
            // Strip relative path from SS_BASE_URL
113
            return rtrim(parse_url($base, PHP_URL_PATH), '/');
114
        }
115
116
        // Unless specified, use empty string for base in CLI
117
        if (in_array(php_sapi_name(), ['cli', 'phpdbg'])) {
118
            return '';
119
        }
120
121
        // Determine the base URL by comparing SCRIPT_NAME to SCRIPT_FILENAME and getting common elements
122
        // This tends not to work on CLI
123
        $path = Convert::slashes($_SERVER['SCRIPT_FILENAME']);
124
        $scriptName = Convert::slashes($_SERVER['SCRIPT_NAME'], '/');
125
126
        // Ensure script is served from public folder (otherwise error)
127
        if (stripos($path, PUBLIC_PATH) !== 0) {
128
            return '';
129
        }
130
131
        // Get entire url following PUBLIC_PATH
132
        $urlSegmentToRemove = Convert::slashes(substr($path, strlen(PUBLIC_PATH)), '/');
133
        if (substr($scriptName, -strlen($urlSegmentToRemove)) !== $urlSegmentToRemove) {
134
            return '';
135
        }
136
137
        // Remove this from end of SCRIPT_NAME to get url to base
138
        $baseURL = substr($scriptName, 0, -strlen($urlSegmentToRemove));
139
        $baseURL = rtrim(ltrim($baseURL, '.'), '/');
140
141
        // When htaccess redirects from /base to /base/public folder, we need to only include /public
142
        // in the BASE_URL if it's also present in the request
143
        if (!$baseURL
144
            || !PUBLIC_DIR
145
            || !isset($_SERVER['REQUEST_URI'])
146
            || substr($baseURL, -strlen(PUBLIC_DIR)) !== PUBLIC_DIR
147
        ) {
148
            return $baseURL;
149
        }
150
151
        $requestURI = $_SERVER['REQUEST_URI'];
152
        // Check if /base/public or /base are in the request
153
        foreach ([$baseURL, dirname($baseURL)] as $candidate) {
154
            if (stripos($requestURI, $candidate) === 0) {
155
                return $candidate;
156
            }
157
        }
158
159
        // Ambiguous
160
        return '';
161
    }));
162
}
163
164
define('THEMES_DIR', 'themes');
165
define('THEMES_PATH', BASE_PATH . DIRECTORY_SEPARATOR . THEMES_DIR);
166
167
// Relies on this being in a subdir of the framework.
168
// If it isn't, or is symlinked to a folder with a different name, you must define FRAMEWORK_DIR
169
170
define('FRAMEWORK_PATH', realpath(__DIR__ . '/../../'));
171
if (strpos(FRAMEWORK_PATH, BASE_PATH) !== 0) {
172
    throw new Exception("Path error: FRAMEWORK_PATH " . FRAMEWORK_PATH . " not within BASE_PATH " . BASE_PATH);
173
}
174
define('FRAMEWORK_DIR', trim(substr(FRAMEWORK_PATH, strlen(BASE_PATH)), DIRECTORY_SEPARATOR));
175
define('THIRDPARTY_DIR', FRAMEWORK_DIR ? (FRAMEWORK_DIR . '/thirdparty') : 'thirdparty');
176
define('THIRDPARTY_PATH', FRAMEWORK_PATH . DIRECTORY_SEPARATOR . 'thirdparty');
177
178
if (!defined('ASSETS_DIR')) {
179
    define('ASSETS_DIR', 'assets');
180
}
181
if (!defined('ASSETS_PATH')) {
182
    call_user_func(function () {
183
        $paths = [
184
            BASE_PATH,
185
            (PUBLIC_DIR ? PUBLIC_DIR : null),
186
            ASSETS_DIR
187
        ];
188
        define('ASSETS_PATH', implode(DIRECTORY_SEPARATOR, array_filter($paths)));
189
    });
190
}
191
192
// Custom include path - deprecated
193
if (defined('CUSTOM_INCLUDE_PATH')) {
194
    set_include_path(CUSTOM_INCLUDE_PATH . PATH_SEPARATOR . get_include_path());
0 ignored issues
show
The constant CUSTOM_INCLUDE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
195
}
196
197
// Define the temporary folder if it wasn't defined yet
198
if (!defined('TEMP_PATH')) {
199
    if (defined('TEMP_FOLDER')) {
200
        define('TEMP_PATH', TEMP_FOLDER);
201
    } else {
202
        define('TEMP_PATH', TempFolder::getTempFolder(BASE_PATH));
203
    }
204
}
205
206
// Define the temporary folder for backwards compatibility
207
if (!defined('TEMP_FOLDER')) {
208
    define('TEMP_FOLDER', TEMP_PATH);
209
}
210
211
// Define the Ressource Dir constant that will be use to exposed vendor assets
212
if (!defined('RESOURCES_DIR')) {
213
    $project = new SilverStripe\Core\Manifest\Module(BASE_PATH, BASE_PATH);
214
    $resourcesDir = $project->getResourcesDir() ?: 'resources';
215
    if (preg_match('/^[_\-a-z0-9]+$/i', $resourcesDir)) {
216
        define('RESOURCES_DIR', $resourcesDir);
217
    } else {
218
        throw new LogicException(sprintf(
219
            'Resources dir error: "%s" is not a valid resources directory name. Update the ' .
220
            '`extra.resources-dir` key in your composer.json file',
221
            $resourcesDir
222
        ));
223
    }
224
}
225