Forum code that automatically turns urls into clickable links

16 posts by 2 authors in: Forums > CMS Builder
Last Post: December 29, 2018   (RSS)

By daniel - December 27, 2018 - edited: December 27, 2018

Hi Jerry,

The forums use a PHP library called HTML Purifier (http://htmlpurifier.org/) to - among other things - add links to message bodies in the function sforum_cleanAndFormatHTML(). This library is integrated into the CMSB core with the common function htmlPurify(), so it should be possible to use it to just add links with something like this:

$config = array();
$config['AutoFormat.Linkify'] = true;

$newHtml = htmlPurify($oldHtml, $config);

If you're looking for something standalone that can be used outside of CMSB, here's a short snippet that should be able to handle most simple cases:

$text = preg_replace("|(https?://[\w\-@:%\+.~#?&//=]+)|", '<a href="\\1">\\1</a>', $text);

Let me know any questions!

Thanks,

Daniel
Technical Lead
interactivetools.com

Hi Daniel,

Thanks as always for your expert guidance.

I think that I got both implementations to work on the cookbook recipe details pages, although I want to do a few more tests to see if other things got broken along the way.

(Like what happens if there's a url in the example code of a recipe...)

I do have one more question. Should I be using print, print_r, or echo for the built in version of the code?

Thanks,

Jerry Kornbluth

Here’s what I have so far:

The text for my recipes are pulled from a text box called $table_of_contentsRecord['recipe'].

I've left out any formatting code to simplify the examples as much as possible.

For the code built in to CMSB

<?php $recipe = ($table_of_contentsRecord['recipe']); ?>
<?php

// automatic links using code built in to CMSB
$config = array();
$config['AutoFormat.Linkify'] = true;

$recipe = htmlPurify($recipe, $config);
echo $recipe;
?>

And for the code to use outside of CMSB:

<?php $recipe = ($table_of_contentsRecord['recipe']); ?>
<?php

// standard implementation for use outside of CMSB

$recipe = preg_replace("|(https?://[\w\-@:%\+.~#?&//=]+)|", '<a href="\\1">\\1</a>', $recipe); // Added per Daniel to create links from URLs

echo $recipe;
?>

The first CMS Builder reference book is now available on-line!







Take advantage of a free 3 month trial subscription, only for CMSB users, at: http://www.thecmsbcookbook.com/trial.php

Hi Daniel,

There's still one minor issue that I’d love to solve.

I’d like to exclude htmlPurify() from acting on the code examples within a cookbook recipe.

All code examples are enclosed in block quotes which I accomplish by surrounding each code block with qzl at the beginning and lzq at the end and then using the following code:

$recipe = str_replace('qzl', '<blockquote class="snippet"> ', $recipe);
$recipe = str_replace('lzq', '</blockquote> ', $recipe);

and styling the blockquotes with:

.snippet {font-family: Verdana, sans-serif; color: #000000; font-size: 1em; font-weight:normal;
margin: 0px 0px 0px 15px;
padding: 8px 12px;
border: 1px dashed #305555;
background-color: #54ccf2;
display: block;
overflow-x: auto;
}

I think that if I could wrap the htmlPurify code in an if statement that excludes any blockquoted data in the recipe that might work automatically, but I haven’t been able to figure out how to implement that.

Any ideas?

Complete working page code is attached.

Thanks,

Jerry Kornbluth

The first CMS Builder reference book is now available on-line!







Take advantage of a free 3 month trial subscription, only for CMSB users, at: http://www.thecmsbcookbook.com/trial.php
Attachments:

recipedetail.php 10K

By daniel - December 28, 2018

Hi Jerry,

For echo vs. print vs. print_r; I'd recommend echo for any time you want to output plain text to a page. (For some more specific details, see: https://stackoverflow.com/questions/1647322/whats-the-difference-between-echo-print-and-print-r-in-php)

From what I can see, there's no easy way to exclude the code snippets from being passed through htmlPurify(), as the whole content for the recipe is contained within a single variable. You will need to find a way to split up the content to isolate the parts you want to add links to and run the purifier on those.

A full solution is a bit beyond what I can offer here, but my suggestion would be to try using explode() to split up the content around the code blocks; something like this may work (untested code):

// split on opening blockquote
$chunks = explode('qzl', $recipe);

// loop through each chunk
foreach ($chunks as $chunk) {

  // split chunk on end blockquote
  $tmp = explode('lzq', $chunk);
  
  // did we find an ending blockquote?
  if (count( $tmp ) > 1) {

    // purify content after blockquote
    $chunks[ $chunk ][1] = htmlPurify( $chunks[ $chunk ][1] );
  }
  else {

    // purify only element
    $chunks[ $chunk ][0] = htmlPurify( $chunks[ $chunk ][0] );
  }

  // replace ending blockquote
  $chunks[ $chunk ] = implode('lqz', $tmp);
}

// replace opening blockquote
$recipe = implode('qzl', $chunks);

Let me know any questions!

Thanks,

Daniel
Technical Lead
interactivetools.com

WOW!

Thanks, Daniel,

I'll give it a try and post the results.

Jerry Kornbluth

The first CMS Builder reference book is now available on-line!







Take advantage of a free 3 month trial subscription, only for CMSB users, at: http://www.thecmsbcookbook.com/trial.php

Hi Daniel,

I tried to implemented your code on a simplified version of the detail page but I ‘m getting 2 strange errors and the other anomalies in link 2) below.

Probably a really simple fix, but I’m at a loss as to how to troubleshoot this kind of error.

Here are some links that illustrate the issue:

With the original working simple CMSB htmlPurify code: http://www.thecmsbcookbook.com/recipedetail.php?589
(The links inside and outside the blockquotes are active)

With the code as above: http://www.thecmsbcookbook.com/recipedetailH.php?589
With:

1) The errors as shown below
2) The link outside the qzl and lzq is not active and the one inside is active, and
3) There are 2 jumbled copies of the contents.

If you have a moment, could you take another look?

Thanks,

Jerry Kornbluth
_____________________________________
The test record ‘recipe’ text box contains only the following as text:

TEXT BEFORE A LINK

http://www.thecmsbcookbook.com

AFTER LINK

qzl
AFTER A QZL
<a href="http://www.thecmsbcookbook.com/css/fonts2019.css.php" />CLICK TO ACCEPT THIS</a>
lzq
AFTER AN LZQ
______________________________________
And the resulting errors are:

#7729 - E_NOTICE: Undefined index:

AFTER A QZL

<a href="http://www.thecmsbcookbook.com/css/fonts2019.css.php" />CLICK TO ACCEPT THIS</a>

lzq

AFTER AN LZQ
/home3/ellescho/public_html/thecmsbcookbook/recipedetailH.php (line 132)
http://www.thecmsbcookbook.com/recipedetailH.php?589

AND

#7728 - E_NOTICE: Undefined index:

TEXT BEFORE A LINK

http://www.thecmsbcookbook.com

AFTER LINK

/home3/ellescho/public_html/thecmsbcookbook/recipedetailH.php (line 137)
http://www.thecmsbcookbook.com/recipedetailH.php?589
__________________________________________

The active code that I’m using on the detail page is:

<?php $recipe = ($table_of_contentsRecord['recipe']); ?>
<?php
/// split on opening blockquote
$chunks = explode('qzl', $recipe);

// loop through each chunk
foreach ($chunks as $chunk) {

// split chunk on end blockquote
$tmp = explode('lzq', $chunk);

// did we find an ending blockquote?
if (count( $tmp ) > 1) {

// purify content after blockquote
$chunks[ $chunk ][1] = htmlPurify( $chunks[ $chunk ][1] );
}
else {

// purify only element
$chunks[ $chunk ][0] = htmlPurify( $chunks[ $chunk ][0] );
}

// replace ending blockquote
$chunks[ $chunk ] = implode('lqz', $tmp);
}

// replace opening blockquote
$recipe = implode('qzl', $chunks);

// reset block quotes
$recipe = str_replace('qzl', '<blockquote class="snippet"> ', $recipe);
$recipe = str_replace('lzq', '</blockquote> ', $recipe);
?>

<table>
<tr>
<td>
<?php echo $recipe; ?>
</td>
</tr>
</table>

The first CMS Builder reference book is now available on-line!







Take advantage of a free 3 month trial subscription, only for CMSB users, at: http://www.thecmsbcookbook.com/trial.php

By daniel - December 28, 2018

Hey Jerry,

Just noticed a couple logic errors in the sample code. Corrected here:

// split on opening blockquote
$chunks = explode('qzl', $recipe);

// loop through each chunk
foreach ($chunks as $key => $chunk) {

  // split chunk on end blockquote
  $tmp = explode('lzq', $chunk);
  
  // did we find an ending blockquote?
  if (count( $tmp ) > 1) {

    // purify content after blockquote
    $tmp[1] = htmlPurify( $tmp[1] );
  }
  else {

    // purify only element
    $tmp[0] = htmlPurify( $tmp[0] );
  }

  // replace ending blockquote
  $chunks[ $key ] = implode('lqz', $tmp);
}

// replace opening blockquote
$recipe = implode('qzl', $chunks);

Let me know if that does any better!

Thanks,

Daniel
Technical Lead
interactivetools.com

Hey Daniel,

Almost there...

Looks and works much better, and no errors.

However, still 2 small issues:

1) the functionality the reverse of what it should be.

Currently, the URLs in the block quotes are active (they shouldn't be) and the URLs outside are inactive (they should be).

2) An lzq (lower case) is printing when it shouldn't.

Probably really quick fixes for you...

See http://www.thecmsbcookbook.com/recipedetailI.php?TEST-ONLY-589

Thanks,

Jerry Kornbluth

The first CMS Builder reference book is now available on-line!







Take advantage of a free 3 month trial subscription, only for CMSB users, at: http://www.thecmsbcookbook.com/trial.php

By daniel - December 28, 2018

Hi Jerry,

One quick thing: There's a "lzq" written as "lqz" - that should fix item 2, however, I'm not 100% sure why it's reversing the result.  Are you able to provide me with the $recipe content before it gets processed (with the qzl and lzq parts intact) so that I can test it myself?

Thanks,

Daniel
Technical Lead
interactivetools.com