From 2d0aba49d913b7d4598073d5ff56237f736731d0 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 27 Oct 2009 21:45:56 -0700 Subject: [PATCH] Implement media upload in the API --- actions/apistatusesupdate.php | 72 ++++++++++++++++------- lib/mediafile.php | 106 +++++++++++++++++----------------- 2 files changed, 106 insertions(+), 72 deletions(-) diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php index 0d71e15128..b7128d0846 100644 --- a/actions/apistatusesupdate.php +++ b/actions/apistatusesupdate.php @@ -38,6 +38,7 @@ if (!defined('STATUSNET')) { } require_once INSTALLDIR . '/lib/apiauth.php'; +require_once INSTALLDIR . '/lib/mediafile.php'; /** * Updates the authenticating user's status (posts a notice). @@ -60,7 +61,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction var $source = null; var $status = null; var $in_reply_to_status_id = null; - static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); /** @@ -76,25 +76,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction { parent::prepare($args); - $this->user = $this->auth_user; - - if (empty($this->user)) { - $this->clientError(_('No such user!'), 404, $this->format); - return false; - } - + $this->user = $this->auth_user; $this->status = $this->trimmed('status'); - - if (empty($this->status)) { - $this->clientError( - 'Client must provide a \'status\' parameter with a value.', - 400, - $this->format - ); - - return false; - } - $this->source = $this->trimmed('source'); if (empty($this->source) || in_array($source, $this->reserved_sources)) { @@ -129,6 +112,27 @@ class ApiStatusesUpdateAction extends ApiAuthAction return; } + if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) { + $this->clientError(sprintf(_('The server was unable to handle ' . + 'that much POST data (%s bytes) due to its current configuration.'), + $_SERVER['CONTENT_LENGTH'])); + return; + } + + if (empty($this->user)) { + $this->clientError(_('No such user!'), 404, $this->format); + return; + } + + if (empty($this->status)) { + $this->clientError( + 'Client must provide a \'status\' parameter with a value.', + 400, + $this->format + ); + return; + } + $status_shortened = common_shorten_links($this->status); if (Notice::contentTooLong($status_shortened)) { @@ -187,14 +191,42 @@ class ApiStatusesUpdateAction extends ApiAuthAction } } + $upload = null; + + common_debug('looking for attachment'); + + $upload = MediaFile::fromUpload('media', $this->user); + + common_debug("uploaded file = " . var_export($upload, true)); + + if (isset($upload)) { + common_debug('newNotice: found an upload'); + + $status_shortened .= ' ' . $upload->shortUrl(); + + common_debug('content w/upload = ' . $status_shortened); + + if (Notice::contentTooLong($status_shortened)) { + $upload->delete(); + $this->clientError(sprintf(_('Max notice size is %d chars, including attachment URL.'), + Notice::maxContent())); + } else { + common_debug('content not too long'); + } + } + $this->notice = Notice::saveNew( $this->user->id, - html_entity_decode($this->status, ENT_NOQUOTES, 'UTF-8'), + html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8'), $this->source, 1, $reply_to ); + if (isset($upload)) { + $upload->attachToNotice($this->notice); + } + common_broadcast_notice($this->notice); } diff --git a/lib/mediafile.php b/lib/mediafile.php index be101cdcab..31868daec8 100644 --- a/lib/mediafile.php +++ b/lib/mediafile.php @@ -31,9 +31,9 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -class MediaFile +class MediaFile { - + var $filename = null; var $fileRecord = null; var $user = null; @@ -46,16 +46,16 @@ class MediaFile if ($user == null) { $this->user = common_current_user(); } - + common_debug('in MediaFile constructor'); - + $this->filename = $filename; $this->mimetype = $mimetype; - + common_debug('storing file'); $this->fileRecord = $this->storeFile(); common_debug('finished storing file'); - + $this->fileurl = common_local_url('attachment', array('attachment' => $this->fileRecord->id)); @@ -67,24 +67,24 @@ class MediaFile common_debug('shortening file url'); $this->short_fileurl = common_shorten_url($this->fileurl); common_debug('shortened file url = ' . $short_fileurl); - + // Also, not sure this is necessary -- Zach $this->maybeAddRedir($this->fileRecord->id, $this->short_fileurl); - + common_debug("MediaFile: end of constructor"); } - + function attachToNotice($notice) { common_debug('MediaFile::attachToNotice() -- doing File_to_post'); File_to_post::processNew($this->fileRecord->id, $notice->id); common_debug('MediaFile done doing File_to_post'); - + $this->maybeAddRedir($this->fileRecord->id, - common_local_url('file', array('notice' => $notice->id))); + common_local_url('file', array('notice' => $notice->id))); } - - function shortUrl() + + function shortUrl() { return $this->short_fileurl; } @@ -115,12 +115,12 @@ class MediaFile $file_id = $file->insert(); if (!$file_id) { - + common_debug("storeFile: problem inserting new file"); common_log_db_error($file, "INSERT", __FILE__); throw new ClientException(_('There was a database error while saving your file. Please try again.')); } - + common_debug('finished storing file'); return $file; @@ -133,15 +133,15 @@ class MediaFile function maybeAddRedir($file_id, $url) { - + common_debug("maybeAddRedir: looking up url: $url for file id $file_id"); $file_redir = File_redirection::staticGet('url', $url); if (empty($file_redir)) { - + common_debug("maybeAddRedir: $url is not in the db"); - + $file_redir = new File_redirection; $file_redir->url = $url; $file_redir->file_id = $file_id; @@ -153,20 +153,24 @@ class MediaFile throw new ClientException(_('There was a database error while saving your file. Please try again.')); } } else { - + common_debug("maybeAddRedir: no need to add $url, it's already in the db"); } } - static function fromUpload($param = 'media') + static function fromUpload($param = 'media', $user = null) { common_debug("fromUpload: param = $param"); - + + if (empty($user)) { + $user = common_current_user(); + } + if (!isset($_FILES[$param]['error'])){ common_debug('no file found'); return; } - + switch ($_FILES[$param]['error']) { case UPLOAD_ERR_OK: // success, jump out break; @@ -183,7 +187,7 @@ class MediaFile @unlink($_FILES[$param]['tmp_name']); throw new ClientException(_('The uploaded file was only' . ' partially uploaded.')); - return; + return; case UPLOAD_ERR_NO_TMP_DIR: throw new ClientException(_('Missing a temporary folder.')); return; @@ -197,24 +201,22 @@ class MediaFile throw new ClientException(_('System error uploading file.')); return; } - - $user = common_current_user(); - + if (!MediaFile::respectsQuota($user, $_FILES['attach']['size'])) { - + // Should never actually get here - + @unlink($_FILES[$param]['tmp_name']); throw new ClientException(_('File exceeds user\'s quota!')); return; } $mimetype = MediaFile::getUploadedFileType($_FILES[$param]['tmp_name']); - + $filename = null; - + if (isset($mimetype)) { - + $basename = basename($_FILES[$param]['name']); $filename = File::filename($user->getProfile(), $basename, $mimetype); $filepath = File::path($filename); @@ -222,44 +224,44 @@ class MediaFile common_debug("filepath = " . $filepath); $result = move_uploaded_file($_FILES[$param]['tmp_name'], $filepath); - - if (!$result) { + + if (!$result) { throw new ClientException(_('File could not be moved to destination directory.')); return; } - + } else { throw new ClientException(_('Could not determine file\'s mime-type!')); return; } - + return new MediaFile($user, $filename, $mimetype); } - static function fromFilehandle($user, $fh) { + static function fromFilehandle($fh, $user) { $stream = stream_get_meta_data($fh); if (MediaFile::respectsQuota($user, filesize($stream['uri']))) { - + // Should never actually get here - + throw new ClientException(_('File exceeds user\'s quota!')); return; } $mimetype = MediaFile::getUploadedFileType($fh); - + $filename = null; - + if (isset($mimetype)) { $filename = File::filename($user->getProfile(), "email", $mimetype); $filepath = File::path($filename); - + $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664); - + if (!$result) { throw new ClientException(_('File could not be moved to destination directory.' . $stream['uri'] . ' ' . $filepath)); @@ -268,33 +270,33 @@ class MediaFile throw new ClientException(_('Could not determine file\'s mime-type!')); return; } - + return new MediaFile($user, $filename, $mimetype); } static function getUploadedFileType($f) { require_once 'MIME/Type.php'; - + common_debug("in getUploadedFileType"); $cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd'); $cmd = common_config('attachments', 'filecommand'); - + $filetype = null; - + if (is_string($f)) { - + // assuming a filename - + $filetype = MIME_Type::autoDetect($f); } else { - + // assuming a filehandle - + $stream = stream_get_meta_data($f); $filetype = MIME_Type::autoDetect($stream['uri']); } - + if (in_array($filetype, common_config('attachments', 'supported'))) { return $filetype; } @@ -308,7 +310,7 @@ class MediaFile _('%s is not a supported filetype on this server.'), $filetype) . $hint); } - static function respectsQuota($user, $filesize) + static function respectsQuota($user, $filesize) { $file = new File; $result = $file->isRespectsQuota($user, $filesize);