Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Code profiler in ajax
  • Before opening an issue on github, I wanted to make sure I should.

    It's started with an update I did (1.9.x). The behavior wasn't there before. So now, every ajax call that doesn't return $this->response() contain all code profiler script (When it's enabled in config).

    Not a problem for the large majority of cases, but, for example, when you define a router() method in a controller which return a new response object, the response contain the code profiler content.

    So should I create an issue for that ? Or do you have another way to avoid this ?
  • Hmm, that shouldn't be the case. Please create an issue for it, I'll have a look in the meantime.
  • According to the code:

    $headers = headers_list();
    $show = true;

    foreach ($headers as $header)
    {
        if (stripos($header, 'content-type') === 0 and stripos($header, 'text/html') === false)
        {
            $show = false;
        }
    }

    It should not show profiler data if the content-type of the response isn't "text/html".

    The REST and Hybrid controllers are made to either return an array, or use $this->response() to set the response. If you return anything else, it will drop the return value, and return $this->response (the property) instead. 

    You say this happens when $this->response() isn't returned. What is returned then? Can you give an example so I can test?
  • Here is my method (It's a controller Controller_Public_Private, which prevent access for non logged in user, except if the method is in a "allowed_methods" property in child controller

    public function router($ressource, $arguments) 
    {
        $allowed = false;

        // Check if method is in allowed access array, or block
        if( isset($this->_allowed_methods) )
        {
            $allowed = in_array(Request::active()->action, $this->_allowed_methods);
        }

        if(Input::is_ajax())
        {
            if( ! $allowed and ! Auth::check())
            {
                return Response::forge(Format::forge(['error' => 'must_login'])->to_json(), 403);
            }
        }

        if( ! $allowed and ! Auth::check() )
        {
            $this->must_login();
        }

        parent::router($ressource, $arguments);
    }

    The frontend ajax call (jQuery .ajax() method with dataType set to 'json', and also the .json in the url) set the Accept header as following :

    Accept:
    application/json, text/javascript, */*

    According to your code, It shouldn't behave like that, since the strpos should be false.

    Maybe a good lead could be dont show profilter if Input::is_ajax() is true before checking accept headers ?

  • The code snippet I posted doesn't check the accept header, it checks the header set in the Response.

    Just calling is_ajax() isn't sufficient, there are lots of other output formats that are not related to ajax calls, that also require profiler output to be suppressed.

    So, is it a plain controller, or a controller that extends Controller_Rest or Controller_Hybrid?

    A standard Controller always returns text/html, Controller_Rest and Controller_Hybrid set the content type on the response based on the accept header and the selected response format.

    If it does extend Controller_Rest or Controller_Hybrid, you shouldn't return a standard Response (because that doesn't contain the correct settings), don't use

    return Response::forge(Format::forge(['error' => 'must_login'])->to_json(), 403);

    but use

    $this->response(Format::forge(['error' => 'must_login'])->to_json(), 403);
    return;
  • OK thanks it's noted, but that doesn't solve it. 

    The Controller is extended from Controller_Hybrid. I replaced the piece of code with yours, and still got the profiler in response.
  • Ok, that means I can test it here, and should be able to see the same result.
  • Ok, first results:

    return $this->response($data, 403);

    and 

    $this->response($data, 403);
    return;

    and 

    return $data;

    all work, but

    return Response::forge($data);

    doesn't, it throws an exception as Response outputs HTML, and $data is an array, which isn't compatible.

    and 

    return Response::forge(Format::forge($data)->to_json(), 403);

    doesn't, because altough the payload is now a string (thanks to the Format), the reponse is still text/html, which causes the profiler output to be attached.

    (tested with Postman to create valid ajax requests)

    This is obvious, since you decide here not to use the controllers REST response object, but your own response object. So you have to make sure yourself that it is setup properly.
  • So, root cause of the problem is that you return a "text/html" response on an ajax call, instead of an "application/json" response.

    Test code used:

    public function action_response($param = false)
    {
        $this->format = 'json';
        $data = array('this', 'is', 'test', '#', $param);

        switch ($param)
        {
            case "1":
                return $this->response($data, 403);

            case "2":
                $this->response($data, 403);
                return;

            case "3":
                $this->http_status = 403;
                return $data;

            case "4":
                return Response::forge(Format::forge($data)->to_json(), 403);

            case "5":
            default:
                return Response::forge($data, 403);
        }
    }

  • So the $this->format = 'json'; solved the problem :

    if(Input::is_ajax())
    {
            if( ! $allowed and ! Auth::check())
            {
    // Without this, the code profiler content would be in the response
                    $this->format = 'json';

                    $this->response(['error' => 'must_login'], 403);

                    return;
            }
    }

    So even with the controller response object, why must we set the format to make it wor ? I believed that controller REST and Hybrid's response content type was set using request accept header ?
  • Yes, it is (unless that is disabled in the config).

    The REST Controller does autodetection of the format in the router method (which the Hybrid Controller inherits). For how and in which order, see https://fuelphp.com/docs/general/controllers/rest.html#/format_determination.
     
    This will set $this->format. If in your case the format isn't detected as "json" as your reply suggests, you will have to debug your ajax request, so you can understand why. For example, with jQuery ajax calls you need to set dataType: "json" to set the correct http accept header.

    When you call $this->reponse(), it will make sure the Response object of the Contoller is set with the correct reponse headers. Previously, you used Response::forge() instead of $this->response, so that didn't happen.

    So, debug your requests to see where it goes wrong. Even if you can't change them, at least you'll know why you have to hardcode the return format there to make it work.
  • That's why i'm asking you, because from the beginning the request dataType was set to json, and the accept header is as follow : 

    application/json, text/javascript, */*

    But it's not a big deal if I don't found the answer, given that it works with the harcoded format.

    But before I update Fuel to latest 2 month ago maybe, The profiler wasn't in response with the same ajax call. So it's more like are you sure it's not a fuel issue ?
  • I'm not sure at all. 

    If it works if you hardcode it, and doesn't if you don't, it's either the request that is wrong, or the processing of it. I've only tested sofar with "application/json", and that worked fine. I'll rerun the tests with that accept header.
  • HarroHarro
    Accepted Answer
    Reran the tests with $_SERVER['HTTP_ACCEPT'] set to "application/json, text/javascript, */*", and that selects the "json" return format without problems.

    So unfortunately I'm not any closer to finding out why that doesn't happen in your case.

    Since I want to make sure it's not a framework issue somewhere, could you please find some time to do some debugging of the _detect_format() method in the REST controller, and check what it returns, and why?
  • Found why : I was calling the parent router method at the end, so the format property was null. Logic issue in my code so. No problem with fuel.

    Thanks -
  • Thanks for the feedback, good you found the issue.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion