Avatar.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. /**
  3. * Table Definition for avatar
  4. */
  5. require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
  6. class Avatar extends Managed_DataObject
  7. {
  8. ###START_AUTOCODE
  9. /* the code below is auto generated do not remove the above tag */
  10. public $__table = 'avatar'; // table name
  11. public $profile_id; // int(4) primary_key not_null
  12. public $original; // tinyint(1)
  13. public $width; // int(4) primary_key not_null
  14. public $height; // int(4) primary_key not_null
  15. public $mediatype; // varchar(32) not_null
  16. public $filename; // varchar(255)
  17. public $url; // varchar(255) unique_key
  18. public $created; // datetime() not_null
  19. public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
  20. /* the code above is auto generated do not remove the tag below */
  21. ###END_AUTOCODE
  22. public static function schemaDef()
  23. {
  24. return array(
  25. 'fields' => array(
  26. 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
  27. 'original' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'uploaded by user or generated?'),
  28. 'width' => array('type' => 'int', 'not null' => true, 'description' => 'image width'),
  29. 'height' => array('type' => 'int', 'not null' => true, 'description' => 'image height'),
  30. 'mediatype' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'file type'),
  31. 'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'local filename, if local'),
  32. 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'avatar location'),
  33. 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
  34. 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
  35. ),
  36. 'primary key' => array('profile_id', 'width', 'height'),
  37. 'unique keys' => array(
  38. 'avatar_url_key' => array('url'),
  39. ),
  40. 'foreign keys' => array(
  41. 'avatar_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
  42. ),
  43. 'indexes' => array(
  44. 'avatar_profile_id_idx' => array('profile_id'),
  45. ),
  46. );
  47. }
  48. // We clean up the file, too
  49. function delete($useWhere=false)
  50. {
  51. $filename = $this->filename;
  52. if (file_exists(Avatar::path($filename))) {
  53. @unlink(Avatar::path($filename));
  54. }
  55. return parent::delete($useWhere);
  56. }
  57. /*
  58. * Deletes all avatars (but may spare the original) from a profile.
  59. *
  60. * @param Profile $target The profile we're deleting avatars of.
  61. * @param boolean $original Whether original should be removed or not.
  62. */
  63. public static function deleteFromProfile(Profile $target, $original=true) {
  64. try {
  65. $avatars = self::getProfileAvatars($target);
  66. foreach ($avatars as $avatar) {
  67. if ($avatar->original && !$original) {
  68. continue;
  69. }
  70. $avatar->delete();
  71. }
  72. } catch (NoAvatarException $e) {
  73. // There are no avatars to delete, a sort of success.
  74. }
  75. return true;
  76. }
  77. static protected $_avatars = array();
  78. /*
  79. * Get an avatar by profile. Currently can't call newSize with $height
  80. */
  81. public static function byProfile(Profile $target, $width=null, $height=null)
  82. {
  83. $width = intval($width);
  84. $height = !is_null($height) ? intval($height) : null;
  85. if (is_null($height)) {
  86. $height = $width;
  87. }
  88. $size = "{$width}x{$height}";
  89. if (!isset(self::$_avatars[$target->id])) {
  90. self::$_avatars[$target->id] = array();
  91. } elseif (isset(self::$_avatars[$target->id][$size])){
  92. return self::$_avatars[$target->id][$size];
  93. }
  94. $avatar = null;
  95. if (Event::handle('StartProfileGetAvatar', array($target, $width, &$avatar))) {
  96. $avatar = self::pkeyGet(
  97. array(
  98. 'profile_id' => $target->id,
  99. 'width' => $width,
  100. 'height' => $height,
  101. )
  102. );
  103. Event::handle('EndProfileGetAvatar', array($target, $width, &$avatar));
  104. }
  105. if (is_null($avatar)) {
  106. // Obviously we can't find an avatar, so let's resize the original!
  107. $avatar = Avatar::newSize($target, $width);
  108. } elseif (!($avatar instanceof Avatar)) {
  109. throw new NoAvatarException($target, $avatar);
  110. }
  111. self::$_avatars[$target->id]["{$avatar->width}x{$avatar->height}"] = $avatar;
  112. return $avatar;
  113. }
  114. public static function getUploaded(Profile $target)
  115. {
  116. $avatar = new Avatar();
  117. $avatar->profile_id = $target->id;
  118. $avatar->original = true;
  119. if (!$avatar->find(true)) {
  120. throw new NoAvatarException($target, $avatar);
  121. }
  122. if (!file_exists(Avatar::path($avatar->filename))) {
  123. // The delete call may be odd for, say, unmounted filesystems
  124. // that cause a file to currently not exist, but actually it does...
  125. $avatar->delete();
  126. throw new NoAvatarException($target, $avatar);
  127. }
  128. return $avatar;
  129. }
  130. public static function getProfileAvatars(Profile $target) {
  131. $avatar = new Avatar();
  132. $avatar->profile_id = $target->id;
  133. if (!$avatar->find()) {
  134. throw new NoAvatarException($target, $avatar);
  135. }
  136. return $avatar->fetchAll();
  137. }
  138. /**
  139. * Where should the avatar go for this user?
  140. */
  141. static function filename($id, $extension, $size=null, $extra=null)
  142. {
  143. if ($size) {
  144. return $id . '-' . $size . (($extra) ? ('-' . $extra) : '') . $extension;
  145. } else {
  146. return $id . '-original' . (($extra) ? ('-' . $extra) : '') . $extension;
  147. }
  148. }
  149. static function path($filename)
  150. {
  151. $dir = common_config('avatar', 'dir');
  152. if ($dir[strlen($dir)-1] != '/') {
  153. $dir .= '/';
  154. }
  155. return $dir . $filename;
  156. }
  157. static function url($filename)
  158. {
  159. $path = common_config('avatar', 'path');
  160. if ($path[strlen($path)-1] != '/') {
  161. $path .= '/';
  162. }
  163. if ($path[0] != '/') {
  164. $path = '/'.$path;
  165. }
  166. $server = common_config('avatar', 'server');
  167. if (empty($server)) {
  168. $server = common_config('site', 'server');
  169. }
  170. $ssl = common_config('avatar', 'ssl');
  171. if (is_null($ssl)) { // null -> guess
  172. if (common_config('site', 'ssl') == 'always' &&
  173. !common_config('avatar', 'server')) {
  174. $ssl = true;
  175. } else {
  176. $ssl = false;
  177. }
  178. }
  179. $protocol = ($ssl) ? 'https' : 'http';
  180. return $protocol.'://'.$server.$path.$filename;
  181. }
  182. function displayUrl()
  183. {
  184. $server = common_config('avatar', 'server');
  185. if ($server && !empty($this->filename)) {
  186. return Avatar::url($this->filename);
  187. } else {
  188. return $this->url;
  189. }
  190. }
  191. static function urlByProfile(Profile $target, $width=null, $height=null) {
  192. try {
  193. return self::byProfile($target, $width, $height)->displayUrl();
  194. } catch (Exception $e) {
  195. return self::defaultImage($width);
  196. }
  197. }
  198. static function defaultImage($size)
  199. {
  200. static $sizenames = array(AVATAR_PROFILE_SIZE => 'profile',
  201. AVATAR_STREAM_SIZE => 'stream',
  202. AVATAR_MINI_SIZE => 'mini');
  203. return Theme::path('default-avatar-'.$sizenames[$size].'.png');
  204. }
  205. static function newSize(Profile $target, $width) {
  206. $width = intval($width);
  207. if ($width < 1 || $width > common_config('avatar', 'maxsize')) {
  208. // TRANS: An error message when avatar size is unreasonable
  209. throw new Exception(_m('Avatar size too large'));
  210. }
  211. $original = Avatar::getUploaded($target);
  212. $imagefile = new ImageFile($target->id, Avatar::path($original->filename));
  213. $filename = $imagefile->resize($width);
  214. $scaled = clone($original);
  215. $scaled->original = false;
  216. $scaled->width = $width;
  217. $scaled->height = $width;
  218. $scaled->url = Avatar::url($filename);
  219. $scaled->filename = $filename;
  220. $scaled->created = common_sql_now();
  221. if (!$scaled->insert()) {
  222. // TRANS: An error message when unable to insert avatar data into the db
  223. throw new Exception(_m('Could not insert new avatar data to database'));
  224. }
  225. // Return the new avatar object
  226. return $scaled;
  227. }
  228. }