9. File analyse_status_table.php

This PHP file is called in an AJAX script AnalyseDeletedAndNewMedia(), which is implemented in public_private.js. The update information needed in the file is transferred from the caller by POST method.

The information in tab 4 in the “Media processing status” window (see Fig. 5.3, Fig. 5.4, and Fig. 6.1) is used to update the iminfo.xml files in each location directory.

9.1. Source code

<?php
// File called by AJAX script AnalyseDeletedAndNewMedia () implemented in public_private.js

require_once('filesystem.php');
require_once('iminfo_xhr.php');
require_once('prepareDirOverviewGalleryAjax.php');
require_once('getid3/getid3.php');
require_once($_SERVER['DOCUMENT_ROOT'].'/login/loginFunctions.php');

function processNewMedia(&$iminfo_objs,$newMedia,$table_content,$unixTime)
{
// 
	$getID3=new getID3;
	$finfo=finfo_open(FILEINFO_MIME_TYPE);
	$mediaCnt=0;
	$transferCnt=0;
	foreach ($newMedia as $key=>$loc_obj){
		if (($loc_obj['image_count']==0)&&($loc_obj['video_count']==0)) continue; // No new media --> next location
		$new_image_loc=$loc_obj['image_files'];
		$new_video_loc=$loc_obj['video_files'];
		chdir($key);
		$new_im_pub_media_cnt=0;
		$new_im_prv_media_cnt=0;
		$new_vi_pub_media_cnt=0;
		$new_vi_prv_media_cnt=0;
		$new_vi_pub_files_cnt=0;
		$new_vi_prv_files_cnt=0;
		$mediaCnt=count($iminfo_objs[$key]->media);
		foreach ($new_image_loc as $new_image){
			$insert_last_pos=FALSE;
			$tblRow=$new_image[0]['tableEntry']-1;
			$exif=exif_read_data($new_image[0]['name'],'IFD0');
			if (!$exif) $exif=exif_read_data($new_image[0]['name'],'FILE');
			$new_image_object=IminfoNewImageObject($exif);
			if ($table_content[$tblRow][4]){ // Public
				$new_image_object->PublicPrivate=' R';
				$new_im_pub_media_cnt++;
			}
			else {// Private
				$new_image_object->PublicPrivate=' Private';
				$new_im_prv_media_cnt++;
			}
			// Determine where the new image object has to be inserted
			if (isset($exif['DateTimeOriginal'])){
				$stamp=strtotime($exif['DateTimeOriginal']);// What if not set?
				// Look for image which is "first" youngest than the image to be inserted
				$target=$iminfo_objs[$key]->xpath("//media[TimeStamp > $stamp][1]"); // SINGLE ELEMENT
				if (!empty($target)){ // YOUNGER IMAGES ARE FOUND
					// $tPos is a dummy variable. Position of the inserted media object is used in the element <TimeSortedFile>
					if (iminfo_insert($new_image_object,current($target),$tPos,'BEFORE_TARGET')) $mediaCnt++;
				}
				else $insert_last_pos=TRUE;
			}
			else $insert_last_pos=TRUE;
			if ($insert_last_pos){
				$target=current($iminfo_objs[$key]->xpath('//media[last()]'));
				// $tPos is a dummy variable. Position of the inserted media object is used in the element <TimeSortedFile>
				if (iminfo_insert($new_image_object,$target,$tPos,'AFTER_TARGET')) $mediaCnt++;
			}
			$transferCnt++;
		}
		foreach ($new_video_loc as $new_video){// Each new video media can have multiple files, i.e. different formats
			$insert_last_pos=TRUE;
			$video_cnt=count($new_video);
			$tblRow=$new_video[0]['tableEntry']-1;
			$mimes=array_fill(0,$video_cnt,'');
			foreach ($new_video as $key2=>$video) $mimes[$key2]=substr(finfo_file($finfo,$video['name']),6);
			$mimes_keys=array_flip($mimes);
			if (isset($mimes_keys['mp4'])){
				$video_info=$getID3->analyze($new_video[$mimes_keys['mp4']]['name']);
				if (isset($video_info['quicktime'])){// Overwrite $unixTime
					$unixTime=intval($video_info['quicktime']['moov']['subatoms'][0]['creation_time_unix']);
					if ($unixTime<0){// creation_time_unix is not specified in header
						// Fallback scenario
						$unixTime=filemtime($new_video[$mimes_keys['mp4']]['name']);// TIMEZONE + 00:00
					}
					$target=$iminfo_objs[$key]->xpath("//media[TimeStamp > $unixTime][1]");
					if (!empty($target)) $insert_last_pos=FALSE;
				}
			}
			else {
				if (isset($mimes_keys['webm'])){
					$video_info=$getID3->analyze($new_video[$mimes_keys['webm']]['name']);
					$unixTime=filemtime($new_video[$mimes_keys['webm']]['name']);
				}
				else{
					$video_info=$getID3->analyze($new_video[0]['name']);
					$unixTime=filemtime($new_video[0]['name']);
				}
				$insert_last_pos=TRUE;
			}
			$new_video_object=IminfoNewVideoObject($video_info,$unixTime,$mimes);
			if ($table_content[$tblRow][4]){// Public
				$new_video_object->PublicPrivate=' R';
				$new_vi_pub_media_cnt++;
				$new_vi_pub_files_cnt+=$video_cnt;
			}
			else {// Private
				$new_video_object->PublicPrivate=' Private';
				$new_vi_prv_media_cnt++;
				$new_vi_prv_files_cnt+=$video_cnt;
			}
			if (!$insert_last_pos) {
				if (iminfo_insert($new_video_object,current($target),$tPos,'BEFORE_TARGET')) $mediaCnt++;
			}
			else {
				$target=current($iminfo_objs[$key]->xpath('//media[last()]'));
				if (iminfo_insert($new_video_object,$target,$tPos,'AFTER_TARGET')) $mediaCnt++;
			}
			$transferCnt++;
		}
		$iminfo_objs[$key]->ImageInfo->PublicCount+=$new_im_pub_media_cnt;
		$iminfo_objs[$key]->ImageInfo->Trf_PublicCount=$new_im_pub_media_cnt;
		$iminfo_objs[$key]->ImageInfo->PrivateCount+=$new_im_prv_media_cnt;
		$iminfo_objs[$key]->ImageInfo->Trf_PrivateCount=$new_im_prv_media_cnt;
		$iminfo_objs[$key]->VideoInfo->PublicCount+=$new_vi_pub_media_cnt;
		$iminfo_objs[$key]->VideoInfo->Trf_PublicCount=$new_vi_pub_media_cnt;
		$iminfo_objs[$key]->VideoInfo->PrivateCount+=$new_vi_prv_media_cnt;
		$iminfo_objs[$key]->VideoInfo->Trf_PrivateCount=$new_vi_prv_media_cnt;
		$iminfo_objs[$key]->VideoInfo->PublicFilesCount+=$new_vi_pub_files_cnt;
		$iminfo_objs[$key]->VideoInfo->PrivateFilesCount+=$new_vi_prv_files_cnt;
		$iminfo_objs[$key]->MediaCounterInfo->MaxCnt=$mediaCnt;
// Tag Transferred2SiteDir is not yet updated here because the media are not processed in this procedure.
// This is done in "media-update-progress.php: function update_videos() and update_images()".
		chdir('..');
	}
	return $transferCnt;
}

function processRemovedMedia(&$iminfo_objs,$remMedia,$table_content)
// return value: 0 if no media are to be processed back.
// If media are to be put back (depends on user choices) the return value is different from 0 (and positive)
{
	$transferCnt=0;
	foreach ($remMedia as $key=>$rem_media_loc){
		$xml=$iminfo_objs[$key];
		foreach ($rem_media_loc as $rem_image){
			$tblRow=$rem_image['tableEntry']-1;
			$row=$table_content[$tblRow];
			$dataAttr['pub_priv']=$rem_image['public_private'];
			$dataAttr['orgname']=$rem_image['location_org_name'];
			$transferCnt+=processRemovedMediaEntry($xml,$dataAttr,$row);
		}
		$iminfo_objs[$key]=$xml;
	}
/*
	foreach ($table_content as $k => $row){
		// Get string value of 4-th element in row
		$new_removed=trim($row[3]);// 'New / Removed' column
		$dir=trim($row[0]); // 'Location directory' column
		$xml=$iminfo_objs[$dir];
		if (strpos($new_removed,'Removed media')!==false){
			$transferCnt+=processRemovedMediaEntry($xml,$col2_dataAttr[$k],$row);
		}
		$iminfo_objs[$dir]=$xml;
	}
*/
	return $transferCnt;
}

function processRemovedMediaEntry(&$xml,$col2_dataAttr,$rowData)
{
	$removed=trim($rowData[3]);
	$transferCnt=0;
	$org_name=$col2_dataAttr['orgname'];
// Find media element with given "OriginalFile"
// Reference: http://stackoverflow.com/questions/17537909/php-simplexml-get-a-specific-item-based-on-the-value-of-a-field
	$elm=current($xml->xpath('//media[starts-with(normalize-space(OriginalFile),"'.$org_name.'")]'));
	// Row in table represents removed media
	if ($elm !== false){ // Media entry is found
		$mimetype=$elm->MIMETYPE->children();
		if (strpos($removed,'Has original')){
			if ($elm->Transferred2SiteDir>TRANSFER_NONE){ // First time noticed that media is removed: xml entry has to be notified.
				if ($mimetype[0]->getName()=='IMAGE'){
					$xml->ImageInfo->ReleasedCount-=1;
					if ($col2_dataAttr['pub_priv']=='public'){
						$xml->ImageInfo->Rel_PublicCount-=1;
						if ($rowData[4]) $elm->Transferred2SiteDir=TRANSFER_NONE; // DO not put back.
						else { // 'Pub/Private Upd.Iminfo/Put back'
							$xml->ImageInfo->Trf_PublicCount+=1;
							$transferCnt=1;
							$elm->Transferred2SiteDir=TRANSFER2PUBLIC_AGAIN;
						}
					}
					else { // Private
						$xml->ImageInfo->Rel_PrivateCount-=1;
						if ($rowData[4]) $elm->Transferred2SiteDir=TRANSFER_NONE; // DO NOT PUT BACK
						else {
							$xml->ImageInfo->Trf_PrivateCount+=1;
							$transferCnt=1;
							$elm->Transferred2SiteDir=TRANSFER2PRIVATE_AGAIN;
						}
					}
				}
				else if ($mimetype[0]->getName()=='VIDEO'){
					$xml->VideoInfo->ReleasedCount-=1;
					if ($col2_dataAttr['pub_priv']=='public'){
						$xml->VideoInfo->Rel_PublicCount-=1;
						$xml->VideoInfo->Rel_PublicFilesCount-=$elm->Count;
						if ($rowData[4]) $elm->Transferred2SiteDir=TRANSFER_NONE; // DO NOT PUT BACK
						else {
							$xml->VideoInfo->Trf_PublicCount+=1;
							$transferCnt=1;
							$elm->Transferred2SiteDir=TRANSFER2PUBLIC_AGAIN;
						}
					}
					else {
						$xml->VideoInfo->Rel_PrivateCount-=1;
						$xml->VideoInfo->Rel_PrivateFilesCount-=$elm->Count;
						if ($rowData[4]) $elm->Transferred2SiteDir=TRANSFER_NONE; // DO NOT PUT BACK
						else {
							$xml->VideoInfo->Trf_PrivateCount+=1;
							$transferCnt=1;
							$elm->Transferred2SiteDir=TRANSFER2PRIVATE_AGAIN;
						}
					}
				}
			}
			else if ($elm->Transferred2SiteDir==TRANSFER_NONE){
			// Removed media has been notified by xml entry, and original is available
				if (($mimetype[0]->getName()=='IMAGE')&&(!$rowData[4])){
					$transferCnt=1;
					if ($col2_dataAttr['pub_priv']=='public'){
						$xml->ImageInfo->Trf_PublicCount+=1;
						$elm->Transferred2SiteDir=TRANSFER2PUBLIC_AGAIN;
					} else {
						$xml->ImageInfo->Trf_PrivateCount+=1;
						$elm->Transferred2SiteDir=TRANSFER2PRIVATE_AGAIN;
					}
				}
				else if (($mimetype[0]->getName()=='VIDEO')&&(!$rowData[4])){
					$transferCnt=1;
					if ($col2_dataAttr['pub_priv']=='public'){
						$xml->VideoInfo->Trf_PublicCount+=1;
						$elm->Transferred2SiteDir=TRANSFER2PUBLIC_AGAIN;
					} else {
						$xml->VideoInfo->Trf_PrivateCount+=1;
						$elm->Transferred2SiteDir=TRANSFER2PRIVATE_AGAIN;
					}
				}
			}
		}
		else { // No original media is available
//			$checkStat=$rowData[4]; // MUST BE 1: Delete entry in IMINFO
			$xml=iminfo_delete_media_elm($elm); // Updated xml:
		}
	}
	return $transferCnt; //If removed media has to be put back --> $transferCnt=1, else 0
}

// ***************************
// MAIN SCRIPT
// ***************************
$json_str1=$_POST['json_str1'];
$json_str2=$_POST['json_str2']; // Original media filename, public/private info
$newMediaJSSONstr=$_POST['json_str3'];
$remMediaJSSONstr=$_POST['json_str4'];
$infoJSSONstr=$_POST['info'];
$tmp_dir=$_SERVER['DOCUMENT_ROOT'].DS."tmp".DS."admin";
if (isset($_SESSION['sess_username'])){$uname=$_SESSION['sess_username'];}
else $uname=WEBSITE_VISITOR;
//file_put_contents($tmp_dir.DS."NewOrDeletedMedia-table",$json_str1);
//file_put_contents($tmp_dir.DS."col2_dataAttr",$json_str2);
// Get info from "Media Processing Status" window
$table_content=json_decode($json_str1,TRUE);
$col2_dataAttr=json_decode($json_str2,TRUE);
$newMedia=json_decode($newMediaJSSONstr,TRUE);
$remMedia=json_decode($remMediaJSSONstr,TRUE);
$info=json_decode($infoJSSONstr,TRUE);
$wdir=$info['wdir'];
$XFFFFF['permissionDeleteProcFile']=TRUE;
$XFFFFF['server_ip']=$_SERVER['SERVER_ADDR'];
$XFFFFF['client_ip']=$info['ip'];
$dir=$_SERVER['DOCUMENT_ROOT'].DS.$wdir;
$server_info=array('uname'=>$uname,'sid'=>0,'hostname'=>$_SERVER['SERVER_NAME'],'hostaddress'=>$_SERVER['SERVER_ADDR'],'debugJS'=>TRUE);
chdir($dir);
$xmlDefs=simplexml_load_file('phpdefinition.xml');
$iminfo_objs=GetIminfoObjects($xmlDefs);
$locDirs=array_fill(0,count($table_content),'');
$str='';
$transferCnt=0;
$unixTime=time();
$timeStr=date("Ymd-Hi",$unixTime);
$doZIP=FALSE;
$zip=FALSE;
$zipname='';
$send_email=FALSE;

// Update IMINFO objects with new and/or deleted media.
$transferCnt+=processNewMedia($iminfo_objs,$newMedia,$table_content,$unixTime);
$transferCnt+=processRemovedMedia($iminfo_objs,$remMedia,$table_content);

// Save updated IMINFO.XML files
foreach ($table_content as $k => $row) $locDirs[$k]=trim($row[0]);
$unique_locDir=array_unique($locDirs);
$iminfo_version=array('old'=>0,'new'=>0);
$upd_succ=array_fill(0,count($unique_locDir),array('status'=>UPDATE_IMINFO_EXISTS_OK,'directory'=>'','fname'=>'iminfo.xml','reason'=>'','code'=>0,'iminfo_version'=>$iminfo_version));
foreach ($unique_locDir as $k => $loc_dir){
	chdir($loc_dir);
	$xml_data=$iminfo_objs[$loc_dir];
//	list($modified,$xml_data)=IminfoXML2UpdatedIminfoXML_Obj($xml_data);
	$iminfo_objs[$loc_dir]=$xml_data;
	if ($doZIP) rename_with_timestamp('iminfo.xml',$timeStr);
//	if ($iminfo_objs[$loc_dir]->asXML('iminfo_test_new_removed.xml')){
	if ($iminfo_objs[$loc_dir]->asXML('iminfo.xml')){
		$upd_succ[$k]['status']=1;
		$zip|=$doZIP;
	}
	chdir('..');
	$upd_succ[$k]['directory']=$loc_dir;
}
$ZipModuleLoaded=extension_loaded('zip');
if ($zip && $ZipModuleLoaded)	list($nIminfoInZIP,$zipname)=zip_iminfo_files($ZipModuleLoaded,$upd_succ,$timeStr);
if ($send_email) send_email_update_iminfo($nIminfoInZIP,$zipname,$wdir,$upd_succ,$XFFFFF,$server_info,$server_info,__FUNCTION__);

if ($transferCnt==0) {
	if (!file_exists("rproc.txt")) CreateRPROC("rproc.txt",PROCESSED_FILES_ORIGINALS_ADD_REM,$iminfo_objs); // ??
	if (!file_exists(FPROCFILE)) fclose(fopen(FPROCFILE,"w"));
}
//array_filter($table_content,function($array) use ($key){return s_inarr_key($array, $key); } );

10. Functions in file Imageresizeprocess.php

Depending on the value of the fourth output argument of the function dirThumbs(), i.e. the resize status, the server side PHP file is called or not in familie-vakantie.php. This file is called by means of a hidden HTML form so that arguments can be transferred by means of the POST method. Simultaneously a progress window is opened to monitor the resizing process progress. The progress update at the server side is communicated to the client side using the Server Side Event method (available from HTML-5: XMLHttpRequest object), and the communication itself makes use of JavaScript Object Notation (JSON).

The Imageresizeprocess.php file will call another PHP file for actually resizing the images (resize-images.php).

11. Functions in resize-images.php

With the POST method the $vakantieDir and $parent input arguments are retrieved. Then the function ResizeGalleryPictures($parent, $vakantieDir) is called. First the masterfile rproc.txt is processed and the content of the file is stored in a 2 dimensional array. The array contains information about the location sub-directories. The function will continue with generating resized images from the original images, which are located in the location sub-directories. The resized images will be placed in a newly generated subdirectory called “Resized”. An image info file will also be created in each location sub-directory (“iminfo.txt”). This “iminfo.txt” file is a comma separated file:

  1. Each line corresponds to 1 image or video in the web page. In HTML5 multiple video files can be used for one web video since HTML5 makes use of fallback scenario’s. If a web browser does not support a given video container format the next video file in the HTML5 video tag will be tried.
  2. Each line has 11 entries:
    1. nnnn-Image filename, where nnnn is a 4 digit leading order count string. Ordering the image files can be done alphabetically or date taken time (date taken time is guaranteed to be known: it depends on the settings of the camera),
    2. Original image filename,
    3. Date taken string (retrieved from EXIF image data),
    4. Data string converted to number. If there is no date taken string, an empty string is used,
    5. String “R” (meaning Resized) or “Private”,
    6. Image width of the original image or video,
    7. Image height of the original image or video,
    8. Horizontal image resolution per pixel (XResolution),
    9. Vertical image resolution per pixel (YResolution),
    10. GPS longitude coordinate (NO-LNG if not found in image),
    11. GPS latitude coordinate (NO-LAT if not found in image)

The resized image files have no EXIF data in their header! The resized image files have a fixed height of 1200px. The width is determined by the aspect ratio of the original file (the original image files should have a height of at least 1200px, otherwise upscaling will take place). The resized image files will have a suffix appended to the original file basename: (“-small”). Image thumb files will also be generated with a fixed height of 90px and have file suffix “-thumb” appended file basename. The generation of the resized images and the thumbs is a time consuming process and may take a while depending on the number of images and the number of location sub-directories. An XML version iminfo.xml is also introduced.

_images/Fig29-ResizeImages.png

Fig. 11.1 Process flow of resize images.