Add Local Time Zone
This commit is contained in:
136
inc/media.php
136
inc/media.php
@@ -1,22 +1,22 @@
|
||||
<?php
|
||||
|
||||
class Media extends PhpObject {
|
||||
|
||||
|
||||
//DB Tables
|
||||
const MEDIA_TABLE = 'medias';
|
||||
|
||||
|
||||
//Media folders
|
||||
const MEDIA_FOLDER = 'files/';
|
||||
const THUMB_FOLDER = self::MEDIA_FOLDER.'thumbs/';
|
||||
|
||||
|
||||
const THUMB_MAX_WIDTH = 400;
|
||||
|
||||
|
||||
/**
|
||||
* Database Handle
|
||||
* @var Db
|
||||
*/
|
||||
private $oDb;
|
||||
|
||||
|
||||
/**
|
||||
* Media Project
|
||||
* @var Project
|
||||
@@ -25,9 +25,9 @@ class Media extends PhpObject {
|
||||
private $asMedia;
|
||||
private $asMedias;
|
||||
private $sSystemType;
|
||||
|
||||
|
||||
private $iMediaId;
|
||||
|
||||
|
||||
public function __construct(Db &$oDb, &$oProject, $iMediaId=0) {
|
||||
parent::__construct(__CLASS__, Settings::DEBUG);
|
||||
$this->oDb = &$oDb;
|
||||
@@ -37,19 +37,19 @@ class Media extends PhpObject {
|
||||
$this->sSystemType = (substr(php_uname(), 0, 7) == "Windows")?'win':'unix';
|
||||
$this->setMediaId($iMediaId);
|
||||
}
|
||||
|
||||
|
||||
public function setMediaId($iMediaId) {
|
||||
$this->iMediaId = $iMediaId;
|
||||
}
|
||||
|
||||
|
||||
public function getMediaId() {
|
||||
return $this->iMediaId;
|
||||
}
|
||||
|
||||
|
||||
public function getProjectCodeName() {
|
||||
return $this->oProject->getProjectCodeName();
|
||||
}
|
||||
|
||||
|
||||
public function setComment($sComment) {
|
||||
$sError = '';
|
||||
$asData = array();
|
||||
@@ -59,27 +59,27 @@ class Media extends PhpObject {
|
||||
else $asData = $this->getInfo();
|
||||
}
|
||||
else $sError = 'media_no_id';
|
||||
|
||||
|
||||
return Spot::getResult(($sError==''), $sError, $asData);
|
||||
}
|
||||
|
||||
|
||||
public function getMediasInfo($iMediaId=0) {
|
||||
$bOwnMedia = ($iMediaId > 0);
|
||||
if($bOwnMedia && empty($this->asMedia) || !$bOwnMedia && empty($this->asMedias)) {
|
||||
if($this->oProject->getProjectId()) {
|
||||
$asParams = array(
|
||||
'select' => array(Db::getId(self::MEDIA_TABLE), 'filename', 'taken_on', 'posted_on', 'rotate', 'type AS subtype', 'comment'),
|
||||
'select' => array(Db::getId(self::MEDIA_TABLE), 'filename', 'taken_on', 'posted_on', 'timezone', 'rotate', 'type AS subtype', 'comment'),
|
||||
'from' => self::MEDIA_TABLE,
|
||||
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId())
|
||||
);
|
||||
if($bOwnMedia) $asParams['constraint'][Db::getId(self::MEDIA_TABLE)] = $iMediaId;
|
||||
|
||||
|
||||
$asMedias = $this->oDb->selectRows($asParams);
|
||||
foreach($asMedias as &$asMedia) {
|
||||
$asMedia['media_path'] = self::getMediaPath($asMedia['filename']);
|
||||
$asMedia['thumb_path'] = $this->getMediaThumbnail($asMedia['filename']);
|
||||
}
|
||||
|
||||
|
||||
if(!empty($asMedias)) {
|
||||
if($bOwnMedia) $this->asMedia = array_shift($asMedias);
|
||||
else $this->asMedias = $asMedias;
|
||||
@@ -88,15 +88,15 @@ class Media extends PhpObject {
|
||||
}
|
||||
return $bOwnMedia?$this->asMedia:$this->asMedias;
|
||||
}
|
||||
|
||||
|
||||
public function getInfo() {
|
||||
return $this->getMediasInfo($this->iMediaId);
|
||||
}
|
||||
|
||||
|
||||
public function isProjectModeValid() {
|
||||
return ($this->oProject->getMode() == Project::MODE_BLOG);
|
||||
}
|
||||
|
||||
|
||||
public function addMedia($sMediaName, $sMethod='upload') {
|
||||
$sError = '';
|
||||
$asParams = array();
|
||||
@@ -109,30 +109,32 @@ class Media extends PhpObject {
|
||||
$asParams[] = $sMediaName;
|
||||
}
|
||||
else {
|
||||
//Add media to DB
|
||||
$asMediaInfo = $this->getMediaInfoFromFile($sMediaName);
|
||||
|
||||
//Converting times to DB Time Zone, by using date()
|
||||
$asDbInfo = array(
|
||||
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
||||
'filename' => $sMediaName,
|
||||
'taken_on' => ($asMediaInfo['taken_ts'] > 0)?date(Db::TIMESTAMP_FORMAT, $asMediaInfo['taken_ts']):0, //Site Time
|
||||
'posted_on' => date(Db::TIMESTAMP_FORMAT, $asMediaInfo['file_ts']), //Site Time
|
||||
'taken_on' => ($asMediaInfo['taken_ts'] > 0)?date(Db::TIMESTAMP_FORMAT, $asMediaInfo['taken_ts']):0,
|
||||
'posted_on' => date(Db::TIMESTAMP_FORMAT, $asMediaInfo['file_ts']),
|
||||
'timezone' => $asMediaInfo['timezone'],
|
||||
'rotate' => $asMediaInfo['rotate'],
|
||||
'type' => $asMediaInfo['type']
|
||||
);
|
||||
|
||||
|
||||
if($sMethod=='sync') $iMediaId = $this->oDb->insertUpdateRow(self::MEDIA_TABLE, $asDbInfo, array(Db::getId(Project::PROJ_TABLE), 'filename'));
|
||||
else $iMediaId = $this->oDb->insertRow(self::MEDIA_TABLE, $asDbInfo);
|
||||
|
||||
|
||||
if(!$iMediaId) $sError = 'error_commit_db';
|
||||
else {
|
||||
$this->setMediaId($iMediaId);
|
||||
$asParams = $this->getInfo(); //Creates thumbnail
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Spot::getResult(($sError==''), $sError, $asParams);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* One-shot function to initialize DB with existing images
|
||||
*/
|
||||
@@ -146,13 +148,15 @@ class Media extends PhpObject {
|
||||
$this->setExtractMode(PhpObject::MODE_HTML);
|
||||
return $this->getCleanMessageStack();
|
||||
}
|
||||
|
||||
|
||||
private function getMediaInfoFromFile($sMediaName)
|
||||
{
|
||||
$sMediaPath = self::getMediaPath($sMediaName);
|
||||
$sType = self::getMediaType($sMediaName);
|
||||
|
||||
$iTimeStamp = $iTakenOn = $iPostedOn = 0;
|
||||
|
||||
$iTimeStamp = $iTakenOn = 0;
|
||||
$iPostedOn = filemtime($sMediaPath);
|
||||
$sTimeZone = date_default_timezone_get();
|
||||
$sRotate = '0';
|
||||
$sTakenOn = '';
|
||||
switch($sType) {
|
||||
@@ -161,28 +165,44 @@ class Media extends PhpObject {
|
||||
$sParams = implode(' ', array(
|
||||
'-loglevel error', //Remove comments
|
||||
'-select_streams v:0', //First video channel
|
||||
'-show_entries stream_tags=rotate,creation_time', //filter tags :rotation & creation time only
|
||||
'-show_entries '. //filter tags : Creation Time & Rotation
|
||||
'format_tags=creation_time,com.apple.quicktime.creationdate'.':'.
|
||||
'stream_tags=rotate,creation_time',
|
||||
'-print_format json', //output format: json
|
||||
'-i' //input file
|
||||
));
|
||||
exec('ffprobe '.$sParams.' "'.$sMediaPath.'"', $asResult);
|
||||
$asResult = json_decode(implode('', $asResult), true);
|
||||
|
||||
//Timestamps
|
||||
$sTakenOn = date(Db::TIMESTAMP_FORMAT, strtotime($asResult['streams'][0]['tags']['creation_time']));
|
||||
$iPostedOn = filemtime($sMediaPath);
|
||||
|
||||
$asExif = json_decode(implode('', $asResult), true);
|
||||
|
||||
//Taken On
|
||||
if(isset($asExif['format']['tags']['com.apple.quicktime.creationdate'])) {
|
||||
$sTakenOn = $asExif['format']['tags']['com.apple.quicktime.creationdate']; //contains Time Zone
|
||||
$sTimeZone = Spot::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
|
||||
}
|
||||
else $sTakenOn = $asExif['format']['tags']['creation_time'] ?? $asExif['streams'][0]['tags']['creation_time'];
|
||||
|
||||
//Orientation
|
||||
if(isset($asResult['streams'][0]['tags']['rotate'])) $sRotate = $asResult['streams'][0]['tags']['rotate'];
|
||||
if(isset($asExif['streams'][0]['tags']['rotate'])) $sRotate = $asExif['streams'][0]['tags']['rotate'];
|
||||
break;
|
||||
case 'image':
|
||||
case 'image':
|
||||
$asExif = @exif_read_data($sMediaPath, 0, true);
|
||||
if(!$asExif) $asExif['FILE']['FileDateTime'] = filemtime($sMediaPath);
|
||||
|
||||
//Timestamps
|
||||
if(array_key_exists('EXIF', $asExif) && array_key_exists('DateTimeOriginal', $asExif['EXIF'])) $sTakenOn = $asExif['EXIF']['DateTimeOriginal'];
|
||||
|
||||
//Posted On
|
||||
if(array_key_exists('FILE', $asExif) && array_key_exists('FileDateTime', $asExif['FILE'])) $iPostedOn = $asExif['FILE']['FileDateTime'];
|
||||
|
||||
|
||||
//Taken On & Timezone
|
||||
if(array_key_exists('EXIF', $asExif)) {
|
||||
if(array_key_exists('DateTimeOriginal', $asExif['EXIF'])) $sTakenOn = $asExif['EXIF']['DateTimeOriginal'];
|
||||
|
||||
/* Priorities:
|
||||
* 1. OffsetTimeOriginal: timezone for DateTimeOriginal (exif version >= 2.31)
|
||||
* 2. 0x9011: same as above, but unidentified
|
||||
* 3. Timezone extracted from DateTimeOriginal
|
||||
* 4. Uploader Browser Time Zone (PHP Default Time Zone)
|
||||
*/
|
||||
$sTimeZone = $asExif['EXIF']['OffsetTimeOriginal'] ?? $asExif['EXIF']['UndefinedTag:0x9011'] ?? Spot::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
|
||||
}
|
||||
|
||||
//Orientation
|
||||
if(array_key_exists('IFD0', $asExif) && array_key_exists('Orientation', $asExif['IFD0'])) {
|
||||
switch($asExif['IFD0']['Orientation'])
|
||||
@@ -195,30 +215,32 @@ class Media extends PhpObject {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//Media info do not have any TZ: Interpreting date time using project timezone (assuming all medias have been taken in this time zone)
|
||||
|
||||
//Assign the correct Time Zone to $sTakenOn if it is not already contained in it. Then get Unix Timestamp
|
||||
//Time Zone (2nd parameter) will be ignored if already contained in $sTakenOn
|
||||
if($sTakenOn != '') {
|
||||
$oTakenOn = new DateTime($sTakenOn, new DateTimeZone($this->oProject->getTimeZone()));
|
||||
$oTakenOn = new DateTime($sTakenOn, new DateTimeZone($sTimeZone));
|
||||
$iTakenOn = $oTakenOn->format('U');
|
||||
}
|
||||
|
||||
|
||||
//Merge timestamps
|
||||
$iTimeStamp = ($iTakenOn > 0)?$iTakenOn:$iPostedOn;
|
||||
|
||||
|
||||
return array(
|
||||
'timestamp' => $iTimeStamp,
|
||||
'timezone' => $sTimeZone,
|
||||
'taken_ts' => $iTakenOn,
|
||||
'file_ts' => $iPostedOn,
|
||||
'rotate' => $sRotate,
|
||||
'type' => $sType
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private function getMediaThumbnail($sMediaName)
|
||||
{
|
||||
$sMediaPath = self::getMediaPath($sMediaName);
|
||||
$sThumbPath = self::getMediaPath($sMediaName, 'thumbnail');
|
||||
|
||||
|
||||
if(!file_exists($sThumbPath)) {
|
||||
$sType = self::getMediaType($sMediaName);
|
||||
switch($sType) {
|
||||
@@ -236,23 +258,23 @@ class Media extends PhpObject {
|
||||
'"'.$sTempPath.'"', //output file
|
||||
));
|
||||
exec('ffmpeg '.$sParams, $asResult);
|
||||
|
||||
|
||||
//Resize
|
||||
$asThumbInfo = ToolBox::createThumbnail($sTempPath, self::THUMB_MAX_WIDTH, 0, $sThumbPath, true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else $asThumbInfo = array('error'=>'', 'out'=>$sThumbPath);
|
||||
|
||||
|
||||
return ($asThumbInfo['error']=='')?$asThumbInfo['out']:$sMediaPath;
|
||||
}
|
||||
|
||||
|
||||
private static function getMediaPath($sMediaName, $sFileType='media') {
|
||||
if($sFileType=='thumbnail') return self::THUMB_FOLDER.$sMediaName.(strtolower(substr($sMediaName, -3))=='mov'?'.png':'');
|
||||
else return self::MEDIA_FOLDER.$sMediaName;
|
||||
}
|
||||
|
||||
|
||||
private static function getMediaType($sMediaName) {
|
||||
$sMediaPath = self::getMediaPath($sMediaName);
|
||||
$sMediaMime = mime_content_type($sMediaPath);
|
||||
@@ -260,7 +282,7 @@ class Media extends PhpObject {
|
||||
case 'video/quicktime': $sType = 'video'; break;
|
||||
default: $sType = 'image'; break;
|
||||
}
|
||||
|
||||
|
||||
return $sType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user