antonioribeiro / tracker

Laravel Stats Tracker
MIT License
2.9k stars 592 forks source link

ErrorException A non-numeric value encountered in Session.php (line 19) #297

Open rattfieldnz opened 7 years ago

rattfieldnz commented 7 years ago

Hey there,

First of all, I'm glad I have come across your package! I was going to do this from scratch, but figured there's no point in re-inventing the wheel (especially when you want to get a project finished sooner rather than later)...

To get right to the point...

I visit my project's URL on my Vagrant testing server @ http://freebtc.website.new.localhost:8080/stats/errors (your equivalent being stats/?page=errors), and I see information as below:

capture

Ironically, you will see the first two error messages are ones I'm submitting this issue for :).

I select '7 days' as my chosen timeframe, which works as expected:

capture2

Being the annoying person I am, I enter a back-tick as a value for 'days'. This is what produces the error I've submitted the issue for:

capture3

The full stack trace is also below:

(1/1) ErrorExceptionA non-numeric value encountered

in Session.php (line 19)
at HandleExceptions->handleError(2, 'A non-numeric value encountered', '/var/www/freebtc.website.new.localhost/vendor/pragmarx/tracker/src/Vendor/Laravel/Support/Session.php', 19)
at call_user_func(array(object(HandleExceptions), 'handleError'), 2, 'A non-numeric value encountered', '/var/www/freebtc.website.new.localhost/vendor/pragmarx/tracker/src/Vendor/Laravel/Support/Session.php', 19)in Handler.php (line 58)
at Handler->handleError(2, 'A non-numeric value encountered', '/var/www/freebtc.website.new.localhost/vendor/pragmarx/tracker/src/Vendor/Laravel/Support/Session.php', 19, array())in Session.php (line 19)
at Session->__construct()
at ReflectionClass->newInstanceArgs(array())in Container.php (line 762)
at Container->build('PragmaRX\\Tracker\\Vendor\\Laravel\\Support\\Session')in Container.php (line 608)
at Container->resolve('PragmaRX\\Tracker\\Vendor\\Laravel\\Support\\Session')in Container.php (line 575)
at Container->make('PragmaRX\\Tracker\\Vendor\\Laravel\\Support\\Session')in Application.php (line 728)
at Application->make('PragmaRX\\Tracker\\Vendor\\Laravel\\Support\\Session')in RouteDependencyResolverTrait.php (line 77)
at ControllerDispatcher->transformDependency(object(ReflectionParameter), array())in RouteDependencyResolverTrait.php (line 46)
at ControllerDispatcher->resolveMethodDependencies(array(), object(ReflectionMethod))in RouteDependencyResolverTrait.php (line 27)
at ControllerDispatcher->resolveClassMethodDependencies(array(), object(StatsController), 'errors')in ControllerDispatcher.php (line 40)
at ControllerDispatcher->dispatch(object(Route), object(StatsController), 'errors')in Route.php (line 203)
at Route->runController()in Route.php (line 160)
at Route->run()in Router.php (line 574)
at Router->Illuminate\Routing\{closure}(object(Request))in Pipeline.php (line 30)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in LaratrustRole.php (line 56)
at LaratrustRole->handle(object(Request), object(Closure), array('owner'))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in Authenticate.php (line 28)
at Authenticate->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in Tracker.php (line 24)
at Tracker->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in BlockReferralSpam.php (line 45)
at BlockReferralSpam->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in SecureHeadersMiddleware.php (line 21)
at SecureHeadersMiddleware->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in ETag.php (line 20)
at ETag->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in VerifyCsrfToken.php (line 65)
at VerifyCsrfToken->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in ShareErrorsFromSession.php (line 49)
at ShareErrorsFromSession->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in StartSession.php (line 64)
at StartSession->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in AddQueuedCookiesToResponse.php (line 37)
at AddQueuedCookiesToResponse->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in EncryptCookies.php (line 59)
at EncryptCookies->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in Pipeline.php (line 102)
at Pipeline->then(object(Closure))in Router.php (line 576)
at Router->runRouteWithinStack(object(Route), object(Request))in Router.php (line 535)
at Router->dispatchToRoute(object(Request))in Router.php (line 513)
at Router->dispatch(object(Request))in Kernel.php (line 176)
at Kernel->Illuminate\Foundation\Http\{closure}(object(Request))in Pipeline.php (line 30)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in CheckForMaintenanceMode.php (line 46)
at CheckForMaintenanceMode->handle(object(Request), object(Closure))in Pipeline.php (line 148)
at Pipeline->Illuminate\Pipeline\{closure}(object(Request))in Pipeline.php (line 53)
at Pipeline->Illuminate\Routing\{closure}(object(Request))in Pipeline.php (line 102)
at Pipeline->then(object(Closure))in Kernel.php (line 151)
at Kernel->sendRequestThroughRouter(object(Request))in Kernel.php (line 116)
at Kernel->handle(object(Request))in index.php (line 53)

The issue seems very straight-forward to solve :). Line 19 of your Session class (vendor/pragmarx/tracker/src/Vendor/Laravel/Support/Session.php) contains the following:

$this->minutes = new Minutes(60 * 24 * LaravelSession::get('tracker.stats.days'));

A quick sanity check on the 'LaravelSession::get('tracker.stats.days')' value could fix this... Would performing an 'is_int' check be sufficient, considering any other logic which could contribute to the value being obtained? I will test that theory out, and get back to you on my findings...

rattfieldnz commented 7 years ago

I'm also using version Laravel 5.4.28, and version 3.1.4 of this package. If it will also help, my full Composer file is attached...

composer.json.txt

rattfieldnz commented 7 years ago

Here is a slight modification I have made to the Session class to make it 'work'...

Constructor:

<?php
namespace App\ThirdParty\PragmaRX\Tracker\Vendor\Laravel\Support;

use Illuminate\Support\Facades\Input;
use PragmaRX\Tracker\Support\Minutes;
use Session as LaravelSession;

/**
 * Class Session
 *
 * This class is a modified copy of pragmarx/tracker's Session class,
 * will be used until issue at https://github.com/antonioribeiro/tracker/issues/297
 * is resolved (non numeric value for 'days' causing exception/error).
 *
 * @package App\ThirdParty\PragmaRX\Tracker\Vendor\Laravel\Support
 */
class Session
{
    private $minutes;

    public function __construct()
    {
        LaravelSession::put('tracker.stats.days', $this->getValue('days', 1));

        LaravelSession::put('tracker.stats.page', $this->getValue('page', 'visits'));

        $this->minutes = $this->getMinutesFromDays(LaravelSession::get('tracker.stats.days'));
    }

    /**
     * @return Minutes
     */
    public function getMinutes()
    {
        return $this->minutes;
    }

    /**
     * Get total amount of minutes from given amount of days.
     * Returns number of minutes for 1 day by default.
     *
     * @param $days
     *
     * @return \PragmaRX\Tracker\Support\Minutes
     */
    public function getMinutesFromDays($days): Minutes {

        // Use 0 as default number of days.
        // Will return 0 minutes from current time by default,
        // if entered value is not numeric.
        return !is_numeric($days) ?
            new Minutes(60 * 24 * 0) :
            new Minutes(60 * 24 * $days);
    }

    public function getValue($variable, $default = null)
    {
        if (Input::has($variable)) {
            $value = Input::get($variable);
        } else {
            $value = LaravelSession::get('tracker.stats.'.$variable, $default);
        }

        return $value;
    }
}

You will notice the change in the class constructor... I have basically created a function called 'getMinutesFromDays'. This does a basic check to see if the value is numeric - it returns a default value if not, otherwise it returns the intended value generated from the value passed in. This is the simplest fix I came up with; however, it would be good to see if this is sensible enough from other users (and appropriate changes made).

In the new function I have created, I have specified a return type of 'Minutes'. This will only work in PHP 7+ (http://php.net/manual/en/functions.returning-values.php). If you're using an earlier suitable version of PHP, just remove this return type specified (and colon).

If my modification is sensible/good enough, let me know and I'll submit a pull request :).