1

I'm using Kohana 3.2, and I want to be able to call another script (unrelated to Kohana, outside of its 'jurisdiction') that returns a application/json response. When I tried using:

$response = json_decode(Request::factory('/scripts/index.php?id=json')->execute()->body());

It errors out saying there's no route to scripts/index.php. So I tried using Request_Client_External

Request_Client_External::factory()->execute(Request::factory('/scripts/index.php?page=s'))->body();

Gives me Request_Exception [ 0 ]: Error fetching remote /scripts/index.php?page=s [ status 0 ] Could not resolve host: scripts; Host not found. It appears it need a full flagged URL using http/https, but how to avoid the overhead of it doing a real external request?

Doing a

Request::factory(url::site('/scripts/index.php?page=s', 'http'))->execute()

works but is it considered "external"?

pocesar
  • 6,860
  • 6
  • 56
  • 88

1 Answers1

1

The short answer to your question is that the only way to use Request::factory()->execute() to achieve that is to use pass it the full url (with whatever "overhead" that entails, which shouldn't be too much: your server's probably quite good at talking to itself).

Otherwise, ideally you'd put the functionality of scripts into a library and call that from Kohana. However it sounds like that's not an option for you. If you have to leave /scripts/index.php untouched and insist on an 'internal' request, you could use PHP's output buffering, as illustrated below. But there are a bunch of caveats so I wouldn't recommend it: the best way is passing a full url.

    // Go one level deeper into output buffering
    ob_start();

    // Mimic your query string ?id=json (see first caveat below)
    $_GET = $_REQUEST = array('id' => 'json');
    // Get rid of $_POST and $_FILES
    $_POST = $_FILES = array();

    // Read the file's contents as $json
    include('/scripts/index.php');
    $json = ob_get_clean();

    $response = json_decode($json);

Some caveats.

Firstly, the code changes $_GLOBALS. You probably don't use these in your Kohana code (you use $this->request->get() like a good HMVCer, right?). But in case you do, you should 'remember' and then restore the values, putting $old_globals = $GLOBALS; etc. before the above code, and $GLOBALS = $old_globals; after.

Sessions: if your /scripts/index.php uses `session_start() this will cause a warning if you've already started a session at this point in Kohana.

Note that all variables set in scripts/index.php will remain set in the context you're in. If you want to avoid possible conflicts with that context, you'd start a new context, i.e. wrap the above into its own function.

Finally, you'd also need to make sure that /scripts/index.php doesn't do anything like Kohana::base_url = 'something_else', or touch any other static attributes, or do something catastrophic using this.

Jonathan
  • 1,089
  • 1
  • 7
  • 10
  • good explanation, but I guess I'll just stick the the `Request::factory(url::site('/scripts/index.php','http'))` and let the host do it via HTTP anyway. just a shame I can't call that folder without making an extra HTTP call – pocesar Feb 16 '13 at 09:43
  • 1
    Sounds wise! If your aim is to avoid making an HTTP request (why?), I just thought: you could use `exec` to start a new (CLI) instance of PHP, like this: `$response = json_decode(exec("php -r '\$_SESSION = json_decode('\''".json_encode($_SESSION)."'\'', TRUE); \$_REQUEST[\"id\"] = \$_GET[\"id\"] = \"json\"; include(\"/scripts/index.php\");'"));`. You might want to pass `$_COOKIE` the same way I've passed `$_SESSION`. But yeah, an HTTP request is the way to go. – Jonathan Feb 17 '13 at 00:04