Hi,

I've installed Drupal 8.3.2 in a subfolder of my public_html webfolder. The website is accessed by https://www.mydomainname.com/subfolder

I enabled the statistics module, but this one is now making calls to:

https://www.mydomainname.com/subfolder/<b>index.php</b>/core/modules/statistics/statistics.php

The 'index.php' should not be in the URL. The URL is constructed in: core/modules/statistics/statistics.module:statistics_node_view (line 44). But I think the root cause is in the Url implementation which should not add the 'index.php'?

Also this problem can be reproduced for the usual installation of Drupal (without a subfolder):

  1. Install statistics module and checked 'Count content views' in configuration of this module.
  2. Go to page <site>/index.php/node/add/article and create Article node
  3. Go to page /admin/reports/dblog and see the message 'page not found'.
CommentFileSizeAuthor
#56 interdiff-53-56.txt664 bytesAnonymous (not verified)
#56 2881999-56.patch4.06 KBAnonymous (not verified)
#53 2881999-49.patch4.07 KBAnonymous (not verified)
#53 2881999-49-test-only.patch3.08 KBAnonymous (not verified)
#49 interdiff-44-49.txt3.45 KBAnonymous (not verified)
#49 2881999-49.patch4.07 KBAnonymous (not verified)
#49 2881999-49-test-only.patch4.07 KBAnonymous (not verified)
#44 2881999-44.patch5.19 KBAnonymous (not verified)
#41 interdiff-33-41.txt1.59 KBAnonymous (not verified)
#41 2881999-41.patch4.42 KBAnonymous (not verified)
#41 2881999-41-test-only.patch3.43 KBAnonymous (not verified)
#37 2881999-37.patch1.97 KBWim Leers
#37 interdiff-36-37.txt546 bytesWim Leers
#36 2881999-36.patch1.48 KBWim Leers
#33 interdiff-31-33.txt634 bytesAnonymous (not verified)
#33 2881999-33.patch4.17 KBAnonymous (not verified)
#33 2881999-33-test-only.patch3.18 KBAnonymous (not verified)
#31 interdiff-23-31.txt2.23 KBAnonymous (not verified)
#31 2881999-31.patch4.18 KBAnonymous (not verified)
#23 interdiff-21-23.txt1.03 KBAnonymous (not verified)
#23 2881999-23.patch1.96 KBAnonymous (not verified)
#21 iterdiff-15-20.txt1.07 KBAnonymous (not verified)
#21 2881999-20.patch1.99 KBAnonymous (not verified)
#15 interdiff-12-15.txt1.01 KBAnonymous (not verified)
#15 2881999-15.patch2 KBAnonymous (not verified)
#12 2881999-12.patch1.93 KBAnonymous (not verified)
#12 2881999-12-test-only.patch991 bytesAnonymous (not verified)
#8 2881999-8.patch984 bytesAnonymous (not verified)
#2 2881999_fail_reproduce.gif339.86 KBAnonymous (not verified)
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Jochus created an issue. See original summary.

Anonymous’s picture

FileSize
339.86 KB

I installed the 8.3.2 in the subdomain, installed and enabled the statistics module and could not reproduce the problem (see attached gif with confirm it)

Jochus’s picture

Hi vaplas,

Thanks for your very fast feedback. I just tried it also on a 'fresh' installation, and indeed, the problem is not in there. I'll have to find out which contrib module/theme brakes the functionality.

You can close this ticket. As soon as I find the root cause, I'll add it here for future reference.

Jochus’s picture

Status: Active » Closed (works as designed)

(sorry, it seems I can close the ticket myself :-))

Anonymous’s picture

Status: Closed (works as designed) » Closed (cannot reproduce)

@Jochus, no problem. Maybe you have some changes in the .htaccess file?

Jochus’s picture

Status: Closed (cannot reproduce) » Active

Ok, found how I can reproduce it on a fresh install. Make sure to execute the following steps:

Scenario:
* Set up clean Drupal 8 installatin
* Create content: Article
- make sure the article gets a an URL alias ($ALIAS)
* Access your article using the URL http://localhost/subfolder/index.php/$ALIAS

Problem:
call to statistics.php result in 404 NOT FOUND

Jochus’s picture

And your question will be: why do you add the "index.php"? Well, I have no idea, it happens automatically:

Scenario:
* Browse to http://www.jochenhebbrecht.be/site/
* Click 'an article' (doesn't matter which one)
* Check the URL

Problem:
index.php is automatically added in the URL (this problem does NOT occur when I'm logged in to the Drupal site)

Update:
After reading this page: https://www.drupal.org/node/256410, I've changed:

# RewriteBase /

to

RewriteBase /site

But the problem still occurs ...

Anonymous’s picture

Title: Path to statistics.php is not correct when Drupal is installed in subfolder » Path to statistics.php is not correct when the path start with index.php
Issue summary: View changes
Status: Active » Needs review
FileSize
984 bytes

Good research, @Jochus!

Unfortunately (or fortunately), I can not reproduce the appearance index.php via enable URL alias. Maybe this is problem of Apache config or php version. See also #2839167-3: index.php in pathes.

But the problem with 'statistics.php' path can be reproduced for the usual installation of Drupal (without a subfolder) too:

  1. Install statistics module and check 'Count content views' in config (/admin/config/system/statistics).
  2. Go to page /index.php/node/add/article and create Article node
  3. Go to page /admin/reports/dblog and see the message 'page not found'.

I'm update issue summary and title, but do feel free to correct it :)

This patch should fix problem for both cases (with/without subfolder installation), but i'm not sure that this is ideal solution.


Also I found an unpleasant bug. Saving node with 'index.php' in path (/index.php/node/1/edit) leads to the appearance of 'index.php' in all actions links (even if after go to the '/node/1' page). The reason for this is the caching of generated action links (you cann't reproduce this on dev regim with 'cache.backend.null'). But looks like this out of scope this issue.
Anonymous’s picture

Version: 8.3.2 » 8.4.x-dev
Jochus’s picture

Hi vaplas,

Title has been modified correctly by your side! :-)!
With your patch, I'm unable to reproduce the problem.

Thank you!

alayham’s picture

I am seeing this error a lot recently. Patch applied. testing for a few days.

Anonymous’s picture

Thanks @Jochus and @alayham for feedback!

A bit test coverage (test-only is interdiff with #8 patch).

The last submitted patch, 12: 2881999-12-test-only.patch, failed testing.

Berdir’s picture

+++ b/core/modules/statistics/statistics.module
@@ -41,7 +41,7 @@ function statistics_help($route_name, RouteMatchInterface $route_match) {
     $build['#attached']['library'][] = 'statistics/drupal.statistics';
-    $settings = ['data' => ['nid' => $node->id()], 'url' => Url::fromUri('base:' . drupal_get_path('module', 'statistics') . '/statistics.php')->toString()];
+    $settings = ['data' => ['nid' => $node->id()], 'url' => base_path() . drupal_get_path('module', 'statistics') . '/statistics.php'];
     $build['#attached']['drupalSettings']['statistics'] = $settings;

I don't think we should deprecate on base_path(), which is more or less deprecated.

What about using file_url_transform_relative(file_create_url()) for this? Kinda weird to do it for a .php file, but we *are* creating a URL to a file.

This might break someone uncondtionally changing all file URL's to be passed through a different domain/CDN but I think you shouldn't do that anyway.

We should ask @dawehner about this.

Anonymous’s picture

Thank you for this tip, @Berdir!

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

Looks good.

I tested the test without the fix to statistics.module and it failed as expected.

tstoeckler’s picture

So update_authorize_update_batch_finished() contains the following to - if I am not mistaken - to achieve the same thing:

  $results['tasks'][] = [
    '#type' => 'link',
    '#url' => $url,
    '#title' => t('Run database updates'),
    // Since this is being called outsite of the primary front controller,
    // the base_url needs to be set explicitly to ensure that links are
    // relative to the site root.
    // @todo Simplify with https://www.drupal.org/node/2548095
    '#options' => [
      'absolute' => TRUE,
      'base_url' => $GLOBALS['base_url'],
    ],
    '#access' => $url->access(\Drupal::currentUser())
  ];

That code predates the existance of file_url_transform_relative(), though, and using that might actually be a nicer solution. So not downgrading, as I'm not sure, but wanted to point this out. I agree @dawehner would be great voice here.

Wim Leers’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/statistics/statistics.module
@@ -41,7 +41,8 @@ function statistics_help($route_name, RouteMatchInterface $route_match) {
+    $statistics_path = file_url_transform_relative(file_create_url(drupal_get_path('module', 'statistics') . '/statistics.php'));

This is very very very wrong. This is not what file_create_url() or file_url_transform_relative() are designed for.

Berdir’s picture

> Creates a web-accessible URL for a stream to an external or local file.

statistics.php *is* a file. Any route based thing doesn't work because it for example includes index.php/ in the URL if you are currently on such a path.

as far as I see, the only other alternative is to use the base_url function/global, any other suggestion?

Wim Leers’s picture

But it's not a static file, an asset. Something like an image, a PDF, a CSS file. It's an executable that you want to be executed.

For now, I think it's best to do what @tstoeckler quoted in #17. That's the most similar use case.

Anonymous’s picture

Status: Needs work » Needs review
FileSize
1.99 KB
1.07 KB

Looks like this unrouted url has problems due to script option (UnroutedUrlAssembler::addOptionDefaults()).

Test only remains like #12.

dawehner’s picture

Did you tried using something like this:

$settings = ['data' => ['nid' => $node->id()], 'url' => \Drupal::request()->getBasePath() . '/' . drupal_get_path('module', 'statistics') . '/statistics.php']; 

?

Anonymous’s picture

Thanks, @dawehner! And it works fine with index.php (including a subfolder case) too. And this approach is not yet in our collection:

  • #8 - base_path()
  • #15 - file_url_transform_relative(file_create_url(...))
  • #21 - ['script' => '']
  • #23 - \Drupal::request()->getBasePath()
dawehner’s picture

Thanks, @dawehner! And it works fine with index.php (including a subfolder case) too. And this approach is not yet in our collection:

Oh yeah, I should have actually listed the cases I tested:

  • localhost/d8
  • localhost/d8/index.php
  • d8.loc/index.php
  • d8.loc

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

websiteworkspace’s picture

Is the bug described in this thread the source of the constant:


"page not found" 

http://{site}/core/modules/statistics/statistics.php

warning/errors in the recent log messages for nearly every URL on a site?

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

For me at least this is ready to go. We have test coverage and a working fix.

catch’s picture

Status: Reviewed & tested by the community » Needs review

I'm not sure why we can't use file_url_transform_relative() here. The docs don't indicate it's for this use case, but that's exactly what it's for?

dawehner’s picture

At least for me having a absolute URL instead of a relative URL feels safer, but that's just me :)

websiteworkspace’s picture

This bug still exists as of the 8.4.0 update.

The log keeps showing statistics.php not found errors.

I've uninstalled the core statistics now, since it is basically neutered in 8.x, now also broken, and therefore useless.

Anonymous’s picture

We have two big problem for statistics module on page with 'index.php' prefix:

  1. it does not work, and as a consequence
  2. it generates a lot of spam log messages

We have two additional issues, which can solve this problem by another way:

#23 contains a list of possible solutions for the get correct path to file. (All that were offered here, except #17, because it does not help to protect against the appearance of a script key, see #21).

We have a white-box test for these solutions. Probably also a black-box test will be useful. Here it is with solution from dawehner (#22).

Status: Needs review » Needs work

The last submitted patch, 31: 2881999-31.patch, failed testing. View results

The last submitted patch, 33: 2881999-33-test-only.patch, failed testing. View results

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

I just started looking at the statistics module (because I want to use it on my own site) and noticed that its JS is using drupalSettings.statistics.url to determine which URL to send data to.

That's … weird … because we have Drupal.url() for that since several years (new in D8 though). There's no need to send this data in the body of every HTML response.

This optimization also happens to fix the bug originally reported here.

Wim Leers’s picture

/me curses https://www.drupal.org/node/2815083 for not running automatically

Here's an updated patch with the ES6 transpiled to ES5.

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

Thanks Wim, looks good to me

Berdir’s picture

Status: Reviewed & tested by the community » Needs work

No, that's not so weird.

statistics.php is a file. Drupal.url() is about a (routed) path, it adds the path prefix, e.g. the language prefix. But that doesn't work for files and results in a 404 on a multilingual site.

That said, we can possible use the same implementation and just leave out the pathPrefix? (No we can not as I found out below)

Also, according to my test, it actually does *not* fix the index.php problem either. If I am on d8/index.php/node/1, then drupalSettings.path.basePath is "/index.php/", again because it is about routed paths and not files.

We really need a JS test that makes sure it works with language prefix and with index.php in the path :)

dawehner’s picture

I'm confused why we lost the test coverage from earlier versions of this patch.

@Berdir
You made a good point here. I also believe that this should be done in PHP vs. JS, because the file might be somewhere different, for example when you don't want to put your code into the webroot. Based upon that changing this value in PHP seems easier than changing it in JS.

Anonymous’s picture

Status: Needs work » Needs review
FileSize
3.43 KB
4.42 KB
1.59 KB

restoration of tests from #33 + tests with language prefix.

The last submitted patch, 41: 2881999-41-test-only.patch, failed testing. View results

Berdir’s picture

Status: Needs review » Needs work
+++ b/core/modules/statistics/tests/src/FunctionalJavascript/StatisticsLoggingTest.php
@@ -0,0 +1,83 @@
+
+  /**
+   * Data provider for testLoggingPage().
+   */
+  public function providerTestLoggingPage() {
+    return [
+      ['node/1'],
+      ['en/node/1'],
+      ['index.php/node/1'],
+      ['index.php/en/node/1'],
+    ];

The thing is that means is that we have to run through the whole install process 4 times, as each provider is a completely separate test run.

I would just make this a loop inside the test method. Not so nice, but IMHO we should only use providers for browser tests if they provide a real benefit and we need to actually install/configure different and conflicting things that we can't do in a single test run.

That does mean that we have to change the logic around the "1 view" check, but actually seems like a good thing, making sure that it also works correctly on cache hits and so on?

As a follow-up, maybe we could convert most of the other test coverage that fakes actual hits with PHP to this JS test. I think that could both improve and simplify our test coverage.

Anonymous’s picture

#43: Here are two versions for it: testLoggingPage and testLoggingPage2. It also seems that BTB::StatisticsLoggingTest is not needed anymore.

Wim Leers’s picture

#38: you're a bit trigger-happy with that RTBC — this still needed test coverage and actual manual testing.


#39:

statistics.php is a file.

It's not a file. A "file" in Drupal parlance is a static asset. An image. A video. A font. A CSS file. A JS file. A document. This is a PHP file, with code we want to execute. Hence it is not a file. Files/assets can be served from a reverse proxy. statistics.php cannot be served from a reverse proxy.

Also, according to my test, it actually does *not* fix the index.php problem either. […]

Makes sense!


#40:

I'm confused why we lost the test coverage from earlier versions of this patch.

Because I started from scratch.

because the file might be somewhere different, for example when you don't want to put your code into the webroot.

Really? Isn't this tantamount to hacking core? And if you're hacking core's PHP code, you might as well also hack core's JS code.

I see no reason for burdening every HTML response with metadata that can be perfectly computed on the client side.

timmillwood’s picture

@Wim Leers - Re #38 I was so excited someone was actually working on Statistics.

Berdir’s picture

> A "file" in Drupal parlance is a static asset

> This is a PHP file

Would be news to me that the term "file" can be used only for static assets. file_create_url() for example doesn't ever talk about static assets only, it only talks about managed and shipped files. This is IMHO a shipped file.

Either way, that's not really the relevant part of my review, the relevant part is that is *not* a route. I think that we can agree on :)

And that means that your approach or anything that just relies on the the existing information in drupalSetings.path can not work.

dawehner’s picture

because the file might be somewhere different, for example when you don't want to put your code into the webroot.

Really? Isn't this tantamount to hacking core? And if you're hacking core's PHP code, you might as well also hack core's JS code.

No, this is considered a good security practice. You can read more about it here https://www.drupal.org/node/2767907

I like that the current solution allows you to get the best of everything possible. There is a sensible location set by default, but you can also alter the settings and point it to somewhere else.

Some of the language in this thread seems a little aggressive, let's please remember to be mindful of how our words come across. Thanks :)

  1. +++ b/core/modules/statistics/tests/src/FunctionalJavascript/StatisticsLoggingTest.php
    @@ -0,0 +1,126 @@
    +      'node/1',
    +      'en/node/1',
    +      'index.php/node/1',
    +      'index.php/en/node/1',
    

    Nice test coverage!

  2. +++ b/core/modules/statistics/tests/src/FunctionalJavascript/StatisticsLoggingTest.php
    @@ -0,0 +1,126 @@
    +    $this->assertSame(0, $this->getStatisticsCounter('node/1'));
    +    $this->assertSame(1, $this->getStatisticsCounter('node/1'));
    +    $this->assertSame(2, $this->getStatisticsCounter('en/node/1'));
    +    $this->assertSame(3, $this->getStatisticsCounter('en/node/1'));
    +    $this->assertSame(4, $this->getStatisticsCounter('index.php/node/1'));
    +    $this->assertSame(5, $this->getStatisticsCounter('index.php/node/1'));
    +    $this->assertSame(6, $this->getStatisticsCounter('index.php/en/node/1'));
    +    $this->assertSame(7, $this->getStatisticsCounter('index.php/en/node/1'));
    

    That is some really nice test!

  3. +++ b/core/modules/statistics/tests/src/FunctionalJavascript/StatisticsLoggingTest.php
    @@ -0,0 +1,126 @@
    +   * Get counter of views by path.
    

    Nitpick: "Gets" instead of "Get"

Anonymous’s picture

Status: Needs work » Needs review
FileSize
4.07 KB
4.07 KB
3.45 KB

@dawehner thanks for review and kind words about tests!

  • Nitpick fixed.
  • Removed an extra test.
  • And a slight improvement for last test (I hope)
+++ b/core/modules/statistics/tests/src/FunctionalJavascript/StatisticsLoggingTest.php
@@ -48,51 +49,11 @@ protected function setUp() {
-    $this->assertSame(0, $this->getStatisticsCounter('node/1'));
+    // At the first request, the page does not contain statistics counter.
+    $this->assertNull($this->getStatisticsCounter('node/1'));

@@ -120,7 +81,7 @@ protected function getStatisticsCounter($path) {
+    return $field_counter ? (int) explode(' ', $field_counter->getText())[0] : NULL;

This will make it possible to verify that we have not statistics block, not "0 view".

dawehner’s picture

This looks really good for me now, but maybe @timmillwood as the statistics module maintainer should have another look.

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me.

Only issue is the test-only patch in #49 isn't only the test. Feel free to reupload both the test-only and full patch for #49 to help committer review.

As this is a bug fix it should be possible to backport to 8.5.x too.

Wim Leers’s picture

#46: 😃❤️


#48:

Would be news to me that the term "file" can be used only for static assets. file_create_url() for example doesn't ever talk about static assets only, it only talks about managed and shipped files. This is IMHO a shipped file.

I am the one who wrote those docs in #499156: CDN integration: allow file URLs to be rewritten by hook_file_url_alter() … and at the time my English was far less proficient. Sorry for the ambiguity :( I totally agree that the wording could and should be much better!

The last submitted patch, 53: 2881999-49-test-only.patch, failed testing. View results

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
+++ b/core/modules/statistics/tests/src/FunctionalJavascript/StatisticsLoggingTest.php
@@ -0,0 +1,87 @@
+  public static $modules = ['node', 'block', 'statistics', 'language'];

Why is the block module being installed?

Anonymous’s picture

Eagle eyes! Just unsuccessful copy-paste from Drupal\Tests\statistics\Functional\StatisticsLoggingTest

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you for fixing!

alexpott’s picture

Adding credit to reviewers who've helped the patch progress and steered it towards a solution.

alexpott’s picture

Version: 8.6.x-dev » 8.5.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Committed d85463b and pushed to 8.6.x. Thanks!

Setting to ptbp for cherry-pick to 8.5.x once 8.5.0 is out.

  • alexpott committed d85463b on 8.6.x
    Issue #2881999 by vaplas, Wim Leers, dawehner, Jochus, Berdir,...
alexpott’s picture

Status: Patch (to be ported) » Fixed

Committed 684bdfa and pushed to 8.5.x. Thanks!

  • alexpott committed 1cd6308 on 8.5.x
    Issue #2881999 by vaplas, Wim Leers, dawehner, Jochus, Berdir,...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.