Я полностью согласен с комментарием @JayBlanchard, в котором упоминается тот факт, что было бы намного безопаснее использовать PHP DOM-парсер. Затем вы можете легко удалить их, если у них нет атрибута no-defer
.
Но хорошо ... если вы действительно хотите сделать это с помощью регулярного выражения, я сначала попытался бы найти все <script>
теги и захват атрибутов в группе захвата с чем-то вроде этого:
Идея состоит в том, чтобы выполнить работу за 2 прохода. Это можно сделать с помощью функции PHP preg_replace_callback()
, которая позволит вам затем выполнить PHP для каждого совпадения, и вы сможете немного безопасно проанализировать атрибуты и посмотреть, есть ли у вас no-defer
и решите оставить его вместо того, чтобы вставлять его в массив сценариев, чтобы перейти в конец страницы.
Вы также можете использовать preg_match_all()
и l oop поверх результатов, чтобы решить, что делать. Но я бы лично go сначала для решения парсера DOM, а затем для решения preg_replace_callback()
с функцией обратного вызова, которая может получить доступ к массиву для хранения удаленных элементов. Это можно сделать с помощью анонимных (замыкающих) функций и функциональности use ($scripts_to_move_down)
. Смотрите здесь: https://www.php.net/manual/en/functions.anonymous.php
Это может выглядеть примерно так:
$script_tags_to_move = [];
// Find all script tags and store and then remove them if they don't have the
// no-defer attribute.
$html = preg_replace_callback(
'/<\s*script(?<attributes>[^>]*)>.*?<\s*\/\s*script\s*>/si',
function ($matches) use (&$script_tags_to_move) {
// If the attributes contains no-defer (search is not very safe -> to improve).
if (preg_match('/(^|\s)no-defer(\s|$)/i', $matches['attributes'])) {
// Keep the script tag in the HTML.
return $matches[0];
} else {
// Store the script tag.
$script_tags_to_move[] = $matches[0];
// And remove it from the HTML.
return '';
}
},
$html
);
// Inject the script tags at the end, before the closing body tag.
$html = preg_replace(
'~<\s*/\s*body\s*>~is',
implode("\n", $script_tags_to_move) . '</body>',
$html
);
Попробуйте здесь: http://sandbox.onlinephpfunctions.com/code/21a938482e883a1d470e61f312764c112c73bb85