PHP включить из URL-адреса, который перенаправляет

Я унаследовал плохой сайт, где в нашей сети есть много (читай: много) размещенных сайтов, которые делают это:

include "http://www.example.com/news.php";

Да, я знаю, что это плохо, небезопасно и т. д., и что это должно быть echo file_get_contents(...); или что-то в этом роде (вывод «news.php» — это просто HTML), но, к сожалению, это то, что они сейчас используют, и мы не можем легко изменить это.

Раньше работало нормально, до вчерашнего дня. Мы начали 301-перенаправлять все запросы с www.example.com только на example.com. Кажется, что PHP не следует этому перенаправлению, когда люди включают версию с www, поэтому это перенаправление ломает множество сайтов.

Подводя итог: есть ли способ заставить PHP следовать этим перенаправлениям? Я могу внести изменения только на стороне example.com или через конфигурацию всего сервера.


person Bart van Heukelom    schedule 22.12.2009    source источник
comment
Какое точное сообщение об ошибке (или сообщения) вы получаете с error_reporting=E_ALL (или выше)?   -  person VolkerK    schedule 22.12.2009
comment
Перемещено навсегда Документ перемещен сюда.   -  person Bart van Heukelom    schedule 22.12.2009
comment
Это не похоже на сообщение об ошибке php ;-) Возможно, веб-сервер отправляет не код состояния 301, а 200 ok.   -  person VolkerK    schedule 22.12.2009
comment
Есть ли разница между include($foo) и echo file_get_contents($foo) (для удаленных файлов)? Я так не думаю...   -  person Franz    schedule 22.12.2009
comment
Начиная с php 5.2 есть allow_url_include, но это вызовет другое сообщение об ошибке.   -  person VolkerK    schedule 22.12.2009
comment
Есть разница. Не в этом случае, но если бы удаленный сайт вернул PHP-код, он был бы выполнен с включением (и, очевидно, не с FGC)   -  person Bart van Heukelom    schedule 22.12.2009
comment
@Franz: действительно есть: echo распечатает все, что получит. include запустит его как PHP-скрипт.   -  person Piskvor left the building    schedule 22.12.2009
comment
@Барт: Правда? Ничего себе, я этого не знал, я думал, что include 'http://...' просто вернет результаты и ничего не выполнит (хотя мне всегда было интересно, для чего еще allow_url_include будет предназначено: P). Спасибо за эту информацию.   -  person Franz    schedule 22.12.2009
comment
@Franz: см. so.piskvor.org/1945814 для POC.   -  person Piskvor left the building    schedule 23.12.2009


Ответы (4)


Вы сказали в комментарии: «Я могу пойти и изменить все включения, но это будет очень много работы».

Да. Это «плохой, небезопасный, но-у меня-нет-причины-изменять-его-код» возвращается, чтобы укусить вас. Это будет много работы; но теперь есть веская причина, чтобы изменить его. Иногда навести порядок в старом беспорядке — это самый простой, хотя и не самый легкий выход из него.

Правка: я не имел в виду "это ваш код и ваша вина" - скорее, "плохой код часто требует много работы, чтобы исправить, но обычно это меньше работы, чем продолжать нагромождение хаков вокруг него для вечность, просто чтобы она работала».

Что касается «пойти и изменить», я бы рекомендовал использовать cURL - работает намного лучше, чем PHP-оболочки HTTP fopen.

person Piskvor left the building    schedule 22.12.2009
comment
Что ж, в свою защиту скажу, что я не придумывал плохой код. мне досталось по наследству :( - person Bart van Heukelom; 22.12.2009
comment
@Bart van Heukelom: Извините, я был слишком пренебрежительным в оригинальной версии. Не хотел показаться таким высокомерным. - person Piskvor left the building; 22.12.2009

Вы не можете использовать завиток? В curl_setopt есть возможность следовать перенаправлениям.

person AntonioCS    schedule 22.12.2009
comment
Я думаю, что нет, потому что, к сожалению, это то, что они используют сейчас, и мы не можем легко это изменить ;-) - person VolkerK; 22.12.2009
comment
Ну, он действительно говорит: «Не могу ||легко|| изменить это'. Так что изменить это невозможно - person AntonioCS; 22.12.2009

Начнем с перенаправления http-ответа.

<?php
error_reporting(E_ALL);
var_dump( get_headers('http://www.example.com/news.php') );
// include 'http://www.example.com/news.php'

Вывод должен содержать HTTP/1.0 301 Moved Permanently в качестве первой записи и Location: http://example.com/news.php где-то.

person VolkerK    schedule 22.12.2009
comment
Да, но я не могу изменить этот код, иначе я бы просто изменил его на file_get_contents. Я должен сделать это на стороне example.com. - person Bart van Heukelom; 22.12.2009
comment
...или через общесерверную настройку PHP. Что ж, я могу пойти и изменить все включения, но это будет много работы :p - person Bart van Heukelom; 22.12.2009
comment
Это просто тестовый скрипт. Поместите его в любой каталог, где include 'http://www.example.com/news.php' не работает должным образом, и проверьте вывод. - person VolkerK; 22.12.2009
comment
И если http/1.x 310 ... не является первой строкой или если в результате нет строки Location: xyz, это то, что мешает php следовать перенаправлению (потому что это не перенаправление). Если он есть, мы должны проверить более маловероятные причины (какими бы они ни были). - person VolkerK; 22.12.2009

Я не думаю, что какое-либо из этих решений, предоставляемых самим PHP, поможет... Я просто не думаю, что какое-либо из них следует за заголовками, а что нет. Как бы то ни было, я считаю, что такое поведение правильное: вы запрашиваете результат определенного запроса и получаете его. Тот факт, что результат говорит вам искать в другом месте, сам по себе является действительным результатом.

На вашем месте я бы посмотрел на cURL. Для него есть расширение PHP, и оно позволит вам указать ему следовать заголовкам и добраться туда, куда вы пытаетесь попасть. Если это непригодно для использования (например, вам абсолютно необходимо использовать тот подход, которым вы сейчас пользуетесь), вам нужно будет отменить перенаправления на «исходном» сервере: возможно, вы могли бы вернуть информацию или перенаправление на основе запрос IP-адреса или что-то подобное?

person Narcissus    schedule 22.12.2009
comment
Оболочка http fopen следует заголовкам Location: xyz, если не указано иное (например, с помощью get_headers()) - person VolkerK; 22.12.2009