Changeset 3730:5c45a5df9a59 for inc/core/class.dc.media.php
- Timestamp:
- 03/08/18 17:58:39 (8 years ago)
- Branch:
- default
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
inc/core/class.dc.media.php
r3357 r3730 10 10 # 11 11 # -- END LICENSE BLOCK ----------------------------------------- 12 if (!defined('DC_RC_PATH')) { return;}12 if (!defined('DC_RC_PATH')) {return;} 13 13 14 14 /** … … 17 17 18 18 This class handles Dotclear media items. 19 */19 */ 20 20 class dcMedia extends filemanager 21 21 { 22 protected $core; ///< <b>dcCore</b> dcCore instance 23 protected $con; ///< <b>connection</b> Database connection 24 protected $table; ///< <b>string</b> Media table name 25 protected $type; ///< <b>string</b> Media type filter 26 protected $postmedia; 27 protected $file_sort = 'name-asc'; 28 29 protected $file_handler = array(); ///< <b>array</b> Array of callbacks 30 31 public $thumb_tp = '%s/.%s_%s.jpg'; ///< <b>string</b> Thumbnail file pattern 32 public $thumb_tp_alpha = '%s/.%s_%s.png'; ///< <b>string</b> Thumbnail file pattern (with alpha layer) 33 34 /** 35 <b>array</b> Tubmnail sizes: 36 - m: medium image 37 - s: small image 38 - t: thumbnail image 39 - sq: square image 40 */ 41 public $thumb_sizes = array( 42 'm' => array(448,'ratio','medium'), 43 's' => array(240,'ratio','small'), 44 't' => array(100,'ratio','thumbnail'), 45 'sq' => array(48,'crop','square') 46 ); 47 48 public $icon_img = 'images/media/%s.png'; ///< <b>string</b> Icon file pattern 49 50 /** 51 Object constructor. 52 53 @param core <b>dcCore</b> dcCore instance 54 @param type <b>string</b> Media type filter 55 */ 56 public function __construct($core,$type='') 57 { 58 $this->core =& $core; 59 $this->con =& $core->con; 60 $this->postmedia = new dcPostMedia($core); 61 62 if ($this->core->blog == null) { 63 throw new Exception(__('No blog defined.')); 64 } 65 66 $this->table = $this->core->prefix.'media'; 67 $root = $this->core->blog->public_path; 68 69 if (preg_match('#^http(s)?://#',$this->core->blog->settings->system->public_url)) { 70 $root_url = rawurldecode($this->core->blog->settings->system->public_url); 71 } else { 72 $root_url = rawurldecode($this->core->blog->host.path::clean($this->core->blog->settings->system->public_url)); 73 } 74 75 if (!is_dir($root)) { 76 # Check public directory 77 if ( $core->auth->isSuperAdmin() ) { 78 throw new Exception(__("There is no writable directory /public/ at the location set in about:config \"public_path\". You must create this directory with sufficient rights (or change this setting).")); 79 } else { 80 throw new Exception(__("There is no writable root directory for the media manager. You should contact your administrator.")); 81 } 82 } 83 84 $this->type = $type; 85 86 parent::__construct($root,$root_url); 87 $this->chdir(''); 88 89 $this->path = $this->core->blog->settings->system->public_path; 90 91 $this->addExclusion(DC_RC_PATH); 92 $this->addExclusion(dirname(__FILE__).'/../'); 93 94 $this->exclude_pattern = $core->blog->settings->system->media_exclusion; 95 96 # Event handlers 97 $this->addFileHandler('image/jpeg','create',array($this,'imageThumbCreate')); 98 $this->addFileHandler('image/png','create',array($this,'imageThumbCreate')); 99 $this->addFileHandler('image/gif','create',array($this,'imageThumbCreate')); 100 101 $this->addFileHandler('image/png','update',array($this,'imageThumbUpdate')); 102 $this->addFileHandler('image/jpeg','update',array($this,'imageThumbUpdate')); 103 $this->addFileHandler('image/gif','update',array($this,'imageThumbUpdate')); 104 105 $this->addFileHandler('image/png','remove',array($this,'imageThumbRemove')); 106 $this->addFileHandler('image/jpeg','remove',array($this,'imageThumbRemove')); 107 $this->addFileHandler('image/gif','remove',array($this,'imageThumbRemove')); 108 109 $this->addFileHandler('image/jpeg','create',array($this,'imageMetaCreate')); 110 111 $this->addFileHandler('image/jpeg','recreate',array($this,'imageThumbCreate')); 112 $this->addFileHandler('image/png','recreate',array($this,'imageThumbCreate')); 113 $this->addFileHandler('image/gif','recreate',array($this,'imageThumbCreate')); 114 115 $this->addFileHandler('image/jpeg','recreate',array($this,'imageThumbCreate')); 116 $this->addFileHandler('image/png','recreate',array($this,'imageThumbCreate')); 117 $this->addFileHandler('image/gif','recreate',array($this,'imageThumbCreate')); 118 119 # Thumbnails sizes 120 $this->thumb_sizes['m'][0] = abs($core->blog->settings->system->media_img_m_size); 121 $this->thumb_sizes['s'][0] = abs($core->blog->settings->system->media_img_s_size); 122 $this->thumb_sizes['t'][0] = abs($core->blog->settings->system->media_img_t_size); 123 124 # Thumbnails sizes names 125 $this->thumb_sizes['m'][2] = __($this->thumb_sizes['m'][2]); 126 $this->thumb_sizes['s'][2] = __($this->thumb_sizes['s'][2]); 127 $this->thumb_sizes['t'][2] = __($this->thumb_sizes['t'][2]); 128 $this->thumb_sizes['sq'][2] = __($this->thumb_sizes['sq'][2]); 129 130 # --BEHAVIOR-- coreMediaConstruct 131 $this->core->callBehavior('coreMediaConstruct',$this); 132 } 133 134 /** 135 Changes working directory. 136 137 @param dir <b>string</b> Directory name. 138 */ 139 public function chdir($dir) 140 { 141 parent::chdir($dir); 142 $this->relpwd = preg_replace('/^'.preg_quote($this->root,'/').'\/?/','',$this->pwd); 143 } 144 145 /** 146 Adds a new file handler for a given media type and event. 147 148 Available events are: 149 - create: file creation 150 - update: file update 151 - remove: file deletion 152 153 @param type <b>string</b> Media type 154 @param event <b>string</b> Event 155 @param function <b>callback</b> 156 */ 157 public function addFileHandler($type,$event,$function) 158 { 159 if (is_callable($function)) { 160 $this->file_handler[$type][$event][] = $function; 161 } 162 } 163 164 protected function callFileHandler($type,$event) 165 { 166 if (!empty($this->file_handler[$type][$event])) 167 { 168 $args = func_get_args(); 169 array_shift($args); 170 array_shift($args); 171 172 foreach ($this->file_handler[$type][$event] as $f) 173 { 174 call_user_func_array($f,$args); 175 } 176 } 177 } 178 179 /** 180 Returns HTML breadCrumb for media manager navigation. 181 182 @param href <b>string</b> URL pattern 183 @param last <b>string</b> Last item pattern 184 @return <b>string</b> HTML code 185 */ 186 public function breadCrumb($href,$last='') 187 { 188 $res = ''; 189 if ($this->relpwd && $this->relpwd != '.') { 190 $pwd = ''; 191 $arr = explode('/',$this->relpwd); 192 $count = count($arr); 193 foreach ($arr as $v) { 194 if (($last != '') && (0 === --$count)) { 195 $res .= sprintf($last,$v); 196 } else { 197 $pwd .= rawurlencode($v).'/'; 198 $res .= '<a href="'.sprintf($href,$pwd).'">'.$v.'</a> / '; 199 } 200 } 201 } 202 return $res; 203 204 } 205 206 protected function fileRecord($rs) 207 { 208 if ($rs->isEmpty()) { return null; } 209 210 if (!$this->isFileExclude($this->root.'/'.$rs->media_file) && is_file($this->root.'/'.$rs->media_file)) 211 { 212 $f = new fileItem($this->root.'/'.$rs->media_file,$this->root,$this->root_url); 213 214 if ($this->type && $f->type_prefix != $this->type) { 215 return null; 216 } 217 218 $meta = @simplexml_load_string($rs->media_meta); 219 220 $f->editable = true; 221 $f->media_id = $rs->media_id; 222 $f->media_title = $rs->media_title; 223 $f->media_meta = $meta instanceof SimpleXMLElement ? $meta : simplexml_load_string('<meta></meta>'); 224 $f->media_user = $rs->user_id; 225 $f->media_priv = (boolean) $rs->media_private; 226 $f->media_dt = strtotime($rs->media_dt); 227 $f->media_dtstr = dt::str('%Y-%m-%d %H:%M',$f->media_dt); 228 229 $f->media_image = false; 230 231 if (!$this->core->auth->check('media_admin',$this->core->blog->id) 232 && $this->core->auth->userID() != $f->media_user) { 233 $f->del = false; 234 $f->editable = false; 235 } 236 237 $type_prefix = explode('/',$f->type); 238 $type_prefix = $type_prefix[0]; 239 240 switch ($type_prefix) { 241 case 'image': 242 $f->media_image = true; 243 $f->media_icon = 'image'; 244 break; 245 case 'audio': 246 $f->media_icon = 'audio'; 247 break; 248 case 'text': 249 $f->media_icon = 'text'; 250 break; 251 case 'video': 252 $f->media_icon = 'video'; 253 break; 254 default: 255 $f->media_icon = 'blank'; 256 } 257 switch ($f->type) { 258 case 'application/msword': 259 case 'application/vnd.oasis.opendocument.text': 260 case 'application/vnd.sun.xml.writer': 261 case 'application/pdf': 262 case 'application/postscript': 263 $f->media_icon = 'document'; 264 break; 265 case 'application/msexcel': 266 case 'application/vnd.oasis.opendocument.spreadsheet': 267 case 'application/vnd.sun.xml.calc': 268 $f->media_icon = 'spreadsheet'; 269 break; 270 case 'application/mspowerpoint': 271 case 'application/vnd.oasis.opendocument.presentation': 272 case 'application/vnd.sun.xml.impress': 273 $f->media_icon = 'presentation'; 274 break; 275 case 'application/x-debian-package': 276 case 'application/x-bzip': 277 case 'application/x-gzip': 278 case 'application/x-java-archive': 279 case 'application/rar': 280 case 'application/x-redhat-package-manager': 281 case 'application/x-tar': 282 case 'application/x-gtar': 283 case 'application/zip': 284 $f->media_icon = 'package'; 285 break; 286 case 'application/octet-stream': 287 $f->media_icon = 'executable'; 288 break; 289 case 'application/x-shockwave-flash': 290 $f->media_icon = 'video'; 291 break; 292 case 'application/ogg': 293 $f->media_icon = 'audio'; 294 break; 295 case 'text/html': 296 $f->media_icon = 'html'; 297 break; 298 } 299 300 $f->media_type = $f->media_icon; 301 $f->media_icon = sprintf($this->icon_img,$f->media_icon); 302 303 # Thumbnails 304 $f->media_thumb = array(); 305 $p = path::info($f->relname); 306 307 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 308 309 $thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp),$this->root.'/'.$p['dirname'],$p['base'],'%s'); 310 $thumb_url = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp),$this->root_url.$p['dirname'],$p['base'],'%s'); 311 312 # Cleaner URLs 313 $thumb_url = preg_replace('#\./#','/',$thumb_url); 314 $thumb_url = preg_replace('#(?<!:)/+#','/',$thumb_url); 315 316 if ($alpha) { 317 $thumb_alt = sprintf($this->thumb_tp,$this->root.'/'.$p['dirname'],$p['base'],'%s'); 318 $thumb_url_alt = sprintf($this->thumb_tp,$this->root_url.$p['dirname'],$p['base'],'%s'); 319 # Cleaner URLs 320 $thumb_url_alt = preg_replace('#\./#','/',$thumb_url_alt); 321 $thumb_url_alt = preg_replace('#(?<!:)/+#','/',$thumb_url_alt); 322 } 323 324 foreach ($this->thumb_sizes as $suffix => $s) { 325 if (file_exists(sprintf($thumb,$suffix))) { 326 $f->media_thumb[$suffix] = sprintf($thumb_url,$suffix); 327 } elseif ($alpha && file_exists(sprintf($thumb_alt,$suffix))) { 328 $f->media_thumb[$suffix] = sprintf($thumb_url_alt,$suffix); 329 } 330 } 331 332 if (isset($f->media_thumb['sq']) && $f->media_type == 'image') { 333 $f->media_icon = $f->media_thumb['sq']; 334 } 335 336 return $f; 337 } 338 339 return null; 340 } 341 342 343 public function setFileSort($type='name') 344 { 345 if (in_array($type,array('name-asc','name-desc','date-asc','date-desc'))) { 346 $this->file_sort = $type; 347 } 348 } 349 350 protected function sortFileHandler($a,$b) 351 { 352 if (is_null($a) || is_null($b)) { 353 return (is_null($a) ? 1 : -1); 354 } 355 switch ($this->file_sort) 356 { 357 case 'date-asc': 358 if ($a->media_dt == $b->media_dt) { 359 return 0; 360 } 361 return ($a->media_dt < $b->media_dt) ? -1 : 1; 362 case 'date-desc': 363 if ($a->media_dt == $b->media_dt) { 364 return 0; 365 } 366 return ($a->media_dt > $b->media_dt) ? -1 : 1; 367 case 'name-desc': 368 return strcasecmp($b->basename,$a->basename); 369 case 'name-asc': 370 default: 371 return strcasecmp($a->basename,$b->basename); 372 } 373 } 374 375 /** 376 Gets current working directory content (using filesystem) 377 378 */ 379 public function getFSDir() 380 { 381 parent::getDir(); 382 } 383 384 /** 385 Gets current working directory content. 386 387 @param type <b>string</b> Media type filter 388 */ 389 public function getDir($type=null) 390 { 391 if ($type) { 392 $this->type = $type; 393 } 394 395 $media_dir = $this->relpwd ?: '.'; 396 397 $strReq = 398 'SELECT media_file, media_id, media_path, media_title, media_meta, media_dt, '. 399 'media_creadt, media_upddt, media_private, user_id '. 400 'FROM '.$this->table.' '. 401 "WHERE media_path = '".$this->path."' ". 402 "AND media_dir = '".$this->con->escape($media_dir)."' "; 403 404 if (!$this->core->auth->check('media_admin',$this->core->blog->id)) 405 { 406 $strReq .= 'AND (media_private <> 1 '; 407 408 if ($this->core->auth->userID()) { 409 $strReq .= "OR user_id = '".$this->con->escape($this->core->auth->userID())."'"; 410 } 411 $strReq .= ') '; 412 } 413 414 $rs = $this->con->select($strReq); 415 416 parent::getDir(); 417 418 $f_res = array(); 419 $p_dir = $this->dir; 420 421 # If type is set, remove items from p_dir 422 if ($this->type) 423 { 424 foreach ($p_dir['files'] as $k => $f) { 425 if ($f->type_prefix != $this->type) { 426 unset($p_dir['files'][$k]); 427 } 428 } 429 } 430 431 $f_reg = array(); 432 433 while ($rs->fetch()) 434 { 435 # File in subdirectory, forget about it! 436 if (dirname($rs->media_file) != '.' && dirname($rs->media_file) != $this->relpwd) { 437 continue; 438 } 439 440 if ($this->inFiles($rs->media_file)) 441 { 442 $f = $this->fileRecord($rs); 443 if ($f !== null) { 444 if (isset($f_reg[$rs->media_file])) 445 { 446 # That media is duplicated in the database, 447 # time to do a bit of house cleaning. 448 $this->con->execute( 449 'DELETE FROM '.$this->table.' '. 450 "WHERE media_id = ".$this->fileRecord($rs)->media_id 451 ); 452 } else { 453 $f_res[] = $this->fileRecord($rs); 454 $f_reg[$rs->media_file] = 1; 455 } 456 } 457 } 458 elseif (!empty($p_dir['files']) && $this->relpwd == '') 459 { 460 # Physical file does not exist remove it from DB 461 # Because we don't want to erase everything on 462 # dotclear upgrade, do it only if there are files 463 # in directory and directory is root 464 $this->con->execute( 465 'DELETE FROM '.$this->table.' '. 466 "WHERE media_path = '".$this->con->escape($this->path)."' ". 467 "AND media_file = '".$this->con->escape($rs->media_file)."' " 468 ); 469 $this->callFileHandler(files::getMimeType($rs->media_file),'remove',$this->pwd.'/'.$rs->media_file); 470 } 471 } 472 473 $this->dir['files'] = $f_res; 474 foreach ($this->dir['dirs'] as $k => $v) { 475 $v->media_icon = sprintf($this->icon_img,($v->parent ? 'folder-up' : 'folder')); 476 } 477 478 # Check files that don't exist in database and create them 479 if ($this->core->auth->check('media,media_admin',$this->core->blog->id)) 480 { 481 foreach ($p_dir['files'] as $f) 482 { 483 if (!isset($f_reg[$f->relname])) { 484 if (($id = $this->createFile($f->basename,null,false,null,false)) !== false) { 485 $this->dir['files'][] = $this->getFile($id); 486 } 487 } 488 } 489 } 490 try { 491 usort($this->dir['files'],array($this,'sortFileHandler')); 492 } catch (Exception $e) {} 493 } 494 495 /** 496 Gets file by its id. Returns a filteItem object. 497 498 @param id <b>integer</b> File ID 499 @return <b>fileItem</b> 500 */ 501 public function getFile($id) 502 { 503 $strReq = 504 'SELECT media_id, media_path, media_title, '. 505 'media_file, media_meta, media_dt, media_creadt, '. 506 'media_upddt, media_private, user_id '. 507 'FROM '.$this->table.' '. 508 "WHERE media_path = '".$this->path."' ". 509 'AND media_id = '.(integer) $id.' '; 510 511 if (!$this->core->auth->check('media_admin',$this->core->blog->id)) 512 { 513 $strReq .= 'AND (media_private <> 1 '; 514 515 if ($this->core->auth->userID()) { 516 $strReq .= "OR user_id = '".$this->con->escape($this->core->auth->userID())."'"; 517 } 518 $strReq .= ') '; 519 } 520 521 $rs = $this->con->select($strReq); 522 return $this->fileRecord($rs); 523 } 524 525 /** 526 Search into media db (only). 527 528 @param query <b>string</b> Search query 529 @return boolean true or false if nothing found 530 */ 531 public function searchMedia($query) 532 { 533 if ($query == '') { 534 return false; 535 } 536 537 $strReq = 538 'SELECT media_file, media_id, media_path, media_title, media_meta, media_dt, '. 539 'media_creadt, media_upddt, media_private, user_id '. 540 'FROM '.$this->table.' '. 541 "WHERE media_path = '".$this->path."' ". 542 "AND (media_title LIKE '%".$this->con->escape($query)."%' ". 543 " OR media_file LIKE '%".$this->con->escape($query)."%' ". 544 " OR media_meta LIKE '<Description>%".$this->con->escape($query)."%</Description>')"; 545 546 if (!$this->core->auth->check('media_admin',$this->core->blog->id)) 547 { 548 $strReq .= 'AND (media_private <> 1 '; 549 550 if ($this->core->auth->userID()) { 551 $strReq .= "OR user_id = '".$this->con->escape($this->core->auth->userID())."'"; 552 } 553 $strReq .= ') '; 554 } 555 556 $rs = $this->con->select($strReq); 557 558 $this->dir = array('dirs' => array(),'files' => array()); 559 $f_res = array(); 560 while ($rs->fetch()) 561 { 562 $fr = $this->fileRecord($rs); 563 if ($fr) { 564 $f_res[] = $fr; 565 } 566 } 567 $this->dir['files'] = $f_res; 568 569 try { 570 usort($this->dir['files'],array($this,'sortFileHandler')); 571 } catch (Exception $e) {} 572 573 return (count($f_res) > 0 ? true : false); 574 } 575 576 /** 577 Returns media items attached to a blog post. Result is an array containing 578 fileItems objects. 579 580 @param post_id <b>integer</b> Post ID 581 @param media_id <b>integer</b> Optionnal media ID 582 @param link_type <b>string</b> Optionnal link type 583 @return <b>array</b> Array of fileItems 584 */ 585 public function getPostMedia($post_id,$media_id=null,$link_type=null) 586 { 587 $params = array( 588 'post_id' => $post_id, 589 'media_path' => $this->path 590 ); 591 if ($media_id) { 592 $params['media_id'] = (integer) $media_id; 593 } 594 if ($link_type) { 595 $params['link_type'] = $link_type; 596 } 597 $rs = $this->postmedia->getPostMedia($params); 598 599 $res = array(); 600 601 while ($rs->fetch()) { 602 $f = $this->fileRecord($rs); 603 if ($f !== null) { 604 $res[] = $f; 605 } 606 } 607 608 return $res; 609 } 610 611 /** 612 @deprecated since version 2.4 613 @see dcPostMedia::addPostMedia 614 */ 615 public function addPostMedia($post_id,$media_id,$link_type='attachment') 616 { 617 $this->postmedia->addPostMedia($post_id,$media_id,$link_type); 618 } 619 620 /** 621 @deprecated since version 2.4 622 @see dcPostMedia::removePostMedia 623 */ 624 public function removePostMedia($post_id,$media_id,$link_type='attachment') 625 { 626 $this->postmedia->removePostMedia($post_id,$media_id,$link_type); 627 } 628 629 /** 630 Rebuilds database items collection. Optional <var>$pwd</var> parameter is 631 the path where to start rebuild. 632 633 @param pwd <b>string</b> Directory to rebuild 634 */ 635 public function rebuild($pwd='') 636 { 637 if (!$this->core->auth->isSuperAdmin()) { 638 throw new Exception(__('You are not a super administrator.')); 639 } 640 641 $this->chdir($pwd); 642 parent::getDir(); 643 644 $dir = $this->dir; 645 646 foreach ($dir['dirs'] as $d) { 647 if (!$d->parent) { 648 $this->rebuild($d->relname,false); 649 } 650 } 651 652 foreach ($dir['files'] as $f) { 653 $this->chdir(dirname($f->relname)); 654 $this->createFile($f->basename); 655 } 656 657 $this->rebuildDB($pwd); 658 } 659 660 protected function rebuildDB($pwd) 661 { 662 $media_dir = $pwd ?: '.'; 663 664 $strReq = 665 'SELECT media_file, media_id '. 666 'FROM '.$this->table.' '. 667 "WHERE media_path = '".$this->path."' ". 668 "AND media_dir = '".$this->con->escape($media_dir)."' "; 669 670 $rs = $this->con->select($strReq); 671 672 $delReq = 'DELETE FROM '.$this->table.' '. 673 'WHERE media_id IN (%s) '; 674 $del_ids = array(); 675 676 while ($rs->fetch()) 677 { 678 if (!is_file($this->root.'/'.$rs->media_file)) { 679 $del_ids[] = (integer) $rs->media_id; 680 } 681 } 682 683 if (!empty($del_ids)) { 684 $this->con->execute(sprintf($delReq,implode(',',$del_ids))); 685 } 686 } 687 688 public function makeDir($d) 689 { 690 $d = files::tidyFileName($d); 691 parent::makeDir($d); 692 } 693 694 /** 695 Creates or updates a file in database. Returns new media ID or false if 696 file does not exist. 697 698 @param name <b>string</b> File name (relative to working directory) 699 @param title <b>string</b> File title 700 @param private <b>boolean</b> File is private 701 @param dt <b>string</b> File date 702 @return <b>integer</b> New media ID 703 */ 704 public function createFile($name,$title=null,$private=false,$dt=null,$force=true) 705 { 706 if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) { 707 throw new Exception(__('Permission denied.')); 708 } 709 710 $file = $this->pwd.'/'.$name; 711 if (!file_exists($file)) { 712 return false; 713 } 714 715 $media_file = $this->relpwd ? path::clean($this->relpwd.'/'.$name) : path::clean($name); 716 $media_type = files::getMimeType($name); 717 718 $cur = $this->con->openCursor($this->table); 719 720 $strReq = 'SELECT media_id '. 721 'FROM '.$this->table.' '. 722 "WHERE media_path = '".$this->con->escape($this->path)."' ". 723 "AND media_file = '".$this->con->escape($media_file)."' "; 724 725 $rs = $this->con->select($strReq); 726 727 if ($rs->isEmpty()) 728 { 729 $this->con->writeLock($this->table); 730 try 731 { 732 $rs = $this->con->select('SELECT MAX(media_id) FROM '.$this->table); 733 $media_id = (integer) $rs->f(0) + 1; 734 735 $cur->media_id = $media_id; 736 $cur->user_id = (string) $this->core->auth->userID(); 737 $cur->media_path = (string) $this->path; 738 $cur->media_file = (string) $media_file; 739 $cur->media_dir = (string) dirname($media_file); 740 $cur->media_creadt = date('Y-m-d H:i:s'); 741 $cur->media_upddt = date('Y-m-d H:i:s'); 742 743 $cur->media_title = !$title ? (string) $name : (string) $title; 744 $cur->media_private = (integer) (boolean) $private; 745 746 if ($dt) { 747 $cur->media_dt = (string) $dt; 748 } else { 749 $cur->media_dt = strftime('%Y-%m-%d %H:%M:%S',filemtime($file)); 750 } 751 752 try { 753 $cur->insert(); 754 } catch (Exception $e) { 755 @unlink($name); 756 throw $e; 757 } 758 $this->con->unlock(); 759 } 760 catch (Exception $e) 761 { 762 $this->con->unlock(); 763 throw $e; 764 } 765 } 766 else 767 { 768 $media_id = (integer) $rs->media_id; 769 770 $cur->media_upddt = date('Y-m-d H:i:s'); 771 772 $cur->update('WHERE media_id = '.$media_id); 773 } 774 775 $this->callFileHandler($media_type,'create',$cur,$name,$media_id,$force); 776 777 return $media_id; 778 } 779 780 /** 781 Updates a file in database. 782 783 @param file <b>fileItem</b> Current fileItem object 784 @param newFile <b>fileItem</b> New fileItem object 785 */ 786 public function updateFile($file,$newFile) 787 { 788 if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) { 789 throw new Exception(__('Permission denied.')); 790 } 791 792 $id = (integer) $file->media_id; 793 794 if (!$id) { 795 throw new Exception('No file ID'); 796 } 797 798 if (!$this->core->auth->check('media_admin',$this->core->blog->id) 799 && $this->core->auth->userID() != $file->media_user) { 800 throw new Exception(__('You are not the file owner.')); 801 } 802 803 $cur = $this->con->openCursor($this->table); 804 805 # We need to tidy newFile basename. If dir isn't empty, concat to basename 806 $newFile->relname = files::tidyFileName($newFile->basename); 807 if ($newFile->dir) { 808 $newFile->relname = $newFile->dir.'/'.$newFile->relname; 809 } 810 811 if ($file->relname != $newFile->relname) { 812 $newFile->file = $this->root.'/'.$newFile->relname; 813 814 if ($this->isFileExclude($newFile->relname)) { 815 throw new Exception(__('This file is not allowed.')); 816 } 817 818 if (file_exists($newFile->file)) { 819 throw new Exception(__('New file already exists.')); 820 } 821 822 $this->moveFile($file->relname,$newFile->relname); 823 824 $cur->media_file = (string) $newFile->relname; 825 $cur->media_dir = (string) dirname($newFile->relname); 826 } 827 828 $cur->media_title = (string) $newFile->media_title; 829 $cur->media_dt = (string) $newFile->media_dtstr; 830 $cur->media_upddt = date('Y-m-d H:i:s'); 831 $cur->media_private = (integer) $newFile->media_priv; 832 833 $cur->update('WHERE media_id = '.$id); 834 835 $this->callFileHandler($file->type,'update',$file,$newFile); 836 } 837 838 /** 839 Uploads a file. 840 841 @param tmp <b>string</b> Full path of temporary uploaded file 842 @param name <b>string</b> File name (relative to working directory) 843 @param title <b>string</b> File title 844 @param private <b>boolean</b> File is private 845 */ 846 public function uploadFile($tmp,$name,$title=null,$private=false,$overwrite=false) 847 { 848 if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) { 849 throw new Exception(__('Permission denied.')); 850 } 851 852 $name = files::tidyFileName($name); 853 854 parent::uploadFile($tmp,$name,$overwrite); 855 856 return $this->createFile($name,$title,$private); 857 } 858 859 /** 860 Creates a file from binary content. 861 862 @param name <b>string</b> File name (relative to working directory) 863 @param bits <b>string</b> Binary file content 864 */ 865 public function uploadBits($name,$bits) 866 { 867 if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) { 868 throw new Exception(__('Permission denied.')); 869 } 870 871 $name = files::tidyFileName($name); 872 873 parent::uploadBits($name,$bits); 874 875 return $this->createFile($name,null,null); 876 } 877 878 /** 879 Removes a file. 880 881 @param f <b>fileItem</b> fileItem object 882 */ 883 public function removeFile($f) 884 { 885 if (!$this->core->auth->check('media,media_admin',$this->core->blog->id)) { 886 throw new Exception(__('Permission denied.')); 887 } 888 889 $media_file = $this->relpwd ? path::clean($this->relpwd.'/'.$f) : path::clean($f); 890 891 $strReq = 'DELETE FROM '.$this->table.' '. 892 "WHERE media_path = '".$this->con->escape($this->path)."' ". 893 "AND media_file = '".$this->con->escape($media_file)."' "; 894 895 if (!$this->core->auth->check('media_admin',$this->core->blog->id)) 896 { 897 $strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."'"; 898 } 899 900 $this->con->execute($strReq); 901 902 if ($this->con->changes() == 0) { 903 throw new Exception(__('File does not exist in the database.')); 904 } 905 906 parent::removeFile($f); 907 908 $this->callFileHandler(files::getMimeType($media_file),'remove',$f); 909 } 910 911 /** 912 * Root directories 913 * 914 * Returns an array of directory under {@link $root} directory. 915 * 916 * @uses fileItem 917 * @return array 918 */ 919 public function getDBDirs() 920 { 921 $media_dir = $this->relpwd ?: '.'; 922 923 $strReq = 924 'SELECT distinct media_dir '. 925 'FROM '.$this->table.' '. 926 "WHERE media_path = '".$this->path."'"; 927 $rs = $this->con->select($strReq); 928 while ($rs->fetch()) { 929 if (is_dir($this->root.'/'.$rs->media_dir)) 930 $dir[] = ($rs->media_dir == '.' ? '' : $rs->media_dir); 931 } 932 933 return $dir; 934 } 935 936 /** 937 Extract zip file in current location 938 939 @param f <b>fileRecord</b> fileRecord object 940 */ 941 public function inflateZipFile($f,$create_dir=true) 942 { 943 $zip = new fileUnzip($f->file); 944 $zip->setExcludePattern($this->exclude_pattern); 945 $list = $zip->getList(false,'#(^|/)(__MACOSX|\.svn|\.DS_Store|\.directory|Thumbs\.db)(/|$)#'); 946 947 if ($create_dir) 948 { 949 $zip_root_dir = $zip->getRootDir(); 950 if ($zip_root_dir != false) { 951 $destination = $zip_root_dir; 952 $target = $f->dir; 953 } else { 954 $destination = preg_replace('/\.([^.]+)$/','',$f->basename); 955 $target = $f->dir.'/'.$destination; 956 } 957 958 if (is_dir($f->dir.'/'.$destination)) { 959 throw new Exception(sprintf(__('Extract destination directory %s already exists.'),dirname($f->relname).'/'.$destination)); 960 } 961 } 962 else 963 { 964 $target = $f->dir; 965 $destination = ''; 966 } 967 968 $zip->unzipAll($target); 969 $zip->close(); 970 971 // Clean-up all extracted filenames 972 $clean = function ($name) { 973 $n = text::deaccent($name); 974 $n = preg_replace('/^[.]/u','',$n); 975 return preg_replace('/[^A-Za-z0-9._\-\/]/u','_',$n); 976 }; 977 foreach ($list as $zk => $zv) { 978 // Check if extracted file exists 979 $zf = $target.'/'.$zk; 980 if (!$zv['is_dir'] && file_exists($zf)) { 981 $zt = $clean($zf); 982 if ($zt != $zf) { 983 rename($zf,$zt); 984 } 985 } 986 } 987 988 return dirname($f->relname).'/'.$destination; 989 } 990 991 /** 992 Returns zip file content 993 994 @param f <b>fileRecord</b> fileRecord object 995 @return <b>array</b> 996 */ 997 public function getZipContent($f) 998 { 999 $zip = new fileUnzip($f->file); 1000 $list = $zip->getList(false,'#(^|/)(__MACOSX|\.svn|\.DS_Store|\.directory|Thumbs\.db)(/|$)#'); 1001 $zip->close(); 1002 return $list; 1003 } 1004 1005 /** 1006 Calls file handlers registered for recreate event 1007 1008 @param f <b>fileItem</b> fileItem object 1009 */ 1010 public function mediaFireRecreateEvent($f) 1011 { 1012 $media_type = files::getMimeType($f->basename); 1013 $this->callFileHandler($media_type,'recreate',null,$f->basename); // Args list to be completed as necessary (Franck) 1014 } 1015 1016 /* Image handlers 1017 ------------------------------------------------------- */ 1018 public function imageThumbCreate($cur,$f,$force=true) 1019 { 1020 $file = $this->pwd.'/'.$f; 1021 1022 if (!file_exists($file)) { 1023 return false; 1024 } 1025 1026 $p = path::info($file); 1027 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 1028 $thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp),$p['dirname'],$p['base'],'%s'); 1029 1030 try 1031 { 1032 $img = new imageTools(); 1033 $img->loadImage($file); 1034 1035 $w = $img->getW(); 1036 $h = $img->getH(); 1037 1038 if ($force) $this->imageThumbRemove($f); 1039 1040 foreach ($this->thumb_sizes as $suffix => $s) { 1041 $thumb_file = sprintf($thumb,$suffix); 1042 if (!file_exists($thumb_file) && $s[0] > 0 && 1043 ($suffix == 'sq' || $w > $s[0] || $h > $s[0])) 1044 { 1045 $rate = ($s[0] < 100 ? 95 : ($s[0] < 600 ? 90 : 85)); 1046 $img->resize($s[0],$s[0],$s[1]); 1047 $img->output(($alpha ? 'png' : 'jpeg'),$thumb_file,$rate); 1048 $img->loadImage($file); 1049 } 1050 } 1051 $img->close(); 1052 } 1053 catch (Exception $e) 1054 { 1055 if ($cur === null) { # Called only if cursor is null (public call) 1056 throw $e; 1057 } 1058 } 1059 } 1060 1061 protected function imageThumbUpdate($file,$newFile) 1062 { 1063 if ($file->relname != $newFile->relname) 1064 { 1065 $p = path::info($file->relname); 1066 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 1067 $thumb_old = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp),$p['dirname'],$p['base'],'%s'); 1068 1069 $p = path::info($newFile->relname); 1070 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 1071 $thumb_new = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp),$p['dirname'],$p['base'],'%s'); 1072 1073 foreach ($this->thumb_sizes as $suffix => $s) { 1074 try { 1075 parent::moveFile(sprintf($thumb_old,$suffix),sprintf($thumb_new,$suffix)); 1076 } catch (Exception $e) {} 1077 } 1078 } 1079 } 1080 1081 public function imageThumbRemove($f) 1082 { 1083 $p = path::info($f); 1084 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 1085 $thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp),'',$p['base'],'%s'); 1086 1087 foreach ($this->thumb_sizes as $suffix => $s) { 1088 try { 1089 parent::removeFile(sprintf($thumb,$suffix)); 1090 } catch (Exception $e) {} 1091 } 1092 } 1093 1094 protected function imageMetaCreate($cur,$f,$id) 1095 { 1096 $file = $this->pwd.'/'.$f; 1097 1098 if (!file_exists($file)) { 1099 return false; 1100 } 1101 1102 $xml = new xmlTag('meta'); 1103 $meta = imageMeta::readMeta($file); 1104 $xml->insertNode($meta); 1105 1106 $c = $this->core->con->openCursor($this->table); 1107 $c->media_meta = $xml->toXML(); 1108 1109 if ($cur->media_title !== null && $cur->media_title == basename($cur->media_file)) 1110 { 1111 if ($meta['Title']) { 1112 $c->media_title = $meta['Title']; 1113 } 1114 } 1115 1116 if ($meta['DateTimeOriginal'] && $cur->media_dt === '') 1117 { 1118 # We set picture time to user timezone 1119 $media_ts = strtotime($meta['DateTimeOriginal']); 1120 if ($media_ts !== false) { 1121 $o = dt::getTimeOffset($this->core->auth->getInfo('user_tz'),$media_ts); 1122 $c->media_dt = dt::str('%Y-%m-%d %H:%M:%S',$media_ts+$o); 1123 } 1124 } 1125 1126 $c->update('WHERE media_id = '.$id); 1127 } 1128 1129 /** 1130 Returns HTML code for audio player (HTML5 and if possible fallback Flash player) 1131 1132 @param type <b>string</b> audio mime type 1133 @param url <b>string</b> audio URL to play 1134 @param player <b>string</b> Player URL (flash player fallback) 1135 @param args <b>array</b> Player parameters (flash player fallback) 1136 @param fallback <b>boolean</b> Include Flash player fallback 1137 @param preload <b>boolean</b> Add preload="auto" attribute if true, else preload="none" 1138 @return <b>string</b> 1139 */ 1140 public static function audioPlayer($type,$url,$player=null,$args=null,$fallback=true,$preload=true) 1141 { 1142 $audio = 1143 '<audio controls preload="'.($preload ? 'auto' : 'none').'">'. 1144 '<source src="'.$url.'">'; 1145 1146 if ($fallback && $type == 'audio/mpeg3') { 1147 // Include Flash player fallback 1148 if (!$player) { 1149 $player = 'player_mp3.swf'; 1150 } 1151 1152 if (!is_array($args)) 1153 { 1154 $args = array( 1155 'showvolume' => 1, 1156 'loadingcolor' => 'ff9900', 1157 'bgcolor1' => 'eeeeee', 1158 'bgcolor2' => 'cccccc', 1159 'buttoncolor' => '0066cc', 1160 'buttonovercolor' => 'ff9900', 1161 'slidercolor1' => 'cccccc', 1162 'slidercolor2' => '999999', 1163 'sliderovercolor' => '0066cc' 1164 ); 1165 } 1166 1167 $args['mp3'] = $url; 1168 1169 if (empty($args['width'])) { 1170 $args['width'] = 200; 1171 } 1172 if (empty($args['height'])) { 1173 $args['height'] = 20; 1174 } 1175 1176 $vars = array(); 1177 foreach ($args as $k => $v) { 1178 $vars[] = $k.'='.$v; 1179 } 1180 1181 $audio .= 1182 '<object type="application/x-shockwave-flash" '. 1183 'data="'.$player.'" '. 1184 'width="'.$args['width'].'" height="'.$args['height'].'">'. 1185 '<param name="movie" value="'.$player.'" />'. 1186 '<param name="wmode" value="transparent" />'. 1187 '<param name="FlashVars" value="'.implode('&',$vars).'" />'. 1188 __('Embedded Audio Player'). 1189 '</object>'; 1190 } 1191 1192 $audio .= 1193 '</audio>'; 1194 1195 return $audio; 1196 } 1197 1198 /** 1199 Returns HTML code for video player (HTML5 and if possible fallback Flash player) 1200 1201 @param type <b>string</b> video mime type 1202 @param url <b>string</b> video URL to play 1203 @param player <b>string</b> Player URL (flash player fallback) 1204 @param args <b>array</b> Player parameters (flash player fallback) 1205 @param fallback <b>boolean</b> Include Flash player fallback (if not .flv) 1206 @param preload <b>boolean</b> Add preload="auto" attribute if true, else preload="none" 1207 @return <b>string</b> 1208 */ 1209 public static function videoPlayer($type,$url,$player=null,$args=null,$fallback=true,$preload=true) 1210 { 1211 $video = ''; 1212 1213 // Cope with width and height, if given 1214 $width = 400; 1215 $height = 300; 1216 if (is_array($args)) { 1217 if (!empty($args['width']) && $args['width']) { 1218 $width = (int) $args['width']; 1219 } 1220 if (!empty($args['height']) && $args['height']) { 1221 $height = (int) $args['height']; 1222 } 1223 } 1224 1225 if ($type != 'video/x-flv') { 1226 $video = 1227 '<video controls preload="'.($preload ? 'auto' : 'none').'"'. 1228 ($width ? ' width="'.$width.'"' : ''). 1229 ($height ? ' height="'.$height.'"' : '').'>'. 1230 '<source src="'.$url.'">'; 1231 } 1232 1233 if ($type == 'video/x-flv' || ($fallback && ($type == 'video/mp4' || $type == 'video/x-m4v'))) 1234 { 1235 // Include Flash player fallback 1236 if (!$player) { 1237 $player = 'player_flv.swf'; 1238 } 1239 1240 if (!is_array($args)) 1241 { 1242 $args = array( 1243 'margin' => 1, 1244 'showvolume' => 1, 1245 'showtime' => 1, 1246 'showfullscreen' => 1, 1247 'buttonovercolor' => 'ff9900', 1248 'slidercolor1' => 'cccccc', 1249 'slidercolor2' => '999999', 1250 'sliderovercolor' => '0066cc' 1251 ); 1252 } 1253 1254 $args['flv'] = $url; 1255 1256 if (empty($args['width'])) { 1257 $args['width'] = 400; 1258 } 1259 if (empty($args['height'])) { 1260 $args['height'] = 300; 1261 } 1262 1263 $vars = array(); 1264 foreach ($args as $k => $v) { 1265 $vars[] = $k.'='.$v; 1266 } 1267 1268 $video .= 1269 '<object type="application/x-shockwave-flash" '. 1270 'data="'.$player.'" '. 1271 'width="'.$args['width'].'" height="'.$args['height'].'">'. 1272 '<param name="movie" value="'.$player.'" />'. 1273 '<param name="wmode" value="transparent" />'. 1274 '<param name="allowFullScreen" value="true" />'. 1275 '<param name="FlashVars" value="'.implode('&',$vars).'" />'. 1276 __('Embedded Video Player'). 1277 '</object>'; 1278 } 1279 1280 if ($type != 'video/x-flv') { 1281 $video .= 1282 '</video>'; 1283 } 1284 1285 return $video; 1286 } 1287 1288 /** 1289 Returns HTML code for MP3 player 1290 1291 @param url <b>string</b> MP3 URL to play 1292 @param player <b>string</b> Player URL 1293 @param args <b>array</b> Player parameters 1294 @param fallback <b>boolean</b> Include Flash player fallback 1295 @param preload <b>boolean</b> Add preload="auto" attribute if true, else preload="none" 1296 @return <b>string</b> 1297 */ 1298 public static function mp3player($url,$player=null,$args=null,$fallback=true,$preload=true) 1299 { 1300 if (!$player) { 1301 $player = 'player_mp3.swf'; 1302 } 1303 1304 if (!is_array($args)) 1305 { 1306 $args = array( 1307 'showvolume' => 1, 1308 'loadingcolor' => 'ff9900', 1309 'bgcolor1' => 'eeeeee', 1310 'bgcolor2' => 'cccccc', 1311 'buttoncolor' => '0066cc', 1312 'buttonovercolor' => 'ff9900', 1313 'slidercolor1' => 'cccccc', 1314 'slidercolor2' => '999999', 1315 'sliderovercolor' => '0066cc' 1316 ); 1317 } 1318 1319 $args['mp3'] = $url; 1320 1321 if (empty($args['width'])) { 1322 $args['width'] = 200; 1323 } 1324 if (empty($args['height'])) { 1325 $args['height'] = 20; 1326 } 1327 1328 $vars = array(); 1329 foreach ($args as $k => $v) { 1330 $vars[] = $k.'='.$v; 1331 } 1332 1333 return 1334 '<audio controls preload="'.($preload ? 'auto' : 'none').'">'. 1335 '<source src="'.$url.'" type="audio/mpeg">'. 1336 ($fallback ? 1337 '<object type="application/x-shockwave-flash" '. 1338 'data="'.$player.'" '. 1339 'width="'.$args['width'].'" height="'.$args['height'].'">'. 1340 '<param name="movie" value="'.$player.'" />'. 1341 '<param name="wmode" value="transparent" />'. 1342 '<param name="FlashVars" value="'.implode('&',$vars).'" />'. 1343 __('Embedded Audio Player'). 1344 '</object>' : ''). 1345 '</audio>'; 1346 } 1347 1348 /** 1349 Returns HTML code for FLV player 1350 1351 @param url <b>string</b> FLV URL to play 1352 @param player <b>string</b> Player URL 1353 @param args <b>array</b> Player parameters 1354 @return <b>string</b> 1355 */ 1356 public static function flvplayer($url,$player=null,$args=null) 1357 { 1358 if (!$player) { 1359 $player = 'player_flv.swf'; 1360 } 1361 1362 if (!is_array($args)) 1363 { 1364 $args = array( 1365 'margin' => 1, 1366 'showvolume' => 1, 1367 'showtime' => 1, 1368 'showfullscreen' => 1, 1369 'buttonovercolor' => 'ff9900', 1370 'slidercolor1' => 'cccccc', 1371 'slidercolor2' => '999999', 1372 'sliderovercolor' => '0066cc' 1373 ); 1374 } 1375 1376 $args['flv'] = $url; 1377 1378 if (empty($args['width'])) { 1379 $args['width'] = 400; 1380 } 1381 if (empty($args['height'])) { 1382 $args['height'] = 300; 1383 } 1384 1385 $vars = array(); 1386 foreach ($args as $k => $v) { 1387 $vars[] = $k.'='.$v; 1388 } 1389 1390 return 1391 '<object type="application/x-shockwave-flash" '. 1392 'data="'.$player.'" '. 1393 'width="'.$args['width'].'" height="'.$args['height'].'">'. 1394 '<param name="movie" value="'.$player.'" />'. 1395 '<param name="wmode" value="transparent" />'. 1396 '<param name="allowFullScreen" value="true" />'. 1397 '<param name="FlashVars" value="'.implode('&',$vars).'" />'. 1398 __('Embedded Video Player'). 1399 '</object>'; 1400 } 22 protected $core; ///< <b>dcCore</b> dcCore instance 23 protected $con; ///< <b>connection</b> Database connection 24 protected $table; ///< <b>string</b> Media table name 25 protected $type; ///< <b>string</b> Media type filter 26 protected $postmedia; 27 protected $file_sort = 'name-asc'; 28 29 protected $file_handler = array(); ///< <b>array</b> Array of callbacks 30 31 public $thumb_tp = '%s/.%s_%s.jpg'; ///< <b>string</b> Thumbnail file pattern 32 public $thumb_tp_alpha = '%s/.%s_%s.png'; ///< <b>string</b> Thumbnail file pattern (with alpha layer) 33 34 /** 35 <b>array</b> Tubmnail sizes: 36 - m: medium image 37 - s: small image 38 - t: thumbnail image 39 - sq: square image 40 */ 41 public $thumb_sizes = array( 42 'm' => array(448, 'ratio', 'medium'), 43 's' => array(240, 'ratio', 'small'), 44 't' => array(100, 'ratio', 'thumbnail'), 45 'sq' => array(48, 'crop', 'square') 46 ); 47 48 public $icon_img = 'images/media/%s.png'; ///< <b>string</b> Icon file pattern 49 50 /** 51 Object constructor. 52 53 @param core <b>dcCore</b> dcCore instance 54 @param type <b>string</b> Media type filter 55 */ 56 public function __construct($core, $type = '') 57 { 58 $this->core = &$core; 59 $this->con = &$core->con; 60 $this->postmedia = new dcPostMedia($core); 61 62 if ($this->core->blog == null) { 63 throw new Exception(__('No blog defined.')); 64 } 65 66 $this->table = $this->core->prefix . 'media'; 67 $root = $this->core->blog->public_path; 68 69 if (preg_match('#^http(s)?://#', $this->core->blog->settings->system->public_url)) { 70 $root_url = rawurldecode($this->core->blog->settings->system->public_url); 71 } else { 72 $root_url = rawurldecode($this->core->blog->host . path::clean($this->core->blog->settings->system->public_url)); 73 } 74 75 if (!is_dir($root)) { 76 # Check public directory 77 if ($core->auth->isSuperAdmin()) { 78 throw new Exception(__("There is no writable directory /public/ at the location set in about:config \"public_path\". You must create this directory with sufficient rights (or change this setting).")); 79 } else { 80 throw new Exception(__("There is no writable root directory for the media manager. You should contact your administrator.")); 81 } 82 } 83 84 $this->type = $type; 85 86 parent::__construct($root, $root_url); 87 $this->chdir(''); 88 89 $this->path = $this->core->blog->settings->system->public_path; 90 91 $this->addExclusion(DC_RC_PATH); 92 $this->addExclusion(dirname(__FILE__) . '/../'); 93 94 $this->exclude_pattern = $core->blog->settings->system->media_exclusion; 95 96 # Event handlers 97 $this->addFileHandler('image/jpeg', 'create', array($this, 'imageThumbCreate')); 98 $this->addFileHandler('image/png', 'create', array($this, 'imageThumbCreate')); 99 $this->addFileHandler('image/gif', 'create', array($this, 'imageThumbCreate')); 100 101 $this->addFileHandler('image/png', 'update', array($this, 'imageThumbUpdate')); 102 $this->addFileHandler('image/jpeg', 'update', array($this, 'imageThumbUpdate')); 103 $this->addFileHandler('image/gif', 'update', array($this, 'imageThumbUpdate')); 104 105 $this->addFileHandler('image/png', 'remove', array($this, 'imageThumbRemove')); 106 $this->addFileHandler('image/jpeg', 'remove', array($this, 'imageThumbRemove')); 107 $this->addFileHandler('image/gif', 'remove', array($this, 'imageThumbRemove')); 108 109 $this->addFileHandler('image/jpeg', 'create', array($this, 'imageMetaCreate')); 110 111 $this->addFileHandler('image/jpeg', 'recreate', array($this, 'imageThumbCreate')); 112 $this->addFileHandler('image/png', 'recreate', array($this, 'imageThumbCreate')); 113 $this->addFileHandler('image/gif', 'recreate', array($this, 'imageThumbCreate')); 114 115 $this->addFileHandler('image/jpeg', 'recreate', array($this, 'imageThumbCreate')); 116 $this->addFileHandler('image/png', 'recreate', array($this, 'imageThumbCreate')); 117 $this->addFileHandler('image/gif', 'recreate', array($this, 'imageThumbCreate')); 118 119 # Thumbnails sizes 120 $this->thumb_sizes['m'][0] = abs($core->blog->settings->system->media_img_m_size); 121 $this->thumb_sizes['s'][0] = abs($core->blog->settings->system->media_img_s_size); 122 $this->thumb_sizes['t'][0] = abs($core->blog->settings->system->media_img_t_size); 123 124 # Thumbnails sizes names 125 $this->thumb_sizes['m'][2] = __($this->thumb_sizes['m'][2]); 126 $this->thumb_sizes['s'][2] = __($this->thumb_sizes['s'][2]); 127 $this->thumb_sizes['t'][2] = __($this->thumb_sizes['t'][2]); 128 $this->thumb_sizes['sq'][2] = __($this->thumb_sizes['sq'][2]); 129 130 # --BEHAVIOR-- coreMediaConstruct 131 $this->core->callBehavior('coreMediaConstruct', $this); 132 } 133 134 /** 135 Changes working directory. 136 137 @param dir <b>string</b> Directory name. 138 */ 139 public function chdir($dir) 140 { 141 parent::chdir($dir); 142 $this->relpwd = preg_replace('/^' . preg_quote($this->root, '/') . '\/?/', '', $this->pwd); 143 } 144 145 /** 146 Adds a new file handler for a given media type and event. 147 148 Available events are: 149 - create: file creation 150 - update: file update 151 - remove: file deletion 152 153 @param type <b>string</b> Media type 154 @param event <b>string</b> Event 155 @param function <b>callback</b> 156 */ 157 public function addFileHandler($type, $event, $function) 158 { 159 if (is_callable($function)) { 160 $this->file_handler[$type][$event][] = $function; 161 } 162 } 163 164 protected function callFileHandler($type, $event) 165 { 166 if (!empty($this->file_handler[$type][$event])) { 167 $args = func_get_args(); 168 array_shift($args); 169 array_shift($args); 170 171 foreach ($this->file_handler[$type][$event] as $f) { 172 call_user_func_array($f, $args); 173 } 174 } 175 } 176 177 /** 178 Returns HTML breadCrumb for media manager navigation. 179 180 @param href <b>string</b> URL pattern 181 @param last <b>string</b> Last item pattern 182 @return <b>string</b> HTML code 183 */ 184 public function breadCrumb($href, $last = '') 185 { 186 $res = ''; 187 if ($this->relpwd && $this->relpwd != '.') { 188 $pwd = ''; 189 $arr = explode('/', $this->relpwd); 190 $count = count($arr); 191 foreach ($arr as $v) { 192 if (($last != '') && (0 === --$count)) { 193 $res .= sprintf($last, $v); 194 } else { 195 $pwd .= rawurlencode($v) . '/'; 196 $res .= '<a href="' . sprintf($href, $pwd) . '">' . $v . '</a> / '; 197 } 198 } 199 } 200 return $res; 201 202 } 203 204 protected function fileRecord($rs) 205 { 206 if ($rs->isEmpty()) {return;} 207 208 if (!$this->isFileExclude($this->root . '/' . $rs->media_file) && is_file($this->root . '/' . $rs->media_file)) { 209 $f = new fileItem($this->root . '/' . $rs->media_file, $this->root, $this->root_url); 210 211 if ($this->type && $f->type_prefix != $this->type) { 212 return; 213 } 214 215 $meta = @simplexml_load_string($rs->media_meta); 216 217 $f->editable = true; 218 $f->media_id = $rs->media_id; 219 $f->media_title = $rs->media_title; 220 $f->media_meta = $meta instanceof SimpleXMLElement ? $meta : simplexml_load_string('<meta></meta>'); 221 $f->media_user = $rs->user_id; 222 $f->media_priv = (boolean) $rs->media_private; 223 $f->media_dt = strtotime($rs->media_dt); 224 $f->media_dtstr = dt::str('%Y-%m-%d %H:%M', $f->media_dt); 225 226 $f->media_image = false; 227 228 if (!$this->core->auth->check('media_admin', $this->core->blog->id) 229 && $this->core->auth->userID() != $f->media_user) { 230 $f->del = false; 231 $f->editable = false; 232 } 233 234 $type_prefix = explode('/', $f->type); 235 $type_prefix = $type_prefix[0]; 236 237 switch ($type_prefix) { 238 case 'image': 239 $f->media_image = true; 240 $f->media_icon = 'image'; 241 break; 242 case 'audio': 243 $f->media_icon = 'audio'; 244 break; 245 case 'text': 246 $f->media_icon = 'text'; 247 break; 248 case 'video': 249 $f->media_icon = 'video'; 250 break; 251 default: 252 $f->media_icon = 'blank'; 253 } 254 switch ($f->type) { 255 case 'application/msword': 256 case 'application/vnd.oasis.opendocument.text': 257 case 'application/vnd.sun.xml.writer': 258 case 'application/pdf': 259 case 'application/postscript': 260 $f->media_icon = 'document'; 261 break; 262 case 'application/msexcel': 263 case 'application/vnd.oasis.opendocument.spreadsheet': 264 case 'application/vnd.sun.xml.calc': 265 $f->media_icon = 'spreadsheet'; 266 break; 267 case 'application/mspowerpoint': 268 case 'application/vnd.oasis.opendocument.presentation': 269 case 'application/vnd.sun.xml.impress': 270 $f->media_icon = 'presentation'; 271 break; 272 case 'application/x-debian-package': 273 case 'application/x-bzip': 274 case 'application/x-gzip': 275 case 'application/x-java-archive': 276 case 'application/rar': 277 case 'application/x-redhat-package-manager': 278 case 'application/x-tar': 279 case 'application/x-gtar': 280 case 'application/zip': 281 $f->media_icon = 'package'; 282 break; 283 case 'application/octet-stream': 284 $f->media_icon = 'executable'; 285 break; 286 case 'application/x-shockwave-flash': 287 $f->media_icon = 'video'; 288 break; 289 case 'application/ogg': 290 $f->media_icon = 'audio'; 291 break; 292 case 'text/html': 293 $f->media_icon = 'html'; 294 break; 295 } 296 297 $f->media_type = $f->media_icon; 298 $f->media_icon = sprintf($this->icon_img, $f->media_icon); 299 300 # Thumbnails 301 $f->media_thumb = array(); 302 $p = path::info($f->relname); 303 304 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 305 306 $thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $this->root . '/' . $p['dirname'], $p['base'], '%s'); 307 $thumb_url = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $this->root_url . $p['dirname'], $p['base'], '%s'); 308 309 # Cleaner URLs 310 $thumb_url = preg_replace('#\./#', '/', $thumb_url); 311 $thumb_url = preg_replace('#(?<!:)/+#', '/', $thumb_url); 312 313 if ($alpha) { 314 $thumb_alt = sprintf($this->thumb_tp, $this->root . '/' . $p['dirname'], $p['base'], '%s'); 315 $thumb_url_alt = sprintf($this->thumb_tp, $this->root_url . $p['dirname'], $p['base'], '%s'); 316 # Cleaner URLs 317 $thumb_url_alt = preg_replace('#\./#', '/', $thumb_url_alt); 318 $thumb_url_alt = preg_replace('#(?<!:)/+#', '/', $thumb_url_alt); 319 } 320 321 foreach ($this->thumb_sizes as $suffix => $s) { 322 if (file_exists(sprintf($thumb, $suffix))) { 323 $f->media_thumb[$suffix] = sprintf($thumb_url, $suffix); 324 } elseif ($alpha && file_exists(sprintf($thumb_alt, $suffix))) { 325 $f->media_thumb[$suffix] = sprintf($thumb_url_alt, $suffix); 326 } 327 } 328 329 if (isset($f->media_thumb['sq']) && $f->media_type == 'image') { 330 $f->media_icon = $f->media_thumb['sq']; 331 } 332 333 return $f; 334 } 335 336 return; 337 } 338 339 public function setFileSort($type = 'name') 340 { 341 if (in_array($type, array('name-asc', 'name-desc', 'date-asc', 'date-desc'))) { 342 $this->file_sort = $type; 343 } 344 } 345 346 protected function sortFileHandler($a, $b) 347 { 348 if (is_null($a) || is_null($b)) { 349 return (is_null($a) ? 1 : -1); 350 } 351 switch ($this->file_sort) { 352 case 'date-asc': 353 if ($a->media_dt == $b->media_dt) { 354 return 0; 355 } 356 return ($a->media_dt < $b->media_dt) ? -1 : 1; 357 case 'date-desc': 358 if ($a->media_dt == $b->media_dt) { 359 return 0; 360 } 361 return ($a->media_dt > $b->media_dt) ? -1 : 1; 362 case 'name-desc': 363 return strcasecmp($b->basename, $a->basename); 364 case 'name-asc': 365 default: 366 return strcasecmp($a->basename, $b->basename); 367 } 368 } 369 370 /** 371 Gets current working directory content (using filesystem) 372 373 */ 374 public function getFSDir() 375 { 376 parent::getDir(); 377 } 378 379 /** 380 Gets current working directory content. 381 382 @param type <b>string</b> Media type filter 383 */ 384 public function getDir($type = null) 385 { 386 if ($type) { 387 $this->type = $type; 388 } 389 390 $media_dir = $this->relpwd ?: '.'; 391 392 $strReq = 393 'SELECT media_file, media_id, media_path, media_title, media_meta, media_dt, ' . 394 'media_creadt, media_upddt, media_private, user_id ' . 395 'FROM ' . $this->table . ' ' . 396 "WHERE media_path = '" . $this->path . "' " . 397 "AND media_dir = '" . $this->con->escape($media_dir) . "' "; 398 399 if (!$this->core->auth->check('media_admin', $this->core->blog->id)) { 400 $strReq .= 'AND (media_private <> 1 '; 401 402 if ($this->core->auth->userID()) { 403 $strReq .= "OR user_id = '" . $this->con->escape($this->core->auth->userID()) . "'"; 404 } 405 $strReq .= ') '; 406 } 407 408 $rs = $this->con->select($strReq); 409 410 parent::getDir(); 411 412 $f_res = array(); 413 $p_dir = $this->dir; 414 415 # If type is set, remove items from p_dir 416 if ($this->type) { 417 foreach ($p_dir['files'] as $k => $f) { 418 if ($f->type_prefix != $this->type) { 419 unset($p_dir['files'][$k]); 420 } 421 } 422 } 423 424 $f_reg = array(); 425 426 while ($rs->fetch()) { 427 # File in subdirectory, forget about it! 428 if (dirname($rs->media_file) != '.' && dirname($rs->media_file) != $this->relpwd) { 429 continue; 430 } 431 432 if ($this->inFiles($rs->media_file)) { 433 $f = $this->fileRecord($rs); 434 if ($f !== null) { 435 if (isset($f_reg[$rs->media_file])) { 436 # That media is duplicated in the database, 437 # time to do a bit of house cleaning. 438 $this->con->execute( 439 'DELETE FROM ' . $this->table . ' ' . 440 "WHERE media_id = " . $this->fileRecord($rs)->media_id 441 ); 442 } else { 443 $f_res[] = $this->fileRecord($rs); 444 $f_reg[$rs->media_file] = 1; 445 } 446 } 447 } elseif (!empty($p_dir['files']) && $this->relpwd == '') { 448 # Physical file does not exist remove it from DB 449 # Because we don't want to erase everything on 450 # dotclear upgrade, do it only if there are files 451 # in directory and directory is root 452 $this->con->execute( 453 'DELETE FROM ' . $this->table . ' ' . 454 "WHERE media_path = '" . $this->con->escape($this->path) . "' " . 455 "AND media_file = '" . $this->con->escape($rs->media_file) . "' " 456 ); 457 $this->callFileHandler(files::getMimeType($rs->media_file), 'remove', $this->pwd . '/' . $rs->media_file); 458 } 459 } 460 461 $this->dir['files'] = $f_res; 462 foreach ($this->dir['dirs'] as $k => $v) { 463 $v->media_icon = sprintf($this->icon_img, ($v->parent ? 'folder-up' : 'folder')); 464 } 465 466 # Check files that don't exist in database and create them 467 if ($this->core->auth->check('media,media_admin', $this->core->blog->id)) { 468 foreach ($p_dir['files'] as $f) { 469 if (!isset($f_reg[$f->relname])) { 470 if (($id = $this->createFile($f->basename, null, false, null, false)) !== false) { 471 $this->dir['files'][] = $this->getFile($id); 472 } 473 } 474 } 475 } 476 try { 477 usort($this->dir['files'], array($this, 'sortFileHandler')); 478 } catch (Exception $e) {} 479 } 480 481 /** 482 Gets file by its id. Returns a filteItem object. 483 484 @param id <b>integer</b> File ID 485 @return <b>fileItem</b> 486 */ 487 public function getFile($id) 488 { 489 $strReq = 490 'SELECT media_id, media_path, media_title, ' . 491 'media_file, media_meta, media_dt, media_creadt, ' . 492 'media_upddt, media_private, user_id ' . 493 'FROM ' . $this->table . ' ' . 494 "WHERE media_path = '" . $this->path . "' " . 495 'AND media_id = ' . (integer) $id . ' '; 496 497 if (!$this->core->auth->check('media_admin', $this->core->blog->id)) { 498 $strReq .= 'AND (media_private <> 1 '; 499 500 if ($this->core->auth->userID()) { 501 $strReq .= "OR user_id = '" . $this->con->escape($this->core->auth->userID()) . "'"; 502 } 503 $strReq .= ') '; 504 } 505 506 $rs = $this->con->select($strReq); 507 return $this->fileRecord($rs); 508 } 509 510 /** 511 Search into media db (only). 512 513 @param query <b>string</b> Search query 514 @return boolean true or false if nothing found 515 */ 516 public function searchMedia($query) 517 { 518 if ($query == '') { 519 return false; 520 } 521 522 $strReq = 523 'SELECT media_file, media_id, media_path, media_title, media_meta, media_dt, ' . 524 'media_creadt, media_upddt, media_private, user_id ' . 525 'FROM ' . $this->table . ' ' . 526 "WHERE media_path = '" . $this->path . "' " . 527 "AND (media_title LIKE '%" . $this->con->escape($query) . "%' " . 528 " OR media_file LIKE '%" . $this->con->escape($query) . "%' " . 529 " OR media_meta LIKE '<Description>%" . $this->con->escape($query) . "%</Description>')"; 530 531 if (!$this->core->auth->check('media_admin', $this->core->blog->id)) { 532 $strReq .= 'AND (media_private <> 1 '; 533 534 if ($this->core->auth->userID()) { 535 $strReq .= "OR user_id = '" . $this->con->escape($this->core->auth->userID()) . "'"; 536 } 537 $strReq .= ') '; 538 } 539 540 $rs = $this->con->select($strReq); 541 542 $this->dir = array('dirs' => array(), 'files' => array()); 543 $f_res = array(); 544 while ($rs->fetch()) { 545 $fr = $this->fileRecord($rs); 546 if ($fr) { 547 $f_res[] = $fr; 548 } 549 } 550 $this->dir['files'] = $f_res; 551 552 try { 553 usort($this->dir['files'], array($this, 'sortFileHandler')); 554 } catch (Exception $e) {} 555 556 return (count($f_res) > 0 ? true : false); 557 } 558 559 /** 560 Returns media items attached to a blog post. Result is an array containing 561 fileItems objects. 562 563 @param post_id <b>integer</b> Post ID 564 @param media_id <b>integer</b> Optionnal media ID 565 @param link_type <b>string</b> Optionnal link type 566 @return <b>array</b> Array of fileItems 567 */ 568 public function getPostMedia($post_id, $media_id = null, $link_type = null) 569 { 570 $params = array( 571 'post_id' => $post_id, 572 'media_path' => $this->path 573 ); 574 if ($media_id) { 575 $params['media_id'] = (integer) $media_id; 576 } 577 if ($link_type) { 578 $params['link_type'] = $link_type; 579 } 580 $rs = $this->postmedia->getPostMedia($params); 581 582 $res = array(); 583 584 while ($rs->fetch()) { 585 $f = $this->fileRecord($rs); 586 if ($f !== null) { 587 $res[] = $f; 588 } 589 } 590 591 return $res; 592 } 593 594 /** 595 @deprecated since version 2.4 596 @see dcPostMedia::addPostMedia 597 */ 598 public function addPostMedia($post_id, $media_id, $link_type = 'attachment') 599 { 600 $this->postmedia->addPostMedia($post_id, $media_id, $link_type); 601 } 602 603 /** 604 @deprecated since version 2.4 605 @see dcPostMedia::removePostMedia 606 */ 607 public function removePostMedia($post_id, $media_id, $link_type = 'attachment') 608 { 609 $this->postmedia->removePostMedia($post_id, $media_id, $link_type); 610 } 611 612 /** 613 Rebuilds database items collection. Optional <var>$pwd</var> parameter is 614 the path where to start rebuild. 615 616 @param pwd <b>string</b> Directory to rebuild 617 */ 618 public function rebuild($pwd = '') 619 { 620 if (!$this->core->auth->isSuperAdmin()) { 621 throw new Exception(__('You are not a super administrator.')); 622 } 623 624 $this->chdir($pwd); 625 parent::getDir(); 626 627 $dir = $this->dir; 628 629 foreach ($dir['dirs'] as $d) { 630 if (!$d->parent) { 631 $this->rebuild($d->relname, false); 632 } 633 } 634 635 foreach ($dir['files'] as $f) { 636 $this->chdir(dirname($f->relname)); 637 $this->createFile($f->basename); 638 } 639 640 $this->rebuildDB($pwd); 641 } 642 643 protected function rebuildDB($pwd) 644 { 645 $media_dir = $pwd ?: '.'; 646 647 $strReq = 648 'SELECT media_file, media_id ' . 649 'FROM ' . $this->table . ' ' . 650 "WHERE media_path = '" . $this->path . "' " . 651 "AND media_dir = '" . $this->con->escape($media_dir) . "' "; 652 653 $rs = $this->con->select($strReq); 654 655 $delReq = 'DELETE FROM ' . $this->table . ' ' . 656 'WHERE media_id IN (%s) '; 657 $del_ids = array(); 658 659 while ($rs->fetch()) { 660 if (!is_file($this->root . '/' . $rs->media_file)) { 661 $del_ids[] = (integer) $rs->media_id; 662 } 663 } 664 665 if (!empty($del_ids)) { 666 $this->con->execute(sprintf($delReq, implode(',', $del_ids))); 667 } 668 } 669 670 public function makeDir($d) 671 { 672 $d = files::tidyFileName($d); 673 parent::makeDir($d); 674 } 675 676 /** 677 Creates or updates a file in database. Returns new media ID or false if 678 file does not exist. 679 680 @param name <b>string</b> File name (relative to working directory) 681 @param title <b>string</b> File title 682 @param private <b>boolean</b> File is private 683 @param dt <b>string</b> File date 684 @return <b>integer</b> New media ID 685 */ 686 public function createFile($name, $title = null, $private = false, $dt = null, $force = true) 687 { 688 if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) { 689 throw new Exception(__('Permission denied.')); 690 } 691 692 $file = $this->pwd . '/' . $name; 693 if (!file_exists($file)) { 694 return false; 695 } 696 697 $media_file = $this->relpwd ? path::clean($this->relpwd . '/' . $name) : path::clean($name); 698 $media_type = files::getMimeType($name); 699 700 $cur = $this->con->openCursor($this->table); 701 702 $strReq = 'SELECT media_id ' . 703 'FROM ' . $this->table . ' ' . 704 "WHERE media_path = '" . $this->con->escape($this->path) . "' " . 705 "AND media_file = '" . $this->con->escape($media_file) . "' "; 706 707 $rs = $this->con->select($strReq); 708 709 if ($rs->isEmpty()) { 710 $this->con->writeLock($this->table); 711 try 712 { 713 $rs = $this->con->select('SELECT MAX(media_id) FROM ' . $this->table); 714 $media_id = (integer) $rs->f(0) + 1; 715 716 $cur->media_id = $media_id; 717 $cur->user_id = (string) $this->core->auth->userID(); 718 $cur->media_path = (string) $this->path; 719 $cur->media_file = (string) $media_file; 720 $cur->media_dir = (string) dirname($media_file); 721 $cur->media_creadt = date('Y-m-d H:i:s'); 722 $cur->media_upddt = date('Y-m-d H:i:s'); 723 724 $cur->media_title = !$title ? (string) $name : (string) $title; 725 $cur->media_private = (integer) (boolean) $private; 726 727 if ($dt) { 728 $cur->media_dt = (string) $dt; 729 } else { 730 $cur->media_dt = strftime('%Y-%m-%d %H:%M:%S', filemtime($file)); 731 } 732 733 try { 734 $cur->insert(); 735 } catch (Exception $e) { 736 @unlink($name); 737 throw $e; 738 } 739 $this->con->unlock(); 740 } catch (Exception $e) { 741 $this->con->unlock(); 742 throw $e; 743 } 744 } else { 745 $media_id = (integer) $rs->media_id; 746 747 $cur->media_upddt = date('Y-m-d H:i:s'); 748 749 $cur->update('WHERE media_id = ' . $media_id); 750 } 751 752 $this->callFileHandler($media_type, 'create', $cur, $name, $media_id, $force); 753 754 return $media_id; 755 } 756 757 /** 758 Updates a file in database. 759 760 @param file <b>fileItem</b> Current fileItem object 761 @param newFile <b>fileItem</b> New fileItem object 762 */ 763 public function updateFile($file, $newFile) 764 { 765 if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) { 766 throw new Exception(__('Permission denied.')); 767 } 768 769 $id = (integer) $file->media_id; 770 771 if (!$id) { 772 throw new Exception('No file ID'); 773 } 774 775 if (!$this->core->auth->check('media_admin', $this->core->blog->id) 776 && $this->core->auth->userID() != $file->media_user) { 777 throw new Exception(__('You are not the file owner.')); 778 } 779 780 $cur = $this->con->openCursor($this->table); 781 782 # We need to tidy newFile basename. If dir isn't empty, concat to basename 783 $newFile->relname = files::tidyFileName($newFile->basename); 784 if ($newFile->dir) { 785 $newFile->relname = $newFile->dir . '/' . $newFile->relname; 786 } 787 788 if ($file->relname != $newFile->relname) { 789 $newFile->file = $this->root . '/' . $newFile->relname; 790 791 if ($this->isFileExclude($newFile->relname)) { 792 throw new Exception(__('This file is not allowed.')); 793 } 794 795 if (file_exists($newFile->file)) { 796 throw new Exception(__('New file already exists.')); 797 } 798 799 $this->moveFile($file->relname, $newFile->relname); 800 801 $cur->media_file = (string) $newFile->relname; 802 $cur->media_dir = (string) dirname($newFile->relname); 803 } 804 805 $cur->media_title = (string) $newFile->media_title; 806 $cur->media_dt = (string) $newFile->media_dtstr; 807 $cur->media_upddt = date('Y-m-d H:i:s'); 808 $cur->media_private = (integer) $newFile->media_priv; 809 810 $cur->update('WHERE media_id = ' . $id); 811 812 $this->callFileHandler($file->type, 'update', $file, $newFile); 813 } 814 815 /** 816 Uploads a file. 817 818 @param tmp <b>string</b> Full path of temporary uploaded file 819 @param name <b>string</b> File name (relative to working directory) 820 @param title <b>string</b> File title 821 @param private <b>boolean</b> File is private 822 */ 823 public function uploadFile($tmp, $name, $title = null, $private = false, $overwrite = false) 824 { 825 if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) { 826 throw new Exception(__('Permission denied.')); 827 } 828 829 $name = files::tidyFileName($name); 830 831 parent::uploadFile($tmp, $name, $overwrite); 832 833 return $this->createFile($name, $title, $private); 834 } 835 836 /** 837 Creates a file from binary content. 838 839 @param name <b>string</b> File name (relative to working directory) 840 @param bits <b>string</b> Binary file content 841 */ 842 public function uploadBits($name, $bits) 843 { 844 if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) { 845 throw new Exception(__('Permission denied.')); 846 } 847 848 $name = files::tidyFileName($name); 849 850 parent::uploadBits($name, $bits); 851 852 return $this->createFile($name, null, null); 853 } 854 855 /** 856 Removes a file. 857 858 @param f <b>fileItem</b> fileItem object 859 */ 860 public function removeFile($f) 861 { 862 if (!$this->core->auth->check('media,media_admin', $this->core->blog->id)) { 863 throw new Exception(__('Permission denied.')); 864 } 865 866 $media_file = $this->relpwd ? path::clean($this->relpwd . '/' . $f) : path::clean($f); 867 868 $strReq = 'DELETE FROM ' . $this->table . ' ' . 869 "WHERE media_path = '" . $this->con->escape($this->path) . "' " . 870 "AND media_file = '" . $this->con->escape($media_file) . "' "; 871 872 if (!$this->core->auth->check('media_admin', $this->core->blog->id)) { 873 $strReq .= "AND user_id = '" . $this->con->escape($this->core->auth->userID()) . "'"; 874 } 875 876 $this->con->execute($strReq); 877 878 if ($this->con->changes() == 0) { 879 throw new Exception(__('File does not exist in the database.')); 880 } 881 882 parent::removeFile($f); 883 884 $this->callFileHandler(files::getMimeType($media_file), 'remove', $f); 885 } 886 887 /** 888 * Root directories 889 * 890 * Returns an array of directory under {@link $root} directory. 891 * 892 * @uses fileItem 893 * @return array 894 */ 895 public function getDBDirs() 896 { 897 $media_dir = $this->relpwd ?: '.'; 898 899 $strReq = 900 'SELECT distinct media_dir ' . 901 'FROM ' . $this->table . ' ' . 902 "WHERE media_path = '" . $this->path . "'"; 903 $rs = $this->con->select($strReq); 904 while ($rs->fetch()) { 905 if (is_dir($this->root . '/' . $rs->media_dir)) { 906 $dir[] = ($rs->media_dir == '.' ? '' : $rs->media_dir); 907 } 908 909 } 910 911 return $dir; 912 } 913 914 /** 915 Extract zip file in current location 916 917 @param f <b>fileRecord</b> fileRecord object 918 */ 919 public function inflateZipFile($f, $create_dir = true) 920 { 921 $zip = new fileUnzip($f->file); 922 $zip->setExcludePattern($this->exclude_pattern); 923 $list = $zip->getList(false, '#(^|/)(__MACOSX|\.svn|\.DS_Store|\.directory|Thumbs\.db)(/|$)#'); 924 925 if ($create_dir) { 926 $zip_root_dir = $zip->getRootDir(); 927 if ($zip_root_dir != false) { 928 $destination = $zip_root_dir; 929 $target = $f->dir; 930 } else { 931 $destination = preg_replace('/\.([^.]+)$/', '', $f->basename); 932 $target = $f->dir . '/' . $destination; 933 } 934 935 if (is_dir($f->dir . '/' . $destination)) { 936 throw new Exception(sprintf(__('Extract destination directory %s already exists.'), dirname($f->relname) . '/' . $destination)); 937 } 938 } else { 939 $target = $f->dir; 940 $destination = ''; 941 } 942 943 $zip->unzipAll($target); 944 $zip->close(); 945 946 // Clean-up all extracted filenames 947 $clean = function ($name) { 948 $n = text::deaccent($name); 949 $n = preg_replace('/^[.]/u', '', $n); 950 return preg_replace('/[^A-Za-z0-9._\-\/]/u', '_', $n); 951 }; 952 foreach ($list as $zk => $zv) { 953 // Check if extracted file exists 954 $zf = $target . '/' . $zk; 955 if (!$zv['is_dir'] && file_exists($zf)) { 956 $zt = $clean($zf); 957 if ($zt != $zf) { 958 rename($zf, $zt); 959 } 960 } 961 } 962 963 return dirname($f->relname) . '/' . $destination; 964 } 965 966 /** 967 Returns zip file content 968 969 @param f <b>fileRecord</b> fileRecord object 970 @return <b>array</b> 971 */ 972 public function getZipContent($f) 973 { 974 $zip = new fileUnzip($f->file); 975 $list = $zip->getList(false, '#(^|/)(__MACOSX|\.svn|\.DS_Store|\.directory|Thumbs\.db)(/|$)#'); 976 $zip->close(); 977 return $list; 978 } 979 980 /** 981 Calls file handlers registered for recreate event 982 983 @param f <b>fileItem</b> fileItem object 984 */ 985 public function mediaFireRecreateEvent($f) 986 { 987 $media_type = files::getMimeType($f->basename); 988 $this->callFileHandler($media_type, 'recreate', null, $f->basename); // Args list to be completed as necessary (Franck) 989 } 990 991 /* Image handlers 992 ------------------------------------------------------- */ 993 public function imageThumbCreate($cur, $f, $force = true) 994 { 995 $file = $this->pwd . '/' . $f; 996 997 if (!file_exists($file)) { 998 return false; 999 } 1000 1001 $p = path::info($file); 1002 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 1003 $thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $p['dirname'], $p['base'], '%s'); 1004 1005 try 1006 { 1007 $img = new imageTools(); 1008 $img->loadImage($file); 1009 1010 $w = $img->getW(); 1011 $h = $img->getH(); 1012 1013 if ($force) { 1014 $this->imageThumbRemove($f); 1015 } 1016 1017 foreach ($this->thumb_sizes as $suffix => $s) { 1018 $thumb_file = sprintf($thumb, $suffix); 1019 if (!file_exists($thumb_file) && $s[0] > 0 && 1020 ($suffix == 'sq' || $w > $s[0] || $h > $s[0])) { 1021 $rate = ($s[0] < 100 ? 95 : ($s[0] < 600 ? 90 : 85)); 1022 $img->resize($s[0], $s[0], $s[1]); 1023 $img->output(($alpha ? 'png' : 'jpeg'), $thumb_file, $rate); 1024 $img->loadImage($file); 1025 } 1026 } 1027 $img->close(); 1028 } catch (Exception $e) { 1029 if ($cur === null) { 1030 # Called only if cursor is null (public call) 1031 throw $e; 1032 } 1033 } 1034 } 1035 1036 protected function imageThumbUpdate($file, $newFile) 1037 { 1038 if ($file->relname != $newFile->relname) { 1039 $p = path::info($file->relname); 1040 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 1041 $thumb_old = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $p['dirname'], $p['base'], '%s'); 1042 1043 $p = path::info($newFile->relname); 1044 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 1045 $thumb_new = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), $p['dirname'], $p['base'], '%s'); 1046 1047 foreach ($this->thumb_sizes as $suffix => $s) { 1048 try { 1049 parent::moveFile(sprintf($thumb_old, $suffix), sprintf($thumb_new, $suffix)); 1050 } catch (Exception $e) {} 1051 } 1052 } 1053 } 1054 1055 public function imageThumbRemove($f) 1056 { 1057 $p = path::info($f); 1058 $alpha = ($p['extension'] == 'png') || ($p['extension'] == 'PNG'); 1059 $thumb = sprintf(($alpha ? $this->thumb_tp_alpha : $this->thumb_tp), '', $p['base'], '%s'); 1060 1061 foreach ($this->thumb_sizes as $suffix => $s) { 1062 try { 1063 parent::removeFile(sprintf($thumb, $suffix)); 1064 } catch (Exception $e) {} 1065 } 1066 } 1067 1068 protected function imageMetaCreate($cur, $f, $id) 1069 { 1070 $file = $this->pwd . '/' . $f; 1071 1072 if (!file_exists($file)) { 1073 return false; 1074 } 1075 1076 $xml = new xmlTag('meta'); 1077 $meta = imageMeta::readMeta($file); 1078 $xml->insertNode($meta); 1079 1080 $c = $this->core->con->openCursor($this->table); 1081 $c->media_meta = $xml->toXML(); 1082 1083 if ($cur->media_title !== null && $cur->media_title == basename($cur->media_file)) { 1084 if ($meta['Title']) { 1085 $c->media_title = $meta['Title']; 1086 } 1087 } 1088 1089 if ($meta['DateTimeOriginal'] && $cur->media_dt === '') { 1090 # We set picture time to user timezone 1091 $media_ts = strtotime($meta['DateTimeOriginal']); 1092 if ($media_ts !== false) { 1093 $o = dt::getTimeOffset($this->core->auth->getInfo('user_tz'), $media_ts); 1094 $c->media_dt = dt::str('%Y-%m-%d %H:%M:%S', $media_ts + $o); 1095 } 1096 } 1097 1098 $c->update('WHERE media_id = ' . $id); 1099 } 1100 1101 /** 1102 Returns HTML code for audio player (HTML5 and if possible fallback Flash player) 1103 1104 @param type <b>string</b> audio mime type 1105 @param url <b>string</b> audio URL to play 1106 @param player <b>string</b> Player URL (flash player fallback) 1107 @param args <b>array</b> Player parameters (flash player fallback) 1108 @param fallback <b>boolean</b> Include Flash player fallback 1109 @param preload <b>boolean</b> Add preload="auto" attribute if true, else preload="none" 1110 @return <b>string</b> 1111 */ 1112 public static function audioPlayer($type, $url, $player = null, $args = null, $fallback = true, $preload = true) 1113 { 1114 $audio = 1115 '<audio controls preload="' . ($preload ? 'auto' : 'none') . '">' . 1116 '<source src="' . $url . '">'; 1117 1118 if ($fallback && $type == 'audio/mpeg3') { 1119 // Include Flash player fallback 1120 if (!$player) { 1121 $player = 'player_mp3.swf'; 1122 } 1123 1124 if (!is_array($args)) { 1125 $args = array( 1126 'showvolume' => 1, 1127 'loadingcolor' => 'ff9900', 1128 'bgcolor1' => 'eeeeee', 1129 'bgcolor2' => 'cccccc', 1130 'buttoncolor' => '0066cc', 1131 'buttonovercolor' => 'ff9900', 1132 'slidercolor1' => 'cccccc', 1133 'slidercolor2' => '999999', 1134 'sliderovercolor' => '0066cc' 1135 ); 1136 } 1137 1138 $args['mp3'] = $url; 1139 1140 if (empty($args['width'])) { 1141 $args['width'] = 200; 1142 } 1143 if (empty($args['height'])) { 1144 $args['height'] = 20; 1145 } 1146 1147 $vars = array(); 1148 foreach ($args as $k => $v) { 1149 $vars[] = $k . '=' . $v; 1150 } 1151 1152 $audio .= 1153 '<object type="application/x-shockwave-flash" ' . 1154 'data="' . $player . '" ' . 1155 'width="' . $args['width'] . '" height="' . $args['height'] . '">' . 1156 '<param name="movie" value="' . $player . '" />' . 1157 '<param name="wmode" value="transparent" />' . 1158 '<param name="FlashVars" value="' . implode('&', $vars) . '" />' . 1159 __('Embedded Audio Player') . 1160 '</object>'; 1161 } 1162 1163 $audio .= 1164 '</audio>'; 1165 1166 return $audio; 1167 } 1168 1169 /** 1170 Returns HTML code for video player (HTML5 and if possible fallback Flash player) 1171 1172 @param type <b>string</b> video mime type 1173 @param url <b>string</b> video URL to play 1174 @param player <b>string</b> Player URL (flash player fallback) 1175 @param args <b>array</b> Player parameters (flash player fallback) 1176 @param fallback <b>boolean</b> Include Flash player fallback (if not .flv) 1177 @param preload <b>boolean</b> Add preload="auto" attribute if true, else preload="none" 1178 @return <b>string</b> 1179 */ 1180 public static function videoPlayer($type, $url, $player = null, $args = null, $fallback = true, $preload = true) 1181 { 1182 $video = ''; 1183 1184 // Cope with width and height, if given 1185 $width = 400; 1186 $height = 300; 1187 if (is_array($args)) { 1188 if (!empty($args['width']) && $args['width']) { 1189 $width = (int) $args['width']; 1190 } 1191 if (!empty($args['height']) && $args['height']) { 1192 $height = (int) $args['height']; 1193 } 1194 } 1195 1196 if ($type != 'video/x-flv') { 1197 $video = 1198 '<video controls preload="' . ($preload ? 'auto' : 'none') . '"' . 1199 ($width ? ' width="' . $width . '"' : '') . 1200 ($height ? ' height="' . $height . '"' : '') . '>' . 1201 '<source src="' . $url . '">'; 1202 } 1203 1204 if ($type == 'video/x-flv' || ($fallback && ($type == 'video/mp4' || $type == 'video/x-m4v'))) { 1205 // Include Flash player fallback 1206 if (!$player) { 1207 $player = 'player_flv.swf'; 1208 } 1209 1210 if (!is_array($args)) { 1211 $args = array( 1212 'margin' => 1, 1213 'showvolume' => 1, 1214 'showtime' => 1, 1215 'showfullscreen' => 1, 1216 'buttonovercolor' => 'ff9900', 1217 'slidercolor1' => 'cccccc', 1218 'slidercolor2' => '999999', 1219 'sliderovercolor' => '0066cc' 1220 ); 1221 } 1222 1223 $args['flv'] = $url; 1224 1225 if (empty($args['width'])) { 1226 $args['width'] = 400; 1227 } 1228 if (empty($args['height'])) { 1229 $args['height'] = 300; 1230 } 1231 1232 $vars = array(); 1233 foreach ($args as $k => $v) { 1234 $vars[] = $k . '=' . $v; 1235 } 1236 1237 $video .= 1238 '<object type="application/x-shockwave-flash" ' . 1239 'data="' . $player . '" ' . 1240 'width="' . $args['width'] . '" height="' . $args['height'] . '">' . 1241 '<param name="movie" value="' . $player . '" />' . 1242 '<param name="wmode" value="transparent" />' . 1243 '<param name="allowFullScreen" value="true" />' . 1244 '<param name="FlashVars" value="' . implode('&', $vars) . '" />' . 1245 __('Embedded Video Player') . 1246 '</object>'; 1247 } 1248 1249 if ($type != 'video/x-flv') { 1250 $video .= 1251 '</video>'; 1252 } 1253 1254 return $video; 1255 } 1256 1257 /** 1258 Returns HTML code for MP3 player 1259 1260 @param url <b>string</b> MP3 URL to play 1261 @param player <b>string</b> Player URL 1262 @param args <b>array</b> Player parameters 1263 @param fallback <b>boolean</b> Include Flash player fallback 1264 @param preload <b>boolean</b> Add preload="auto" attribute if true, else preload="none" 1265 @return <b>string</b> 1266 */ 1267 public static function mp3player($url, $player = null, $args = null, $fallback = true, $preload = true) 1268 { 1269 if (!$player) { 1270 $player = 'player_mp3.swf'; 1271 } 1272 1273 if (!is_array($args)) { 1274 $args = array( 1275 'showvolume' => 1, 1276 'loadingcolor' => 'ff9900', 1277 'bgcolor1' => 'eeeeee', 1278 'bgcolor2' => 'cccccc', 1279 'buttoncolor' => '0066cc', 1280 'buttonovercolor' => 'ff9900', 1281 'slidercolor1' => 'cccccc', 1282 'slidercolor2' => '999999', 1283 'sliderovercolor' => '0066cc' 1284 ); 1285 } 1286 1287 $args['mp3'] = $url; 1288 1289 if (empty($args['width'])) { 1290 $args['width'] = 200; 1291 } 1292 if (empty($args['height'])) { 1293 $args['height'] = 20; 1294 } 1295 1296 $vars = array(); 1297 foreach ($args as $k => $v) { 1298 $vars[] = $k . '=' . $v; 1299 } 1300 1301 return 1302 '<audio controls preload="' . ($preload ? 'auto' : 'none') . '">' . 1303 '<source src="' . $url . '" type="audio/mpeg">' . 1304 ($fallback ? 1305 '<object type="application/x-shockwave-flash" ' . 1306 'data="' . $player . '" ' . 1307 'width="' . $args['width'] . '" height="' . $args['height'] . '">' . 1308 '<param name="movie" value="' . $player . '" />' . 1309 '<param name="wmode" value="transparent" />' . 1310 '<param name="FlashVars" value="' . implode('&', $vars) . '" />' . 1311 __('Embedded Audio Player') . 1312 '</object>' : '') . 1313 '</audio>'; 1314 } 1315 1316 /** 1317 Returns HTML code for FLV player 1318 1319 @param url <b>string</b> FLV URL to play 1320 @param player <b>string</b> Player URL 1321 @param args <b>array</b> Player parameters 1322 @return <b>string</b> 1323 */ 1324 public static function flvplayer($url, $player = null, $args = null) 1325 { 1326 if (!$player) { 1327 $player = 'player_flv.swf'; 1328 } 1329 1330 if (!is_array($args)) { 1331 $args = array( 1332 'margin' => 1, 1333 'showvolume' => 1, 1334 'showtime' => 1, 1335 'showfullscreen' => 1, 1336 'buttonovercolor' => 'ff9900', 1337 'slidercolor1' => 'cccccc', 1338 'slidercolor2' => '999999', 1339 'sliderovercolor' => '0066cc' 1340 ); 1341 } 1342 1343 $args['flv'] = $url; 1344 1345 if (empty($args['width'])) { 1346 $args['width'] = 400; 1347 } 1348 if (empty($args['height'])) { 1349 $args['height'] = 300; 1350 } 1351 1352 $vars = array(); 1353 foreach ($args as $k => $v) { 1354 $vars[] = $k . '=' . $v; 1355 } 1356 1357 return 1358 '<object type="application/x-shockwave-flash" ' . 1359 'data="' . $player . '" ' . 1360 'width="' . $args['width'] . '" height="' . $args['height'] . '">' . 1361 '<param name="movie" value="' . $player . '" />' . 1362 '<param name="wmode" value="transparent" />' . 1363 '<param name="allowFullScreen" value="true" />' . 1364 '<param name="FlashVars" value="' . implode('&', $vars) . '" />' . 1365 __('Embedded Video Player') . 1366 '</object>'; 1367 } 1401 1368 }
Note: See TracChangeset
for help on using the changeset viewer.