require_once("include/bbcode.php");
require_once("include/markdownify/markdownify.php");
+
+ function get_bb_tag_pos($s, $name, $occurance = 1) {
+
+ if($occurance < 1)
+ $occurance = 1;
+
+ $start_open = -1;
+ for($i = 1; $i <= $occurance; $i++) {
+ if( $start_open !== false)
+ $start_open = strpos($s, '[' . $name, $start_open + 1); // allow [name= type tags
+ }
+
+ if( $start_open === false)
+ return false;
+
+ $start_equal = strpos($s, '=', $start_open);
+ $start_close = strpos($s, ']', $start_open);
+
+ if( $start_close === false)
+ return false;
+
+ $start_close++;
+
+ $end_open = strpos($s, '[/' . $name . ']', $start_close);
+
+ if( $end_open === false)
+ return false;
+
+ $res = array( 'start' => array('open' => $start_open, 'close' => $start_close),
+ 'end' => array('open' => $end_open, 'close' => $end_open + strlen('[/' . $name . ']')) );
+ if( $start_equal !== false)
+ $res['start']['equal'] = $start_equal + 1;
+
+ return $res;
+ }
+
+ function bb_tag_preg_replace($pattern, $replace, $name, $s) {
+
+ $string = $s;
+
+ $occurance = 1;
+ $pos = get_bb_tag_pos($string, $name, $occurance);
+ while($pos !== false && $occurance < 1000) {
+
+ $start = substr($string, 0, $pos['start']['open']);
+ $subject = substr($string, $pos['start']['open'], $pos['end']['close'] - $pos['start']['open']);
+ $end = substr($string, $pos['end']['close']);
+ if($end === false)
+ $end = '';
+
+ $subject = preg_replace($pattern, $replace, $subject);
+ $string = $start . $subject . $end;
+
+ $occurance++;
+ $pos = get_bb_tag_pos($string, $name, $occurance);
+ }
+
+ return $string;
+ }
+
// we don't want to support a bbcode specific markdown interpreter
// and the markdown library we have is pretty good, but provides HTML output.
// So we'll use that to convert to HTML, then convert the HTML back to bbcode,
$s = Markdown($s);
$s = str_replace('#','#',$s);
-
- $s = str_replace("\n",'<br />',$s);
+ // we seem to have double linebreaks
+ // $s = str_replace("\n",'<br />',$s);
$s = html2bbcode($s);
// $s = str_replace('*','*',$s);
+ // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands
+ $s = str_replace('♲',html_entity_decode('♲',ENT_QUOTES,'UTF-8'),$s);
+
// Convert everything that looks like a link to a link
$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3]$2$3[/url]',$s);
//$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s);
- $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism",'[youtube]$2[/youtube]',$s);
- $s = preg_replace("/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism",'[youtube]$1[/youtube]',$s);
- $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism",'[vimeo]$2[/vimeo]',$s);
- $s = preg_replace("/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism",'[vimeo]$1[/vimeo]',$s);
+ $s = bb_tag_preg_replace("/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism",'[youtube]$2[/youtube]','url',$s);
+ $s = bb_tag_preg_replace("/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism",'[youtube]$1[/youtube]','url',$s);
+ $s = bb_tag_preg_replace("/\[url\=?(.*?)\]https?:\/ \/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism",'[vimeo]$2[/vimeo]','url',$s);
+ $s = bb_tag_preg_replace("/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism",'[vimeo]$1[/vimeo]','url',$s);
// remove duplicate adjacent code tags
$s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism","[code]$2[/code]", $s);
}
+ //////////////////////
+ // The following "diaspora_ul" and "diaspora_ol" are only appropriate for the
+ // pre-Markdownify conversion. If Markdownify isn't used, use the non-Markdownify
+ // versions below
+ //////////////////////
+ /*
function diaspora_ul($s) {
// Replace "[*]" followed by any number (including zero) of
// spaces by "* " to match Diaspora's list format
else
return $s[0];
}
+ */
+
+ //////////////////////
+ // Non-Markdownify versions of "diaspora_ol" and "diaspora_ul"
+ //////////////////////
+ function diaspora_ul($s) {
+ // Replace "[\\*]" followed by any number (including zero) of
+ // spaces by "* " to match Diaspora's list format
+ return preg_replace("/\[\\\\\*\]( *)/", "* ", $s[1]);
+ }
+
+ function diaspora_ol($s) {
+ // A hack: Diaspora will create a properly-numbered ordered list even
+ // if you use '1.' for each element of the list, like:
+ // 1. First element
+ // 1. Second element
+ // 1. Third element
+ return preg_replace("/\[\\\\\*\]( *)/", "1. ", $s[1]);
+ }
function bb2diaspora($Text,$preserve_nl = false) {
-//////////////////////
-// An attempt was made to convert bbcode to html and then to markdown
-// consisting of the following lines.
-// I'm undoing this as we have a lot of bbcode constructs which
-// were simply getting lost, for instance bookmark, vimeo, video, youtube, events, etc.
-// We can try this again, but need a very good test sequence to verify
-// all the major bbcode constructs that we use are getting through.
-//////////////////////
-/*
-- // bbcode() will convert "[*]" into "<li>" with no closing "</li>"
-- // Markdownify() is unable to handle these, as it makes each new
-- // "<li>" into a deeper nested element until it crashes. So pre-format
-- // the lists as Diaspora lists before sending the $Text to bbcode()
-- //
-- // Note that to get nested lists to work for Diaspora, we would need
-- // to define the closing tag for the list elements. So nested lists
-- // are going to be flattened out in Diaspora for now
- /* $endlessloop = 0;
-
- $endlessloop = 0;
-- while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) ||
-- ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) ||
-- ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false))) && (++$endlessloop < 20)) {
-- $Text = preg_replace_callback("/\[list\](.*?)\[\/list\]/is", 'diaspora_ul', $Text);
-- $Text = preg_replace_callback("/\[list=1\](.*?)\[\/list\]/is", 'diaspora_ol', $Text);
-- $Text = preg_replace_callback("/\[list=i\](.*?)\[\/list\]/s",'diaspora_ol', $Text);
-- $Text = preg_replace_callback("/\[list=I\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
-- $Text = preg_replace_callback("/\[list=a\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
-- $Text = preg_replace_callback("/\[list=A\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
-- $Text = preg_replace_callback("/\[ul\](.*?)\[\/ul\]/is", 'diaspora_ul', $Text);
-- $Text = preg_replace_callback("/\[ol\](.*?)\[\/ol\]/is", 'diaspora_ol', $Text);
-- }
-
--*/
++ // Re-enabling the converter again.
++ // The bbcode parser now handles youtube-links (and the other stuff) correctly.
++ // Additionally the html code is now fixed so that lists are now working.
+
// Convert it to HTML - don't try oembed
-// $Text = bbcode($Text, $preserve_nl, false);
+ $Text = bbcode($Text, $preserve_nl, false);
// Now convert HTML to Markdown
-// $md = new Markdownify(false, false, false);
-// $Text = $md->parseString($Text);
+ $md = new Markdownify(false, false, false);
+ $Text = $md->parseString($Text);
// If the text going into bbcode() has a plain URL in it, i.e.
// with no [url] tags around it, it will come out of parseString()
// looking like: <http://url.com>, which gets removed by strip_tags().
// So take off the angle brackets of any such URL
-// $Text = preg_replace("/<http(.*?)>/is", "http$1", $Text);
+ $Text = preg_replace("/<http(.*?)>/is", "http$1", $Text);
// Remove all unconverted tags
-// $Text = strip_tags($Text);
-
-//////
-// end of bb->html->md conversion attempt
-//////
+ $Text = strip_tags($Text);
- /*
+
++/* Old routine
+
$ev = bbtoevent($Text);
// Replace any html brackets with HTML Entities to prevent executing HTML or script
$Text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])is","$2",$Text);
// Check for list text
- $Text = preg_replace_callback("/\[list\](.*?)\[\/list\]/is", 'diaspora_ul', $Text);
- $Text = preg_replace_callback("/\[ul\](.*?)\[\/ul\]/is", 'diaspora_ul', $Text);
- $Text = preg_replace_callback("/\[list=1\](.*?)\[\/list\]/is", 'diaspora_ol', $Text);
- $Text = preg_replace_callback("/\[list=i\](.*?)\[\/list\]/s",'diaspora_ol', $Text);
- $Text = preg_replace_callback("/\[list=I\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
- $Text = preg_replace_callback("/\[list=a\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
- $Text = preg_replace_callback("/\[list=A\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
- $Text = preg_replace_callback("/\[ol\](.*?)\[\/ol\]/is", 'diaspora_ol', $Text);
- // $Text = preg_replace("/\[li\](.*?)\[\/li\]/s", '<li>$1</li>' ,$Text);
+ $endlessloop = 0;
+ while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) ||
+ ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) ||
+ ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) ||
+ ((strpos($Text, "[/li]") !== false) && (strpos($Text, "[li]") !== false))) && (++$endlessloop < 20)) {
+ $Text = preg_replace_callback("/\[list\](.*?)\[\/list\]/is", 'diaspora_ul', $Text);
+ $Text = preg_replace_callback("/\[list=1\](.*?)\[\/list\]/is", 'diaspora_ol', $Text);
+ $Text = preg_replace_callback("/\[list=i\](.*?)\[\/list\]/s",'diaspora_ol', $Text);
+ $Text = preg_replace_callback("/\[list=I\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
+ $Text = preg_replace_callback("/\[list=a\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
+ $Text = preg_replace_callback("/\[list=A\](.*?)\[\/list\]/s", 'diaspora_ol', $Text);
+ $Text = preg_replace_callback("/\[ul\](.*?)\[\/ul\]/is", 'diaspora_ul', $Text);
+ $Text = preg_replace_callback("/\[ol\](.*?)\[\/ol\]/is", 'diaspora_ol', $Text);
+ $Text = preg_replace("/\[li\]( *)(.*?)\[\/li\]/s", '* $2' ,$Text);
+ }
// Just get rid of table tags since Diaspora doesn't support tables
$Text = preg_replace("/\[th\](.*?)\[\/th\]/s", '$1' ,$Text);
// If we found an event earlier, strip out all the event code and replace with a reformatted version.
- if(x($ev,'desc') && x($ev,'start')) {
+ if(x($ev,'start')) {
$sub = format_event_diaspora($ev);
- $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/is",$sub,$Text);
- $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/is",'',$Text);
+ $Text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/is",'',$Text);
+ $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/is",'',$Text);
+ $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/is",$sub,$Text);
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/is",'',$Text);
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/is",'',$Text);
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",'',$Text);
$Text = preg_replace("/\<(.*?)(src|href)=(.*?)\&\;(.*?)\>/ism",'<$1$2=$3&$4>',$Text);
$Text = preg_replace_callback('/\[(.*?)\]\((.*?)\)/ism','unescape_underscores_in_links',$Text);
+
+*/
// Remove any leading or trailing whitespace, as this will mess up
// the Diaspora signature verification and cause the item to disappear
$o = 'Friendica event notification:' . "\n";
- $o .= '**' . bb2diaspora($ev['desc']) . '**' . "\n";
+ $o .= '**' . (($ev['summary']) ? bb2diaspora($ev['summary']) : bb2diaspora($ev['desc'])) . '**' . "\n";
$o .= t('Starts:') . ' ' . '['
. (($ev['adjust']) ? day_translate(datetime_convert('UTC', 'UTC',
return $unspacefied;
}
+ if(! function_exists('bb_extract_images')) {
+ function bb_extract_images($body) {
+
+ $saved_image = array();
+ $orig_body = $body;
+ $new_body = '';
+
+ $cnt = 0;
+ $img_start = strpos($orig_body, '[img');
+ $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
+ $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
+ while(($img_st_close !== false) && ($img_end !== false)) {
+
+ $img_st_close++; // make it point to AFTER the closing bracket
+ $img_end += $img_start;
+
+ if(! strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) {
+ // This is an embedded image
+
+ $saved_image[$cnt] = substr($orig_body, $img_start + $img_st_close, $img_end - ($img_start + $img_st_close));
+ $new_body = $new_body . substr($orig_body, 0, $img_start) . '[$#saved_image' . $cnt . '#$]';
+
+ $cnt++;
+ }
+ else
+ $new_body = $new_body . substr($orig_body, 0, $img_end + strlen('[/img]'));
+
+ $orig_body = substr($orig_body, $img_end + strlen('[/img]'));
+
+ if($orig_body === false) // in case the body ends on a closing image tag
+ $orig_body = '';
+
+ $img_start = strpos($orig_body, '[img');
+ $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
+ $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
+ }
+
+ $new_body = $new_body . $orig_body;
+
+ return array('body' => $new_body, 'images' => $saved_image);
+ }}
+
+ if(! function_exists('bb_replace_images')) {
+ function bb_replace_images($body, $images) {
+
+ $newbody = $body;
+
+ $cnt = 0;
+ foreach($images as $image) {
+ // We're depending on the property of 'foreach' (specified on the PHP website) that
+ // it loops over the array starting from the first element and going sequentially
+ // to the last element
+ $newbody = str_replace('[$#saved_image' . $cnt . '#$]', '<img src="' . $image .'" alt="' . t('Image/photo') . '" />', $newbody);
+ $cnt++;
+ }
+
+ return $newbody;
+ }}
+
+
+
// BBcode 2 HTML was written by WAY2WEB.net
// extended to work with Mistpark/Friendica - Mike Macgirvin
$a = get_app();
- // Hide all [noparse] contained bbtags spacefying them
+ // Hide all [noparse] contained bbtags by spacefying them
+ // POSSIBLE BUG --> Will the 'preg' functions crash if there's an embedded image?
$Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_spacefy',$Text);
$Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_spacefy',$Text);
$Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy',$Text);
- // Extract a single private image which uses data url's since preg has issues with
- // large data sizes. Stash it away while we do bbcode conversion, and then put it back
+ // Extract the private images which use data url's since preg has issues with
+ // large data sizes. Stash them away while we do bbcode conversion, and then put them back
// in after we've done all the regex matching. We cannot use any preg functions to do this.
- $saved_image = '';
- $img_start = strpos($Text,'[img]data:');
- $img_end = strpos($Text,'[/img]');
-
- if($img_start !== false && $img_end !== false && $img_end > $img_start) {
- $start_fragment = substr($Text,0,$img_start);
- $img_start += strlen('[img]');
- $saved_image = substr($Text,$img_start,$img_end - $img_start);
- $end_fragment = substr($Text,$img_end + strlen('[/img]'));
- // logger('saved_image: ' . $saved_image,LOGGER_DEBUG);
- $Text = $start_fragment . '[$#saved_image#$]' . $end_fragment;
- }
+ $extracted = bb_extract_images($Text);
+ $Text = $extracted['body'];
+ $saved_image = $extracted['images'];
// If we find any event code, turn it into an event.
// After we're finished processing the bbcode we'll
// Convert new line chars to html <br /> tags
- $Text = nl2br($Text);
+ // nlbr seems to be hopelessly messed up
+ // $Text = nl2br($Text);
+
+ // We'll emulate it.
+
+ $Text = str_replace("\r\n","\n", $Text);
+ $Text = str_replace(array("\r","\n"), array('<br />','<br />'), $Text);
+
if($preserve_nl)
$Text = str_replace(array("\n","\r"), array('',''),$Text);
+
// Set up the parameters for a URL search string
$URLSearchString = "^\[\]";
// Set up the parameters for a MAIL search string
// Check for list text
$Text = str_replace("[*]", "<li>", $Text);
- $Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '<li>$1</li>' ,$Text);
// handle nested lists
$endlessloop = 0;
while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) ||
((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) ||
- ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false))) && (++$endlessloop < 20)) {
+ ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) ||
+ ((strpos($Text, "[/li]") !== false) && (strpos($Text, "[li]") !== false))) && (++$endlessloop < 20)) {
$Text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>' ,$Text);
$Text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '<ul class="listnone" style="list-style-type: none;">$1</ul>' ,$Text);
$Text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '<ul class="listdecimal" style="list-style-type: decimal;">$1</ul>' ,$Text);
$Text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '<ul class="listupperalpha" style="list-style-type: upper-alpha;">$2</ul>' ,$Text);
$Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>' ,$Text);
$Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '<ul class="listdecimal" style="list-style-type: decimal;">$1</ul>' ,$Text);
+ $Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '<li>$1</li>' ,$Text);
}
$Text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '<th>$1</th>' ,$Text);
// Declare the format for [code] layout
- $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism",'stripcode_br_cb',$Text);
+ // $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism",'stripcode_br_cb',$Text);
$CodeLayout = '<code>$1</code>';
// Check for [code] text
$Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img src="$1" alt="' . t('Image/photo') . '" />', $Text);
- $Text = preg_replace("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4))\[\/video\]/ism", '<video src="$1" controls="controls" width="425" height="350"><a href="$1">$1</a></video>', $Text);
-
- $Text = preg_replace("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3))\[\/audio\]/ism", '<audio src="$1" controls="controls"><a href="$1">$1</a></audio>', $Text);
-
// Try to Oembed
if ($tryoembed) {
+ $Text = preg_replace("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4))\[\/video\]/ism", '<video src="$1" controls="controls" width="425" height="350"><a href="$1">$1</a></video>', $Text);
+ $Text = preg_replace("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3))\[\/audio\]/ism", '<audio src="$1" controls="controls"><a href="$1">$1</a></audio>', $Text);
+
$Text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", 'tryoembed', $Text);
$Text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", 'tryoembed', $Text);
+ } else {
+ $Text = preg_replace("/\[video\](.*?)\[\/video\]/", '$1', $Text);
+ $Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '$1', $Text);
}
// html5 video and audio
- $Text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<iframe src="$1" width="425" height="350"><a href="$1">$1</a></iframe>', $Text);
-
+ if ($tryoembed)
+ $Text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<iframe src="$1" width="425" height="350"><a href="$1">$1</a></iframe>', $Text);
+ else
+ $Text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<a href="$1">$1</a>', $Text);
// Youtube extensions
if ($tryoembed) {
$Text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism",'[youtube]$1[/youtube]',$Text);
$Text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism",'[youtube]$1[/youtube]',$Text);
- $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="425" height="350" src="http://www.youtube.com/embed/$1" frameborder="0" ></iframe>', $Text);
+ if ($tryoembed)
+ $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="425" height="350" src="http://www.youtube.com/embed/$1" frameborder="0" ></iframe>', $Text);
+ else
+ $Text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", "http://www.youtube.com/watch?v=$1", $Text);
if ($tryoembed) {
}
$Text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism",'[vimeo]$1[/vimeo]',$Text);
- $Text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism",'[vimeo]$1[/vimeo]',$Text);
- $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '<iframe width="425" height="350" src="http://player.vimeo.com/video/$1" frameborder="0" ></iframe>', $Text);
+ $Text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism",'[vimeo]$1[/vimeo]',$Text);
+
+ if ($tryoembed)
+ $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '<iframe width="425" height="350" src="http://player.vimeo.com/video/$1" frameborder="0" ></iframe>', $Text);
+ else
+ $Text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", "http://vimeo.com/$1", $Text);
// $Text = preg_replace("/\[youtube\](.*?)\[\/youtube\]/", '<object width="425" height="350" type="application/x-shockwave-flash" data="http://www.youtube.com/v/$1" ><param name="movie" value="http://www.youtube.com/v/$1"></param><!--[if IE]><embed src="http://www.youtube.com/v/$1" type="application/x-shockwave-flash" width="425" height="350" /><![endif]--></object>', $Text);
// fix any escaped ampersands that may have been converted into links
$Text = preg_replace("/\<(.*?)(src|href)=(.*?)\&\;(.*?)\>/ism",'<$1$2=$3&$4>',$Text);
- if(strlen($saved_image))
- $Text = str_replace('[$#saved_image#$]','<img src="' . $saved_image .'" alt="' . t('Image/photo') . '" />',$Text);
+
+ if($saved_image)
+ $Text = bb_replace_images($Text, $saved_image);
+ // Clean up the HTML by loading and saving the HTML with the DOM
+ // Only do it when it has to be done - for performance reasons
+ if (!$tryoembed) {
+ $doc = new DOMDocument();
+ $doc->preserveWhiteSpace = false;
+
+ $Text = mb_convert_encoding($Text, 'HTML-ENTITIES', "UTF-8");
+
+ $doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">';
+ @$doc->loadHTML($doctype."<html><body>".$Text."</body></html>");
+
+ $Text = $doc->saveHTML();
+ $Text = str_replace(array("<html><body>", "</body></html>", $doctype), array("", "", ""), $Text);
+
+ $Text = str_replace('<br></li>','</li>', $Text);
+
+ $Text = mb_convert_encoding($Text, "UTF-8", 'HTML-ENTITIES');
+ }
+
call_hooks('bbcode',$Text);
return $Text;
}
public function q($sql) {
+ global $a;
if((! $this->db) || (! $this->connected))
return false;
$this->error = '';
- //if (get_config("system", "db_log") != "")
- // @file_put_contents(get_config("system", "db_log"), datetime_convert().':'.session_id(). ' Start '.$sql."\n", FILE_APPEND);
+ if ($a->config["system"]["db_log"] != "")
+ $stamp1 = microtime(true);
if($this->mysqli)
$result = @$this->db->query($sql);
else
$result = @mysql_query($sql,$this->db);
- //if (get_config("system", "db_log") != "")
- // @file_put_contents(get_config("system", "db_log"), datetime_convert().':'.session_id(). ' Stop '."\n", FILE_APPEND);
+ if ($a->config["system"]["db_log"] != "") {
+ $stamp2 = microtime(true);
+ $duration = round($stamp2-$stamp1, 3);
+ if ($duration > $a->config["system"]["db_loglimit"]) {
+ $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ @file_put_contents($a->config["system"]["db_log"], $duration."\t".
+ basename($backtrace[1]["file"])."\t".
+ $backtrace[1]["line"]."\t".$backtrace[2]["function"]."\t".
+ substr($sql, 0, 2000)."\n", FILE_APPEND);
+ }
+ }
if($this->mysqli) {
if($this->db->errno)
array_walk($arr,'dbesc_array_cb');
}
}}
+
+
+ function dba_timer() {
+ return microtime(true);
+ }
+
require_once('include/oembed.php');
require_once('include/salmon.php');
require_once('include/crypto.php');
+ require_once('include/Photo.php');
+
function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) {
}
return '';
- }
+ }
+
+ /* limit_body_size()
+ *
+ * The purpose of this function is to apply system message length limits to
+ * imported messages without including any embedded photos in the length
+ */
+ if(! function_exists('limit_body_size')) {
+ function limit_body_size($body) {
+
+ logger('limit_body_size: start', LOGGER_DEBUG);
+
+ $maxlen = get_max_import_size();
+
+ // If the length of the body, including the embedded images, is smaller
+ // than the maximum, then don't waste time looking for the images
+ if($maxlen && (strlen($body) > $maxlen)) {
+
+ logger('limit_body_size: the total body length exceeds the limit', LOGGER_DEBUG);
+
+ $orig_body = $body;
+ $new_body = '';
+ $textlen = 0;
+ $max_found = false;
+
+ $img_start = strpos($orig_body, '[img');
+ $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
+ $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
+ while(($img_st_close !== false) && ($img_end !== false)) {
+
+ $img_st_close++; // make it point to AFTER the closing bracket
+ $img_end += $img_start;
+ $img_end += strlen('[/img]');
+
+ if(! strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) {
+ // This is an embedded image
+
+ if( ($textlen + $img_start) > $maxlen ) {
+ if($textlen < $maxlen) {
+ logger('limit_body_size: the limit happens before an embedded image', LOGGER_DEBUG);
+ $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
+ $textlen = $maxlen;
+ }
+ }
+ else {
+ $new_body = $new_body . substr($orig_body, 0, $img_start);
+ $textlen += $img_start;
+ }
+
+ $new_body = $new_body . substr($orig_body, $img_start, $img_end - $img_start);
+ }
+ else {
+
+ if( ($textlen + $img_end) > $maxlen ) {
+ if($textlen < $maxlen) {
+ logger('limit_body_size: the limit happens before the end of a non-embedded image', LOGGER_DEBUG);
+ $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
+ $textlen = $maxlen;
+ }
+ }
+ else {
+ $new_body = $new_body . substr($orig_body, 0, $img_end);
+ $textlen += $img_end;
+ }
+ }
+ $orig_body = substr($orig_body, $img_end);
+
+ if($orig_body === false) // in case the body ends on a closing image tag
+ $orig_body = '';
+
+ $img_start = strpos($orig_body, '[img');
+ $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
+ $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
+ }
+
+ if( ($textlen + strlen($orig_body)) > $maxlen) {
+ if($textlen < $maxlen) {
+ logger('limit_body_size: the limit happens after the end of the last image', LOGGER_DEBUG);
+ $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
+ $textlen = $maxlen;
+ }
+ }
+ else {
+ logger('limit_body_size: the text size with embedded images extracted did not violate the limit', LOGGER_DEBUG);
+ $new_body = $new_body . $orig_body;
+ $textlen += strlen($orig_body);
+ }
+
+ return $new_body;
+ }
+ else
+ return $body;
+ }}
+function title_is_body($title, $body) {
+
+ $title = strip_tags($title);
+ $title = trim($title);
+ $title = str_replace(array("\n", "\r", "\t", " "), array("","","",""), $title);
+
+ $body = strip_tags($body);
+ $body = trim($body);
+ $body = str_replace(array("\n", "\r", "\t", " "), array("","","",""), $body);
+
+ if (strlen($title) < strlen($body))
+ $body = substr($body, 0, strlen($title));
+
+ if (($title != $body) and (substr($title, -3) == "...")) {
+ $pos = strrpos($title, "...");
+ if ($pos > 0) {
+ $title = substr($title, 0, $pos);
+ $body = substr($body, 0, $pos);
+ }
+ }
+
+ return($title == $body);
+}
$res['body'] = unxmlify($item->get_content());
$res['plink'] = unxmlify($item->get_link(0));
+ // removing the content of the title if its identically to the body
+ // This helps with auto generated titles e.g. from tumblr
+ if (title_is_body($res["title"], $res["body"]))
+ $res['title'] = "";
+
if($res['plink'])
$base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
else
$res['author-avatar'] = unxmlify($link['attribs']['']['href']);
}
}
- }
+ }
$rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
$res['author-avatar'] = unxmlify($link['attribs']['']['href']);
}
}
- }
+ }
$rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
$res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
if($res['app'] === 'web')
$res['app'] = 'OStatus';
- }
+ }
// base64 encoded json structure representing Diaspora signature
$res['body'] = notags(base64url_decode($res['body']));
}
- $maxlen = get_max_import_size();
- if($maxlen && (strlen($res['body']) > $maxlen))
- $res['body'] = substr($res['body'],0, $maxlen);
+
+ $res['body'] = limit_body_size($res['body']);
// It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust
// the content type. Our own network only emits text normally, though it might have been converted to
foreach($base as $link) {
if(!x($res, 'owner-avatar') || !$res['owner-avatar']) {
- if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
+ if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
$res['owner-avatar'] = unxmlify($link['attribs']['']['href']);
}
}
call_hooks('parse_atom', $arr);
+ //if (($res["title"] != "") or (strpos($res["body"], "RT @") > 0)) {
+ if (strpos($res["body"], "RT @") !== false) {
+ $debugfile = tempnam("/home/ike/log", "item-res2-");
+ file_put_contents($debugfile, serialize($arr));
+ }
+
return $res;
}
if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false))
$arr['body'] = strip_tags($arr['body']);
+ require_once('Text/LanguageDetect.php');
+ $naked_body = preg_replace('/\[(.+?)\]/','',$arr['body']);
+ $l = new Text_LanguageDetect;
+ $lng = $l->detectConfidence($naked_body);
+ $arr['postopts'] = (($lng['language']) ? 'lang=' . $lng['language'] . ';' . $lng['confidence'] : '');
+
$arr['wall'] = ((x($arr,'wall')) ? intval($arr['wall']) : 0);
$arr['uri'] = ((x($arr,'uri')) ? notags(trim($arr['uri'])) : random_string());
if($r[0]['uri'] != $r[0]['parent-uri']) {
$arr['thr-parent'] = $arr['parent-uri'];
$arr['parent-uri'] = $r[0]['parent-uri'];
- $z = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `parent-uri` = '%s' AND `uid` = %d
+ $z = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `parent-uri` = '%s' AND `uid` = %d
ORDER BY `id` ASC LIMIT 1",
dbesc($r[0]['parent-uri']),
dbesc($r[0]['parent-uri']),
// Now process the feed
- if($feed->get_item_quantity()) {
+ if($feed->get_item_quantity()) {
logger('consume_feed: feed item count = ' . $feed->get_item_quantity());
foreach($items as $item) {
- $is_reply = false;
+ $is_reply = false;
$item_id = $item->get_id();
$rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
if(isset($rawthread[0]['attribs']['']['ref'])) {
continue;
// Have we seen it? If not, import it.
-
+
$item_id = $item->get_id();
$datarray = get_atom_elements($feed,$item);
-
if((! x($datarray,'author-name')) && ($contact['network'] != NETWORK_DFRN))
$datarray['author-name'] = $contact['name'];
if((! x($datarray,'author-link')) && ($contact['network'] != NETWORK_DFRN))
}
if($item['uri'] == $item['parent-uri']) {
- $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s'
+ $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
+ `body` = '', `title` = ''
WHERE `parent-uri` = '%s' AND `uid` = %d",
dbesc($when),
dbesc(datetime_convert()),
);
}
else {
- $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s'
+ $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',
+ `body` = '', `title` = ''
WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($when),
dbesc(datetime_convert()),
return $o;
}
- function fix_private_photos($s,$uid, $item = null, $cid = 0) {
+ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
$a = get_app();
logger('fix_private_photos', LOGGER_DEBUG);
$site = substr($a->get_baseurl(),strpos($a->get_baseurl(),'://'));
- if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/is",$s,$matches)) {
- $image = $matches[2];
+ $orig_body = $s;
+ $new_body = '';
+
+ $img_start = strpos($orig_body, '[img');
+ $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
+ $img_len = ($img_start !== false ? strpos(substr($orig_body, $img_start + $img_st_close + 1), '[/img]') : false);
+ while( ($img_st_close !== false) && ($img_len !== false) ) {
+
+ $img_st_close++; // make it point to AFTER the closing bracket
+ $image = substr($orig_body, $img_start + $img_st_close, $img_len);
+
logger('fix_private_photos: found photo ' . $image, LOGGER_DEBUG);
+
+
if(stristr($image , $site . '/photo/')) {
+ // Only embed locally hosted photos
$replace = false;
$i = basename($image);
$i = str_replace(array('.jpg','.png'),array('',''),$i);
$x = strpos($i,'-');
+
if($x) {
$res = substr($i,$x+1);
$i = substr($i,0,$x);
// 3. Otherwise, if we have an item, see if the item permissions match the photo
// permissions, regardless of order but first check to see if they're an exact
// match to save some processing overhead.
-
- // Currently we only embed one private photo per message so as not to hit import
- // size limits at the receiving end.
-
- // To embed multiples, we would need to parse out the embedded photos on message
- // receipt and limit size based only on the text component. Would also need to
- // ignore all photos during bbcode translation and item localisation, as these
- // will hit internal regex backtrace limits.
if(has_permissions($r[0])) {
if($cid) {
}
}
if($replace) {
+ $data = $r[0]['data'];
+ $type = $r[0]['type'];
+
+ // If a custom width and height were specified, apply before embedding
+ if(preg_match("/\[img\=([0-9]*)x([0-9]*)\]/is", substr($orig_body, $img_start, $img_st_close), $match)) {
+ logger('fix_private_photos: scaling photo', LOGGER_DEBUG);
+
+ $width = intval($match[1]);
+ $height = intval($match[2]);
+
+ $ph = new Photo($data, $type);
+ if($ph->is_valid()) {
+ $ph->scaleImage(max($width, $height));
+ $data = $ph->imageString();
+ $type = $ph->getType();
+ }
+ }
+
logger('fix_private_photos: replacing photo', LOGGER_DEBUG);
- $s = str_replace($image, 'data:' . $r[0]['type'] . ';base64,' . base64_encode($r[0]['data']), $s);
- logger('fix_private_photos: replaced: ' . $s, LOGGER_DATA);
+ $image = 'data:' . $type . ';base64,' . base64_encode($data);
+ logger('fix_private_photos: replaced: ' . $image, LOGGER_DATA);
}
}
}
}
+
+ $new_body = $new_body . substr($orig_body, 0, $img_start + $img_st_close) . $image . '[/img]';
+ $orig_body = substr($orig_body, $img_start + $img_st_close + $img_len + strlen('[/img]'));
+ if($orig_body === false)
+ $orig_body = '';
+
+ $img_start = strpos($orig_body, '[img');
+ $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
+ $img_len = ($img_start !== false ? strpos(substr($orig_body, $img_start + $img_st_close + 1), '[/img]') : false);
}
- return($s);
+
+ $new_body = $new_body . $orig_body;
+
+ return($new_body);
}
$dnow = substr($dthen,0,8) . '28';
$ret = array();
- while($dnow >= $dthen) {
+ // Starting with the current month, get the first and last days of every
+ // month down to and including the month of the first post
+ while(substr($dnow, 0, 7) >= substr($dthen, 0, 7)) {
$dstart = substr($dnow,0,8) . '01';
$dend = substr($dnow,0,8) . get_dim(intval($dnow),intval(substr($dnow,5)));
$start_month = datetime_convert('','',$dstart,'Y-m-d');
return $o;
}
-
function store_diaspora_retract_sig($item, $user, $baseurl) {
// Note that we can't add a target_author_signature
// if the comment was deleted by a remote user. That should be ok, because if a remote user is deleting
}
else {
$r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1",
- $item['contact-id']
+ $item['contact-id'] // If this function gets called, drop_item() has already checked remote_user() == $item['contact-id']
);
if(count($r)) {
// The below handle only works for NETWORK_DFRN. I think that's ok, because this function
return false;
@curl_setopt($ch, CURLOPT_HEADER, true);
-
+
if (!is_null($accept_content)){
curl_setopt($ch,CURLOPT_HTTPHEADER, array (
"Accept: " . $accept_content
));
}
-
+
@curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
- @curl_setopt($ch, CURLOPT_USERAGENT, "Friendica");
+ //@curl_setopt($ch, CURLOPT_USERAGENT, "Friendica");
+ @curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; Friendica)");
if(intval($timeout)) {
$base = $s;
$curl_info = @curl_getinfo($ch);
$http_code = $curl_info['http_code'];
-
// logger('fetch_url:' . $http_code . ' data: ' . $s);
$header = '';
}
if($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307) {
- $matches = array();
- preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
- $newurl = trim(array_pop($matches));
+ $matches = array();
+ preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
+ $newurl = trim(array_pop($matches));
if(strpos($newurl,'/') === 0)
$newurl = $url . $newurl;
- $url_parsed = @parse_url($newurl);
- if (isset($url_parsed)) {
- $redirects++;
- return fetch_url($newurl,$binary,$redirects,$timeout);
- }
- }
+ $url_parsed = @parse_url($newurl);
+ if (isset($url_parsed)) {
+ $redirects++;
+ return fetch_url($newurl,$binary,$redirects,$timeout);
+ }
+ }
$a->set_curl_code($http_code);
$body = substr($s,strlen($header));
-
$a->set_curl_headers($header);
-
@curl_close($ch);
return($body);
}}
if(! function_exists('validate_email')) {
function validate_email($addr) {
+ if(get_config('system','disable_email_validation'))
+ return true;
+
if(! strpos($addr,'@'))
return false;
$h = substr($addr,strpos($addr,'@') + 1);
$a = get_app();
+ // Picture addresses can contain special characters
+ $s = htmlspecialchars_decode($s);
+
$matches = null;
$c = preg_match_all('/\[img\](.*?)\[\/img\]/ism',$s,$matches,PREG_SET_ORDER);
if($c) {