Exemplo n.º 1
0
 /**
  * Given an item array, convert the body element from bbcode to html and add smilie icons.
  * If attach is true, also add icons for item attachments
  *
  * @param array $item
  * @param boolean $attach
  * @return string item body html
  * @hook prepare_body_init item array before any work
  * @hook prepare_body ('item'=>item array, 'html'=>body string) after first bbcode to html
  * @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author)
  */
 function prepare_body(&$item, $attach = false, $preview = false)
 {
     $a = get_app();
     call_hooks('prepare_body_init', $item);
     $searchpath = $a->get_baseurl() . "/search?tag=";
     $tags = array();
     $hashtags = array();
     $mentions = array();
     if (!get_config('system', 'suppress_tags')) {
         $taglist = q("SELECT `type`, `term`, `url` FROM `term` WHERE `otype` = %d AND `oid` = %d AND `type` IN (%d, %d) ORDER BY `tid`", intval(TERM_OBJ_POST), intval($item['id']), intval(TERM_HASHTAG), intval(TERM_MENTION));
         foreach ($taglist as $tag) {
             if ($tag["url"] == "") {
                 $tag["url"] = $searchpath . strtolower($tag["term"]);
             }
             if ($tag["type"] == TERM_HASHTAG) {
                 $hashtags[] = "#<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>";
                 $prefix = "#";
             } elseif ($tag["type"] == TERM_MENTION) {
                 $mentions[] = "@<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>";
                 $prefix = "@";
             }
             $tags[] = $prefix . "<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>";
         }
     }
     $item['tags'] = $tags;
     $item['hashtags'] = $hashtags;
     $item['mentions'] = $mentions;
     //$cachefile = get_cachefile($item["guid"]."-".strtotime($item["edited"])."-".hash("crc32", $item['body']));
     $cachefile = get_cachefile($item["guid"] . "-" . hash("md5", $item['body']));
     if ($cachefile != '') {
         if (file_exists($cachefile)) {
             $stamp1 = microtime(true);
             $s = file_get_contents($cachefile);
             $a->save_timestamp($stamp1, "file");
         } else {
             redir_private_images($a, $item);
             $s = prepare_text($item['body']);
             $stamp1 = microtime(true);
             file_put_contents($cachefile, $s);
             $a->save_timestamp($stamp1, "file");
             logger('prepare_body: put item ' . $item["id"] . ' into cachefile ' . $cachefile);
         }
     } else {
         redir_private_images($a, $item);
         $s = prepare_text($item['body']);
     }
     require_once "mod/proxy.php";
     $s = proxy_parse_html($s);
     $prep_arr = array('item' => $item, 'html' => $s, 'preview' => $preview);
     call_hooks('prepare_body', $prep_arr);
     $s = $prep_arr['html'];
     if (!$attach) {
         // Replace the blockquotes with quotes that are used in mails
         $mailquote = '<blockquote type="cite" class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">';
         $s = str_replace(array('<blockquote>', '<blockquote class="spoiler">', '<blockquote class="author">'), array($mailquote, $mailquote, $mailquote), $s);
         return $s;
     }
     $as = '';
     $vhead = false;
     $arr = explode('[/attach],', $item['attach']);
     if (count($arr)) {
         $as .= '<div class="body-attach">';
         foreach ($arr as $r) {
             $matches = false;
             $icon = '';
             $cnt = preg_match_all('|\\[attach\\]href=\\"(.*?)\\" length=\\"(.*?)\\" type=\\"(.*?)\\" title=\\"(.*?)\\"|', $r, $matches, PREG_SET_ORDER);
             if ($cnt) {
                 foreach ($matches as $mtch) {
                     $mime = $mtch[3];
                     if (local_user() == $item['uid'] && $item['contact-id'] != $a->contact['id'] && $item['network'] == NETWORK_DFRN) {
                         $the_url = $a->get_baseurl() . '/redir/' . $item['contact-id'] . '?f=1&url=' . $mtch[1];
                     } else {
                         $the_url = $mtch[1];
                     }
                     if (strpos($mime, 'video') !== false) {
                         if (!$vhead) {
                             $vhead = true;
                             $a->page['htmlhead'] .= replace_macros(get_markup_template('videos_head.tpl'), array('$baseurl' => $a->get_baseurl()));
                             $a->page['end'] .= replace_macros(get_markup_template('videos_end.tpl'), array('$baseurl' => $a->get_baseurl()));
                         }
                         $id = end(explode('/', $the_url));
                         $as .= replace_macros(get_markup_template('video_top.tpl'), array('$video' => array('id' => $id, 'title' => t('View Video'), 'src' => $the_url, 'mime' => $mime)));
                     }
                     $filetype = strtolower(substr($mime, 0, strpos($mime, '/')));
                     if ($filetype) {
                         $filesubtype = strtolower(substr($mime, strpos($mime, '/') + 1));
                         $filesubtype = str_replace('.', '-', $filesubtype);
                     } else {
                         $filetype = 'unkn';
                         $filesubtype = 'unkn';
                     }
                     $icon = '<div class="attachtype icon s22 type-' . $filetype . ' subtype-' . $filesubtype . '"></div>';
                     /*$icontype = strtolower(substr($mtch[3],0,strpos($mtch[3],'/')));
                     		switch($icontype) {
                     			case 'video':
                     			case 'audio':
                     			case 'image':
                     			case 'text':
                     				$icon = '<div class="attachtype icon s22 type-' . $icontype . '"></div>';
                     				break;
                     			default:
                     				$icon = '<div class="attachtype icon s22 type-unkn"></div>';
                     				break;
                     		}*/
                     $title = strlen(trim($mtch[4])) ? escape_tags(trim($mtch[4])) : escape_tags($mtch[1]);
                     $title .= ' ' . $mtch[2] . ' ' . t('bytes');
                     $as .= '<a href="' . strip_tags($the_url) . '" title="' . $title . '" class="attachlink" target="_blank" >' . $icon . '</a>';
                 }
             }
         }
         $as .= '<div class="clear"></div></div>';
     }
     $s = $s . $as;
     // Look for spoiler
     $spoilersearch = '<blockquote class="spoiler">';
     // Remove line breaks before the spoiler
     while (strpos($s, "\n" . $spoilersearch) !== false) {
         $s = str_replace("\n" . $spoilersearch, $spoilersearch, $s);
     }
     while (strpos($s, "<br />" . $spoilersearch) !== false) {
         $s = str_replace("<br />" . $spoilersearch, $spoilersearch, $s);
     }
     while (strpos($s, $spoilersearch) !== false) {
         $pos = strpos($s, $spoilersearch);
         $rnd = random_string(8);
         $spoilerreplace = '<br /> <span id="spoiler-wrap-' . $rnd . '" style="white-space:nowrap;" class="fakelink" onclick="openClose(\'spoiler-' . $rnd . '\');">' . sprintf(t('Click to open/close')) . '</span>' . '<blockquote class="spoiler" id="spoiler-' . $rnd . '" style="display: none;">';
         $s = substr($s, 0, $pos) . $spoilerreplace . substr($s, $pos + strlen($spoilersearch));
     }
     // Look for quote with author
     $authorsearch = '<blockquote class="author">';
     while (strpos($s, $authorsearch) !== false) {
         $pos = strpos($s, $authorsearch);
         $rnd = random_string(8);
         $authorreplace = '<br /> <span id="author-wrap-' . $rnd . '" style="white-space:nowrap;" class="fakelink" onclick="openClose(\'author-' . $rnd . '\');">' . sprintf(t('Click to open/close')) . '</span>' . '<blockquote class="author" id="author-' . $rnd . '" style="display: block;">';
         $s = substr($s, 0, $pos) . $authorreplace . substr($s, $pos + strlen($authorsearch));
     }
     // replace friendica image url size with theme preference
     if (x($a->theme_info, 'item_image_size')) {
         $ps = $a->theme_info['item_image_size'];
         $s = preg_replace('|(<img[^>]+src="[^"]+/photo/[0-9a-f]+)-[0-9]|', "\$1-" . $ps, $s);
     }
     $prep_arr = array('item' => $item, 'html' => $s);
     call_hooks('prepare_body_final', $prep_arr);
     return $prep_arr['html'];
 }
Exemplo n.º 2
0
function item_store($arr, $force_parent = false)
{
    // If a Diaspora signature structure was passed in, pull it out of the
    // item array and set it aside for later storage.
    $dsprsig = null;
    if (x($arr, 'dsprsig')) {
        $dsprsig = json_decode(base64_decode($arr['dsprsig']));
        unset($arr['dsprsig']);
    }
    // if an OStatus conversation url was passed in, it is stored and then
    // removed from the array.
    $ostatus_conversation = null;
    if (isset($arr["ostatus_conversation"])) {
        $ostatus_conversation = $arr["ostatus_conversation"];
        unset($arr["ostatus_conversation"]);
    }
    if (x($arr, 'gravity')) {
        $arr['gravity'] = intval($arr['gravity']);
    } elseif ($arr['parent-uri'] === $arr['uri']) {
        $arr['gravity'] = 0;
    } elseif (activity_match($arr['verb'], ACTIVITY_POST)) {
        $arr['gravity'] = 6;
    } else {
        $arr['gravity'] = 6;
    }
    // extensible catchall
    if (!x($arr, 'type')) {
        $arr['type'] = 'remote';
    }
    // Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin.
    if (strpos($arr['body'], '<') !== false || strpos($arr['body'], '>') !== false) {
        $arr['body'] = strip_tags($arr['body']);
    }
    if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
        require_once 'library/langdet/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'] : '');
        $lng = $l->detect($naked_body, 3);
        if (sizeof($lng) > 0) {
            $postopts = "";
            foreach ($lng as $language => $score) {
                if ($postopts == "") {
                    $postopts = "lang=";
                } else {
                    $postopts .= ":";
                }
                $postopts .= $language . ";" . $score;
            }
            $arr['postopts'] = $postopts;
        }
    }
    $arr['wall'] = x($arr, 'wall') ? intval($arr['wall']) : 0;
    $arr['uri'] = x($arr, 'uri') ? notags(trim($arr['uri'])) : random_string();
    $arr['extid'] = x($arr, 'extid') ? notags(trim($arr['extid'])) : '';
    $arr['author-name'] = x($arr, 'author-name') ? notags(trim($arr['author-name'])) : '';
    $arr['author-link'] = x($arr, 'author-link') ? notags(trim($arr['author-link'])) : '';
    $arr['author-avatar'] = x($arr, 'author-avatar') ? notags(trim($arr['author-avatar'])) : '';
    $arr['owner-name'] = x($arr, 'owner-name') ? notags(trim($arr['owner-name'])) : '';
    $arr['owner-link'] = x($arr, 'owner-link') ? notags(trim($arr['owner-link'])) : '';
    $arr['owner-avatar'] = x($arr, 'owner-avatar') ? notags(trim($arr['owner-avatar'])) : '';
    $arr['created'] = x($arr, 'created') !== false ? datetime_convert('UTC', 'UTC', $arr['created']) : datetime_convert();
    $arr['edited'] = x($arr, 'edited') !== false ? datetime_convert('UTC', 'UTC', $arr['edited']) : datetime_convert();
    $arr['commented'] = datetime_convert();
    $arr['received'] = datetime_convert();
    $arr['changed'] = datetime_convert();
    $arr['title'] = x($arr, 'title') ? notags(trim($arr['title'])) : '';
    $arr['location'] = x($arr, 'location') ? notags(trim($arr['location'])) : '';
    $arr['coord'] = x($arr, 'coord') ? notags(trim($arr['coord'])) : '';
    $arr['last-child'] = x($arr, 'last-child') ? intval($arr['last-child']) : 0;
    $arr['visible'] = x($arr, 'visible') !== false ? intval($arr['visible']) : 1;
    $arr['deleted'] = 0;
    $arr['parent-uri'] = x($arr, 'parent-uri') ? notags(trim($arr['parent-uri'])) : '';
    $arr['verb'] = x($arr, 'verb') ? notags(trim($arr['verb'])) : '';
    $arr['object-type'] = x($arr, 'object-type') ? notags(trim($arr['object-type'])) : '';
    $arr['object'] = x($arr, 'object') ? trim($arr['object']) : '';
    $arr['target-type'] = x($arr, 'target-type') ? notags(trim($arr['target-type'])) : '';
    $arr['target'] = x($arr, 'target') ? trim($arr['target']) : '';
    $arr['plink'] = x($arr, 'plink') ? notags(trim($arr['plink'])) : '';
    $arr['allow_cid'] = x($arr, 'allow_cid') ? trim($arr['allow_cid']) : '';
    $arr['allow_gid'] = x($arr, 'allow_gid') ? trim($arr['allow_gid']) : '';
    $arr['deny_cid'] = x($arr, 'deny_cid') ? trim($arr['deny_cid']) : '';
    $arr['deny_gid'] = x($arr, 'deny_gid') ? trim($arr['deny_gid']) : '';
    $arr['private'] = x($arr, 'private') ? intval($arr['private']) : 0;
    $arr['bookmark'] = x($arr, 'bookmark') ? intval($arr['bookmark']) : 0;
    $arr['body'] = x($arr, 'body') ? trim($arr['body']) : '';
    $arr['tag'] = x($arr, 'tag') ? notags(trim($arr['tag'])) : '';
    $arr['attach'] = x($arr, 'attach') ? notags(trim($arr['attach'])) : '';
    $arr['app'] = x($arr, 'app') ? notags(trim($arr['app'])) : '';
    $arr['origin'] = x($arr, 'origin') ? intval($arr['origin']) : 0;
    $arr['guid'] = x($arr, 'guid') ? notags(trim($arr['guid'])) : get_guid();
    $arr['thr-parent'] = $arr['parent-uri'];
    if ($arr['parent-uri'] === $arr['uri']) {
        $parent_id = 0;
        $parent_deleted = 0;
        $allow_cid = $arr['allow_cid'];
        $allow_gid = $arr['allow_gid'];
        $deny_cid = $arr['deny_cid'];
        $deny_gid = $arr['deny_gid'];
    } else {
        // find the parent and snarf the item id and ACLs
        // and anything else we need to inherit
        $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC LIMIT 1", dbesc($arr['parent-uri']), intval($arr['uid']));
        if (count($r)) {
            // is the new message multi-level threaded?
            // even though we don't support it now, preserve the info
            // and re-attach to the conversation parent.
            if ($r[0]['uri'] != $r[0]['parent-uri']) {
                $arr['parent-uri'] = $r[0]['parent-uri'];
                $z = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `parent-uri` = '%s' AND `uid` = %d \n\t\t\t\t\tORDER BY `id` ASC LIMIT 1", dbesc($r[0]['parent-uri']), dbesc($r[0]['parent-uri']), intval($arr['uid']));
                if ($z && count($z)) {
                    $r = $z;
                }
            }
            $parent_id = $r[0]['id'];
            $parent_deleted = $r[0]['deleted'];
            $allow_cid = $r[0]['allow_cid'];
            $allow_gid = $r[0]['allow_gid'];
            $deny_cid = $r[0]['deny_cid'];
            $deny_gid = $r[0]['deny_gid'];
            $arr['wall'] = $r[0]['wall'];
            // if the parent is private, force privacy for the entire conversation
            // This differs from the above settings as it subtly allows comments from
            // email correspondents to be private even if the overall thread is not.
            if ($r[0]['private']) {
                $arr['private'] = $r[0]['private'];
            }
            // Edge case. We host a public forum that was originally posted to privately.
            // The original author commented, but as this is a comment, the permissions
            // weren't fixed up so it will still show the comment as private unless we fix it here.
            if (intval($r[0]['forum_mode']) == 1 && !$r[0]['private']) {
                $arr['private'] = 0;
            }
        } else {
            // Allow one to see reply tweets from status.net even when
            // we don't have or can't see the original post.
            if ($force_parent) {
                logger('item_store: $force_parent=true, reply converted to top-level post.');
                $parent_id = 0;
                $arr['parent-uri'] = $arr['uri'];
                $arr['gravity'] = 0;
            } else {
                logger('item_store: item parent was not found - ignoring item');
                return 0;
            }
            $parent_deleted = 0;
        }
    }
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($arr['uri']), intval($arr['uid']));
    if ($r && count($r)) {
        logger('item-store: duplicate item ignored. ' . print_r($arr, true));
        return 0;
    }
    call_hooks('post_remote', $arr);
    if (x($arr, 'cancel')) {
        logger('item_store: post cancelled by plugin.');
        return 0;
    }
    dbesc_array($arr);
    logger('item_store: ' . print_r($arr, true), LOGGER_DATA);
    $r = dbq("INSERT INTO `item` (`" . implode("`, `", array_keys($arr)) . "`) VALUES ('" . implode("', '", array_values($arr)) . "')");
    // find the item we just created
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC ", $arr['uri'], intval($arr['uid']));
    if (count($r)) {
        $current_post = $r[0]['id'];
        logger('item_store: created item ' . $current_post);
        create_tags_from_item($r[0]['id']);
    } else {
        logger('item_store: could not locate created item');
        return 0;
    }
    if (count($r) > 1) {
        logger('item_store: duplicated post occurred. Removing duplicates.');
        q("DELETE FROM `item` WHERE `uri` = '%s' AND `uid` = %d AND `id` != %d ", $arr['uri'], intval($arr['uid']), intval($current_post));
    }
    if (!$parent_id || $arr['parent-uri'] === $arr['uri']) {
        $parent_id = $current_post;
    }
    if (strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid)) {
        $private = 1;
    } else {
        $private = $arr['private'];
    }
    // Set parent id - and also make sure to inherit the parent's ACL's.
    $r = q("UPDATE `item` SET `parent` = %d, `allow_cid` = '%s', `allow_gid` = '%s',\n\t\t`deny_cid` = '%s', `deny_gid` = '%s', `private` = %d, `deleted` = %d WHERE `id` = %d LIMIT 1", intval($parent_id), dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), dbesc($deny_gid), intval($private), intval($parent_deleted), intval($current_post));
    create_tags_from_item($current_post);
    // Complete ostatus threads
    if ($ostatus_conversation) {
        complete_conversation($current_post, $ostatus_conversation);
    }
    $arr['id'] = $current_post;
    $arr['parent'] = $parent_id;
    $arr['allow_cid'] = $allow_cid;
    $arr['allow_gid'] = $allow_gid;
    $arr['deny_cid'] = $deny_cid;
    $arr['deny_gid'] = $deny_gid;
    $arr['private'] = $private;
    $arr['deleted'] = $parent_deleted;
    // update the commented timestamp on the parent
    q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent_id));
    if ($dsprsig) {
        q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($current_post), dbesc($dsprsig->signed_text), dbesc($dsprsig->signature), dbesc($dsprsig->signer));
    }
    /**
     * If this is now the last-child, force all _other_ children of this parent to *not* be last-child
     */
    if ($arr['last-child']) {
        $r = q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d AND `id` != %d", dbesc($arr['uri']), intval($arr['uid']), intval($current_post));
    }
    tag_deliver($arr['uid'], $current_post);
    // Store the fresh generated item into the cache
    $cachefile = get_cachefile($arr["guid"] . "-" . hash("md5", $arr['body']));
    if ($cachefile != '' and !file_exists($cachefile)) {
        $s = prepare_text($arr['body']);
        $a = get_app();
        $stamp1 = microtime(true);
        file_put_contents($cachefile, $s);
        $a->save_timestamp($stamp1, "file");
        logger('item_store: put item ' . $current_post . ' into cachefile ' . $cachefile);
    }
    $r = q('SELECT * FROM `item` WHERE id = %d', intval($current_post));
    if (count($r) == 1) {
        call_hooks('post_remote_end', $r[0]);
    } else {
        logger('item_store: new item not found in DB, id ' . $current_post);
    }
    return $current_post;
}
Exemplo n.º 3
0
function scale_external_images($s, $include_link = true, $scale_replace = false)
{
    $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) {
        require_once 'include/Photo.php';
        foreach ($matches as $mtch) {
            logger('scale_external_image: ' . $mtch[1]);
            $hostname = str_replace('www.', '', substr($a->get_baseurl(), strpos($a->get_baseurl(), '://') + 3));
            if (stristr($mtch[1], $hostname)) {
                continue;
            }
            // $scale_replace, if passed, is an array of two elements. The
            // first is the name of the full-size image. The second is the
            // name of a remote, scaled-down version of the full size image.
            // This allows Friendica to display the smaller remote image if
            // one exists, while still linking to the full-size image
            if ($scale_replace) {
                $scaled = str_replace($scale_replace[0], $scale_replace[1], $mtch[1]);
            } else {
                $scaled = $mtch[1];
            }
            $i = fetch_url($scaled);
            $cachefile = get_cachefile(hash("md5", $scaled));
            if ($cachefile != '') {
                $stamp1 = microtime(true);
                file_put_contents($cachefile, $i);
                $a->save_timestamp($stamp1, "file");
            }
            // guess mimetype from headers or filename
            $type = guess_image_type($mtch[1], true);
            if ($i) {
                $ph = new Photo($i, $type);
                if ($ph->is_valid()) {
                    $orig_width = $ph->getWidth();
                    $orig_height = $ph->getHeight();
                    if ($orig_width > 640 || $orig_height > 640) {
                        $ph->scaleImage(640);
                        $new_width = $ph->getWidth();
                        $new_height = $ph->getHeight();
                        logger('scale_external_images: ' . $orig_width . '->' . $new_width . 'w ' . $orig_height . '->' . $new_height . 'h' . ' match: ' . $mtch[0], LOGGER_DEBUG);
                        $s = str_replace($mtch[0], '[img=' . $new_width . 'x' . $new_height . ']' . $scaled . '[/img]' . "\n" . ($include_link ? '[url=' . $mtch[1] . ']' . t('view full size') . '[/url]' . "\n" : ''), $s);
                        logger('scale_external_images: new string: ' . $s, LOGGER_DEBUG);
                    }
                }
            }
        }
    }
    // replace the special char encoding
    $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
    return $s;
}
Exemplo n.º 4
0
function proxy_init()
{
    global $a, $_SERVER;
    // Pictures are stored in one of the following ways:
    // 1. If a folder "proxy" exists and is writeable, then use this for caching
    // 2. If a cache path is defined, use this
    // 3. If everything else failed, cache into the database
    //
    // Question: Do we really need these three methods?
    if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
        header('HTTP/1.1 304 Not Modified');
        header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
        header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']);
        header("Expires: " . gmdate("D, d M Y H:i:s", time() + 31536000) . " GMT");
        header("Cache-Control: max-age=31536000");
        if (function_exists('header_remove')) {
            header_remove('Last-Modified');
            header_remove('Expires');
            header_remove('Cache-Control');
        }
        exit;
    }
    if (function_exists('header_remove')) {
        header_remove('Pragma');
        header_remove('pragma');
    }
    $thumb = false;
    $size = 1024;
    // If the cache path isn't there, try to create it
    if (!is_dir($_SERVER["DOCUMENT_ROOT"] . "/proxy")) {
        if (is_writable($_SERVER["DOCUMENT_ROOT"])) {
            mkdir($_SERVER["DOCUMENT_ROOT"] . "/proxy");
        }
    }
    // Checking if caching into a folder in the webroot is activated and working
    $direct_cache = (is_dir($_SERVER["DOCUMENT_ROOT"] . "/proxy") and is_writable($_SERVER["DOCUMENT_ROOT"] . "/proxy"));
    // Look for filename in the arguments
    if ((isset($a->argv[1]) or isset($a->argv[2]) or isset($a->argv[3])) and !isset($_REQUEST["url"])) {
        if (isset($a->argv[3])) {
            $url = $a->argv[3];
        } elseif (isset($a->argv[2])) {
            $url = $a->argv[2];
        } else {
            $url = $a->argv[1];
        }
        if (isset($a->argv[3]) and $a->argv[3] == "thumb") {
            $size = 200;
        }
        // thumb, small, medium and large.
        if (substr($url, -6) == ":thumb") {
            $size = 150;
        }
        if (substr($url, -6) == ":small") {
            $size = 340;
        }
        if (substr($url, -7) == ":medium") {
            $size = 600;
        }
        if (substr($url, -6) == ":large") {
            $size = 1024;
        }
        $pos = strrpos($url, "=.");
        if ($pos) {
            $url = substr($url, 0, $pos + 1);
        }
        $url = str_replace(array(".jpg", ".jpeg", ".gif", ".png"), array("", "", "", ""), $url);
        $url = base64_decode(strtr($url, '-_', '+/'), true);
        if ($url) {
            $_REQUEST['url'] = $url;
        }
    } else {
        $direct_cache = false;
    }
    if (!$direct_cache) {
        $urlhash = 'pic:' . sha1($_REQUEST['url']);
        $cachefile = get_cachefile(hash("md5", $_REQUEST['url']));
        if ($cachefile != '') {
            if (file_exists($cachefile)) {
                $img_str = file_get_contents($cachefile);
                $mime = image_type_to_mime_type(exif_imagetype($cachefile));
                header("Content-type: {$mime}");
                header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
                header('Etag: "' . md5($img_str) . '"');
                header("Expires: " . gmdate("D, d M Y H:i:s", time() + 31536000) . " GMT");
                header("Cache-Control: max-age=31536000");
                // reduce quality - if it isn't a GIF
                if ($mime != "image/gif") {
                    $img = new Photo($img_str, $mime);
                    if ($img->is_valid()) {
                        $img_str = $img->imageString();
                    }
                }
                echo $img_str;
                killme();
            }
        }
    } else {
        $cachefile = "";
    }
    $valid = true;
    if (!$direct_cache and $cachefile == "") {
        $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' LIMIT 1", $urlhash);
        if (count($r)) {
            $img_str = $r[0]['data'];
            $mime = $r[0]["desc"];
            if ($mime == "") {
                $mime = "image/jpeg";
            }
        }
    } else {
        $r = array();
    }
    if (!count($r)) {
        // It shouldn't happen but it does - spaces in URL
        $_REQUEST['url'] = str_replace(" ", "+", $_REQUEST['url']);
        $redirects = 0;
        $img_str = fetch_url($_REQUEST['url'], true, $redirects, 10);
        $tempfile = tempnam(get_temppath(), "cache");
        file_put_contents($tempfile, $img_str);
        $mime = image_type_to_mime_type(exif_imagetype($tempfile));
        unlink($tempfile);
        // If there is an error then return a blank image
        if (substr($a->get_curl_code(), 0, 1) == "4" or !$img_str) {
            $img_str = file_get_contents("images/blank.png");
            $mime = "image/png";
            $cachefile = "";
            // Clear the cachefile so that the dummy isn't stored
            $valid = false;
            $img = new Photo($img_str, "image/png");
            if ($img->is_valid()) {
                $img->scaleImage(10);
                $img_str = $img->imageString();
            }
        } else {
            if ($mime != "image/jpeg" and !$direct_cache and $cachefile == "") {
                $image = @imagecreatefromstring($img_str);
                if ($image === FALSE) {
                    die;
                }
                q("INSERT INTO `photo`\n\t\t\t( `uid`, `contact-id`, `guid`, `resource-id`, `created`, `edited`, `filename`, `album`, `height`, `width`, `desc`, `data`, `scale`, `profile`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )\n\t\t\tVALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s' )", 0, 0, get_guid(), dbesc($urlhash), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(basename(dbesc($_REQUEST["url"]))), dbesc(''), intval(imagesy($image)), intval(imagesx($image)), $mime, dbesc($img_str), 100, intval(0), dbesc(''), dbesc(''), dbesc(''), dbesc(''));
            } else {
                $img = new Photo($img_str, $mime);
                if ($img->is_valid()) {
                    if (!$direct_cache and $cachefile == "") {
                        $img->store(0, 0, $urlhash, $_REQUEST['url'], '', 100);
                    }
                }
            }
        }
    }
    // reduce quality - if it isn't a GIF
    if ($mime != "image/gif") {
        $img = new Photo($img_str, $mime);
        if ($img->is_valid()) {
            $img->scaleImage($size);
            $img_str = $img->imageString();
        }
    }
    // If there is a real existing directory then put the cache file there
    // advantage: real file access is really fast
    // Otherwise write in cachefile
    if ($valid and $direct_cache) {
        file_put_contents($_SERVER["DOCUMENT_ROOT"] . "/proxy/" . proxy_url($_REQUEST['url'], true), $img_str);
    } elseif ($cachefile != '') {
        file_put_contents($cachefile, $img_str);
    }
    header("Content-type: {$mime}");
    // Only output the cache headers when the file is valid
    if ($valid) {
        header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
        header('Etag: "' . md5($img_str) . '"');
        header("Expires: " . gmdate("D, d M Y H:i:s", time() + 31536000) . " GMT");
        header("Cache-Control: max-age=31536000");
    }
    echo $img_str;
    killme();
}
Exemplo n.º 5
0
function item_store($arr, $force_parent = false, $notify = false)
{
    // If it is a posting where users should get notifications, then define it as wall posting
    if ($notify) {
        $arr['wall'] = 1;
        $arr['type'] = 'wall';
        $arr['origin'] = 1;
        $arr['last-child'] = 1;
        $arr['network'] = NETWORK_DFRN;
    }
    // If a Diaspora signature structure was passed in, pull it out of the
    // item array and set it aside for later storage.
    $dsprsig = null;
    if (x($arr, 'dsprsig')) {
        $dsprsig = json_decode(base64_decode($arr['dsprsig']));
        unset($arr['dsprsig']);
    }
    // if an OStatus conversation url was passed in, it is stored and then
    // removed from the array.
    $ostatus_conversation = null;
    if (isset($arr["ostatus_conversation"])) {
        $ostatus_conversation = $arr["ostatus_conversation"];
        unset($arr["ostatus_conversation"]);
    }
    if (x($arr, 'gravity')) {
        $arr['gravity'] = intval($arr['gravity']);
    } elseif ($arr['parent-uri'] === $arr['uri']) {
        $arr['gravity'] = 0;
    } elseif (activity_match($arr['verb'], ACTIVITY_POST)) {
        $arr['gravity'] = 6;
    } else {
        $arr['gravity'] = 6;
    }
    // extensible catchall
    if (!x($arr, 'type')) {
        $arr['type'] = 'remote';
    }
    /* check for create  date and expire time */
    $uid = intval($arr['uid']);
    $r = q("SELECT expire FROM user WHERE uid = %d", $uid);
    if (count($r)) {
        $expire_interval = $r[0]['expire'];
        if ($expire_interval > 0) {
            $expire_date = new DateTime('- ' . $expire_interval . ' days', new DateTimeZone('UTC'));
            $created_date = new DateTime($arr['created'], new DateTimeZone('UTC'));
            if ($created_date < $expire_date) {
                logger('item-store: item created (' . $arr['created'] . ') before expiration time (' . $expire_date->format(DateTime::W3C) . '). ignored. ' . print_r($arr, true), LOGGER_DEBUG);
                return 0;
            }
        }
    }
    // If there is no guid then take the same guid that was taken before for the same uri
    if (trim($arr['guid']) == "" and trim($arr['uri']) != "") {
        logger('item_store: checking for an existing guid for uri ' . $arr['uri'], LOGGER_DEBUG);
        $r = q("SELECT `guid` FROM `item` WHERE `uri` = '%s' AND `guid` != '' LIMIT 1", dbesc(trim($arr['uri'])));
        if (count($r)) {
            $arr['guid'] = $r[0]["guid"];
            logger('item_store: found guid ' . $arr['guid'] . ' for uri ' . $arr['uri'], LOGGER_DEBUG);
        }
    }
    // Shouldn't happen but we want to make absolutely sure it doesn't leak from a plugin.
    // Deactivated, since the bbcode parser can handle with it - and it destroys posts with some smileys that contain "<"
    //if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false))
    //	$arr['body'] = strip_tags($arr['body']);
    if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
        require_once 'library/langdet/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'] : '');
        $lng = $l->detect($naked_body, 3);
        if (sizeof($lng) > 0) {
            $postopts = "";
            foreach ($lng as $language => $score) {
                if ($postopts == "") {
                    $postopts = "lang=";
                } else {
                    $postopts .= ":";
                }
                $postopts .= $language . ";" . $score;
            }
            $arr['postopts'] = $postopts;
        }
    }
    $arr['wall'] = x($arr, 'wall') ? intval($arr['wall']) : 0;
    $arr['uri'] = x($arr, 'uri') ? notags(trim($arr['uri'])) : random_string();
    $arr['extid'] = x($arr, 'extid') ? notags(trim($arr['extid'])) : '';
    $arr['author-name'] = x($arr, 'author-name') ? notags(trim($arr['author-name'])) : '';
    $arr['author-link'] = x($arr, 'author-link') ? notags(trim($arr['author-link'])) : '';
    $arr['author-avatar'] = x($arr, 'author-avatar') ? notags(trim($arr['author-avatar'])) : '';
    $arr['owner-name'] = x($arr, 'owner-name') ? notags(trim($arr['owner-name'])) : '';
    $arr['owner-link'] = x($arr, 'owner-link') ? notags(trim($arr['owner-link'])) : '';
    $arr['owner-avatar'] = x($arr, 'owner-avatar') ? notags(trim($arr['owner-avatar'])) : '';
    $arr['created'] = x($arr, 'created') !== false ? datetime_convert('UTC', 'UTC', $arr['created']) : datetime_convert();
    $arr['edited'] = x($arr, 'edited') !== false ? datetime_convert('UTC', 'UTC', $arr['edited']) : datetime_convert();
    $arr['commented'] = datetime_convert();
    $arr['received'] = datetime_convert();
    $arr['changed'] = datetime_convert();
    $arr['title'] = x($arr, 'title') ? notags(trim($arr['title'])) : '';
    $arr['location'] = x($arr, 'location') ? notags(trim($arr['location'])) : '';
    $arr['coord'] = x($arr, 'coord') ? notags(trim($arr['coord'])) : '';
    $arr['last-child'] = x($arr, 'last-child') ? intval($arr['last-child']) : 0;
    $arr['visible'] = x($arr, 'visible') !== false ? intval($arr['visible']) : 1;
    $arr['deleted'] = 0;
    $arr['parent-uri'] = x($arr, 'parent-uri') ? notags(trim($arr['parent-uri'])) : '';
    $arr['verb'] = x($arr, 'verb') ? notags(trim($arr['verb'])) : '';
    $arr['object-type'] = x($arr, 'object-type') ? notags(trim($arr['object-type'])) : '';
    $arr['object'] = x($arr, 'object') ? trim($arr['object']) : '';
    $arr['target-type'] = x($arr, 'target-type') ? notags(trim($arr['target-type'])) : '';
    $arr['target'] = x($arr, 'target') ? trim($arr['target']) : '';
    $arr['plink'] = x($arr, 'plink') ? notags(trim($arr['plink'])) : '';
    $arr['allow_cid'] = x($arr, 'allow_cid') ? trim($arr['allow_cid']) : '';
    $arr['allow_gid'] = x($arr, 'allow_gid') ? trim($arr['allow_gid']) : '';
    $arr['deny_cid'] = x($arr, 'deny_cid') ? trim($arr['deny_cid']) : '';
    $arr['deny_gid'] = x($arr, 'deny_gid') ? trim($arr['deny_gid']) : '';
    $arr['private'] = x($arr, 'private') ? intval($arr['private']) : 0;
    $arr['bookmark'] = x($arr, 'bookmark') ? intval($arr['bookmark']) : 0;
    $arr['body'] = x($arr, 'body') ? trim($arr['body']) : '';
    $arr['tag'] = x($arr, 'tag') ? notags(trim($arr['tag'])) : '';
    $arr['attach'] = x($arr, 'attach') ? notags(trim($arr['attach'])) : '';
    $arr['app'] = x($arr, 'app') ? notags(trim($arr['app'])) : '';
    $arr['origin'] = x($arr, 'origin') ? intval($arr['origin']) : 0;
    $arr['guid'] = x($arr, 'guid') ? notags(trim($arr['guid'])) : get_guid(30);
    $arr['network'] = x($arr, 'network') ? trim($arr['network']) : '';
    if ($arr['plink'] == "") {
        $a = get_app();
        $arr['plink'] = $a->get_baseurl() . '/display/' . urlencode($arr['guid']);
    }
    if ($arr['network'] == "") {
        $r = q("SELECT `network` FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($arr['contact-id']), intval($arr['uid']));
        if (count($r)) {
            $arr['network'] = $r[0]["network"];
        }
        // Fallback to friendica (why is it empty in some cases?)
        if ($arr['network'] == "") {
            $arr['network'] = NETWORK_DFRN;
        }
        logger("item_store: Set network to " . $arr["network"] . " for " . $arr["uri"], LOGGER_DEBUG);
    }
    $arr['thr-parent'] = $arr['parent-uri'];
    if ($arr['parent-uri'] === $arr['uri']) {
        $parent_id = 0;
        $parent_deleted = 0;
        $allow_cid = $arr['allow_cid'];
        $allow_gid = $arr['allow_gid'];
        $deny_cid = $arr['deny_cid'];
        $deny_gid = $arr['deny_gid'];
        $notify_type = 'wall-new';
    } else {
        // find the parent and snarf the item id and ACLs
        // and anything else we need to inherit
        $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC LIMIT 1", dbesc($arr['parent-uri']), intval($arr['uid']));
        if (count($r)) {
            // is the new message multi-level threaded?
            // even though we don't support it now, preserve the info
            // and re-attach to the conversation parent.
            if ($r[0]['uri'] != $r[0]['parent-uri']) {
                $arr['parent-uri'] = $r[0]['parent-uri'];
                $z = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `parent-uri` = '%s' AND `uid` = %d\n\t\t\t\t\tORDER BY `id` ASC LIMIT 1", dbesc($r[0]['parent-uri']), dbesc($r[0]['parent-uri']), intval($arr['uid']));
                if ($z && count($z)) {
                    $r = $z;
                }
            }
            $parent_id = $r[0]['id'];
            $parent_deleted = $r[0]['deleted'];
            $allow_cid = $r[0]['allow_cid'];
            $allow_gid = $r[0]['allow_gid'];
            $deny_cid = $r[0]['deny_cid'];
            $deny_gid = $r[0]['deny_gid'];
            $arr['wall'] = $r[0]['wall'];
            $notify_type = 'comment-new';
            // if the parent is private, force privacy for the entire conversation
            // This differs from the above settings as it subtly allows comments from
            // email correspondents to be private even if the overall thread is not.
            if ($r[0]['private']) {
                $arr['private'] = $r[0]['private'];
            }
            // Edge case. We host a public forum that was originally posted to privately.
            // The original author commented, but as this is a comment, the permissions
            // weren't fixed up so it will still show the comment as private unless we fix it here.
            if (intval($r[0]['forum_mode']) == 1 && !$r[0]['private']) {
                $arr['private'] = 0;
            }
            // If its a post from myself then tag the thread as "mention"
            logger("item_store: Checking if parent " . $parent_id . " has to be tagged as mention for user " . $arr['uid'], LOGGER_DEBUG);
            $u = q("select * from user where uid = %d limit 1", intval($arr['uid']));
            if (count($u)) {
                $a = get_app();
                $self = normalise_link($a->get_baseurl() . '/profile/' . $u[0]['nickname']);
                logger("item_store: 'myself' is " . $self . " for parent " . $parent_id . " checking against " . $arr['author-link'] . " and " . $arr['owner-link'], LOGGER_DEBUG);
                if (normalise_link($arr['author-link']) == $self or normalise_link($arr['owner-link']) == $self) {
                    q("UPDATE `thread` SET `mention` = 1 WHERE `iid` = %d", intval($parent_id));
                    logger("item_store: tagged thread " . $parent_id . " as mention for user " . $self, LOGGER_DEBUG);
                }
            }
        } else {
            // Allow one to see reply tweets from status.net even when
            // we don't have or can't see the original post.
            if ($force_parent) {
                logger('item_store: $force_parent=true, reply converted to top-level post.');
                $parent_id = 0;
                $arr['parent-uri'] = $arr['uri'];
                $arr['gravity'] = 0;
            } else {
                logger('item_store: item parent was not found - ignoring item');
                return 0;
            }
            $parent_deleted = 0;
        }
    }
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($arr['uri']), intval($arr['uid']));
    if ($r && count($r)) {
        logger('item-store: duplicate item ignored. ' . print_r($arr, true));
        return 0;
    }
    call_hooks('post_remote', $arr);
    if (x($arr, 'cancel')) {
        logger('item_store: post cancelled by plugin.');
        return 0;
    }
    dbesc_array($arr);
    logger('item_store: ' . print_r($arr, true), LOGGER_DATA);
    $r = dbq("INSERT INTO `item` (`" . implode("`, `", array_keys($arr)) . "`) VALUES ('" . implode("', '", array_values($arr)) . "')");
    // find the item we just created
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = %d ORDER BY `id` ASC ", $arr['uri'], intval($arr['uid']));
    if (count($r)) {
        $current_post = $r[0]['id'];
        logger('item_store: created item ' . $current_post);
        // Only check for notifications on start posts
        if ($arr['parent-uri'] === $arr['uri']) {
            add_thread($r[0]['id']);
            logger('item_store: Check notification for contact ' . $arr['contact-id'] . ' and post ' . $current_post, LOGGER_DEBUG);
            // Send a notification for every new post?
            $r = q("SELECT `notify_new_posts` FROM `contact` WHERE `id` = %d AND `uid` = %d AND `notify_new_posts` LIMIT 1", intval($arr['contact-id']), intval($arr['uid']));
            if (count($r)) {
                logger('item_store: Send notification for contact ' . $arr['contact-id'] . ' and post ' . $current_post, LOGGER_DEBUG);
                $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1", intval($arr['uid']));
                $item = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d", intval($current_post), intval($arr['uid']));
                $a = get_app();
                require_once 'include/enotify.php';
                notification(array('type' => NOTIFY_SHARE, 'notify_flags' => $u[0]['notify-flags'], 'language' => $u[0]['language'], 'to_name' => $u[0]['username'], 'to_email' => $u[0]['email'], 'uid' => $u[0]['uid'], 'item' => $item[0], 'link' => $a->get_baseurl() . '/display/' . urlencode($arr['guid']), 'source_name' => $item[0]['author-name'], 'source_link' => $item[0]['author-link'], 'source_photo' => $item[0]['author-avatar'], 'verb' => ACTIVITY_TAG, 'otype' => 'item'));
                logger('item_store: Notification sent for contact ' . $arr['contact-id'] . ' and post ' . $current_post, LOGGER_DEBUG);
            }
        }
    } else {
        logger('item_store: could not locate created item');
        return 0;
    }
    if (count($r) > 1) {
        logger('item_store: duplicated post occurred. Removing duplicates.');
        q("DELETE FROM `item` WHERE `uri` = '%s' AND `uid` = %d AND `id` != %d ", $arr['uri'], intval($arr['uid']), intval($current_post));
    }
    if (!$parent_id || $arr['parent-uri'] === $arr['uri']) {
        $parent_id = $current_post;
    }
    if (strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid)) {
        $private = 1;
    } else {
        $private = $arr['private'];
    }
    // Set parent id - and also make sure to inherit the parent's ACLs.
    $r = q("UPDATE `item` SET `parent` = %d, `allow_cid` = '%s', `allow_gid` = '%s',\n\t\t`deny_cid` = '%s', `deny_gid` = '%s', `private` = %d, `deleted` = %d WHERE `id` = %d", intval($parent_id), dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), dbesc($deny_gid), intval($private), intval($parent_deleted), intval($current_post));
    // Complete ostatus threads
    if ($ostatus_conversation) {
        complete_conversation($current_post, $ostatus_conversation);
    }
    $arr['id'] = $current_post;
    $arr['parent'] = $parent_id;
    $arr['allow_cid'] = $allow_cid;
    $arr['allow_gid'] = $allow_gid;
    $arr['deny_cid'] = $deny_cid;
    $arr['deny_gid'] = $deny_gid;
    $arr['private'] = $private;
    $arr['deleted'] = $parent_deleted;
    // update the commented timestamp on the parent
    q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent_id));
    update_thread($parent_id);
    if ($dsprsig) {
        q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($current_post), dbesc($dsprsig->signed_text), dbesc($dsprsig->signature), dbesc($dsprsig->signer));
    }
    /**
     * If this is now the last-child, force all _other_ children of this parent to *not* be last-child
     */
    if ($arr['last-child']) {
        $r = q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d AND `id` != %d", dbesc($arr['uri']), intval($arr['uid']), intval($current_post));
    }
    $deleted = tag_deliver($arr['uid'], $current_post);
    // current post can be deleted if is for a communuty page and no mention are
    // in it.
    if (!$deleted) {
        // Store the fresh generated item into the cache
        $cachefile = get_cachefile($arr["guid"] . "-" . hash("md5", $arr['body']));
        if ($cachefile != '' and !file_exists($cachefile)) {
            $s = prepare_text($arr['body']);
            $a = get_app();
            $stamp1 = microtime(true);
            file_put_contents($cachefile, $s);
            $a->save_timestamp($stamp1, "file");
            logger('item_store: put item ' . $current_post . ' into cachefile ' . $cachefile);
        }
        $r = q('SELECT * FROM `item` WHERE id = %d', intval($current_post));
        if (count($r) == 1) {
            call_hooks('post_remote_end', $r[0]);
        } else {
            logger('item_store: new item not found in DB, id ' . $current_post);
        }
    }
    create_tags_from_item($current_post);
    create_files_from_item($current_post);
    if ($notify) {
        proc_run('php', "include/notifier.php", $notify_type, $current_post);
    }
    return $current_post;
}
Exemplo n.º 6
0
 function prepare_body($item, $attach = false)
 {
     $a = get_app();
     call_hooks('prepare_body_init', $item);
     //$cachefile = get_cachefile($item["guid"]."-".strtotime($item["edited"])."-".hash("crc32", $item['body']));
     $cachefile = get_cachefile($item["guid"] . "-" . hash("md5", $item['body']));
     if ($cachefile != '') {
         if (file_exists($cachefile)) {
             $stamp1 = microtime(true);
             $s = file_get_contents($cachefile);
             $a->save_timestamp($stamp1, "file");
         } else {
             redir_private_images($a, $item);
             $s = prepare_text($item['body']);
             $stamp1 = microtime(true);
             file_put_contents($cachefile, $s);
             $a->save_timestamp($stamp1, "file");
             logger('prepare_body: put item ' . $item["id"] . ' into cachefile ' . $cachefile);
         }
     } else {
         redir_private_images($a, $item);
         $s = prepare_text($item['body']);
     }
     $prep_arr = array('item' => $item, 'html' => $s);
     call_hooks('prepare_body', $prep_arr);
     $s = $prep_arr['html'];
     if (!$attach) {
         // Replace the blockquotes with quotes that are used in mails
         $mailquote = '<blockquote type="cite" class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">';
         $s = str_replace(array('<blockquote>', '<blockquote class="spoiler">', '<blockquote class="author">'), array($mailquote, $mailquote, $mailquote), $s);
         return $s;
     }
     $arr = explode('[/attach],', $item['attach']);
     if (count($arr)) {
         $s .= '<div class="body-attach">';
         foreach ($arr as $r) {
             $matches = false;
             $icon = '';
             $cnt = preg_match_all('|\\[attach\\]href=\\"(.*?)\\" length=\\"(.*?)\\" type=\\"(.*?)\\" title=\\"(.*?)\\"|', $r, $matches, PREG_SET_ORDER);
             if ($cnt) {
                 foreach ($matches as $mtch) {
                     $filetype = strtolower(substr($mtch[3], 0, strpos($mtch[3], '/')));
                     if ($filetype) {
                         $filesubtype = strtolower(substr($mtch[3], strpos($mtch[3], '/') + 1));
                         $filesubtype = str_replace('.', '-', $filesubtype);
                     } else {
                         $filetype = 'unkn';
                         $filesubtype = 'unkn';
                     }
                     $icon = '<div class="attachtype icon s22 type-' . $filetype . ' subtype-' . $filesubtype . '"></div>';
                     /*$icontype = strtolower(substr($mtch[3],0,strpos($mtch[3],'/')));
                     		switch($icontype) {
                     			case 'video':
                     			case 'audio':
                     			case 'image':
                     			case 'text':
                     				$icon = '<div class="attachtype icon s22 type-' . $icontype . '"></div>';
                     				break;
                     			default:
                     				$icon = '<div class="attachtype icon s22 type-unkn"></div>';
                     				break;
                     		}*/
                     $title = strlen(trim($mtch[4])) ? escape_tags(trim($mtch[4])) : escape_tags($mtch[1]);
                     $title .= ' ' . $mtch[2] . ' ' . t('bytes');
                     if (local_user() == $item['uid'] && $item['contact-id'] != $a->contact['id'] && $item['network'] == NETWORK_DFRN) {
                         $the_url = $a->get_baseurl() . '/redir/' . $item['contact-id'] . '?f=1&url=' . $mtch[1];
                     } else {
                         $the_url = $mtch[1];
                     }
                     $s .= '<a href="' . strip_tags($the_url) . '" title="' . $title . '" class="attachlink" target="external-link" >' . $icon . '</a>';
                 }
             }
         }
         $s .= '<div class="clear"></div></div>';
     }
     // Look for spoiler
     $spoilersearch = '<blockquote class="spoiler">';
     // Remove line breaks before the spoiler
     while (strpos($s, "\n" . $spoilersearch) !== false) {
         $s = str_replace("\n" . $spoilersearch, $spoilersearch, $s);
     }
     while (strpos($s, "<br />" . $spoilersearch) !== false) {
         $s = str_replace("<br />" . $spoilersearch, $spoilersearch, $s);
     }
     while (strpos($s, $spoilersearch) !== false) {
         $pos = strpos($s, $spoilersearch);
         $rnd = random_string(8);
         $spoilerreplace = '<br /> <span id="spoiler-wrap-' . $rnd . '" style="white-space:nowrap;" class="fakelink" onclick="openClose(\'spoiler-' . $rnd . '\');">' . sprintf(t('Click to open/close')) . '</span>' . '<blockquote class="spoiler" id="spoiler-' . $rnd . '" style="display: none;">';
         $s = substr($s, 0, $pos) . $spoilerreplace . substr($s, $pos + strlen($spoilersearch));
     }
     // Look for quote with author
     $authorsearch = '<blockquote class="author">';
     while (strpos($s, $authorsearch) !== false) {
         $pos = strpos($s, $authorsearch);
         $rnd = random_string(8);
         $authorreplace = '<br /> <span id="author-wrap-' . $rnd . '" style="white-space:nowrap;" class="fakelink" onclick="openClose(\'author-' . $rnd . '\');">' . sprintf(t('Click to open/close')) . '</span>' . '<blockquote class="author" id="author-' . $rnd . '" style="display: block;">';
         $s = substr($s, 0, $pos) . $authorreplace . substr($s, $pos + strlen($authorsearch));
     }
     $prep_arr = array('item' => $item, 'html' => $s);
     call_hooks('prepare_body_final', $prep_arr);
     return $prep_arr['html'];
 }
Exemplo n.º 7
0
function item_post(&$a)
{
    if (!local_user() && !remote_user() && !x($_REQUEST, 'commenter')) {
        return;
    }
    require_once 'include/security.php';
    $uid = local_user();
    if (x($_REQUEST, 'dropitems')) {
        require_once 'include/items.php';
        $arr_drop = explode(',', $_REQUEST['dropitems']);
        drop_items($arr_drop);
        $json = array('success' => 1);
        echo json_encode($json);
        killme();
    }
    call_hooks('post_local_start', $_REQUEST);
    //	logger('postinput ' . file_get_contents('php://input'));
    logger('postvars ' . print_r($_REQUEST, true), LOGGER_DATA);
    $api_source = x($_REQUEST, 'api_source') && $_REQUEST['api_source'] ? true : false;
    $message_id = x($_REQUEST, 'message_id') && $api_source ? strip_tags($_REQUEST['message_id']) : '';
    $return_path = x($_REQUEST, 'return') ? $_REQUEST['return'] : '';
    $preview = x($_REQUEST, 'preview') ? intval($_REQUEST['preview']) : 0;
    // Check for doubly-submitted posts, and reject duplicates
    // Note that we have to ignore previews, otherwise nothing will post
    // after it's been previewed
    if (!$preview && x($_REQUEST['post_id_random'])) {
        if (x($_SESSION['post-random']) && $_SESSION['post-random'] == $_REQUEST['post_id_random']) {
            logger("item post: duplicate post", LOGGER_DEBUG);
            item_post_return($a->get_baseurl(), $api_source, $return_path);
        } else {
            $_SESSION['post-random'] = $_REQUEST['post_id_random'];
        }
    }
    /**
     * Is this a reply to something?
     */
    $parent = x($_REQUEST, 'parent') ? intval($_REQUEST['parent']) : 0;
    $parent_uri = x($_REQUEST, 'parent_uri') ? trim($_REQUEST['parent_uri']) : '';
    $parent_item = null;
    $parent_contact = null;
    $thr_parent = '';
    $parid = 0;
    $r = false;
    $objecttype = null;
    if ($parent || $parent_uri) {
        $objecttype = ACTIVITY_OBJ_COMMENT;
        if (!x($_REQUEST, 'type')) {
            $_REQUEST['type'] = 'net-comment';
        }
        if ($parent) {
            $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($parent));
        } elseif ($parent_uri && local_user()) {
            // This is coming from an API source, and we are logged in
            $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($parent_uri), intval(local_user()));
        }
        // if this isn't the real parent of the conversation, find it
        if ($r !== false && count($r)) {
            $parid = $r[0]['parent'];
            $parent_uri = $r[0]['uri'];
            if ($r[0]['id'] != $r[0]['parent']) {
                $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", intval($parid));
            }
        }
        if ($r === false || !count($r)) {
            notice(t('Unable to locate original post.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
        $parent_item = $r[0];
        $parent = $r[0]['id'];
        // multi-level threading - preserve the info but re-parent to our single level threading
        //if(($parid) && ($parid != $parent))
        $thr_parent = $parent_uri;
        if ($parent_item['contact-id'] && $uid) {
            $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($parent_item['contact-id']), intval($uid));
            if (count($r)) {
                $parent_contact = $r[0];
            }
        }
    }
    if ($parent) {
        logger('mod_item: item_post parent=' . $parent);
    }
    $profile_uid = x($_REQUEST, 'profile_uid') ? intval($_REQUEST['profile_uid']) : 0;
    $post_id = x($_REQUEST, 'post_id') ? intval($_REQUEST['post_id']) : 0;
    $app = x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : '';
    $allow_moderated = false;
    // here is where we are going to check for permission to post a moderated comment.
    // First check that the parent exists and it is a wall item.
    if (x($_REQUEST, 'commenter') && (!$parent || !$parent_item['wall'])) {
        notice(t('Permission denied.') . EOL);
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    // Now check that it is a page_type of PAGE_BLOG, and that valid personal details
    // have been provided, and run any anti-spam plugins
    // TODO
    if (!can_write_wall($a, $profile_uid) && !$allow_moderated) {
        notice(t('Permission denied.') . EOL);
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    // is this an edited post?
    $orig_post = null;
    if ($post_id) {
        $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($post_id));
        if (!count($i)) {
            killme();
        }
        $orig_post = $i[0];
    }
    $user = null;
    $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($profile_uid));
    if (count($r)) {
        $user = $r[0];
    }
    if ($orig_post) {
        $str_group_allow = $orig_post['allow_gid'];
        $str_contact_allow = $orig_post['allow_cid'];
        $str_group_deny = $orig_post['deny_gid'];
        $str_contact_deny = $orig_post['deny_cid'];
        $location = $orig_post['location'];
        $coord = $orig_post['coord'];
        $verb = $orig_post['verb'];
        $objecttype = $orig_post['object-type'];
        $emailcc = $orig_post['emailcc'];
        $app = $orig_post['app'];
        $categories = $orig_post['file'];
        $title = notags(trim($_REQUEST['title']));
        $body = escape_tags(trim($_REQUEST['body']));
        $private = $orig_post['private'];
        $pubmail_enable = $orig_post['pubmail'];
        $network = $orig_post['network'];
        $guid = $orig_post['guid'];
    } else {
        // if coming from the API and no privacy settings are set,
        // use the user default permissions - as they won't have
        // been supplied via a form.
        if ($api_source && !array_key_exists('contact_allow', $_REQUEST) && !array_key_exists('group_allow', $_REQUEST) && !array_key_exists('contact_deny', $_REQUEST) && !array_key_exists('group_deny', $_REQUEST)) {
            $str_group_allow = $user['allow_gid'];
            $str_contact_allow = $user['allow_cid'];
            $str_group_deny = $user['deny_gid'];
            $str_contact_deny = $user['deny_cid'];
        } else {
            // use the posted permissions
            $str_group_allow = perms2str($_REQUEST['group_allow']);
            $str_contact_allow = perms2str($_REQUEST['contact_allow']);
            $str_group_deny = perms2str($_REQUEST['group_deny']);
            $str_contact_deny = perms2str($_REQUEST['contact_deny']);
        }
        $title = notags(trim($_REQUEST['title']));
        $location = notags(trim($_REQUEST['location']));
        $coord = notags(trim($_REQUEST['coord']));
        $verb = notags(trim($_REQUEST['verb']));
        $emailcc = notags(trim($_REQUEST['emailcc']));
        $body = escape_tags(trim($_REQUEST['body']));
        $network = notags(trim($_REQUEST['network']));
        $guid = get_guid(32);
        $naked_body = preg_replace('/\\[(.+?)\\]/', '', $body);
        if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
            $l = new Text_LanguageDetect();
            //$lng = $l->detectConfidence($naked_body);
            //$postopts = (($lng['language']) ? 'lang=' . $lng['language'] . ';' . $lng['confidence'] : '');
            $lng = $l->detect($naked_body, 3);
            if (sizeof($lng) > 0) {
                $postopts = "";
                foreach ($lng as $language => $score) {
                    if ($postopts == "") {
                        $postopts = "lang=";
                    } else {
                        $postopts .= ":";
                    }
                    $postopts .= $language . ";" . $score;
                }
            }
            logger('mod_item: detect language' . print_r($lng, true) . $naked_body, LOGGER_DATA);
        } else {
            $postopts = '';
        }
        $private = strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) ? 1 : 0;
        if ($user['hidewall']) {
            $private = 2;
        }
        // If this is a comment, set the permissions from the parent.
        if ($parent_item) {
            $private = 0;
            // for non native networks use the network of the original post as network of the item
            if ($parent_item['network'] != NETWORK_DIASPORA and $parent_item['network'] != NETWORK_OSTATUS and $network == "") {
                $network = $parent_item['network'];
            }
            if ($parent_item['private'] || strlen($parent_item['allow_cid']) || strlen($parent_item['allow_gid']) || strlen($parent_item['deny_cid']) || strlen($parent_item['deny_gid'])) {
                $private = $parent_item['private'] ? $parent_item['private'] : 1;
            }
            $str_contact_allow = $parent_item['allow_cid'];
            $str_group_allow = $parent_item['allow_gid'];
            $str_contact_deny = $parent_item['deny_cid'];
            $str_group_deny = $parent_item['deny_gid'];
        }
        $pubmail_enable = x($_REQUEST, 'pubmail_enable') && intval($_REQUEST['pubmail_enable']) && !$private ? 1 : 0;
        // if using the API, we won't see pubmail_enable - figure out if it should be set
        if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) {
            $mail_disabled = function_exists('imap_open') && !get_config('system', 'imap_disabled') ? 0 : 1;
            if (!$mail_disabled) {
                $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval(local_user()));
                if (count($r) && intval($r[0]['pubmail'])) {
                    $pubmail_enabled = true;
                }
            }
        }
        if (!strlen($body)) {
            if ($preview) {
                killme();
            }
            info(t('Empty post discarded.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    if (strlen($categories)) {
        // get the "fileas" tags for this post
        $filedas = file_tag_file_to_list($categories, 'file');
    }
    // save old and new categories, so we can determine what needs to be deleted from pconfig
    $categories_old = $categories;
    $categories = file_tag_list_to_file(trim($_REQUEST['category']), 'category');
    $categories_new = $categories;
    if (strlen($filedas)) {
        // append the fileas stuff to the new categories list
        $categories .= file_tag_list_to_file($filedas, 'file');
    }
    // Work around doubled linefeeds in Tinymce 3.5b2
    // First figure out if it's a status post that would've been
    // created using tinymce. Otherwise leave it alone.
    /*	$plaintext = (local_user() ? intval(get_pconfig(local_user(),'system','plaintext')) || !feature_enabled($profile_uid,'richtext') : 0);
    	if((! $parent) && (! $api_source) && (! $plaintext)) {
    		$body = fix_mce_lf($body);
    	}*/
    $plaintext = local_user() ? !feature_enabled($profile_uid, 'richtext') : 0;
    if (!$parent && !$api_source && !$plaintext) {
        $body = fix_mce_lf($body);
    }
    // get contact info for poster
    $author = null;
    $self = false;
    $contact_id = 0;
    if (local_user() && local_user() == $profile_uid) {
        $self = true;
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($_SESSION['uid']));
    } elseif (remote_user()) {
        if (is_array($_SESSION['remote'])) {
            foreach ($_SESSION['remote'] as $v) {
                if ($v['uid'] == $profile_uid) {
                    $contact_id = $v['cid'];
                    break;
                }
            }
        }
        if ($contact_id) {
            $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        }
    }
    if (count($r)) {
        $author = $r[0];
        $contact_id = $author['id'];
    }
    // get contact info for owner
    if ($profile_uid == local_user()) {
        $contact_record = $author;
    } else {
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($profile_uid));
        if (count($r)) {
            $contact_record = $r[0];
        }
    }
    $post_type = notags(trim($_REQUEST['type']));
    if ($post_type === 'net-comment') {
        if ($parent_item !== null) {
            if ($parent_item['wall'] == 1) {
                $post_type = 'wall-comment';
            } else {
                $post_type = 'remote-comment';
            }
        }
    }
    /**
     *
     * When a photo was uploaded into the message using the (profile wall) ajax
     * uploader, The permissions are initially set to disallow anybody but the
     * owner from seeing it. This is because the permissions may not yet have been
     * set for the post. If it's private, the photo permissions should be set
     * appropriately. But we didn't know the final permissions on the post until
     * now. So now we'll look for links of uploaded messages that are in the
     * post and set them to the same permissions as the post itself.
     *
     */
    $match = null;
    if (!$preview && preg_match_all("/\\[img([\\=0-9x]*?)\\](.*?)\\[\\/img\\]/", $body, $match)) {
        $images = $match[2];
        if (count($images)) {
            $objecttype = ACTIVITY_OBJ_IMAGE;
            foreach ($images as $image) {
                if (!stristr($image, $a->get_baseurl() . '/photo/')) {
                    continue;
                }
                $image_uri = substr($image, strrpos($image, '/') + 1);
                $image_uri = substr($image_uri, 0, strpos($image_uri, '-'));
                if (!strlen($image_uri)) {
                    continue;
                }
                $srch = '<' . intval($contact_id) . '>';
                $r = q("SELECT `id` FROM `photo` WHERE `allow_cid` = '%s' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = ''\n\t\t\t\t\tAND `resource-id` = '%s' AND `uid` = %d LIMIT 1", dbesc($srch), dbesc($image_uri), intval($profile_uid));
                if (!count($r)) {
                    continue;
                }
                $r = q("UPDATE `photo` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\tWHERE `resource-id` = '%s' AND `uid` = %d AND `album` = '%s' ", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), dbesc($image_uri), intval($profile_uid), dbesc(t('Wall Photos')));
            }
        }
    }
    /**
     * Next link in any attachment references we find in the post.
     */
    $match = false;
    if (!$preview && preg_match_all("/\\[attachment\\](.*?)\\[\\/attachment\\]/", $body, $match)) {
        $attaches = $match[1];
        if (count($attaches)) {
            foreach ($attaches as $attach) {
                $r = q("SELECT * FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($attach));
                if (count($r)) {
                    $r = q("UPDATE `attach` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\t\tWHERE `uid` = %d AND `id` = %d", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), intval($profile_uid), intval($attach));
                }
            }
        }
    }
    // embedded bookmark in post? set bookmark flag
    $bookmark = 0;
    if (preg_match_all("/\\[bookmark\\=([^\\]]*)\\](.*?)\\[\\/bookmark\\]/ism", $body, $match, PREG_SET_ORDER)) {
        $objecttype = ACTIVITY_OBJ_BOOKMARK;
        $bookmark = 1;
    }
    $body = bb_translate_video($body);
    /**
     * Fold multi-line [code] sequences
     */
    $body = preg_replace('/\\[\\/code\\]\\s*\\[code\\]/ism', "\n", $body);
    $body = scale_external_images($body, false);
    // Setting the object type if not defined before
    if (!$objecttype) {
        $objecttype = ACTIVITY_OBJ_NOTE;
        // Default value
        require_once "include/plaintext.php";
        $objectdata = get_attached_data($body);
        if ($post["type"] == "link") {
            $objecttype = ACTIVITY_OBJ_BOOKMARK;
        } elseif ($post["type"] == "video") {
            $objecttype = ACTIVITY_OBJ_VIDEO;
        } elseif ($post["type"] == "photo") {
            $objecttype = ACTIVITY_OBJ_IMAGE;
        }
    }
    /**
     * Look for any tags and linkify them
     */
    $str_tags = '';
    $inform = '';
    $tags = get_tags($body);
    /**
     * add a statusnet style reply tag if the original post was from there
     * and we are replying, and there isn't one already
     */
    if ($parent_contact && $parent_contact['network'] === NETWORK_OSTATUS && $parent_contact['nick'] && !in_array('@' . $parent_contact['nick'], $tags)) {
        $body = '@' . $parent_contact['nick'] . ' ' . $body;
        $tags[] = '@' . $parent_contact['nick'];
    }
    $tagged = array();
    $private_forum = false;
    if (count($tags)) {
        foreach ($tags as $tag) {
            // If we already tagged 'Robert Johnson', don't try and tag 'Robert'.
            // Robert Johnson should be first in the $tags array
            $fullnametagged = false;
            for ($x = 0; $x < count($tagged); $x++) {
                if (stristr($tagged[$x], $tag . ' ')) {
                    $fullnametagged = true;
                    break;
                }
            }
            if ($fullnametagged) {
                continue;
            }
            $success = handle_tag($a, $body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network);
            if ($success['replaced']) {
                $tagged[] = $tag;
            }
            if (is_array($success['contact']) && intval($success['contact']['prv'])) {
                $private_forum = true;
                $private_id = $success['contact']['id'];
            }
        }
    }
    if ($private_forum && !$parent && !$private) {
        // we tagged a private forum in a top level post and the message was public.
        // Restrict it.
        $private = 1;
        $str_contact_allow = '<' . $private_id . '>';
    }
    $attachments = '';
    $match = false;
    if (preg_match_all('/(\\[attachment\\]([0-9]+)\\[\\/attachment\\])/', $body, $match)) {
        foreach ($match[2] as $mtch) {
            $r = q("SELECT `id`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($mtch));
            if (count($r)) {
                if (strlen($attachments)) {
                    $attachments .= ',';
                }
                $attachments .= '[attach]href="' . $a->get_baseurl() . '/attach/' . $r[0]['id'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . ($r[0]['filename'] ? $r[0]['filename'] : '') . '"[/attach]';
            }
            $body = str_replace($match[1], '', $body);
        }
    }
    $wall = 0;
    if ($post_type === 'wall' || $post_type === 'wall-comment') {
        $wall = 1;
    }
    if (!strlen($verb)) {
        $verb = ACTIVITY_POST;
    }
    if ($network == "") {
        $network = NETWORK_DFRN;
    }
    $gravity = $parent ? 6 : 0;
    // even if the post arrived via API we are considering that it
    // originated on this site by default for determining relayability.
    $origin = x($_REQUEST, 'origin') ? intval($_REQUEST['origin']) : 1;
    $notify_type = $parent ? 'comment-new' : 'wall-new';
    $uri = $message_id ? $message_id : item_new_uri($a->get_hostname(), $profile_uid);
    // Fallback so that we alway have a thr-parent
    if (!$thr_parent) {
        $thr_parent = $uri;
    }
    $datarray = array();
    $datarray['uid'] = $profile_uid;
    $datarray['type'] = $post_type;
    $datarray['wall'] = $wall;
    $datarray['gravity'] = $gravity;
    $datarray['network'] = $network;
    $datarray['contact-id'] = $contact_id;
    $datarray['owner-name'] = $contact_record['name'];
    $datarray['owner-link'] = $contact_record['url'];
    $datarray['owner-avatar'] = $contact_record['thumb'];
    $datarray['author-name'] = $author['name'];
    $datarray['author-link'] = $author['url'];
    $datarray['author-avatar'] = $author['thumb'];
    $datarray['created'] = datetime_convert();
    $datarray['edited'] = datetime_convert();
    $datarray['commented'] = datetime_convert();
    $datarray['received'] = datetime_convert();
    $datarray['changed'] = datetime_convert();
    $datarray['guid'] = $guid;
    $datarray['uri'] = $uri;
    $datarray['title'] = $title;
    $datarray['body'] = $body;
    $datarray['app'] = $app;
    $datarray['location'] = $location;
    $datarray['coord'] = $coord;
    $datarray['tag'] = $str_tags;
    $datarray['file'] = $categories;
    $datarray['inform'] = $inform;
    $datarray['verb'] = $verb;
    $datarray['object-type'] = $objecttype;
    $datarray['allow_cid'] = $str_contact_allow;
    $datarray['allow_gid'] = $str_group_allow;
    $datarray['deny_cid'] = $str_contact_deny;
    $datarray['deny_gid'] = $str_group_deny;
    $datarray['private'] = $private;
    $datarray['pubmail'] = $pubmail_enable;
    $datarray['attach'] = $attachments;
    $datarray['bookmark'] = intval($bookmark);
    $datarray['thr-parent'] = $thr_parent;
    $datarray['postopts'] = $postopts;
    $datarray['origin'] = $origin;
    $datarray['moderated'] = $allow_moderated;
    /**
     * These fields are for the convenience of plugins...
     * 'self' if true indicates the owner is posting on their own wall
     * If parent is 0 it is a top-level post.
     */
    $datarray['parent'] = $parent;
    $datarray['self'] = $self;
    //	$datarray['prvnets']       = $user['prvnets'];
    if ($orig_post) {
        $datarray['edit'] = true;
    }
    // preview mode - prepare the body for display and send it via json
    if ($preview) {
        require_once 'include/conversation.php';
        $o = conversation($a, array(array_merge($contact_record, $datarray)), 'search', false, true);
        logger('preview: ' . $o);
        echo json_encode(array('preview' => $o));
        killme();
    }
    call_hooks('post_local', $datarray);
    if (x($datarray, 'cancel')) {
        logger('mod_item: post cancelled by plugin.');
        if ($return_path) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        $json = array('cancel' => 1);
        if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
            $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
        }
        echo json_encode($json);
        killme();
    }
    if ($orig_post) {
        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `attach` = '%s', `file` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc($datarray['attach']), dbesc($datarray['file']), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($post_id), intval($profile_uid));
        create_tags_from_item($post_id);
        create_files_from_item($post_id);
        update_thread($post_id);
        // update filetags in pconfig
        file_tag_update_pconfig($uid, $categories_old, $categories_new, 'category');
        proc_run('php', "include/notifier.php", 'edit_post', "{$post_id}");
        if (x($_REQUEST, 'return') && strlen($return_path)) {
            logger('return: ' . $return_path);
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    } else {
        $post_id = 0;
    }
    $r = q("INSERT INTO `item` (`guid`, `uid`,`type`,`wall`,`gravity`, `network`, `contact-id`,`owner-name`,`owner-link`,`owner-avatar`, \n\t\t`author-name`, `author-link`, `author-avatar`, `created`, `edited`, `commented`, `received`, `changed`, `uri`, `thr-parent`, `title`, `body`, `app`, `location`, `coord`, \n\t\t`tag`, `inform`, `verb`, `object-type`, `postopts`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`, `private`, `pubmail`, `attach`, `bookmark`,`origin`, `moderated`, `file` )\n\t\tVALUES( '%s', %d, '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, '%s' )", dbesc($datarray['guid']), intval($datarray['uid']), dbesc($datarray['type']), intval($datarray['wall']), intval($datarray['gravity']), dbesc($datarray['network']), intval($datarray['contact-id']), dbesc($datarray['owner-name']), dbesc($datarray['owner-link']), dbesc($datarray['owner-avatar']), dbesc($datarray['author-name']), dbesc($datarray['author-link']), dbesc($datarray['author-avatar']), dbesc($datarray['created']), dbesc($datarray['edited']), dbesc($datarray['commented']), dbesc($datarray['received']), dbesc($datarray['changed']), dbesc($datarray['uri']), dbesc($datarray['thr-parent']), dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['app']), dbesc($datarray['location']), dbesc($datarray['coord']), dbesc($datarray['tag']), dbesc($datarray['inform']), dbesc($datarray['verb']), dbesc($datarray['object-type']), dbesc($datarray['postopts']), dbesc($datarray['allow_cid']), dbesc($datarray['allow_gid']), dbesc($datarray['deny_cid']), dbesc($datarray['deny_gid']), intval($datarray['private']), intval($datarray['pubmail']), dbesc($datarray['attach']), intval($datarray['bookmark']), intval($datarray['origin']), intval($datarray['moderated']), dbesc($datarray['file']));
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($datarray['uri']));
    if (count($r)) {
        $post_id = $r[0]['id'];
        logger('mod_item: saved item ' . $post_id);
        add_thread($post_id);
        // update filetags in pconfig
        file_tag_update_pconfig($uid, $categories_old, $categories_new, 'category');
        // Store the fresh generated item into the cache
        $cachefile = get_cachefile($datarray["guid"] . "-" . hash("md5", $datarray['body']));
        if ($cachefile != '' and !file_exists($cachefile)) {
            $s = prepare_text($datarray['body']);
            $stamp1 = microtime(true);
            file_put_contents($cachefile, $s);
            $a->save_timestamp($stamp1, "file");
            logger('mod_item: put item ' . $r[0]['id'] . ' into cachefile ' . $cachefile);
        }
        if ($parent) {
            // This item is the last leaf and gets the comment box, clear any ancestors
            $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d ", dbesc(datetime_convert()), intval($parent));
            update_thread($parent, true);
            // Inherit ACLs from the parent item.
            $r = q("UPDATE `item` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d\n\t\t\t\tWHERE `id` = %d", dbesc($parent_item['allow_cid']), dbesc($parent_item['allow_gid']), dbesc($parent_item['deny_cid']), dbesc($parent_item['deny_gid']), intval($parent_item['private']), intval($post_id));
            if ($contact_record != $author) {
                notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'uid' => $user['uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode($datarray['guid']), 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_uri' => $parent_item['uri']));
            }
            // Store the comment signature information in case we need to relay to Diaspora
            store_diaspora_comment_sig($datarray, $author, $self ? $a->user['prvkey'] : false, $parent_item, $post_id);
        } else {
            $parent = $post_id;
            if ($contact_record != $author) {
                notification(array('type' => NOTIFY_WALL, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'uid' => $user['uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode($datarray['guid']), 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item'));
            }
        }
        // fallback so that parent always gets set to non-zero.
        if (!$parent) {
            $parent = $post_id;
        }
        $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `plink` = '%s', `changed` = '%s', `last-child` = 1, `visible` = 1\n\t\t\tWHERE `id` = %d", intval($parent), dbesc($parent == $post_id ? $uri : $parent_item['uri']), dbesc($a->get_baseurl() . '/display/' . urlencode($datarray['guid'])), dbesc(datetime_convert()), intval($post_id));
        // photo comments turn the corresponding item visible to the profile wall
        // This way we don't see every picture in your new photo album posted to your wall at once.
        // They will show up as people comment on them.
        if (!$parent_item['visible']) {
            $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d", intval($parent_item['id']));
            update_thread($parent_item['id']);
        }
    } else {
        logger('mod_item: unable to retrieve post that was just stored.');
        notice(t('System error. Post not saved.') . EOL);
        goaway($a->get_baseurl() . "/" . $return_path);
        // NOTREACHED
    }
    // update the commented timestamp on the parent
    q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent));
    update_thread($parent);
    $datarray['id'] = $post_id;
    $datarray['plink'] = $a->get_baseurl() . '/display/' . urlencode($datarray['guid']);
    call_hooks('post_local_end', $datarray);
    if (strlen($emailcc) && $profile_uid == local_user()) {
        $erecips = explode(',', $emailcc);
        if (count($erecips)) {
            foreach ($erecips as $recip) {
                $addr = trim($recip);
                if (!strlen($addr)) {
                    continue;
                }
                $disclaimer = '<hr />' . sprintf(t('This message was sent to you by %s, a member of the Friendica social network.'), $a->user['username']) . '<br />';
                $disclaimer .= sprintf(t('You may visit them online at %s'), $a->get_baseurl() . '/profile/' . $a->user['nickname']) . EOL;
                $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL;
                if (!$datarray['title'] == '') {
                    $subject = email_header_encode($datarray['title'], 'UTF-8');
                } else {
                    $subject = email_header_encode('[Friendica]' . ' ' . sprintf(t('%s posted an update.'), $a->user['username']), 'UTF-8');
                }
                $link = '<a href="' . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />';
                $html = prepare_body($datarray);
                $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>';
                include_once 'include/html2plain.php';
                $params = array('fromName' => $a->user['username'], 'fromEmail' => $a->user['email'], 'toEmail' => $addr, 'replyTo' => $a->user['email'], 'messageSubject' => $subject, 'htmlVersion' => $message, 'textVersion' => html2plain($html . $disclaimer));
                enotify::send($params);
            }
        }
    }
    create_tags_from_item($post_id);
    create_files_from_item($post_id);
    update_thread($post_id);
    // This is a real juggling act on shared hosting services which kill your processes
    // e.g. dreamhost. We used to start delivery to our native delivery agents in the background
    // and then run our plugin delivery from the foreground. We're now doing plugin delivery first,
    // because as soon as you start loading up a bunch of remote delivey processes, *this* page is
    // likely to get killed off. If you end up looking at an /item URL and a blank page,
    // it's very likely the delivery got killed before all your friends could be notified.
    // Currently the only realistic fixes are to use a reliable server - which precludes shared hosting,
    // or cut back on plugins which do remote deliveries.
    proc_run('php', "include/notifier.php", $notify_type, "{$post_id}");
    logger('post_complete');
    item_post_return($a->get_baseurl(), $api_source, $return_path);
    // NOTREACHED
}
Exemplo n.º 8
0
function create_tags_from_item($itemid)
{
    global $a;
    $profile_base = $a->get_baseurl();
    $profile_data = parse_url($profile_base);
    $profile_base_friendica = $profile_data['host'] . $profile_data['path'] . "/profile/";
    $profile_base_diaspora = $profile_data['host'] . $profile_data['path'] . "/u/";
    $searchpath = $a->get_baseurl() . "/search?tag=";
    $messages = q("SELECT `guid`, `uid`, `id`, `edited`, `deleted`, `title`, `body`, `tag`, `parent` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
    if (!$messages) {
        return;
    }
    $message = $messages[0];
    // Clean up all tags
    q("DELETE FROM `term` WHERE `otype` = %d AND `oid` = %d AND `type` IN (%d, %d)", intval(TERM_OBJ_POST), intval($itemid), intval(TERM_HASHTAG), intval(TERM_MENTION));
    if ($message["deleted"]) {
        return;
    }
    $cachefile = get_cachefile($message["guid"] . "-" . hash("md5", $message['body']));
    if ($cachefile != '' and !file_exists($cachefile)) {
        $s = prepare_text($message['body']);
        $stamp1 = microtime(true);
        file_put_contents($cachefile, $s);
        $a->save_timestamp($stamp1, "file");
        logger('create_tags_from_item: put item ' . $message["id"] . ' into cachefile ' . $cachefile);
    }
    $taglist = explode(",", $message["tag"]);
    $tags = "";
    foreach ($taglist as $tag) {
        if (substr(trim($tag), 0, 1) == "#" or substr(trim($tag), 0, 1) == "@") {
            $tags .= " " . trim($tag);
        } else {
            $tags .= " #" . trim($tag);
        }
    }
    $data = " " . $message["title"] . " " . $message["body"] . " " . $tags . " ";
    $tags = array();
    $pattern = "/\\W\\#([^\\[].*?)[\\s'\".,:;\\?!\\[\\]\\/]/ism";
    if (preg_match_all($pattern, $data, $matches)) {
        foreach ($matches[1] as $match) {
            $tags["#" . strtolower($match)] = "";
        }
    }
    // $searchpath.strtolower($match);
    $pattern = "/\\W([\\#@])\\[url\\=(.*?)\\](.*?)\\[\\/url\\]/ism";
    if (preg_match_all($pattern, $data, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
            $tags[$match[1] . strtolower(trim($match[3], ',.:;[]/\\"?!'))] = $match[2];
        }
    }
    foreach ($tags as $tag => $link) {
        if (substr(trim($tag), 0, 1) == "#") {
            // try to ignore #039 or #1 or anything like that
            if (ctype_digit(substr(trim($tag), 1))) {
                continue;
            }
            // try to ignore html hex escapes, e.g. #x2317
            if ((substr(trim($tag), 1, 1) == 'x' || substr(trim($tag), 1, 1) == 'X') && ctype_digit(substr(trim($tag), 2))) {
                continue;
            }
            $type = TERM_HASHTAG;
            $term = substr($tag, 1);
        } elseif (substr(trim($tag), 0, 1) == "@") {
            $type = TERM_MENTION;
            $term = substr($tag, 1);
        } else {
            // This shouldn't happen
            $type = TERM_HASHTAG;
            $term = $tag;
        }
        $r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`) VALUES (%d, %d, %d, %d, '%s', '%s')", intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval($type), dbesc($term), dbesc($link));
        // Search for mentions
        if (substr($tag, 0, 1) == '@' and (strpos($link, $profile_base_friendica) or strpos($link, $profile_base_diaspora))) {
            $users = q("SELECT `uid` FROM `contact` WHERE self AND (`url` = '%s' OR `nurl` = '%s')", $link, $link);
            foreach ($users as $user) {
                if ($user["uid"] == $message["uid"]) {
                    q("UPDATE `item` SET `mention` = 1 WHERE `id` = %d", intval($itemid));
                    q("UPDATE `thread` SET `mention` = 1 WHERE `iid` = %d", intval($message["parent"]));
                }
            }
        }
    }
}