views:

3009

answers:

5

In Java I can write a really basic JSP index.jsp like so:

<% request.getRequestDispatcher("/home.action").forward(request, response); %>

The effect of this is that a user requesting index.jsp (or just the containing directory assuming index.jsp is a default document for the directory) will see home.action without a browser redirect, i.e. the forward happens on the server side.

Can I do something similar with PHP? I suspect it's possible to configure Apache to handle this case, but since I might not have access to the relevant Apache configuration I'd be interested in a solution that relies on PHP alone.

A: 

You can use like:

header ("Location: /path/");
exit;

The exit is need just in case some HTML output was sent before, the header() will not work, so you must sent new header before any output to the browser.

Deniss Kozlovs
This solution involves the client, which is not the case with internal redirect.
MatthieuP
+1  A: 

The trick about Request.Forward is that it gives you a clean, new request to the action you want. Therefore you have no residu from the current request, and for example, no problems with scripts that rely on the java eq of $_SERVER['REQUEST_URI'] being something.

You could just drop in a CURL class and write a simple function to do this:

<?php 
/**
 * CURLHandler handles simple HTTP GETs and POSTs via Curl 
 * 
 * @author SchizoDuckie
 * @version 1.0
 * @access public
 */
class CURLHandler
{

    /**
     * CURLHandler::Get()
     * 
     * Executes a standard GET request via Curl.
     * Static function, so that you can use: CurlHandler::Get('http://www.google.com');
     * 
     * @param string $url url to get
     * @return string HTML output
     */
    public static function Get($url)
    {
       return self::doRequest('GET', $url);
    }

    /**
     * CURLHandler::Post()
     * 
     * Executes a standard POST request via Curl.
     * Static function, so you can use CurlHandler::Post('http://www.google.com', array('q'=>'belfabriek'));
     * If you want to send a File via post (to e.g. PHP's $_FILES), prefix the value of an item with an @ ! 
     * @param string $url url to post data to
     * @param Array $vars Array with key=>value pairs to post.
     * @return string HTML output
     */
    public static function Post($url, $vars, $auth = false) 
    {
       return self::doRequest('POST', $url, $vars, $auth);
    }

    /**
     * CURLHandler::doRequest()
     * This is what actually does the request
     * <pre>
     * - Create Curl handle with curl_init
     * - Set options like CURLOPT_URL, CURLOPT_RETURNTRANSFER and CURLOPT_HEADER
     * - Set eventual optional options (like CURLOPT_POST and CURLOPT_POSTFIELDS)
     * - Call curl_exec on the interface
     * - Close the connection
     * - Return the result or throw an exception.
     * </pre>
     * @param mixed $method Request Method (Get/ Post)
     * @param mixed $url URI to get or post to
     * @param mixed $vars Array of variables (only mandatory in POST requests)
     * @return string HTML output
     */
    public static function doRequest($method, $url, $vars=array(), $auth = false)
    {
     $curlInterface = curl_init();

     curl_setopt_array ($curlInterface, array( 
      CURLOPT_URL => $url,
      CURLOPT_CONNECTTIMEOUT => 2,
      CURLOPT_RETURNTRANSFER => 1,
      CURLOPT_FOLLOWLOCATION =>1,
      CURLOPT_HEADER => 0));

     if (strtoupper($method) == 'POST')
     {
      curl_setopt_array($curlInterface, array(
       CURLOPT_POST => 1,
       CURLOPT_POSTFIELDS => http_build_query($vars))
      ); 
     }
     if($auth !== false)
     {
        curl_setopt($curlInterface, CURLOPT_USERPWD, $auth['username'] . ":" . $auth['password']);
     }
     $result = curl_exec ($curlInterface);
     curl_close ($curlInterface);

     if($result === NULL)
     {
      throw new Exception('Curl Request Error: '.curl_errno($curlInterface) . " - " . curl_error($curlInterface));
     }
     else
     {
      return($result);
     }
    }

}

Just dump this in class.CURLHandler.php and you can do this:

ofcourse, using $_REQUEST is not really safe (you should check $_SERVER['REQUEST_METHOD']) but you get the point.

<?php
include('class.CURLHandler.php');
die CURLHandler::doRequest($_SERVER['REQUEST_METHOD'], 'http://server/myaction', $_REQUEST);
?>

Ofcourse, CURL's not installed everywhere but we've got native PHP curl emulators for that.

Also, this gives you even more flexibility than Request.Forward as you could also catch and post-process the output.

SchizoDuckie
curl is not enabled by default in php. Also curl will make another http request witch means more cpu usage.
Ivan
Yes, but .forward does something like this too FAIK. You do not have any environmental stuff that's associated with the current request. Therefore, another 'http request' has to happen, you do not want to execute this script in the same scope. as it can cause problems with defined variables.
SchizoDuckie
+1  A: 

I believe one of the closest analogous methods would be to use the virtual() function on while running php as an apache module.

virtual() is an Apache-specific function which is similar to in mod_include. It performs an Apache sub-request.

Zoredache
+1  A: 

If you use an MVC like the Zend Framework provides you can change the controller action or even jump between controller actions. The method is _forward as described here.

OIS
A: 

If you are concerned about CURL availability then you could use file_get_contents() and streams. Setting up a function like:

function forward($location, $vars = array()) 
{
    $file ='http://'.$_SERVER['HTTP_HOST']
 .substr($_SERVER['REQUEST_URI'],0,strrpos($_SERVER['REQUEST_URI'], '/')+1)
 .$location;

    if(!empty($vars))
    {
         $file .="?".http_build_query($vars);
    }

    $response = file_get_contents($file);

    echo $response;
}

This just sets up a GET, but you can do a post with file_get_contents() as well.

null
There are a lot things wrong with that approach. For one, it won't pass along any headers and it will only work with a GET type request.
troelskn
and it wil fail miserably if PHP is running in safe mode...
SchizoDuckie