ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ.. namespace core; use core\router\middleware\cors_middleware; use core\router\middleware\error_handling_middleware; use core\router\middleware\moodle_api_authentication_middleware; use core\router\middleware\moodle_authentication_middleware; use core\router\middleware\moodle_bootstrap_middleware; use core\router\middleware\moodle_route_attribute_middleware; use core\router\middleware\uri_normalisation_middleware; use core\router\middleware\validation_middleware; use core\router\request_validator_interface; use core\router\response_handler; use core\router\response_validator_interface; use core\router\route_loader_interface; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\App; use Slim\Exception\HttpForbiddenException; use Slim\Exception\HttpNotFoundException; use Slim\Interfaces\RouteGroupInterface; use Slim\Middleware\ErrorMiddleware; /** * Moodle Router. * * This class represents the Moodle Router, which handles all aspects of Routing in Moodle. * * It should not normally be accessed or used outside of its own unit tests, the route_testcase, and the `r.php` handler. * * @package core * @copyright Andrew Lyons * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class router { /** @var string The base path to use for all requests */ public readonly string $basepath; /** @var App The SlimPHP App */ protected readonly App $app; /** * Create a new Router. * * @param response_handler $responsehandler * @param route_loader_interface $routeloader * @param request_validator_interface $requestvalidator * @param response_validator_interface $responsevalidator * @param null|string $basepath */ public function __construct( /** @var response_handler */ protected response_handler $responsehandler, /** @var route_loader_interface The router loader to use */ protected readonly route_loader_interface $routeloader, /** @var request_validator_interface */ protected request_validator_interface $requestvalidator, /** @var response_validator_interface */ protected response_validator_interface $responsevalidator, ?string $basepath = null, ) { if ($basepath === null) { $basepath = $this->guess_basepath(); } $this->basepath = $basepath; } /** * Guess the basepath for the Router. * * @return string */ protected function guess_basepath(): string { global $CFG; // Moodle is not guaranteed to exist at the domain root. // Strip out the current script. $scriptroot = parse_url($CFG->wwwroot, PHP_URL_PATH) ?? ''; $scriptfile = str_replace( realpath($CFG->dirroot), '', realpath($_SERVER['SCRIPT_FILENAME']), ); // Replace occurrences of backslashes with forward slashes, especially on Windows. $scriptfile = str_replace('\\', '/', $scriptfile); // The server is not configured to rewrite unknown requests to automatically use the router. $userphp = false; if ($_SERVER && array_key_exists('REQUEST_URI', $_SERVER)) { if (str_starts_with($_SERVER['REQUEST_URI'], "{$scriptroot}/r.php")) { $userphp = true; } } if ($CFG->routerconfigured !== true || $userphp) { $scriptroot .= '/r.php'; } return $scriptroot; } /** * Get the configured SlimPHP Application. * * @return App */ public function get_app(): App { if (!isset($this->app)) { $this->create_app($this->basepath); } return $this->app; } /** * Get the Response Factory for the Router. * * @return ResponseFactoryInterface */ public function get_response_factory(): ResponseFactoryInterface { return $this->get_app()->getResponseFactory(); } /** * Create the configured SlimPHP Application. * * @param string $basepath The base path of the Moodle instance */ protected function create_app( string $basepath = '', ): void { // Create an App using the DI Bridge. $this->app = router\bridge::create(); // Add Middleware to the App. // Note: App Middleware is called before any Group or Route middleware. $this->add_middleware(); $this->configure_caching(); $this->configure_routes(); // Configure the basepath for Moodle. $this->app->setBasePath($basepath); } /** * Add Middleware to the App. */ protected function add_middleware(): void { // Middleware is added like an onion. // For a Response, the outer-most middleware is executed first, and the inner-most middleware is executed last. // For a Request, the inner-most middleware is executed first, and the outer-most middleware is executed last. // Add the body parsing middleware from Slim. // See https://www.slimframework.com/docs/v4/middleware/body-parsing.html for further information. $this->app->addBodyParsingMiddleware(); // Add Middleware to Bootstrap Moodle from a request. $this->app->add(di::get(moodle_bootstrap_middleware::class)); // Add the Moodle route attribute to the request. // This must be processed after the Routing Middleware has been processed on the request. $this->app->add(di::get(moodle_route_attribute_middleware::class)); // Add the Routing Middleware as one of the outer-most middleware. // This allows the Route to be accessed before it is handled. // See https://www.slimframework.com/docs/v4/cookbook/retrieving-current-route.html for further information. $this->app->addRoutingMiddleware(); // Add request normalisation middleware to standardise the URI. // This must be done before the Routing Middleware to ensure that the route is matched correctly. $this->app->add(di::get(uri_normalisation_middleware::class)); // Add the Error Handling Middleware to the App. $this->add_error_handler_middleware(); } /** * Add the Error Handling Middleware to the RouteGroup. */ protected function add_error_handler_middleware(): void { // Add the Error Handling Middleware and configure it to show Moodle Errors for HTML pages. $errormiddleware = new ErrorMiddleware( $this->app->getCallableResolver(), $this->app->getResponseFactory(), displayErrorDetails: true, logErrors: true, logErrorDetails: true, ); // Set a custom error handler for the HttpNotFoundException and HttpForbiddenException. // We route these to a custom error handler to ensure that the error is displayed with a feedback form. $errormiddleware->setErrorHandler( [ HttpNotFoundException::class, HttpForbiddenException::class, ], new router\error_handler($this->app), ); $errormiddleware->getDefaultErrorHandler()->registerErrorRenderer('text/html', router\error_renderer::class); $this->app->add($errormiddleware); } /** * Configure the API routes. */ protected function configure_routes(): void { $routegroups = $this->routeloader->configure_routes($this->app); foreach ($routegroups as $name => $collection) { match ($name) { route_loader_interface::ROUTE_GROUP_API => $this->configure_api_route($collection), route_loader_interface::ROUTE_GROUP_PAGE => $this->configure_standard_route($collection), route_loader_interface::ROUTE_GROUP_SHIM => $this->configure_shim_route($collection), default => null, }; } } /** * Configure the API Route Middleware. * * @param RouteGroupInterface $group */ protected function configure_api_route(RouteGroupInterface $group): void { $group ->add(di::get(error_handling_middleware::class)) // Add a Middleware to set the CORS headers for all REST Responses. ->add(di::get(cors_middleware::class)) ->add(di::get(moodle_api_authentication_middleware::class)) ->add(di::get(validation_middleware::class)); } /** * Configure the Standard page Route Middleware. * * @param RouteGroupInterface $group */ protected function configure_standard_route(RouteGroupInterface $group): void { $group ->add(di::get(moodle_authentication_middleware::class)) ->add(di::get(validation_middleware::class)); } /** * Configure the Shim Route Middleware. * * @param RouteGroupInterface $group */ protected function configure_shim_route(RouteGroupInterface $group): void { $group // Note: In the future we may wish to add a shim middleware to notify users of updated bookmarks. ->add(di::get(validation_middleware::class)); } /** * Configure caching for the routes. */ protected function configure_caching(): void { global $CFG; // Note: Slim uses a file cache and is not compatible with MUC. $this->app->getRouteCollector()->setCacheFile( sprintf( "%s/routes.%s.cache", $CFG->cachedir, sha1($this->basepath), ), ); } /** * Handle the specified Request. * * @param ServerRequestInterface $request * @return ResponseInterface */ public function handle_request( ServerRequestInterface $request, ): ResponseInterface { return $this->get_app()->handle($request); } /** * Serve the current request using global variables. * * @codeCoverageIgnore */ public function serve(): void { $this->get_app()->run(); } }