Example #1
0
function attach_init(&$a)
{
    if (argc() < 2) {
        notice(t('Item not available.') . EOL);
        return;
    }
    $r = attach_by_hash(argv(1), argc() > 2 ? intval(argv(2)) : 0);
    if (!$r['success']) {
        notice($r['message'] . EOL);
        return;
    }
    $c = q("select channel_address from channel where channel_id = %d limit 1", intval($r['data']['uid']));
    if (!$c) {
        return;
    }
    $unsafe_types = array('text/html', 'text/css', 'application/javascript');
    if (in_array($r['data']['filetype'], $unsafe_types)) {
        header('Content-type: text/plain');
    } else {
        header('Content-type: ' . $r['data']['filetype']);
    }
    header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"');
    if ($r['data']['flags'] & ATTACH_FLAG_OS) {
        $istream = fopen('store/' . $c[0]['channel_address'] . '/' . $r['data']['data'], 'rb');
        $ostream = fopen('php://output', 'wb');
        if ($istream && $ostream) {
            pipe_streams($istream, $ostream);
            fclose($istream);
            fclose($ostream);
        }
    } else {
        echo $r['data']['data'];
    }
    killme();
}
Example #2
0
 function post()
 {
     $hash = $_POST['hash'];
     $time = $_POST['time'];
     $sig = $_POST['signature'];
     $resource = $_POST['resource'];
     $revision = intval($_POST['revision']);
     if (!$hash) {
         killme();
     }
     $channel = channelx_by_hash($hash);
     if (!$channel || !$time || !$sig) {
         killme();
     }
     $slop = intval(get_pconfig($channel['channel_id'], 'system', 'getfile_time_slop'));
     if ($slop < 1) {
         $slop = 3;
     }
     $d1 = datetime_convert('UTC', 'UTC', "now + {$slop} minutes");
     $d2 = datetime_convert('UTC', 'UTC', "now - {$slop} minutes");
     if ($time > $d1 || $time < $d2) {
         logger('time outside allowable range');
         killme();
     }
     if (!rsa_verify($hash . '.' . $time, base64url_decode($sig), $channel['channel_pubkey'])) {
         logger('verify failed.');
         killme();
     }
     $r = attach_by_hash($resource, $revision);
     if (!$r['success']) {
         notice($r['message'] . EOL);
         return;
     }
     $unsafe_types = array('text/html', 'text/css', 'application/javascript');
     if (in_array($r['data']['filetype'], $unsafe_types)) {
         header('Content-type: text/plain');
     } else {
         header('Content-type: ' . $r['data']['filetype']);
     }
     header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"');
     if (intval($r['data']['os_storage'])) {
         $fname = dbunescbin($r['data']['data']);
         if (strpos($fname, 'store') !== false) {
             $istream = fopen($fname, 'rb');
         } else {
             $istream = fopen('store/' . $channel['channel_address'] . '/' . $fname, 'rb');
         }
         $ostream = fopen('php://output', 'wb');
         if ($istream && $ostream) {
             pipe_streams($istream, $ostream);
             fclose($istream);
             fclose($ostream);
         }
     } else {
         echo dbunescbin($r['data']['data']);
     }
     killme();
 }
Example #3
0
function sync_files($channel, $files)
{
    require_once 'include/attach.php';
    if ($channel && $files) {
        foreach ($files as $f) {
            if (!$f) {
                continue;
            }
            $fetch_url = $f['fetch_url'];
            $oldbase = dirname($fetch_url);
            $original_channel = $f['original_channel'];
            if (!($fetch_url && $original_channel)) {
                continue;
            }
            if ($f['attach']) {
                $attachment_stored = false;
                foreach ($f['attach'] as $att) {
                    convert_oldfields($att, 'data', 'content');
                    if ($att['deleted']) {
                        attach_delete($channel, $att['hash']);
                        continue;
                    }
                    $attach_exists = false;
                    $x = attach_by_hash($att['hash']);
                    logger('sync_files duplicate check: attach_exists=' . $attach_exists, LOGGER_DEBUG);
                    logger('sync_files duplicate check: att=' . print_r($att, true), LOGGER_DEBUG);
                    logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x, true), LOGGER_DEBUG);
                    if ($x['success']) {
                        $attach_exists = true;
                        $attach_id = $x[0]['id'];
                    }
                    $newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']);
                    unset($att['id']);
                    $att['aid'] = $channel['channel_account_id'];
                    $att['uid'] = $channel['channel_id'];
                    // check for duplicate folder names with the same parent.
                    // If we have a duplicate that doesn't match this hash value
                    // change the name so that the contents won't be "covered over"
                    // by the existing directory. Use the same logic we use for
                    // duplicate files.
                    if (strpos($att['filename'], '.') !== false) {
                        $basename = substr($att['filename'], 0, strrpos($att['filename'], '.'));
                        $ext = substr($att['filename'], strrpos($att['filename'], '.'));
                    } else {
                        $basename = $att['filename'];
                        $ext = '';
                    }
                    $r = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' and hash != '%s' ", dbesc($basename . $ext), dbesc($basename . '(%)' . $ext), dbesc($att['folder']), dbesc($att['hash']));
                    if ($r) {
                        $x = 1;
                        do {
                            $found = false;
                            foreach ($r as $rr) {
                                if ($rr['filename'] === $basename . '(' . $x . ')' . $ext) {
                                    $found = true;
                                    break;
                                }
                            }
                            if ($found) {
                                $x++;
                            }
                        } while ($found);
                        $att['filename'] = $basename . '(' . $x . ')' . $ext;
                    } else {
                        $att['filename'] = $basename . $ext;
                    }
                    // end duplicate detection
                    // @fixme - update attachment structures if they are modified rather than created
                    $att['content'] = $newfname;
                    // Note: we use $att['hash'] below after it has been escaped to
                    // fetch the file contents.
                    // If the hash ever contains any escapable chars this could cause
                    // problems. Currently it does not.
                    dbesc_array($att);
                    if ($attach_exists) {
                        logger('sync_files attach exists: ' . print_r($att, true), LOGGER_DEBUG);
                        $str = '';
                        foreach ($att as $k => $v) {
                            if ($str) {
                                $str .= ",";
                            }
                            $str .= " `" . $k . "` = '" . $v . "' ";
                        }
                        $r = dbq("update `attach` set " . $str . " where id = " . intval($attach_id));
                    } else {
                        logger('sync_files attach does not exists: ' . print_r($att, true), LOGGER_DEBUG);
                        $r = dbq("INSERT INTO attach (`" . implode("`, `", array_keys($att)) . "`) VALUES ('" . implode("', '", array_values($att)) . "')");
                    }
                    // is this a directory?
                    if ($att['filetype'] === 'multipart/mixed' && $att['is_dir']) {
                        os_mkdir($newfname, STORAGE_DEFAULT_PERMISSIONS, true);
                        $attachment_stored = true;
                        continue;
                    } else {
                        // it's a file
                        // for the sync version of this algorithm (as opposed to 'offline import')
                        // we will fetch the actual file from the source server so it can be
                        // streamed directly to disk and avoid consuming PHP memory if it's a huge
                        // audio/video file or something.
                        $time = datetime_convert();
                        $parr = array('hash' => $channel['channel_hash'], 'time' => $time, 'resource' => $att['hash'], 'revision' => 0, 'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])));
                        $store_path = $newfname;
                        $fp = fopen($newfname, 'w');
                        if (!$fp) {
                            logger('failed to open storage file.', LOGGER_NORMAL, LOG_ERR);
                            continue;
                        }
                        $redirects = 0;
                        $x = z_post_url($fetch_url, $parr, $redirects, array('filep' => $fp));
                        fclose($fp);
                        if ($x['success']) {
                            $attachment_stored = true;
                        }
                        continue;
                    }
                }
            }
            if (!$attachment_stored) {
                // @TODO should we queue this and retry or delete everything or what?
                logger('attachment store failed', LOGGER_NORMAL, LOG_ERR);
            }
            if ($f['photo']) {
                foreach ($f['photo'] as $p) {
                    unset($p['id']);
                    $p['aid'] = $channel['channel_account_id'];
                    $p['uid'] = $channel['channel_id'];
                    convert_oldfields($p, 'data', 'content');
                    convert_oldfields($p, 'scale', 'imgscale');
                    convert_oldfields($p, 'size', 'filesize');
                    convert_oldfields($p, 'type', 'mimetype');
                    // if this is a profile photo, undo the profile photo bit
                    // for any other photo which previously held it.
                    if ($p['photo_usage'] == PHOTO_PROFILE) {
                        $e = q("update photo set photo_usage = %d where photo_usage = %d\n\t\t\t\t\t\t\tand resource_id != '%s' and uid = %d ", intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), dbesc($p['resource_id']), intval($channel['channel_id']));
                    }
                    // same for cover photos
                    if ($p['photo_usage'] == PHOTO_COVER) {
                        $e = q("update photo set photo_usage = %d where photo_usage = %d\n\t\t\t\t\t\t\tand resource_id != '%s' and uid = %d ", intval(PHOTO_NORMAL), intval(PHOTO_COVER), dbesc($p['resource_id']), intval($channel['channel_id']));
                    }
                    if ($p['imgscale'] === 0 && $p['os_storage']) {
                        $p['content'] = $store_path;
                    } else {
                        $p['content'] = base64_decode($p['content']);
                    }
                    $exists = q("select * from photo where resource_id = '%s' and imgscale = %d and uid = %d limit 1", dbesc($p['resource_id']), intval($p['imgscale']), intval($channel['channel_id']));
                    dbesc_array($p);
                    if ($exists) {
                        $str = '';
                        foreach ($p as $k => $v) {
                            if ($str) {
                                $str .= ",";
                            }
                            $str .= " `" . $k . "` = '" . $v . "' ";
                        }
                        $r = dbq("update `photo` set " . $str . " where id = " . intval($exists[0]['id']));
                    } else {
                        $r = dbq("INSERT INTO photo (`" . implode("`, `", array_keys($p)) . "`) VALUES ('" . implode("', '", array_values($p)) . "')");
                    }
                }
            }
            if ($f['item']) {
                sync_items($channel, $f['item'], ['channel_address' => $original_channel, 'url' => $oldbase]);
            }
        }
    }
}