This year for whatever reason, a lot of Souper Bowl of Caring participants' photos are being published sideways.

Thanks to a helpful article on StackOverflow I was able to fix it.

There are a few good answers, but the one I liked the most:
function image_fix_orientation(&$image, $filename) {
    $exif = exif_read_data($filename);

    if (!empty($exif['Orientation'])) {
        switch ($exif['Orientation']) {
            case 3:
                $image = imagerotate($image, 180, 0);
                break;

            case 6:
                $image = imagerotate($image, -90, 0);
                break;

            case 8:
                $image = imagerotate($image, 90, 0);
                break;
        }
    }
}


Re-factored a bit to work with the Image library, and we got:
/**
 * Examins the exif data for an image to try and detect if the orientation is incorrect. Fixes the image if necessary
 *
 * @param resource $image The image resource
 * @param string $filename The filename where the image is stored
 * @return bool|null True on success, false on failue, null on no change
 **/
	public static function fixOrientation($filename) {
		if (!is_file($filename)) {
			return false;
		}
		if (($size = getimagesize($filename)) === false) {
			return false;
		}
		if (empty($size['mime'])) {
			return false;
		}

		$image = self::createFromFile($filename);
		$exif = exif_read_data($filename);
		$angle = 0;

		if (!empty($exif['Orientation'])) {
			switch ($exif['Orientation']) {
				case 3:
					$angle = 180;
					break;
				case 6:
					$angle = -90;
					break;
				case 8:
					$angle = 90;
					break;
			}
		}
		if ($angle) {
			$image = imagerotate($image, $angle, 0);
			self::imageOutput($size['mime'], $image, $filename, 100);
			return true;
		}
		return null;
	}


If you run that on the $data['tmp_name'] when it's first detected, it works great.

Success!