<?php
/* wppa-upload-common.php
* Package: wp-photo-album-plus
*
* Contains common upload functions
* Version 7.6.07.008
*
*/

// Upload a single item; an element form $_FILES
// @1: Array( 'name'     => the original filename
// 			  'tmp_name' => the path to the just uploaded file or a file somewhere else in the filesystem
// 			  'error' 	 => error code )
// @2: Text: 'upload', 'front', 'import'
function wppa_upload_one_item( $file, $album, $from = '' ) {
global $wpdb;
global $wppa_supported_photo_extensions;
global $wppa_supported_video_extensions;
global $wppa_supported_audio_extensions;
global $wppa_supported_document_extensions;

	// Check arg
	if ( ! is_array( $file ) ) {
		wppa_upload_common_error( __( 'Unexpected internal error in wppa_upload_one_item()', 'wp-photo-album-plus' ), $from );
		return false;
	}

	// Check on upload error
	if ( $file['error'] ) {
		wppa_upload_common_error( __( 'Upload error', 'wp-photo-album-plus' ) . ': ' . $file['error'], $from );
		return false;
	}

	// Save some data and sanitize som data
	wppa( 'unsanitized_filename', $file['name'] );
	$file['name'] = wppa_down_ext( $file['name'] );
	$file['name'] = wppa_sanitize_album_photo_name( $file['name'] );

	// Test if we try to upload a supported filetype
	$supp = wppa_get_supported_extensions();

	$the_type = wppa_get_ext( $file['name'] );
	if ( ! in_array( $the_type, $supp ) ) {
		wppa_upload_common_error( __( 'Invalid file-extension found during upload. Supported filetypes are', 'wp-photo-album-plus' ) . ': ' . implode( ', ', $supp ), $from );
		return false;;
	}

	// See if this filename (except extension) already exists in this album
	$ext_type = '';
	$ext_id = wppa_is_file_alias( $file['name'], $album );

	if ( $ext_id ) {
		$ext_ext = wppa_get_ext( wppa_get_photo_item( $ext_id, 'filename' ) );
		if ( wppa_is_video( $ext_id ) ) {
			$ext_type = 'video';
		}
		elseif ( wppa_has_audio( $ext_id ) ) {
			$ext_type = 'audio';
		}
		elseif ( wppa_is_pdf( $ext_id ) ) {
			$ext_type = 'document';
		}
		elseif ( in_array( $ext_ext, array( 'jpg', 'jpeg', 'png', 'gif' ) ) ) {
			$ext_type = 'image';
		}
		else {
			$ext_type = 'unknown';
		}
	}

	if ( in_array( $the_type, $wppa_supported_video_extensions ) ) {
		$new_type = 'video';
	}
	elseif ( in_array( $the_type, $wppa_supported_audio_extensions ) ) {
		$new_type = 'audio';
	}
	elseif ( in_array( $the_type, $wppa_supported_document_extensions ) ) {
		$new_type = 'document';
	}
	elseif ( in_array( $the_type, array( 'jpg', 'jpeg', 'png', 'gif' ) ) ) {
		$new_type = 'image';
	}
	else {
		$new_type = 'unknown';
	}

	// Cheack against incompatible combinations
	$cerr = false;
	if ( $ext_type == 'video' && $new_type == 'audio' || $ext_type == 'audio' && $new_type == 'video' ) {
		$cerr = true;
	}
	elseif ( $ext_type == 'video' && $new_type == 'document' || $ext_type == 'document' && $new_type == 'video' ) {
		$cerr = true;
	}
	elseif ( $ext_type == 'audio' && $new_type == 'document' || $ext_type == 'document' && $new_type == 'audio' ) {
		$cerr = true;
	}
	elseif ( $ext_type == 'audio' && $new_type == 'document' || $ext_type == 'document' && $new_type == 'audio' ) {
		$cerr = true;
	}
	elseif ( $ext_type == 'video' && $new_type == 'document' || $ext_type == 'document' && $new_type == 'video' ) {
		$cerr = true;
	}
	if ( $cerr ) {
		wppa_upload_common_error( sprintf( __( 'You can not combine %s with %s files', 'wp-photo-album-plus' ), $ext_type, $new_type ), $from );
		return false;;
	}

	// Check against duplicate files
	if ( $new_type == 'image' || $new_type == 'document' ) {
		if ( $ext_type == $new_type ) {
			if ( wppa_switch( 'void_dups' ) ) {
				wppa_upload_common_ok( sprintf( __( 'Item %s already exists in this album and will be overwritten', 'wp-photo-album-plus' ), $file['name'] ), $from );
			}
			else {

				// Forget its a dup
				$ext_type 	= '';
				$ext_id 	= false;
			}
		}
	}

	// Dispatch on filetype
	switch ( $the_type ) {

		case 'pdf':

			// If image already exists, just add the pdf and set the file extension right
			if ( $ext_id ) {
				wppa_copy( $file['tmp_name'], wppa_get_source_album_dir( $album ) . '/' . $file['name'] );
				wppa_update_photo( array( 'id' 			=> $ext_id,
										  'filename' 	=> wppa_strip_ext( $file['name'] ) . '.pdf',
										  ) );
				wppa_upload_post_process( $the_type, $album, $ext_id, $from );
				return true;;
			}

			// Assume poster image will be creted  by imagick or uploaded, so set ext to jpg. wppa_is_pdf looks at filename extension.
			if ( file_exists( $file['tmp_name'] ) ) {
				$id = wppa_create_photo_entry( array( 	'album' 	=> $album,
														'ext' 		=> 'jpg',
														'name' 		=> $file['name'],
														'filename' 	=> wppa_strip_ext( $file['name'] ) . '.pdf',
														'sname' 	=> $file['name'],
													) );

				wppa_copy( $file['tmp_name'], wppa_get_source_album_dir( $album ) . '/' . wppa_strip_ext( $file['name'] ) . '.pdf' );

				// Make the photo files will creatre poster .jpg if imagick is active
				wppa_make_the_photo_files( wppa_get_source_album_dir( $album ) . '/' . wppa_strip_ext( $file['name'] ) . '.pdf', $id, 'pdf' );
			}

			wppa_upload_post_process( $the_type, $album, $id, $from );
			return true;; // Yes we uploaded a file
			break;

		case 'jpg':
		case 'jpeg':
		case 'png':
		case 'gif':

			// Process posterfile or update existing image file (dups not allowed)
			if ( $ext_type == 'video' || $ext_type == 'audio' || $ext_type == 'document' || $ext_type == $new_type ) {
				wppa_log( 'dbg', 'Updating ' . $ext_id . ', ' . $file['name'] . ' ' . $ext_type . ' with ' . $the_type );
				wppa_move_uploaded_file( $file['tmp_name'], wppa_get_source_album_dir( $album ) . '/' . $file['name'] );
				if ( $ext_type == 'document' ) {
					wppa_update_photo( array( 'id' => $ext_id, 'ext' => $the_type ) );
				}
				wppa_cache_photo( 'invalidate', $ext_id );
				wppa_make_the_photo_files( wppa_get_source_album_dir( $album ) . '/' . $file['name'], $ext_id, wppa_get_ext( $file['name'] ) );
				wppa_upload_post_process( $the_type, $album, $ext_id, $from );
				return true;; // Yes we uploaded a file
			}

			// Just a photo
			$id = wppa_insert_photo( $file['tmp_name'], $album, $file['name'] );
			if ( $id ) {
				wppa_upload_post_process( $the_type, $album, $id, $from );
				return true;; // Yes we uploaded a file
			}
			else {
				wppa_upload_common_error( __( 'Error inserting photo' , 'wp-photo-album-plus') . ' ' . wppa_sanitize_file_name( basename( $file['name'] ) ) . '.', $from );
				return false;; // No we did not uploaded a file
			}
			break;

		case 'mp4':
		case 'ogv':
		case 'webm':
		case 'mp3':
		case 'wav':
		case 'ogg':

			// Add new entry
			if ( ! $ext_id ) {
				$id = wppa_create_photo_entry( array( 'album' => $album, 'filename' => $file['name'], 'ext' => 'xxx', 'name' => wppa_strip_ext( $file['name'] ) ) );
			}
			else {
				$id = $ext_id;
			}

			// Add file
			$newpath = wppa_strip_ext( wppa_get_photo_path( $id, false ) ) . '.' . $the_type;
			$fs = filesize( $file['tmp_name'] );
			if ( $fs > 1024*1024*64 ) {	// copy fails for files > 64 Mb

				// Remove old version if already exists
				if ( wppa_is_file( $newpath ) ) {
					wppa_unlink( $newpath );
				}
				wppa_rename( $file['tmp_name'], $newpath );
			}
			else {
				wppa_copy( $file['tmp_name'], $newpath );
			}

			// Make sure ext is set to xxx after adding audio or video
			wppa_update_photo( array( 'id' 			=> $id,
									  'filename' 	=> wppa_strip_ext( $file['name'] ) . '.xxx',
									  'ext' 		=> 'xxx',
									  ) );
			wppa_upload_post_process( $the_type, $album, $id, $from );
			return true; // Yes we uploaded a file
			break;

		case 'zip':

			$zipfile = WPPA_DEPOT_PATH . '/' . wppa_sanitize_file_name( $file['name'] );
			wppa_copy( $file['tmp_name'], $zipfile );

			$zip = new ZipArchive;

			if ( $zip->open( $zipfile ) === true ) {

				$done = '0';
				$skip = '0';
				for ( $i = 0; $i < $zip->numFiles; $i++ ) {

					$stat = $zip->statIndex( $i );
					/* statIndex returns:
					Array
					(
						[name] => foobar/baz
						[index] => 3
						[crc] => 499465816
						[size] => 27
						[mtime] => 1123164748
						[comp_size] => 24
						[comp_method] => 8
					)
					*/
					$file_ext = @ strtolower( end( explode( '.', $stat['name'] ) ) );

					if ( in_array( $file_ext, $supp ) ) {
						$zip->extractTo( WPPA_UPLOAD_PATH . '/temp/', $stat['name'] );

						// Find out if the file is ment for a sub(sub)album
						$p = $album;
						if ( strpos( $stat['name'], '/' ) !== false ) {
							$fullname = $stat['name'];
							$names = explode( '/', $fullname );
							$i = 0;

							while ( $i < count( $names ) -1 ) {

								// Find album with parent is current and name is subalbum name
								$a = $wpdb->get_var( $wpdb->prepare( "SELECT id
																	  FROM $wpdb->wppa_albums
																	  WHERE name = %s
																	  AND a_parent = %d
																	  LIMIT 1", $names[$i], $p ) );

								// If not found, create it
								if ( ! $a ) {
									$a = wppa_create_album_entry( array( 'name' => $names[$i],
																		 'a_parent' => $p,
																		 ) );
								}

								$p = $a;
								$i++;
							}
						}

						// Recursively call wppa_upload_one_item()
						$zfile = array( 'tmp_name' 	=> WPPA_UPLOAD_PATH . '/temp/' . $stat['name'],
										'name' 		=> sanitize_file_name( basename( $stat['name'] ) ),
										'error' 	=> 0,
										);
						$iret = wppa_upload_one_item( $zfile, $p, $from );
						if ( $iret ) {
							$done++;
						}
						else {
							$skip++;
						}
						wppa_unlink( WPPA_UPLOAD_PATH . '/temp/' . $stat['name'] );
					}

					// Assuming that entries without a file extension are directries. No warning on directory.
					elseif ( strpos( $stat['name'], '.' ) !== false && strlen( $file_ext ) < 5 ) {
						wppa_upload_common_error( sprintf( __( 'File %s is of an unsupported filetype and has been ignored during extraction.', 'wp-photo-album-plus'), wppa_sanitize_file_name( $stat['name'] ) ), $from );
						$skip++;
					}
				}

				$zip->close();
				wppa_upload_common_ok( sprintf( __( 'Zipfile %s processed. %s files extracted, %s files skipped.', 'wp-photo-album-plus'), basename( $zipfile ), $done, $skip ), $from );

				wppa_unlink( $zipfile );
				return true;; // Yes we uploaded a file
			}

			// Zipfile can not be opened
			else {
				wppa_upload_common_error( __( 'Failed to extract', 'wp-photo-album-plus').' '.$zipfile, $from );
				wppa_unlink( $zipfile );
				return false;;
			}
			break;

		default:
			wppa_upload_common_error( __( 'Unsupported filetype encountered', 'wp-photo-album-plus' ) . ': ' . $the_type, $from );
			return false;; // No we did not uploaded a file
	}
}

function wppa_upload_common_error( $error, $from = '' ) {

	switch( $from ) {
		case 'upload':
			wppa_error_message( $error );
			break;
		default:
			wppa_log( 'err', 'Unimplemented from: ' . $from . ' in wppa_upload_common_error()' );
			break;
	}
}

function wppa_upload_common_ok( $error, $from = '' ) {

	switch( $from ) {
		case 'upload':
			wppa_ok_message( $error );
			break;
		default:
			wppa_log( 'err', 'Unimplemented from: ' . $from . ' in wppa_upload_common_ok()' );
			break;
	}
}

function wppa_get_supported_extensions() {
global $wppa_supported_photo_extensions;
global $wppa_supported_video_extensions;
global $wppa_supported_audio_extensions;
global $wppa_supported_document_extensions;

	$supp = $wppa_supported_photo_extensions;
	if ( wppa_switch( 'enable_video' ) ) {
		$supp = array_merge( $supp, $wppa_supported_video_extensions );
	}
	if ( wppa_switch( 'enable_audio' ) ) {
		$supp = array_merge( $supp, $wppa_supported_audio_extensions );
	}
	if ( wppa_switch( 'enable_pdf' ) ) {
		$supp = array_merge( $supp, $wppa_supported_document_extensions );
	}
	if ( class_exists( 'ZipArchive' ) &&
			(
				wppa_user_is( 'administrator' ) ||
				! wppa_switch( 'upload_one_only' )
			)
		) {
		array_push( $supp, 'zip' );
	}
	return $supp;
}

function wppa_upload_post_process( $the_type, $album, $id, $from ) {

	wppa_set_default_name( $id, wppa( 'unsanitized_filename' ) );
	wppa_invalidate_treecounts( $album );
	wppa_cache_photo( 'invalidate', $id );
	wppa_update_photo( array( 'id' 		=> $id,
							  'sname' 	=> wppa_sanitize_album_photo_name( wppa_get_photo_item( $id, 'name' ) ),
							  ) );
	wppa( 'is_pdf', false );

	if ( $from == 'import' ) {
		if ( wppa( 'ajax' ) ) {
			wppa( 'ajax_import_files_done', true );
		}
	}

	wppa_fix_video_framesize( $id, $from );
}

// To check on possible duplicate
// Returns the id if the given file is a photo and this photo is already in the given album as a photo
function wppa_is_file_duplicate_photo( $file, $album ) {
global $wppa_supported_photo_extensions;
global $wpdb;

	if ( ! $file || ! $album ) return false;

	$ext_id = wppa_is_file_alias( $file, $album );
	if ( ! $ext_id ) return false;

	$ext_ext = wppa_get_photo_item( $ext_id, 'ext' );
	$new_ext = wppa_get_ext( basename( $file ) );

	if ( in_array( $ext_ext, $wppa_supported_photo_extensions ) &&
		 in_array( $new_ext, $wppa_supported_photo_extensions ) ) {
		return $ext_id;
	}
	else {
		return false;
	}
}

// To check for a possible poster or second filetype of existing item
// Returns the id if a given file with any extension already exists in the given album
function wppa_is_file_alias( $file, $album ) {
global $wpdb;

	if ( ! $file ) return false;	// Copy/move very old photo, before filnametracking
	$id = $wpdb->get_var( $wpdb->prepare( "SELECT id
										   FROM $wpdb->wppa_photos
										   WHERE filename LIKE %s
										   AND album = %d",
										   $wpdb->esc_like( wppa_strip_ext( basename( $file ) ) ) . '.%',
										   $album
										) );
	return $id;
}

// Try to find the framesize of a video, and update the items db entry if found.
// Return true on success, false on failure
function wppa_fix_video_framesize( $id, $where ) {

	// Is it a video?
	$files = wppa_is_video( $id );
	if ( ! $files ) {
		return false;
	}
	if ( ! in_array( 'mp4', $files ) ) {
		return false;
	}

	// Does file exist?
	$file = wppa_strip_ext( wppa_get_photo_path( $id ) ) . '.mp4';
	if ( ! wppa_is_file( $file ) ) {
		wppa_log( 'dbg', 'wppa_fix_video_framesize quit because ' . $file . ' does not exists' );
	}

	// Get the info
	if ( ! function_exists( 'wp_read_video_metadata' ) ) {
		require_once  ABSPATH . 'wp-admin/includes/media.php';
	}
	$mp4info = wp_read_video_metadata( $file );

	// Make sure its a video
	if ( $mp4info['fileformat'] != 'mp4' ) {
		wppa_log( 'dbg', 'No mp4 fileformat in ' . $file . ' ' . $where );
		return false;
	}

	// Find sizes
	$videox = isset( $mp4info['width'] ) ? $mp4info['width'] : '0';
	$videoy = isset( $mp4info['height'] ) ? $mp4info['height'] : '0';

	// Update item
	wppa_update_photo( array( 'id' 		=> $id,
							  'videox' 	=> $videox,
							  'videoy' 	=> $videoy,
							) );

	// Duration available?
	$duration = isset( $mp4info['length'] ) ? $mp4info['length'] : false;
	if ( $duration ) {
		wppa_update_photo( array( 'id' 			=> $id,
								  'duration' 	=> $duration,
								) );
	}

	// Date/time original?
	$datetime = isset( $mp4info['created_timestamp'] ) ? $mp4info['created_timestamp'] : false;
	if ( $datetime ) {
		$exifdtm = date( 'Y:m:d H:i:s', $datetime );
		wppa_update_photo( array( 'id' 			=> $id,
								  'exifdtm' 	=> $exifdtm,
								) );
	}
	else $exifdtm = '';

	wppa_log( 'dbg', 'MP4 Metadata found (' . $videox . 'x' . $videoy . '), ' . $duration . ', ' . $exifdtm . ' in ' . $file . ' ' . $where );

	return true;
}