Intereting Posts
Как совместить несколько слов в регулярном выражении Показать все строки в таблице mysql, а затем дать возможность удалить определенные Сброс соединения PHP при загрузке большого файла независимо от правильной настройки PHP-функция для построения строки запроса из массива – не HTTP-запрос Как сохранить XML с помощью PHP Декодирование строки Base64 с использованием CryptoJS Страница заказов WooCommerce добавляет пользовательский столбец пользователя PhpStorm Выбрасывает ошибку для phpcs Моя контактная форма отправляет пустые сообщения body_messages В PHP при отправке строк в базу данных следует позаботиться о незаконных символах с помощью htmlspecialchars () или использовать регулярное выражение? Свойство объекта массива php Доступ к переменной PHP в JavaScript Отслеживание времени выполнения скрипта в PHP PHP: Требовать, чтобы путь не работал для работы cron? Анализ XML с помощью PHP и XMLReader

file_get_contents (- Исправить относительные URL-адреса

Я пытаюсь показать веб-сайт пользователю, загрузив его с помощью php. Это сценарий, который я использую:

<?php $url = 'http://stackoverflow.com/pagecalledjohn.php'; //Download page $site = file_get_contents($url); //Fix relative URLs $site = str_replace('src="','src="' . $url,$site); $site = str_replace('url(','url(' . $url,$site); //Display to user echo $site; ?> 

Пока этот сценарий работает, за исключением нескольких основных проблем с функцией str_replace. Проблема связана с относительными URL-адресами. Если мы используем изображение на нашем созданном pagecalledjohn.php кота (что-то вроде этого: Кот ). Это png, и, как я вижу, его можно разместить на странице, используя 6 разных URL-адресов:

 1. src="//www.stackoverflow.com/cat.png" 2. src="http://www.stackoverflow.com/cat.png" 3. src="https://www.stackoverflow.com/cat.png" 4. src="somedirectory/cat.png" 

4 в этом случае неприменим, но добавлен в любом случае!

 5. src="/cat.png" 6. src="cat.png" 

Есть ли способ, используя php, я могу выполнить поиск src = "и заменить его URL-адресом (удаленным именем файла) загружаемой страницы, но без ввода URL-адреса там, если это варианты 1,2 или 3, и немного изменить процедуру для 4,5 и 6?

Solutions Collecting From Web of "file_get_contents (- Исправить относительные URL-адреса"

Вместо того, чтобы пытаться изменить каждую ссылку на путь в исходном коде, почему бы вам просто не добавить <base> в свой заголовок, чтобы конкретно указать базовый URL-адрес, по которому должны вычисляться все относительные URL-адреса?

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

Это может быть достигнуто с использованием выбранного вами инструмента для манипуляций с DOM. В приведенном ниже примере показано, как это сделать, используя DOMDocument и связанные с ним классы.

 $target_domain = 'http://stackoverflow.com/'; $url = $target_domain . 'pagecalledjohn.php'; //Download page $site = file_get_contents($url); $dom = DOMDocument::loadHTML($site); if($dom instanceof DOMDocument === false) { // something went wrong in loading HTML to DOM Document // provide error messaging and exit } // find <head> tag $head_tag_list = $dom->getElementsByTagName('head'); // there should only be one <head> tag if($head_tag_list->length !== 1) { throw new Exception('Wow! The HTML is malformed without single head tag.'); } $head_tag = $head_tag_list->item(0); // find first child of head tag to later use in insertion $head_has_children = $head_tag->hasChildNodes(); if($head_has_children) { $head_tag_first_child = $head_tag->firstChild; } // create new <base> tag $base_element = $dom->createElement('base'); $base_element->setAttribute('href', $target_domain); // insert new base tag as first child to head tag if($head_has_children) { $base_node = $head_tag->insertBefore($base_element, $head_tag_first_child); } else { $base_node = $head_tag->appendChild($base_element); } echo $dom->saveHTML(); 

По крайней мере, вы действительно хотите изменить все ссылки на пути в исходном коде, я бы настоятельно рекомендовал это делать с инструментами DOM-манипуляции (DOMDOcument, DOMXPath и т. Д.), А не с регулярным выражением. Я думаю, вы найдете это гораздо более стабильным решением.

Я не знаю, правильно ли я понял ваш вопрос, если вы хотите иметь дело со всеми текстовыми последовательностями, заключенными в src=" and " , следующий шаблон мог бы сделать это:

 ~(\ssrc=")([^"]+)(")~ 

В нем есть три группы захвата, второй из которых содержит интересующие вас данные. Первые и последние полезны для изменения всего матча.

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

 $site = <<<BUFFER 1. src="//www.stackoverflow.com/cat.png" 2. src="http://img.ruphp.com/relative-url/cat.png" 3. src="http://img.ruphp.com/relative-url/cat.png" 4. src="somedirectory/cat.png" 5. src="/cat.png" 6. src="cat.png" BUFFER; 

Давайте на мгновение проигнорируем, что нет окружающих тегов HTML, вы не разбираетесь в HTML в любом случае, я уверен, поскольку вы не просили парсер HTML, а для регулярного выражения. В следующем примере совпадение в середине (URL) будет вложено так, чтобы было ясно, что оно соответствует:

Итак, теперь, чтобы заменить каждую из ссылок, давайте начнем легко, просто выделив их в строке.

 $pattern = '~(\ssrc=")([^"]+)(")~'; echo preg_replace_callback($pattern, function ($matches) { return $matches[1] . ">>>" . $matches[2] . "<<<" . $matches[3]; }, $site); 

Результат для приведенного ниже примера:

 1. src=">>>//www.stackoverflow.com/cat.png<<<" 2. src=">>>http://img.ruphp.com/relative-url/cat.png<<<" 3. src=">>>http://img.ruphp.com/relative-url/cat.png<<<" 4. src=">>>somedirectory/cat.png<<<" 5. src=">>>/cat.png<<<" 6. src=">>>cat.png<<<" 

Поскольку способ замены строки должен быть изменен, ее можно извлечь, поэтому ее легче изменить:

 $callback = function($method) { return function ($matches) use ($method) { return $matches[1] . $method($matches[2]) . $matches[3]; }; }; 

Эта функция создает обратный вызов замены, основанный на методе замены вашего пароля как параметра.

Такая функция замены может быть:

 $highlight = function($string) { return ">>>$string<<<"; }; 

И это называется следующим:

 $pattern = '~(\ssrc=")([^"]+)(")~'; echo preg_replace_callback($pattern, $callback($highlight), $site); 

Выходные данные остаются теми же, это просто для иллюстрации того, как работает отработка:

 1. src=">>>//www.stackoverflow.com/cat.png<<<" 2. src=">>>http://img.ruphp.com/relative-url/cat.png<<<" 3. src=">>>http://img.ruphp.com/relative-url/cat.png<<<" 4. src=">>>somedirectory/cat.png<<<" 5. src=">>>/cat.png<<<" 6. src=">>>cat.png<<<" 

Преимущество этого заключается в том, что для функции замещения вам нужно иметь дело только с совпадением URL как с одной строкой, а не с регулярным выражением, сопоставляющим массив для разных групп.

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

 $removeFilename = function ($url) { $url = new Net_URL2($url); $base = basename($path = $url->getPath()); $url->setPath(substr($path, 0, -strlen($base))); return $url; }; 

В этом коде используется компонент URL-адреса Pear's Net_URL2 (также доступный через Packagist и Github, также могут иметь свои пакеты ОС). Он может легко анализировать и изменять URL-адреса, поэтому хорошо иметь работу.

Итак, теперь замена выполняется с новой функцией замены имени файла URL:

 $pattern = '~(\ssrc=")([^"]+)(")~'; echo preg_replace_callback($pattern, $callback($removeFilename), $site); 

И тогда результат:

 1. src="//www.stackoverflow.com/" 2. src="http://www.stackoverflow.com/" 3. src="https://www.stackoverflow.com/" 4. src="somedirectory/" 5. src="/" 6. src="" 

Обратите внимание, что это пример. Он показывает, как вы можете это делать с регулярными выражениями. Тем не менее, вы можете также использовать HTML-парсер. Давайте сделаем это фактическим фрагментом HTML:

 1. <img src="//www.stackoverflow.com/cat.png"/> 2. <img src="http://img.ruphp.com/relative-url/cat.png"/> 3. <img src="http://img.ruphp.com/relative-url/cat.png"/> 4. <img src="somedirectory/cat.png"/> 5. <img src="/cat.png"/> 6. <img src="cat.png"/> 

Затем обработайте все атрибуты <img> " src " с помощью созданной функции сменного фильтра:

 $doc = new DOMDocument(); $saved = libxml_use_internal_errors(true); $doc->loadHTML($site, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); libxml_use_internal_errors($saved); $srcs = (new DOMXPath($doc))->query('//img/@hsrc') ?: []; foreach ($srcs as $src) { $src->nodeValue = $removeFilename($src->nodeValue); } echo $doc->saveHTML(); 

Результат опять же:

 1. <img src="//www.stackoverflow.com/cat.png"> 2. <img src="http://img.ruphp.com/relative-url/cat.png"> 3. <img src="http://img.ruphp.com/relative-url/cat.png"> 4. <img src="somedirectory/cat.png"> 5. <img src="/cat.png"> 6. <img src="cat.png"> 

Использовался другой способ разбора – замена по-прежнему остается прежней. Просто предложить два разных способа, которые также частично совпадают.

Я предлагаю сделать это в несколько шагов.

Чтобы не усложнять решение, допустим, что любое значение src всегда является изображением (это может быть и другое, например скрипт). Кроме того, предположим, что нет пробелов между знаками равенства и кавычками (это можно легко устранить, если они есть). Наконец, давайте предположим, что имя файла не содержит каких-либо экранированных кавычек (если это было сделано, regexp будет более сложным). Поэтому вы можете использовать следующее regexp для поиска всех ссылок на изображения: src="([^"]*)" . (Кроме того, это не распространяется на случай, когда src заключен в одинарные кавычки, но его легко создать аналогичное регулярное выражение для этого.)

Однако логику обработки можно выполнить с помощью функции preg_replace_callback , а не str_replace . Вы можете обеспечить обратный вызов этой функции, где каждый URL-адрес может обрабатываться на основе его содержимого.

Так что вы могли бы сделать что-то вроде этого (не тестировалось!):

 $site = preg_replace_callback( 'src="([^"]*)"', function ($src) { $url = $src[1]; $ret = ""; if (preg_match("^//", $url)) { // case 1. $ret = "src='" . $url . '"'; } else if (preg_match("^https?://", $url)) { // case 2. and 3. $ret = "src='" . $url . '"'; } else { // case 4., 5., 6. $ret = "src='http://your.site.com.com/" . $url . '"'; } return $ret; }, $site );