Файл: library/XenForo/Model/Avatar.php
Строк: 364
<?php
/**
* Model for avatars.
*
* @package XenForo_Avatar
*/
class XenForo_Model_Avatar extends XenForo_Model
{
/**
* List of available avatar sizes. The largest must go first.
* Avatars of each size code (directory name) will be no bigger
* than the given pixel amount.
*
* @var array Format: [code] => max pixels
*/
protected static $_sizes = array(
'l' => 192,
'm' => 96,
's' => 48
);
public static $imageQuality = 85;
/**
* Processes an avatar upload for a user.
*
* @param XenForo_Upload $upload The uploaded avatar.
* @param integer $userId User ID avatar belongs to
* @param array|false $permissions User's permissions. False to skip permission checks
*
* @return array Changed avatar fields
*/
public function uploadAvatar(XenForo_Upload $upload, $userId, $permissions)
{
if (!$userId)
{
throw new XenForo_Exception('Missing user ID.');
}
if ($permissions !== false && !is_array($permissions))
{
throw new XenForo_Exception('Invalid permission set.');
}
$largestDimension = $this->getSizeFromCode('l');
if (!$upload->isValid())
{
throw new XenForo_Exception($upload->getErrors(), true);
}
if (!$upload->isImage())
{
throw new XenForo_Exception(new XenForo_Phrase('uploaded_file_is_not_valid_image'), true);
};
$imageType = $upload->getImageInfoField('type');
if (!in_array($imageType, array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG)))
{
throw new XenForo_Exception(new XenForo_Phrase('uploaded_file_is_not_valid_image'), true);
}
$baseTempFile = $upload->getTempFile();
$width = $upload->getImageInfoField('width');
$height = $upload->getImageInfoField('height');
return $this->applyAvatar($userId, $baseTempFile, $imageType, $width, $height, $permissions);
}
/**
* Applies the avatar file to the specified user.
*
* @param integer $userId
* @param string $fileName
* @param constant|false $imageType Type of image (IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG)
* @param integer|false $width
* @param integer|false $height
* @param array|false $permissions
*
* @return array
*/
public function applyAvatar($userId, $fileName, $imageType = false, $width = false, $height = false, $permissions = false)
{
if (!$imageType || !$width || !$height)
{
$imageInfo = getimagesize($fileName);
if (!$imageInfo)
{
throw new XenForo_Exception('Non-image passed in to applyAvatar');
}
$width = $imageInfo[0];
$height = $imageInfo[1];
$imageType = $imageInfo[2];
}
if (!in_array($imageType, array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG)))
{
throw new XenForo_Exception('Invalid image type passed in to applyAvatar');
}
if (!XenForo_Image_Abstract::canResize($width, $height))
{
throw new XenForo_Exception(new XenForo_Phrase('uploaded_image_is_too_big'), true);
}
// require 2:1 aspect ratio or squarer
if ($width > 2 * $height || $height > 2 * $width)
{
throw new XenForo_Exception(new XenForo_Phrase('please_provide_an_image_whose_longer_side_is_no_more_than_twice_length'), true);
}
$outputFiles = array();
$outputType = $imageType;
reset(self::$_sizes);
list($sizeCode, $maxDimensions) = each(self::$_sizes);
$shortSide = ($width > $height ? $height : $width);
if ($shortSide > $maxDimensions)
{
$newTempFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
$image = XenForo_Image_Abstract::createFromFile($fileName, $imageType);
if (!$image)
{
throw new XenForo_Exception(new XenForo_Phrase('image_could_be_processed_try_another_contact_owner'), true);
}
$image->thumbnailFixedShorterSide($maxDimensions);
$image->output($outputType, $newTempFile, self::$imageQuality);
$width = $image->getWidth();
$height = $image->getHeight();
$outputFiles[$sizeCode] = $newTempFile;
}
else
{
$outputFiles[$sizeCode] = $fileName;
}
if (is_array($permissions))
{
$maxFileSize = XenForo_Permission::hasPermission($permissions, 'avatar', 'maxFileSize');
if ($maxFileSize != -1 && filesize($outputFiles[$sizeCode]) > $maxFileSize)
{
foreach ($outputFiles AS $tempFile)
{
if ($tempFile != $fileName)
{
@unlink($tempFile);
}
}
throw new XenForo_Exception(new XenForo_Phrase('your_avatar_file_size_large_smaller_x', array(
'size' => XenForo_Locale::numberFormat($maxFileSize, 'size')
)), true);
}
}
$crop = array(
'x' => array('m' => 0),
'y' => array('m' => 0),
);
while (list($sizeCode, $maxDimensions) = each(self::$_sizes))
{
$newTempFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
$image = XenForo_Image_Abstract::createFromFile($fileName, $imageType);
if (!$image)
{
continue;
}
$image->thumbnailFixedShorterSide($maxDimensions);
if ($image->getOrientation() != XenForo_Image_Abstract::ORIENTATION_SQUARE)
{
$crop['x'][$sizeCode] = floor(($image->getWidth() - $maxDimensions) / 2);
$crop['y'][$sizeCode] = floor(($image->getHeight() - $maxDimensions) / 2);
$image->crop($crop['x'][$sizeCode], $crop['y'][$sizeCode], $maxDimensions, $maxDimensions);
}
$image->output($outputType, $newTempFile, self::$imageQuality);
unset($image);
$outputFiles[$sizeCode] = $newTempFile;
}
if (count($outputFiles) != count(self::$_sizes))
{
foreach ($outputFiles AS $tempFile)
{
if ($tempFile != $fileName)
{
@unlink($tempFile);
}
}
throw new XenForo_Exception(new XenForo_Phrase('image_could_be_processed_try_another_contact_owner'), true);
}
// done in 2 loops as multiple items may point to same file
foreach ($outputFiles AS $sizeCode => $tempFile)
{
$this->_writeAvatar($userId, $sizeCode, $tempFile);
}
foreach ($outputFiles AS $tempFile)
{
if ($tempFile != $fileName)
{
@unlink($tempFile);
}
}
$dwData = array(
'avatar_date' => XenForo_Application::$time,
'avatar_width' => $width,
'avatar_height' => $height,
'avatar_crop_x' => $crop['x']['m'],
'avatar_crop_y' => $crop['y']['m'],
'gravatar' => '',
);
$dw = XenForo_DataWriter::create('XenForo_DataWriter_User');
$dw->setExistingData($userId);
$dw->bulkSet($dwData);
$dw->save();
return $dwData;
}
/**
* Re-crops an existing avatar with a square, starting at the specified coordinates
*
* @param integer $userId
* @param integer $x
* @param integer $y
*
* @return array Changed avatar fields
*/
public function recropAvatar($userId, $x, $y)
{
$sizeList = self::$_sizes;
// get rid of the first entry in the sizes array
list($largeSizeCode, $largeMaxDimensions) = each($sizeList);
$outputFiles = array();
$avatarFile = $this->getAvatarFilePath($userId, $largeSizeCode);
$imageInfo = getimagesize($avatarFile);
if (!$imageInfo)
{
throw new XenForo_Exception('Non-image passed in to recropAvatar');
}
$imageType = $imageInfo[2];
// now loop through the rest
while (list($sizeCode, $maxDimensions) = each($sizeList))
{
$image = XenForo_Image_Abstract::createFromFile($avatarFile, $imageType);
$image->thumbnailFixedShorterSide($maxDimensions);
if ($image->getOrientation() != XenForo_Image_Abstract::ORIENTATION_SQUARE)
{
$ratio = $maxDimensions / $sizeList['m'];
$xCrop = floor($ratio * $x);
$yCrop = floor($ratio * $y);
if ($image->getWidth() > $maxDimensions && $image->getWidth() - $xCrop < $maxDimensions)
{
$xCrop = $image->getWidth() - $maxDimensions;
}
if ($image->getHeight() > $maxDimensions && $image->getHeight() - $yCrop < $maxDimensions)
{
$yCrop = $image->getHeight() - $maxDimensions;
}
$image->crop($xCrop, $yCrop, $maxDimensions, $maxDimensions);
}
$newTempFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
$image->output($imageType, $newTempFile, self::$imageQuality);
unset($image);
$outputFiles[$sizeCode] = $newTempFile;
}
foreach ($outputFiles AS $sizeCode => $tempFile)
{
$this->_writeAvatar($userId, $sizeCode, $tempFile);
}
foreach ($outputFiles AS $tempFile)
{
@unlink($tempFile);
}
$dwData = array(
'avatar_date' => XenForo_Application::$time,
'avatar_crop_x' => $x,
'avatar_crop_y' => $y,
'gravatar' => '',
);
$dw = XenForo_DataWriter::create('XenForo_DataWriter_User');
$dw->setExistingData($userId);
$dw->bulkSet($dwData);
$dw->save();
return $dwData;
}
/**
* Writes out an avatar.
*
* @param integer $userId
* @param string $size Size code
* @param string $tempFile Temporary avatar file. Will be moved.
*
* @return boolean
*/
protected function _writeAvatar($userId, $size, $tempFile)
{
if (!in_array($size, array_keys(self::$_sizes)))
{
throw new XenForo_Exception('Invalid avatar size.');
}
$filePath = $this->getAvatarFilePath($userId, $size);
$directory = dirname($filePath);
if (XenForo_Helper_File::createDirectory($directory, true) && is_writable($directory))
{
if (file_exists($filePath))
{
@unlink($filePath);
}
return XenForo_Helper_File::safeRename($tempFile, $filePath);
}
else
{
return false;
}
}
/**
* Get the file path to an avatar.
*
* @param integer $userId
* @param string $size Size code
* @param string External data directory path (optional)
*
* @return string
*/
public function getAvatarFilePath($userId, $size, $externalDataPath = null)
{
if ($externalDataPath === null)
{
$externalDataPath = XenForo_Helper_File::getExternalDataPath();
}
return sprintf('%s/avatars/%s/%d/%d.jpg',
$externalDataPath,
$size,
floor($userId / 1000),
$userId
);
}
/**
* Deletes a user's avatar.
*
* @param integer $userId
* @param boolean $updateUser
*
* @return array Changed avatar fields
*/
public function deleteAvatar($userId, $updateUser = true)
{
foreach (array_keys(self::$_sizes) AS $size)
{
$filePath = $this->getAvatarFilePath($userId, $size);
if (file_exists($filePath) && is_writable($filePath))
{
@unlink($filePath);
}
}
$dwData = array(
'avatar_date' => 0,
'avatar_width' => 0,
'avatar_height' => 0,
'avatar_crop_x' => 0,
'avatar_crop_y' => 0,
'gravatar' => '',
);
if ($updateUser)
{
$dw = XenForo_DataWriter::create('XenForo_DataWriter_User', XenForo_DataWriter::ERROR_SILENT);
$dw->setExistingData($userId);
$dw->bulkSet($dwData);
$dw->save();
}
return $dwData;
}
/**
* Returns the _sizes array, defining what avatar sizes are available.
*
* @return array
*/
public static function getSizes()
{
return self::$_sizes;
}
/**
* Returns the maximum size (in pixels) of an avatar corresponding to the size code specified
*
* @param string $sizeCode (s,m,l)
*
* @return integer
*/
public static function getSizeFromCode($sizeCode)
{
return self::$_sizes[strtolower($sizeCode)];
}
/**
* Checks whether a Gravatar exists for a given email address
*
* @param string $email
*
* @return string|boolean Gravatar URL on success
*/
public static function gravatarExists($email, &$errorText = '', $size = 1, &$gravatarUrl = '')
{
if (!XenForo_Helper_Email::isEmailValid($email))
{
$errorText = new XenForo_Phrase('gravatars_require_valid_email_addresses');
return false;
}
try
{
$client = XenForo_Helper_Http::getClient(self::_getGravatarUrl($email, 1, 404), array(
'maxredirects' => 0,
'timeout' => 5
));
if ($client->request('HEAD')->getStatus() !== 200)
{
$errorText = new XenForo_Phrase('no_gravatar_found_for_specified_email_address');
return false;
}
}
catch (Exception $e)
{
if (strpos($e->getMessage(), 'Read timed out') === false)
{
// don't log timeouts - they're most likely on Gravatar's side
XenForo_Error::logException($e, false);
}
$errorText = new XenForo_Phrase('there_was_problem_communicating_with_gravatar');
return false;
}
$gravatarUrl = self::_getGravatarUrl($email, $size, false);
return true;
}
/**
* Builds a basic Gravatar URL for the given parameters
* @param string $email
* @param integer $size
* @param mixed $default
*
* @return string
*/
public static function _getGravatarUrl($email, $size, $default = false)
{
$md5 = md5(strtolower(trim($email)));
if (!empty($default))
{
$default = '&d=' . urlencode($default);
}
return (XenForo_Application::$secure ? 'https://secure' : 'http://www')
. ".gravatar.com/avatar/{$md5}?s={$size}{$default}";
}
}