[pmwiki-users] preg_replace issue for php 5.6

Petko Yotov 5ko at 5ko.fr
Wed Aug 5 09:28:41 CDT 2015

On 2015-08-05 15:03, Jean-Pierre Chrétien wrote:
> Petko Yotov <5ko <at> 5ko.fr> writes:
>> The same warning may appear with some of the $*Patterns arrays, like
>> $MakePageNamePatterns or $ROEPatterns if they are not updated for PHP
>> 5.5. Try deactivating lines from (farm)config.php until you find the 
>> one
>> that produces the warning.
>> See how the core $MakePageNamePatterns creates a callback function to
>> make a letter uppercase (pmwiki.php, line 729). Or we can help you
>> rewrite the patterns.
>> Also, your shell search may skip some recipes: a regular expression 
>> with
>> evaluation '/e' may have other modifiers, it may look like
>>    /iusxe
>> that is, any letters among [x, s, i, u] before "e" and it is still
>> evaluated so will cause a warning. Or the modifiers can be a variable
>> like /$mods which is expanded by PHP.
>> Incidently, the slash is not always present, a regular expression may
>> use other delimiters like "!". That's why I mostly rely on 
>> progressively
>> deactivating recipes or local configuration until I find the problem.
> Thanks for your answer.
> I think I found the culprit (or one of the culprits, the procedure is 
> not
> over yet) : here is what I see in convert-html.php
> L31	'#\s*(<(ul|ol)\s*>\s*<li.*</\2>)\n?#ise' =>
> 'ConvertHtmlList(stripslashes("$1"))',
> which cumulate both a complex modifier "ise"

The modifiers simply indicate that the pattern should be case 
insensitive (i), that the dot metacharacter "." includes new lines (s) 
and that the replacement needs evaluation.

The letters can be in any order, you could see "ise" or "sei" they are 
equivalent. Simply remove the "e" and keep the others.

> and a delimiter different from
> the usual "/".

The delimiter can be any character, the first one is considered a 
delimiter. In this case the author chose something other than "/" 
because the "/" is often present in HTML and if it was a delimiter it 
wpuld have to be escaped in the patterns.

> This substitutions takes place in a single SDVA( $ROEPatterns, array( 
> function.
> I'm not fluent in php, so what would be the modifications needed to 
> solve
> this ? Is it enough to replace "$x" by "$md[x]" ?

Fixing $ROEPatterns is slightly more complex than replacing $1 with 

We need to create a callback function, so we use PCCF() "PmWiki Create 
Callback Function".

Here are the patterns that need fixing in that recipe, with the new 
PHP5.5 compatible patterns:

//'#\[([=@]).*?\1\]#es' => "Keep(stripslashes('\$0'), 'H')",
   '#\[([=@]).*?\1\]#s' => PCCF("return Keep(\$m[0], 'H');"),

//'#\s*(<(ul|ol)\s*>\s*<li.*</\2>)\n?#ise' => 
   '#\s*(<(ul|ol)\s*>\s*<li.*</\2>)\n?#is' => PCCF('return 

//'#\s*<h(\d)\s*>(.*?)</h\1>\n*#ise' => "\"\n\n\".str_repeat('!','$1').' 
   '#\s*<h(\d)\s*>(.*?)</h\1>\n*#is' => PCCF("return 
\"\n\n\".str_repeat('!',\$m[1]).' '.\$m[2].\"\n\";"),

//'#<span\b\s*([^>]*)>(.*?)</span>#ise' => 
'"%".ConvertHtmlSpan(stripslashes("$1"))."% $2 %%"',
   '#<span\b\s*([^>]*)>(.*?)</span>#is' => PCCF('return 
"%".ConvertHtmlSpan($m[1])."% ".$m[2]." %%";'),

//'#<a\s[^>]*\bname=([\'"])([^\'"]*?)\1[^>]*>(.*?)</a>#ise' => 
'"[[#".preg_replace("/\s+/","_",stripslashes("$2")).\']] $3\'',
   '#<a\s[^>]*\bname=([\'"])([^\'"]*?)\1[^>]*>(.*?)</a>#is' => 
PCCF('return "[[#".preg_replace("/\s+/","_",$m[2]).\']] \'.$m[3];'),

//'#<a\s+([^>]*)>(.*?)</a>#ise' => 'ConvertHtmlLink(stripslashes("$1"), 
   '#<a\s+([^>]*)>(.*?)</a>#is' => PCCF('return ConvertHtmlLink($m[1], 

//'#<select\b([^>]*)>(.*?)</select>#ise' => 
select$1\$1 label=\"\$2\":)","$2")',
   '#<select\b([^>]*)>(.*?)</select>#is' => PCCF('return 
select".$m[1]."\\$1 label=\\"\\$2\\":)",$m[2]);'),

//"#$KeepToken(\d.*?H)$KeepToken#e" => "\$GLOBALS['KPV']['$1']"
   "#$KeepToken(\d.*?H)$KeepToken#" => PCCF("return 

The above should fix the recipe

This is not a simple copy and paste recipe to be applied!

We remove the final "e" from the pattern.

The existing replacement is wrapped with PCCF("return 'EXISTING';").

Inside the replacement, remove any stripslashes() or its shortcut PSS().

Replace any $0, $1, $2, ... with $m[0], $m[1], $m[2]...

If the most external quotes of your replacement are double quotes, add a 
backslash before the $ like \$m[1], otherwise PHP will try to expand the 
$m variable at the moment of writing, instead of the moment of 

Look into your replacement with thought: if a $1 element was inside a 
string like '% $1 %%' then the new string with $m[1] must be written 
differently: '% '.$m[1].'%%'. That is, we break the string into 
concatenated parts so that $m[1] can be expanded at the moment of 
replacement. If we don't, the replacement will contain literal 'dollar' 
'm' 'bracket' '1' 'bracket' and not the value of $m[1].

So yes, it is a bit more complex but can be done with patience and 
concentration. :-) Otherwise we can always help.


Change log     :  http://www.pmwiki.org/wiki/PmWiki/ChangeLog
Release notes  :  http://www.pmwiki.org/wiki/PmWiki/ReleaseNotes
If you upgrade :  http://www.pmwiki.org/wiki/PmWiki/Upgrades

If this message helped you and saved you time, feel free to make
a small contribution:  http://5ko.fr/donate-ml (mailing list).

More information about the pmwiki-users mailing list