I had this regex to fix corrupted serialized objects
$data = preg_replace(
'!s:(\d+):"(.*?)";!se',
"'s:' . strlen('$2') . ':\"$2\";'",
$data
);
But recently updated the code for PHP 5.5+ because of /e modifier has been deprecated
$data = preg_replace_callback(
'/s:(\d+):"(.*?)";/',
create_function(
'$matches',
'return "s:".strlen($matches[2]).":\"".( $matches[2] )."\";";'
),
$data
);
I have analyzed the returning data of the both functions and it seems the new one is deletes additional slashes
result for 1
<a title=\\"A sample title\\" href=\\"http://sitei-url.com/\\">text</a>
result for 2
<a title=\"A sample title\" href=\"http://sitei-url.com/\">text</a>
when I try the unserialize the returning data, the first one is working ok but second one not
I'd appreciated to some help on this!
Thanks
edit
this one seems working as the first one. Added s parameter.
$data = preg_replace_callback(
'/s:(\d+):"(.*?)";/s',
create_function(
'$matches',
'return "s:".strlen($matches[2]).":\"".( $matches[2] )."\";";'
),
$data
);
Thanks for everyone for their answers!
An example with a closure :
$data = preg_replace_callback(
'/s:(\d+):"(.*?)";/',
function($matches) {
return "s:" . strlen($matches[2]) . ":\\\"" . $matches[2] . "\\\";";
),
$data
);
EDIT For PHP 5.2 Compatibility
function pregCallback($matches) {
return "s:" . strlen($matches[2]) . ":\\\"" . $matches[2] . "\\\";";
}
$data = preg_replace_callback('/s:(\d+):"(.*?)";/', 'pregCallback', $data);
Related
I have 'create_function() in my PHP code:
function encode_code_in_comment( $source ) { $encoded = preg_replace_callback( '/\[(php|html|javascript|css|nginx|apache|terminal)\](.*?)\[\/\1\]/ims',
create_function(
'$matches',
'$matches[2] = preg_replace(
array("/^[\r|\n]+/i", "/[\r|\n]+$/i"), "",
$matches[2]);
return "<pre class=\"language-" . $matches[1] . "\"><code>" . esc_html( $matches[2] ) . "</code></pre>";'
),
$source );
if ( $encoded ) {
return $encoded;
} else {
return $source;
}}
I know that there are duplicates threads about the subject, but nevertheless, i'm really struggling to covert this to an anonymous function. How do i rewrite it?
Your main problem is that your code is badly formatted, making it hard to see where the create_function call begins and ends; here it is with some more logical linebreaks and indents:
function encode_code_in_comment( $source ) {
$encoded = preg_replace_callback(
'/\[(php|html|javascript|css|nginx|apache|terminal)\](.*?)\[\/\1\]/ims',
create_function(
'$matches',
'
$matches[2] = preg_replace(
array("/^[\r|\n]+/i", "/[\r|\n]+$/i"),
"",
$matches[2]
);
return "<pre class=\"language-" . $matches[1] . "\"><code>" . esc_html( $matches[2] ) . "</code></pre>";
'
),
$source
);
if ( $encoded ) {
return $encoded;
} else {
return $source;
}
}
From this and the documentation of create_function, we can see that the created function needs one argument, $matches, and to have a body starting $matches[2] = and ending </pre>";
Looking at the manual for anonymous functions we see that the new syntax is function(arguments) { body }, so instead of:
create_function('$matches', ... )
you want:
function($matches) { ... }
and in between, instead of:
'
$matches[2] = ...
...
... </pre>";
'
you want to just remove the quotes and leave the code:
$matches[2] = ...
...
... </pre>";
The body is in single quotes, and there are no escaped single quotes in there, so the code doesn't need any other changes.
I'm writing a regex where I need to filter content to format it's typography. So far, my code seems to be filtering out my content properly using preg_replace, but I can't figure out how to avoid this for content wrapped within certain tags, say <pre>.
As a reference, this is to be used within WordPress's the_content filter, so my current code looks like so:
function my_typography( $str ) {
$ignore_elements = array("code", "pre");
$rules = array(
"?" => array("before"=> " ", "after"=>""),
// the others are stripped out for simplicity
);
foreach($rules as $rule=>$params) {
// Pseudo :
// if( !in_array( $parent_tag, $ignore_elements) {
// /Pseudo
$formatted = $params['before'] . $rule . $params['after'];
$str = preg_replace( $rule, $formatted, $str );
// Pseudo :
// }
// /Pseudo
}
return $str;
}
add_filter( 'the_content', 'my_typography' );
Basically:
<p>Was this filtered? I hope so</p>
<pre>Was this filtered? I hope not.</pre>
should become
<p>Was this filtered ? I hope so</p>
<pre>Was this filtered? I hope not.</pre>
You need to wrap search regex with regex delimiter in preg_replace and must call preg_quote to escape all special regex characters such ?, ., *, + etc:
$str = preg_replace( '~' . preg_quote($rule, '~') . '~', $formatted, $str );
Full Code:
function my_typography( $str ) {
$ignore_elements = array("code", "pre");
$rules = array(
"?" => array("before"=> " ", "after"=>""),
// the others are stripped out for simplicity
);
foreach($rules as $rule=>$params) {
// Pseudo :
// if( !in_array( $parent_tag, $ignore_elements) {
// /Pseudo
$formatted = $params['before'] . $rule . $params['after'];
$str = preg_replace( '~' . preg_quote($rule, '~') . '~', $formatted, $str );
// Pseudo :
// }
// /Pseudo
}
return $str;
}
Output:
<p>Was this filtered ? I hope so</p>
<pre>Was this filtered ? I hope not.</pre>
How can I update this code :
$data = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $array);
with the preg_replace_callback function?
Thanks.
preg_replace_callback() is very similar to preg_replace(), except parameter 2 is a callable function that takes $matches as a parameter. Don't forget to remove the /e modifier, since we aren't executing anything.
$array = array(
's:1:"test";',
's:2:"one more";',
);
$data = preg_replace_callback('!s:(\d+):"(.*?)";!', function($matches) {
$string = $matches[2];
$length = strlen($string);
return 's:' . $length . ':"' . $string . '";';
}, $array);
print_r($data);
// Array ( [0] => s:4:"test"; [1] => s:8:"one more"; )
I found the following online but I'm having trouble implementing it
(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,#?^=%&:/~\+#]*[\w\-\#?^=%&/~\+#])?
This is what I want the php to do:
Take the following : Look here: http://www.rocketlanguages.com/spanish/resources/pronunciation_spanish_accents.php
And turn it into: Look here: http://www.rocketlanguages.com/span...anish_accents.php
If the URL is long then the a text gets broken down with a ... in the middle
Try this:
// URL regex from here:
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
define( 'URL_REGEX', <<<'_END'
~(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))~
_END
);
// PHP 5.3 or higher, can use closures (anonymous functions)
function replace_urls_with_anchor_tags( $string,
$length = 50,
$elision_string = '...' ) {
$replace_function = function( $matches ) use ( $length, $elision_string) {
$matched_url = $matches[ 0 ];
return '<a href="' . $matched_url . '">' .
abbreviated_url( $matched_url, $length, $elision_string ) .
'</a>';
};
return preg_replace_callback(
URL_REGEX,
$replace_function,
$string
);
}
function abbreviated_url( $url, $length = 50, $elision_string = '...' ) {
if ( strlen( $url ) <= $length ) {
return $url;
}
$width_either_side = (int) ( ( $length - strlen( $elision_string ) ) / 2 );
$left = substr( $url, 0, $width_either_side );
$right = substr( $url, strlen( $url ) - $width_either_side );
return $left . $elision_string . $right;
}
(The backtick in the URL_REGEX definition confuses stackoverflow.com's syntax highlighting, but it's nothing to be concerned about)
The function replace_urls_with_anchor_tags takes a string and changes all the URLs matched within to anchor tags, shortening long URLs by eliding with ellipses. The function takes optional length and elision_string arguments in case you wish to play around with the length and change the ellipses to something else.
Here's a usage example:
// Test it out
$test = <<<_END
Look here:
http://www.rocketlanguages.com/spanish/resources/pronunciation_spanish_accents.php
And here:
http://stackoverflow.com/questions/12385770/implementing-web-address-regular-expression
_END;
echo replace_urls_with_anchor_tags( $test, 50, '...' );
// OUTPUT:
// Look here:
// http://www.rocketlangua...ion_spanish_accents.php
//
// And here:
// http://stackoverflow.co...ress-regular-expression
Note that if you are using PHP 5.2 or lower you must rewrite replace_urls_with_anchor_tags to use create_function instead of closures. Closures were not introduced until PHP 5.3:
// No closures in PHP 5.2, must use create_function()
function replace_urls_with_anchor_tags( $string,
$length = 50,
$elision_string = '...' ) {
$replace_function = create_function(
'$matches',
'return "<a href=\"$matches[0]\">" .
abbreviated_url( $matches[ 0 ], ' .
$length . ', ' .
'"' . $elision_string . '"' .
') . "</a>";'
);
return preg_replace_callback(
URL_REGEX,
$replace_function,
$string
);
}
Note that I replaced the URL regex you had found with one linked to on the page DaveRandom referred to in his comment. It's more complete, and in fact there is actually a mistake in the regex you were using -- a couple of '/' characters are not escaped (in here: [\w\-\.,#?^=%&:/~\+#]*[\w\-\#?^=%&/~\+#]). Also, it doesn't detect port numbers like 80 or 8080.
Hope this helps.
I am using this Regular expression and it is working fine for me, try this if you want
(http|https|ftp):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?
I have this interesting function that I'm using to create new lines into paragraphs. I'm using it instead of the nl2br() function, as it outputs better formatted text.
function nl2p($string, $line_breaks = true, $xml = true) {
$string = str_replace(array('<p>', '</p>', '<br>', '<br />'), '', $string);
// It is conceivable that people might still want single line-breaks
// without breaking into a new paragraph.
if ($line_breaks == true)
return '<p>'.preg_replace(array("/([\n]{2,})/i", "/([^>])\n([^<])/i"), array("</p>\n<p>", '<br'.($xml == true ? ' /' : '').'>'), trim($string)).'</p>';
else
return '<p>'.preg_replace(
array("/([\n]{2,})/i", "/([\r\n]{3,})/i","/([^>])\n([^<])/i"),
array("</p>\n<p>", "</p>\n<p>", '<br'.($xml == true ? ' /' : '').'>'),
trim($string)).'</p>';
}
The problem is that whenever I try to create a single line break, it inadvertently removes the first character of the paragraph below it. I'm not familiar enough with regex to understand what is causing the problem.
Here is another approach that doesn't use regular expressions. Note, this function will remove any single line-breaks.
function nl2p($string)
{
$paragraphs = '';
foreach (explode("\n", $string) as $line) {
if (trim($line)) {
$paragraphs .= '<p>' . $line . '</p>';
}
}
return $paragraphs;
}
If you only need to do this once in your app and don't want to create a function, it can easily be done inline:
<?php foreach (explode("\n", $string) as $line): ?>
<?php if (trim($line)): ?>
<p><?=$line?></p>
<?php endif ?>
<?php endforeach ?>
The problem is with your match for single line breaks. It matches the last character before the line break and the first after. Then you replace the match with <br>, so you lose those characters as well. You need to keep them in the replacement.
Try this:
function nl2p($string, $line_breaks = true, $xml = true) {
$string = str_replace(array('<p>', '</p>', '<br>', '<br />'), '', $string);
// It is conceivable that people might still want single line-breaks
// without breaking into a new paragraph.
if ($line_breaks == true)
return '<p>'.preg_replace(array("/([\n]{2,})/i", "/([^>])\n([^<])/i"), array("</p>\n<p>", '$1<br'.($xml == true ? ' /' : '').'>$2'), trim($string)).'</p>';
else
return '<p>'.preg_replace(
array("/([\n]{2,})/i", "/([\r\n]{3,})/i","/([^>])\n([^<])/i"),
array("</p>\n<p>", "</p>\n<p>", '$1<br'.($xml == true ? ' /' : '').'>$2'),
trim($string)).'</p>';
}
I also wrote a very simple version:
function nl2p($text)
{
return '<p>' . str_replace(['\r\n', '\r', '\n'], '</p><p>', $text) . '</p>';
}
#Laurent's answer wasn't working for me - the else statement was doing what the $line_breaks == true statement should have been doing, and it was making multiple line breaks into <br> tags, which PHP's native nl2br() already does.
Here's what I managed to get working with the expected behavior:
function nl2p( $string, $line_breaks = true, $xml = true ) {
// Remove current tags to avoid double-wrapping.
$string = str_replace( array( '<p>', '</p>', '<br>', '<br />' ), '', $string );
// Default: Use <br> for single line breaks, <p> for multiple line breaks.
if ( $line_breaks == true ) {
$string = '<p>' . preg_replace(
array( "/([\n]{2,})/i", "/([\r\n]{3,})/i", "/([^>])\n([^<])/i" ),
array( "</p>\n<p>", "</p>\n<p>", '$1<br' . ( $xml == true ? ' /' : '' ) . '>$2' ),
trim( $string ) ) . '</p>';
// Use <p> for all line breaks if $line_breaks is set to false.
} else {
$string = '<p>' . preg_replace(
array( "/([\n]{1,})/i", "/([\r]{1,})/i" ),
"</p>\n<p>",
trim( $string ) ) . '</p>';
}
// Remove empty paragraph tags.
$string = str_replace( '<p></p>', '', $string );
// Return string.
return $string;
}
Here's an approach that comes with a reverse method to replace paragraphs back to regular line breaks and vice versa.
These are useful to use when building a form input. When saving a users input you may want to convert line breaks to paragraph tags, however when editing the text in a form, you may not want the user to see any html characters. Then we would replace the paragraphs back to line breaks.
// This function will convert newlines to HTML paragraphs
// without paying attention to HTML tags. Feed it a raw string and it will
// simply return that string sectioned into HTML paragraphs
function nl2p($str) {
$arr=explode("\n",$str);
$out='';
for($i=0;$i<count($arr);$i++) {
if(strlen(trim($arr[$i]))>0)
$out.='<p>'.trim($arr[$i]).'</p>';
}
return $out;
}
// Return paragraph tags back to line breaks
function p2nl($str)
{
$str = preg_replace("/<p[^>]*?>/", "", $str);
$str = str_replace("</p>", "\r\n", $str);
return $str;
}
Expanding upon #NaturalBornCamper's solution:
function nl2p( $text, $class = '' ) {
$string = str_replace( array( "\r\n\r\n", "\n\n" ), '</p><p>', $text);
$string = str_replace( array( "\r\n", "\n" ), '<br />', $string);
return '<p' . ( $class ? ' class="' . $class . '"' : '' ) . '>' . $string . '</p>';
}
This takes care of both double line breaks by converting them to paragraphs, and single line breaks by converting them to <br />
Just type this between your lines:
echo '<br>';
This will give you a new line.