]> git.mxchange.org Git - friendica.git/blob - include/tags.php
Revert "Move Objects to Model"
[friendica.git] / include / tags.php
1 <?php
2 /**
3  * @file include/tags.php
4  */
5 use Friendica\App;
6 use Friendica\Content\Feature;
7 use Friendica\Core\System;
8 use Friendica\Database\DBM;
9 use Friendica\Object\Contact;
10
11 function create_tags_from_item($itemid) {
12         $profile_base = System::baseUrl();
13         $profile_data = parse_url($profile_base);
14         $profile_base_friendica = $profile_data['host'].$profile_data['path']."/profile/";
15         $profile_base_diaspora = $profile_data['host'].$profile_data['path']."/u/";
16
17         $messages = q("SELECT `guid`, `uid`, `id`, `edited`, `deleted`, `created`, `received`, `title`, `body`, `tag`, `parent` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
18
19         if (!$messages)
20                 return;
21
22         $message = $messages[0];
23
24         // Clean up all tags
25         q("DELETE FROM `term` WHERE `otype` = %d AND `oid` = %d AND `type` IN (%d, %d)",
26                 intval(TERM_OBJ_POST),
27                 intval($itemid),
28                 intval(TERM_HASHTAG),
29                 intval(TERM_MENTION));
30
31         if ($message["deleted"])
32                 return;
33
34         $taglist = explode(",", $message["tag"]);
35
36         $tags = "";
37         foreach ($taglist as $tag)
38                 if ((substr(trim($tag), 0, 1) == "#") || (substr(trim($tag), 0, 1) == "@"))
39                         $tags .= " ".trim($tag);
40                 else
41                         $tags .= " #".trim($tag);
42
43         $data = " ".$message["title"]." ".$message["body"]." ".$tags." ";
44
45         // ignore anything in a code block
46         $data = preg_replace('/\[code\](.*?)\[\/code\]/sm','',$data);
47
48         $tags = array();
49
50         $pattern = "/\W\#([^\[].*?)[\s'\".,:;\?!\[\]\/]/ism";
51         if (preg_match_all($pattern, $data, $matches))
52                 foreach ($matches[1] as $match)
53                         $tags["#".strtolower($match)] = "";
54
55         $pattern = "/\W([\#@])\[url\=(.*?)\](.*?)\[\/url\]/ism";
56         if (preg_match_all($pattern, $data, $matches, PREG_SET_ORDER)) {
57                 foreach ($matches as $match)
58                         $tags[$match[1].strtolower(trim($match[3], ',.:;[]/\"?!'))] = $match[2];
59         }
60
61         foreach ($tags as $tag=>$link) {
62
63                 if (substr(trim($tag), 0, 1) == "#") {
64                         // try to ignore #039 or #1 or anything like that
65                         if (ctype_digit(substr(trim($tag),1)))
66                                 continue;
67                         // try to ignore html hex escapes, e.g. #x2317
68                         if ((substr(trim($tag),1,1) == 'x' || substr(trim($tag),1,1) == 'X') && ctype_digit(substr(trim($tag),2)))
69                                 continue;
70                         $type = TERM_HASHTAG;
71                         $term = substr($tag, 1);
72                 } elseif (substr(trim($tag), 0, 1) == "@") {
73                         $type = TERM_MENTION;
74                         $term = substr($tag, 1);
75                 } else { // This shouldn't happen
76                         $type = TERM_HASHTAG;
77                         $term = $tag;
78                 }
79
80                 if ($message["uid"] == 0) {
81                         $global = true;
82
83                         q("UPDATE `term` SET `global` = 1 WHERE `otype` = %d AND `guid` = '%s'",
84                                 intval(TERM_OBJ_POST), dbesc($message["guid"]));
85                 } else {
86                         $isglobal = q("SELECT `global` FROM `term` WHERE `uid` = 0 AND `otype` = %d AND `guid` = '%s'",
87                                 intval(TERM_OBJ_POST), dbesc($message["guid"]));
88
89                         $global = (count($isglobal) > 0);
90                 }
91
92                 $r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `guid`, `created`, `received`, `global`)
93                                 VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', %d)",
94                         intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval($type), dbesc($term),
95                         dbesc($link), dbesc($message["guid"]), dbesc($message["created"]), dbesc($message["received"]), intval($global));
96
97                 // Search for mentions
98                 if ((substr($tag, 0, 1) == '@') && (strpos($link, $profile_base_friendica) || strpos($link, $profile_base_diaspora))) {
99                         $users = q("SELECT `uid` FROM `contact` WHERE self AND (`url` = '%s' OR `nurl` = '%s')", $link, $link);
100                         foreach ($users AS $user) {
101                                 if ($user["uid"] == $message["uid"]) {
102                                         q("UPDATE `item` SET `mention` = 1 WHERE `id` = %d", intval($itemid));
103
104                                         q("UPDATE `thread` SET `mention` = 1 WHERE `iid` = %d", intval($message["parent"]));
105                                 }
106                         }
107                 }
108         }
109 }
110
111 function create_tags_from_itemuri($itemuri, $uid) {
112         $messages = q("SELECT `id` FROM `item` WHERE uri ='%s' AND uid=%d", dbesc($itemuri), intval($uid));
113
114         if (count($messages)) {
115                 foreach ($messages as $message) {
116                         create_tags_from_item($message["id"]);
117                 }
118         }
119 }
120
121 function update_items() {
122
123         $messages = dba::p("SELECT `oid`,`item`.`guid`, `item`.`created`, `item`.`received` FROM `term` INNER JOIN `item` ON `item`.`id`=`term`.`oid` WHERE `term`.`otype` = 1 AND `term`.`guid` = ''");
124
125         logger("fetched messages: ".dba::num_rows($messages));
126         while ($message = dba::fetch($messages)) {
127
128                 if ($message["uid"] == 0) {
129                         $global = true;
130
131                         q("UPDATE `term` SET `global` = 1 WHERE `otype` = %d AND `guid` = '%s'",
132                                 intval(TERM_OBJ_POST), dbesc($message["guid"]));
133                 } else {
134                         $isglobal = q("SELECT `global` FROM `term` WHERE `uid` = 0 AND `otype` = %d AND `guid` = '%s'",
135                                 intval(TERM_OBJ_POST), dbesc($message["guid"]));
136
137                         $global = (count($isglobal) > 0);
138                 }
139
140                 q("UPDATE `term` SET `guid` = '%s', `created` = '%s', `received` = '%s', `global` = %d WHERE `otype` = %d AND `oid` = %d",
141                         dbesc($message["guid"]), dbesc($message["created"]), dbesc($message["received"]),
142                         intval($global), intval(TERM_OBJ_POST), intval($message["oid"]));
143         }
144
145         dba::close($messages);
146
147         $messages = dba::p("SELECT `guid` FROM `item` WHERE `uid` = 0");
148
149         logger("fetched messages: ".dba::num_rows($messages));
150         while ($message = dba::fetch(messages)) {
151                 q("UPDATE `item` SET `global` = 1 WHERE `guid` = '%s'", dbesc($message["guid"]));
152         }
153
154         dba::close($messages);
155 }
156
157 /**
158  * @brief Get alphabetical sorted array of used tags/terms of an user including
159  * a weighting by frequency of use.
160  * 
161  * @param int $uid      The user ID.
162  * @param int $count    Max number of displayed tags/terms.
163  * @param int $owner_id The contact id of the owner of the tagged items.
164  * @param string $flags Special item flags.
165  * @param int $type     The tag/term type.
166  * 
167  * @return arr          Alphabetical sorted array of used tags of an user.
168  */
169 function tagadelic($uid, $count = 0, $owner_id = 0, $flags = '', $type = TERM_HASHTAG) {
170         require_once('include/security.php');
171
172         $item_condition = item_condition();
173         $sql_options = item_permissions_sql($uid);
174         $limit = $count ? sprintf("LIMIT %d", intval($count)) : "";
175
176         if ($flags) {
177                 if ($flags === 'wall') {
178                         $sql_options .= " AND `item`.`wall` ";
179                 }
180         }
181
182         if ($owner_id) {
183                 $sql_options .= " AND `item`.`owner-id` = ".intval($owner_id)." ";
184         }
185
186         // Fetch tags
187         $r = dba::p("SELECT `term`, COUNT(`term`) AS `total` FROM `term`
188                 LEFT JOIN `item` ON `term`.`oid` = `item`.`id`
189                 WHERE `term`.`uid` = ? AND `term`.`type` = ?
190                 AND `term`.`otype` = ?
191                 AND $item_condition $sql_options
192                 GROUP BY `term` ORDER BY `total` DESC $limit",
193                 $uid,
194                 $type,
195                 TERM_OBJ_POST
196         );
197         if(!DBM::is_result($r)) {
198                 return array();
199         }
200                 
201         return tag_calc($r);
202 }
203
204 /**
205  * @brief Construct a tag/term cloud block for an user.
206  * 
207  * @param int $uid      The user ID.
208  * @param int $count    Max number of displayed tags/terms.
209  * @param int $owner_id The contact ID of the owner of the tagged items.
210  * @param string $flags Special item flags.
211  * @param int $type     The tag/term type.
212  * 
213  * @return string       HTML formatted output.
214  */
215 function wtagblock($uid, $count = 0,$owner_id = 0, $flags = '', $type = TERM_HASHTAG) {
216         $o = '';
217         $r = tagadelic($uid, $count, $owner_id, $flags, $type);
218         if (count($r)) {
219                 $contact = dba::select(
220                         "contact",
221                         array("url"),
222                         array("id" => $uid),
223                         array("limit" => 1)
224                 );
225                 $url = System::removedBaseUrl($contact['url']);
226
227                 foreach ($r as $rr) {
228                         $tag['level'] = $rr[2];
229                         $tag['url'] = $url."?tag=".urlencode($rr[0]);
230                         $tag['name'] = $rr[0];
231
232                         $tags[] = $tag;
233                 }
234
235                 $tpl = get_markup_template("tagblock_widget.tpl");
236                 $o = replace_macros($tpl, array(
237                         '$title' => t('Tags'),
238                         '$tags'  => $tags
239                 ));
240
241         }
242         return $o;
243 }
244
245 /**
246  * @brief Calculate weighting of tags according to the frequency of use.
247  * 
248  * @param array $arr Array of tags/terms with tag/term name and total count of use.
249  * @return array     Alphabetical sorted array of used tags/terms of an user.
250  */
251 function tag_calc($arr) {
252         $tags = array();
253         $min = 1e9;
254         $max = -1e9;
255         $x = 0;
256
257         if (!$arr) {
258                 return array();
259         }
260
261         foreach ($arr as $rr) {
262                 $tags[$x][0] = $rr['term'];
263                 $tags[$x][1] = log($rr['total']);
264                 $tags[$x][2] = 0;
265                 $min = min($min, $tags[$x][1]);
266                 $max = max($max, $tags[$x][1]);
267                 $x ++;
268         }
269
270         usort($tags, 'tags_sort');
271         $range = max(.01, $max - $min) * 1.0001;
272
273         for ($x = 0; $x < count($tags); $x ++) {
274                 $tags[$x][2] = 1 + floor(9 * ($tags[$x][1] - $min) / $range);
275         }
276
277         return $tags;
278 }
279
280 /**
281  * @brief Compare function to sort tags/terms alphabetically.
282  * 
283  * @param type $a
284  * @param type $b
285  * 
286  * @return int
287  */
288 function tags_sort($a, $b) {
289         if (strtolower($a[0]) == strtolower($b[0])) {
290                 return 0;
291         }
292         return ((strtolower($a[0]) < strtolower($b[0])) ? -1 : 1);
293 }
294
295 /**
296  * @brief Insert a tag cloud widget for the present profile.
297  * 
298  * @param int     $limit Max number of displayed tags.
299  * @return string HTML formattat output.
300  */
301 function tagcloud_wall_widget($limit = 50) {
302         $a = get_app();
303
304         if(!$a->profile['profile_uid'] || !$a->profile['url']) {
305                 return "";
306         }
307
308         if(Feature::isEnabled($a->profile['profile_uid'], 'tagadelic')) {
309                 $owner_id = Contact::getIdForURL($a->profile['url']);
310
311                 if(!$owner_id) {
312                         return "";
313                 }
314                 return wtagblock($a->profile['profile_uid'], $limit, $owner_id, 'wall');
315         }
316
317         return "";
318 }