123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- <?php
- /**
- * @file
- * Home of the FeedsFileFetcher and related classes.
- */
- /**
- * Definition of the import batch object created on the fetching stage by
- * FeedsFileFetcher.
- */
- class FeedsFileFetcherResult extends FeedsFetcherResult {
- /**
- * Constructor.
- */
- public function __construct($file_path) {
- parent::__construct('');
- $this->file_path = $file_path;
- }
- /**
- * Overrides parent::getRaw().
- */
- public function getRaw() {
- return $this->sanitizeRaw(file_get_contents($this->file_path));
- }
- /**
- * Overrides parent::getFilePath().
- */
- public function getFilePath() {
- if (!is_readable($this->file_path)) {
- throw new Exception(t('File @filepath is not accessible.', array('@filepath' => $this->file_path)));
- }
- return $this->sanitizeFile($this->file_path);
- }
- }
- /**
- * Fetches data via HTTP.
- */
- class FeedsFileFetcher extends FeedsFetcher {
- /**
- * Implements FeedsFetcher::fetch().
- */
- public function fetch(FeedsSource $source) {
- $source_config = $source->getConfigFor($this);
- // Just return a file fetcher result if this is a file.
- if (is_file($source_config['source'])) {
- return new FeedsFileFetcherResult($source_config['source']);
- }
- // Batch if this is a directory.
- $state = $source->state(FEEDS_FETCH);
- $files = array();
- if (!isset($state->files)) {
- $state->files = $this->listFiles($source_config['source']);
- $state->total = count($state->files);
- }
- if (count($state->files)) {
- $file = array_shift($state->files);
- $state->progress($state->total, $state->total - count($state->files));
- return new FeedsFileFetcherResult($file);
- }
- throw new Exception(t('Resource is not a file or it is an empty directory: %source', array('%source' => $source_config['source'])));
- }
- /**
- * Returns an array of files in a directory.
- *
- * @param string $dir
- * A stream wreapper URI that is a directory.
- *
- * @return array
- * An array of stream wrapper URIs pointing to files. The array is empty if
- * no files could be found. Never contains directories.
- */
- protected function listFiles($dir) {
- // Seperate out string into array of extensions. Make sure its regex safe.
- $config = $this->getConfig();
- $extensions = array_filter(array_map('preg_quote', explode(' ', $config['allowed_extensions'])));
- $regex = '/\.(' . implode('|', $extensions) . ')$/';
- $files = array();
- foreach (file_scan_directory($dir, $regex) as $file) {
- $files[] = $file->uri;
- }
- return $files;
- }
- /**
- * Source form.
- */
- public function sourceForm($source_config) {
- $form = array();
- $form['fid'] = array(
- '#type' => 'value',
- '#value' => empty($source_config['fid']) ? 0 : $source_config['fid'],
- );
- if (empty($this->config['direct'])) {
- $form['source'] = array(
- '#type' => 'value',
- '#value' => empty($source_config['source']) ? '' : $source_config['source'],
- );
- $form['upload'] = array(
- '#type' => 'file',
- '#title' => empty($this->config['direct']) ? t('File') : NULL,
- '#description' => empty($source_config['source']) ? t('Select a file from your local system.') : t('Select a different file from your local system.'),
- '#theme_wrappers' => array('feeds_upload'),
- '#file_info' => empty($source_config['fid']) ? NULL : file_load($source_config['fid']),
- '#size' => 10,
- );
- }
- else {
- $form['source'] = array(
- '#type' => 'textfield',
- '#title' => t('File'),
- '#description' => t('Specify a path to a file or a directory. Prefix the path with a scheme. Available schemes: @schemes.', array('@schemes' => implode(', ', $this->config['allowed_schemes']))),
- '#default_value' => empty($source_config['source']) ? '' : $source_config['source'],
- );
- }
- return $form;
- }
- /**
- * Overrides parent::sourceFormValidate().
- */
- public function sourceFormValidate(&$values) {
- $values['source'] = trim($values['source']);
- if (empty($this->config['direct'])) {
- $feed_dir = $this->config['directory'];
- if (!file_prepare_directory($feed_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
- if (user_access('administer feeds')) {
- $plugin_key = feeds_importer($this->id)->config[$this->pluginType()]['plugin_key'];
- $link = url('admin/structure/feeds/' . $this->id . '/settings/' . $plugin_key);
- form_set_error('feeds][FeedsFileFetcher][source', t('Upload failed. Please check the upload <a href="@link">settings.</a>', array('@link' => $link)));
- }
- else {
- form_set_error('feeds][FeedsFileFetcher][source', t('Upload failed. Please contact your site administrator.'));
- }
- watchdog('feeds', 'The upload directory %directory required by a feed could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', array('%directory' => $feed_dir));
- }
- // Validate and save uploaded file.
- elseif ($file = file_save_upload('feeds', array('file_validate_extensions' => array(0 => $this->config['allowed_extensions'])), $feed_dir)) {
- $values['source'] = $file->uri;
- $values['file'] = $file;
- }
- elseif (empty($values['source'])) {
- form_set_error('feeds][FeedsFileFetcher][source', t('Please upload a file.'));
- }
- else {
- // File present from previous upload. Nothing to validate.
- }
- }
- else {
- // Check if chosen url scheme is allowed.
- $scheme = file_uri_scheme($values['source']);
- if (!$scheme || !in_array($scheme, $this->config['allowed_schemes'])) {
- form_set_error('feeds][FeedsFileFetcher][source', t("The file needs to reside within the site's files directory, its path needs to start with scheme://. Available schemes: @schemes.", array('@schemes' => implode(', ', $this->config['allowed_schemes']))));
- }
- // Check whether the given path is readable.
- elseif (!is_readable($values['source'])) {
- form_set_error('feeds][FeedsFileFetcher][source', t('The specified file or directory does not exist.'));
- }
- }
- }
- /**
- * Overrides parent::sourceSave().
- */
- public function sourceSave(FeedsSource $source) {
- $source_config = $source->getConfigFor($this);
- // If a new file is present, delete the old one and replace it with the new
- // one.
- if (isset($source_config['file'])) {
- $file = $source_config['file'];
- if (isset($source_config['fid'])) {
- $this->deleteFile($source_config['fid'], $source->feed_nid);
- }
- $file->status = FILE_STATUS_PERMANENT;
- file_save($file);
- file_usage_add($file, 'feeds', get_class($this), $source->feed_nid);
- $source_config['fid'] = $file->fid;
- unset($source_config['file']);
- $source->setConfigFor($this, $source_config);
- }
- }
- /**
- * Overrides parent::sourceDelete().
- */
- public function sourceDelete(FeedsSource $source) {
- $source_config = $source->getConfigFor($this);
- if (isset($source_config['fid'])) {
- $this->deleteFile($source_config['fid'], $source->feed_nid);
- }
- }
- /**
- * Overrides parent::configDefaults().
- */
- public function configDefaults() {
- $schemes = $this->getSchemes();
- $scheme = in_array('private', $schemes) ? 'private' : 'public';
- return array(
- 'allowed_extensions' => 'txt csv tsv xml opml',
- 'direct' => FALSE,
- 'directory' => $scheme . '://feeds',
- 'allowed_schemes' => $schemes,
- );
- }
- /**
- * Overrides parent::configForm().
- */
- public function configForm(&$form_state) {
- $form = array();
- $form['allowed_extensions'] = array(
- '#type' => 'textfield',
- '#title' => t('Allowed file extensions'),
- '#description' => t('Allowed file extensions for upload.'),
- '#default_value' => $this->config['allowed_extensions'],
- );
- $form['direct'] = array(
- '#type' => 'checkbox',
- '#title' => t('Supply path to file or directory directly'),
- '#description' => t('For experts. Lets users specify a path to a file <em>or a directory of files</em> directly,
- instead of a file upload through the browser. This is useful when the files that need to be imported
- are already on the server.'),
- '#default_value' => $this->config['direct'],
- );
- $form['directory'] = array(
- '#type' => 'textfield',
- '#title' => t('Upload directory'),
- '#description' => t('Directory where uploaded files get stored. Prefix the path with a scheme. Available schemes: @schemes.', array('@schemes' => implode(', ', $this->getSchemes()))),
- '#default_value' => $this->config['directory'],
- '#states' => array(
- 'visible' => array(':input[name="direct"]' => array('checked' => FALSE)),
- 'required' => array(':input[name="direct"]' => array('checked' => FALSE)),
- ),
- );
- if ($options = $this->getSchemeOptions()) {
- $form['allowed_schemes'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Allowed schemes'),
- '#default_value' => $this->config['allowed_schemes'],
- '#options' => $options,
- '#description' => t('Select the schemes you want to allow for direct upload.'),
- '#states' => array(
- 'visible' => array(':input[name="direct"]' => array('checked' => TRUE)),
- ),
- );
- }
- return $form;
- }
- /**
- * Overrides parent::configFormValidate().
- *
- * Ensure that the chosen directory is accessible.
- */
- public function configFormValidate(&$values) {
- $values['directory'] = trim($values['directory']);
- $values['allowed_schemes'] = array_filter($values['allowed_schemes']);
- if (!$values['direct']) {
- // Ensure that the upload directory field is not empty when not in
- // direct-mode.
- if (!$values['directory']) {
- form_set_error('directory', t('Please specify an upload directory.'));
- // Do not continue validating the directory if none was specified.
- return;
- }
- // Validate the URI scheme of the upload directory.
- $scheme = file_uri_scheme($values['directory']);
- if (!$scheme || !in_array($scheme, $this->getSchemes())) {
- form_set_error('directory', t('Please enter a valid scheme into the directory location.'));
- // Return here so that attempts to create the directory below don't
- // throw warnings.
- return;
- }
- // Ensure that the upload directory exists.
- if (!file_prepare_directory($values['directory'], FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
- form_set_error('directory', t('The chosen directory does not exist and attempts to create it failed.'));
- }
- }
- }
- /**
- * Deletes a file.
- *
- * @param int $fid
- * The file id.
- * @param int $feed_nid
- * The feed node's id, or 0 if a standalone feed.
- *
- * @return bool|array
- * TRUE for success, FALSE in the event of an error, or an array if the file
- * is being used by any modules.
- *
- * @see file_delete()
- */
- protected function deleteFile($fid, $feed_nid) {
- if ($file = file_load($fid)) {
- file_usage_delete($file, 'feeds', get_class($this), $feed_nid);
- return file_delete($file);
- }
- return FALSE;
- }
- /**
- * Returns available schemes.
- *
- * @return array
- * The available schemes.
- */
- protected function getSchemes() {
- return array_keys(file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE));
- }
- /**
- * Returns available scheme options for use in checkboxes or select list.
- *
- * @return array
- * The available scheme array keyed scheme => description
- */
- protected function getSchemeOptions() {
- $options = array();
- foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $info) {
- $options[$scheme] = check_plain($scheme . ': ' . $info['description']);
- }
- return $options;
- }
- }
|