我的自定义PHP框架的路由系统无法有效地阻止直接访问“views/”目录中的文件

My custom PHP framework's routing system isn't effectively preventing direct access to files within the 'views/' directory

提问人:Manish Shahi 提问时间:11/17/2023 更新时间:11/17/2023 访问量:30

问:

我正在开发一个自定义的PHP框架来简化我的日常工作,特别是对于较小的Web项目,我觉得使用Laravel有点繁琐。我的路由器类运行良好,但我遇到了一个问题。“views”、“classes”、“models”和“controllers”文件夹中的文件可直接访问。如何防止这种直接访问?此外,我注意到可以通过 URL“https://localhost:8000/.htaccess”查看“.htaccess”文件。关于如何解决这些问题的任何想法?

类/SimpleRouter.php

<?php

namespace router;

class SimpleRouter
{
    private $routes = [];

    public function addRoute($method, $url, $handler)
    {
        // Convert the method to uppercase to standardize
        $method = strtoupper($method);

        // Check if the method is supported
        if (!in_array($method, ['GET', 'POST', 'PUT', 'DELETE'])) {
            throw new \Exception("Unsupported method: $method");
        }

        $this->routes[$method][$url] = $handler;
    }

    public function route($method, $url)
    {
        $url = rtrim($url, '/');
        $urlParts = $url ? explode('/', $url) : [];
        $handled = false;

        if (isset($this->routes[$method][$url])) {
            // Exact match found for the method and URL, call the handler
            $handler = $this->routes[$method][$url];
            $this->callHandler($handler);
            $handled = true;
        } elseif ($method !== 'GET') {
            // If the method is not GET and route not found, attempt matching with parameters
            $handled = $this->matchWithParams($method, $url, $urlParts);
        }

        if (!$handled) {
            // No matching route found or method not supported, invoke the default 404 handler
            $this->defaultRoute();
        }
    }

    private function callHandler($handler, $data = null)
    {
        if (is_callable($handler)) {
            // Callable function, invoke directly
            $handler();
        } elseif (is_string($handler) && strpos($handler, '@') !== false) {
            // Handler is in "Controller@method" format
            list($controllerName, $methodName) = explode('@', $handler, 2);
            $controller = "\\controllers\\$controllerName";

            if (class_exists($controller)) {
                $instance = new $controller();

                if (method_exists($instance, $methodName)) {
                    // Call the controller method and pass data if available
                    if ($data !== null) {
                        $instance->$methodName($data);
                    } else {
                        $instance->$methodName();
                    }
                    return;
                }
            }

            // If the controller/method doesn't exist, invoke the default 404 handler
            $this->defaultRoute();
        } elseif (is_string($handler) && file_exists(__DIR__ . "/../views/{$handler}.php")) {
            // Handler is a view file, include it
            include_once __DIR__ . "/../views/{$handler}.php";
        } else {
            // Invalid handler or file not found, invoke the default 404 handler
            $this->defaultRoute();
        }
    }



    private function matchWithParams($method, $url, $urlParts)
    {
        foreach ($this->routes[$method] as $route => $handler) {
            $route = rtrim($route, '/');
            $routeParts = explode('/', $route);

            if (count($routeParts) === count($urlParts)) {
                $params = [];

                foreach ($routeParts as $key => $part) {
                    if (!empty($part) && $part[0] === '{' && $part[strlen($part) - 1] === '}') {
                        // Extract parameter name and pattern from {param:pattern}
                        preg_match('/{([^:]+)(:([^}]+))?}/', $part, $matches);

                        $paramName = $matches[1];
                        $pattern = isset($matches[3]) ? $matches[3] : null;

                        if ($pattern && !preg_match("/^$pattern$/", $urlParts[$key])) {
                            // Parameter value doesn't match the pattern, break and try the next route
                            break 2;
                        }

                        $params[$paramName] = $urlParts[$key];
                    } elseif ($part !== $urlParts[$key]) {
                        // If parts don't match, break and try the next route
                        break;
                    }
                }

                if (count($params) > 0) {
                    // Match found, call the handler with parameters
                    $this->callHandlerWithParams($handler, $params);
                    return true;
                }
            }
        }

        // No match found for the given URL and parameters
        return false;
    }

    private function callHandlerWithParams($handler, $params)
    {
        if (is_callable($handler)) {
            // Callable function, invoke directly with parameters
            $handler($params);
        } elseif (is_string($handler) && strpos($handler, '@') !== false) {
            // Handler is in "Controller@method" format
            list($controller, $method) = explode('@', $handler, 2);
            if (class_exists($controller) && method_exists($controller, $method)) {
                // Controller and method exist, create instance and invoke method with parameters
                $instance = new $controller();
                $instance->$method($params);
            } else {
                // Controller or method not found, invoke the default 404 handler
                $this->defaultRoute();
            }
        } elseif (is_string($handler) && file_exists("views/{$handler}.php")) {
            // Handler is a view file, include it
            include_once "views/{$handler}.php";
        } else {
            // Invalid handler, invoke the default 404 handler
            $this->defaultRoute();
        }
    }

    private function defaultRoute()
    {
        include('views/errors/404.php');
    }
}

请帮忙。提前致谢!

PHP的

评论

1赞 CBroe 11/17/2023
默认的 Apache 配置中,对任何以 开头的文件的请求都将被拒绝。因此,要么有人在您的服务器上明确更改了它,要么您正在使用 - 其他东西 (litespeed)?.ht
0赞 Manish Shahi 11/17/2023
它在 localhost 上,我确实有一个共享的 litespeed 服务器。在我的.htaccess中,我有这个:<Files ~ "^\.htaccess"> Order allow,deny Deny from all Satisfy All </Files>
0赞 CBroe 11/17/2023
不确定是否需要,但除此之外,我不明白为什么这不应该起作用。(虽然我自己不是 litespeed 的专家。Satisfy All
0赞 Manish Shahi 11/17/2023
我也是,根据路由器逻辑,我也不确定如何阻止直接访问。
0赞 Olivier 11/17/2023
如果您使用 Litespeed,那么这是一个 Litespeed 问题,而不是 PHP。您应该修复您的标签。

答: 暂无答案