FMCorz / moodle-block_xp

A gamification plugin for Moodle allowing students to gain experience points and level up.
https://levelup.plus/?ref=github
150 stars 41 forks source link

Coding error detected, it must be fixed by a programmer: Controller for route not found. #79

Closed fishfree closed 6 years ago

fishfree commented 6 years ago

When I click on the report link in a Levelup block, I see the error. I clearly remember it works with no problem before. Moodle 3.3.1+ (Build: 20170804) with default Boost theme. Level up! 3.1.0

FMCorz commented 6 years ago

Thanks for the report.

Could you provide me with more information regarding your webserver, and how it is set up?

Are you using nginx?

You may try to disable slasharguments in the site's administration settings. Thanks!

fishfree commented 6 years ago

Yes, I'm using Nginx. How to disable slasharguments in the site's administration?

FMCorz commented 6 years ago

I suspect that other things in Moodle may not work due to your config.

Have you followed? https://docs.moodle.org/33/en/Nginx#Nginx

Here is my config which works:

    location ~ [^/]\.php(/|$) {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

To disable slasharguments, search for it in the admin.

FMCorz commented 6 years ago

Have you made any progress?

fishfree commented 6 years ago

I replace "location ~ .php$ {" with your "location ~ [^/].php(/|$) {", problem still exists.

FMCorz commented 6 years ago

It's not so much the location, rather the fastcgi parameters.

FMCorz commented 6 years ago

Have you found a solution?

chockemeyer commented 6 years ago

I have the same problem (using Moodle 3.4) and fixing the fastcgi parameters did not help. Here is my part of the respective nginx config file: location ~ [^/].php(/|$) { fastcgi_split_path_info ^(.+.php)(/.+)$; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; include fastcgi_params; }

Any help would be welcome!

FMCorz commented 6 years ago

Have you tested the configuration mentioned above? The order of the directives might matter.

chockemeyer commented 6 years ago

Yes, it doesn't fix the problem either.

chockemeyer commented 6 years ago

Disabling shlasharguments helped but that can only be a short-term solution as the comment on slasharguments says that it will be required in future.

scara commented 6 years ago

Hi @chockemeyer, beware that "." in a regexp is different from the literal . i.e. do not use:

location ~ [^/].php(/|$) {
fastcgi_split_path_info ^(.+.php)(/.+)$;

but add the missing \ before .php to let . be a real dot char in the pattern matching:

location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info  ^(.+\.php)(/.+)$;

HTH, Matteo

chockemeyer commented 6 years ago

Thanks Matteo but meanwhile I have the version posted by FMCorz on Sep 21 which includes the backslash.

FMCorz commented 6 years ago

@chockemeyer Do you also have issues with downloading files when slasharguments is turned on? The logic for serving files is almost exactly the same as the login for finding the route. A quick test would be to write content embedding a file hosted on the system (e.g. Private files), and see if that file is displayed properly.

Alternatively, could you place a file called test.php at blocks/xp/test.php with the following content:

<?php
require(__dir__ . '/../../config.php');
echo '<pre>';
var_dump($_SERVER['PATH_INFO']);
var_dump($_SERVER['SCRIPT_NAME']);
var_dump($_SERVER['REQUEST_URI']);
var_dump($_SERVER['SERVER_SOFTWARE']);

Then accessing WWWROOT/blocks/xp/test.php/a/b/c/d, you should get something similar to this:

string(8) "/a/b/c/d"
string(27) "/levelup/blocks/xp/test.php"
string(35) "/levelup/blocks/xp/test.php/a/b/c/d"
string(12) "nginx/1.10.3"

You probably will have something else than levelup for the 2nd and 3rd entries, or nothing at all. Could you please share your result? Remember the re-enable slasharguments prior to trying it.

chockemeyer commented 6 years ago

I don't have problems with downloading files, at least embedded PDF files are shown correctly and I also could download backup files.

The results for your test.phpare

string(0) ""
string(19) "/blocks/xp/test.php"
string(27) "/blocks/xp/test.php/a/b/c/d"
string(12) "nginx/1.12.2"

independent of whether slasharguments is turned on or off.

FMCorz commented 6 years ago

Not sure what happens, I'm confused as to why files are downloaded. Could you share the link to a file? I'm curious about the URL that Moodle constructed, I won't be downloading the file.

For reference here is my full config:

$ cat sites-enabled/somesite 
server {
    listen 80;
    listen [::]:80;

    root /something;

    index index.php index.html index.htm index.nginx-debian.html;

    server_name example.com;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    location ~ /\.ht {
        deny all;
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ [^/]\.php(/|$) {
        include snippets/fastcgi-php.conf;

        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

}
$ cat snippets/fastcgi-php.conf 
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;

# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;

# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

fastcgi_index index.php;
include fastcgi.conf;
scara commented 6 years ago

Hi @chockemeyer, what about cgi.fix_pathinfo=1 in your php.ini?

HTH, Matteo

chockemeyer commented 6 years ago

Link to a file included in a page: https://moodle.tquant.eu/pluginfile.php?file=/197/mod_resource/content/4/MartinLages_SuggestionsforApps%20.pdf Link for a Private File: https://moodle.tquant.eu/pluginfile.php?file=/5/user/private/logo_TquanT.jpg&forcedownload=1

nginx config file:

server {
    listen 443 ssl;

    root /var/www/moodlessl/moodle;
    index index.php index.html index.htm;

    server_name moodle.tquant.eu;

        rewrite ^/(.*.php)(/)(.*)$ /$1?file=/$3 last;

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    location /dataroot/ {
        internal;
        alias /var/www/moodlessl/moodledata/; # ensure the path ends with /
    }

    location ~ [^/]\.php(/|$) {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

}

snippets/fastcgi-php.conf:

# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;

# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;

# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

fastcgi_index index.php;
include fastcgi.conf;
chockemeyer commented 6 years ago

@scara cgi.fix_pathinfo=1 is set.

scara commented 6 years ago

Mmmhhh... could you share what is your OS and the PHP version? Has everything - PHP, nginx - been installed via standard packages? Spare time permitted I'd like to recreate it via docker to investigate your config.

In the past there were some strange bugs e.g. MDL-51554 and I not actually sure if you're hitting something strange here under nginx/1.12.2 or there's something simply missing at first sight.

HTH, Matteo

scara commented 6 years ago

FYI @chockemeyer

Link to a file included in a page: https://moodle.tquant.eu/pluginfile.php?file=/197/mod_resource/content/4/MartinLages_SuggestionsforApps%20.pdf Link for a Private File: https://moodle.tquant.eu/pluginfile.php?file=/5/user/private/logo_TquanT.jpg&forcedownload=1

Everything work in Moodle since your are under slasharguments off: that's the reason why for the HTTP GET param file in your URLs, which is the way Moodle uses to find the "slasharguments" when not properly supported. Otherwise, they should look as below:

HTH, Matteo

chockemeyer commented 6 years ago

I have a xubuntu 14.04 LTS with PHP 7.0. nginx and php are installed from the following sources:

deb http://nginx.org/packages/ubuntu/ trusty nginx
deb-src http://nginx.org/packages/ubuntu/ trusty nginx
deb http://ppa.launchpad.net/ondrej/php/ubuntu trusty main

And yes, turning slasharguments on, the file URLs look as you described it.

FMCorz commented 6 years ago

Pretty sure this is the incriminating line:

rewrite ^/(.*.php)(/)(.*)$ /$1?file=/$3 last;

Level up! does not expect the route to be passed through the file argument, rather the _r argument. As the rest of you config file looks right. Could you try to comment out the rewrite line, enable slasharguments, restart nginx and access the test file as commented above?

If this does not work, the workaround is to add a rewrite rule for Level up!. I don't recommend this approach, but here is an untested example:

rewrite ^/(blocks/xp/.*.php)(/)(.*)$ /$1?_r=/$3 last;
rewrite ^/(.*.php)(/)(.*)$ /$1?file=/$3 last;
chockemeyer commented 6 years ago

The test.phpnow returns

string(8) "/a/b/c/d"
string(19) "/blocks/xp/test.php"
string(27) "/blocks/xp/test.php/a/b/c/d"
string(12) "nginx/1.12.2"

And, much more important, Level Up seems to work now with slasharguments turned on.

Thank you very much!

fishfree commented 6 years ago

@FMCorz Your "rewrite ^/(blocks/xp/..php)(/)(.)$ /$1?_r=/$3 last;" saved me! Problem disappears. Cool~

scara commented 6 years ago

Hi @fishfree, beware that you've implemented an unsupported workaround that could not work in the future.

It should be better to investigate the web server configuration for a proper slash argument support 😉 .

HTH, Matteo

matia12 commented 6 years ago

Hi All, I am trying levelup plugin on Moodle 3.4.2 installed on windows, IIS web server and the database is MSSQL. I added the block to a course and when pressing any link including ladder and settings I got the below error

Coding error detected, it must be fixed by a programmer: Controller for route not found. More information about this error ×Debug info: Error code: codingerror ×Stack trace: line 95 of \blocks\xp\classes\local\routing\router.php: coding_exception thrown line 79 of \blocks\xp\classes\local\routing\router.php: call to block_xp\local\routing\router->get_controller_from_request() line 38 of \blocks\xp\index.php: call to block_xp\local\routing\router->dispatch()

I added the test page and I get the below output string(1) "/" string(19) "/blocks/xp/test.php" string(34) "/blocks/xp/test.php/?file=/a/b/c/d" string(17) "Microsoft-IIS/8.5"

any suggestion how can I fix the issue

How to apply this rewrite "rewrite ^/(blocks/xp/..php)(/)(.)$ /$1?_r=/$3 last; to IIS

matia12 commented 6 years ago

It is now working fine for me now in IIS 8.5 the pattern should be ^(blocks\/xp\/[^\?]+?.php)(\/.+)$ and the rewrite URL should be {R:1}?_r={R:2} screenshot below show the correct rule for the workaround in IIS 8.5 https://1drv.ms/u/s!Amdk-vbboLpgh0taTJqtwiOcaXFE

FMCorz commented 5 years ago

This has been documented here:

https://levelup.branchup.tech/docs/article/error-controller-for-route-not-found