<?php
/**
* @version	$Id: file_helper.php 14241 2011-03-16 20:24:35Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class FileHelper extends kHelper {

		/**
		 * Puts existing item images (from subitem) to virtual fields (in main item)
		 *
		 * @param kCatDBItem $object
		 */
		function LoadItemFiles(&$object)
		{
			$max_file_count = $this->Application->ConfigValue($object->Prefix.'_MaxImageCount'); // file count equals to image count (temporary measure)

			$sql = 'SELECT *
					FROM '.TABLE_PREFIX.'ItemFiles
					WHERE ResourceId = '.$object->GetDBField('ResourceId').'
					ORDER BY FileId ASC
					LIMIT 0, '.(int)$max_file_count;
			$item_files = $this->Conn->Query($sql);

			$file_counter = 1;
			foreach ($item_files as $item_file) {
				$file_path = $item_file['FilePath'];
				$object->SetDBField('File'.$file_counter, $file_path);
				$object->SetOriginalField('File'.$file_counter, $file_path);
				$object->Fields['File'.$file_counter]['original_field'] = $item_file['FileName'];
				$file_counter++;
			}
		}

		/**
		 * Saves newly uploaded images to external image table
		 *
		 * @param kCatDBItem $object
		 */
		function SaveItemFiles(&$object)
		{
			$table_name = $this->Application->getUnitOption('#file', 'TableName');
			$max_file_count = $this->Application->getUnitOption($object->Prefix, 'FileCount'); // $this->Application->ConfigValue($object->Prefix.'_MaxImageCount');

			$this->CheckFolder(FULL_PATH . ITEM_FILES_PATH);

			$i = 0;
			while ($i < $max_file_count) {
				$field = 'File'.($i + 1);
				$field_options = $object->GetFieldOptions($field);

				$file_path = $object->GetDBField($field);
				if ($file_path) {
					if (isset($field_options['original_field'])) {
						$key_clause = 'FileName = '.$this->Conn->qstr($field_options['original_field']).' AND ResourceId = '.$object->GetDBField('ResourceId');

						if ($object->GetDBField('Delete'.$field)) {
							// if item was cloned, then new filename is in db (not in $image_src)
							$sql = 'SELECT FilePath
									FROM '.$table_name.'
									WHERE '.$key_clause;
							$file_path = $this->Conn->GetOne($sql);
							if (@unlink(FULL_PATH.ITEM_FILES_PATH.$file_path)) {
								$sql = 'DELETE FROM '.$table_name.'
										WHERE '.$key_clause;
								$this->Conn->Query($sql);
							}
						}
						else {
							// image record found -> update
							$fields_hash = Array (
								'FilePath' => $file_path,
							);

							$this->Conn->doUpdate($fields_hash, $table_name, $key_clause);
						}
					}
					else {
						// record not found -> create
						$fields_hash = Array (
							'ResourceId' => $object->GetDBField('ResourceId'),
							'FileName' => $field,
							'Status' => STATUS_ACTIVE,
							'FilePath' => $file_path,
						);

						$this->Conn->doInsert($fields_hash, $table_name);
						$field_options['original_field'] = $field;
						$object->SetFieldOptions($field, $field_options);
					}
				}
				$i++;
			}
		}

		/**
		 * Preserves cloned item images/files to be rewrited with original item images/files
		 *
		 * @param Array $field_values
		 */
		function PreserveItemFiles(&$field_values)
		{
			foreach ($field_values as $field_name => $field_value) {
				if (!is_array($field_value)) continue;

				if (isset($field_value['upload']) && ($field_value['error'] == UPLOAD_ERR_NO_FILE)) {
					// this is upload field, but nothing was uploaded this time
					unset($field_values[$field_name]);
				}
			}
		}

		/**
		 * Determines what image/file fields should be created (from post or just dummy fields for 1st upload)
		 *
		 * @param string $prefix
		 * @param bool $is_image
		 */
		function createItemFiles($prefix, $is_image = false)
		{
			$items_info = $this->Application->GetVar($prefix);
			if ($items_info) {
				list ($id, $fields_values) = each($items_info);
				$this->createUploadFields($prefix, $fields_values, $is_image);
			}
			else {
				$this->createUploadFields($prefix, Array(), $is_image);
			}
		}

		/**
		 * Dynamically creates virtual fields for item for each image/file field in submit
		 *
		 * @param string $prefix
		 * @param Array $fields_values
		 * @param bool $is_image
		 */
		function createUploadFields($prefix, $fields_values, $is_image = false)
		{
			$field_options = Array (
				'type'			=>	'string',
				'max_len'		=>	240,
				'default'		=>	'',
			);

			if ($is_image) {
				$field_options['formatter'] = 'kPictureFormatter';
				$field_options['include_path'] = 1;
				$field_options['allowed_types'] = Array ('image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/gif', 'image/bmp');
				$field_prefix = 'Image';
			}
			else {
				$field_options['formatter'] = 'kUploadFormatter';
				$field_options['upload_dir'] = ITEM_FILES_PATH;
				$field_options['allowed_types'] = Array ('application/pdf', 'application/msexcel', 'application/msword', 'application/mspowerpoint');
				$field_prefix = 'File';
			}

			$fields = $this->Application->getUnitOption($prefix, 'Fields');
			$virtual_fields = $this->Application->getUnitOption($prefix, 'VirtualFields');

			$image_count = 0;
			foreach ($fields_values as $field_name => $field_value) {
				if (preg_match('/^('.$field_prefix.'[\d]+|Primary'.$field_prefix.')$/', $field_name)) {
					$fields[$field_name] = $field_options;
					$virtual_fields[$field_name] = $field_options;
					$this->_createCustomFields($prefix, $field_name, $virtual_fields, $is_image);

					$image_count++;
				}
			}

			if (!$image_count) {
				// no images found in POST -> create default image fields
				$image_count = $this->Application->ConfigValue($prefix.'_MaxImageCount');

				if ($is_image) {
					$created_count = 1;
					$image_names = Array ('Primary' . $field_prefix => '');

					while ($created_count < $image_count) {
						$image_names[$field_prefix . $created_count] = '';
						$created_count++;
					}
				}
				else {
					$created_count = 0;
					$image_names = Array ();

					while ($created_count < $image_count) {
						$image_names[$field_prefix . ($created_count + 1)] = '';
						$created_count++;
					}
				}

				$this->createUploadFields($prefix, $image_names, $is_image);
				return ;
			}

			$this->Application->setUnitOption($prefix, $field_prefix.'Count', $image_count);
			$this->Application->setUnitOption($prefix, 'Fields', $fields);
			$this->Application->setUnitOption($prefix, 'VirtualFields', $virtual_fields);
		}

		/**
		 * Adds ability to create more virtual fields associated with main image/file
		 *
		 * @param string $prefix
		 * @param string $field_name
		 * @param Array $virtual_fields
		 */
		function _createCustomFields($prefix, $field_name, &$virtual_fields, $is_image)
		{
			$virtual_fields['Delete' . $field_name] = Array ('type' => 'int', 'default' => 0);

			if ($is_image) {
				$virtual_fields[$field_name . 'Alt'] = Array ('type' => 'string', 'default' => '');
			}
		}

		/**
		 * Downloads file to user
		 *
		 * @param string $filename
		 */
		function DownloadFile($filename)
		{
			$content_type = function_exists('mime_content_type') ? mime_content_type($filename) : 'application/octet-stream';

			header('Content-type: '.$content_type);
			header('Content-Disposition: attachment; filename="'.basename($filename).'"');
			header('Content-Length: '.filesize($filename));
			readfile($filename);
			flush();
		}

		/**
		 * Creates folder with given $path
		 *
		 * @param string $path
		 * @return bool
		 */
		function CheckFolder($path)
		{
			$result = true;

			if (!file_exists($path) || !is_dir($path)) {
				$parent_path = preg_replace('#/[^/]+/?$#', '', $path);
				$result = $this->CheckFolder($parent_path);

				if ($result) {
					$result = mkdir($path);

					if ($result) {
						chmod($path, 0777);

						// don't commit any files from created folder
						if (file_exists(FULL_PATH . '/CVS')) {
							$cvsignore = fopen($path . '/.cvsignore', 'w');
							fwrite($cvsignore, '*.*');
							fclose($cvsignore);
							chmod($path . '/.cvsignore', 0777);
						}
					}
					else {
						trigger_error('Cannot create directory "<strong>' . $path . '</strong>"', E_USER_WARNING);
						return false;
					}
				}
			}

			return $result;
		}

		/**
		 * Copies all files and directories from $source to $destination directory. Create destination directory, when missing.
		 *
		 * @param string $source
		 * @param string $destination
		 * @return bool
		 */
		function copyFolderRecursive($source, $destination)
		{
			if ( substr($source, -1) == DIRECTORY_SEPARATOR ) {
				$source = substr($source, 0, -1);
				$destination .= DIRECTORY_SEPARATOR . basename($source);
			}

			$dir = opendir($source);
			$result = $this->CheckFolder($destination);

			if (!$result || !is_resource($dir)) {
				// failed to create target directory OR failed to open source directory
				return false;
			}

			while ( false !== ($file = readdir($dir)) ) {
				if ($file == '.' || $file == '..') {
					continue;
				}

				if ( is_dir($source . DIRECTORY_SEPARATOR . $file) ) {
					$result = $this->copyFolderRecursive($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file);
				}
				else {
					$result = copy($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file);
				}

				if (!$result) {
					trigger_error('Cannot create file/directory "<strong>' . $destination . DIRECTORY_SEPARATOR . $file . '</strong>"', E_USER_WARNING);
					break;
				}
			}

			closedir($dir);

			return $result;
		}

		/**
		 * Copies all files from $source to $destination directory. Create destination directory, when missing.
		 *
		 * @param string $source
		 * @param string $destination
		 * @return bool
		 */
		function copyFolder($source, $destination)
		{
			if ( substr($source, -1) == DIRECTORY_SEPARATOR ) {
				$source = substr($source, 0, -1);
				$destination .= DIRECTORY_SEPARATOR . basename($source);
			}

			$dir = opendir($source);
			$result = $this->CheckFolder($destination);

			if (!$result || !is_resource($dir)) {
				// failed to create target directory OR failed to open source directory
				return false;
			}

			while ( false !== ($file = readdir($dir)) ) {
				if ($file == '.' || $file == '..' || !is_file($source . DIRECTORY_SEPARATOR . $file)) {
					continue;
				}

				$result = copy($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file);

				if (!$result) {
					trigger_error('Cannot create file "<strong>' . $destination . DIRECTORY_SEPARATOR . $file . '</strong>"', E_USER_WARNING);
					break;
				}
			}

			closedir($dir);

			return $result;
		}

		/**
		 * Transforms given path to file into it's url, where each each component is encoded (excluding domain and protocol)
		 *
		 * @param string $url
		 * @return string
		 */
		function pathToUrl($url)
		{
			$url = str_replace(DIRECTORY_SEPARATOR, '/', preg_replace('/^' . preg_quote(FULL_PATH, '/') . '(.*)/', '\\1', $url, 1));
			$url = implode('/', array_map('rawurlencode', explode('/', $url)));

			return rtrim($this->Application->BaseURL(), '/') . $url;
		}

		/**
		 * Transforms given url to path to it
		 *
		 * @param string $url
		 * @return string
		 */
		function urlToPath($url)
		{
			$base_url = rtrim($this->Application->BaseURL(), '/');
			$path = preg_replace('/^' . preg_quote($base_url, '/') . '(.*)/', FULL_PATH . '\\1', $url);

			return str_replace('/', DIRECTORY_SEPARATOR, rawurldecode($path));
		}
	}