wavelog/application/libraries/Paths.php

210 lines
8.5 KiB
PHP
Raw Permalink Normal View History

2024-02-02 14:57:27 +01:00
<?php defined('BASEPATH') or exit('No direct script access allowed');
/***
2024-02-24 10:26:17 +01:00
* Paths Library to return specific paths
2024-02-02 14:57:27 +01:00
*/
class Paths {
/**
* Returns the userdata path (or legacy path if the userdata option is not set) for the given type and user_id.
*
* @param string $type The type of path to return (e.g. 'eqsl_card', 'qsl_card')
* @param string $pathorurl 'u' to return the web-relative path, 'p' to return the absolute filesystem path, 'b' to return the base user directory path (without the type subdirectory)
* @param int|null $user_id The user_id to return the path for. If null, will use the user_id from session data
*/
function getUserdataPath($type, $pathorurl = 'u', $user_id = null) {
// test if new folder directory option is enabled
2024-02-02 14:57:27 +01:00
$CI = &get_instance();
$userdata_dir = $CI->config->item('userdata');
// make sure these are the same as in Debug_model.php function migrate_userdata()
$allowed_types = [
'basedir', // special type to return the base user directory without the type subdirectory
2026-06-14 13:56:09 +02:00
'eqsl_card',
'qsl_card',
'qslpostcard_images' // has no legacy path
];
// validate path type
if (!in_array($pathorurl, ['u', 'p', 'b'])) {
log_message('error', 'Invalid pathorurl passed to getUserdataPath: ' . $pathorurl);
return false; // invalid pathorurl
}
if (!in_array($type, $allowed_types)) {
log_message('error', 'Invalid type passed to getUserdataPath: ' . $type);
return false; // invalid type
}
if (isset($userdata_dir)) {
if (!valid_uid($user_id)) {
$user_id = $CI->session->userdata('user_id');
}
// check if there is a user_id in the session data and it's not empty
if (valid_uid($user_id)) {
// create the folder (not for 'basedir', which is the user's base directory itself)
if ($type != 'basedir' && !file_exists(realpath(APPPATH . '../') . '/' . $userdata_dir . '/' . $user_id . '/' . $type)) {
mkdir(realpath(APPPATH . '../') . '/' . $userdata_dir . '/' . $user_id . '/' . $type, 0755, true);
}
// and return it
if ($pathorurl == 'u') {
return $userdata_dir . '/' . $user_id . '/' . $type;
} else if ($pathorurl == 'p' && $type != 'basedir') {
return realpath(APPPATH . '../') . '/' . $userdata_dir . '/' . $user_id . '/' . $type;
} else if ($pathorurl == 'b' && $type == 'basedir') {
return realpath(APPPATH . '../') . '/' . $userdata_dir . '/' . $user_id;
}
} else {
2026-06-12 10:05:36 +02:00
log_message('info', 'getUserdataPath(); Can not get ' . $type . ' path because no user_id in session data');
}
} else {
// if the config option is not set we just return the old path
return $this->legacyPaths($type, $pathorurl);
}
2024-02-02 14:57:27 +01:00
}
2026-06-12 10:39:42 +02:00
/**
* @deprecated Use getUserdataPath('eqsl_card') instead.
* Kept as a fallback for the brief window during a git update where an
* older view might still call this method before it gets removed.
*/
function getPathEqsl($pathorurl = 'u', $user_id = null) {
return $this->getUserdataPath('eqsl_card', $pathorurl, $user_id);
}
/**
* @deprecated Use getUserdataPath('qsl_card') instead.
* Kept as a fallback for the brief window during a git update where an
* older view might still call this method before it gets removed.
*/
function getPathQsl($pathorurl = 'u', $user_id = null) {
return $this->getUserdataPath('qsl_card', $pathorurl, $user_id);
}
private function legacyPaths($type, $pathorurl = 'u') {
switch ($type) {
case 'eqsl_card':
$path = 'images/eqsl_card_images';
break;
case 'qsl_card':
$path = 'assets/qslcard';
break;
default:
log_message('error', 'Invalid type passed to legacyPaths(): ' . $type);
return false;
}
// 'u' returns the web-relative path, anything else the absolute filesystem path
if ($pathorurl == 'u') {
return $path;
} else {
return realpath(APPPATH . '../') . '/' . $path;
}
2024-02-02 14:57:27 +01:00
}
function delete_user_files($user_id) {
$CI = & get_instance();
if (!valid_uid($user_id)) {
log_message('error', 'delete_user_files() called with invalid user_id: ' . $user_id);
return false;
}
$userdata_dir = $CI->config->item('userdata');
if (isset($userdata_dir)) {
$base_path = $this->getUserdataPath('basedir', 'b', $user_id); // get the base path for the user
if (file_exists($base_path)) {
2026-06-15 04:25:23 +00:00
if (!$this->_delete_directory($base_path)) {
log_message('error', 'delete_user_files(); Failed to fully delete user files for user_id: ' . $user_id);
return false;
}
log_message('debug', 'delete_user_files(); Deleted user files for user_id: ' . $user_id);
} else {
log_message('debug', 'delete_user_files(); No user files to delete for user_id: ' . $user_id);
}
} else {
log_message('debug', 'delete_user_files(); No userdata directory configured, so no user files to delete for user_id: ' . $user_id);
}
return true;
}
private function _delete_directory($dir) {
if (!file_exists($dir)) {
return true;
}
if (!is_dir($dir)) {
return unlink($dir);
}
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') {
continue;
}
if (!$this->_delete_directory($dir . DIRECTORY_SEPARATOR . $item)) {
return false;
}
}
return rmdir($dir);
}
function make_update_path($path) {
$CI = & get_instance();
$path = "updates/" . $path;
$datadir = $CI->config->item('datadir');
if(!$datadir) {
return $path;
}
return $datadir . "/" . $path;
}
2024-12-10 15:12:33 +01:00
2026-03-16 09:37:02 +00:00
/**
* Generate a CSRF token, store it in the session under $key, and return it
* for injection into view data.
*/
function csrf_generate($key) {
$CI = &get_instance();
$token = bin2hex(random_bytes(32));
$CI->session->set_userdata($key, $token);
return $token;
}
/**
* Verify the submitted csrf_token POST field against the session value for
* $key. Rotates the token on success. Returns true on success, false on failure.
*/
function csrf_verify($key) {
$CI = &get_instance();
$submitted = $CI->input->post('csrf_token', TRUE);
$stored = $CI->session->userdata($key);
if (empty($submitted) || empty($stored) || !hash_equals($stored, $submitted)) {
return false;
}
$CI->session->set_userdata($key, bin2hex(random_bytes(32)));
return true;
}
2024-12-10 15:12:33 +01:00
function cache_buster($filepath) {
// make sure $filepath starts with a slash
if (substr($filepath, 0, 1) !== '/') $filepath = '/' . $filepath;
$CI = & get_instance();
$fullpath = empty($CI->config->item('directory')) ? $_SERVER['DOCUMENT_ROOT'] . $filepath : $_SERVER['DOCUMENT_ROOT'] . '/' . $CI->config->item('directory') . $filepath;
// We comment out this line because latest teste at LA8AJA's XAMPP setup showed that it works even without it
// So we will keep it simple and just use the $filepath as is, since it seems to work fine on both Linux and Windows setups
// $fullpath = rtrim($_SERVER['DOCUMENT_ROOT'], '/\\') . str_replace('/', DIRECTORY_SEPARATOR, $filepath);
2026-07-07 16:33:32 +02:00
// $filepath is always a hard-coded, app-relative asset path from callers
// (never user input), so $fullpath is not attacker-controlled.
if (file_exists($fullpath)) { // nosemgrep: php.lang.security.injection.tainted-filename.tainted-filename
return base_url($filepath) . '?v=' . filemtime($fullpath); // nosemgrep: php.lang.security.injection.tainted-filename.tainted-filename
} else {
log_message('error', 'CACHE BUSTER: File does not exist: ' . $fullpath);
2024-12-10 15:12:33 +01:00
}
return base_url($filepath);
}
2024-02-02 14:57:27 +01:00
}