使用preg_replace()将图像占位符转换为HTML< img>标记

avwztpqn  于 2023-05-12  发布在  其他
关注(0)|答案(5)|浏览(113)

我想用有效的HTML标记替换带方括号的图像占位符。
示例占位符可能如下所示:

[img:http://example.com/_data/025_img.jpg]

我想改变的是,它写着[img: ... ]的位置,用<img>标记,得到如下结果:

<img src='http://example.com/_data/025_img.jpg' border='0' />

与此任务相关的用户上传图像的其他信息:
1.用户将图像上传到其配置文件
1.图像名称存储在DB中。
1.它们列在具有文本区域的表单旁边
1.在输入文本时,我想通过添加以下标签[img: ... ]为用户提供一个或多个图像,其中...是在单击用户图库中列出的图像时复制的链接。
1.我正在使用Codeigniter,并通过视图将textarea传递到控制器->模型中,在那里它被一个帮助器消毒,用于各种事情... sql/quotes等。XSS也在CI上启用;
1.然后我想扫描文本,看看用户在哪里有[img: ... ]标签,并将其交换为<img>标签,然后用文本后面的图像呈现帖子。
因此,来自用户的实际输入将是以下内容:

The brown fox jumped over foo bar [img:http://example.com/_data/025_img.jpg] and then went to bed [img:http://example.com/_data/0277_img.jpg] while thinking about [img:http://example.com/_data/1115_img.jpg]

这就是我要求使用preg_replace()而不是preg_match()的原因。preg_match()不会使文本跟随图像。

idv4meu8

idv4meu81#

让我们先把简单的事情解决掉。

/\[img:([^\]]+)\]/

即:

  • 文字[img:
  • 捕获基团,其包含
  • 一个字符类,由
  • 不是文字的东西]
  • 至少重复一次
  • 文字]

通过preg_match运行此命令,match数组中的元素1很可能是一个图像URL,您可以轻松地将其插入到img标记中。
但你不该这么做不是现在。
首先,这是不安全的赫克。我写这篇文章的时候会发生什么?

[img:javascript:alert(document.cookie);]

哦。那可不妙。
你可能需要确保用户声称是URL的东西真的是URL。您可以通过调用parse_url来尝试执行此操作。它将给予一个URL组件数组。确保该内容具有域和路径,并通过HTTP或HTTPS提供服务。
好的,但是当用户输入 this 时会发生什么呢?

[img:http://www.example.com/foo.jpg" onmouseover="alert(document.cookie)"]

这是一个有效的将被parse_url成功解构的URL,并且很可能通过基本的格式良好性检查。过滤掉空格和引号(单 * 和双 *)将是一个很好的起点,但还有更多的事情需要担心。
底线是这样的标记是XSS, or Cross-site scripting vulnerabilities中的向量。
您可以 * 可能 * 通过htmlspecialchars传递URL来减轻一些威胁。这将至少核武器报价和括号,这是很难与那些照顾讨厌。只是要注意字符集的愚蠢,一些非UTF-8字符编码可能包含ASCII引号…
你可能想使用一种真实的的标记语言(即使它只是markdown),你可能想在结果上使用一个基于白名单的HTML过滤器,比如HTML Purifier。这将有助于保护你免受某种程度的精神错乱。
记住,只有当他们不想抓你的时候,你才是偏执狂。网络上充满了愚蠢到恶意的人,以及恶意到愚蠢的人。

67up9zun

67up9zun2#

如果你不喜欢regex,你不必使用它们。至少不是为了这个目的。
应执行以下操作:

$in = "[img:http://example.com/_data/025_img.jpg]";

if (strpos($in, "[img:") === 0)
{
    $in = "<img src='" . substr($in, 5, -1) . "' border='0' />";
}

echo $in;

但是,这将是regex方式:

$in = "[img:http://example.com/_data/025_img.jpg]";

preg_match("~\[img\:(.*?)\]~", $in, $matches);

if ($matches)
{
    echo "<img src='" . $matches[1] . "' border='0' />";
}

简要说明:

模式为:"~\[img\:(.*?)\]~"
我使用~作为模式的分隔符。您的起始[必须转义,因为它是一个regex字符。img可以保持原样,:必须再次转义。之后,任何字符可以遵循:.*-问号是将选择变为“ungreedy”,否则将匹配到末尾。把它放在(大括号)中,这样它就被标记为$matches的输出。之后,再次关闭]-仅此而已。

更新:参见Gumbos注解,:不需要转义。

gblwokeq

gblwokeq3#

正则表达式很难,但却很强大。我不是大师,所以不要认为这是最好的解决方案。

$regEx = '/\[img:http:\/\/[\w]{3,10}\.(com|org|us){1}[\w\/]{5,15}\.(jpg|png|gif){1}\]/i';

$string = 'someting before [img:http://example.com/_data/025_img.png], something after [img:http://example.org/_data/025_img.jpg] and end of the line EOL';
$pstring = $string;
$matches[0] = array();
preg_match_all($regEx, $string, $matches);

matches数组看起来像:

Array
(
    [0] => Array
        (
            [0] => [img:http://example.com/_data/025_img.png]
            [1] => [img:http://example.org/_data/025_img.jpg]
        )

    [1] => Array
        (
            [0] => com
            [1] => org
        )

    [2] => Array
        (
            [0] => png
            [1] => jpg
        )

)

好吧,这是怎么回事:
1.正则表达式
/-启动regexpression
\[img:http:\/\/-每个字符串必须以[img:http://开头
[\w]{3,10}-比我预期的3至10只有数字,字母和下划线行,这是gona域名(虽然我不确定域必须包含下划线,所以很好的优化点)
\.-点
(com|org|us){1}-这些家伙之一
[\w\/]{5,15}-从5到15行作为路径,注意I included / here in addition
\.-点
(jpg|png|gif){1}-这些家伙之一
\]-模式结束
/i-不区分大小写

  1. preg_match_all查找给定字符串中的所有匹配项,从分支到括号中的额外子串匹配项作为$matches的第二个和第三个元素,我不太猜为什么,所以如果有人能帮助理解这一点,我将不胜感激。
    1.接下来,使用简单的字符串操作,我可以使所有主菜更换
    就像这样:(注意没有if语句,因为我在开始时添加了空的$matches[0],没有ifs生活得更好:)
foreach ($matches[0] as $match) {
    $img = str_replace(array('[img:',']'), array('<img src="', '" />'), $match);
    $pstring = str_replace($match, $img, $pstring);
}

您可以随意使用正则表达式,根据需要使其简单或复杂。
$pstring输出为

someting before <img src="http://example.com/_data/025_img.png" />, something after <img src="http://example.org/_data/025_img.jpg" /> and end of the line EOL

这里是Playgroundhttp://phpfiddle.org/main/code/bbu-e24

ghhaqwfi

ghhaqwfi4#

<?php
$str = '[img:http://example.com/_data/025_img.jpg]';
$image = '<img src="'.str_replace(array("[img:","]"),"",$str).'" border="0">';
echo $image;?>
kxe2p93d

kxe2p93d5#

根据您的问题细节,我认为您对图像路径/文件名的控制非常好。
如果这件事纯粹是关于用一个相当严格的格式验证一个url,并用一个img标签替换占位符,那么编写一个匹配整个方括号标签的模式,并捕获表示图像url的内部子字符串。
代码:(Demo

echo preg_replace(
         '~\[img:\s*(https?://example\.com(?:/\w+)*\.(?:jpe?g|png|gif))]~',
         '<img src="$1" border="0" />',
         $text
     );

如果你想更好地识别图像源字符串,或者你对用户输入的控制没有你想要的那么强,你可以使用preg_replace_callback()来验证url是否存在于你的数据库/服务器中。

echo preg_replace_callback(
         '~\[img:\s*([^\'" \]]+)]~',
         function($m) {
             // do validation techiques
             if ($notValid) {
                 return '[invalid img]';
             }
             return "<img src='{$m[1]}' border='0' />";
         },
         $text
     );

相关问题