Code desription
Code will find every image tags <img attr1=value1 attr2=value2 ... />
in text, create for every image own image tag with new HtmlElement()
- this class is just custom light version of new DOMElement()
, replace original image tag with placeholder, after every image is replace with placeholder, in this case I choose this placeholder {#@#IMG_' . $id .'}
which is enough original for me type of texts , then will use on whole text htmlspecialchars()
function and at the end it will replace placeholders with newly created image tags and return text back.
Code explanation
if (preg_match_all('#<img\s+([^>]+?)\s?(/>|>)#i', $text, $matches)) {
Check if text contain any images, if yes, variabale $matches
will contain 3 dimensional array of arrays, which will look like this for example:
array (3)
0 => array (6)
| 0 => "<img alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes" />"
| 1 => "<img alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes" />"
| 2 => "<img alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes" />"
| 3 => "<img alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes" />"
| 4 => "<img alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes" />"
| 5 => "<img alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes" />"
1 => array (6)
| 0 => "alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes""
| 1 => "alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes""
| 2 => "alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes""
| 3 => "alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes""
| 4 => "alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes""
| 5 => "alt="rolleyes" src="//t.domain.com/default/rolleyes.gif" title="rolleyes""
2 => array (6)
| 0 => "/>"
| 1 => "/>"
| 2 => "/>"
| 3 => "/>"
| 4 => "/>"
| 5 => "/>"
then it create own images based on original <img />
attributes and store them in varibale $images
foreach ($matches[1] as $id => $imgAttributes) {
$img = new \HtmlElement('img');
$img->addAttributes($imgAttributes);
$img->attributes([
'src' => $img->attr('src'),
'alt' => escapeHtml($img->attr('alt')),
'title' => escapeHtml($img->attr('title'))
]);
$images[$id] = $img->render();
in my case i just need attributes alt
, title
and src
from images, also if you don't need use escape HTML in attributes like alt
, title
or others, you can omit this part of code and witch little alterations continue with next code row:
$text = str_replace($matches[0][$id], '{#@#IMG_' . $id .'}', $text);
which will replace in original text every image tag with placeholder '{#@#IMG_' . $id .'}'
, so for exmaple first image will be replaced in original text like:
{#@#IMG_0}
Keep in mind placeholder should be enough original for your type of texts and also can't contain any special characters which would be replaced with htmlspecialchars()
for HTML entities.
When every image is replaced by own placeholder then we can convert special characters to HTML entities in whole text:
$text = escapeHtml($text);
and as last step we replace placeholders in text with image tags:
foreach ($images as $id => $image) {
$text = str_replace('{#@#IMG_' . $id . '}', $image, $text);
}
Whole code
function escapeHtml($text)
{
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8', false);
}
function escapeHtmlKeepImages($text)
{
if (preg_match_all('#<img\s+([^>]+?)\s?(/>|>)#i', $text, $matches)) {
$images = [];
foreach ($matches[1] as $id => $imgAttributes) {
$img = new \HtmlElement('img');
$img->addAttributes($imgAttributes);
$img->attributes([
'src' => $img->attr('src'),
'alt' => escapeHtml($img->attr('alt')),
'title' => escapeHtml($img->attr('title'))
]);
$images[$id] = $img->render();
$text = str_replace($matches[0][$id], '{#@#IMG_' . $id .'}', $text);
}
$text = escapeHtml($text);
foreach ($images as $id => $image) {
$text = str_replace('{#@#IMG_' . $id . '}', $image, $text);
}
} else {
$text = escapeHtml($text);
}
return $text;
}
Version where you don't need treat attributes alt
, title
and others, with example
$text = '
<strong>hello</strong>
<img src="image.gif" alt="something" >><3
how are you?
<img src="signature.gif" alt="signature" title="signature"/>
';
function escapeHtml($text)
{
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8', false);
}
function escapeHtmlKeepImages($text)
{
if (preg_match_all('#<img\s+([^>]+?)\s?(/>|>)#i', $text, $matches)) {
array_map(
function ($id, $img) use (&$text) {
$text = str_replace($img, '{#@#IMG_' . $id . '}', $text);
},
array_keys($matches[0]), $matches[0]
);
$text = escapeHtml($text);
array_map(
function ($id, $img) use (&$text) {
$text = str_replace('{#@#IMG_' . $id . '}', $img, $text);
},
array_keys($matches[0]), $matches[0]
);
} else {
$text = escapeHtml($text);
}
return $text;
}
echo escapeHtmlKeepImages($text);
output:
<strong>hello</strong>
<img src="image.gif" alt="something" >><3
how are you?
<img src="signature.gif" alt="signature" title="signature"/>