Как сохранить файлы в личный каталог?


Я пишу пользовательский модуль, в котором данные записываются в файл, а файл хранится в папке частного каталога.

Для этого я создал частный каталог и назначил ему необходимые разрешения (могу подтвердить, что он доступен для записи, протестировал его, создав новый тип контента из пользовательского интерфейса и добавив файл, загруженный в файл, и способный сохранить загруженный файл в этот каталог). Но моя проблема в том, что я не могу сохранить файл в этот каталог программно.

Я получите сообщение об ошибке с указанием:

Данные не удалось сохранить, поскольку адресат /var/www/html/сайты/имя сайта/файлы/частный/файл.json недействителен. Это может быть вызвано неправильным использованием file_save_data() или отсутствующей оболочкой потока.

Мой личный каталог расположен в каталоге файлов как подкаталог и назван как частный, я настроил его в settings.php и можете просмотреть его в https://example.com/admin/config/media/file-system конечно, очистил кэш после настройки личного каталога в settings.php .

Я могу сохранить файл в общедоступный каталог, используя следующий код:

    $output = Json::encode($data);

    $directory = file_default_scheme() . '://userslist';

    file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);

    $fileLocation = $directory.'/'.JSON_FILENAME;

    $file = file_save_data($output, $fileLocation, FILE_EXISTS_REPLACE);

Но я не могу сохранить в подпапке в общедоступном каталоге, используя следующий код:

    $directory = \Drupal::service('file_system')->realpath("public://userslist");

То же самое относится и к частному каталогу:

    $directory = \Drupal::service('file_system')->realpath("private://");

Я даже могу сохранять данные, используя следующий код:

    $directory = file_default_scheme() . '://private';

Поскольку частный каталог присутствует в качестве подкаталога в общедоступном каталоге, следовательно, путь к общедоступному каталогу назначен вручную выше.

Но не удается сохранить с помощью realpath который динамически получает путь к частному или общедоступному файловому каталогу.

Может ли кто-нибудь помочь мне решить эту проблему?

Я попробовал функциональность в двух разных системных средах: одна - Linux, а другая - Windows, и я получаю ту же ошибку, что и выше.

Спасибо.

Редактировать 1: Я сделал несколько ошибок и ошибок и получил следующие результаты, но все еще не могу найти правильный способ сохранить файл в личный каталог.

    // My private file configuration in settings.php 
    $settings['file_private_path'] = 'sites/sitename/files/private';

    $directory = file_default_scheme() . '://userslist';
    dpm($directory); // public://userslist
    // File is writable to the directory and can be accessed through browser.

    $directory = PrivateStream::basePath(). '://userslist'; ;
    dpm($directory); // sites/sitename/files/private://userslist

    $directory = PrivateStream::basePath(). '/userslist'; ;
    dpm($directory); // sites/sitename/files/private/userslist

    $directory = drupal_realpath('public://userslist');
    dpm($directory);  // /var/www/html/sites/sitename/files/userslist

    $directory = \Drupal::service('stream_wrapper_manager')->getViaUri('private://userslist')->getUri();
    dpm($directory); // private://userslist

    // File is writable to the directory and can't be accessed through browser.
    // normally a file which is present in private directory and accessed through browser will have the following url pattern 

    // https://example.com/sitename/default/files/private/userslist/file.json
    // but it has the following pattern.
    // https://example.com/sitename/system/files/userslist/file.json

    $directory = \Drupal::service('file_system')->realpath(file_default_scheme().'://userslist');
    dpm($directory); // /var/www/html/sites/sitename/files/userslist

    $directory = \Drupal::service('file_system')->realpath("private://userslist") ;
    dpm($directory); // /var/www/html/sites/sitename/files/private/userslist

    $directory = \Drupal::service('file_system')->realpath("public://userslist");
    dpm($directory); // /var/www/html/sites/sitename/files/userslist

    $directory = file_default_scheme() . '://private/userslist';
    dpm($directory); //public://private/userslist
 1
Author: Adrian Cid Almaguer, 2018-11-06

3 answers

Ваш код почти готов, на самом деле вам не нужен realpath. Построение переменной $directory в виде URI-оболочки потока (т.Е. private://SOME_PATH) является стандартным способом.

Вы получаете эту ошибку от file_valid_uri() - который называется file_save_data() - и ожидает параметр обертки потока $destination (без абсолютных/относительных путей).

В общем, я бы посоветовал вам держаться подальше от абсолютных/относительных путей к файлам и использовать синтаксис URI обертки потока, функции, которые вы используете, поддерживают и/или ожидайте их.

Следующий код позволит вам использовать частную файловую систему:

use Drupal\Core\StreamWrapper\PrivateStream;
...
...
$file_save_path_stream_directory =  'private://userslist';
...
...
file_prepare_directory($file_save_path_stream_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);

$fileLocation = $file_save_path_stream_directory . '/' . JSON_FILENAME;

$file = file_save_data($output, $fileLocation, FILE_EXISTS_REPLACE);    

Удачи!

P.S.: Прочтите эту запись об изменении (https://www.drupal.org/node/2392959 ), содержит важную относительную информацию.

 2
Author: Stefanos Petrakis, 2018-11-08 11:36:50

Я согласен с @Стефаносом Петракисом, что вам не нужен реальный путь, потому что file_valid_uri() сделает уведомление, но $directory = PrivateStream::basePath() . '://userslist'; укажет вам путь к личному файлу, который также не является допустимым uri.

Попробуйте выполнить следующее.

  $directory = \Drupal::service('stream_wrapper_manager')->getViaUri('private://userslist')->getUri();
  file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
  $fileLocation = $directory . '/' . JSON_FILENAME;
  $file = file_save_data($output, $fileLocation, FILE_EXISTS_REPLACE);
 1
Author: berramou, 2018-11-06 12:16:35

Хотя это старый вопрос, я хотел бы отметить, что сейчас он устарел. Вместо этого мы должны использовать \Drupal::service('file_system') сейчас.

Как file_prepare_directory теперь говорится:

function file_prepare_directory(&$directory, $options = FileSystemInterface::MODIFY_PERMISSIONS) {
  @trigger_error('file_prepare_directory() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\File\FileSystemInterface::prepareDirectory(). See https://www.drupal.org/node/3006851.', E_USER_DEPRECATED);
  return \Drupal::service('file_system')->prepareDirectory($directory, $options);
}

Пожалуйста, смотрите https://www.drupal.org/node/3006851 для получения дополнительной информации.

 0
Author: vrijdenker, 2020-06-02 13:34:10