gnu-social/classes/Avatar.php
Mikael Nordfeldth 1a1e44cdfd Issue #118 wanted better TOR support, now Avatar URLs are not stored
There was no reason to store the generated Avatar URLs because it's so
cheap to generate them on the fly.
2016-01-06 16:14:26 +01:00

260 lines
9.0 KiB
PHP

<?php
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Table Definition for avatar
*/
class Avatar extends Managed_DataObject
{
public $__table = 'avatar'; // table name
public $profile_id; // int(4) primary_key not_null
public $original; // tinyint(1)
public $width; // int(4) primary_key not_null
public $height; // int(4) primary_key not_null
public $mediatype; // varchar(32) not_null
public $filename; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
public static function schemaDef()
{
return array(
'fields' => array(
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
'original' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'uploaded by user or generated?'),
'width' => array('type' => 'int', 'not null' => true, 'description' => 'image width'),
'height' => array('type' => 'int', 'not null' => true, 'description' => 'image height'),
'mediatype' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'file type'),
'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'local filename, if local'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
'primary key' => array('profile_id', 'width', 'height'),
'unique keys' => array(
// 'avatar_filename_key' => array('filename'),
),
'foreign keys' => array(
'avatar_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
),
'indexes' => array(
'avatar_profile_id_idx' => array('profile_id'),
),
);
}
// We clean up the file, too
function delete($useWhere=false)
{
$filename = $this->filename;
if (file_exists(Avatar::path($filename))) {
@unlink(Avatar::path($filename));
}
return parent::delete($useWhere);
}
/*
* Deletes all avatars (but may spare the original) from a profile.
*
* @param Profile $target The profile we're deleting avatars of.
* @param boolean $original Whether original should be removed or not.
*/
public static function deleteFromProfile(Profile $target, $original=true) {
try {
$avatars = self::getProfileAvatars($target);
foreach ($avatars as $avatar) {
if ($avatar->original && !$original) {
continue;
}
$avatar->delete();
}
} catch (NoAvatarException $e) {
// There are no avatars to delete, a sort of success.
}
return true;
}
static protected $_avatars = array();
/*
* Get an avatar by profile. Currently can't call newSize with $height
*/
public static function byProfile(Profile $target, $width=null, $height=null)
{
$width = intval($width);
$height = !is_null($height) ? intval($height) : null;
if (is_null($height)) {
$height = $width;
}
$size = "{$width}x{$height}";
if (!isset(self::$_avatars[$target->id])) {
self::$_avatars[$target->id] = array();
} elseif (isset(self::$_avatars[$target->id][$size])){
return self::$_avatars[$target->id][$size];
}
$avatar = null;
if (Event::handle('StartProfileGetAvatar', array($target, $width, &$avatar))) {
$avatar = self::pkeyGet(
array(
'profile_id' => $target->id,
'width' => $width,
'height' => $height,
)
);
Event::handle('EndProfileGetAvatar', array($target, $width, &$avatar));
}
if (is_null($avatar)) {
// Obviously we can't find an avatar, so let's resize the original!
$avatar = Avatar::newSize($target, $width);
} elseif (!($avatar instanceof Avatar)) {
throw new NoAvatarException($target, $avatar);
}
self::$_avatars[$target->id]["{$avatar->width}x{$avatar->height}"] = $avatar;
return $avatar;
}
public static function getUploaded(Profile $target)
{
$avatar = new Avatar();
$avatar->profile_id = $target->id;
$avatar->original = true;
if (!$avatar->find(true)) {
throw new NoAvatarException($target, $avatar);
}
if (!file_exists(Avatar::path($avatar->filename))) {
// The delete call may be odd for, say, unmounted filesystems
// that cause a file to currently not exist, but actually it does...
$avatar->delete();
throw new NoAvatarException($target, $avatar);
}
return $avatar;
}
public static function getProfileAvatars(Profile $target) {
$avatar = new Avatar();
$avatar->profile_id = $target->id;
if (!$avatar->find()) {
throw new NoAvatarException($target, $avatar);
}
return $avatar->fetchAll();
}
/**
* Where should the avatar go for this user?
*/
static function filename($id, $extension, $size=null, $extra=null)
{
if ($size) {
return $id . '-' . $size . (($extra) ? ('-' . $extra) : '') . $extension;
} else {
return $id . '-original' . (($extra) ? ('-' . $extra) : '') . $extension;
}
}
static function path($filename)
{
$dir = common_config('avatar', 'dir');
if ($dir[strlen($dir)-1] != '/') {
$dir .= '/';
}
return $dir . $filename;
}
static function url($filename)
{
$path = common_config('avatar', 'path');
if ($path[strlen($path)-1] != '/') {
$path .= '/';
}
if ($path[0] != '/') {
$path = '/'.$path;
}
$server = common_config('avatar', 'server');
if (empty($server)) {
$server = common_config('site', 'server');
}
$ssl = common_config('avatar', 'ssl');
if (is_null($ssl)) { // null -> guess
if (common_config('site', 'ssl') == 'always' &&
!common_config('avatar', 'server')) {
$ssl = true;
} else {
$ssl = false;
}
}
$protocol = ($ssl) ? 'https' : 'http';
return $protocol.'://'.$server.$path.$filename;
}
function displayUrl()
{
return Avatar::url($this->filename);
}
static function urlByProfile(Profile $target, $width=null, $height=null) {
try {
return self::byProfile($target, $width, $height)->displayUrl();
} catch (Exception $e) {
return self::defaultImage($width);
}
}
static function defaultImage($size)
{
static $sizenames = array(AVATAR_PROFILE_SIZE => 'profile',
AVATAR_STREAM_SIZE => 'stream',
AVATAR_MINI_SIZE => 'mini');
return Theme::path('default-avatar-'.$sizenames[$size].'.png');
}
static function newSize(Profile $target, $width) {
$width = intval($width);
if ($width < 1 || $width > common_config('avatar', 'maxsize')) {
// TRANS: An error message when avatar size is unreasonable
throw new Exception(_m('Avatar size too large'));
}
// So far we only have square avatars and I don't have time to
// rewrite support for non-square ones right now ;)
$height = $width;
$original = Avatar::getUploaded($target);
$imagefile = new ImageFile(null, Avatar::path($original->filename));
$filename = Avatar::filename($target->getID(), image_type_to_extension($imagefile->preferredType()),
$width, common_timestamp());
$imagefile->resizeTo(Avatar::path($filename), array('width'=>$width, 'height'=>$height));
$scaled = clone($original);
$scaled->original = false;
$scaled->width = $width;
$scaled->height = $height;
$scaled->filename = $filename;
$scaled->created = common_sql_now();
if (!$scaled->insert()) {
// TRANS: An error message when unable to insert avatar data into the db
throw new Exception(_m('Could not insert new avatar data to database'));
}
// Return the new avatar object
return $scaled;
}
}