file_exists или getimagesize работают только с локальными абсолютными путями к файлам, но не с URL-адресами в PHP.

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

Я использую следующий код для отображения либо стандартного логотипа на сайте интрасети, либо пользовательского логотипа:

if(L_HEADER) {
  $logo = L_HEADER;
}
else {
  $logo = 'logo.png';
}
$properties = getimagesize(CONFIG_URL . 'images/' . $logo)

L_HEADER и CONFIG_URL — это константы с предопределенными значениями (другой файл):

  1. L_HEADER содержит "opb_beta.png"
  2. CONFIG_URL содержит "http://billing.intranet.opb/"

Конкатенация работает правильно, что также подтверждается сообщением об ошибке лог-файла Apache:

Предупреждение PHP: getimagesize(http://billing.intranet.opb/images/opb_beta.png): не удалось открыть поток: HTTP-запрос не выполнен! HTTP/1.1 404 NOT FOUND
в /var/www/billing/templates/header.inc.php в строке 42

Итак, первый очевидный вывод: путь неверный. Но это не так, поверьте. Я проверил это, как 1.000 раз. Фактически, первое любопытство заключается в том, что изображение отображается и правильно ссылается на пару строк ниже в коде того же файла:

echo '<img src="' . CONFIG_URL . 'images/' . $logo . '"  
  width="' . $properties[0] . '" height = "' . $properties[1] . '" />";

Когда я получаю упомянутую выше ошибку, высота и ширина равны «0», но, глядя на исходный код, URL-адрес в порядке, доступ к нему вручную открывает изображение, и при замене ширины и высоты ручными значениями изображение отображается просто отлично .

Тем не менее, более любопытно (а также мой текущий finx), при изменении getimagesize на следующий он работает просто отлично:

$properties = getimagesize($_SERVER['DOCUMENT_ROOT'] . /public_html/images/' . $logo);

Я упомяну, что я использую перенаправление Apache; вот почему в URL-адресе вы не видите «public_html», а в абсолютном пути второго примера вы его видите.

То же самое происходит с «file_exists». URL-адрес не работает, работает абсолютный локальный путь для того же файла.

Еще одно любопытство: в другом фрагменте кода я проверяю наличие обновлений в Интернете. Там я использую «настоящий» общедоступный URL-адрес с file_exists и fopen. Я выгляжу так и отлично работает:

if(file_exists('http://desk.co.cr/df_stable.txt') {
  if(($handle = fopen('http://desk.co.cr/df_stable.txt', 'r')) !== FALSE) {
    // some other code
  }
}

Теперь то, что я уже проверил:

  • Права доступа к файлам установлены правильно для всего пути, при этом www-data является группой и владельцем всех файлов, а также доступом для чтения и записи для файла изображения.
  • для параметра allow_url_fopen установлено значение «Вкл.».
  • open_basedir имеет значение «нет значения», и в определениях виртуальных хостов Apache нет переопределения.
  • файл определенно существует, и синтаксис + путь верны.

Немного справочной информации:

  • Сервер работает на Ubuntu 14.04 LTS.
  • Апач 2.4.7
  • PHP 5.5.9

Пока у меня нет идей.


person Sebastian    schedule 16.09.2015    source источник
comment
Вы смотрели в access_log, чтобы увидеть, какой URL-адрес действительно был запрошен? возможно, у вас есть шаткий переписать.   -  person Marc B    schedule 17.09.2015
comment
Хост файл сервера может быть? Что происходит, когда вы выполняете nslookup на сервере для домена?   -  person Dan Blows    schedule 17.09.2015
comment
@MarcB Да, я проверил access_log и error_log. Оба показывают правильный URL. Я даже скопировал + вставил его в браузер, чтобы проверить, и изображение отображается нормально.   -  person Sebastian    schedule 18.09.2015
comment
@Blowski: Ваш комментарий идет в том же направлении, что и комментарии @IMSoP ниже. На самом деле, чтобы отличить интранет от любого другого нормального веб-сайта, здесь работает dnsmasq. nslookup показывает nslookup billing.intranet.opb Server: 127.0.0.1 Address: 127.0.0.1#53 Name: billing.intranet.opb Address: 158.120.100.152 Не спрашивайте, почему этот IP. Это локальный IP-адрес нашей локальной сети - длинная история ;-)   -  person Sebastian    schedule 18.09.2015


Ответы (1)


В вашем вопросе скрыта жизненно важная подсказка, которую вы уже нашли:

Еще одно любопытство: в другом фрагменте кода я проверяю наличие обновлений в Интернете. Там я использую «настоящий» общедоступный URL-адрес.

Таким образом, URL-адрес, который не работает, относится к частному домену, который ваш компьютер настроен для поиска правильного IP-адреса. Скорее всего, это было сделано либо путем запуска локального DNS-сервера, либо путем настройки файла «hosts» ПК для жесткого кодирования адреса для этого домена.

Однако, когда вы запрашиваете URL-адрес с самого сервера, в игру вступает совершенно другая конфигурация DNS, поэтому, вероятно, он просто не знает, где находится этот сервер, даже если он сам! Вам необходимо настроить параметры DNS сервера или /etc/hosts в соответствии с тем, что установлено на вашем ПК.

Одна из связанных с этим возможностей заключается в том, что сервер настроен на такой же поиск адреса, но маршрутизатор не позволяет ему подключаться к себе таким образом. Один из способов обойти это — указать запись файла hosts на 127.0.0.1 и настроить Apache для соответствия.

Если вы можете получить командную строку на сервере, вы можете попробовать:

nslookup billing.intranet.opb
# if that returns the right IP address, see if it's reachable:
ping billing.intranet.opb
# and if it's the right server, it will be listening on port 80:
telnet billing.intranet.opb 80
# telnet will either time out, or connect and give you a prompt

Если telnet подключается, вы даже можете написать HTTP-запрос вручную (пустая строка завершает запрос; не занимайте слишком много времени, иначе сервер выйдет из строя), например:

HTTP/1.1 HEAD /
Host: billing.intranet.opb
person IMSoP    schedule 16.09.2015
comment
Вы правы — здесь работает dnsmasq, который заботится о том, какие запросы уходят, а какие остаются внутри. Жестко закодированные файлы hosts не используются. Ваш последний комментарий о возможно, но я понятия не имею, как это проверить. - person Sebastian; 18.09.2015
comment
@IMoSP Извините за поздний ответ, но вот. Прежде всего, спасибо за ваш отзыв. Я выполнил другую команду, и nslookup возвращает правильный IP-адрес, как и ping. billing.intranet.opb также доступен через telnet, и заголовки возвращаются правильно (я пробовал обычные HTTP и GET). - person Sebastian; 22.09.2015