<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	File: qa-include/qa-app-upload.php
	Description: Application-level file upload functionality


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

	if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
		header('Location: ../');
		exit;
	}


	function qa_get_max_upload_size()
/*
	Return the maximum size of file that can be uploaded, based on database and PHP limits
*/
	{
		if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

		$mindb = 16777215; // from MEDIUMBLOB column type

		$minphp = trim(ini_get('upload_max_filesize'));
		$minphp = convert_to_bytes(substr($minphp, -1), $minphp);

		return min($mindb, $minphp);
	}


	function qa_upload_file($localfilename, $sourcefilename, $maxfilesize=null, $onlyimage=false, $imagemaxwidth=null, $imagemaxheight=null)
/*
	Move an uploaded image or other file into blob storage. Pass the $localfilename where the file is currently stored
	(temporarily) and the $sourcefilename of the file on the user's computer (if using PHP's usual file upload
	mechanism, these are obtained from $_FILES[..]['tmp_name'] and $_FILES[..]['name'] fields respectively). To apply a
	maximum file size (in bytes) beyond the general one, use $maxfilesize, otherwise set it to null. Set $onlyimage to
	true if only image uploads (PNG, GIF, JPEG) are allowed. To apply a maximum width or height (in pixels) to uploaded
	images, set $imagemaxwidth and $imagemaxheight. The function returns an array which may contain the following elements:

	'error' => a string containing an error, if one occurred
	'format' => the format (file extension) of the blob created (all scaled images end up as 'jpeg')
	'width' => if an image, the width in pixels of the blob created (after possible scaling)
	'height' => if an image, the height in pixels of the blob created (after possible scaling)
	'blobid' => the blobid that was created (if there was no error)
	'bloburl' => the url that can be used to view/download the created blob (if there was no error)
*/
	{
		if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

		$result=array();

	//	Check per-user upload limits

		require_once QA_INCLUDE_DIR.'app/users.php';
		require_once QA_INCLUDE_DIR.'app/limits.php';

		switch (qa_user_permit_error(null, QA_LIMIT_UPLOADS))
		{
			case 'limit':
				$result['error']=qa_lang('main/upload_limit');
				return $result;

			case false:
				qa_limits_increment(qa_get_logged_in_userid(), QA_LIMIT_UPLOADS);
				break;

			default:
				$result['error']=qa_lang('users/no_permission');
				return $result;
		}

	//	Check the uploaded file is not too large

		$filesize=filesize($localfilename);
		if (isset($maxfilesize))
			$maxfilesize=min($maxfilesize, qa_get_max_upload_size());
		else
			$maxfilesize=qa_get_max_upload_size();

		if ( ($filesize<=0) || ($filesize>$maxfilesize) ) { // if file was too big for PHP, $filesize will be zero
			$result['error']=qa_lang_sub('main/max_upload_size_x', qa_format_number($maxfilesize/1048576, 1).'MB');
			return $result;
		}

	//	Find out what type of source file was uploaded and if appropriate, check it's an image and get preliminary size measure

		$pathinfo=pathinfo($sourcefilename);
		$format=strtolower(@$pathinfo['extension']);
		$isimage=($format=='png') || ($format=='gif') || ($format=='jpeg') || ($format=='jpg'); // allowed image extensions

		if ($isimage) {
			$imagesize=@getimagesize($localfilename);

			if (is_array($imagesize)) {
				$result['width']=$imagesize[0];
				$result['height']=$imagesize[1];

				switch ($imagesize['2']) { // reassign format based on actual content, if we can
					case IMAGETYPE_GIF:
						$format='gif';
						break;

					case IMAGETYPE_JPEG:
						$format='jpeg';
						break;

					case IMAGETYPE_PNG:
						$format='png';
						break;
				}
			}
		}

		$result['format']=$format;

		if ($onlyimage)
			if ( (!$isimage) || !is_array($imagesize) ) {
				$result['error']=qa_lang_sub('main/image_not_read', 'GIF, JPG, PNG');
				return $result;
			}

	//	Read in the raw file contents

		$content=file_get_contents($localfilename);

	//	If appropriate, get more accurate image size and apply constraints to it

		require_once QA_INCLUDE_DIR.'util/image.php';

		if ($isimage && qa_has_gd_image()) {
			$image=@imagecreatefromstring($content);

			if (is_resource($image)) {
				$result['width']=$width=imagesx($image);
				$result['height']=$height=imagesy($image);

				if (isset($imagemaxwidth) || isset($imagemaxheight))
					if (qa_image_constrain(
						$width, $height,
						isset($imagemaxwidth) ? $imagemaxwidth : $width,
						isset($imagemaxheight) ? $imagemaxheight : $height
					)) {
						qa_gd_image_resize($image, $width, $height);

						if (is_resource($image)) {
							$content=qa_gd_image_jpeg($image);
							$result['format']=$format='jpeg';
							$result['width']=$width;
							$result['height']=$height;
						}
					}

				if (is_resource($image)) // might have been lost
					imagedestroy($image);
			}
		}

	//	Create the blob and return

		require_once QA_INCLUDE_DIR.'app/blobs.php';

		$userid=qa_get_logged_in_userid();
		$cookieid=isset($userid) ? qa_cookie_get() : qa_cookie_get_create();
		$result['blobid']=qa_create_blob($content, $format, $sourcefilename, $userid, $cookieid, qa_remote_ip_address());

		if (!isset($result['blobid'])) {
			$result['error']=qa_lang('main/general_error');
			return $result;
		}

		$result['bloburl']=qa_get_blob_url($result['blobid'], true);

		return $result;
	}


	function qa_upload_file_one($maxfilesize=null, $onlyimage=false, $imagemaxwidth=null, $imagemaxheight=null)
/*
	In response to a file upload, move the first uploaded file into blob storage. Other parameters are as for qa_upload_file(...)
*/
	{
		$file=reset($_FILES);

		return qa_upload_file($file['tmp_name'], $file['name'], $maxfilesize, $onlyimage, $imagemaxwidth, $imagemaxheight);
	}


/*
	Omit PHP closing tag to help avoid accidental output
*/