В идеале, для того, чтобы cURL в PHP автоматичесски "отлавливал" переадресацию по HTTP-заголовку 301 или 302, следует использовать константу CURLOPT_FOLLOWLOCATION, но на практике, как часто это бывает, все не так просто. В случае использования safe_mode или open_basedir php огорчает такой ошибкой: Warning: curl_setopt() : CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set in ... Поскольку safe_mode, а особенно, open_basedir используются весьма часто, и возможности их отключить зачастую нет, необходимо использовать обходные пути.

Для начала следует принять заголовки, отдаваемые сервером. Реализуется это так - PHP-скрипт ниже:

$ch = curl_init('http://yandex.ru');  
curl_setopt($ch, CURLOPT_HEADER, 1);  // Отображать в ответе заголовки
curl_setopt($ch, CURLOPT_NOBODY, 1);  // Неотображать текст самой страницы
$header = curl_exec($ch);  
curl_close($ch);  
 
echo $header;

Изучив заголовки, полученные в ответе при помощи cURL, находим Location - это и будет адрес перенаправления.

HTTP/1.1 301 Moved Permanently
Date: Sun, 10 Jul 2011 01:05:45 GMT
Server: Apache/2.2.9 (Unix) mod_perl/2.0.4 Perl/v5.12.1
Location: http://www.yandex.ru/
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=iso-8859-1

Первоначально, Яндекс пересылает всех посетителей, с адреса без www на адрес с www.

Чтобы автоматически переходить по всем редиректам (с защитой от зацикливания), можно использовать код на PHP c cURL и функцию, опубликованную ниже.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://yandex.ru');
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // Сколько сек. ждать ответ сервреа
$page = curl_redir_exec($ch);
$page = curl_exec($ch);

curl_close($ch);

echo $page;
 
function curl_redir_exec($ch)
  {
  static $curl_loops = 0;
  static $curl_max_loops = 20;
  if ($curl_loops >= $curl_max_loops)
    {
    $curl_loops = 0;
    return false;
    }
  curl_setopt($ch, CURLOPT_HEADER, true);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $data = curl_exec($ch);
  list($header, $data) = explode("\n\n", $data, 2);
  $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 
  if ($http_code == 301 || $http_code == 302)
    {
    $matches = array();
    preg_match('/Location:(.*?)\n/', $header, $matches);
    $url = @parse_url(trim(array_pop($matches)));
    if (!$url)
      {
      $curl_loops = 0;
      return $data;
      }
    $last_url = parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
   
    if (!$url['scheme'])
      $url['scheme'] = $last_url['scheme'];
    if (!$url['host'])
      $url['host'] = $last_url['host'];
    if (!$url['path'])
      $url['path'] = $last_url['path'];
    $new_url = $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query']?'?'.$url['query']:'');
    echo $new_url.' --- '.$http_code.'<br>';
    curl_setopt($ch, CURLOPT_URL, $new_url);
    return curl_redir_exec($ch);
    }
  else
    {
    $curl_loops = 0;
    return $data;
    }
  }

Этот скрипт php является готовым решением для перехода по редиректам с помощью cURL.

Полезные ссылки

Официальная документация по cURL (eng)
Примеры использования cURL
Статьи об cURL