如何在Laravel创建请求实例之前替换查询字符串中的某些编码字符?

huangapple go评论82阅读模式
英文:

How to replace some encoded character in a query string before Laravel create a Request instance?

问题

When the query string separator & is encoded with its corresponding value %26, the request cannot extract the query parameters correctly.

On my web application, I do not encode this character and I have no controls on how it's structured before hitting my API.

I did a debug trace of the Request object in the controller method and this URL my.api.com/api/productcategory/catalogue?sort_by%5bcountry.name_en%5d=asc&sort_by%5bproductbrand.name%5d=asc&sort_by%5bproduct.name%5d=asc&sort_by%5bvintage.vintage%5d=asc&per_page=25&page=1&lang=en returns the correct following query parameters:

query: Symfony\Component\HttpFoundation\ParameterBag {#60 ▼
    #parameters: array:4 [▼
      "sort_by" => array:4 [▶]
      "per_page" => "25"
      "page" => "1"
      "lang" => "en"
    ]
  }

On the other hand, when the & is encoded as in this URL my.api.com/api/productcategory/catalogue?sort_by%5bcountry.name_en%5d=asc%26sort_by%5bproductbrand.name%5d=asc%26sort_by%5bproduct.name%5d=asc%26sort_by%5bvintage.vintage%5d=asc%26per_page=25%26page=1%26lang=en, the query parameter are wrongly extracted like this:

query: Symfony\Component\HttpFoundation\ParameterBag {#60 ▼
    #parameters: array:1 [▼
      "sort_by" => array:1 [▼
        "country.name_en" => "asc&sort_by[productbrand.name]=asc&sort_by[product.name]=asc&sort_by[vintage.vintage]=asc&per_page=25&page=1&lang=en"
      ]
    ]
  }

Is there a way to intercept the query and do a str_replace('%26', '&', $theQuery) before it gets process by the Request object?

I'm Using Laravel 6.2 with PHP 7.2 on Ubuntu 22.04

英文:

When the query string separator & is encoded with its corresponding value %26, the request cannot extract the query parameters correctly.

On my web application, I do not encode this character and I have no controls on how it's structured before hitting my API.

I did a debug trace of the Request object in the controller method and this URL my.api.com/api/productcategory/catalogue?sort_by%5bcountry.name_en%5d=asc&sort_by%5bproductbrand.name%5d=asc&sort_by%5bproduct.name%5d=asc&sort_by%5bvintage.vintage%5d=asc&per_page=25&page=1&lang=en returns the correct following query parameters:

query: Symfony\Component\HttpFoundation\ParameterBag {#60 ▼
    #parameters: array:4 [▼
      "sort_by" => array:4 [▶]
      "per_page" => "25"
      "page" => "1"
      "lang" => "en"
    ]
  }

On the other hand, when the & is encoded as in this URL my.api.com/api/productcategory/catalogue?sort_by%5bcountry.name_en%5d=asc%26sort_by%5bproductbrand.name%5d=asc%26sort_by%5bproduct.name%5d=asc%26sort_by%5bvintage.vintage%5d=asc%26per_page=25%26page=1%26lang=en, the query parameter are wrongly extracted like this:

query: Symfony\Component\HttpFoundation\ParameterBag {#60 ▼
    #parameters: array:1 [▼
      "sort_by" => array:1 [▼
        "country.name_en" => "asc&sort_by[productbrand.name]=asc&sort_by[product.name]=asc&sort_by[vintage.vintage]=asc&per_page=25&page=1&lang=en"
      ]
    ]
  }

Is there a way to intercept the query and do a str_replace('%26', '&', $theQuery) before it gets process by the Request object?

I'm Using Laravel 6.2 with PHP 7.2 on Ubuntu 22.04

答案1

得分: 1

根据Andrew的建议,以下是使用中间件的解决方案,其中它被用于每个API路由。

class URLMonitorMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        // 解析完整URL并返回其组成部分
        $parsedUrl = parse_url($request->fullUrl());
        // 不一定总是有查询字符串...!
        if (isset($parsedUrl['query'])) {
            // 解码查询字符串
            $decodedQuery = urldecode($parsedUrl['query']);
            // 将查询字符串解析为变量
            parse_str($decodedQuery, $query);
            // 用查询设置替换当前参数。
            $request->replace($query);
        }

        return $next($request);
    }
}
英文:

As per Andrew suggestion, here is the solution using a Middleware, where it is called for each API routes.

class URLMonitorMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        // Parse the full URL and return its components
        $parsedUrl = parse_url($request->fullUrl());
        // There may not always be a query string...!
        if (isset($parsedUrl['query'])) {
            // Decode the query
            $decodedQuery = urldecode($parsedUrl['query']);
            // Parses the query into variables
            parse_str($decodedQuery, $query);
            // Replaces the current parameters with the query set.
            $request->replace($query);
        }

        return $next($request);
    }
}

答案2

得分: -1

I think you are looking for middleware in this situation. It allows you to manage requests before they enter the application. You can manipulate the request object. Middleware can be applied to every single route globally or selectively used on certain routes only.

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class BeforeMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        // Perform action

        return $next($request);
    }
}

Laravel Middleware

When dealing with the request object, Laravel has built-in methods for overwriting attributes. You can access specific attributes with:

$data = $request->all();
// $data['sort_by']

But in your case, you can access the URL and modify it with:

$request->fullUrl()

Accessing the request

英文:

I think you are looking for middleware in this situation. It allows you to manage requests before they enter the application. You can manipulate the request object. Middleware can be applied to every single route globally or selectively used on certain routes only.

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class BeforeMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        // Perform action
 
        return $next($request);
    }
}

Laravel Middleware

When dealing with the request object, Laravel has built in methods for overwriting attributes. You can access specific attributes with:

$data = $request->all();
// $data['sort_by'] 

But in your case you can access the url and modify it with:

$request->fullUrl()

Accessing the request

huangapple
  • 本文由 发表于 2023年6月29日 23:15:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76582411.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定