X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=classes%2FFile.php;h=5acf6a7b50bbacfff11dd4e96a96f578eceaaa34;hb=d6f52f5939c65e904740f4f8b27a18375e1b2964;hp=7748fe83f9fd30223ac77d3bddb5119e1102e771;hpb=b3bf036975593db27c6e7e653f18160d086f7b2d;p=quix0rs-gnu-social.git diff --git a/classes/File.php b/classes/File.php index 7748fe83f9..5acf6a7b50 100644 --- a/classes/File.php +++ b/classes/File.php @@ -33,6 +33,8 @@ class File extends Managed_DataObject public $date; // int(4) public $protected; // int(4) public $filename; // varchar(255) + public $width; // int(4) + public $height; // int(4) public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP public static function schemaDef() @@ -47,6 +49,8 @@ class File extends Managed_DataObject 'date' => array('type' => 'int', 'description' => 'date of resource according to http query'), 'protected' => array('type' => 'int', 'description' => 'true when URL is private (needs login)'), 'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'if a local file, name of the file'), + 'width' => array('type' => 'int', 'description' => 'width in pixels, if it can be described as such and data is available'), + 'height' => array('type' => 'int', 'description' => 'height in pixels, if it can be described as such and data is available'), 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), ), @@ -73,62 +77,26 @@ class File extends Managed_DataObject // I don't know why we have to keep doing this but I'm adding this last check to avoid // uniqueness bugs. - $x = File::getKV('url', $given_url); + $file = File::getKV('url', $given_url); - if (!$x instanceof File) { - $x = new File; - $x->url = $given_url; - if (!empty($redir_data['protected'])) $x->protected = $redir_data['protected']; - if (!empty($redir_data['title'])) $x->title = $redir_data['title']; - if (!empty($redir_data['type'])) $x->mimetype = $redir_data['type']; - if (!empty($redir_data['size'])) $x->size = intval($redir_data['size']); - if (isset($redir_data['time']) && $redir_data['time'] > 0) $x->date = intval($redir_data['time']); - $file_id = $x->insert(); + if (!$file instanceof File) { + $file = new File; + $file->url = $given_url; + if (!empty($redir_data['protected'])) $file->protected = $redir_data['protected']; + if (!empty($redir_data['title'])) $file->title = $redir_data['title']; + if (!empty($redir_data['type'])) $file->mimetype = $redir_data['type']; + if (!empty($redir_data['size'])) $file->size = intval($redir_data['size']); + if (isset($redir_data['time']) && $redir_data['time'] > 0) $file->date = intval($redir_data['time']); + $file_id = $file->insert(); } - $x->saveOembed($redir_data, $given_url); - return $x; - } - - /** - * Save embedding information for this file, if applicable. - * - * Normally this won't need to be called manually, as File::saveNew() - * takes care of it. - * - * @param array $redir_data lookup data eg from File_redirection::where() - * @param string $given_url - * @return boolean success - */ - public function saveOembed(array $redir_data, $given_url) - { - if (isset($redir_data['type']) - && (('text/html' === substr($redir_data['type'], 0, 9) - || 'application/xhtml+xml' === substr($redir_data['type'], 0, 21)))) { - try { - $oembed_data = File_oembed::_getOembed($given_url); - } catch (Exception $e) { - return false; - } - if ($oembed_data === false) { - return false; - } - $fo = File_oembed::getKV('file_id', $this->id); - - if ($fo instanceof File_oembed) { - common_log(LOG_WARNING, "Strangely, a File_oembed object exists for new file $file_id", __FILE__); - } else { - File_oembed::saveNew($oembed_data, $this->id); - return true; - } - } - return false; + Event::handle('EndFileSaveNew', array($file, $redir_data, $given_url)); + return $file; } /** * Go look at a URL and possibly save data about it if it's new: * - follow redirect chains and store them in file_redirection - * - look up oEmbed data and save it in file_oembed * - if a thumbnail is available, save it in file_thumbnail * - save file record with basic info * - optionally save a file_to_post record @@ -267,7 +235,7 @@ class File extends Managed_DataObject } // Normalize and make the original filename more URL friendly. - $origname = basename($origname); + $origname = basename($origname, $ext); if (class_exists('Normalizer')) { // http://php.net/manual/en/class.normalizer.php // http://www.unicode.org/reports/tr15/ @@ -382,7 +350,7 @@ class File extends Managed_DataObject $enclosure->size=$this->size; $enclosure->mimetype=$this->mimetype; - if(! isset($this->filename)){ + if (!isset($this->filename)) { $notEnclosureMimeTypes = array(null,'text/html','application/xhtml+xml'); $mimetype = $this->mimetype; if($mimetype != null){ @@ -392,70 +360,83 @@ class File extends Managed_DataObject if($semicolon){ $mimetype = substr($mimetype,0,$semicolon); } - if(in_array($mimetype,$notEnclosureMimeTypes)){ - // Never treat generic HTML links as an enclosure type! - // But if we have oEmbed info, we'll consider it golden. - $oembed = File_oembed::getKV('file_id',$this->id); - if($oembed && in_array($oembed->type, array('photo', 'video'))){ - $mimetype = strtolower($oembed->mimetype); - $semicolon = strpos($mimetype,';'); - if($semicolon){ - $mimetype = substr($mimetype,0,$semicolon); - } - // @fixme uncertain if this is right. - // we want to expose things like YouTube videos as - // viewable attachments, but don't expose them as - // downloadable enclosures.....? - //if (in_array($mimetype, $notEnclosureMimeTypes)) { - // return false; - //} else { - if($oembed->mimetype) $enclosure->mimetype=$oembed->mimetype; - if($oembed->url) $enclosure->url=$oembed->url; - if($oembed->title) $enclosure->title=$oembed->title; - if($oembed->modified) $enclosure->modified=$oembed->modified; - unset($oembed->size); - //} - } else { - return false; - } + if (in_array($mimetype, $notEnclosureMimeTypes)) { + Event::handle('FileEnclosureMetadata', array($this, &$enclosure)); } } + if (empty($enclosure->mimetype)) { + // This means we don't know what it is, so it can't be an enclosure! + throw new ServerException('Unknown enclosure mimetype, not enough metadata'); + } return $enclosure; } - // quick back-compat hack, since there's still code using this - function isEnclosure() - { - $enclosure = $this->getEnclosure(); - return !empty($enclosure); - } - /** * Get the attachment's thumbnail record, if any. + * Make sure you supply proper 'int' typed variables (or null). * - * @param $width int Max width of thumbnail in pixels - * @param $height int Max height of thumbnail in pixels. If null, set to $width + * @param $width int Max width of thumbnail in pixels. (if null, use common_config values) + * @param $height int Max height of thumbnail in pixels. (if null, square-crop to $width) + * @param $crop bool Crop to the max-values' aspect ratio * * @return File_thumbnail */ - public function getThumbnail($width=null, $height=null) + public function getThumbnail($width=null, $height=null, $crop=false) { + if (intval($this->width) < 1 || intval($this->height) < 1) { + // Old files may have 0 until migrated with scripts/upgrade.php + // For any legitimately unrepresentable ones, we could generate our + // own image (like a square with MIME type in text) + throw new UnsupportedMediaException('No image geometry available.'); + } + if ($width === null) { - $width = common_config('attachments', 'thumb_width'); - $height = common_config('attachments', 'thumb_height'); - $square = common_config('attachments', 'thumb_square'); - } elseif ($height === null) { - $square = true; + $width = common_config('thumbnail', 'width'); + $height = common_config('thumbnail', 'height'); + $crop = common_config('thumbnail', 'crop'); + } + + if ($height === null) { + $height = $width; + $crop = true; + } + + // Get proper aspect ratio width and height before lookup + // We have to do it through an ImageFile object because of orientation etc. + // Only other solution would've been to rotate + rewrite uploaded files. + $image = ImageFile::fromFileObject($this); + list($width, $height, $x, $y, $w2, $h2) = + $image->scaleToFit($width, $height, $crop); + + // Doublecheck that parameters are sane and integers. + if ($width < 1 || $width > common_config('thumbnail', 'maxsize') + || $height < 1 || $height > common_config('thumbnail', 'maxsize')) { + // Fail on bad width parameter. If this occurs, it's due to algorithm in ImageFile->scaleToFit + throw new ServerException('Bad thumbnail size parameters.'); } $params = array('file_id'=> $this->id, 'width' => $width, - 'height' => $square ? $width : $height); + 'height' => $height); $thumb = File_thumbnail::pkeyGet($params); - if ($thumb === null) { - // generate a new thumbnail for desired parameters + if ($thumb instanceof File_thumbnail) { + return $thumb; } - return $thumb; + + // throws exception on failure to generate thumbnail + $outname = "thumb-{$width}x{$height}-" . $this->filename; + $outpath = self::path($outname); + + $image->resizeTo($outpath, $width, $height, $x, $y, $w2, $h2); + + // Avoid deleting the original + if ($image->getPath() != $this->getPath()) { + $image->unlink(); + } + return File_thumbnail::saveThumbnail($this->id, + self::url($outname), + $width, $height, + $outname); } public function getPath() @@ -520,4 +501,34 @@ class File extends Managed_DataObject return $count; } + + public function isLocal() + { + return !empty($this->filename); + } + + public function delete($useWhere=false) + { + // Delete the file, if it exists locally + if (!empty($this->filename) && file_exists(self::path($this->filename))) { + $deleted = @unlink(self::path($this->filename)); + if (!$deleted) { + common_log(LOG_ERR, sprintf('Could not unlink existing file: "%s"', self::path($this->filename))); + } + } + + // Clear out related things in the database and filesystem, such as thumbnails + if (Event::handle('FileDeleteRelated', array($this))) { + $thumbs = new File_thumbnail(); + $thumbs->file_id = $this->id; + if ($thumbs->find()) { + while ($thumbs->fetch()) { + $thumbs->delete(); + } + } + } + + // And finally remove the entry from the database + return parent::delete($useWhere); + } }