[meta] Modernize File/StreamWrapper API

Created on 31 March 2014, about 10 years ago
Updated 20 April 2023, about 1 year ago

Objective

Status: Incomplete β€” This is just a first proposal.

  1. Since PHP 5.4, stream wrappers have matured significantly; our entire Drupal-specific StreamWrapperInterface is most likely obsolete.
    (cf. #2107287: PHP 5.4 calls a new stream_metadata() method on stream wrappers not implemented by Drupal β†’ )

  2. Most of the functions used for file operations are split between file.inc and file.module. They can be grouped by purpose and consolidated as services inside of Drupal\Core\File namespace:

    1. File API functions consuming Settings to ensure that created files are readable/writable:

      drupal_chmod()
      drupal_unlink()
      drupal_mkdir()
      drupal_rmdir()
      

      Drupal\Core\File\FileHandler
      β€” or similar; the Drupal-specific File API helper functions from #2050759: Move drupal_chmod and other code in file.inc to a Drupal\Core\File\FileSystem class β†’

    2. OS/environment helpers:
      drupal_dirname()
      drupal_basename()
      drupal_tempnam()
      drupal_move_uploaded_file()
      file_upload_max_size()
      file_directory_os_temp()
      file_create_filename()
      
    3. Unmanaged file API:
      file_unmanaged_copy()
      file_unmanaged_prepare()
      file_unmanaged_move()
      file_unmanaged_delete()
      file_unmanaged_delete_recursive()
      file_unmanaged_save_data()
      

      They are transformed by #2244513: Move the unmanaged file APIs to the file_system service (file.inc) β†’ into this interface:

      namespace Drupal\Core\File\Handler;
      
      interface UnmanagedFileHandlerInterface extends FileHandlerInterface {
      
        public function copy($source, $destination = NULL, $replace = self::FILE_EXISTS_RENAME);
      
        public function delete($path);
      
        public function deleteRecursive($path, callable $callback = NULL);
      
        public function move($source, $destination = NULL, $replace = self::FILE_EXISTS_RENAME);
      
        public function prepare($source, &$destination = NULL, $replace = self::FILE_EXISTS_RENAME) {
      
        public function saveData($data, $destination = NULL, $replace = self::FILE_EXISTS_RENAME);
      
      }
      
    4. htaccess helpers
      file_ensure_htaccess()
      file_htaccess_lines()
      file_save_htaccess()
      

      Transformed by #2620304: htaccess functions should be a service β†’ into

      namespace Drupal\Core\File;
      
      class Htaccess {
      
        public function ensure() {
        }
      
        public function save($directory, $private = TRUE, $force_overwrite = FALSE) {
        }
      
      }
      
    5. URL generation
      file_create_url()
      file_url_transform_relative()
      

      Transformed by #2669074: Convert file_create_url() & file_url_transform_relative() to service, deprecate it β†’ into

      namespace Drupal\Core\File;
      
      class FileUrlGenerator {
      
        public function generate($uri, $relative = FALSE) {
        }
      
        public function transformRelative($file_url) {
        }
      
      }
      
    6. Generic helpers:
      Handled by #3035312: Move file_scan_directory() to file_system service β†’
      file_scan_directory()
      file_get_mimetype()
      
    7. Other…
  3. For stream wrappers, we should arrive at this for D8:

    Drupal\Component\StreamWrapper\StreamWrapperInterface  [ex. PhpStreamWrapperInterface]
    Drupal\Component\StreamWrapper\StreamWrapperManager
    Drupal\Component\StreamWrapper\LocalStreamBase         [sans getLabel()/getDescription()]
    ...
    Drupal\Core\StreamWrapper\StreamWrapperInterface       [extends Component\StreamWrapperInterface, adding getLabel()/getDescription()]
    Drupal\Core\StreamWrapper\PublicStream
    Drupal\Core\StreamWrapper\TemporaryStream
    Drupal\Core\StreamWrapper\PrivateStream
    

    β†’ Our StreamWrapper mechanism turns into a re-usable component.

  4. settings.php file and (local) stream wrapper settings should turn into this:

    $settings['file_chmod_directory'] = ...;
    $settings['file_chmod_file'] = ...;
    $settings['stream']['public'] = ...;
    $settings['stream']['private'] = ...;
    $settings['stream']['temporary'] = ...;
    
πŸ“Œ Task
Status

Active

Version

10.1 ✨

Component
File systemΒ  β†’

Last updated 1 day ago

Created by

πŸ‡©πŸ‡ͺGermany sun Karlsruhe

Live updates comments and jobs are added and updated live.
  • API clean-up

    Refactors an existing API or subsystem for consistency, performance, modularization, flexibility, third-party integration, etc. May imply an API change. Frequently used during the Code Slush phase of the release cycle.

  • Needs issue summary update

    Issue summaries save everyone time if they are kept up-to-date. See Update issue summary task instructions.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • From SteamWrapperInterface.php:

     * Note that PHP 5.2 fopen() only supports URIs of the form "scheme://target"
     * despite the fact that according to RFC 3986 a URI's scheme component
     * delimiter is in general just ":", not "://".  Because of this PHP limitation
     * and for consistency Drupal will only accept URIs of form "scheme://target".
    

    This is something that can be updated, as there's no need to support PHP 5.2 anymore.

Production build 0.69.0 2024