Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

435 wiersze
13KB

  1. <?php
  2. /**
  3. * @file include/plaintext.php
  4. */
  5. use Friendica\ParseUrl;
  6. require_once("include/Photo.php");
  7. require_once("include/bbcode.php");
  8. require_once("include/html2plain.php");
  9. require_once("include/network.php");
  10. /**
  11. * @brief Fetches attachment data that were generated the old way
  12. *
  13. * @param string $body Message body
  14. * @return array
  15. * 'type' -> Message type ("link", "video", "photo")
  16. * 'text' -> Text before the shared message
  17. * 'after' -> Text after the shared message
  18. * 'image' -> Preview image of the message
  19. * 'url' -> Url to the attached message
  20. * 'title' -> Title of the attachment
  21. * 'description' -> Description of the attachment
  22. */
  23. function get_old_attachment_data($body) {
  24. $post = array();
  25. // Simplify image codes
  26. $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body);
  27. if (preg_match_all("(\[class=(.*?)\](.*?)\[\/class\])ism",$body, $attached, PREG_SET_ORDER)) {
  28. foreach ($attached AS $data) {
  29. if (!in_array($data[1], array("type-link", "type-video", "type-photo")))
  30. continue;
  31. $post["type"] = substr($data[1], 5);
  32. $pos = strpos($body, $data[0]);
  33. if ($pos > 0) {
  34. $post["text"] = trim(substr($body, 0, $pos));
  35. $post["after"] = trim(substr($body, $pos + strlen($data[0])));
  36. } else
  37. $post["text"] = trim(str_replace($data[0], "", $body));
  38. $attacheddata = $data[2];
  39. $URLSearchString = "^\[\]";
  40. if (preg_match("/\[img\]([$URLSearchString]*)\[\/img\]/ism", $attacheddata, $matches)) {
  41. $picturedata = get_photo_info($matches[1]);
  42. if (($picturedata[0] >= 500) AND ($picturedata[0] >= $picturedata[1]))
  43. $post["image"] = $matches[1];
  44. else
  45. $post["preview"] = $matches[1];
  46. }
  47. if (preg_match("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) {
  48. $post["url"] = $matches[1];
  49. $post["title"] = $matches[2];
  50. }
  51. if (($post["url"] == "") AND (in_array($post["type"], array("link", "video")))
  52. AND preg_match("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) {
  53. $post["url"] = $matches[1];
  54. }
  55. // Search for description
  56. if (preg_match("/\[quote\](.*?)\[\/quote\]/ism", $attacheddata, $matches))
  57. $post["description"] = $matches[1];
  58. }
  59. }
  60. return $post;
  61. }
  62. /**
  63. * @brief Fetches attachment data that were generated with the "attachment" element
  64. *
  65. * @param string $body Message body
  66. * @return array
  67. * 'type' -> Message type ("link", "video", "photo")
  68. * 'text' -> Text before the shared message
  69. * 'after' -> Text after the shared message
  70. * 'image' -> Preview image of the message
  71. * 'url' -> Url to the attached message
  72. * 'title' -> Title of the attachment
  73. * 'description' -> Description of the attachment
  74. */
  75. function get_attachment_data($body) {
  76. $data = array();
  77. if (!preg_match("/(.*)\[attachment(.*?)\](.*?)\[\/attachment\](.*)/ism", $body, $match))
  78. return get_old_attachment_data($body);
  79. $attributes = $match[2];
  80. $data["text"] = trim($match[1]);
  81. $type = "";
  82. preg_match("/type='(.*?)'/ism", $attributes, $matches);
  83. if ($matches[1] != "")
  84. $type = strtolower($matches[1]);
  85. preg_match('/type="(.*?)"/ism', $attributes, $matches);
  86. if ($matches[1] != "")
  87. $type = strtolower($matches[1]);
  88. if ($type == "")
  89. return(array());
  90. if (!in_array($type, array("link", "audio", "photo", "video")))
  91. return(array());
  92. if ($type != "")
  93. $data["type"] = $type;
  94. $url = "";
  95. preg_match("/url='(.*?)'/ism", $attributes, $matches);
  96. if ($matches[1] != "")
  97. $url = $matches[1];
  98. preg_match('/url="(.*?)"/ism', $attributes, $matches);
  99. if ($matches[1] != "")
  100. $url = $matches[1];
  101. if ($url != "")
  102. $data["url"] = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
  103. $title = "";
  104. preg_match("/title='(.*?)'/ism", $attributes, $matches);
  105. if ($matches[1] != "")
  106. $title = $matches[1];
  107. preg_match('/title="(.*?)"/ism', $attributes, $matches);
  108. if ($matches[1] != "")
  109. $title = $matches[1];
  110. if ($title != "") {
  111. $title = bbcode(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, false, true);
  112. $title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
  113. $title = str_replace(array("[", "]"), array("&#91;", "&#93;"), $title);
  114. $data["title"] = $title;
  115. }
  116. $image = "";
  117. preg_match("/image='(.*?)'/ism", $attributes, $matches);
  118. if ($matches[1] != "")
  119. $image = $matches[1];
  120. preg_match('/image="(.*?)"/ism', $attributes, $matches);
  121. if ($matches[1] != "")
  122. $image = $matches[1];
  123. if ($image != "")
  124. $data["image"] = html_entity_decode($image, ENT_QUOTES, 'UTF-8');
  125. $preview = "";
  126. preg_match("/preview='(.*?)'/ism", $attributes, $matches);
  127. if ($matches[1] != "")
  128. $preview = $matches[1];
  129. preg_match('/preview="(.*?)"/ism', $attributes, $matches);
  130. if ($matches[1] != "")
  131. $preview = $matches[1];
  132. if ($preview != "")
  133. $data["preview"] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8');
  134. $data["description"] = trim($match[3]);
  135. $data["after"] = trim($match[4]);
  136. return($data);
  137. }
  138. function get_attached_data($body) {
  139. /*
  140. - text:
  141. - type: link, video, photo
  142. - title:
  143. - url:
  144. - image:
  145. - description:
  146. - (thumbnail)
  147. */
  148. $post = get_attachment_data($body);
  149. // if nothing is found, it maybe having an image.
  150. if (!isset($post["type"])) {
  151. $URLSearchString = "^\[\]";
  152. if (preg_match_all("(\[url=([$URLSearchString]*)\]\s*\[img\]([$URLSearchString]*)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) {
  153. if (count($pictures) == 1) {
  154. // Checking, if the link goes to a picture
  155. $data = ParseUrl::getSiteinfoCached($pictures[0][1], true);
  156. // Workaround:
  157. // Sometimes photo posts to the own album are not detected at the start.
  158. // So we seem to cannot use the cache for these cases. That's strange.
  159. if (($data["type"] != "photo") AND strstr($pictures[0][1], "/photos/"))
  160. $data = ParseUrl::getSiteinfo($pictures[0][1], true);
  161. if ($data["type"] == "photo") {
  162. $post["type"] = "photo";
  163. if (isset($data["images"][0])) {
  164. $post["image"] = $data["images"][0]["src"];
  165. $post["url"] = $data["url"];
  166. } else
  167. $post["image"] = $data["url"];
  168. $post["preview"] = $pictures[0][2];
  169. $post["text"] = str_replace($pictures[0][0], "", $body);
  170. } else {
  171. $imgdata = get_photo_info($pictures[0][1]);
  172. if (substr($imgdata["mime"], 0, 6) == "image/") {
  173. $post["type"] = "photo";
  174. $post["image"] = $pictures[0][1];
  175. $post["preview"] = $pictures[0][2];
  176. $post["text"] = str_replace($pictures[0][0], "", $body);
  177. }
  178. }
  179. } elseif (count($pictures) > 1) {
  180. $post["type"] = "link";
  181. $post["url"] = $b["plink"];
  182. $post["image"] = $pictures[0][2];
  183. $post["text"] = $body;
  184. }
  185. } elseif (preg_match_all("(\[img\]([$URLSearchString]*)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) {
  186. if (count($pictures) == 1) {
  187. $post["type"] = "photo";
  188. $post["image"] = $pictures[0][1];
  189. $post["text"] = str_replace($pictures[0][0], "", $body);
  190. } elseif (count($pictures) > 1) {
  191. $post["type"] = "link";
  192. $post["url"] = $b["plink"];
  193. $post["image"] = $pictures[0][1];
  194. $post["text"] = $body;
  195. }
  196. }
  197. if (preg_match_all("(\[url\]([$URLSearchString]*)\[\/url\])ism", $body, $links, PREG_SET_ORDER)) {
  198. if (count($links) == 1) {
  199. $post["type"] = "text";
  200. $post["url"] = $links[0][1];
  201. $post["text"] = $body;
  202. }
  203. }
  204. if (!isset($post["type"])) {
  205. $post["type"] = "text";
  206. $post["text"] = trim($body);
  207. }
  208. } elseif (isset($post["url"]) AND ($post["type"] == "video")) {
  209. $data = ParseUrl::getSiteinfoCached($post["url"], true);
  210. if (isset($data["images"][0]))
  211. $post["image"] = $data["images"][0]["src"];
  212. }
  213. return($post);
  214. }
  215. function shortenmsg($msg, $limit, $twitter = false) {
  216. /// @TODO
  217. /// For Twitter URLs aren't shortened, but they have to be calculated as if.
  218. $lines = explode("\n", $msg);
  219. $msg = "";
  220. $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
  221. $ellipsis = html_entity_decode("&#x2026;", ENT_QUOTES, 'UTF-8');
  222. foreach ($lines AS $row=>$line) {
  223. if (iconv_strlen(trim($msg."\n".$line), "UTF-8") <= $limit)
  224. $msg = trim($msg."\n".$line);
  225. // Is the new message empty by now or is it a reshared message?
  226. elseif (($msg == "") OR (($row == 1) AND (substr($msg, 0, 4) == $recycle)))
  227. $msg = iconv_substr(iconv_substr(trim($msg."\n".$line), 0, $limit, "UTF-8"), 0, -3, "UTF-8").$ellipsis;
  228. else
  229. break;
  230. }
  231. return($msg);
  232. }
  233. /**
  234. * @brief Convert a message into plaintext for connectors to other networks
  235. *
  236. * @param App $a The application class
  237. * @param array $b The message array that is about to be posted
  238. * @param int $limit The maximum number of characters when posting to that network
  239. * @param bool $includedlinks Has an attached link to be included into the message?
  240. * @param int $htmlmode This triggers the behaviour of the bbcode conversion
  241. * @param string $target_network Name of the network where the post should go to.
  242. *
  243. * @return string The converted message
  244. */
  245. function plaintext(App $a, $b, $limit = 0, $includedlinks = false, $htmlmode = 2, $target_network = "") {
  246. // Remove the hash tags
  247. $URLSearchString = "^\[\]";
  248. $body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $b["body"]);
  249. // Add an URL element if the text contains a raw link
  250. $body = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url]$2[/url]', $body);
  251. // Remove the abstract
  252. $body = remove_abstract($body);
  253. // At first look at data that is attached via "type-..." stuff
  254. // This will hopefully replaced with a dedicated bbcode later
  255. //$post = get_attached_data($b["body"]);
  256. $post = get_attached_data($body);
  257. if (($b["title"] != "") AND ($post["text"] != ""))
  258. $post["text"] = trim($b["title"]."\n\n".$post["text"]);
  259. elseif ($b["title"] != "")
  260. $post["text"] = trim($b["title"]);
  261. $abstract = "";
  262. // Fetch the abstract from the given target network
  263. if ($target_network != "") {
  264. $default_abstract = fetch_abstract($b["body"]);
  265. $abstract = fetch_abstract($b["body"], $target_network);
  266. // If we post to a network with no limit we only fetch
  267. // an abstract exactly for this network
  268. if (($limit == 0) AND ($abstract == $default_abstract))
  269. $abstract = "";
  270. } else // Try to guess the correct target network
  271. switch ($htmlmode) {
  272. case 8:
  273. $abstract = fetch_abstract($b["body"], NETWORK_TWITTER);
  274. break;
  275. case 7:
  276. $abstract = fetch_abstract($b["body"], NETWORK_STATUSNET);
  277. break;
  278. case 6:
  279. $abstract = fetch_abstract($b["body"], NETWORK_APPNET);
  280. break;
  281. default: // We don't know the exact target.
  282. // We fetch an abstract since there is a posting limit.
  283. if ($limit > 0)
  284. $abstract = fetch_abstract($b["body"]);
  285. }
  286. if ($abstract != "") {
  287. $post["text"] = $abstract;
  288. if ($post["type"] == "text") {
  289. $post["type"] = "link";
  290. $post["url"] = $b["plink"];
  291. }
  292. }
  293. $html = bbcode($post["text"].$post["after"], false, false, $htmlmode);
  294. $msg = html2plain($html, 0, true);
  295. $msg = trim(html_entity_decode($msg,ENT_QUOTES,'UTF-8'));
  296. $link = "";
  297. if ($includedlinks) {
  298. if ($post["type"] == "link")
  299. $link = $post["url"];
  300. elseif ($post["type"] == "text")
  301. $link = $post["url"];
  302. elseif ($post["type"] == "video")
  303. $link = $post["url"];
  304. elseif ($post["type"] == "photo")
  305. $link = $post["image"];
  306. if (($msg == "") AND isset($post["title"]))
  307. $msg = trim($post["title"]);
  308. if (($msg == "") AND isset($post["description"]))
  309. $msg = trim($post["description"]);
  310. // If the link is already contained in the post, then it neeedn't to be added again
  311. // But: if the link is beyond the limit, then it has to be added.
  312. if (($link != "") AND strstr($msg, $link)) {
  313. $pos = strpos($msg, $link);
  314. // Will the text be shortened in the link?
  315. // Or is the link the last item in the post?
  316. if (($limit > 0) AND ($pos < $limit) AND (($pos + 23 > $limit) OR ($pos + strlen($link) == strlen($msg))))
  317. $msg = trim(str_replace($link, "", $msg));
  318. elseif (($limit == 0) OR ($pos < $limit)) {
  319. // The limit has to be increased since it will be shortened - but not now
  320. // Only do it with Twitter (htmlmode = 8)
  321. if (($limit > 0) AND (strlen($link) > 23) AND ($htmlmode == 8))
  322. $limit = $limit - 23 + strlen($link);
  323. $link = "";
  324. if ($post["type"] == "text")
  325. unset($post["url"]);
  326. }
  327. }
  328. }
  329. if ($limit > 0) {
  330. // Reduce multiple spaces
  331. // When posted to a network with limited space, we try to gain space where possible
  332. while (strpos($msg, " ") !== false)
  333. $msg = str_replace(" ", " ", $msg);
  334. // Twitter is using its own limiter, so we always assume that shortened links will have this length
  335. if (iconv_strlen($link, "UTF-8") > 0)
  336. $limit = $limit - 23;
  337. if (iconv_strlen($msg, "UTF-8") > $limit) {
  338. if (($post["type"] == "text") AND isset($post["url"]))
  339. $post["url"] = $b["plink"];
  340. elseif (!isset($post["url"])) {
  341. $limit = $limit - 23;
  342. $post["url"] = $b["plink"];
  343. } elseif (strpos($b["body"], "[share") !== false)
  344. $post["url"] = $b["plink"];
  345. elseif (get_pconfig($b["uid"], "system", "no_intelligent_shortening"))
  346. $post["url"] = $b["plink"];
  347. $msg = shortenmsg($msg, $limit);
  348. }
  349. }
  350. $post["text"] = trim($msg);
  351. return($post);
  352. }
  353. ?>