将url查询参数与控制器一起使用

I am attempting to implement an oembed provider using the Silverstripe framework but have come across an issue.

I have a controller routed from the url /omebed.json and it works fine if I call something like /omebed.json?mediaurl=mymovie.mp4.
However the Oembed standard states it should be /omebed.json?url=mymovie.mp4

But Silverstripe internally checks the $_GET['url'] variable and will attempt to route to that page/controller. So SilverStripe is trying to route to /mymovie.mp4 skipping my controller and hitting the ErrorPage_Controller creating a 404.

I'm thinking im going to have to extend the ErrorPage_Controller and rejig it if the url is oembed.json, but this seems a little hackish.

Any suggestions?

Cheers

Extending on @Stephen's answer, here is a way to get around that issue without duplicating main.php and without modifying it directly.

What I did was create a _ss_environment.php file which is added early on in the loading process of Silverstripe.

_ss_environment.php

global $url;
$url = $_GET['raw_url'];
if (isset($_GET['url']))
{
    unset($_GET['url']);
}

// IIS includes get variables in url
$i = strpos($url, '?');
if($i !== false)
{
    $url = substr($url, 0, $i);
}

.htaccess

RewriteCond %{REQUEST_URI} ^(.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.php$
RewriteRule .* framework/main.php?raw_url=%1 [QSA]

So here is what is happening:

  • The .htaccess is now using raw_url instead of url
  • _ss_environment.php is being called early in the loading process, setting the global $url variable that main.php normally sets. This is set with raw_url rather than url.
  • To prevent main.php to just override it again when it sees your url query string parameter, it is unset (Silverstripe seems to reset this later as far as my test is concerned).
  • Lastly is a little block of code that main.php would normally run if $_GET['url'] is set, copied as-is for apparent support in IIS. (If you don't use IIS, you likely won't need it.)

This has a few benefits:

  • No update to main.php allows upgrading Silverstripe slightly easier in the future
  • Runs the minimal amount of code needed to "trick" Silverstripe into thinking it is running normally.

The one obvious drawback to any solution for changing away form the url query string parameter is if anything looks at the parameter directly. With how Silverstripe works, it is more likely that code uses the $url global variable or the Director class rather than looking at the query string for the current URL.

I tested this on a 3.1 site by doing the changes I mentioned and:

  • Creating a controller called TestController
  • In the init function of the controller, I am running the following:

    var_dump($_GET['url']);
    var_dump($this->getRequest()->getVars());
    
  • Visited /TestController?url=abc123, saw the value of both dumps have "abc123" as the value for the URL parameter.
  • Navigated to a few other custom pages on the site to make sure they were still working (no issues that I saw)

Unfortunately, I haven't been able to find documentation for the order of inclusion in regards to _config.php and _ss_environment.php. However, after browsing through the code, I have worked out it is this:

I could probably go on however I think this gives a pretty good picture of what is going on. I don't really see a way around not using the _ss_environment.php file. Nothing else gets included early enough that you can hook into without modifying core code.

I had a quick play with this the other day. And looking at what main.php does it might be best to hack away at it rather than ErrorPage_controller.

For startes SS's default .htaccess file does this:

<IfModule mod_rewrite.c>
    SetEnv HTTP_MOD_REWRITE On
    RewriteEngine On
    # RewriteBase /silverstripe

    RewriteCond %{REQUEST_URI} ^(.*)$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule .* framework/main.php?url=%1&%{QUERY_STRING} [L]
</IfModule>

Note the ?url changing that to something else and then changing main.php's usage as well may/should help or will cause a heap of extra errors and sadness.

To avoid hacking the core/framework, you could change the .htaccess to target a copy of main.php in mysite (with appropriate include changes).