| Current Path : /home/magalijoj/www/blog/inc/core/ |
| Current File : /home/magalijoj/www/blog/inc/core/class.dc.media.php |
<?php
# ***** BEGIN LICENSE BLOCK *****
# This file is part of DotClear.
# Copyright (c) 2005 Olivier Meunier and contributors. All rights
# reserved.
#
# DotClear is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# DotClear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with DotClear; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# ***** END LICENSE BLOCK *****
/**
@ingroup DC_CORE
@brief Dotclear media manage
This class handles Dotclear media items.
*/
class dcMedia extends filemanager
{
protected $core; ///< <b>dcCore</b> dcCore instance
protected $con; ///< <b>connection</b> Database connection
protected $table; ///< <b>string</b> Media table name
protected $table_ref; ///< <b>string</b> Post-media relation table name
protected $type; ///< <b>string</b> Media type filter
protected $file_handler = array(); ///< <b>array</b> Array of callbacks
public $thumb_tp = '%s/.%s_%s.jpg'; ///< <b>string</b> Thumbnail file pattern
/**
<b>array</b> Tubmnail sizes:
- m: medium image
- s: small image
- t: thumbnail image
- sq: square image
*/
public $thumb_sizes = array(
'm' => array(448,'ratio','medium'),
's' => array(240,'ratio','small'),
't' => array(100,'ratio','thumbnail'),
'sq' => array(48,'crop','square')
);
public $icon_img = 'images/media/%s.png'; ///< <b>string</b> Icon file pattern
/**
Object constructor.
@param core <b>dcCore</b> dcCore instance
@param type <b>string</b> Media type filter
*/
public function __construct(&$core,$type='')
{
$this->core =& $core;
$this->con =& $core->con;
if ($this->core->blog == null) {
throw new Exception(__('No blog defined.'));
}
$this->table = $this->core->prefix.'media';
$this->table_ref = $this->core->prefix.'post_media';
$root = $this->core->blog->public_path;
$root_url = $this->core->blog->host.path::clean($this->core->blog->settings->public_url);
if (!is_dir($root)) {
throw new Exception(sprintf(__('Directory %s does not exist.'),$root));
}
$this->type = $type;
parent::__construct($root,$root_url);
$this->chdir('');
$this->path = $this->core->blog->settings->public_path;
$this->addExclusion(DC_RC_PATH);
$this->addExclusion(dirname(__FILE__).'/../');
# Event handlers
$this->addFileHandler('image/jpeg','create',array($this,'imageThumbCreate'));
$this->addFileHandler('image/png','create',array($this,'imageThumbCreate'));
$this->addFileHandler('image/gif','create',array($this,'imageThumbCreate'));
$this->addFileHandler('image/png','update',array($this,'imageThumbUpdate'));
$this->addFileHandler('image/jpeg','update',array($this,'imageThumbUpdate'));
$this->addFileHandler('image/gif','update',array($this,'imageThumbUpdate'));
$this->addFileHandler('image/png','remove',array($this,'imageThumbRemove'));
$this->addFileHandler('image/jpeg','remove',array($this,'imageThumbRemove'));
$this->addFileHandler('image/gif','remove',array($this,'imageThumbRemove'));
$this->addFileHandler('image/jpeg','create',array($this,'imageMetaCreate'));
}
/**
Changes working directory.
@param dir <b>string</b> Directory name.
*/
public function chdir($dir)
{
parent::chdir($dir);
$this->relpwd = preg_replace('/^'.preg_quote($this->root,'/').'\/?/','',$this->pwd);
}
/**
Adds a new file handler for a given media type and event.
Available events are:
- create: file creation
- update: file update
- remove: file deletion
@param type <b>string</b> Media type
@param event <b>string</b> Event
@param function <b>callback</b>
*/
public function addFileHandler($type,$event,$function)
{
if (is_callable($function)) {
$this->file_handler[$type][$event][] = $function;
}
}
protected function callFileHandler($type,$event)
{
if (!empty($this->file_handler[$type][$event]))
{
$args = func_get_args();
array_shift($args);
array_shift($args);
foreach ($this->file_handler[$type][$event] as $f)
{
call_user_func_array($f,$args);
}
}
}
/**
Returns HTML breadCrumb for media manager navigation.
@param href <b>string</b> URL pattern
@return <b>string</b> HTML code
*/
public function breadCrumb($href)
{
$res = '';
if ($this->relpwd && $this->relpwd != '.') {
$pwd = '';
foreach (explode('/',$this->relpwd) as $v) {
$pwd .= rawurlencode($v).'/';
$res .= '<a href="'.sprintf($href,$pwd).'">'.$v.'</a> / ';
}
}
return $res;
}
protected function fileRecord(&$rs)
{
if ($rs->isEmpty()) { return null; }
if (is_file($this->root.'/'.$rs->media_file))
{
$f = new fileItem($this->root.'/'.$rs->media_file,$this->root,$this->root_url);
if ($this->type && $f->type_prefix != $this->type) {
return null;
}
$f->editable = true;
$f->media_id = $rs->media_id;
$f->media_title = $rs->media_title;
$f->media_meta = $rs->media_meta;
$f->media_user = $rs->user_id;
$f->media_priv = (boolean) $rs->media_private;
$f->media_dt = strtotime($rs->media_dt);
$f->media_dtstr = dt::str('%Y-%m-%d %H:%M',$f->media_dt);
$f->media_image = false;
if (!$this->core->auth->check('media_admin',$this->core->blog->id)
&& $this->core->auth->userID() != $f->media_user) {
$f->del = false;
$f->editable = false;
}
$type_prefix = explode('/',$f->type);
$type_prefix = $type_prefix[0];
switch ($type_prefix) {
case 'image':
$f->media_image = true;
$f->media_icon = 'image';
break;
case 'audio':
$f->media_icon = 'audio';
break;
case 'text':
$f->media_icon = 'text';
break;
case 'video':
$f->media_icon = 'video';
break;
default:
$f->media_icon = 'blank';
}
switch ($f->type) {
case 'application/msword':
case 'application/vnd.oasis.opendocument.text':
case 'application/vnd.sun.xml.writer':
case 'application/pdf':
case 'application/postscript':
$f->media_icon = 'document';
break;
case 'application/msexcel':
case 'application/vnd.oasis.opendocument.spreadsheet':
case 'application/vnd.sun.xml.calc':
$f->media_icon = 'spreadsheet';
break;
case 'application/mspowerpoint':
case 'application/vnd.oasis.opendocument.presentation':
case 'application/vnd.sun.xml.impress':
$f->media_icon = 'presentation';
break;
case 'application/x-debian-package':
case 'application/x-gzip':
case 'application/x-java-archive':
case 'application/rar':
case 'application/x-redhat-package-manager':
case 'application/x-tar':
case 'application/x-gtar':
case 'application/zip':
$f->media_icon = 'package';
break;
case 'application/octet-stream':
$f->media_icon = 'executable';
break;
case 'application/x-shockwave-flash':
$f->media_icon = 'video';
break;
case 'application/ogg':
$f->media_icon = 'audio';
break;
case 'text/html':
$f->media_icon = 'html';
break;
}
$f->media_type = $f->media_icon;
$f->media_icon = sprintf($this->icon_img,$f->media_icon);
# Thumbnails
$f->media_thumb = array();
$p = path::info($f->relname);
$thumb = sprintf($this->thumb_tp,$this->root.'/'.$p['dirname'],$p['base'],'%s');
$thumb_url = sprintf($this->thumb_tp,$this->root_url.$p['dirname'],$p['base'],'%s');
foreach ($this->thumb_sizes as $suffix => $s) {
if (file_exists(sprintf($thumb,$suffix))) {
$f->media_thumb[$suffix] = sprintf($thumb_url,$suffix);
}
}
if (isset($f->media_thumb['sq'])) {
$f->media_icon = $f->media_thumb['sq'];
}
return $f;
}
return null;
}
/**
Gets current working directory content.
@param type <b>string</b> Media type filter
*/
public function getDir($type=null)
{
if ($type) {
$this->type = $type;
}
$media_dir = $this->relpwd ? $this->relpwd : '.';
$strReq =
'SELECT media_file, media_id, media_path, media_title, media_meta, media_dt, '.
'media_creadt, media_upddt, media_private, user_id '.
'FROM '.$this->table.' '.
"WHERE media_path = '".$this->path."' ".
"AND media_dir = '".$this->con->escape($media_dir)."' ";
if (!$this->core->auth->check('media_admin',$this->core->blog->id))
{
$strReq .= 'AND (media_private <> 1 ';
if ($this->core->auth->userID()) {
$strReq .= "OR user_id = '".$this->con->escape($this->core->auth->userID())."'";
}
$strReq .= ') ';
}
$strReq .= 'ORDER BY LOWER(media_file) ASC';
$rs = $this->con->select($strReq);
parent::getDir();
$f_res = array();
$p_dir = $this->dir;
# If type is set, remove items from p_dir
if ($this->type)
{
foreach ($p_dir['files'] as $k => $f) {
if ($f->type_prefix != $this->type) {
unset($p_dir['files'][$k]);
}
}
}
$f_reg = array();
while ($rs->fetch())
{
# File in subdirectory, forget about it!
if (dirname($rs->media_file) != '.' && dirname($rs->media_file) != $this->relpwd) {
continue;
}
if ($this->inFiles($rs->media_file))
{
$f = $this->fileRecord($rs);
if ($f !== null) {
$f_res[] = $this->fileRecord($rs);
$f_reg[$rs->media_file] = 1;
}
}
elseif (!empty($p_dir['files']) && $this->relpwd == '')
{
# Physica file does not exist remove it from DB
# Because we don't want to erase everything on
# dotclear upgrade, do it only if there are files
# in directory and directory is root
$this->con->execute(
'DELETE FROM '.$this->table.' '.
"WHERE media_path = '".$this->con->escape($this->path)."' ".
"AND media_file = '".$this->con->escape($rs->media_file)."' "
);
$this->callFileHandler(files::getMimeType($rs->media_file),'remove',$this->pwd.'/'.$rs->media_file);
}
}
$this->dir['files'] = $f_res;
foreach ($this->dir['dirs'] as $k => $v) {
$v->media_icon = sprintf($this->icon_img,'folder');
}
# Check files that don't exist in database and create them
foreach ($p_dir['files'] as $f)
{
if (!isset($f_reg[$f->relname])) {
if (($id = $this->createFile($f->basename)) !== false) {
$this->dir['files'][] = $this->getFile($id);
}
}
}
}
/**
Gets file by its id. Returns a filteItem object.
@param id <b>integer</b> File ID
@return <b>fileItem</b>
*/
public function getFile($id)
{
$strReq =
'SELECT media_id, media_path, media_title, '.
'media_file, media_meta, media_dt, media_creadt, '.
'media_upddt, media_private, user_id '.
'FROM '.$this->table.' '.
"WHERE media_path = '".$this->path."' ".
'AND media_id = '.(integer) $id.' ';
if (!$this->core->auth->check('media_admin',$this->core->blog->id))
{
$strReq .= 'AND (media_private <> 1 ';
if ($this->core->auth->userID()) {
$strReq .= "OR user_id = '".$this->con->escape($this->core->auth->userID())."'";
}
$strReq .= ') ';
}
$rs = $this->con->select($strReq);
return $this->fileRecord($rs);
}
/**
Returns media items attached to a blog post. Result is an array containing
fileItems objects.
@param post_id <b>integer</b> Post ID
@param media_id <b>integer</b> Optionnal media ID
@return <b>array</b> Array of fileItems
*/
public function getPostMedia($post_id,$media_id=null)
{
$post_id = (integer) $post_id;
$strReq =
'SELECT media_file, M.media_id, media_path, media_title, media_meta, media_dt, '.
'media_creadt, media_upddt, media_private, user_id '.
'FROM '.$this->table.' M, '.$this->table_ref.' PM '.
"WHERE media_path = '".$this->path."' ".
'AND M.media_id = PM.media_id '.
'AND post_id = '.$post_id.' ';
if ($media_id) {
$strReq .= 'AND M.media_id = '.(integer) $media_id.' ';
}
$rs = $this->con->select($strReq);
$res = array();
while ($rs->fetch()) {
$f = $this->fileRecord($rs);
if ($f !== null) {
$res[] = $f;
}
}
return $res;
}
/**
Attaches a media to a post.
@param post_id <b>integer</b> Post ID
@param media_id <b>integer</b> Optionnal media ID
*/
public function addPostMedia($post_id,$media_id)
{
$post_id = (integer) $post_id;
$media_id = (integer) $media_id;
$f = $this->getPostMedia($post_id,$media_id);
if (!empty($f)) {
return;
}
$cur = $this->con->openCursor($this->table_ref);
$cur->post_id = $post_id;
$cur->media_id = $media_id;
$cur->insert();
$this->core->blog->triggerBlog();
}
/**
Detaches a media from a post.
@param post_id <b>integer</b> Post ID
@param media_id <b>integer</b> Optionnal media ID
*/
public function removePostMedia($post_id,$media_id)
{
$post_id = (integer) $post_id;
$media_id = (integer) $media_id;
$strReq = 'DELETE FROM '.$this->table_ref.' '.
'WHERE post_id = '.$post_id.' '.
'AND media_id = '.$media_id.' ';
$this->con->execute($strReq);
$this->core->blog->triggerBlog();
}
/**
Rebuilds database items collection. Optional <var>$pwd</var> parameter is
the path where to start rebuild.
@param pwd <b>string</b> Directory to rebuild
*/
public function rebuild($pwd='')
{
if (!$this->core->auth->isSuperAdmin()) {
throw new Exception(__('You are not a super administrator.'));
}
$this->chdir($pwd);
parent::getDir();
$dir = $this->dir;
foreach ($dir['dirs'] as $d) {
if (!$d->parent) {
$this->rebuild($d->relname,false);
}
}
foreach ($dir['files'] as $f) {
$this->chdir(dirname($f->relname));
$this->createFile($f->basename);
}
$this->rebuildDB($pwd);
}
protected function rebuildDB($pwd)
{
$media_dir = $pwd ? $pwd : '.';
$strReq =
'SELECT media_file, media_id '.
'FROM '.$this->table.' '.
"WHERE media_path = '".$this->path."' ".
"AND media_dir = '".$this->con->escape($media_dir)."' ";
$rs = $this->con->select($strReq);
$delReq = 'DELETE FROM '.$this->table.' '.
'WHERE media_id IN (%s) ';
$del_ids = array();
while ($rs->fetch())
{
if (!is_file($this->root.'/'.$rs->media_file)) {
$del_ids[] = (integer) $rs->media_id;
}
}
if (!empty($del_ids)) {
$this->con->execute(sprintf($delReq,implode(',',$del_ids)));
}
}
/**
Creates or updates a file in database. Returns new media ID or false if
file does not exist.
@param name <b>string</b> File name (relative to working directory)
@param title <b>string</b> File title
@param private <b>boolean</b> File is private
@param dt <b>string</b> File date
@return <b>integer</b> New media ID
*/
public function createFile($name,$title=null,$private=false,$dt=null)
{
if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) {
throw new Exception(__('Permission denied.'));
}
$file = $this->pwd.'/'.$name;
if (!file_exists($file)) {
return false;
}
$media_file = $this->relpwd ? path::clean($this->relpwd.'/'.$name) : path::clean($name);
$media_type = files::getMimeType($name);
$cur = $this->con->openCursor($this->table);
$strReq = 'SELECT media_id '.
'FROM '.$this->table.' '.
"WHERE media_path = '".$this->con->escape($this->path)."' ".
"AND media_file = '".$this->con->escape($media_file)."' ";
$rs = $this->con->select($strReq);
if ($rs->isEmpty())
{
$rs = $this->con->select('SELECT MAX(media_id) FROM '.$this->table);
$media_id = (integer) $rs->f(0) + 1;
$cur->media_id = $media_id;
$cur->user_id = (string) $this->core->auth->userID();
$cur->media_path = (string) $this->path;
$cur->media_file = (string) $media_file;
$cur->media_dir = (string) dirname($media_file);
$cur->media_creadt = array('NOW()');
$cur->media_upddt = array('NOW()');
$cur->media_title = !$title ? (string) $name : (string) $title;
$cur->media_private = (integer) (boolean) $private;
if ($dt) {
$cur->media_dt = (string) $dt;
} else {
$cur->media_dt = strftime('%Y-%m-%d %H:%M:%S',filemtime($file));
}
try {
$cur->insert();
} catch (Exception $e) {
@unlink($name);
throw $e;
}
}
else
{
$media_id = (integer) $rs->media_id;
$cur->media_upddt = array('NOW()');
$cur->update('WHERE media_id = '.$media_id);
}
$this->callFileHandler($media_type,'create',$cur,$name,$media_id);
return $media_id;
}
/**
Updates a file in database.
@param file <b>fileItem</b> Current fileItem object
@param newFile <b>fileItem</b> New fileItem object
*/
public function updateFile($file,$newFile)
{
if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) {
throw new Exception(__('Permission denied.'));
}
$id = (integer) $file->media_id;
if (!$id) {
throw new Exception('No file ID');
}
if (!$this->core->auth->check('media_admin',$this->core->blog->id)
&& $this->core->auth->userID() != $file->media_user) {
throw new Exception(__('You are not the file owner.'));
}
$cur = $this->con->openCursor($this->table);
# We need to tidy newFile basename. If dir isn't empty, concat to basename
$newFile->relname = files::tidyFileName($newFile->basename);
if ($newFile->dir) {
$newFile->relname = $newFile->dir.'/'.$newFile->relname;
}
if ($file->relname != $newFile->relname) {
$newFile->file = $this->root.'/'.$newFile->relname;
if (file_exists($newFile->file)) {
throw new Exception(__('New file already exists.'));
}
$this->moveFile($file->relname,$newFile->relname);
$cur->media_file = (string) $newFile->relname;
$cur->media_dir = (string) dirname($newFile->relname);
}
$cur->media_title = (string) $newFile->media_title;
$cur->media_dt = (string) $newFile->media_dtstr;
$cur->media_upddt = array('NOW()');
$cur->media_private = (integer) $newFile->media_priv;
$cur->update('WHERE media_id = '.$id);
$this->callFileHandler($file->type,'update',$file,$newFile);
}
/**
Uploads a file.
@param tmp <b>string</b> Full path of temporary uploaded file
@param name <b>string</b> File name (relative to working directory)
@param title <b>string</b> File title
@param private <b>boolean</b> File is private
*/
public function uploadFile($tmp,$name,$title=null,$private=false)
{
if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) {
throw new Exception(__('Permission denied.'));
}
$name = files::tidyFileName($name);
parent::uploadFile($tmp,$name);
return $this->createFile($name,$title,$private);
}
/**
Creates a file from binary content.
@param name <b>string</b> File name (relative to working directory)
@param bits <b>string</b> Binary file content
*/
public function uploadBits($name,$bits)
{
if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) {
throw new Exception(__('Permission denied.'));
}
$name = files::tidyFileName($name);
parent::uploadBits($name,$bits);
return $this->createFile($name,null,null);
}
/**
Removes a file.
@param f <b>fileItem</b> fileItem object
*/
public function removeFile($f)
{
if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) {
throw new Exception(__('Permission denied.'));
}
$media_file = $this->relpwd ? path::clean($this->relpwd.'/'.$f) : path::clean($f);
$strReq = 'DELETE FROM '.$this->table.' '.
"WHERE media_path = '".$this->con->escape($this->path)."' ".
"AND media_file = '".$this->con->escape($media_file)."' ";
if (!$this->core->auth->check('media_admin',$this->core->blog->id))
{
$strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."'";
}
$this->con->execute($strReq);
if ($this->con->changes() == 0) {
throw new Exception(__('File does not exist in the database.'));
}
parent::removeFile($f);
$this->callFileHandler(files::getMimeType($media_file),'remove',$f);
}
/* Image handlers
------------------------------------------------------- */
protected function imageThumbCreate(&$cur,$f)
{
$file = $this->pwd.'/'.$f;
if (!file_exists($file)) {
return false;
}
$p = path::info($file);
$thumb = sprintf($this->thumb_tp,$p['dirname'],$p['base'],'%s');
try {
$img = new imageTools();
$img->loadImage($file);
$w = $img->getW();
$h = $img->getH();
foreach ($this->thumb_sizes as $suffix => $s) {
if ($suffix == 'sq' || ($w > $s[0] && $h > $s[0])) {
$img->resize($s[0],$s[0],$s[1]);
$img->output('jpeg',sprintf($thumb,$suffix),80);
}
}
} catch (Exception $e) {}
}
protected function imageThumbUpdate(&$file,&$newFile)
{
if ($file->relname != $newFile->relname)
{
$p = path::info($file->relname);
$thumb_old = sprintf($this->thumb_tp,$p['dirname'],$p['base'],'%s');
$p = path::info($newFile->relname);
$thumb_new = sprintf($this->thumb_tp,$p['dirname'],$p['base'],'%s');
foreach ($this->thumb_sizes as $suffix => $s) {
try {
parent::moveFile(sprintf($thumb_old,$suffix),sprintf($thumb_new,$suffix));
} catch (Exception $e) {}
}
}
}
protected function imageThumbRemove($f)
{
$p = path::info($f);
$thumb = sprintf($this->thumb_tp,'',$p['base'],'%s');
foreach ($this->thumb_sizes as $suffix => $s) {
try {
parent::removeFile(sprintf($thumb,$suffix));
} catch (Exception $e) {}
}
}
protected function imageMetaCreate(&$cur,$f,$id)
{
$file = $this->pwd.'/'.$f;
if (!file_exists($file)) {
return false;
}
$xml = new xmlTag('meta');
$meta = imageMeta::readMeta($file);
$xml->insertNode($meta);
$c = $this->core->con->openCursor($this->table);
$c->media_meta = $xml->toXML();
if ($meta['Title']) {
$c->media_title = $meta['Title'];
} elseif ($meta['Description']) {
$c->media_title = $meta['Description'];
}
if ($meta['DateTimeOriginal'])
{
# We set picture time to user timezone
$media_ts = strtotime($meta['DateTimeOriginal']);
if ($media_ts !== false) {
$o = dt::getTimeOffset($this->core->auth->getInfo('user_tz'),$media_ts);
$c->media_dt = dt::str('%Y-%m-%d %H:%M:%S',$media_ts+$o);
}
}
$c->update('WHERE media_id = '.$id);
}
/**
Returns HTML code for MP3 player
@param url <b>string</b> MP3 URL to play
@param player <b>string</b> Player URL
@return <b>string</b>
*/
public function mp3player($url,$player='player_mp3.swf')
{
$args = $player.'?mp3='.$url.
'&loadingcolor=ff9900'.
'&bgcolor1=eeeeee'.
'&bgcolor2=cccccc'.
'&buttoncolor=0066cc'.
'&buttonovercolor=ff9900'.
'&slidercolor1=cccccc'.
'&slidercolor2=999999'.
'&sliderovercolor=0066cc';
return
'<object type="application/x-shockwave-flash" '.
'data="'.$args.'" '.
'width="200" height="20">'.
'<param name="movie" value="'.$args.'" />'.
'<param name="wmode" value="transparent" />'.
'</object>';
}
public function flvplayer($url,$player='player_flv.swf')
{
$args = 'flv='.$url.
'&width=400'.
'&height=300'.
'&margin=1'.
'&showvolume=1'.
'&showtime=1';
return
'<object type="application/x-shockwave-flash" '.
'data="'.$player.'" '.
'width="400" height="300">'.
'<param name="movie" value="'.$player.'" />'.
'<param name="FlashVars" value="'.$args.'" />'.
'</object>';
}
}
?>