MODX Revolution PHP Cross Reference Content Management Systems

Source: /core/model/modx/sources/mods3mediasource.class.php - 1053 lines - 40392 bytes - Summary - Text - Print

   1  <?php
   2  /**

   3   * @package modx

   4   * @subpackage sources

   5   */
   6  require_once MODX_CORE_PATH . 'model/modx/sources/modmediasource.class.php';
   7  /**

   8   * Implements an Amazon S3-based media source, allowing basic manipulation, uploading and URL-retrieval of resources

   9   * in a specified S3 bucket.

  10   * 

  11   * @package modx

  12   * @subpackage sources

  13   */
  14  class modS3MediaSource extends modMediaSource implements modMediaSourceInterface {
  15      /** @var AmazonS3 $driver */

  16      public $driver;
  17      /** @var string $bucket */

  18      public $bucket;
  19  
  20      /**

  21       * Override the constructor to always force S3 sources to not be streams.

  22       *

  23       * {@inheritDoc}

  24       *

  25       * @param xPDO $xpdo

  26       */
  27      public function __construct(xPDO & $xpdo) {
  28          parent::__construct($xpdo);
  29          $this->set('is_stream',false);
  30      }
  31  
  32      /**

  33       * Initializes S3 media class, getting the S3 driver and loading the bucket

  34       * @return boolean

  35       */
  36      public function initialize() {
  37          parent::initialize();
  38          $properties = $this->getPropertyList();
  39          if (!defined('AWS_KEY')) {
  40              define('AWS_KEY',$this->xpdo->getOption('key',$properties,''));
  41              define('AWS_SECRET_KEY',$this->xpdo->getOption('secret_key',$properties,''));
  42              /* (Not needed at this time)

  43              define('AWS_ACCOUNT_ID',$modx->getOption('aws.account_id',$config,''));

  44              define('AWS_CANONICAL_ID',$modx->getOption('aws.canonical_id',$config,''));

  45              define('AWS_CANONICAL_NAME',$modx->getOption('aws.canonical_name',$config,''));

  46              define('AWS_MFA_SERIAL',$modx->getOption('aws.mfa_serial',$config,''));

  47              define('AWS_CLOUDFRONT_KEYPAIR_ID',$modx->getOption('aws.cloudfront_keypair_id',$config,''));

  48              define('AWS_CLOUDFRONT_PRIVATE_KEY_PEM',$modx->getOption('aws.cloudfront_private_key_pem',$config,''));

  49              define('AWS_ENABLE_EXTENSIONS', 'false');*/
  50          }
  51          include_once $this->xpdo->getOption('core_path',null,MODX_CORE_PATH).'model/aws/sdk.class.php';
  52  
  53          $this->getDriver();
  54          $this->setBucket($this->xpdo->getOption('bucket',$properties,''));
  55          return true;
  56      }
  57  
  58      /**

  59       * Get the name of this source type

  60       * @return string

  61       */
  62      public function getTypeName() {
  63          $this->xpdo->lexicon->load('source');
  64          return $this->xpdo->lexicon('source_type.s3');
  65      }
  66      /**

  67       * Get the description of this source type

  68       * @return string

  69       */
  70      public function getTypeDescription() {
  71          $this->xpdo->lexicon->load('source');
  72          return $this->xpdo->lexicon('source_type.s3_desc');
  73      }
  74  
  75  
  76      /**

  77       * Gets the AmazonS3 class instance

  78       * @return AmazonS3

  79       */
  80      public function getDriver() {
  81          if (empty($this->driver)) {
  82              try {
  83                  $this->driver = new AmazonS3();
  84              } catch (Exception $e) {
  85                  $this->xpdo->log(modX::LOG_LEVEL_ERROR,'[modAws] Could not load AmazonS3 class: '.$e->getMessage());
  86              }
  87          }
  88          return $this->driver;
  89      }
  90  
  91      /**

  92       * Set the bucket for the connection to S3

  93       * @param string $bucket

  94       * @return void

  95       */
  96      public function setBucket($bucket) {
  97          $this->bucket = $bucket;
  98      }
  99  
 100      /**

 101       * Get a list of objects from within a bucket

 102       * @param string $dir

 103       * @return array

 104       */
 105      public function getS3ObjectList($dir) {
 106          $c['delimiter'] = '/';
 107          if (!empty($dir) && $dir != '/') { $c['prefix'] = $dir; }
 108  
 109          $list = array();
 110          $cps = $this->driver->list_objects($this->bucket,$c);
 111          foreach ($cps->body->CommonPrefixes as $prefix) {
 112              if (!empty($prefix->Prefix) && $prefix->Prefix != $dir && $prefix->Prefix != '/') {
 113                  $list[] = (string)$prefix->Prefix;
 114              }
 115          }
 116          $response = $this->driver->get_object_list($this->bucket,$c);
 117          foreach ($response as $file) {
 118              $list[] = $file;
 119          }
 120          return $list;
 121      }
 122  
 123      /**

 124       * Get the ID of the edit file action

 125       *

 126       * @return boolean|int

 127       */
 128      public function getEditActionId() {
 129          $editAction = false;
 130          /** @var modAction $act */

 131          $act = $this->xpdo->getObject('modAction',array('controller' => 'system/file/edit'));
 132          if ($act) { $editAction = $act->get('id'); }
 133          return $editAction;
 134      }
 135  
 136      /**

 137       * @param string $path

 138       * @return array

 139       */
 140      public function getContainerList($path) {
 141          $properties = $this->getPropertyList();
 142          $list = $this->getS3ObjectList($path);
 143          $editAction = $this->getEditActionId();
 144  
 145          $useMultiByte = $this->ctx->getOption('use_multibyte', false);
 146          $encoding = $this->ctx->getOption('modx_charset', 'UTF-8');
 147  
 148          $directories = array();
 149          $files = array();
 150          foreach ($list as $idx => $currentPath) {
 151              if ($currentPath == $path) continue;
 152              $fileName = basename($currentPath);
 153              $isDir = substr(strrev($currentPath),0,1) === '/';
 154  
 155              $extension = pathinfo($fileName,PATHINFO_EXTENSION);
 156              $extension = $useMultiByte ? mb_strtolower($extension,$encoding) : strtolower($extension);
 157  
 158              $relativePath = $currentPath == '/' ? $currentPath : str_replace($path,'',$currentPath);
 159              $slashCount = substr_count($relativePath,'/');
 160              if (($slashCount > 1 && $isDir) || ($slashCount > 0 && !$isDir)) {
 161                  continue;
 162              }
 163              if ($isDir) {
 164                  $directories[$currentPath] = array(
 165                      'id' => $currentPath,
 166                      'text' => $fileName,
 167                      'cls' => 'icon-'.$extension,
 168                      'type' => 'dir',
 169                      'leaf' => false,
 170                      'path' => $currentPath,
 171                      'pathRelative' => $currentPath,
 172                      'perms' => '',
 173                  );
 174                  $directories[$currentPath]['menu'] = array('items' => $this->getListContextMenu($currentPath,$isDir,$directories[$currentPath]));
 175              } else {
 176                  $page = '?a='.$editAction.'&file='.$currentPath.'&wctx='.$this->ctx->get('key').'&source='.$this->get('id');
 177  
 178                  $isBinary = $this->isBinary(rtrim($properties['url'],'/').'/'.$currentPath);
 179  
 180                  $cls = array();
 181                  $cls[] = 'icon-'.$extension;
 182                  if($isBinary) {
 183                      $cls[] = 'icon-lock';
 184                  }
 185  
 186                  if ($this->hasPermission('file_remove')) $cls[] = 'premove';
 187                  if ($this->hasPermission('file_update')) $cls[] = 'pupdate';
 188  
 189                  $files[$currentPath] = array(
 190                      'id' => $currentPath,
 191                      'text' => $fileName,
 192                      'cls' => implode(' ', $cls),
 193                      'type' => 'file',
 194                      'leaf' => true,
 195                      'path' => $currentPath,
 196                      'page' => $isBinary ? null : $page,
 197                      'pathRelative' => $currentPath,
 198                      'directory' => $currentPath,
 199                      'url' => rtrim($properties['url'],'/').'/'.$currentPath,
 200                      'file' => $currentPath,
 201                  );
 202                  $files[$currentPath]['menu'] = array('items' => $this->getListContextMenu($currentPath,$isDir,$files[$currentPath]));
 203              }
 204          }
 205  
 206          $ls = array();
 207          /* now sort files/directories */

 208          ksort($directories);
 209          foreach ($directories as $dir) {
 210              $ls[] = $dir;
 211          }
 212          ksort($files);
 213          foreach ($files as $file) {
 214              $ls[] = $file;
 215          }
 216  
 217          return $ls;
 218      }
 219  
 220      /**

 221       * Get the context menu for when viewing the source as a tree

 222       * 

 223       * @param string $file

 224       * @param boolean $isDir

 225       * @param array $fileArray

 226       * @return array

 227       */
 228      public function getListContextMenu($file,$isDir,array $fileArray) {
 229          $menu = array();
 230          if (!$isDir) { /* files */
 231              if ($this->hasPermission('file_update')) {
 232                  if ($fileArray['page'] != null) {
 233                      $menu[] = array(
 234                          'text' => $this->xpdo->lexicon('file_edit'),
 235                          'handler' => 'this.editFile',
 236                      );
 237                      $menu[] = array(
 238                          'text' => $this->xpdo->lexicon('quick_update_file'),
 239                          'handler' => 'this.quickUpdateFile',
 240                      );
 241                  }
 242                  $menu[] = array(
 243                      'text' => $this->xpdo->lexicon('rename'),
 244                      'handler' => 'this.renameFile',
 245                  );
 246              }
 247              if ($this->hasPermission('file_view')) {
 248                  $menu[] = array(
 249                      'text' => $this->xpdo->lexicon('file_download'),
 250                      'handler' => 'this.downloadFile',
 251                  );
 252              }
 253              if ($this->hasPermission('file_remove')) {
 254                  if (!empty($menu)) $menu[] = '-';
 255                  $menu[] = array(
 256                      'text' => $this->xpdo->lexicon('file_remove'),
 257                      'handler' => 'this.removeFile',
 258                  );
 259              }
 260          } else { /* directories */
 261              if ($this->hasPermission('directory_create')) {
 262                  $menu[] = array(
 263                      'text' => $this->xpdo->lexicon('file_folder_create_here'),
 264                      'handler' => 'this.createDirectory',
 265                  );
 266              }
 267              $menu[] = array(
 268                  'text' => $this->xpdo->lexicon('directory_refresh'),
 269                  'handler' => 'this.refreshActiveNode',
 270              );
 271              if ($this->hasPermission('file_upload')) {
 272                  $menu[] = '-';
 273                  $menu[] = array(
 274                      'text' => $this->xpdo->lexicon('upload_files'),
 275                      'handler' => 'this.uploadFiles',
 276                  );
 277              }
 278              if ($this->hasPermission('file_create')) {
 279                  $menu[] = array(
 280                      'text' => $this->xpdo->lexicon('file_create'),
 281                      'handler' => 'this.createFile',
 282                  );
 283                  $menu[] = array(
 284                      'text' => $this->xpdo->lexicon('quick_create_file'),
 285                      'handler' => 'this.quickCreateFile',
 286                  );
 287              }
 288              if ($this->hasPermission('directory_remove')) {
 289                  $menu[] = '-';
 290                  $menu[] = array(
 291                      'text' => $this->xpdo->lexicon('file_folder_remove'),
 292                      'handler' => 'this.removeDirectory',
 293                  );
 294              }
 295          }
 296          return $menu;
 297      }
 298  
 299      /**

 300       * Get all files in the directory and prepare thumbnail views

 301       * 

 302       * @param string $path

 303       * @return array

 304       */
 305      public function getObjectsInContainer($path) {
 306          $list = $this->getS3ObjectList($path);
 307          $properties = $this->getPropertyList();
 308  
 309          $modAuth = $this->xpdo->user->getUserToken($this->xpdo->context->get('key'));
 310  
 311          /* get default settings */

 312          $use_multibyte = $this->ctx->getOption('use_multibyte', false);
 313          $encoding = $this->ctx->getOption('modx_charset', 'UTF-8');
 314          $bucketUrl = rtrim($properties['url'],'/').'/';
 315          $allowedFileTypes = $this->getOption('allowedFileTypes',$this->properties,'');
 316          $allowedFileTypes = !empty($allowedFileTypes) && is_string($allowedFileTypes) ? explode(',',$allowedFileTypes) : $allowedFileTypes;
 317          $imageExtensions = $this->getOption('imageExtensions',$this->properties,'jpg,jpeg,png,gif');
 318          $imageExtensions = explode(',',$imageExtensions);
 319          $thumbnailType = $this->getOption('thumbnailType',$this->properties,'png');
 320          $thumbnailQuality = $this->getOption('thumbnailQuality',$this->properties,90);
 321          $skipFiles = $this->getOption('skipFiles',$this->properties,'.svn,.git,_notes,.DS_Store');
 322          $skipFiles = explode(',',$skipFiles);
 323          $skipFiles[] = '.';
 324          $skipFiles[] = '..';
 325  
 326          /* iterate */

 327          $files = array();
 328          foreach ($list as $object) {
 329              $objectUrl = $bucketUrl.trim($object,'/');
 330              $baseName = basename($object);
 331              $isDir = substr(strrev($object),0,1) == '/' ? true : false;
 332              if (in_array($object,$skipFiles)) continue;
 333  
 334              if (!$isDir) {
 335                  $fileArray = array(
 336                      'id' => $object,
 337                      'name' => $baseName,
 338                      'url' => $objectUrl,
 339                      'relativeUrl' => $objectUrl,
 340                      'fullRelativeUrl' => $objectUrl,
 341                      'pathname' => $objectUrl,
 342                      'size' => 0,
 343                      'leaf' => true,
 344                      'menu' => array(
 345                          array('text' => $this->xpdo->lexicon('file_remove'),'handler' => 'this.removeFile'),
 346                      ),
 347                  );
 348  
 349                  $fileArray['ext'] = pathinfo($baseName,PATHINFO_EXTENSION);
 350                  $fileArray['ext'] = $use_multibyte ? mb_strtolower($fileArray['ext'],$encoding) : strtolower($fileArray['ext']);
 351                  $fileArray['cls'] = 'icon-'.$fileArray['ext'];
 352  
 353                  if (!empty($allowedFileTypes) && !in_array($fileArray['ext'],$allowedFileTypes)) continue;
 354  
 355                  /* get thumbnail */

 356                  if (in_array($fileArray['ext'],$imageExtensions)) {
 357                      $imageWidth = $this->ctx->getOption('filemanager_image_width', 400);
 358                      $imageHeight = $this->ctx->getOption('filemanager_image_height', 300);
 359                      $thumbHeight = $this->ctx->getOption('filemanager_thumb_height', 60);
 360                      $thumbWidth = $this->ctx->getOption('filemanager_thumb_width', 80);
 361  
 362                      $size = @getimagesize($objectUrl);
 363                      if (is_array($size)) {
 364                          $imageWidth = $size[0] > 800 ? 800 : $size[0];
 365                          $imageHeight = $size[1] > 600 ? 600 : $size[1];
 366                      }
 367  
 368                      /* ensure max h/w */

 369                      if ($thumbWidth > $imageWidth) $thumbWidth = $imageWidth;
 370                      if ($thumbHeight > $imageHeight) $thumbHeight = $imageHeight;
 371  
 372                      /* generate thumb/image URLs */

 373                      $thumbQuery = http_build_query(array(
 374                          'src' => $object,
 375                          'w' => $thumbWidth,
 376                          'h' => $thumbHeight,
 377                          'f' => $thumbnailType,
 378                          'q' => $thumbnailQuality,
 379                          'HTTP_MODAUTH' => $modAuth,
 380                          'wctx' => $this->ctx->get('key'),
 381                          'source' => $this->get('id'),
 382                      ));
 383                      $imageQuery = http_build_query(array(
 384                          'src' => $object,
 385                          'w' => $imageWidth,
 386                          'h' => $imageHeight,
 387                          'HTTP_MODAUTH' => $modAuth,
 388                          'f' => $thumbnailType,
 389                          'q' => $thumbnailQuality,
 390                          'wctx' => $this->ctx->get('key'),
 391                          'source' => $this->get('id'),
 392                      ));
 393                      $fileArray['thumb'] = $this->ctx->getOption('connectors_url', MODX_CONNECTORS_URL).'system/phpthumb.php?'.urldecode($thumbQuery);
 394                      $fileArray['image'] = $this->ctx->getOption('connectors_url', MODX_CONNECTORS_URL).'system/phpthumb.php?'.urldecode($imageQuery);
 395  
 396                  } else {
 397                      $fileArray['thumb'] = $this->ctx->getOption('manager_url', MODX_MANAGER_URL).'templates/default/images/restyle/nopreview.jpg';
 398                      $fileArray['thumbWidth'] = $this->ctx->getOption('filemanager_thumb_width', 80);
 399                      $fileArray['thumbHeight'] = $this->ctx->getOption('filemanager_thumb_height', 60);
 400                  }
 401                  $files[] = $fileArray;
 402              }
 403          }
 404          return $files;
 405      }
 406  
 407      /**

 408       * Create a Container

 409       *

 410       * @param string $name

 411       * @param string $parentContainer

 412       * @return boolean

 413       */
 414      public function createContainer($name,$parentContainer) {
 415          $newPath = $parentContainer.rtrim($name,'/').'/';
 416          /* check to see if folder already exists */

 417          if ($this->driver->if_object_exists($this->bucket,$newPath)) {
 418              $this->addError('file',$this->xpdo->lexicon('file_folder_err_ae').': '.$newPath);
 419              return false;
 420          }
 421  
 422          /* create empty file that acts as folder */

 423          $created = $this->driver->create_object($this->bucket,$newPath,array(
 424              'body' => '',
 425              'acl' => AmazonS3::ACL_PUBLIC,
 426              'length' => 0,
 427          ));
 428  
 429          if (!$created) {
 430              $this->addError('name',$this->xpdo->lexicon('file_folder_err_create').$newPath);
 431              return false;
 432          }
 433  
 434          $this->xpdo->logManagerAction('directory_create','',$newPath);
 435          return true;
 436      }
 437  
 438      /**

 439       * Remove an empty folder from s3

 440       *

 441       * @param $path

 442       * @return boolean

 443       */
 444      public function removeContainer($path) {
 445          if (!$this->driver->if_object_exists($this->bucket,$path)) {
 446              $this->addError('file',$this->xpdo->lexicon('file_folder_err_ns').': '.$path);
 447              return false;
 448          }
 449  
 450          /* remove file from s3 */

 451          $deleted = $this->driver->delete_object($this->bucket,$path);
 452  
 453          /* log manager action */

 454          $this->xpdo->logManagerAction('directory_remove','',$path);
 455  
 456          return !empty($deleted);
 457      }
 458  
 459      /**

 460       * Create a file

 461       *

 462       * @param string $objectPath

 463       * @param string $name

 464       * @param string $content

 465       * @return boolean|string

 466       */
 467      public function createObject($objectPath,$name,$content) {
 468          /* check to see if file already exists */

 469          if ($this->driver->if_object_exists($this->bucket,$objectPath.$name)) {
 470              $this->addError('file',sprintf($this->xpdo->lexicon('file_err_ae'),$objectPath.$name));
 471              return false;
 472          }
 473  
 474          /* create empty file that acts as folder */

 475          $created = $this->driver->create_object($this->bucket,$objectPath.$name,array(
 476                  'body' => $content,
 477                  'acl' => AmazonS3::ACL_PUBLIC,
 478                  'length' => 0,
 479             ));
 480  
 481          if (!$created) {
 482              $this->addError('name',$this->xpdo->lexicon('file_err_create').$objectPath.$name);
 483              return false;
 484          }
 485  
 486          $this->xpdo->logManagerAction('file_create','',$objectPath.$name);
 487          return true;
 488      }
 489  
 490      /**

 491       * Update the contents of a file

 492       *

 493       * @param string $objectPath

 494       * @param string $content

 495       * @return boolean|string

 496       */
 497      public function updateObject($objectPath,$content) {
 498          /* create empty file that acts as folder */

 499          $created = $this->driver->create_object($this->bucket,$objectPath,array(
 500                   'body' => $content,
 501                   'acl' => AmazonS3::ACL_PUBLIC,
 502                   'length' => 0,
 503              ));
 504  
 505          if (!$created) {
 506              $this->addError('name',$this->xpdo->lexicon('file_err_create').$objectPath);
 507              return false;
 508          }
 509  
 510          $this->xpdo->logManagerAction('file_create','',$objectPath);
 511          return true;
 512      }
 513  
 514  
 515      /**

 516       * Delete a file from S3

 517       * 

 518       * @param string $objectPath

 519       * @return boolean

 520       */
 521      public function removeObject($objectPath) {
 522          if (!$this->driver->if_object_exists($this->bucket,$objectPath)) {
 523              $this->addError('file',$this->xpdo->lexicon('file_folder_err_ns').': '.$objectPath);
 524              return false;
 525          }
 526  
 527          /* remove file from s3 */

 528          $deleted = $this->driver->delete_object($this->bucket,$objectPath);
 529  
 530          /* log manager action */

 531          $this->xpdo->logManagerAction('file_remove','',$objectPath);
 532  
 533          return !empty($deleted);
 534      }
 535  
 536      /**

 537       * Rename/move a file

 538       * 

 539       * @param string $oldPath

 540       * @param string $newName

 541       * @return bool

 542       */
 543      public function renameObject($oldPath,$newName) {
 544          if (!$this->driver->if_object_exists($this->bucket,$oldPath)) {
 545              $this->addError('file',$this->xpdo->lexicon('file_folder_err_ns').': '.$oldPath);
 546              return false;
 547          }
 548          $dir = dirname($oldPath);
 549          $newPath = ($dir != '.' ? $dir.'/' : '').$newName;
 550  
 551          $copied = $this->driver->copy_object(array(
 552              'bucket' => $this->bucket,
 553              'filename' => $oldPath,
 554          ),array(
 555              'bucket' => $this->bucket,
 556              'filename' => $newPath,
 557          ),array(
 558              'acl' => AmazonS3::ACL_PUBLIC,
 559          ));
 560          if (!$copied) {
 561              $this->addError('file',$this->xpdo->lexicon('file_folder_err_rename').': '.$oldPath);
 562              return false;
 563          }
 564  
 565          $this->driver->delete_object($this->bucket,$oldPath);
 566  
 567          $this->xpdo->logManagerAction('file_rename','',$oldPath);
 568          return true;
 569      }
 570  
 571      /**

 572       * Upload files to S3

 573       * 

 574       * @param string $container

 575       * @param array $objects

 576       * @return bool

 577       */
 578      public function uploadObjectsToContainer($container,array $objects = array()) {
 579          if ($container == '/' || $container == '.') $container = '';
 580  
 581          $allowedFileTypes = explode(',',$this->xpdo->getOption('upload_files',null,''));
 582          $allowedFileTypes = array_merge(explode(',',$this->xpdo->getOption('upload_images')),explode(',',$this->xpdo->getOption('upload_media')),explode(',',$this->xpdo->getOption('upload_flash')),$allowedFileTypes);
 583          $allowedFileTypes = array_unique($allowedFileTypes);
 584          $maxFileSize = $this->xpdo->getOption('upload_maxsize',null,1048576);
 585  
 586          /* loop through each file and upload */

 587          foreach ($objects as $file) {
 588              if ($file['error'] != 0) continue;
 589              if (empty($file['name'])) continue;
 590              $ext = @pathinfo($file['name'],PATHINFO_EXTENSION);
 591              $ext = strtolower($ext);
 592  
 593              if (empty($ext) || !in_array($ext,$allowedFileTypes)) {
 594                  $this->addError('path',$this->xpdo->lexicon('file_err_ext_not_allowed',array(
 595                      'ext' => $ext,
 596                  )));
 597                  continue;
 598              }
 599              $size = @filesize($file['tmp_name']);
 600  
 601              if ($size > $maxFileSize) {
 602                  $this->addError('path',$this->xpdo->lexicon('file_err_too_large',array(
 603                      'size' => $size,
 604                      'allowed' => $maxFileSize,
 605                  )));
 606                  continue;
 607              }
 608  
 609              $newPath = $container.$file['name'];
 610  
 611  
 612              $contentType = $this->getContentType($ext);
 613              $uploaded = $this->driver->create_object($this->bucket,$newPath,array(
 614                  'fileUpload' => $file['tmp_name'],
 615                  'acl' => AmazonS3::ACL_PUBLIC,
 616                  'length' => $size,
 617                  'contentType' => $contentType,
 618              ));
 619  
 620              if (!$uploaded) {
 621                  $this->addError('path',$this->xpdo->lexicon('file_err_upload'));
 622              }
 623          }
 624  
 625          /* invoke event */

 626          $this->xpdo->invokeEvent('OnFileManagerUpload',array(
 627              'files' => &$objects,
 628              'directory' => $container,
 629              'source' => &$this,
 630          ));
 631  
 632          $this->xpdo->logManagerAction('file_upload','',$container);
 633  
 634          return !$this->hasErrors();
 635      }
 636  
 637      /**

 638       * Get the content type of the file based on extension

 639       * @param string $ext

 640       * @return string

 641       */
 642      protected function getContentType($ext) {
 643          $contentType = 'application/octet-stream';
 644          $mimeTypes = array(
 645              '323' => 'text/h323',
 646              'acx' => 'application/internet-property-stream',
 647              'ai' => 'application/postscript',
 648              'aif' => 'audio/x-aiff',
 649              'aifc' => 'audio/x-aiff',
 650              'aiff' => 'audio/x-aiff',
 651              'asf' => 'video/x-ms-asf',
 652              'asr' => 'video/x-ms-asf',
 653              'asx' => 'video/x-ms-asf',
 654              'au' => 'audio/basic',
 655              'avi' => 'video/x-msvideo',
 656              'axs' => 'application/olescript',
 657              'bas' => 'text/plain',
 658              'bcpio' => 'application/x-bcpio',
 659              'bin' => 'application/octet-stream',
 660              'bmp' => 'image/bmp',
 661              'c' => 'text/plain',
 662              'cat' => 'application/vnd.ms-pkiseccat',
 663              'cdf' => 'application/x-cdf',
 664              'cer' => 'application/x-x509-ca-cert',
 665              'class' => 'application/octet-stream',
 666              'clp' => 'application/x-msclip',
 667              'cmx' => 'image/x-cmx',
 668              'cod' => 'image/cis-cod',
 669              'cpio' => 'application/x-cpio',
 670              'crd' => 'application/x-mscardfile',
 671              'crl' => 'application/pkix-crl',
 672              'crt' => 'application/x-x509-ca-cert',
 673              'csh' => 'application/x-csh',
 674              'css' => 'text/css',
 675              'dcr' => 'application/x-director',
 676              'der' => 'application/x-x509-ca-cert',
 677              'dir' => 'application/x-director',
 678              'dll' => 'application/x-msdownload',
 679              'dms' => 'application/octet-stream',
 680              'doc' => 'application/msword',
 681              'dot' => 'application/msword',
 682              'dvi' => 'application/x-dvi',
 683              'dxr' => 'application/x-director',
 684              'eps' => 'application/postscript',
 685              'etx' => 'text/x-setext',
 686              'evy' => 'application/envoy',
 687              'exe' => 'application/octet-stream',
 688              'fif' => 'application/fractals',
 689              'flr' => 'x-world/x-vrml',
 690              'gif' => 'image/gif',
 691              'gtar' => 'application/x-gtar',
 692              'gz' => 'application/x-gzip',
 693              'h' => 'text/plain',
 694              'hdf' => 'application/x-hdf',
 695              'hlp' => 'application/winhlp',
 696              'hqx' => 'application/mac-binhex40',
 697              'hta' => 'application/hta',
 698              'htc' => 'text/x-component',
 699              'htm' => 'text/html',
 700              'html' => 'text/html',
 701              'htt' => 'text/webviewhtml',
 702              'ico' => 'image/x-icon',
 703              'ief' => 'image/ief',
 704              'iii' => 'application/x-iphone',
 705              'ins' => 'application/x-internet-signup',
 706              'isp' => 'application/x-internet-signup',
 707              'jfif' => 'image/pipeg',
 708              'jpe' => 'image/jpeg',
 709              'jpeg' => 'image/jpeg',
 710              'jpg' => 'image/jpeg',
 711              'js' => 'application/x-javascript',
 712              'latex' => 'application/x-latex',
 713              'lha' => 'application/octet-stream',
 714              'lsf' => 'video/x-la-asf',
 715              'lsx' => 'video/x-la-asf',
 716              'lzh' => 'application/octet-stream',
 717              'm13' => 'application/x-msmediaview',
 718              'm14' => 'application/x-msmediaview',
 719              'm3u' => 'audio/x-mpegurl',
 720              'man' => 'application/x-troff-man',
 721              'mdb' => 'application/x-msaccess',
 722              'me' => 'application/x-troff-me',
 723              'mht' => 'message/rfc822',
 724              'mhtml' => 'message/rfc822',
 725              'mid' => 'audio/mid',
 726              'mny' => 'application/x-msmoney',
 727              'mov' => 'video/quicktime',
 728              'movie' => 'video/x-sgi-movie',
 729              'mp2' => 'video/mpeg',
 730              'mp3' => 'audio/mpeg',
 731              'mpa' => 'video/mpeg',
 732              'mpe' => 'video/mpeg',
 733              'mpeg' => 'video/mpeg',
 734              'mpg' => 'video/mpeg',
 735              'mpp' => 'application/vnd.ms-project',
 736              'mpv2' => 'video/mpeg',
 737              'ms' => 'application/x-troff-ms',
 738              'mvb' => 'application/x-msmediaview',
 739              'nws' => 'message/rfc822',
 740              'oda' => 'application/oda',
 741              'p10' => 'application/pkcs10',
 742              'p12' => 'application/x-pkcs12',
 743              'p7b' => 'application/x-pkcs7-certificates',
 744              'p7c' => 'application/x-pkcs7-mime',
 745              'p7m' => 'application/x-pkcs7-mime',
 746              'p7r' => 'application/x-pkcs7-certreqresp',
 747              'p7s' => 'application/x-pkcs7-signature',
 748              'pbm' => 'image/x-portable-bitmap',
 749              'pdf' => 'application/pdf',
 750              'pfx' => 'application/x-pkcs12',
 751              'pgm' => 'image/x-portable-graymap',
 752              'pko' => 'application/ynd.ms-pkipko',
 753              'pma' => 'application/x-perfmon',
 754              'pmc' => 'application/x-perfmon',
 755              'pml' => 'application/x-perfmon',
 756              'pmr' => 'application/x-perfmon',
 757              'pmw' => 'application/x-perfmon',
 758              'pnm' => 'image/x-portable-anymap',
 759              'pot' => 'application/vnd.ms-powerpoint',
 760              'ppm' => 'image/x-portable-pixmap',
 761              'pps' => 'application/vnd.ms-powerpoint',
 762              'ppt' => 'application/vnd.ms-powerpoint',
 763              'prf' => 'application/pics-rules',
 764              'ps' => 'application/postscript',
 765              'pub' => 'application/x-mspublisher',
 766              'qt' => 'video/quicktime',
 767              'ra' => 'audio/x-pn-realaudio',
 768              'ram' => 'audio/x-pn-realaudio',
 769              'ras' => 'image/x-cmu-raster',
 770              'rgb' => 'image/x-rgb',
 771              'rmi' => 'audio/mid',
 772              'roff' => 'application/x-troff',
 773              'rtf' => 'application/rtf',
 774              'rtx' => 'text/richtext',
 775              'scd' => 'application/x-msschedule',
 776              'sct' => 'text/scriptlet',
 777              'setpay' => 'application/set-payment-initiation',
 778              'setreg' => 'application/set-registration-initiation',
 779              'sh' => 'application/x-sh',
 780              'shar' => 'application/x-shar',
 781              'sit' => 'application/x-stuffit',
 782              'snd' => 'audio/basic',
 783              'spc' => 'application/x-pkcs7-certificates',
 784              'spl' => 'application/futuresplash',
 785              'src' => 'application/x-wais-source',
 786              'sst' => 'application/vnd.ms-pkicertstore',
 787              'stl' => 'application/vnd.ms-pkistl',
 788              'stm' => 'text/html',
 789              'svg' => 'image/svg+xml',
 790              'sv4cpio' => 'application/x-sv4cpio',
 791              'sv4crc' => 'application/x-sv4crc',
 792              't' => 'application/x-troff',
 793              'tar' => 'application/x-tar',
 794              'tcl' => 'application/x-tcl',
 795              'tex' => 'application/x-tex',
 796              'texi' => 'application/x-texinfo',
 797              'texinfo' => 'application/x-texinfo',
 798              'tgz' => 'application/x-compressed',
 799              'tif' => 'image/tiff',
 800              'tiff' => 'image/tiff',
 801              'tr' => 'application/x-troff',
 802              'trm' => 'application/x-msterminal',
 803              'tsv' => 'text/tab-separated-values',
 804              'txt' => 'text/plain',
 805              'uls' => 'text/iuls',
 806              'ustar' => 'application/x-ustar',
 807              'vcf' => 'text/x-vcard',
 808              'vrml' => 'x-world/x-vrml',
 809              'wav' => 'audio/x-wav',
 810              'wcm' => 'application/vnd.ms-works',
 811              'wdb' => 'application/vnd.ms-works',
 812              'wks' => 'application/vnd.ms-works',
 813              'wmf' => 'application/x-msmetafile',
 814              'wps' => 'application/vnd.ms-works',
 815              'wri' => 'application/x-mswrite',
 816              'wrl' => 'x-world/x-vrml',
 817              'wrz' => 'x-world/x-vrml',
 818              'xaf' => 'x-world/x-vrml',
 819              'xbm' => 'image/x-xbitmap',
 820              'xla' => 'application/vnd.ms-excel',
 821              'xlc' => 'application/vnd.ms-excel',
 822              'xlm' => 'application/vnd.ms-excel',
 823              'xls' => 'application/vnd.ms-excel',
 824              'xlt' => 'application/vnd.ms-excel',
 825              'xlw' => 'application/vnd.ms-excel',
 826              'xof' => 'x-world/x-vrml',
 827              'xpm' => 'image/x-xpixmap',
 828              'xwd' => 'image/x-xwindowdump',
 829              'z' => 'application/x-compress',
 830              'zip' => 'application/zip'
 831          );
 832          if (in_array(strtolower($ext),$mimeTypes)) {
 833              $contentType = $mimeTypes[$ext];
 834          } else {
 835              $contentType = 'octet/application-stream';
 836          }
 837          return $contentType;
 838      }
 839  
 840      /**

 841       * Move a file or folder to a specific location

 842       *

 843       * @param string $from The location to move from

 844       * @param string $to The location to move to

 845       * @param string $point

 846       * @return boolean

 847       */
 848      public function moveObject($from,$to,$point = 'append') {
 849          $this->xpdo->lexicon->load('source');
 850          $success = false;
 851  
 852          if (substr(strrev($from),0,1) == '/') {
 853              $this->xpdo->error->message = $this->xpdo->lexicon('s3_no_move_folder',array(
 854                  'from' => $from
 855              ));
 856              return $success;
 857          }
 858  
 859          if (!$this->driver->if_object_exists($this->bucket,$from)) {
 860              $this->xpdo->error->message = $this->xpdo->lexicon('file_err_ns').': '.$from;
 861              return $success;
 862          }
 863  
 864          if ($to != '/') {
 865              if (!$this->driver->if_object_exists($this->bucket,$to)) {
 866                  $this->xpdo->error->message = $this->xpdo->lexicon('file_err_ns').': '.$to;
 867                  return $success;
 868              }
 869              $toPath = rtrim($to,'/').'/'.basename($from);
 870          } else {
 871              $toPath = basename($from);
 872          }
 873          
 874          $response = $this->driver->copy_object(array(
 875              'bucket' => $this->bucket,
 876              'filename' => $from,
 877          ),array(
 878              'bucket' => $this->bucket,
 879              'filename' => $toPath,
 880          ),array(
 881              'acl' => AmazonS3::ACL_PUBLIC,
 882          ));
 883          $success = $response->isOK();
 884  
 885          if ($success) {
 886              $deleteResponse = $this->driver->delete_object($this->bucket,$from);
 887              $success = $deleteResponse->isOK();
 888          } else {
 889              $this->xpdo->error->message = $this->xpdo->lexicon('file_folder_err_rename').': '.$to.' -> '.$from;
 890          }
 891  
 892          return $success;
 893      }
 894  
 895      /**

 896       * @return array

 897       */
 898      public function getDefaultProperties() {
 899          return array(
 900              'url' => array(
 901                  'name' => 'url',
 902                  'desc' => 'prop_s3.url_desc',
 903                  'type' => 'textfield',
 904                  'options' => '',
 905                  'value' => 'http://mysite.s3.amazonaws.com/',
 906                  'lexicon' => 'core:source',
 907              ),
 908              'bucket' => array(
 909                  'name' => 'bucket',
 910                  'desc' => 'prop_s3.bucket_desc',
 911                  'type' => 'textfield',
 912                  'options' => '',
 913                  'value' => '',
 914                  'lexicon' => 'core:source',
 915              ),
 916              'key' => array(
 917                  'name' => 'key',
 918                  'desc' => 'prop_s3.key_desc',
 919                  'type' => 'password',
 920                  'options' => '',
 921                  'value' => '',
 922                  'lexicon' => 'core:source',
 923              ),
 924              'secret_key' => array(
 925                  'name' => 'secret_key',
 926                  'desc' => 'prop_s3.secret_key_desc',
 927                  'type' => 'password',
 928                  'options' => '',
 929                  'value' => '',
 930                  'lexicon' => 'core:source',
 931              ),
 932              'imageExtensions' => array(
 933                  'name' => 'imageExtensions',
 934                  'desc' => 'prop_s3.imageExtensions_desc',
 935                  'type' => 'textfield',
 936                  'value' => 'jpg,jpeg,png,gif',
 937                  'lexicon' => 'core:source',
 938              ),
 939              'thumbnailType' => array(
 940                  'name' => 'thumbnailType',
 941                  'desc' => 'prop_s3.thumbnailType_desc',
 942                  'type' => 'list',
 943                  'options' => array(
 944                      array('name' => 'PNG','value' => 'png'),
 945                      array('name' => 'JPG','value' => 'jpg'),
 946                      array('name' => 'GIF','value' => 'gif'),
 947                  ),
 948                  'value' => 'png',
 949                  'lexicon' => 'core:source',
 950              ),
 951              'thumbnailQuality' => array(
 952                  'name' => 'thumbnailQuality',
 953                  'desc' => 'prop_s3.thumbnailQuality_desc',
 954                  'type' => 'textfield',
 955                  'options' => '',
 956                  'value' => 90,
 957                  'lexicon' => 'core:source',
 958              ),
 959              'skipFiles' => array(
 960                  'name' => 'skipFiles',
 961                  'desc' => 'prop_s3.skipFiles_desc',
 962                  'type' => 'textfield',
 963                  'options' => '',
 964                  'value' => '.svn,.git,_notes,nbproject,.idea,.DS_Store',
 965                  'lexicon' => 'core:source',
 966              ),
 967          );
 968      }
 969  
 970      /**

 971       * Prepare a src parameter to be rendered with phpThumb

 972       * 

 973       * @param string $src

 974       * @return string

 975       */
 976      public function prepareSrcForThumb($src) {
 977          $properties = $this->getPropertyList();
 978          if (strpos($src,$properties['url']) === false) {
 979              $src = $properties['url'].ltrim($src,'/');
 980          }
 981          return $src;
 982      }
 983  
 984      /**

 985       * Get the base URL for this source. Only applicable to sources that are streams.

 986       *

 987       * @param string $object An optional object to find the base url of

 988       * @return string

 989       */
 990      public function getBaseUrl($object = '') {
 991          $properties = $this->getPropertyList();
 992          return $properties['url'];
 993      }
 994  
 995      /**

 996       * Get the absolute URL for a specified object. Only applicable to sources that are streams.

 997       *

 998       * @param string $object

 999       * @return string

1000       */
1001      public function getObjectUrl($object = '') {
1002          $properties = $this->getPropertyList();
1003          return $properties['url'].$object;
1004      }
1005  
1006      public function getObjectFileSize($filename) {
1007          return $this->driver->get_object_filesize($this->bucket, $filename);
1008      }
1009  
1010      /**

1011       * Tells if a file is a binary file or not.

1012       *

1013       * @param string $file

1014       * @return boolean True if a binary file.

1015       */
1016      public function isBinary($file, $isContent = false) {
1017          if(!$isContent) {
1018              $file = file_get_contents($file, null, null, null, 512);
1019          }
1020  
1021          $content = str_replace(array("\n", "\r", "\t"), '', $file);
1022          return ctype_print($content) ? false : true;
1023      }
1024  
1025      /**

1026       * Get the contents of a specified file

1027       *

1028       * @param string $objectPath

1029       * @return array

1030       */
1031      public function getObjectContents($objectPath) {
1032          $properties = $this->getPropertyList();
1033          $objectUrl = $properties['url'].$objectPath;
1034          $contents = @file_get_contents($objectUrl);
1035  
1036          $imageExtensions = $this->getOption('imageExtensions',$this->properties,'jpg,jpeg,png,gif');
1037          $imageExtensions = explode(',',$imageExtensions);
1038          $fileExtension = pathinfo($objectPath,PATHINFO_EXTENSION);
1039  
1040          return array(
1041              'name' => $objectPath,
1042              'basename' => basename($objectPath),
1043              'path' => $objectPath,
1044              'size' => $this->getObjectFileSize($objectPath),
1045              'last_accessed' => '',
1046              'last_modified' => '',
1047              'content' => $contents,
1048              'image' => in_array($fileExtension,$imageExtensions) ? true : false,
1049              'is_writable' => !$this->isBinary($contents, true),
1050              'is_readable' => true,
1051          );
1052      }
1053  }

title

Description

title

Description

title

Description

title

title

Body