diff options
Diffstat (limited to 'include/attach.php')
-rw-r--r-- | include/attach.php | 825 |
1 files changed, 817 insertions, 8 deletions
diff --git a/include/attach.php b/include/attach.php index 6d611cec0..f5eaaa448 100644 --- a/include/attach.php +++ b/include/attach.php @@ -1,6 +1,27 @@ <?php +/** @file + * + * @brief File/attach API with the potential for revision control. + * + * TODO: a filesystem storage abstraction which maintains security (and 'data' contains a system filename + * which is inaccessible from the web). This could get around PHP storage limits and store videos and larger + * items, using fread or OS methods or native code to read/write or chunk it through. + * Also an 'append' option to the storage function might be a useful addition. + */ +require_once('include/permissions.php'); +require_once('include/security.php'); + +/** + * @brief Guess the mimetype from file ending. + * + * This function takes a file name and guess the mimetype from the + * filename extension. + * + * @param $filename a string filename + * @return string The mimetype according to a file ending. + */ function z_mime_content_type($filename) { $mime_types = array( @@ -15,6 +36,7 @@ function z_mime_content_type($filename) { 'xml' => 'application/xml', 'swf' => 'application/x-shockwave-flash', 'flv' => 'video/x-flv', + 'epub' => 'application/epub+zip', // images 'png' => 'image/png', @@ -69,15 +91,802 @@ function z_mime_content_type($filename) { return $mime_types[$ext]; } } -// can't use this because we're just passing a name, e.g. not a file that can be opened -// elseif (function_exists('finfo_open')) { -// $finfo = @finfo_open(FILEINFO_MIME); -// $mimetype = @finfo_file($finfo, $filename); -// @finfo_close($finfo); -// return $mimetype; -// } + + return 'application/octet-stream'; + +} + + +/** + * @brief Count files/attachments. + * + * + * @param $channel_id + * @param $observer + * @param $hash (optional) + * @param $filename (optional) + * @param $filetype (optional) + * @return array + * $ret['success'] boolean + * $ret['results'] amount of found results, or false + * $ret['message'] string with error messages if any + */ +function attach_count_files($channel_id, $observer, $hash = '', $filename = '', $filetype = '') { + + $ret = array('success' => false); + + if(! perm_is_allowed($channel_id,$observer, 'read_storage')) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + require_once('include/security.php'); + $sql_extra = permissions_sql($channel_id); + + if($hash) + $sql_extra .= protect_sprintf(" and hash = '" . dbesc($hash) . "' "); + + if($filename) + $sql_extra .= protect_sprintf(" and filename like '@" . dbesc($filename) . "@' "); + + if($filetype) + $sql_extra .= protect_sprintf(" and filetype like '@" . dbesc($filetype) . "@' "); + + $r = q("select id from attach where uid = %d $sql_extra", + intval($channel_id) + ); + + $ret['success'] = ((is_array($r)) ? true : false); + $ret['results'] = ((is_array($r)) ? count($r) : false); + return $ret; + +} + +/** + * @brief Returns a list of files/attachments. + * + * @param $channel_id + * @param $observer + * @param $hash (optional) + * @param $filename (optional) + * @param $filetype (optional) + * @param $orderby + * @param $start + * @param $entries + * @return array + * $ret['success'] boolean + * $ret['results'] array with results, or false + * $ret['message'] string with error messages if any + */ +function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $filetype = '', $orderby = 'created desc', $start = 0, $entries = 0) { + + $ret = array('success' => false); + + if(! perm_is_allowed($channel_id,$observer, 'read_storage')) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + require_once('include/security.php'); + $sql_extra = permissions_sql($channel_id); + + if($hash) + $sql_extra .= protect_sprintf(" and hash = '" . dbesc($hash) . "' "); + + if($filename) + $sql_extra .= protect_sprintf(" and filename like '@" . dbesc($filename) . "@' "); + + if($filetype) + $sql_extra .= protect_sprintf(" and filetype like '@" . dbesc($filetype) . "@' "); + + if($entries) + $limit = " limit " . intval($start) . ", " . intval(entries) . " "; + + // Retrieve all columns except 'data' + + $r = q("select id, aid, uid, hash, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d $sql_extra $orderby $limit", + intval($channel_id) + ); + + $ret['success'] = ((is_array($r)) ? true : false); + $ret['results'] = ((is_array($r)) ? $r : false); + return $ret; + +} + +/** + * @brief Find an attachment by hash and revision. + * + * Returns the entire attach structure including data. + * + * This could exhaust memory so most useful only when immediately sending the data. + * + * @param $hash + * @param $rev + */ +function attach_by_hash($hash, $rev = 0) { + + $ret = array('success' => false); + + // Check for existence, which will also provide us the owner uid + + $sql_extra = ''; + if($rev == (-1)) + $sql_extra = " order by revision desc "; + elseif($rev) + $sql_extra = " and revision = " . intval($rev) . " "; + + + $r = q("SELECT uid FROM attach WHERE hash = '%s' $sql_extra LIMIT 1", + dbesc($hash) + ); + if(! $r) { + $ret['message'] = t('Item was not found.'); + return $ret; + } + + if(! perm_is_allowed($r[0]['uid'], get_observer_hash(), 'view_storage')) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + $sql_extra = permissions_sql($r[0]['uid']); + + // Now we'll see if we can access the attachment + + $r = q("SELECT * FROM attach WHERE hash = '%s' and uid = %d $sql_extra LIMIT 1", + dbesc($hash), + intval($r[0]['uid']) + ); + + if(! $r) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + $ret['success'] = true; + $ret['data'] = $r[0]; + return $ret; + +} + +/** + * @brief Find an attachment by hash and revision. + * + * Returns the entire attach structure excluding data. + * + * @see attach_by_hash() + * @param $hash + * @param $ref + */ +function attach_by_hash_nodata($hash, $rev = 0) { + + $ret = array('success' => false); + + // Check for existence, which will also provide us the owner uid + + $sql_extra = ''; + if($rev == (-1)) + $sql_extra = " order by revision desc "; + elseif($rev) + $sql_extra = " and revision = " . intval($rev) . " "; + + $r = q("SELECT uid FROM attach WHERE hash = '%s' $sql_extra LIMIT 1", + dbesc($hash) + ); + if(! $r) { + $ret['message'] = t('Item was not found.'); + return $ret; + } + + if(! perm_is_allowed($r[0]['uid'],get_observer_hash(),'view_storage')) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + $sql_extra = permissions_sql($r[0]['uid']); + + // Now we'll see if we can access the attachment + + $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d and hash = '%s' $sql_extra limit 1", + intval($r[0]['uid']), + dbesc($hash) + ); + + if(! $r) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + $ret['success'] = true; + $ret['data'] = $r[0]; + return $ret; + +} + +/** + * @brief + * + * @param $channel channel array of owner + * @param $observer_hash hash of current observer + * @param $options (optional) + * @param $arr (optional) + */ +function attach_store($channel, $observer_hash, $options = '', $arr = null) { + + $ret = array('success' => false); + $channel_id = $channel['channel_id']; + $sql_options = ''; + + if(! perm_is_allowed($channel_id,get_observer_hash(), 'write_storage')) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + // The 'update' option sets db values without uploading a new attachment + // 'replace' replaces the existing uploaded data + // 'revision' creates a new revision with new upload data + // Default is to upload a new file + + // revise or update must provide $arr['hash'] of the thing to revise/update + + if($options !== 'update') { + if(! x($_FILES,'userfile')) { + $ret['message'] = t('No source file.'); + return $ret; + } + + $src = $_FILES['userfile']['tmp_name']; + $filename = basename($_FILES['userfile']['name']); + $filesize = intval($_FILES['userfile']['size']); + } + + $existing_size = 0; + + if($options === 'replace') { + $x = q("select id, hash, filesize from attach where id = %d and uid = %d limit 1", + intval($replace), + intval($channel_id) + ); + if(! $x) { + $ret['message'] = t('Cannot locate file to replace'); + return $ret; + } + $existing_id = $x[0]['id']; + $existing_size = intval($x[0]['filesize']); + $hash = $x[0]['hash']; + } + + if($options === 'revise' || $options === 'update') { + $sql_options = " order by revision desc "; + if($options === 'update' && $arr && array_key_exists('revision',$arr)) + $sql_options = " and revision = " . intval($arr['revision']) . " "; + + $x = q("select id, aid, uid, filename, filetype, filesize, hash, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where hash = '%s' and uid = %d $sql_options limit 1", + dbesc($arr['hash']), + intval($channel_id) + ); + if(! $x) { + $ret['message'] = t('Cannot locate file to revise/update'); + return $ret; + } + $hash = $x[0]['hash']; + } + + // Check storage limits + if($options !== 'update') { + $maxfilesize = get_config('system','maxfilesize'); + + if(($maxfilesize) && ($filesize > $maxfilesize)) { + $ret['message'] = sprintf( t('File exceeds size limit of %d'), $maxfilesize); + @unlink($src); + return $ret; + } + + $limit = service_class_fetch($channel_id, 'attach_upload_limit'); + + if($limit !== false) { + $r = q("select sum(filesize) as total from attach where aid = %d ", + intval($channel['channel_account_id']) + ); + if(($r) && (($r[0]['total'] + $filesize) > ($limit - $existing_size))) { + $ret['message'] = upgrade_message(true) . sprintf(t("You have reached your limit of %1$.0f Mbytes attachment storage."), $limit / 1024000); + @unlink($src); + return $ret; + } + } + $mimetype = z_mime_content_type($filename); + } + + if(! isset($hash)) + $hash = random_string(); + $created = datetime_convert(); + + if($options === 'replace') { + $r = q("update attach set filename = '%s', filetype = '%s', filesize = %d, data = '%s', edited = '%s' where id = %d and uid = %d limit 1", + dbesc($filename), + dbesc($mimetype), + intval($filesize), + dbesc(@file_get_contents($src)), + dbesc($created), + intval($existing_id), + intval($channel_id) + ); + } + elseif($options === 'revise') { + $r = q("insert into attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + intval($x[0]['aid']), + intval($channel_id), + dbesc($x[0]['hash']), + dbesc(get_observer_hash()), + dbesc($filename), + dbesc($mimetype), + intval($filesize), + intval($x[0]['revision'] + 1), + dbesc(@file_get_contents($src)), + dbesc($created), + dbesc($created), + dbesc($x[0]['allow_cid']), + dbesc($x[0]['allow_gid']), + dbesc($x[0]['deny_cid']), + dbesc($x[0]['deny_gid']) + ); + } + elseif($options === 'update') { + $r = q("update attach set filename = '%s', filetype = '%s', edited = '%s', + allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where id = %d and uid = %d limit 1", + dbesc((array_key_exists('filename',$arr)) ? $arr['filename'] : $x[0]['filename']), + dbesc((array_key_exists('filetype',$arr)) ? $arr['filetype'] : $x[0]['filetype']), + dbesc($created), + dbesc((array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : $x[0]['allow_cid']), + dbesc((array_key_exists('allow_gid',$arr)) ? $arr['allow_gid'] : $x[0]['allow_gid']), + dbesc((array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : $x[0]['deny_cid']), + dbesc((array_key_exists('deny_gid',$arr)) ? $arr['deny_gid'] : $x[0]['deny_gid']), + intval($x[0]['id']), + intval($x[0]['uid']) + ); + } else { - return 'application/octet-stream'; + $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, data, created, edited, allow_cid, allow_gid,deny_cid, deny_gid ) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + intval($channel['channel_account_id']), + intval($channel_id), + dbesc($hash), + dbesc(get_observer_hash()), + dbesc($filename), + dbesc($mimetype), + intval($filesize), + intval(0), + dbesc(@file_get_contents($src)), + dbesc($created), + dbesc($created), + dbesc(($arr && array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : '<' . $channel['channel_hash'] . '>'), + dbesc(($arr && array_key_exists('allow_gid',$arr)) ? $arr['allow_gid'] : ''), + dbesc(($arr && array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : ''), + dbesc(($arr && array_key_exists('deny_gid',$arr)) ? $arr['deny_gid'] : '') + ); + } + + if($options !== 'update') + @unlink($src); + + if(! $r) { + $ret['message'] = t('File upload failed. Possible system limit or action terminated.'); + return $ret; + } + + // Caution: This re-uses $sql_options set further above + + $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d and hash = '%s' $sql_options limit 1", + intval($channel_id), + dbesc($hash) + ); + + if(! $r) { + $ret['message'] = t('Stored file could not be verified. Upload failed.'); + return $ret; + } + + $ret['success'] = true; + $ret['data'] = $r[0]; + return $ret; +} + +/** + * Read a virtual directory and return contents, checking permissions of all parent components. + * @function z_readdir + * @param integer $channel_id + * @param string $observer_hash hash of current observer + * @param string $pathname + * @param string $parent_hash (optional) + * + * @returns array $ret + * $ret['success'] = boolean true or false + * $ret['message'] = error message if success is false + * $ret['data'] = array of attach DB entries without data component + */ +function z_readdir($channel_id, $observer_hash, $pathname, $parent_hash = '') { + + $ret = array('success' => false); + if(! perm_is_allowed($r[0]['uid'], get_observer_hash(), 'view_storage')) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + if(strpos($pathname, '/')) { + $paths = explode('/', $pathname); + if(count($paths) > 1) { + $curpath = array_shift($paths); + + $r = q("select hash, id from attach where uid = %d and filename = '%s' and (flags & %d ) " . permissions_sql($channel_id) . " limit 1", + intval($channel_id), + dbesc($curpath), + intval(ATTACH_FLAG_DIR) + ); + if(! $r) { + $ret['message'] = t('Path not available.'); + return $ret; + } + + return z_readdir($channel_id, $observer_hash, implode('/', $paths), $r[0]['hash']); + } + } + else + $paths = array($pathname); + + $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where id = %d and folder = '%s' and filename = '%s' and (flags & %d ) " . permissions_sql($channel_id), + intval($channel_id), + dbesc($parent_hash), + dbesc($paths[0]), + intval(ATTACH_FLAG_DIR) + ); + if(! $r) { + $ret['message'] = t('Path not available.'); + return $ret; + } + $ret['success'] = true; + $ret['data'] = $r; + return $ret; +} + +/** + * @function attach_mkdir($channel,$observer_hash,$arr); + * + * @brief Create directory. + * + * @param $channel channel array of owner + * @param $observer_hash hash of current observer + * @param $arr parameter array to fulfil request + * Required: + * $arr['filename'] + * $arr['folder'] // hash of parent directory, empty string for root directory + * Optional: + * $arr['hash'] // precumputed hash for this node + * $arr['allow_cid'] + * $arr['allow_gid'] + * $arr['deny_cid'] + * $arr['deny_gid'] + */ +function attach_mkdir($channel, $observer_hash, $arr = null) { + + $ret = array('success' => false); + $channel_id = $channel['channel_id']; + $sql_options = ''; + + $basepath = 'store/' . $channel['channel_address']; + + logger('attach_mkdir: basepath: ' . $basepath); + + if(! is_dir($basepath)) + mkdir($basepath,STORAGE_DEFAULT_PERMISSIONS, true); + + if(! perm_is_allowed($channel_id, $observer_hash, 'write_storage')) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + if(! $arr['filename']) { + $ret['message'] = t('Empty pathname'); + return $ret; + } + + $arr['hash'] = (($arr['hash']) ? $arr['hash'] : random_string()); + + // Check for duplicate name. + // Check both the filename and the hash as we will be making use of both. + + $r = q("select hash from attach where ( filename = '%s' or hash = '%s' ) and folder = '%s' and uid = %d limit 1", + dbesc($arr['filename']), + dbesc($arr['hash']), + dbesc($arr['folder']), + intval($channel['channel_id']) + ); + if($r) { + $ret['message'] = t('duplicate filename or path'); + return $ret; + } + + if($arr['folder']) { + + // Walk the directory tree from parent back to root to make sure the parent is valid and name is unique and we + // have permission to see this path. This implies the root directory itself is public since we won't have permissions + // set on the psuedo-directory. We can however set permissions for anything and everything contained within it. + + $lpath = ''; + $lfile = $arr['folder']; + $sql_options = permissions_sql($channel['channel_id']); + + do { + $r = q("select filename, hash, flags, folder from attach where uid = %d and hash = '%s' and ( flags & %d ) + $sql_options limit 1", + intval($channel['channel_id']), + dbesc($lfile), + intval(ATTACH_FLAG_DIR) + ); + + if(! $r) { + logger('attach_mkdir: hash ' . $lfile . ' not found in ' . $lpath); + $ret['message'] = t('Path not found.'); + return $ret; + } + if($lfile) + $lpath = $r[0]['hash'] . '/' . $lpath; + $lfile = $r[0]['folder']; + } while ( ($r[0]['folder']) && ($r[0]['flags'] & ATTACH_FLAG_DIR)) ; + $path = $basepath . '/' . $lpath; + } + else + $path = $basepath . '/'; + + $path .= $arr['hash']; + + $created = datetime_convert(); + + $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, folder, flags, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid ) + VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", + intval($channel['channel_account_id']), + intval($channel_id), + dbesc($arr['hash']), + dbesc(get_observer_hash()), + dbesc($arr['filename']), + dbesc('multipart/mixed'), + intval(0), + intval(0), + dbesc($arr['folder']), + intval(ATTACH_FLAG_DIR|ATTACH_FLAG_OS), + dbesc($path), + dbesc($created), + dbesc($created), + dbesc(($arr && array_key_exists('allow_cid',$arr)) ? $arr['allow_cid'] : $channel['channel_allow_cid']), + dbesc(($arr && array_key_exists('allow_gid',$arr)) ? $arr['allow_gid'] : $channel['channel_allow_gid']), + dbesc(($arr && array_key_exists('deny_cid',$arr)) ? $arr['deny_cid'] : $channel['channel_deny_cid']), + dbesc(($arr && array_key_exists('deny_gid',$arr)) ? $arr['deny_gid'] : $channel['channel_deny_gid']) + ); + + if($r) { + if(mkdir($path,STORAGE_DEFAULT_PERMISSIONS, true)) { + $ret['success'] = true; + $ret['data'] = $arr; + } + else { + logger('attach_mkdir: ' . mkdir . ' ' . $path . 'failed.'); + $ret['message'] = t('mkdir failed.'); + } + } + else + $ret['message'] = t('database storage failed.'); + + return $ret; + +} + +/** + * @brief Changes permissions of a file. + * + * @param $channel_id + * @param $resource + * @param $allow_cid + * @param $allow_gid + * @param $deny_cid + * @param $deny_gid + * @param $recurse + */ +function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $recurse = false) { + + $r = q("select hash, flags from attach where hash = '%s' and uid = %d limit 1", + dbesc($resource), + intval($channel_id) + ); + + if(! $r) + return; + + if($r[0]['flags'] & ATTACH_FLAG_DIR) { + if($recurse) { + $r = q("select hash, flags from attach where folder = '%s' and uid = %d", + dbesc($resource), + intval($channel_id) + ); + if($r) { + foreach($r as $rr) { + attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $recurse); + } + } + } + } + + $x = q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d limit 1", + dbesc($allow_cid), + dbesc($allow_gid), + dbesc($deny_cid), + dbesc($deny_gid), + dbesc($resource), + intval($channel_id) + ); + + return; +} + +/** + * @brief Delete a file. + * + * @param $channel_id + * @param $resource + */ +function attach_delete($channel_id, $resource) { + + + $c = q("select channel_address from channel where channel_id = %d limit 1", + intval($channel_id) + ); + + $channel_address = (($c) ? $c[0]['channel_address'] : 'notfound'); + + $r = q("select hash, flags from attach where hash = '%s' and uid = %d limit 1", + dbesc($resource), + intval($channel_id) + ); + + + if(! $r) + return; + + if($r[0]['flags'] & ATTACH_FLAG_DIR) { + $x = q("select hash, flags from attach where folder = '%s' and uid = %d", + dbesc($resource), + intval($channel_id) + ); + if($x) { + foreach($x as $xx) { + attach_delete($channel_id, $xx['hash']); + } + } + } + if($r[0]['flags'] & ATTACH_FLAG_OS) { + $y = q("select data from attach where hash = '%s' and uid = %d limit 1", + dbesc($resource), + intval($channel_id) + ); + + if($y) { + $f = 'store/' . $channel_address . '/' . $y[0]['data']; + if(is_dir($f)) + @rmdir($f); + elseif(file_exists($f)) + unlink($f); + } + } + + $z = q("delete from attach where hash = '%s' and uid = %d limit 1", + dbesc($resource), + intval($channel_id) + ); + + return; +} + +/** + * @brief Returns path to file in cloud/. + * + * @param $arr + * @return string with the path the file to cloud/ + */ +function get_cloudpath($arr) { + + $basepath = 'cloud/'; + if($arr['uid']) { + $r = q("select channel_address from channel where channel_id = %d limit 1", + intval($arr['uid']) + ); + if($r) + $basepath .= $r[0]['channel_address'] . '/'; } + + $path = $basepath; + + if($arr['folder']) { + + $lpath = ''; + $lfile = $arr['folder']; + + do { + $r = q("select filename, hash, flags, folder from attach where uid = %d and hash = '%s' and ( flags & %d ) + limit 1", + intval($arr['uid']), + dbesc($lfile), + intval(ATTACH_FLAG_DIR) + ); + + if(! $r) + break; + + if($lfile) + $lpath = $r[0]['filename'] . '/' . $lpath; + $lfile = $r[0]['folder']; + + } while ( ($r[0]['folder']) && ($r[0]['flags'] & ATTACH_FLAG_DIR)) ; + + $path .= $lpath; + } + + $path .= $arr['filename']; + return $path; } +/** + * @brief Returns path to parent folder in cloud/. + * + * @param $arr + * @return string with the folder path + */ +function get_parent_cloudpath($channel_id, $channel_name, $attachHash) { + //Build directory tree and redirect + $parentHash = $attachHash; + do { + $parentHash = find_folder_hash_by_attach_hash($channel_id, $parentHash); + if ($parentHash) { + $parentName = find_filename_by_hash($channel_id, $parentHash); + $parentFullPath = $parentName."/".$parentFullPath; + } + } while ($parentHash); + $parentFullPath = z_root() . "/cloud/" . $channel_name . "/" . $parentFullPath; + return $parentFullPath; +} +function find_folder_hash_by_attach_hash($channel_id, $attachHash) { + $r = q("select * from attach where uid = %d and hash = '%s' limit 1", + intval($channel_id), dbesc($attachHash) + ); + $hash = ""; + if($r) { + foreach($r as $rr) { + $hash = $rr['folder']; + } + } + return $hash; +} +function find_filename_by_hash($channel_id, $attachHash) { + $r = q("select * from attach where uid = %d and hash = '%s' limit 1", + intval($channel_id), dbesc($attachHash) + ); + $filename = ""; + if($r) { + foreach($r as $rr) { + $filename = $rr['filename']; + } + } + return $filename; +} + + +/** + * + * @param $in + * @param $out + */ +function pipe_streams($in, $out) { + $size = 0; + while (!feof($in)) + $size += fwrite($out, fread($in,8192)); + return $size; +} |