aboutsummaryrefslogtreecommitdiffstats
path: root/include/attach.php
diff options
context:
space:
mode:
Diffstat (limited to 'include/attach.php')
-rw-r--r--include/attach.php313
1 files changed, 207 insertions, 106 deletions
diff --git a/include/attach.php b/include/attach.php
index e1db67af4..39269eb03 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -21,7 +21,7 @@ require_once('include/group.php');
* This function takes a file name and guess the mimetype from the
* filename extension.
*
- * @param $filename a string filename
+ * @param string $filename a string filename
* @return string The mimetype according to a file ending.
*/
function z_mime_content_type($filename) {
@@ -31,7 +31,6 @@ function z_mime_content_type($filename) {
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
- 'php' => 'text/html',
'css' => 'text/css',
'md' => 'text/markdown',
'bb' => 'text/bbcode',
@@ -41,8 +40,17 @@ function z_mime_content_type($filename) {
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
'epub' => 'application/epub+zip',
+ 'c' => 'text/plain',
+ 'h' => 'text/plain',
+ 'sh' => 'text/plain',
+ 'py' => 'text/plain',
+ 'php' => 'text/plain',
+ 'rb' => 'text/plain',
+ 'pdl' => 'text/plain',
+
// images
+
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
@@ -73,9 +81,7 @@ function z_mime_content_type($filename) {
'flac' => 'audio/flac',
'opus' => 'audio/ogg',
'webm' => 'video/webm',
-// 'webm' => 'audio/webm',
'mp4' => 'video/mp4',
-// 'mp4' => 'audio/mp4',
'mkv' => 'video/x-matroska',
// adobe
@@ -183,7 +189,7 @@ function attach_count_files($channel_id, $observer, $hash = '', $filename = '',
* * \e array|boolean \b results array with results, or false
* * \e string \b message with error messages if any
*/
-function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $filetype = '', $orderby = 'created desc', $start = 0, $entries = 0) {
+function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $filetype = '', $orderby = 'created desc', $start = 0, $entries = 0, $since = '', $until = '') {
$ret = array('success' => false);
@@ -192,6 +198,7 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $
return $ret;
}
+
require_once('include/security.php');
$sql_extra = permissions_sql($channel_id);
@@ -207,14 +214,22 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $
if($entries)
$limit = " limit " . intval($start) . ", " . intval($entries) . " ";
- // Retrieve all columns except 'data'
+ if(! $since)
+ $since = NULL_DATE;
+
+ if(! $until)
+ $until = datetime_convert();
+
+ $sql_extra .= " and created >= '" . dbesc($since) . "' and created <= '" . dbesc($until) . "' ";
+
+ // Retrieve all columns except 'content'
$r = q("select id, aid, uid, hash, filename, filetype, filesize, revision, folder, os_path, display_path, os_storage, is_dir, is_photo, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d $sql_extra ORDER BY $orderby $limit",
intval($channel_id)
);
$ret['success'] = ((is_array($r)) ? true : false);
- $ret['results'] = ((is_array($r)) ? $r : false);
+ $ret['results'] = ((is_array($r)) ? $r : []);
return $ret;
}
@@ -270,6 +285,8 @@ function attach_by_hash($hash, $observer_hash, $rev = 0) {
return $ret;
}
+ $r[0]['content'] = dbunescbin($r[0]['content']);
+
if($r[0]['folder']) {
$x = attach_can_view_folder($r[0]['uid'],$observer_hash,$r[0]['folder']);
if(! $x) {
@@ -291,6 +308,11 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) {
$hash = $folder_hash;
$result = false;
+ if(! $folder_hash) {
+ return perm_is_allowed($uid,$ob_hash,'view_storage');
+ }
+
+
do {
$r = q("select folder from attach where hash = '%s' and uid = %d $sql_extra",
dbesc($hash),
@@ -412,6 +434,10 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
require_once('include/photos.php');
+ /**
+ * @hooks photo_upload_begin
+ * Called when attempting to upload a photo.
+ */
call_hooks('photo_upload_begin', $arr);
$ret = array('success' => false);
@@ -486,14 +512,36 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$x = attach_mkdir($channel,$observer_hash,$arr);
if($x['message'])
logger('import_directory: ' . $x['message']);
+
return;
}
}
elseif($options !== 'update') {
- $f = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => '');
-
- call_hooks('photo_upload_file',$f);
- call_hooks('attach_upload_file',$f);
+ $f = [
+ 'src' => '',
+ 'filename' => '',
+ 'filesize' => 0,
+ 'type' => ''
+ ];
+
+ /**
+ * @hooks photo_upload_file
+ * Called to generate alternate filenames for an upload.
+ * * \e string \b src - return value, default empty
+ * * \e string \b filename - return value, default empty
+ * * \e number \b filesize - return value, default 0
+ * * \e string \b type - return value, default empty
+ */
+ call_hooks('photo_upload_file', $f);
+ /**
+ * @hooks attach_upload_file
+ * Called when uploading a file.
+ * * \e string \b src - return value, default empty
+ * * \e string \b filename - return value, default empty
+ * * \e number \b filesize - return value, default 0
+ * * \e string \b type - return value, default empty
+ */
+ call_hooks('attach_upload_file', $f);
if (x($f,'src') && x($f,'filesize')) {
$src = $f['src'];
@@ -502,6 +550,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$type = $f['type'];
} else {
if(! x($_FILES,'userfile')) {
+ logger('No source file');
$ret['message'] = t('No source file.');
return $ret;
}
@@ -542,6 +591,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
intval($channel_id)
);
if(! $x) {
+ logger('update file source not found');
$ret['message'] = t('Cannot locate file to revise/update');
return $ret;
}
@@ -562,6 +612,12 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$def_extension = '.png';
}
+ // If we know it's a photo, over-ride the type in case the source system could not determine what it was
+
+ if($is_photo) {
+ $type = $gis['mime'];
+ }
+
$pathname = '';
if($is_photo) {
@@ -677,10 +733,17 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$maxfilesize = get_config('system','maxfilesize');
if(($maxfilesize) && ($filesize > $maxfilesize)) {
+ logger('quota_exceeded');
$ret['message'] = sprintf( t('File exceeds size limit of %d'), $maxfilesize);
if($remove_when_processed)
@unlink($src);
- call_hooks('photo_upload_end',$ret);
+
+ /**
+ * @hooks photo_upload_end
+ * Called when a photo upload has been processed.
+ */
+ call_hooks('photo_upload_end', $ret);
+
return $ret;
}
@@ -691,11 +754,17 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
intval($channel['channel_account_id'])
);
if(($r) && (($r[0]['total'] + $filesize) > ($limit - $existing_size))) {
+ logger('service_class limit exceeded');
$ret['message'] = upgrade_message(true) . sprintf(t("You have reached your limit of %1$.0f Mbytes attachment storage."), $limit / 1024000);
if($remove_when_processed)
@unlink($src);
- call_hooks('photo_upload_end',$ret);
+ /**
+ * @hooks photo_upload_end
+ * Called when a photo upload has been processed.
+ */
+ call_hooks('photo_upload_end', $ret);
+
return $ret;
}
}
@@ -718,8 +787,15 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$os_path = $os_relpath;
$display_path = ltrim($pathname . '/' . $filename,'/');
- if($src)
- @file_put_contents($os_basepath . $os_relpath,@file_get_contents($src));
+ if($src) {
+ $istream = @fopen($src,'rb');
+ $ostream = @fopen($os_basepath . $os_relpath,'wb');
+ if($istream && $ostream) {
+ pipe_streams($istream,$ostream,65535);
+ fclose($istream);
+ fclose($ostream);
+ }
+ }
if(array_key_exists('created', $arr))
$created = $arr['created'];
@@ -773,7 +849,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
);
}
elseif($options === 'update') {
- $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', edited = '%s', os_storage = %d, is_photo = %d, os_path = '%s',
+ $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', edited = '%s', os_storage = %d, is_photo = %d, os_path = '%s',
display_path = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where id = %d and uid = %d",
dbesc((array_key_exists('filename',$arr)) ? $arr['filename'] : $x[0]['filename']),
dbesc((array_key_exists('filetype',$arr)) ? $arr['filetype'] : $x[0]['filetype']),
@@ -862,7 +938,13 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if(! $r) {
$ret['message'] = t('File upload failed. Possible system limit or action terminated.');
- call_hooks('photo_upload_end',$ret);
+
+ /**
+ * @hooks photo_upload_end
+ * Called when a photo upload has been processed.
+ */
+ call_hooks('photo_upload_end', $ret);
+
return $ret;
}
@@ -875,17 +957,30 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
if(! $r) {
$ret['message'] = t('Stored file could not be verified. Upload failed.');
- call_hooks('photo_upload_end',$ret);
+
+ /**
+ * @hooks photo_upload_end
+ * Called when a photo upload has been processed.
+ */
+ call_hooks('photo_upload_end', $ret);
+
return $ret;
}
$ret['success'] = true;
$ret['data'] = $r[0];
if(! $is_photo) {
- // This would've been called already with a success result in photos_upload() if it was a photo.
- call_hooks('photo_upload_end',$ret);
+ /**
+ * @hooks photo_upload_end
+ * Called when a photo upload has been processed.
+ * This would've been called already with a success result in photos_upload() if it was a photo.
+ */
+ call_hooks('photo_upload_end', $ret);
}
+ \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $hash ]);
+
+
if($dosync) {
$sync = attach_export_data($channel,$hash);
@@ -894,9 +989,9 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
}
if($notify) {
- //$cloudPath = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['0']['display_path'];
- //$object = get_file_activity_object($channel['channel_id'], $r['0']['hash'], $cloudPath);
- //file_activity($channel['channel_id'], $object, $r['0']['allow_cid'], $r['0']['allow_gid'], $r['0']['deny_cid'], $r['0']['deny_gid'], 'post', $notify);
+ $cloudPath = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['0']['display_path'];
+ $object = get_file_activity_object($channel['channel_id'], $r['0']['hash'], $cloudPath);
+ file_activity($channel['channel_id'], $object, $r['0']['allow_cid'], $r['0']['allow_gid'], $r['0']['deny_cid'], $r['0']['deny_gid'], 'post', $notify);
}
return $ret;
@@ -986,7 +1081,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
$os_basepath = 'store/' . $channel['channel_address'];
- logger('attach_mkdir: basepath: ' . $os_basepath);
+ logger('basepath: ' . $os_basepath);
if(! is_dir($os_basepath))
os_mkdir($os_basepath,STORAGE_DEFAULT_PERMISSIONS, true);
@@ -1055,7 +1150,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
return $ret;
}
- $dpath = $r[0]['filename'] . (($dpath) ? '/' . $dpath : '');
+ $dpath = $r[0]['filename'] . (($dpath) ? '/' . $dpath : '');
if($lfile)
$lpath = $r[0]['hash'] . (($lpath) ? '/' . $lpath : '');
@@ -1154,7 +1249,7 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
$basepath = 'store/' . $channel['channel_address'];
- logger('attach_mkdirp: basepath: ' . $basepath);
+ logger('basepath: ' . $basepath);
if(! is_dir($basepath))
os_mkdir($basepath,STORAGE_DEFAULT_PERMISSIONS, true);
@@ -1180,6 +1275,7 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
foreach($paths as $p) {
if(! $p)
continue;
+
$arx = array(
'filename' => $p,
'folder' => $current_parent,
@@ -1308,7 +1404,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
);
if(! $r) {
- attach_drop_photo($channel_id,$resource);
+ attach_drop_photo($channel_id,$resource);
return;
}
@@ -1367,7 +1463,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
intval($channel_id)
);
- file_activity($channel_id, $object, $object['allow_cid'], $object['allow_gid'], $object['deny_cid'], $object['deny_gid'], 'update', $notify=1);
+ file_activity($channel_id, $object, $object['allow_cid'], $object['allow_gid'], $object['deny_cid'], $object['deny_gid'], 'update', true);
return;
}
@@ -1501,6 +1597,13 @@ function find_folder_hash_by_attach_hash($channel_id, $attachHash, $recurse = fa
return $hash;
}
+/**
+ * @brief Return the hash of an attachment's folder.
+ *
+ * @param int $channel_id
+ * @param string $path
+ * @return string
+ */
function find_folder_hash_by_path($channel_id, $path) {
if(! $path)
@@ -1530,7 +1633,6 @@ function find_folder_hash_by_path($channel_id, $path) {
return '';
return $parent_hash;
-
}
/**
@@ -1557,14 +1659,17 @@ function find_filename_by_hash($channel_id, $attachHash) {
}
/**
+ * @brief Pipes $in to $out in 16KB chunks.
*
- * @param $in
- * @param $out
+ * @param resource $in File pointer of input
+ * @param resource $out File pointer of output
+ * @param int $bufsize size of chunk, default 16384
+ * @return number with the size
*/
-function pipe_streams($in, $out) {
+function pipe_streams($in, $out, $bufsize = 16384) {
$size = 0;
while (!feof($in))
- $size += fwrite($out, fread($in, 16384));
+ $size += fwrite($out, fread($in, $bufsize));
return $size;
}
@@ -1726,11 +1831,12 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
}
/**
- * @brief Create file activity object
+ * @brief Create file activity object.
*
* @param int $channel_id
* @param string $hash
- * @param string $cloudpath
+ * @param string $url
+ * @return array An associative array for the specified file.
*/
function get_file_activity_object($channel_id, $hash, $url) {
@@ -1958,6 +2064,7 @@ function attach_export_data($channel, $resource_id, $deleted = false) {
if($hash_ptr === $resource_id) {
$attach_ptr = $r[0];
}
+ $r[0]['content'] = dbunescbin($r[0]['content']);
$hash_ptr = $r[0]['folder'];
$paths[] = $r[0];
@@ -1970,6 +2077,9 @@ function attach_export_data($channel, $resource_id, $deleted = false) {
if($attach_ptr['is_photo']) {
+
+ // This query could potentially result in a few megabytes of data use.
+
$r = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale asc",
dbesc($resource_id),
intval($channel['channel_id'])
@@ -1981,6 +2091,17 @@ function attach_export_data($channel, $resource_id, $deleted = false) {
$ret['photo'] = $r;
}
+// This query can be used instead in memory starved environments. There will be a corresponding
+// performance hit during sync because the data will need to be fetched over the network.
+// $r = q("select aid,uid,xchan,resource_id,created,edited,title,description,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,profile,is_nsfw,os_storage,display_path,photo_flags,allow_cid,allow_gid,deny_cid,deny_gid from photo where resource_id = '%s' and uid = %d order by imgscale asc",
+// dbesc($resource_id),
+// intval($channel['channel_id'])
+// );
+
+// if($r) {
+// $ret['photo'] = $r;
+// }
+
$r = q("select * from item where resource_id = '%s' and resource_type = 'photo' and uid = %d ",
dbesc($resource_id),
intval($channel['channel_id'])
@@ -2143,7 +2264,6 @@ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpat
* the attach.hash of the new parent folder, which must already exist. If $new_folder_hash is blank or empty,
* the file is relocated to the root of the channel's storage area.
*
- * @fixme: this operation is currently not synced to clones !!
*
* @param int $channel_id
* @param int $resource_id
@@ -2153,7 +2273,7 @@ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpat
function attach_move($channel_id, $resource_id, $new_folder_hash) {
$c = channelx_by_n($channel_id);
- if(! $c)
+ if(! ($c && $resource_id))
return false;
$r = q("select * from attach where hash = '%s' and uid = %d limit 1",
@@ -2165,13 +2285,32 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
$oldstorepath = dbunescbin($r[0]['content']);
+ if($r[0]['is_dir']) {
+ $move_success = true;
+ $x = q("select hash from attach where folder = '%s' and uid = %d",
+ dbesc($r[0]['hash']),
+ intval($channel_id)
+ );
+ if($x) {
+ foreach($x as $xv) {
+ $rs = attach_move($channel_id,$xv['hash'],$r[0]['hash']);
+ if(! $rs) {
+ $move_success = false;
+ break;
+ }
+ }
+ }
+ return $move_success;
+ }
+
+
if($new_folder_hash) {
- $n = q("select * from attach where hash = '%s' and uid = %d limit 1",
+ $n = q("select * from attach where hash = '%s' and uid = %d and is_dir = 1 limit 1",
dbesc($new_folder_hash),
intval($channel_id)
);
if(! $n)
- return;
+ return false;
$newdirname = $n[0]['filename'];
$newstorepath = dbunescbin($n[0]['content']) . '/' . $resource_id;
@@ -2257,7 +2396,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
if($r[0]['is_photo']) {
- $t = q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s'
+ $t = q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s'
where resource_id = '%s' and uid = %d",
dbesc($newdirname),
dbesc($filename),
@@ -2278,6 +2417,11 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
}
+/**
+ * Used to generate a select input box of all your folders
+ */
+
+
function attach_folder_select_list($channel_id) {
$r = q("select * from attach where is_dir = 1 and uid = %d",
@@ -2328,6 +2472,10 @@ function attach_folder_rpaths($all_folders,$that_folder) {
return (($error) ? false : [ $current_hash , $path ]);
}
+/**
+ * @brief Given a channel_id and attach_hash, return an array with the full relative path and os_path
+ */
+
function attach_syspaths($channel_id,$attach_hash) {
@@ -2349,10 +2497,19 @@ function attach_syspaths($channel_id,$attach_hash) {
while($attach_hash);
return [ 'os_path' => $os_path, 'path' => $path ];
-
-
}
+/**
+ * in earlier releases we did not fill in os_path and display_path in the attach DB structure.
+ * (It was not needed or used). Going forward we intend to make use of these fields.
+ * A cron task checks for empty values (as older attachments may have arrived at our site
+ * in a clone operation) and executes attach_syspaths() to generate these field values and correct
+ * the attach table entry. The operation is limited to 100 DB entries at a time so as not to
+ * overload the system in any cron run. Eventually it will catch up with old attach structures
+ * and switch into maintenance mode to correct any that might arrive in clone packets from older
+ * sites.
+ */
+
function attach_upgrade() {
@@ -2379,6 +2536,12 @@ function attach_upgrade() {
}
+/**
+ * Chunked uploader for integration with the blueimp jquery-uploader
+ * This is currently used.
+ */
+
+
function save_chunk($channel,$start,$end,$len) {
$result = [];
@@ -2386,7 +2549,7 @@ function save_chunk($channel,$start,$end,$len) {
$tmp_path = $_FILES['files']['tmp_name'];
$new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp';
os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true);
-
+
$new_path = $new_base . '/' . $_FILES['files']['name'];
if(! file_exists($new_path)) {
@@ -2403,7 +2566,7 @@ function save_chunk($channel,$start,$end,$len) {
}
if(($len - 1) == $end) {
unlink($tmp_path);
- $result['name'] = $_FILES['files']['tmp_name'];
+ $result['name'] = $_FILES['files']['name'];
$result['type'] = $_FILES['files']['type'];
$result['tmp_name'] = $new_path;
$result['error'] = 0;
@@ -2417,65 +2580,3 @@ function save_chunk($channel,$start,$end,$len) {
}
-/*
- * chunkloader
- * Submit handler for chunked uploads
- *
- */
-
-function chunkloader($channel,$arr) {
-
- logger('request: ' . print_r($arr,true), LOGGER_DEBUG);
- logger('files: ' . print_r($_FILES,true), LOGGER_DEBUG);
-
-
- $result = [];
-
-
- $tmp_path = $_FILES['file']['tmp_name'];
- $new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp';
- os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true);
-
- $new_path = $new_base . '/' . $arr['resumableFilename'];
-
- rename($tmp_path,$new_path . '.' . intval($arr['resumableChunkNumber']));
-
- $missing_parts = false;
- for($x = 1; $x <= intval($arr['resumableTotalChunks']); $x ++) {
- if(! file_exists($new_path . '.' . $x)) {
- $missing_parts = true;
- break;
- }
- }
-
- if($missing_parts) {
- $result['partial'] = true;
- return $result;
- }
-
- if(intval($arr['resumableTotalChunks']) === 1) {
- rename($new_path . '.' . '1', $new_path);
- }
- else {
- for($x = 1; $x <= intval($arr['resumableTotalChunks']); $x ++) {
- $istream = fopen($new_path . '.' . $x,'rb');
- $ostream = fopen($new_path,'ab');
- if($istream && $ostream) {
- pipe_streams($istream,$ostream);
- fclose($istream);
- fclose($ostream);
- }
- unlink($new_path . '.' . $x);
- }
- }
-
- $result['name'] = $arr['resumableFilename'];
- $result['type'] = $arr['resumableType'];
- $result['tmp_name'] = $new_path;
- $result['error'] = 0;
- $result['size'] = $arr['resumableTotalSize'];
- $result['complete'] = true;
- return $result;
-
-}
-