0

In Drupal 8 the Symfony HttpKernel Component offers a nice way to make an internal sub-request (forward a request to another page without changing the URL). I'm wondering if there is an ad hoc way to mimic some parts of this idea with existing Drupal 7 APIs.

I have a use case where I need to provide a central path that delivers XML, but for various reasons that XML must be fetched from embedded content on a separate path, that I don't control, but that's also delivered via the Drupal menu system. The specifics of the use case are probably beyond the scope of this specific question, so I won't elaborate too much there. Anyway, I've had some success creating a menu callback that simply calls menu_execute_active_handler() internally, and then renders the output. It gets the path to use for the sub-request via a query string. Something like:

// The XML we are looking for will be inside a sub-requested page at path
// xml-source-path and inside a <script id="xml-source-id"> block.
$query = drupal_get_query_parameters();
if (isset($query['xml-source-path']) && isset($query['xml-source-id'])) {
  $source = drupal_render_page(menu_execute_active_handler($query['xml-source-path'], FALSE));
  // Search for the XML within the raw sub-request markup.
  $matches = array();
  preg_match('/<script[^>]*id=\"' . $query['xml-source-id'] . '\"[^>]*>(.*)<\/script>/simU', $source, $matches);
  if (!empty($matches[1]) && strpos($matches[1], '<?xml') === 0) {
    $xml = $matches[1];
    // ----- Misc other processing to fetched $xml -----
    // Set headers and directly print result.
    drupal_add_http_header('Content-type', 'application/xml; charset=utf-8');
    print($xml); 
  }
}

Though this works great for most of my own tests, I'm really not sure if I'm breaking any best practices here, or worse, introducing any security concerns. Since the callback itself is triggered from within a call to menu_execute_active_handler() (in index.php itself) is a recursive call like this potentially problematic? Also, would the fact that I'm accepting the path for sub-request via a query string provide any way for this menu callback to be used for malicious purposes? I really don't think so, but I'd feel much better if I could confirm, or identify a better way.

  • Posted my D7 code below, but I need this in D8. How did you do this in D8? – Robin Jan 9 '15 at 14:31
  • I'm also working on the D8 solution to this now. What I've got was gleaned from this example sub-request controller along with some notes from non-Drupal projects that use Symfony like this. Once I commit some changes I can certainly share the link to the Drupal repo as well. – rjacobs Jan 10 '15 at 4:14
  • Here's another D8 controller example (see JuiceboxXmlControllerBase::fetchXmlSubRequest()). This is the direct D8 equivalent to the D7 example I posted in the question. – rjacobs Feb 5 '15 at 19:02
0

I do this as following:

// We mimic menu_execute_active_handler().
$router_item = menu_get_item($href);
if ($router_item['access']) {
  if ($router_item['include_file']) {
    require_once DRUPAL_ROOT . '/' . $router_item['include_file'];
  }
  $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
}
else {
  // Access denied.
  $page_callback_result = MENU_ACCESS_DENIED;
}

if (is_array($page_callback_result)) {
  // Render array.
  $output .= drupal_render($page_callback_result);
}
elseif (is_string($page_callback_result)) {
  // Render string.
  $output .= $page_callback_result;
}
  • I suppose this makes sense as it gives you full control over the process. From what I can see however, this logic is pretty much identical to what happens when you call menu_execute_active_handler() with the $delivery param set to FALSE. This just makes me wonder if there is any advantage to doing things this way as opposed to just re-using the core menu_execute_active_handler() function? – rjacobs Jan 10 '15 at 4:07
  • I think there are still some hanging questions with all this, but I suppose this is the cleanest way to do things in most cases. I'm still not sure if it's better than re-triggering menu_execute_active_handler() directly, but I like the fact that it offers a bit more control. – rjacobs Feb 5 '15 at 18:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.