5

I need to modify links and img references in the body of nodes and comments. MPD already gave me good advice regarding using a script.

Is there an easy way in Drupal or PHP to parse out all the links in the body copy?

0

3 Answers 3

12

It's never easy to do something like this because parsing HTML is a bit hit-and-miss, depending on how well formatted the input is.

I've always found the best way to do it is to load the HTML into a DOMDocument object, loop through and change whatever element attributes/values I need to, then use the DOMDocument to give me the new output.

This is a very rough example but hopefully it'll give you the idea:

$html = '
  <p>Blah blah blah</p>
  <p><a href="/some-path" title="A Title">Link Text</a>
  </p><p><img src="/some-path.jpg" alt="Some alt" /></p>';

$doc = new DOMDocument;

// This is a reasonable use of the @ operator as malformed HTML will produce
// a lot of warnings. Please don't shoot me ;)
@$doc->loadHTML($html); 

// Get the links.
$links = $doc->getElementsByTagName('a');
foreach ($links as $link) {
  // Change the value of an attribute based on the current value.
  if ($link->getAttribute('href') == '/some-path') {
    $link->setAttribute('href', '/some-other-path');
  }
}

// Get the images.
$images = $doc->getElementsByTagName('img');
foreach ($images as $image) {
  // Change the value of an attribute based on the current value.
  if ($image->getAttribute('src') == '/some-path.jpg') {
    $image->setAttribute('src', '/some-other-path.jpg');
  }
}

// Get the new HTML
$new_html = $doc->saveHTML();

// Strip out the tags that loadHTML() introduces to get the clean HTML.
$patterns = array("/^\<\!DOCTYPE.*?<html><body>/si", "!</body></html>$!si");
$body_text = preg_replace($patterns, '', $new_html);

// Update the node body.
$node->body[$node->language][0]['value'] = $body_text;

EDIT

I knew I'd seen a good question about this on SO; have a look at How to parse and process HTML with PHP? for a good discussion on the subject in general.

1
  • This answer was quite helpful though when using different language based site. In my case 'Malayalam' the end result was was not UTF-8 based but Latin based. I searched a little more to solve this and replaced some lines as: $dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); and $node->body[$node->language][0]['value'] = html_entity_decode($body_text);. My purpose was to convert inner images to base64 code. Thank You @clive
    – sarathkm
    Commented Sep 7, 2016 at 4:53
1

As I answered in your other question, filters are the proper solution since they won't actually alter the data, but the output. This means that should you want to change it differently (or fix a conversion bug), data is still there.

Just check the documentation on hook_filter_info() and have a good time parsing HTML with PHP.

-1

Maybe you are not looking at the good way.

Have you try to make a replace in the database?

update TABLE_NAME set FIELD_NAME = replace(FIELD_NAME, 'find this string', 'replace found string with this string');

update client_table set company_name = replace(company_name, 'Old Company', 'New Company')

I have use use them for some migrations. It's no easy—you must check and map all the replace—but it works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.