157 lines
5.2 KiB
PHP
157 lines
5.2 KiB
PHP
<?php
|
|
|
|
class Picture extends PhpObject {
|
|
|
|
//DB Tables
|
|
const PIC_TABLE = 'pictures';
|
|
|
|
//Picture folders
|
|
const PIC_FOLDER = 'files/';
|
|
const THUMB_FOLDER = self::PIC_FOLDER.'thumbs/';
|
|
|
|
/**
|
|
* Database Handle
|
|
* @var Db
|
|
*/
|
|
private $oDb;
|
|
|
|
/**
|
|
* Picture Project
|
|
* @var Project
|
|
*/
|
|
private $oProject;
|
|
private $asPics;
|
|
|
|
public function __construct(Db &$oDb, &$oProject) {
|
|
parent::__construct(__CLASS__, Settings::DEBUG);
|
|
$this->oDb = &$oDb;
|
|
$this->oProject = &$oProject;
|
|
}
|
|
|
|
public function getPicsInfo() {
|
|
if(empty($this->asPics)) {
|
|
if($this->oProject->getProjectId()) {
|
|
$asPics = $this->oDb->selectRows(array(
|
|
'select' => array(Db::getId(self::PIC_TABLE), 'filename', 'taken_on', 'posted_on', 'rotate'),
|
|
'from' => self::PIC_TABLE,
|
|
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId())
|
|
));
|
|
|
|
foreach($asPics as &$asPic) {
|
|
$asPic['pic_path'] = self::getPicPath($asPic['filename']);
|
|
$asPic['thumb_path'] = self::getPicThumbnail($asPic['filename']);
|
|
}
|
|
$this->asPics = $asPics;
|
|
}
|
|
}
|
|
return $this->asPics;
|
|
}
|
|
|
|
public function isProjectModeValid() {
|
|
return ($this->oProject->getMode() == Project::MODE_BLOG);
|
|
}
|
|
|
|
public function addPic($sPicName, $sMethod='upload') {
|
|
$sError = '';
|
|
if(!$this->isProjectModeValid() && $sMethod!='sync') $sError = 'Le projet (id='.$this->oProject->getProjectId().') n\'est pas en mode "blog"';
|
|
elseif($this->oDb->pingValue(self::PIC_TABLE, array('filename'=>$sPicName)) && $sMethod!='sync') $sError = 'l\'image existe déjà';
|
|
else {
|
|
//Add picture to DB
|
|
$asPicInfo = $this->getPicInfoFromFile($sPicName);
|
|
$asDbInfo = array(
|
|
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
|
'filename' => $sPicName,
|
|
'taken_on' => ($asPicInfo['taken_ts'] > 0)?date(Db::TIMESTAMP_FORMAT, $asPicInfo['taken_ts']):0, //Site Time (Settings::TIMEZONE)
|
|
'posted_on' => date(Db::TIMESTAMP_FORMAT, $asPicInfo['file_ts']), //Site Time
|
|
'rotate' => $asPicInfo['rotate']
|
|
);
|
|
|
|
if($sMethod=='sync') $iPicId = $this->oDb->insertUpdateRow(self::PIC_TABLE, $asDbInfo, array(Db::getId(Project::PROJ_TABLE), 'filename'));
|
|
else $iPicId = $this->oDb->insertRow(self::PIC_TABLE, $asDbInfo);
|
|
|
|
if(!$iPicId) $sError = 'l\'image n\'a pas pu être entrée en base';
|
|
else {
|
|
//Create thumbnail
|
|
self::getPicThumbnail($sPicName);
|
|
}
|
|
}
|
|
|
|
if($sError!='') {
|
|
$sError = 'Erreur lors de l\'ajout de "'.$sPicName.'" : '.$sError;
|
|
$this->addError($sError);
|
|
}
|
|
|
|
return $sError;
|
|
}
|
|
|
|
/**
|
|
* One-shot function to initialize DB with existing images
|
|
*/
|
|
public function syncFileFolder() {
|
|
$asPicPaths = glob(self::getPicPath('*.{jpg,JPG,jpeg,JPEG,png,PNG}'), GLOB_BRACE);
|
|
foreach($asPicPaths as $sPicPath)
|
|
{
|
|
$sPicName = pathinfo($sPicPath, PATHINFO_BASENAME);
|
|
$this->addPic($sPicName, 'sync');
|
|
}
|
|
$this->setExtractMode(PhpObject::MODE_HTML);
|
|
return $this->getCleanMessageStack();
|
|
}
|
|
|
|
private function getPicInfoFromFile($sPicName)
|
|
{
|
|
$sPicPath = self::getPicPath($sPicName);
|
|
$iTimeStamp = $iTakenOn = $iPostedOn = 0;
|
|
$sTakenOn = '';
|
|
$asExif = @exif_read_data($sPicPath, 0, true);
|
|
if(!$asExif) $asExif['FILE']['FileDateTime'] = filemtime($sPicPath);
|
|
|
|
//Timestamps
|
|
if(array_key_exists('EXIF', $asExif) && array_key_exists('DateTimeOriginal', $asExif['EXIF'])) $sTakenOn = $asExif['EXIF']['DateTimeOriginal'];
|
|
if(array_key_exists('FILE', $asExif) && array_key_exists('FileDateTime', $asExif['FILE'])) $iPostedOn = $asExif['FILE']['FileDateTime'];
|
|
|
|
//Picture info do not have any TZ: Interpreting date time using project timezone (assuming all pictures have been taken in this time zone)
|
|
if($sTakenOn != '') {
|
|
$oTakenOn = new DateTime($sTakenOn, new DateTimeZone($this->oProject->getTimeZone()));
|
|
$iTakenOn = $oTakenOn->format('U');
|
|
}
|
|
|
|
//Merge timestamps
|
|
$iTimeStamp = ($iTakenOn > 0)?$iTakenOn:$iPostedOn;
|
|
|
|
//Orientation
|
|
if(array_key_exists('IFD0', $asExif) && array_key_exists('Orientation', $asExif['IFD0'])) {
|
|
switch($asExif['IFD0']['Orientation'])
|
|
{
|
|
case 1: $sRotate = '0'; break; //None
|
|
case 3: $sRotate = '180'; break; //Flip over
|
|
case 6: $sRotate = '90'; break; //Clockwise
|
|
case 8: $sRotate = '-90'; break; //Trigo
|
|
default: $sRotate = '0';
|
|
}
|
|
}
|
|
else $sRotate = '0';
|
|
|
|
return array(
|
|
'timestamp' => $iTimeStamp,
|
|
'taken_ts' => $iTakenOn,
|
|
'file_ts' => $iPostedOn,
|
|
'rotate' => $sRotate
|
|
);
|
|
}
|
|
|
|
private static function getPicThumbnail($sPicName)
|
|
{
|
|
$sPicPath = self::getPicPath($sPicName);
|
|
$sThumbPath = self::getPicPath($sPicName, 'thumbnail');
|
|
|
|
if(!file_exists($sThumbPath)) $asThumbInfo = ToolBox::createThumbnail($sPicPath, 400, 0, $sThumbPath, false, array('jpg', 'jpeg', 'gif', 'png'), false, true);
|
|
else $asThumbInfo = array('error'=>'', 'out'=>$sThumbPath);
|
|
|
|
return ($asThumbInfo['error']=='')?$asThumbInfo['out']:$sPicPath;
|
|
}
|
|
|
|
private static function getPicPath($sPicName, $sFileType='picture') {
|
|
return ($sFileType=='thumbnail'?self::THUMB_FOLDER:self::PIC_FOLDER).$sPicName;
|
|
}
|
|
} |