找回密码
 快速注册
搜索
查看: 107|回复: 24

先替换[tikz]再替换[font]、[color]

[复制链接]

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

hbghlyj 发表于 2024-3-1 04:52 |阅读模式
建议在discuzcode.php中,先替换[tikz]再替换[font]、[color],以避免常见的嵌套问题
可能会用到php urlencode

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-3-1 04:57
這樣可以一步到位,取代前端的处理let tikzs = document.getElementsByTagName('tikz');等等

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-3-1 05:00
hbghlyj 发表于 2024-2-29 20:52
以避免常见的嵌套问题


測試:
  1. <?php
  2. echo urlencode('[color=red]');
复制代码

輸出
  1. %5Bcolor%3Dred%5D
复制代码

再做[color=]替换時就不會被匹配到了

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-3-1 14:34
本帖最后由 kuing 于 2024-3-6 15:18 编辑 有空再说😌

=====
还是在 js 层面解决吧,把转换了的 [color 和 [font 给改回来就好了,也就加两句的事:
  1. .replace(/<font color="(.*?)">/g,'[color=$1]')
  2. .replace(/<font face="(.*?)">/g,'[font=$1]')
复制代码

test:

  1. [tikz]\tikz{
  2. \draw[color=red](0,0)--(1,1)node[right]{$1<2,2>1$};
  3. \draw[color=blue](0,0)circle(1)node[font=\tiny]{$1<2,2>1$};
  4. }[/tikz]
复制代码

点评

除了[font=]和[color=],还有包括[align=center]  发表于 2024-10-7 17:43

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-9-29 14:55

实例:[align=center] 会干扰 [tikz] 的内容

正常效果是

但经过干扰后就变成了

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-7 15:53
discuzcode.php 里面,那些“论坛后台设置的自定义代码”的相关代码在哪里呢?我看了半天,没看出来在哪

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-7 16:14
处理 [code] 的部分,我已经大概了解,貌似是先将内容转移到另一个地方先暂存着,原先的地方变成 [\tDISCUZ_CODE_数目\t] ,等其他代码处理完了,再把 [\tDISCUZ_CODE_数目\t] 替换回相应的格式化的内容。

我想 [tikz] 的处理应该不需要这么复杂,直接替换成图片格式就行,只是时机要在替换 [code] 之后、替换其他 bbcode 和自定义 bbcode 之前,但自定义的我还看不明白,所以有楼上一问。

另外我对 php 也不大熟悉,如果代码写错,会不会搞坏了啥造成严重后果?

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-7 17:17
本帖最后由 kuing 于 2024-10-8 14:41 编辑
kuing 发表于 2024-10-7 15:53
discuzcode.php 里面,那些“论坛后台设置的自定义代码”的相关代码在哪里呢?我看了半天,没看出来在哪 ...


噢,我好像知道了
自定义 bbcode 存在 forum_bbcode 这个表里,
然后 cache_bbcodes.php 基于该表生成 bbcode 替换规则的缓存,
然后在 function_discuzcode.php#L226 这一句执行替换。

不过,这一句的上一行的条件为啥是
  1. if($parsetype != 1 && $allowbbcode < 0 && isset($_G['cache']['bbcodes'][-$allowbbcode])) {
复制代码

为啥是 $allowbbcode < 0?从 L74 来看 $allowbbcode 默认是 1 呀,那这句岂不是一般都不运作?

知道了,在 forum_viewthread.php#L1265 里是这样用的:
  1. $post['message'] = discuzcode($post['message'], $post['smileyoff'], $post['bbcodeoff'], $post['htmlon'] & 1, $_G['forum']['allowsmilies'], $forum_allowbbcode, ...
复制代码

第六个参数 $forum_allowbbcode 就是代入那个 $allowbbcode ,而 $forum_allowbbcode 是在 L1219 定义的:
  1. $forum_allowbbcode = $_G['forum']['allowbbcode'] ? -$post['groupid'] : 0;
复制代码

看起来,一般还真是传入了负数,那就没问题了。

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-7 18:07
本帖最后由 kuing 于 2024-10-7 21:29 编辑 那现在要做的应该就是模仿 code 的处理:
if($parsetype != 1 && !$bbcodeoff && $allowbbcode && (strpos($message, '[/code]') || strpos($message, '[/CODE]')) !== FALSE) {
	$message = preg_replace_callback("/\s?\[code\](.+?)\[\/code\]\s?/is", 'discuzcode_callback_codedisp_1', $message);
}
我们也来一个
  1. if($parsetype != 1 && !$bbcodeoff && $allowbbcode && (strpos($message, '[/tikz]') || strpos($message, '[/TIKZ]')) !== FALSE) {
  2. $message = preg_replace_callback("/\[tikz\](.+?)\[\/tikz\]/is", 'tikzcode_callback', $message);
  3. }
复制代码
吗?然后 tikzcode_callback 函数就是当前 js 里做的那些操作?

点评

另外,这样弄之后,论坛后台自定义的 tikz 的 bbcode(目前的设置是替换为 <tikz class="tupian">{1}</tikz>)应该就无效了吧,因为已经提前替换了。   发表于 2024-10-7 21:29

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-8 02:53
本帖最后由 kuing 于 2024-10-9 03:01 编辑
kuing 发表于 2024-10-7 18:07
那现在要做的应该就是模仿 code 的处理:
...
...
然后 tikzcode_callback 函数就是当前 js 里做的那些操作?


本来想将原先 js 那段内容改写成 php (即 2# 说的,取代前段处理)
但实操过发现有点麻烦,首先用 1# 说的 urlencode 发现不行,得用 rawurlencode ,但还有 < 变成 &lt; 的问题,不过这应该不难处理。
更大的问题是“点击显示代码”的问题,php 的 rawurlencode 与 js 的 encodeURI、encodeURIComponent 都不一样(见《Urlencode踩坑日记》)。
在 php 编码再用 js 的 dec... 解码会有不少差别,无法很好地还原,而展示代码是在前端运作的,只能用 js,除非重写,改变展示代码的方式,那就太麻烦了……(这里应该是我当时粗心搞错了,见后面几楼)

所以放弃这种方向,改为绕过 bbcode 的处理,那就很简单:
在处理那堆自带 bbcode 之前加入以下:
  1. // kk add
  2. if($parsetype != 1 && strpos($message, '[/tikz]') !== FALSE) {
  3.     $message = preg_replace_callback("/\[tikz\](.+?)\[\/tikz\]/s", function ($matches) { return '[tikz]'.urlencode($matches[1]).'[/tikz]'; }, $message);
  4. }
复制代码

然后在处理自定义 bbcode 之前加入以下:
  1. // kk add
  2. if($parsetype != 1 && strpos($message, '[/tikz]') !== FALSE) {
  3.     $message = preg_replace_callback("/\[tikz\](.+?)\[\/tikz\]/s", function ($matches) { return '[tikz]'.urldecode($matches[1]).'[/tikz]'; }, $message);
  4. }
复制代码

这样就绕过了那堆自带 bbcode ,js 方面就不需要 4# 那两句,现在都不干扰了。

PS、其实一直不知道 $parsetype != 1 代表啥,纯粹是模仿 code 那段。

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-10-8 16:32
kuing 发表于 2024-10-7 18:53
php 的 rawurlencode 与 js 的 encodeURI、encodeURIComponent 都不一样

encodeURIComponent并不会对*进行转义,而PHP中rawurlencode却会将*转义为%2A。

点评

一共五个不同:
!  '  (  )  *
都是 JS 不转而 PHP 转  发表于 2024-10-9 03:30

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-10-8 16:35
kuing 发表于 2024-10-7 18:53
在 php 编码再用 js 的 dec... 解码会有不少差别,无法很好地还原


PHP 中 rawurlencode() 后可以通过 JS 中的 decodeURIComponent() 复原

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-10-8 16:56
kuing 发表于 2024-10-7 18:53
其实一直不知道 $parsetype != 1 代表啥

由于 Discuz 有“论坛”和“群组”两个功能,在“群组”中变量 $parsetype 被设置为 1,如 /source/module/forum/forum_group.php 所示
  1. $descriptionnew = discuzcode(dhtmlspecialchars(censor(trim($_GET['descriptionnew']), NULL, FALSE, FALSE)), 0, 0, 0, 0, 1, 1, 0, 0, 1);
复制代码

点评

soga  发表于 2024-10-8 17:49

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-8 17:52
hbghlyj 发表于 2024-10-8 16:35
PHP 中 rawurlencode() 后可以通过 JS 中的 decodeURIComponent() 复原

能否弄个同时运行 php 和 js 的简易环境来测试一下?
(现在回想起来,可能我昨晚没弄清楚,结论下得太早……

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-10-8 17:58
kuing 发表于 2024-10-8 09:52
能否弄个同时运行 php 和 js 的简易环境来测试一下?
(现在回想起来,可能我昨晚没弄清楚,结论下得太早 ...


首先我们在 JS 中创建一个包含所有 ASCII 字符的字符串(不包括控制字符)
  1. let asciiPrintableString = '';
  2. for (let i = 32; i < 127; i++) {
  3.     asciiPrintableString += String.fromCharCode(i);
  4. }
  5. console.log(asciiPrintableString);
复制代码

输出为
  1. !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
复制代码

然后将此字符串传递给 PHP 函数 rawurlencode()
  1. <?php
  2. echo rawurlencode(' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~');
复制代码

输出为
  1. %20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~
复制代码

然后将此字符串传递给 JS 函数 decodeURIComponent() 并与原始字符串进行比较
  1. decodeURIComponent('%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~')==asciiPrintableString
复制代码

输出为
true

点评

好吧😥  发表于 2024-10-8 18:17

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-8 18:42
hbghlyj 发表于 2024-10-8 17:58
首先我们在 JS 中创建一个包含所有 ASCII 字符的字符串(不包括控制字符)

输出为

那如果是 urlencode 再 decodeURIComponent 能不能复原回来?

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-10-8 19:40
kuing 发表于 2024-10-8 10:42
那如果是 urlencode 再 decodeURIComponent 能不能复原回来?

唯一的区别是空格,在 urlencode() 之后变成 +,因此无法通过 decodeURIComponent 还原

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-9 15:00
本帖最后由 kuing 于 2024-10-9 16:12 编辑
  1. [tikz]()+!=*,:;[/tikz]
复制代码

得:

右键复制图片链接地址为:https://i.upmath.me/svg/()+!=*,:;
这些符号可以保留在 url 中。

其实美元符和中括号也可以,但安全起见,还是转吧。

730

主题

1万

回帖

9万

积分

积分
93593
QQ

显示全部楼层

kuing 发表于 2024-10-9 15:54
本帖最后由 kuing 于 2024-10-9 16:29 编辑 最新改法:
首先在处理 code 的代码之后立即加入以下:
  1. // kk add
  2. if($parsetype != 1 && !$bbcodeoff && $allowbbcode && strpos($message, '[/tikz]') !== FALSE) {
  3.         $message = preg_replace_callback("/\[tikz\](.+?)\[\/tikz\]/s", function ($matches) { return '[tikz]'.rawurlencode($matches[1]).'[/tikz]'; }, $message);
  4. }
复制代码

强调“立即加”是指不能放太晚,因为随后就有一句 $message = dhtmlspecialchars($message);,如果在这句之后才转码,就会出现 < 变成 &lt; 的情况。
同样道理,这一步也只能仅转码,图片链接啥的就得过了这一句才能做。
所以以下的替换句语是放在处理自定义 bbcode 之前:
  1. // kk add
  2. if($parsetype != 1 && strpos($message, '[/tikz]') !== FALSE) {
  3.         $message = preg_replace_callback("/\[tikz\](.+?)\[\/tikz\]/s", 'tikzcode_callback', $message);
  4. }
复制代码

其中 tikzcode_callback 函数的定义得放在最外面,代码为:
  1. // kk add
  2. function tikzcode_callback($matches) {
  3.     $str = str_replace(array(
  4.                 '%21', '%28', '%29', '%2A', '%2B', '%2C', '%3A', '%3B', '%3D'
  5.                 ),array(
  6.                 '!', '(', ')', '*', '+', ',', ':', ';', '='
  7.                 ),$matches[1]);
  8.     return '<tikz class="tupian"><div class="jiaz"></div><div class="tuozt" onmousedown="tuozhuai2(this.parentNode);return false;"><!--拖动--></div><div class="guiw" onclick="guiwei(this.parentNode);return false;"><!--归位--></div><img src="https://i.upmath.me/svg/'.$str.'" onclick="show_tikz_window(\''.$str.'\');" onload="this.parentNode.classList.add(\'jiazed\')" /></tikz>';
  9. }
复制代码

这就是由之前 js 里的代码改过来的。
PHP 的 rawurlencode 转码比较好,几乎啥都转,之前 js 时还需要处理单引号,这里就不用。
但这也造成字符串很长,而 url 长度有限制,所以我决定将一些可以保留的字符转回来(如圆括号、逗号等)以减少长度,因此有了上面的 str_replace(array(...,测试见楼上。

这样 zdy3pc.js 和 zdy3.js 都可以删去原先生成 tikz 图的代码(但不包括显示代码窗口的那些)。

哦对了,手机版原先与 PC 版有区别,没有弄拖动那些 div,现在统一了,那手机版就多了 div,可以用 css 把它们设为不显示,不过好像并不碍事就懒得弄了。(手机版基本不想管😄)

手机版|悠闲数学娱乐论坛(第3版)

GMT+8, 2025-3-4 12:22

Powered by Discuz!

× 快速回复 返回顶部 返回列表