self::MAXFILESIZE) { return self::ERROR_FILETOOBIG; } $dimensions = getimagesize($filesArrayElement['tmp_name']); $width = $dimensions[0]; $height = $dimensions[1]; // Big Enough? if ($width < self::MINWIDTH || $height < self::MINHEIGHT) { return self::ERROR_IMAGETOOSMALL; } // Too Big? $area = $width * $height; if ($area > self::MAXPIXELAREA) { return self::ERROR_IMAGETOOBIG; } return false; } /** * Replaces a user's avatar with the specified image * * @param int $userID The user whose avatar is being updated * @param array $filesArrayElement A member of the $_FILES array containing the new avatar image * @throws InvalidArgumentException */ public static function updateFromUploadedFile($userID, $filesArrayElement) { // Validate UserID if (!(filter_var($userID, FILTER_VALIDATE_INT) > 0)) { throw new \InvalidArgumentException("User id is invalid: $userID"); } // Validate File if (self::errorCheckUploadedFile($filesArrayElement)) { throw new \InvalidArgumentException("File error check failed. Error check file for more details."); } // Remember the previous avatar files so we can delete them once the new avatar files are activated $oldFiles = query("SELECT smImageName, smImageName64, smImageName128 FROM tig.Users WHERE UserID = " . mysqlescape($userID)); // Allow extra memory for memory-intensive image processing $oldMemoryLimit = ini_set('memory_limit', self::MEMORYLIMIT); // Resize the images $filename32 = self::createLocalFile($filesArrayElement, $userID, 32); $filename64 = self::createLocalFile($filesArrayElement, $userID, 64); $filename128 = self::createLocalFile($filesArrayElement, $userID, 128); // Restore original memory limit now that image processing is done ini_set('memory_limit', $oldMemoryLimit); // Looking at "members/avatar/index.html", it doesn't appear that the // CDN is even used. In case it is in some way I don't realize, // the avatar images are copied there. self::createCdnFile($filename32); self::createCdnFile($filename64); self::createCdnFile($filename128); // Activate the new avatars in the database safe_dbwrite("UPDATE tig.Users SET smImageName = '$filename32', smImageName64 = '$filename64', smImageName128 = '$filename128' WHERE UserID = " . mysqlescape($userID)); // Activate the new avatars in the $TIGUserInfo cookie - I don't know // where this info is used but avatarupload.html does this so it's // included here. global $TIGUserInfo; $TIGUserInfo['smImageName'] = $filename32; $TIGUserInfo['smImageName64'] = $filename64; $TIGUserInfo['smImageName128'] = $filename128; setcookie("TIGUserInfo", serialize($TIGUserInfo), "0", "/", ".tigweb.org"); // Delete Obsolete Avatars - If there were previous avatar files and // their names have changed (meaning the old avatars were not // simply overwritten), then delete the previous files. if ($oldFiles['smImageName'] && $filename32 != $oldFiles['smImageName']) { self::deleteLocalFile($oldFiles['smImageName']); self::deleteCdnFile($oldFiles['smImageName']); } if ($oldFiles['smImageName64'] && $filename64 != $oldFiles['smImageName64']) { self::deleteLocalFile($oldFiles['smImageName64']); self::deleteCdnFile($oldFiles['smImageName64']); } if ($oldFiles['smImageName128'] && $filename128 != $oldFiles['smImageName128']) { self::deleteLocalFile($oldFiles['smImageName128']); self::deleteCdnFile($oldFiles['smImageName128']); } // Add "Jeff changed his avatar" to Feeds add2bb($userID, 75, "{$TIGUserInfo['Username']}|"); } /** * Saves a square avatar image file * * @param $filesArrayElement A member of $_FILES * @param int $userID The user the avatar is for. Ex. 654811 * @param int $size The side length of the square avatar image to create. Ex. 32 * @return string The name of the file created */ private static function createLocalFile($filesArrayElement, $userID, $size) { $extension = pathinfo($filesArrayElement['name'], PATHINFO_EXTENSION); // Ex. "654811_32.jpg" $filename = "{$userID}_{$size}.{$extension}"; $imageManipulator = new \Zebra_Image(); $imageManipulator->source_path = $filesArrayElement['tmp_name']; $imageManipulator->target_path = IMAGEROOT . self::IMAGEFOLDER . $filename; $imageManipulator->resize($size, $size, ZEBRA_IMAGE_CROP_CENTER); return $filename; } /** * Permanently erases a avatar file stored on the server * * @param string $filename The local avatar file to delete. ex. 654811_32.jpg */ private static function deleteLocalFile($filename) { $filePath = IMAGEROOT . self::IMAGEFOLDER . $filename; if (is_file($filePath)) { unlink($filePath); } } /** * Copies local avatar images to Cloud Files * * @param string $filename The local filename * @throws InvalidArgumentException */ private static function createCdnFile($filename) { $filePath = IMAGEROOT . self::IMAGEFOLDER . $filename; if (!is_file($filePath)) { throw new \InvalidArgumentException('Source file not found'); } $container = self::getCloudFilesContainer(); $image = $container->create_object($filename); $image->load_from_filename(IMAGEROOT . self::IMAGEFOLDER . $filename); $container->make_public(3600); } /** * Reomves and avatar image from Cloud Files * * @param string $filename The local filename * @throws InvalidArgumentException */ private static function deleteCdnFile($filename) { $container = self::getCloudFilesContainer(); try { $container->delete_object($filename); } catch (NoSuchObjectExceptionException $ex) { // do nothing - it doesn't matter whether the file was deleted or not there in the beginning } } /** * Connects to Rackspace Cloud Files to manipulate photos * * @return CF_Container Connection to the Rackspace container containing avatars */ private static function getCloudFilesContainer() { if (!self::$cloudFilesContainer) { $auth = new \CF_Authentication(self::CDNUSERNAME, self::CDNAPIKEY); $auth->authenticate(); $connection = new \CF_Connection($auth); self::$cloudFilesContainer = $connection->get_container(self::CDNCONTAINER); } return self::$cloudFilesContainer; } }