/**
  * copy() follows the rules unlike move_uploaded_file():
  * http://www.php.net/manual/en/function.move-uploaded-file.php#85149
  *
  * As for the security issue, validation should be used to check if a file
  * is, in fact, an uploaded file. Custom validation for this is provided
  * in app/config/bootstrap/validators.php
  *
  * @param  [type] $source      [description]
  * @param  [type] $destination [description]
  * @param  [type] $options     [description]
  * @return [type]              [description]
  */
 public function save($source, $destination, array $options = [])
 {
     return $this->_filter(__METHOD__, compact('source', 'destination', 'options'), function ($self, $params) {
         $source = $params['source'];
         $destination = $params['destination'];
         $options = $params['options'];
         return function ($self, $params) use(&$source, &$destination, $options) {
             $copied = copy($source, $destination);
             $results = [];
             // @todo check if $this->_config['processors'] exists to avoid undefined index notice
             foreach ($this->_config['processors'] as $method => $arguments) {
                 if (!in_array($method, $this->_processors)) {
                     throw new InvalidArgumentException("The processor `{$name}` is not supported.");
                 }
                 foreach ($arguments as $index => $arg) {
                     $arguments[$index] = Uploadable::interpolate($arg, $options);
                 }
                 $results[$method] = Uploadable::applyStrategies($method, $options['name'], $destination, $arguments);
             }
             if ($copied && !in_array(false, $results, true)) {
                 return $results;
             }
             return false;
         };
     });
 }
Beispiel #2
0
 /**
  * @todo If `styles` is not defined, just copy the original to `$destination`
  * @todo If width and height are not defined, don't resize
  * @todo http://www.imagemagick.org/Usage/resize/
  * @param  [type] $path    [description]
  * @param  [type] $options [description]
  * @return [type]          [description]
  */
 public function save($destination, array $options = [])
 {
     $options['quality'] = ['quality' => 75];
     if (isset($this->_config['quality'])) {
         $options['quality'] = ['quality' => $this->_config['quality']];
     }
     foreach ($this->interpolate($destination) as $dimension => $resolved) {
         list($options['width'], $options['height']) = explode('x', $dimension);
         $source = $options['source'];
         $this->_resize($source, $resolved, $options);
     }
     /**
      * We return `true` instead of the chain since we don't want
      * File::save() to do anything because Imagine::save() does
      * all the writing.
      */
     $adapter = Uploadable::adapter($options['name']);
     $adapter->applyFilter(__FUNCTION__, function ($self, $params, $chain) {
         return function ($self, $params) {
             return true;
         };
     });
 }
Beispiel #3
0
 /**
  * @todo We may also need to filter `remove()`.
  */
 protected function _init()
 {
     parent::_init();
     if (PHP_SAPI === 'cli') {
         return true;
     }
     if ($model = $this->_model) {
         $behavior = $this;
         $model::applyFilter('save', function ($self, $params, $chain) use($behavior) {
             $options = ['placeholders' => []];
             $configs = $behavior->_config;
             $fields = $behavior::_formattedFields($configs['fields']);
             $source = $destination = $configName = [];
             $data = $behavior::_modified($params['data'], $fields);
             $dataKeys = array_keys($data);
             if (empty($dataKeys)) {
                 return $chain->next($self, $params, $chain);
             }
             $queried = $params['entity']->export()['data'];
             if (0 === count(array_intersect_key($queried, $fields))) {
                 return $chain->next($self, $params, $chain);
             }
             $params['data'] = [];
             $params['entity']->set($data);
             $entity = $params['entity'];
             $entityData['model'] = $entity->model();
             $entityData['data'] = $entity->data();
             if (!isset($configs['placeholders'])) {
                 $configs['placeholders'] = [];
             }
             $defaults = ['save' => null, 'remove' => null];
             $skip = [];
             $fieldCount = 0;
             foreach ($fields as $field => $name) {
                 if (array_key_exists($field, $data)) {
                     $configName[$field] = $name;
                     $source[$field] = $_FILES[$field]['tmp_name'];
                     $settings = UploadableStorage::config($name);
                     $settings += $defaults;
                     $path = $settings['save'];
                     $newFile = $_FILES[$field]['name'];
                     if ($entity->exists()) {
                         if (!$entity->modified($field)) {
                             $skip[$field] = true;
                         } else {
                             // We delete the old file
                             $oldFile = $entity->export()['data'][$field];
                             $removeOptions['placeholders'] = UploadableStorage::placeholders($oldFile, $configs['placeholders'] + ['field' => $field], $entityData);
                             $removePath = UploadableStorage::interpolate($settings['remove'], $removeOptions);
                             UploadableStorage::remove($removePath, $removeOptions + ['name' => $name]);
                             if (null === $data[$field]) {
                                 $skip[$field] = true;
                                 continue;
                             }
                             $options['placeholders'] = UploadableStorage::placeholders($newFile, $configs['placeholders'] + ['field' => $field], $entityData);
                             $destination[$field] = UploadableStorage::interpolate($path, $options);
                             /**
                              * The field has been modified to now contain 'null' so we
                              * remove the field from the config so that, later on, we don't
                              * try to upload a non-existent file later.
                              */
                             if (null === $entity->{$field}) {
                                 $params['entity']->{$field} = null;
                                 unset($configs['fields'][$field]);
                             } else {
                                 /**
                                  * the field has been modified but it contains a value
                                  * so we must upload the new one.
                                  */
                                 $fieldValue = static::fieldValue($path, $options['placeholders']);
                                 $params['entity']->{$field} = $fieldValue;
                             }
                         }
                     } else {
                         $options['placeholders'] = UploadableStorage::placeholders($newFile, $configs['placeholders'] + ['field' => $field], $entityData);
                         $fieldValue = static::fieldValue($path, $options['placeholders']);
                         $destination[$field] = UploadableStorage::interpolate($path, $options);
                         $params['entity']->{$field} = $fieldValue;
                     }
                 } else {
                     $fieldCount++;
                 }
             }
             if (!$params['entity']->validates()) {
                 return false;
             }
             $saved = $chain->next($self, $params, $chain);
             if ($fieldCount == count($fields)) {
                 return $saved;
             }
             $options['placeholders'] += $params['entity']->data();
             $uploaded = [];
             foreach ($fields as $field => $name) {
                 if (!isset($skip[$field]) || $skip[$field] !== true) {
                     $options['name'] = $configName[$field];
                     $uploaded[] = UploadableStorage::save($source[$field], $destination[$field], $options);
                 }
             }
             return $saved && !in_array(false, $uploaded, true);
         });
         $model::applyFilter('find', function ($self, $params, $chain) use($behavior) {
             $data = $chain->next($self, $params, $chain);
             switch ($params['type']) {
                 case 'first':
                     $entity = $behavior->invokeMethod('_assignAccessors', [$data]);
                     return $entity;
                     break;
                 case 'all':
                     foreach ($data as $datum) {
                         $entity = $behavior->invokeMethod('_assignAccessors', [$datum]);
                     }
                     return $data;
                     break;
                 default:
                     return $data;
                     break;
             }
         });
         $model::applyFilter('delete', function ($self, $params, $chain) use($behavior) {
             $entity = $params['entity'];
             $entityData['model'] = $entity->model();
             $entityData['data'] = $entity->data();
             $configs = $behavior->_config;
             $fields = $behavior::_formattedFields($configs['fields']);
             if (!isset($configs['placeholders'])) {
                 $configs['placeholders'] = [];
             }
             $results = [];
             foreach ($fields as $field => $name) {
                 $path = UploadableStorage::config($name)['remove'];
                 $existingFile = $entity->export()['data'][$field];
                 $options['placeholders'] = UploadableStorage::placeholders($existingFile, $configs['placeholders'] + ['field' => $field], $entityData);
                 $destination = UploadableStorage::interpolate($path, $options);
                 $results[] = UploadableStorage::remove($destination, $options + ['name' => $name]);
             }
             $deleted = $chain->next($self, $params, $chain);
             return $deleted && !in_array(false, $results, true);
         });
     }
 }